]> git.pld-linux.org Git - packages/nfs-utils.git/commitdiff
- http://www.citi.umich.edu/projects/nfsv4/linux/nfs-utils-patches/1.1.1-1/nfs-utils...
authorJakub Bogusz <qboosh@pld-linux.org>
Sat, 3 Nov 2007 12:46:37 +0000 (12:46 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    nfs-utils-CITI_NFS4.patch -> 1.6

nfs-utils-CITI_NFS4.patch

index 66ea292e980b923fe61e2da85a0459a6f41c9048..c3c4d21c55086975e78411a3ca7b67193e417ee8 100644 (file)
 
 The complete set of CITI nfs-utils patches rolled into one patch.
 
-Changes since 1.0.11-CITI_NFS4_ALL-1:
+Changes since 1.1.0-CITI_NFS4_ALL-2:
 
- * Update to nfs-utils-1.1.0
+ * Update to nfs-utils-1.1.1
 
- * Include patches from git not yet in a release:
-   - Fix mount error messages
+ * Patch from Steve Langasek <vorlon@debian.org> and
+   Steinar H. Gunderson <sesse@debian.org> fixing segfault problem on
+   64-bit platforms introduced by the xlog cleanup (re-using va_list).
 
- * Update gssd usage message to include new -n option.
 
- * Patches from Bruce Fields to clean up compile warning, and
-   move pseudoflavor code to a common location
-
- * Patch from Bruce Fields and Fred Isaman that adds support
-   to exportfs for reading a sec= option and sending server
-   security data through cache via
-   "... secinfo n flavor1 flag1 ... flavorN flagN".
 
 
 ---
 
- nfs-utils-1.1.0-kwc/support/include/nfslib.h        |   10 +
- nfs-utils-1.1.0-kwc/support/include/pseudoflavors.h |   17 ++
- nfs-utils-1.1.0-kwc/support/nfs/exports.c           |  158 ++++++++++++++++++--
- nfs-utils-1.1.0-kwc/utils/exportfs/exportfs.c       |    1 
- nfs-utils-1.1.0-kwc/utils/gssd/gssd.c               |    2 
- nfs-utils-1.1.0-kwc/utils/mount/mount.c             |   40 ++++-
- nfs-utils-1.1.0-kwc/utils/mount/nfs4_mount.h        |   12 -
- nfs-utils-1.1.0-kwc/utils/mount/nfs4mount.c         |   27 ---
- nfs-utils-1.1.0-kwc/utils/mountd/cache.c            |   21 ++
- 10 files changed, 240 insertions(+), 49 deletions(-)
+-nfs-utils-1.1.1-kwc/aclocal.m4                  |  569 +++--------
+-nfs-utils-1.1.1-kwc/config.guess                |   34 
+-nfs-utils-1.1.1-kwc/config.sub                  |   24 
+-nfs-utils-1.1.1-kwc/configure                   | 1195 ++++++++++--------------
+-nfs-utils-1.1.1-kwc/ltmain.sh                   |  147 +-
+ nfs-utils-1.1.1-kwc/support/nfs/xlog.c          |    8 
+ nfs-utils-1.1.1-kwc/utils/gssd/context.h        |    6 
+ nfs-utils-1.1.1-kwc/utils/gssd/context_lucid.c  |  391 +++++++
+ nfs-utils-1.1.1-kwc/utils/gssd/context_mit.c    |  256 ++++-
+ nfs-utils-1.1.1-kwc/utils/gssd/gssd.c           |    8 
+ nfs-utils-1.1.1-kwc/utils/gssd/gssd.h           |    3 
+ nfs-utils-1.1.1-kwc/utils/gssd/gssd_main_loop.c |   20 
+ nfs-utils-1.1.1-kwc/utils/gssd/gssd_proc.c      |  119 +-
+ nfs-utils-1.1.1-kwc/utils/gssd/krb5_util.c      |  231 +++-
+ nfs-utils-1.1.1-kwc/utils/gssd/krb5_util.h      |    2 
+ nfs-utils-1.1.1-kwc/utils/gssd/svcgssd_proc.c   |   84 +
+ 16 files changed, 1786 insertions(+), 1311 deletions(-)
 
-diff -puN utils/mount/mount.c~CITI_NFS4_ALL utils/mount/mount.c
---- nfs-utils-1.1.0/utils/mount/mount.c~CITI_NFS4_ALL  2007-06-22 10:51:38.885022000 -0400
-+++ nfs-utils-1.1.0-kwc/utils/mount/mount.c    2007-06-22 10:52:04.954241000 -0400
-@@ -285,22 +285,49 @@ static void parse_opts (const char *opti
+diff -puN support/nfs/xlog.c~CITI_NFS4_ALL support/nfs/xlog.c
+--- nfs-utils-1.1.1/support/nfs/xlog.c~CITI_NFS4_ALL   2007-10-23 14:17:18.316202000 -0400
++++ nfs-utils-1.1.1-kwc/support/nfs/xlog.c     2007-10-23 14:17:18.385133000 -0400
+@@ -133,9 +133,13 @@ xlog_enabled(int fac)
+ void
+ xlog_backend(int kind, const char *fmt, va_list args)
+ {
++      va_list args2;
++
+       if (!(kind & (L_ALL)) && !(logging && (kind & logmask)))
+               return;
++      va_copy(args2, args);
++
+       if (log_syslog) {
+               switch (kind) {
+               case L_FATAL:
+@@ -172,10 +176,12 @@ xlog_backend(int kind, const char *fmt, 
+               fprintf(stderr, "%s: ", log_name);
+ #endif
+-              vfprintf(stderr, fmt, args);
++              vfprintf(stderr, fmt, args2);
+               fprintf(stderr, "\n");
        }
++      va_end(args2);
++
+       if (kind == L_FATAL)
+               exit(1);
  }
+diff -puN utils/gssd/svcgssd_proc.c~CITI_NFS4_ALL utils/gssd/svcgssd_proc.c
+--- nfs-utils-1.1.1/utils/gssd/svcgssd_proc.c~CITI_NFS4_ALL    2007-10-23 14:17:18.488030000 -0400
++++ nfs-utils-1.1.1-kwc/utils/gssd/svcgssd_proc.c      2007-10-23 14:17:18.505013000 -0400
+@@ -51,6 +51,7 @@
+ #include "gss_util.h"
+ #include "err_util.h"
+ #include "context.h"
++#include "gss_oids.h"
  
--static void mount_error(char *node)
-+static void mount_error(char *mntpnt, char *node)
+ extern char * mech2file(gss_OID mech);
+ #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel"
+@@ -66,8 +67,30 @@ struct svc_cred {
+ };
+ static int
++get_krb5_hostbased_name (gss_buffer_desc name, char **hostbased_name)
++{
++      char *p, *sname = NULL;
++      if (strchr(name.value, '@') && strchr(name.value, '/')) {
++              if (!(sname = calloc(name.length, 1))) {
++                      printerr(0, "ERROR: get_krb5_hostbased_name failed "
++                               "to allocate %d bytes\n", name.length);
++                      goto out_err;
++              }
++              /* read in name and instance and replace '/' with '@' */
++              sscanf(name.value, "%[^@]", sname);
++              p = strchr(sname, '/');
++              p[0] = '@';
++      }
++      *hostbased_name = sname;
++      return 0;
++out_err:
++      return -1;
++}
++
++static int
+ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
+-              gss_OID mech, gss_buffer_desc *context_token)
++              gss_OID mech, gss_buffer_desc *context_token,
++              char *client_name)
  {
-       switch(errno) {
-               case ENOTDIR:
--                      fprintf(stderr, "%s: mount point %s is not a directory\n", progname, node);
-+                      fprintf(stderr, "%s: mount point %s is not a directory\n", 
-+                              progname, mntpnt);
-                       break;
-               case EBUSY:
--                      fprintf(stderr, "%s: %s is already mounted or busy\n", progname, node);
-+                      fprintf(stderr, "%s: %s is already mounted or busy\n", 
-+                              progname, mntpnt);
-                       break;
-               case ENOENT:
--                      fprintf(stderr, "%s: mount point %s does not exist\n", progname, node);
-+                      if (node) {
-+                              fprintf(stderr, "%s: %s failed, reason given by server: %s\n",
-+                                      progname, node, strerror(errno));
-+                      } else
-+                              fprintf(stderr, "%s: mount point %s does not exist\n", 
-+                                      progname, mntpnt);
-                       break;
-               default:
-                       fprintf(stderr, "%s: %s\n", progname, strerror(errno));
+       FILE *f;
+       int i;
+@@ -91,8 +114,9 @@ do_svc_downcall(gss_buffer_desc *out_han
+       qword_printint(f, cred->cr_gid);
+       qword_printint(f, cred->cr_ngroups);
+       printerr(2, "mech: %s, hndl len: %d, ctx len %d, timeout: %d, "
+-               "uid: %d, gid: %d, num aux grps: %d:\n",
++               "clnt: %s, uid: %d, gid: %d, num aux grps: %d:\n",
+                fname, out_handle->length, context_token->length, 0x7fffffff,
++               client_name ? client_name : "<null>",
+                cred->cr_uid, cred->cr_gid, cred->cr_ngroups);
+       for (i=0; i < cred->cr_ngroups; i++) {
+               qword_printint(f, cred->cr_groups[i]);
+@@ -100,6 +124,8 @@ do_svc_downcall(gss_buffer_desc *out_han
        }
+       qword_print(f, fname);
+       qword_printhex(f, context_token->value, context_token->length);
++      if (client_name)
++              qword_print(f, client_name);
+       err = qword_eol(f);
+       fclose(f);
+       return err;
+@@ -294,6 +320,45 @@ print_hexl(const char *description, unsi
  }
-+static int chk_mountpoint(char *mount_point)
+ #endif
++static int
++get_hostbased_client_name(gss_name_t client_name, gss_OID mech,
++                        char **hostbased_name)
 +{
-+      struct stat sb;
++      u_int32_t       maj_stat, min_stat;
++      gss_buffer_desc name;
++      gss_OID         name_type = GSS_C_NO_OID;
++      char            *cname;
++      int             res = -1;
 +
-+      if (stat(mount_point, &sb) < 0){
-+              mount_error(mount_point, NULL);
-+              return 1;
++      /* get the client name and for service principals only
++       * add it after the context (service name used for
++       * authenticating callbacks) */
++      maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
++      if (maj_stat != GSS_S_COMPLETE) {
++              pgsserr("get_hostbased_client_name: gss_display_name",
++                      maj_stat, min_stat, mech);
++              goto out_err;
 +      }
-+      if (S_ISDIR(sb.st_mode) == 0){
-+              errno = ENOTDIR;
-+              mount_error(mount_point, NULL);
-+              return 1;
++      if (name.length >= 0xffff) { /* be certain name.length+1 doesn't overflow */
++              printerr(0, "ERROR: get_hostbased_client_name: "
++                       "received gss_name is too long (%d bytes)\n",
++                       name.length);
++              goto out_rel_buf;
 +      }
-+      if (access(mount_point, X_OK) < 0) {
-+              mount_error(mount_point, NULL);
-+              return 1;
++      /* For Kerberos, transform the NT_KRB5_PRINCIPAL to
++       * NT_HOSTBASED_SERVICE */
++      if (g_OID_equal(&krb5oid, mech)) {
++              if (!get_krb5_hostbased_name(name, &cname))
++                      *hostbased_name = cname;
 +      }
-+
-+      return 0;
++      /* For SPKM3, do ??? */
++      res = 0;
++out_rel_buf:
++      gss_release_buffer(&min_stat, &name);
++out_err:
++      return res;
 +}
++
+ void
+ handle_nullreq(FILE *f) {
+       /* XXX initialize to a random integer to reduce chances of unnecessary
+@@ -320,6 +385,7 @@ handle_nullreq(FILE *f) {
+       static char             *lbuf = NULL;
+       static int              lbuflen = 0;
+       static char             *cp;
++      char                    *hostbased_name = NULL;
+       printerr(1, "handling null request\n");
+@@ -385,8 +451,12 @@ handle_nullreq(FILE *f) {
+               gss_release_name(&ignore_min_stat, &client_name);
+               goto out_err;
+       }
+-      gss_release_name(&ignore_min_stat, &client_name);
+-
++      if (get_hostbased_client_name(client_name, mech, &hostbased_name)) {
++              /* get_hostbased_client_name() prints error msg */
++              maj_stat = GSS_S_BAD_NAME; /* XXX ? */
++              gss_release_name(&ignore_min_stat, &client_name);
++              goto out_err;
++      }
  
- extern u_short getport(
-       struct sockaddr_in *saddr,
-@@ -508,6 +535,9 @@ int main(int argc, char *argv[])
-           }
+       /* Context complete. Pass handle_seq in out_handle to use
+        * for context lookup in the kernel. */
+@@ -400,12 +470,14 @@ handle_nullreq(FILE *f) {
+               printerr(0, "WARNING: handle_nullreq: "
+                           "serialize_context_for_kernel failed\n");
+               maj_stat = GSS_S_FAILURE;
++              gss_release_name(&ignore_min_stat, &client_name);
+               goto out_err;
        }
+       /* We no longer need the gss context */
+       gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok);
+-      do_svc_downcall(&out_handle, &cred, mech, &ctx_token);
++      do_svc_downcall(&out_handle, &cred, mech, &ctx_token, hostbased_name);
++      gss_release_name(&ignore_min_stat, &client_name);
+ continue_needed:
+       send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
+                       &out_handle, &out_tok);
+@@ -414,6 +486,8 @@ out:
+               free(ctx_token.value);
+       if (out_tok.value != NULL)
+               gss_release_buffer(&ignore_min_stat, &out_tok);
++      if (hostbased_name)
++              free(hostbased_name);
+       printerr(1, "finished handling null request\n");
+       return;
+diff -puN utils/gssd/gssd_main_loop.c~CITI_NFS4_ALL utils/gssd/gssd_main_loop.c
+--- nfs-utils-1.1.1/utils/gssd/gssd_main_loop.c~CITI_NFS4_ALL  2007-10-23 14:17:18.606911000 -0400
++++ nfs-utils-1.1.1-kwc/utils/gssd/gssd_main_loop.c    2007-10-23 14:17:18.878793000 -0400
+@@ -98,7 +98,7 @@ gssd_run()
+ {
+       int                     ret;
+       struct sigaction        dn_act;
+-      int                     fd;
++      int                     fd, fd_cb;
  
-+      if (chk_mountpoint(mount_point))
-+              exit(EX_FAIL);
+       /* Taken from linux/Documentation/dnotify.txt: */
+       dn_act.sa_sigaction = dir_notify_handler;
+@@ -114,6 +114,19 @@ gssd_run()
+       fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL);
+       fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
++      if ((fd_cb = open(pipefs_nfscbdir, O_RDONLY)) == -1) {
++              /* could be an older kernel or a newer one doing NFS 4.1 */
++              if (errno != ENOENT)
++                      printerr(0, "WARNING: failed to open %s: %s\n",
++                               pipefs_nfscbdir, strerror(errno));
++              /* ignore processing callback directory */
++              memset(pipefs_nfscbdir, '\0', sizeof(pipefs_nfscbdir));
++      } else {
++              fcntl(fd_cb, F_SETSIG, DNOTIFY_SIGNAL);
++              fcntl(fd_cb, F_NOTIFY,
++                      DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
++      }
 +
-       if (nfs_mount_vers == 4)
-               mnt_err = nfs4mount(spec, mount_point, &flags, &extra_opts, &mount_opts, 0);
-       else {
-@@ -538,7 +568,7 @@ int main(int argc, char *argv[])
-                                          mount_opts);
+       init_client_list();
  
-               if (mnt_err) {
--                      mount_error(mount_point);
-+                      mount_error(mount_point, spec);
-                       exit(EX_FAIL);
+       printerr(1, "beginning poll\n");
+@@ -121,8 +134,7 @@ gssd_run()
+               while (dir_changed) {
+                       dir_changed = 0;
+                       if (update_client_list()) {
+-                              printerr(0, "ERROR: couldn't update "
+-                                       "client list\n");
++                              /* Error msg is already printed */
+                               exit(1);
+                       }
+               }
+@@ -141,5 +153,7 @@ gssd_run()
                }
        }
-diff -puN utils/gssd/gssd.c~CITI_NFS4_ALL utils/gssd/gssd.c
---- nfs-utils-1.1.0/utils/gssd/gssd.c~CITI_NFS4_ALL    2007-06-22 10:51:53.782368000 -0400
-+++ nfs-utils-1.1.0-kwc/utils/gssd/gssd.c      2007-06-22 10:51:56.521019000 -0400
-@@ -81,7 +81,7 @@ sig_hup(int signal)
- static void
- usage(char *progname)
- {
--      fprintf(stderr, "usage: %s [-f] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir]\n",
-+      fprintf(stderr, "usage: %s [-f] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir]\n",
-               progname);
-       exit(1);
+       close(fd);
++      if (fd_cb != -1)
++              close(fd_cb);
+       return;
  }
-diff -puN /dev/null support/include/pseudoflavors.h
---- /dev/null  2007-06-21 19:03:53.875366737 -0400
-+++ nfs-utils-1.1.0-kwc/support/include/pseudoflavors.h        2007-06-22 10:52:22.335293000 -0400
-@@ -0,0 +1,17 @@
-+#define RPC_AUTH_GSS_KRB5       390003
-+#define RPC_AUTH_GSS_KRB5I      390004
-+#define RPC_AUTH_GSS_KRB5P      390005
-+#define RPC_AUTH_GSS_LKEY       390006
-+#define RPC_AUTH_GSS_LKEYI      390007
-+#define RPC_AUTH_GSS_LKEYP      390008
-+#define RPC_AUTH_GSS_SPKM       390009
-+#define RPC_AUTH_GSS_SPKMI      390010
-+#define RPC_AUTH_GSS_SPKMP      390011
-+
-+struct flav_info {
-+      char    *flavour;
-+      int     fnum;
-+};
+diff -puN utils/gssd/gssd_proc.c~CITI_NFS4_ALL utils/gssd/gssd_proc.c
+--- nfs-utils-1.1.1/utils/gssd/gssd_proc.c~CITI_NFS4_ALL       2007-10-23 14:17:18.662855000 -0400
++++ nfs-utils-1.1.1-kwc/utils/gssd/gssd_proc.c 2007-10-23 14:17:19.021793000 -0400
+@@ -102,7 +102,7 @@ int pollsize;  /* the size of pollaray (
+ /* XXX buffer problems: */
+ static int
+ read_service_info(char *info_file_name, char **servicename, char **servername,
+-                int *prog, int *vers, char **protocol) {
++                int *prog, int *vers, char **protocol, int *port) {
+ #define INFOBUFLEN 256
+       char            buf[INFOBUFLEN];
+       static char     dummy[128];
+@@ -112,6 +112,9 @@ read_service_info(char *info_file_name, 
+       char            program[16];
+       char            version[16];
+       char            protoname[16];
++      char            princname[128];
++      char            cb_port[128];
++      char            *p;
+       in_addr_t       inaddr;
+       int             fd = -1;
+       struct hostent  *ent = NULL;
+@@ -136,19 +139,33 @@ read_service_info(char *info_file_name, 
+                  service, program, version,
+                  address,
+                  protoname);
+-
+       if (numfields == 5) {
+               strcpy(protoname, "tcp");
+       } else if (numfields != 6) {
+               goto fail;
+       }
++      princname[0] = '\0';
++      if ((p = strstr(buf, "principal name:")) != NULL)
++              sscanf(p, "principal name: %127s\n", princname);
++      cb_port[0] = '\0';
++      if ((p = strstr(buf, "port")) != NULL)
++              sscanf(p, "port: %127s\n", cb_port);
 +
-+extern struct flav_info flav_map[];
-+extern const int flav_map_size;
-diff -puN support/nfs/exports.c~CITI_NFS4_ALL support/nfs/exports.c
---- nfs-utils-1.1.0/support/nfs/exports.c~CITI_NFS4_ALL        2007-06-22 10:52:16.682999000 -0400
-+++ nfs-utils-1.1.0-kwc/support/nfs/exports.c  2007-06-22 10:52:40.578175000 -0400
-@@ -30,10 +30,29 @@
- #include "xmalloc.h"
- #include "xlog.h"
- #include "xio.h"
-+#include "pseudoflavors.h"
- #define EXPORT_DEFAULT_FLAGS  \
-   (NFSEXP_READONLY|NFSEXP_ROOTSQUASH|NFSEXP_GATHERED_WRITES|NFSEXP_NOSUBTREECHECK)
-+struct flav_info flav_map[] = {
-+      { "krb5",       RPC_AUTH_GSS_KRB5       },
-+      { "krb5i",      RPC_AUTH_GSS_KRB5I      },
-+      { "krb5p",      RPC_AUTH_GSS_KRB5P      },
-+      { "lipkey",     RPC_AUTH_GSS_LKEY       },
-+      { "lipkey-i",   RPC_AUTH_GSS_LKEYI      },
-+      { "lipkey-p",   RPC_AUTH_GSS_LKEYP      },
-+      { "spkm3",      RPC_AUTH_GSS_SPKM       },
-+      { "spkm3i",     RPC_AUTH_GSS_SPKMI      },
-+      { "spkm3p",     RPC_AUTH_GSS_SPKMP      },
-+      { "unix",       AUTH_UNIX               },
-+      { "sys",        AUTH_SYS                },
-+      { "null",       AUTH_NULL               },
-+      { "none",       AUTH_NONE               },
-+};
+       /* check service, program, and version */
+-      if(memcmp(service, "nfs", 3)) return -1;
++      if (memcmp(service, "nfs", 3))
++              return -1;
+       *prog = atoi(program + 1); /* skip open paren */
+       *vers = atoi(version);
+-      if((*prog != 100003) || ((*vers != 2) && (*vers != 3) && (*vers != 4)))
+-              goto fail;
 +
-+const int flav_map_size = sizeof(flav_map)/sizeof(flav_map[0]);
++      if (strlen(service) == 3 && !memcmp(service, "nfs", 3)) {
++              if ((*prog != 100003) || ((*vers != 2) && (*vers != 3) &&
++                  (*vers != 4)))
++                      goto fail;
++      } else if (!memcmp(service, "nfs4_cb", 7)) {
++              if (*vers != 1)
++                      goto fail;
++      }
+       /* create service name */
+       inaddr = inet_addr(address);
+@@ -159,7 +176,12 @@ read_service_info(char *info_file_name, 
+       if (!(*servername = calloc(strlen(ent->h_name) + 1, 1)))
+               goto fail;
+       memcpy(*servername, ent->h_name, strlen(ent->h_name));
+-      snprintf(buf, INFOBUFLEN, "%s@%s", service, ent->h_name);
++      if (princname[0] != '\0')
++              printerr(2, "info file contains princname=%s\n", princname);
++
++      snprintf(buf, INFOBUFLEN, "nfs@%s", ent->h_name);
++      if (cb_port[0] != '\0')
++              *port = atoi(cb_port);
+       if (!(*servicename = calloc(strlen(buf) + 1, 1)))
+               goto fail;
+       memcpy(*servicename, buf, strlen(buf));
+@@ -219,9 +241,9 @@ out:
+ static int
+ process_clnt_dir_files(struct clnt_info * clp)
+ {
+-      char    kname[32];
+-      char    sname[32];
+-      char    info_file_name[32];
++      char    kname[PATH_MAX];
++      char    sname[PATH_MAX];
++      char    info_file_name[PATH_MAX];
+       if (clp->krb5_fd == -1) {
+               snprintf(kname, sizeof(kname), "%s/krb5", clp->dirname);
+@@ -231,14 +253,14 @@ process_clnt_dir_files(struct clnt_info 
+               snprintf(sname, sizeof(sname), "%s/spkm3", clp->dirname);
+               clp->spkm3_fd = open(sname, O_RDWR);
+       }
+-      if((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
++      if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1))
+               return -1;
+       snprintf(info_file_name, sizeof(info_file_name), "%s/info",
+                       clp->dirname);
+       if ((clp->servicename == NULL) &&
+            read_service_info(info_file_name, &clp->servicename,
+                               &clp->servername, &clp->prog, &clp->vers,
+-                              &clp->protocol))
++                              &clp->protocol, &clp->port))
+               return -1;
+       return 0;
+ }
+@@ -288,17 +310,17 @@ insert_clnt_poll(struct clnt_info *clp)
+ }
+ static void
+-process_clnt_dir(char *dir)
++process_clnt_dir(char *dir, char *pdir)
+ {
+       struct clnt_info *      clp;
+       if (!(clp = insert_new_clnt()))
+               goto fail_destroy_client;
+-      if (!(clp->dirname = calloc(strlen(dir) + 1, 1))) {
++      if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 1, 1))) {
+               goto fail_destroy_client;
+       }
+-      memcpy(clp->dirname, dir, strlen(dir));
++      sprintf(clp->dirname, "%s/%s", pdir, dir);
+       if ((clp->dir_fd = open(clp->dirname, O_RDONLY)) == -1) {
+               printerr(0, "ERROR: can't open %s: %s\n",
+                        clp->dirname, strerror(errno));
+@@ -342,16 +364,24 @@ init_client_list(void)
+  * directories, since the DNOTIFY could have been in there.
+  */
+ static void
+-update_old_clients(struct dirent **namelist, int size)
++update_old_clients(struct dirent **namelist, int size, char *pdir)
+ {
+       struct clnt_info *clp;
+       void *saveprev;
+       int i, stillhere;
++      char fname[PATH_MAX];
+       for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
++              /* only compare entries in the global list that are from the
++               * same pipefs parent directory as "pdir"
++               */
++              if (strncmp(clp->dirname, pdir, strlen(pdir)) != 0) break;
 +
- int export_errno;
+               stillhere = 0;
+               for (i=0; i < size; i++) {
+-                      if (!strcmp(clp->dirname, namelist[i]->d_name)) {
++                      snprintf(fname, sizeof(fname), "%s/%s",
++                               pdir, namelist[i]->d_name);
++                      if (strcmp(clp->dirname, fname) == 0) {
+                               stillhere = 1;
+                               break;
+                       }
+@@ -372,47 +402,72 @@ update_old_clients(struct dirent **namel
  
- static char   *efname = NULL;
-@@ -100,6 +119,7 @@ getexportent(int fromkernel, int fromexp
-               def_ee.e_mountpoint = NULL;
-               def_ee.e_fslocmethod = FSLOC_NONE;
-               def_ee.e_fslocdata = NULL;
-+              def_ee.e_secinfo[0].flav = NULL;
-               def_ee.e_nsquids = 0;
-               def_ee.e_nsqgids = 0;
+ /* Search for a client by directory name, return 1 if found, 0 otherwise */
+ static int
+-find_client(char *dirname)
++find_client(char *dirname, char *pdir)
+ {
+       struct clnt_info        *clp;
++      char fname[PATH_MAX];
  
-@@ -179,6 +199,27 @@ getexportent(int fromkernel, int fromexp
-       return &ee;
+-      for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next)
+-              if (!strcmp(clp->dirname, dirname))
++      for (clp = clnt_list.tqh_first; clp != NULL; clp = clp->list.tqe_next) {
++              snprintf(fname, sizeof(fname), "%s/%s", pdir, dirname);
++              if (strcmp(clp->dirname, fname) == 0)
+                       return 1;
++      }
+       return 0;
  }
  
-+void secinfo_show(FILE *fp, struct exportent *ep)
+-/* Used to read (and re-read) list of clients, set up poll array. */
+-int
+-update_client_list(void)
++static int
++process_pipedir(char *pipe_name)
+ {
+       struct dirent **namelist;
+       int i, j;
+-      if (chdir(pipefs_nfsdir) < 0) {
++      if (chdir(pipe_name) < 0) {
+               printerr(0, "ERROR: can't chdir to %s: %s\n",
+-                       pipefs_nfsdir, strerror(errno));
++                       pipe_name, strerror(errno));
+               return -1;
+       }
+-      j = scandir(pipefs_nfsdir, &namelist, NULL, alphasort);
++      j = scandir(pipe_name, &namelist, NULL, alphasort);
+       if (j < 0) {
+               printerr(0, "ERROR: can't scandir %s: %s\n",
+-                       pipefs_nfsdir, strerror(errno));
++                       pipe_name, strerror(errno));
+               return -1;
+       }
+-      update_old_clients(namelist, j);
++
++      update_old_clients(namelist, j, pipe_name);
+       for (i=0; i < j; i++) {
+               if (i < FD_ALLOC_BLOCK
+                               && !strncmp(namelist[i]->d_name, "clnt", 4)
+-                              && !find_client(namelist[i]->d_name))
+-                      process_clnt_dir(namelist[i]->d_name);
++                              && !find_client(namelist[i]->d_name, pipe_name))
++                      process_clnt_dir(namelist[i]->d_name, pipe_name);
+               free(namelist[i]);
+       }
+       free(namelist);
++
+       return 0;
+ }
++/* Used to read (and re-read) list of clients, set up poll array. */
++int
++update_client_list(void)
 +{
-+      struct sec_entry *p1, *p2;
-+      int flags;
++      int retval = -1;
 +
-+      for (p1=ep->e_secinfo; p1->flav; p1=p2) {
++      retval = process_pipedir(pipefs_nfsdir);
++      if (retval)
++              printerr(0, "ERROR: processing %s\n", pipefs_nfsdir);
 +
-+              fprintf(fp, ",sec=%s", p1->flav->flavour);
-+              for (p2=p1+1; (p2->flav != NULL) && (p1->flags == p2->flags);
-+                                                              p2++) {
-+                      fprintf(fp, ":%s", p2->flav->flavour);
-+              }
-+              flags = p1->flags;
-+              fprintf(fp, ",%s", (flags & NFSEXP_READONLY) ? "ro" : "rw");
-+              fprintf(fp, ",%sroot_squash", (flags & NFSEXP_ROOTSQUASH)?
-+                              "" : "no_");
-+              fprintf(fp, ",%sall_squash", (flags & NFSEXP_ALLSQUASH)?
-+                              "" : "no_");
++      /* if we successfully processed nfsdir and callback directory exists
++       * process any events in the callback directory
++       */
++      if (retval == 0 && pipefs_nfscbdir[0] != '\0') {
++              retval = process_pipedir(pipefs_nfscbdir);
++              if (retval)
++                      printerr(0, "ERROR: processing %s\n", pipefs_nfscbdir);
 +      }
-+}
 +
- void
- putexportent(struct exportent *ep)
- {
-@@ -259,7 +300,9 @@ putexportent(struct exportent *ep)
-                       else
-                               fprintf(fp, "%d,", id[i]);
++      return retval;
++}
+ static int
+ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
+@@ -587,6 +642,8 @@ int create_auth_rpc_client(struct clnt_i
+                        clp->servername, uid);
+               goto out_fail;
        }
--      fprintf(fp, "anonuid=%d,anongid=%d)\n", ep->e_anonuid, ep->e_anongid);
-+      fprintf(fp, "anonuid=%d,anongid=%d", ep->e_anonuid, ep->e_anongid);
-+      secinfo_show(fp, ep);
-+      fprintf(fp, ")\n");
- }
++      if (clp->port)
++              ((struct sockaddr_in *)a->ai_addr)->sin_port = htons(clp->port);
+       if (a->ai_protocol == IPPROTO_TCP) {
+               if ((rpc_clnt = clnttcp_create(
+                                       (struct sockaddr_in *) a->ai_addr,
+@@ -677,7 +734,7 @@ handle_krb5_upcall(struct clnt_info *clp
+       char                    **ccname;
+       int                     create_resp = -1;
  
- void
-@@ -307,6 +350,7 @@ mkexportent(char *hname, char *path, cha
-       ee.e_mountpoint = NULL;
-       ee.e_fslocmethod = FSLOC_NONE;
-       ee.e_fslocdata = NULL;
-+      ee.e_secinfo[0].flav = NULL;
-       ee.e_nsquids = 0;
-       ee.e_nsqgids = 0;
-       ee.e_uuid = NULL;
-@@ -350,18 +394,110 @@ static int valid_uuid(char *uuid)
+-      printerr(1, "handling krb5 upcall\n");
++      printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
+       token.length = 0;
+       token.value = NULL;
+@@ -787,7 +844,7 @@ handle_spkm3_upcall(struct clnt_info *cl
+       struct authgss_private_data pd;
+       gss_buffer_desc         token;
+-      printerr(2, "handling spkm3 upcall\n");
++      printerr(2, "handling spkm3 upcall (%s)\n", clp->dirname);
+       token.length = 0;
+       token.value = NULL;
+diff -puN utils/gssd/gssd.c~CITI_NFS4_ALL utils/gssd/gssd.c
+--- nfs-utils-1.1.1/utils/gssd/gssd.c~CITI_NFS4_ALL    2007-10-23 14:17:18.789793000 -0400
++++ nfs-utils-1.1.1-kwc/utils/gssd/gssd.c      2007-10-23 14:17:19.183793000 -0400
+@@ -55,6 +55,7 @@
+ char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR;
+ char pipefs_nfsdir[PATH_MAX] = GSSD_PIPEFS_DIR;
++char pipefs_nfscbdir[PATH_MAX] = GSSD_PIPEFS_DIR;
+ char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE;
+ char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR;
+ int  use_memcache = 0;
+@@ -140,6 +141,10 @@ main(int argc, char *argv[])
+                pipefs_dir, GSSD_SERVICE_NAME);
+       if (pipefs_nfsdir[sizeof(pipefs_nfsdir)-1] != '\0')
+               errx(1, "pipefs_nfsdir path name too long");
++      snprintf(pipefs_nfscbdir, sizeof(pipefs_nfscbdir), "%s/%s",
++               pipefs_dir, GSSD_NFSCB_NAME);
++      if (pipefs_nfscbdir[sizeof(pipefs_nfscbdir)-1] != '\0')
++              errx(1, "pipefs_nfscbdir path name too long");
+       if ((progname = strrchr(argv[0], '/')))
+               progname++;
+@@ -165,6 +170,9 @@ main(int argc, char *argv[])
+       signal(SIGTERM, sig_die);
+       signal(SIGHUP, sig_hup);
++      /* Determine Kerberos information from the kernel */
++      gssd_obtain_kernel_krb5_info();
++
+       gssd_run();
+       printerr(0, "gssd_run returned!\n");
+       abort();
+diff -puN utils/gssd/gssd.h~CITI_NFS4_ALL utils/gssd/gssd.h
+--- nfs-utils-1.1.1/utils/gssd/gssd.h~CITI_NFS4_ALL    2007-10-23 14:17:18.846794000 -0400
++++ nfs-utils-1.1.1-kwc/utils/gssd/gssd.h      2007-10-23 14:17:18.957793000 -0400
+@@ -49,6 +49,7 @@
+ #define GSSD_DEFAULT_MACHINE_CRED_SUFFIX      "machine"
+ #define GSSD_DEFAULT_KEYTAB_FILE              "/etc/krb5.keytab"
+ #define GSSD_SERVICE_NAME                     "nfs"
++#define GSSD_NFSCB_NAME                               "nfsd4_cb"
+ #define GSSD_SERVICE_NAME_LEN                 3
+ /*
+@@ -60,6 +61,7 @@ enum {AUTHTYPE_KRB5, AUTHTYPE_SPKM3, AUT
+ extern char                   pipefs_dir[PATH_MAX];
+ extern char                   pipefs_nfsdir[PATH_MAX];
++extern char                   pipefs_nfscbdir[PATH_MAX];
+ extern char                   keytabfile[PATH_MAX];
+ extern char                   ccachedir[PATH_MAX];
+ extern int                    use_memcache;
+@@ -80,6 +82,7 @@ struct clnt_info {
+       int                     krb5_poll_index;
+       int                     spkm3_fd;
+       int                     spkm3_poll_index;
++      int                     port;
+ };
+ void init_client_list(void);
+diff -puN utils/gssd/krb5_util.c~CITI_NFS4_ALL utils/gssd/krb5_util.c
+--- nfs-utils-1.1.1/utils/gssd/krb5_util.c~CITI_NFS4_ALL       2007-10-23 14:17:19.109793000 -0400
++++ nfs-utils-1.1.1-kwc/utils/gssd/krb5_util.c 2007-10-23 14:17:19.198793000 -0400
+@@ -97,6 +97,7 @@
+ #include "config.h"
+ #include <sys/param.h>
+ #include <rpc/rpc.h>
++#include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/socket.h>
+ #include <arpa/inet.h>
+@@ -108,6 +109,7 @@
+ #include <dirent.h>
+ #include <netdb.h>
+ #include <ctype.h>
++#include <fcntl.h>
+ #include <errno.h>
+ #include <time.h>
+ #include <gssapi/gssapi.h>
+@@ -126,6 +128,10 @@
+ /* Global list of principals/cache file names for machine credentials */
+ struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL;
++/* Encryption types supported by the kernel rpcsec_gss code */
++int num_krb5_enctypes = 0;
++krb5_enctype *krb5_enctypes = NULL;
++
+ /*==========================*/
+ /*===  Internal routines ===*/
+ /*==========================*/
+@@ -256,58 +262,6 @@ gssd_find_existing_krb5_ccache(uid_t uid
+       return found;
  }
  
+-
+-#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
+-/*
+- * this routine obtains a credentials handle via gss_acquire_cred()
+- * then calls gss_krb5_set_allowable_enctypes() to limit the encryption
+- * types negotiated.
+- *
+- * XXX Should call some function to determine the enctypes supported
+- * by the kernel. (Only need to do that once!)
+- *
+- * Returns:
+- *    0 => all went well
+- *     -1 => there was an error
+- */
+-
+-int
+-limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
+-{
+-      u_int maj_stat, min_stat;
+-      gss_cred_id_t credh;
+-      gss_OID_set_desc  desired_mechs;
+-      krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC };
+-      int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
+-
+-      /* We only care about getting a krb5 cred */
+-      desired_mechs.count = 1;
+-      desired_mechs.elements = &krb5oid;
+-
+-      maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
+-                                  &desired_mechs, GSS_C_INITIATE,
+-                                  &credh, NULL, NULL);
+-
+-      if (maj_stat != GSS_S_COMPLETE) {
+-              pgsserr("gss_acquire_cred",
+-                      maj_stat, min_stat, &krb5oid);
+-              return -1;
+-      }
+-
+-      maj_stat = gss_set_allowable_enctypes(&min_stat, credh, &krb5oid,
+-                                           num_enctypes, &enctypes);
+-      if (maj_stat != GSS_S_COMPLETE) {
+-              pgsserr("gss_set_allowable_enctypes",
+-                      maj_stat, min_stat, &krb5oid);
+-              gss_release_cred(&min_stat, &credh);
+-              return -1;
+-      }
+-      sec->cred = credh;
+-
+-      return 0;
+-}
+-#endif        /* HAVE_SET_ALLOWABLE_ENCTYPES */
+-
  /*
-+ * Append the given flavor to the exportent's e_secinfo array, or
-+ * do nothing if it's already there.  Returns the index of flavor
-+ * in the resulting array in any case.
+  * Obtain credentials via a key in the keytab given
+  * a keytab handle and a gssd_k5_kt_princ structure.
+@@ -879,6 +833,56 @@ out:
+       return retval;
+ }
++/*
++ * Parse the supported encryption type information
 + */
-+static int secinfo_addflavor(struct flav_info *flav, struct exportent *ep)
++static int
++parse_enctypes(char *enctypes)
 +{
-+      struct sec_entry *p;
++      int n = 0;
++      char *curr, *comma;
++      int i;
 +
-+      for (p=ep->e_secinfo; p->flav; p++) {
-+              if (p->flav == flav)
-+                      return p - ep->e_secinfo;
++      /* Just in case this ever gets called more than once */
++      if (krb5_enctypes != NULL) {
++              free(krb5_enctypes);
++              krb5_enctypes = NULL;
++              num_krb5_enctypes = 0;
 +      }
-+      if (p - ep->e_secinfo >= SECFLAVOR_COUNT) {
-+              xlog(L_ERROR, "more than %d security flavors on an export\n",
-+                      SECFLAVOR_COUNT);
-+              return -1;
++
++      /* count the number of commas */
++      for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
++              comma = strchr(curr, ',');
++              if (comma != NULL)
++                      n++;
++              else
++                      break;
 +      }
-+      p->flav = flav;
-+      p->flags = ep->e_flags;
-+      (p+1)->flav = NULL;
-+      return p - ep->e_secinfo;
-+}
++      /* If no more commas and we're not at the end, there's one more value */
++      if (*curr != '\0')
++              n++;
 +
-+static struct flav_info *find_flavor(char *name)
-+{
-+      struct flav_info *flav;
-+      for (flav = flav_map; flav < flav_map + flav_map_size; flav++)
-+              if (strcmp(flav->flavour, name) == 0)
-+                      return flav;
-+      return NULL;
++      /* Empty string, return an error */
++      if (n == 0)
++              return ENOENT;
++
++      /* Allocate space for enctypes array */
++      if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
++              return ENOMEM;
++      }
++
++      /* Now parse each value into the array */
++      for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
++              krb5_enctypes[i++] = atoi(curr);
++              comma = strchr(curr, ',');
++              if (comma == NULL)
++                      break;
++      }
++
++      num_krb5_enctypes = n;
++      return 0;
 +}
 +
-+/* @str is a colon seperated list of security flavors.  Their order
-+ * is recorded in @ep, and a bitmap corresponding to the list is returned.
-+ * A zero return indicates an error.
+ /*==========================*/
+ /*===  External routines ===*/
+ /*==========================*/
+@@ -1129,3 +1133,126 @@ gssd_k5_err_msg(krb5_context context, kr
+               return error_message(code);
+ #endif
+ }
++
++#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
++/*
++ * this routine obtains a credentials handle via gss_acquire_cred()
++ * then calls gss_krb5_set_allowable_enctypes() to limit the encryption
++ * types negotiated.
++ *
++ * Returns:
++ *    0 => all went well
++ *     -1 => there was an error
 + */
-+static unsigned int parse_flavors(char *str, struct exportent *ep)
++
++int
++limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid)
 +{
-+      unsigned int out=0;
-+      char *flavor;
-+      int bit;
-+
-+      while ( (flavor=strsep(&str, ":")) ) {
-+              struct flav_info *flav = find_flavor(flavor);
-+              if (flav == NULL) {
-+                      xlog(L_ERROR, "unknown flavor %s\n", flavor);
-+                      return 0;
-+              }
-+              bit = secinfo_addflavor(flav, ep);
-+              if (bit < 0)
-+                      return 0;
-+              out |= 1<<bit;
++      u_int maj_stat, min_stat;
++      gss_cred_id_t credh;
++      gss_OID_set_desc  desired_mechs;
++      krb5_enctype enctypes[] = {ENCTYPE_DES_CBC_CRC};
++      int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
++
++      /* We only care about getting a krb5 cred */
++      desired_mechs.count = 1;
++      desired_mechs.elements = &krb5oid;
++
++      maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
++                                  &desired_mechs, GSS_C_INITIATE,
++                                  &credh, NULL, NULL);
++
++      if (maj_stat != GSS_S_COMPLETE) {
++              pgsserr("gss_acquire_cred",
++                      maj_stat, min_stat, &krb5oid);
++              return -1;
 +      }
-+      return out;
++
++      /*
++       * If we failed for any reason to produce global
++       * list of supported enctypes, use local default here.
++       */
++      if (krb5_enctypes == NULL)
++              maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
++                                      &krb5oid, num_enctypes, &enctypes);
++      else
++              maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
++                                      &krb5oid, num_krb5_enctypes,
++                                      krb5_enctypes);
++      if (maj_stat != GSS_S_COMPLETE) {
++              pgsserr("gss_set_allowable_enctypes",
++                      maj_stat, min_stat, &krb5oid);
++              return -1;
++      }
++      sec->cred = credh;
++
++      return 0;
 +}
++#endif        /* HAVE_SET_ALLOWABLE_ENCTYPES */
 +
-+/* Sets the bits in @mask for the appropriate security flavor flags. */
-+static void setflags(int mask, unsigned int active, struct exportent *ep)
++/*
++ * Obtain supported enctypes from kernel.
++ * Set defaults if info is not available.
++ */
++void
++gssd_obtain_kernel_krb5_info(void)
 +{
-+      int bit=0;
++      char enctype_file_name[128];
++      char buf[1024];
++      char enctypes[128];
++      int nscanned;
++      int fd;
++      int use_default_enctypes = 0;
++      int nbytes, numfields;
++      char default_enctypes[] = "1,3,2";
++      int code;
 +
-+      ep->e_flags |= mask;
++      snprintf(enctype_file_name, sizeof(enctype_file_name),
++               "%s/%s", pipefs_dir, "krb5_info");
++
++      if ((fd = open(enctype_file_name, O_RDONLY)) == -1) {
++              printerr(1, "WARNING: gssd_obtain_kernel_krb5_info: "
++                       "Unable to open '%s'. Unable to determine "
++                       "Kerberos encryption types supported by the "
++                       "kernel; using defaults (%s).\n",
++                       enctype_file_name, default_enctypes);
++              use_default_enctypes = 1;
++              goto do_the_parse;
++      }
++      memset(buf, 0, sizeof(buf));
++      if ((nbytes = read(fd, buf, sizeof(buf)-1)) == -1) {
++              printerr(0, "WARNING: gssd_obtain_kernel_krb5_info: "
++                       "Error reading Kerberos encryption type "
++                       "information file '%s'; using defaults (%s).\n",
++                       enctype_file_name, default_enctypes);
++              use_default_enctypes = 1;
++              close(fd);
++              goto do_the_parse;
++      }
++      close(fd);
++      numfields = sscanf(buf, "enctypes: %s\n%n", enctypes, &nscanned);
++      if (numfields < 1) {
++              printerr(0, "WARNING: gssd_obtain_kernel_krb5_info: "
++                       "error parsing Kerberos encryption type "
++                       "information from file '%s'; using defaults (%s).\n",
++                       enctype_file_name, default_enctypes);
++              use_default_enctypes = 1;
++              goto do_the_parse;
++      }
++      if (nbytes > nscanned) {
++              printerr(2, "gssd_obtain_kernel_krb5_info: "
++                       "Ignoring extra information, '%s', from '%s'\n",
++                       buf+nscanned, enctype_file_name);
++              goto do_the_parse;
++      }
++  do_the_parse:
++      if (use_default_enctypes)
++              strcpy(enctypes, default_enctypes);
 +
-+      while (active) {
-+              if (active & 1)
-+                      ep->e_secinfo[bit].flags |= mask;
-+              bit++;
-+              active >>= 1;
++      if ((code = parse_enctypes(enctypes)) != 0) {
++              printerr(0, "ERROR: gssd_obtain_kernel_krb5_info: "
++                       "parse_enctypes%s failed with code %d\n",
++                       use_default_enctypes ? " (with default enctypes)" : "",
++                       code);
 +      }
 +}
+diff -puN utils/gssd/krb5_util.h~CITI_NFS4_ALL utils/gssd/krb5_util.h
+--- nfs-utils-1.1.1/utils/gssd/krb5_util.h~CITI_NFS4_ALL       2007-10-23 14:17:19.166793000 -0400
++++ nfs-utils-1.1.1-kwc/utils/gssd/krb5_util.h 2007-10-23 14:17:19.206793000 -0400
+@@ -26,6 +26,8 @@ int  gssd_refresh_krb5_machine_credentia
+                                         struct gssd_k5_kt_princ *ple);
+ const char *
+ gssd_k5_err_msg(krb5_context context, krb5_error_code code);
++void gssd_obtain_kernel_krb5_info(void);
++
+ #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
+ int limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid);
+diff -puN utils/gssd/context.h~CITI_NFS4_ALL utils/gssd/context.h
+--- nfs-utils-1.1.1/utils/gssd/context.h~CITI_NFS4_ALL 2007-10-23 14:17:19.330737000 -0400
++++ nfs-utils-1.1.1-kwc/utils/gssd/context.h   2007-10-23 14:17:19.458609000 -0400
+@@ -1,5 +1,5 @@
+ /*
+-  Copyright (c) 2004 The Regents of the University of Michigan.
++  Copyright (c) 2004-2006 The Regents of the University of Michigan.
+   All rights reserved.
+   Redistribution and use in source and binary forms, with or without
+@@ -36,6 +36,10 @@
+ /* Hopefully big enough to hold any serialized context */
+ #define MAX_CTX_LEN 4096
++/* New context format flag values */
++#define KRB5_CTX_FLAG_INITIATOR         0x00000001
++#define KRB5_CTX_FLAG_CFX               0x00000002
++#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
+ int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf,
+                                gss_OID mech);
+diff -puN utils/gssd/context_lucid.c~CITI_NFS4_ALL utils/gssd/context_lucid.c
+--- nfs-utils-1.1.1/utils/gssd/context_lucid.c~CITI_NFS4_ALL   2007-10-23 14:17:19.386681000 -0400
++++ nfs-utils-1.1.1-kwc/utils/gssd/context_lucid.c     2007-10-23 14:17:19.465602000 -0400
+@@ -40,6 +40,7 @@
+ #include <stdio.h>
+ #include <syslog.h>
+ #include <string.h>
++#include <errno.h>
+ #include "gss_util.h"
+ #include "gss_oids.h"
+ #include "err_util.h"
+@@ -113,15 +114,13 @@ prepare_krb5_rfc1964_buffer(gss_krb5_luc
+        * Note that the rfc1964 version only supports DES enctypes.
+        */
+       if (lctx->rfc1964_kd.ctx_key.type != 4) {
+-              printerr(1, "prepare_krb5_rfc1964_buffer: "
+-                          "overriding heimdal keytype (%d => %d)\n",
+-                          lctx->rfc1964_kd.ctx_key.type, 4);
++              printerr(2, "%s: overriding heimdal keytype (%d => %d)\n",
++                       __FUNCTION__, lctx->rfc1964_kd.ctx_key.type, 4);
+               lctx->rfc1964_kd.ctx_key.type = 4;
+       }
+ #endif
+-      printerr(2, "prepare_krb5_rfc1964_buffer: serializing keys with "
+-               "enctype %d and length %d\n",
+-               lctx->rfc1964_kd.ctx_key.type,
++      printerr(2, "%s: serializing keys with enctype %d and length %d\n",
++               __FUNCTION__, lctx->rfc1964_kd.ctx_key.type,
+                lctx->rfc1964_kd.ctx_key.length);
+       /* derive the encryption key and copy it into buffer */
+@@ -152,15 +151,361 @@ out_err:
+       return -1;
+ }
+-static int
+-prepare_krb5_rfc_cfx_buffer(gss_krb5_lucid_context_v1_t *lctx,
+-      gss_buffer_desc *buf)
++/* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
++/* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
++
++/* for 3DES */
++#define KG_USAGE_SEAL 22
++#define KG_USAGE_SIGN 23
++#define KG_USAGE_SEQ  24
++
++/* for rfc???? */
++#define KG_USAGE_ACCEPTOR_SEAL  22
++#define KG_USAGE_ACCEPTOR_SIGN  23
++#define KG_USAGE_INITIATOR_SEAL 24
++#define KG_USAGE_INITIATOR_SIGN 25
++
++/* Lifted from mit src/lib/gssapi/krb5/gssapiP_krb5.h */
++enum seal_alg {
++  SEAL_ALG_NONE            = 0xffff,
++  SEAL_ALG_DES             = 0x0000,
++  SEAL_ALG_1               = 0x0001, /* not published */
++  SEAL_ALG_MICROSOFT_RC4   = 0x0010, /* microsoft w2k;  */
++  SEAL_ALG_DES3KD          = 0x0002
++};
++
++#define KEY_USAGE_SEED_ENCRYPTION     0xAA
++#define KEY_USAGE_SEED_INTEGRITY      0x55
++#define KEY_USAGE_SEED_CHECKSUM               0x99
++#define K5CLENGTH 5
 +
-+/* Clears the bits in @mask for the appropriate security flavor flags. */
-+static void clearflags(int mask, unsigned int active, struct exportent *ep)
++/* Flags for version 2 context flags */
++#define KRB5_CTX_FLAG_INITIATOR               0x00000001
++#define KRB5_CTX_FLAG_CFX             0x00000002
++#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
++
++/* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
++/* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
++/*
++ * We don't have "legal" access to these MIT-only
++ * structures located in libk5crypto
++ */
++extern void krb5int_enc_arcfour;
++extern void krb5int_enc_des3;
++extern void krb5int_enc_aes128;
++extern void krb5int_enc_aes256;
++extern int krb5_derive_key();
++
++static void
++key_lucid_to_krb5(const gss_krb5_lucid_key_t *lin, krb5_keyblock *kout)
+ {
+-      printerr(0, "ERROR: prepare_krb5_rfc_cfx_buffer: not implemented\n");
+-      return -1;
++      memset(kout, '\0', sizeof(kout));
++#ifdef HAVE_KRB5
++      kout->enctype = lin->type;
++      kout->length = lin->length;
++      kout->contents = lin->data;
++#else
++      kout->keytype = lin->type;
++      kout->keyvalue.length = lin->length;
++      kout->keyvalue.data = lin->data;
++#endif
+ }
++static void
++key_krb5_to_lucid(const krb5_keyblock *kin, gss_krb5_lucid_key_t *lout)
++{
++      memset(lout, '\0', sizeof(lout));
++#ifdef HAVE_KRB5
++      lout->type = kin->enctype;
++      lout->length = kin->length;
++      lout->data = kin->contents;
++#else
++      lout->type = kin->keytype;
++      lout->length = kin->keyvalue.length;
++      memcpy(lout->data, kin->keyvalue.data, kin->keyvalue.length);
++#endif
++}
++/* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
++/* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
++/* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
++/* XXX Hack alert! XXX  Do NOT submit upstream! XXX */
++/*
++ * Function to derive a new key from a given key and given constant data.
++ */
++static krb5_error_code
++derive_key_lucid(const gss_krb5_lucid_key_t *in, gss_krb5_lucid_key_t *out,
++               int usage, char extra)
 +{
-+      int bit=0;
++      krb5_error_code code;
++      unsigned char constant_data[K5CLENGTH];
++      krb5_data datain;
++      int keylength;
++      void *enc;
++      krb5_keyblock kin, kout;  /* must send krb5_keyblock, not lucid! */
++#ifdef HAVE_HEIMDAL
++      krb5_context kcontext;
++      krb5_keyblock *outkey;
++#endif
 +
-+      ep->e_flags &= ~mask;
++      /*
++       * XXX Hack alert.  We don't have "legal" access to these
++       * values and structures located in libk5crypto
++       */
++      switch (in->type) {
++      case ENCTYPE_DES3_CBC_SHA1:
++#ifdef HAVE_KRB5
++      case ENCTYPE_DES3_CBC_RAW:
++#endif
++              keylength = 24;
++#ifdef HAVE_KRB5
++              enc = &krb5int_enc_des3;
++#endif
++              break;
++      case ENCTYPE_AES128_CTS_HMAC_SHA1_96:
++              keylength = 16;
++#ifdef HAVE_KRB5
++              enc = &krb5int_enc_aes128;
++#endif
++              break;
++      case ENCTYPE_AES256_CTS_HMAC_SHA1_96:
++              keylength = 32;
++#ifdef HAVE_KRB5
++              enc = &krb5int_enc_aes256;
++#endif
++              break;
++      default:
++              code = KRB5_BAD_ENCTYPE;
++              goto out;
++      }
 +
-+      while (active) {
-+              if (active & 1)
-+                      ep->e_secinfo[bit].flags &= ~mask;
-+              bit++;
-+              active >>= 1;
++      /* allocate memory for output key */
++      if ((out->data = malloc(keylength)) == NULL) {
++              code = ENOMEM;
++              goto out;
 +      }
++      out->length = keylength;
++      out->type = in->type;
++
++      /* Convert to correct format for call to krb5_derive_key */
++      key_lucid_to_krb5(in, &kin);
++      key_lucid_to_krb5(out, &kout);
++
++      datain.data = (char *) constant_data;
++      datain.length = K5CLENGTH;
++
++      ((char *)(datain.data))[0] = (usage>>24)&0xff;
++      ((char *)(datain.data))[1] = (usage>>16)&0xff;
++      ((char *)(datain.data))[2] = (usage>>8)&0xff;
++      ((char *)(datain.data))[3] = usage&0xff;
++
++      ((char *)(datain.data))[4] = (char) extra;
++
++#ifdef HAVE_KRB5
++      code = krb5_derive_key(enc, &kin, &kout, &datain);
++#else
++      if ((code = krb5_init_context(&kcontext))) {
++      }
++      code = krb5_derive_key(kcontext, &kin, in->type, constant_data, K5CLENGTH, &outkey);
++#endif
++      if (code) {
++              free(out->data);
++              out->data = NULL;
++              goto out;
++      }
++#ifdef HAVE_KRB5
++      key_krb5_to_lucid(&kout, out);
++#else
++      key_krb5_to_lucid(outkey, out);
++      krb5_free_keyblock(kcontext, outkey);
++      krb5_free_context(kcontext);
++#endif
++
++  out:
++      if (code)
++              printerr(0, "ERROR: %s: returning error %d (%s)\n",
++                       __FUNCTION__, code, error_message(code));
++      return (code);
 +}
 +
-+/* options that can vary per flavor: */
-+#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
-+                                      | NFSEXP_ALLSQUASH)
 +
 +/*
-  * Parse option string pointed to by cp and set mount options accordingly.
-  */
- static int
- parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr)
++ * Prepare a new-style buffer, as defined in rfc4121 (a.k.a. cfx),
++ * to send to the kernel for newer encryption types -- or for DES3.
++ *
++ * The new format is:
++ *
++ *    u32 initiate;                   ( whether we are the initiator or not )
++ *    s32 endtime;
++ *    u32 flags;
++ *    #define KRB5_CTX_FLAG_INITIATOR         0x00000001
++ *    #define KRB5_CTX_FLAG_CFX               0x00000002
++ *    #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
++ *    u64 seq_send;
++ *    u32  enctype;                   ( encrption type of keys )
++ *    u32  size_of_each_key;          ( size of each key in bytes )
++ *    u32  number_of_keys;            ( N -- should always be 3 for now )
++ *    keydata-1;                      ( Ke )
++ *    keydata-2;                      ( Ki )
++ *    keydata-3;                      ( Kc )
++ *
++ */
++static int
++prepare_krb5_rfc4121_buffer(gss_krb5_lucid_context_v1_t *lctx,
++                          gss_buffer_desc *buf)
++{
++      char *p, *end;
++      uint32_t v2_flags = 0;
++      gss_krb5_lucid_key_t enc_key;
++      gss_krb5_lucid_key_t derived_key;
++      gss_buffer_desc fakeoid;
++      uint32_t enctype;
++      uint32_t keysize;
++      uint32_t numkeys;
++
++      memset(&enc_key, 0, sizeof(enc_key));
++      memset(&fakeoid, 0, sizeof(fakeoid));
++
++      if (!(buf->value = calloc(1, MAX_CTX_LEN)))
++              goto out_err;
++      p = buf->value;
++      end = buf->value + MAX_CTX_LEN;
++
++      /* Version 2 */
++      if (WRITE_BYTES(&p, end, lctx->initiate)) goto out_err;
++      if (WRITE_BYTES(&p, end, lctx->endtime)) goto out_err;
++
++      if (lctx->initiate)
++              v2_flags |= KRB5_CTX_FLAG_INITIATOR;
++      if (lctx->protocol != 0)
++              v2_flags |= KRB5_CTX_FLAG_CFX;
++      if (lctx->protocol != 0 && lctx->cfx_kd.have_acceptor_subkey == 1)
++              v2_flags |= KRB5_CTX_FLAG_ACCEPTOR_SUBKEY;
++
++      if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
++
++      if (WRITE_BYTES(&p, end, lctx->send_seq)) goto out_err;
++
++      /* Protocol 0 here implies DES3 or RC4 */
++      printerr(2, "%s: protocol %d\n", __FUNCTION__, lctx->protocol);
++      if (lctx->protocol == 0) {
++              enctype = lctx->rfc1964_kd.ctx_key.type;
++#ifdef HAVE_HEIMDAL
++              /*
++               * The kernel gss code expects ENCTYPE_DES3_CBC_RAW (6) for
++               * 3des keys, but Heimdal key has ENCTYPE_DES3_CBC_SHA1 (16).
++               * Force the Heimdal enctype to 6.
++               */
++              if (enctype == ENCTYPE_DES3_CBC_SHA1) {
++                      printerr(2, "%s: overriding heimdal keytype (%d => %d)\n",
++                               __FUNCTION__, enctype, 6);
++
++                      enctype = 6;
++              }
++#endif
++              keysize = lctx->rfc1964_kd.ctx_key.length;
++              numkeys = 3;    /* XXX is always gonna be three? */
++      } else {
++              if (lctx->cfx_kd.have_acceptor_subkey) {
++                      enctype = lctx->cfx_kd.acceptor_subkey.type;
++                      keysize = lctx->cfx_kd.acceptor_subkey.length;
++              } else {
++                      enctype = lctx->cfx_kd.ctx_key.type;
++                      keysize = lctx->cfx_kd.ctx_key.length;
++              }
++              numkeys = 3;
++      }
++      printerr(2, "%s: serializing %d keys with enctype %d and size %d\n",
++               __FUNCTION__, numkeys, enctype, keysize);
++      if (WRITE_BYTES(&p, end, enctype)) goto out_err;
++      if (WRITE_BYTES(&p, end, keysize)) goto out_err;
++      if (WRITE_BYTES(&p, end, numkeys)) goto out_err;
++
++      if (lctx->protocol == 0) {
++              /* derive and send down: Ke, Ki, and Kc */
++              /* Ke */
++              if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
++                              lctx->rfc1964_kd.ctx_key.length))
++                      goto out_err;
++
++              /* Ki */
++              if (write_bytes(&p, end, lctx->rfc1964_kd.ctx_key.data,
++                              lctx->rfc1964_kd.ctx_key.length))
++                      goto out_err;
++
++              /* Kc */
++              if (derive_key_lucid(&lctx->rfc1964_kd.ctx_key,
++                              &derived_key,
++                              KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM))
++                      goto out_err;
++              if (write_bytes(&p, end, derived_key.data,
++                              derived_key.length))
++                      goto out_err;
++              free(derived_key.data);
++      } else {
++              gss_krb5_lucid_key_t *keyptr;
++              uint32_t sign_usage, seal_usage;
++
++              if (lctx->cfx_kd.have_acceptor_subkey)
++                      keyptr = &lctx->cfx_kd.acceptor_subkey;
++              else
++                      keyptr = &lctx->cfx_kd.ctx_key;
++
++              if (lctx->initiate == 1) {
++                      sign_usage = KG_USAGE_INITIATOR_SIGN;
++                      seal_usage = KG_USAGE_INITIATOR_SEAL;
++              } else {
++                      sign_usage = KG_USAGE_ACCEPTOR_SIGN;
++                      seal_usage = KG_USAGE_ACCEPTOR_SEAL;
++              }
++
++              /* derive and send down: Ke, Ki, and Kc */
++
++              /* Ke */
++              if (derive_key_lucid(keyptr, &derived_key,
++                             seal_usage, KEY_USAGE_SEED_ENCRYPTION))
++                      goto out_err;
++              if (write_bytes(&p, end, derived_key.data,
++                              derived_key.length))
++                      goto out_err;
++              free(derived_key.data);
++
++              /* Ki */
++              if (derive_key_lucid(keyptr, &derived_key,
++                             seal_usage, KEY_USAGE_SEED_INTEGRITY))
++                      goto out_err;
++              if (write_bytes(&p, end, derived_key.data,
++                              derived_key.length))
++                      goto out_err;
++              free(derived_key.data);
++
++              /* Kc */
++              if (derive_key_lucid(keyptr, &derived_key,
++                             sign_usage, KEY_USAGE_SEED_CHECKSUM))
++                      goto out_err;
++              if (write_bytes(&p, end, derived_key.data,
++                              derived_key.length))
++                      goto out_err;
++              free(derived_key.data);
++      }
++
++      buf->length = p - (char *)buf->value;
++      return 0;
++
++out_err:
++      printerr(0, "ERROR: %s: failed serializing krb5 context for kernel\n",
++               __FUNCTION__);
++      if (buf->value) {
++              free(buf->value);
++              buf->value = NULL;
++      }
++      buf->length = 0;
++      if (enc_key.data) {
++              free(enc_key.data);
++              enc_key.data = NULL;
++      }
++      return -1;
++}
+ int
+ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf)
  {
-+      struct sec_entry *p;
-       int     had_subtree_opt = 0;
-       char    *flname = efname?efname:"command line";
-       int     flline = efp?efp->x_line:0;
-+      unsigned int active = 0;
-       squids = ep->e_squids; nsquids = ep->e_nsquids;
-       sqgids = ep->e_sqgids; nsqgids = ep->e_nsqgids;
--
-       if (!cp)
-               goto out;
-@@ -380,9 +516,9 @@ parseopts(char *cp, struct exportent *ep
-               /* process keyword */
-               if (strcmp(opt, "ro") == 0)
--                      ep->e_flags |= NFSEXP_READONLY;
-+                      setflags(NFSEXP_READONLY, active, ep);
-               else if (strcmp(opt, "rw") == 0)
--                      ep->e_flags &= ~NFSEXP_READONLY;
-+                      clearflags(NFSEXP_READONLY, active, ep);
-               else if (!strcmp(opt, "secure"))
-                       ep->e_flags &= ~NFSEXP_INSECURE_PORT;
-               else if (!strcmp(opt, "insecure"))
-@@ -404,13 +540,13 @@ parseopts(char *cp, struct exportent *ep
-               else if (!strcmp(opt, "no_wdelay"))
-                       ep->e_flags &= ~NFSEXP_GATHERED_WRITES;
-               else if (strcmp(opt, "root_squash") == 0)
--                      ep->e_flags |= NFSEXP_ROOTSQUASH;
-+                      setflags(NFSEXP_ROOTSQUASH, active, ep);
-               else if (!strcmp(opt, "no_root_squash"))
--                      ep->e_flags &= ~NFSEXP_ROOTSQUASH;
-+                      clearflags(NFSEXP_ROOTSQUASH, active, ep);
-               else if (strcmp(opt, "all_squash") == 0)
--                      ep->e_flags |= NFSEXP_ALLSQUASH;
-+                      setflags(NFSEXP_ALLSQUASH, active, ep);
-               else if (strcmp(opt, "no_all_squash") == 0)
--                      ep->e_flags &= ~NFSEXP_ALLSQUASH;
-+                      clearflags(NFSEXP_ALLSQUASH, active, ep);
-               else if (strcmp(opt, "subtree_check") == 0) {
-                       had_subtree_opt = 1;
-                       ep->e_flags &= ~NFSEXP_NOSUBTREECHECK;
-@@ -498,6 +634,10 @@ bad_option:
-               } else if (strncmp(opt, "replicas=", 9) == 0) {
-                       ep->e_fslocmethod = FSLOC_REPLICA;
-                       ep->e_fslocdata = strdup(opt+9);
-+              } else if (strncmp(opt, "sec=", 4) == 0) {
-+                      active = parse_flavors(opt+4, ep);
-+                      if (!active)
-+                              goto bad_option;
-               } else {
-                       xlog(L_ERROR, "%s:%d: unknown keyword \"%s\"\n",
-                                       flname, flline, opt);
-@@ -509,6 +649,8 @@ bad_option:
-                       cp++;
-       }
+@@ -170,7 +515,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
+       gss_krb5_lucid_context_v1_t *lctx = 0;
+       int retcode = 0;
  
-+      for (p = ep->e_secinfo; p->flav; p++)
-+              p->flags |= ep->e_flags & ~NFSEXP_SECINFO_FLAGS;
-       ep->e_squids = squids;
-       ep->e_sqgids = sqgids;
-       ep->e_nsquids = nsquids;
-diff -puN utils/mount/nfs4mount.c~CITI_NFS4_ALL utils/mount/nfs4mount.c
---- nfs-utils-1.1.0/utils/mount/nfs4mount.c~CITI_NFS4_ALL      2007-06-22 10:52:18.413097000 -0400
-+++ nfs-utils-1.1.0-kwc/utils/mount/nfs4mount.c        2007-06-22 10:52:25.846889000 -0400
-@@ -36,6 +36,7 @@
- #define nfsstat nfs_stat
- #endif
+-      printerr(2, "DEBUG: serialize_krb5_ctx: lucid version!\n");
++      printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__);
+       maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx,
+                                               1, &return_ctx);
+       if (maj_stat != GSS_S_COMPLETE) {
+@@ -192,11 +537,20 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
+               break;
+       }
  
-+#include "pseudoflavors.h"
- #include "nls.h"
- #include "conn.h"
- #include "xcommon.h"
-@@ -71,26 +72,6 @@ char *GSSDLCK = DEFAULT_DIR "/rpcgssd";
- #define NFS_PORT 2049
- #endif
+-      /* Now lctx points to a lucid context that we can send down to kernel */
+-      if (lctx->protocol == 0)
++        /*
++       * Now lctx points to a lucid context that we can send down to kernel
++       *
++       * Note: we send down different information to the kernel depending
++       * on the protocol version and the enctyption type.
++       * For protocol version 0 with all enctypes besides DES3, we use
++       * the original format.  For protocol version != 0 or DES3, we
++       * send down the new style information.
++       */
++
++      if (lctx->protocol == 0 && lctx->rfc1964_kd.ctx_key.type <= 4)
+               retcode = prepare_krb5_rfc1964_buffer(lctx, buf);
+       else
+-              retcode = prepare_krb5_rfc_cfx_buffer(lctx, buf);
++              retcode = prepare_krb5_rfc4121_buffer(lctx, buf);
  
--struct {
--      char    *flavour;
--      int     fnum;
--} flav_map[] = {
--      { "krb5",       RPC_AUTH_GSS_KRB5       },
--      { "krb5i",      RPC_AUTH_GSS_KRB5I      },
--      { "krb5p",      RPC_AUTH_GSS_KRB5P      },
--      { "lipkey",     RPC_AUTH_GSS_LKEY       },
--      { "lipkey-i",   RPC_AUTH_GSS_LKEYI      },
--      { "lipkey-p",   RPC_AUTH_GSS_LKEYP      },
--      { "spkm3",      RPC_AUTH_GSS_SPKM       },
--      { "spkm3i",     RPC_AUTH_GSS_SPKMI      },
--      { "spkm3p",     RPC_AUTH_GSS_SPKMP      },
--      { "unix",       AUTH_UNIX               },
--      { "sys",        AUTH_SYS                },
--      { "null",       AUTH_NULL               },
--      { "none",       AUTH_NONE               },
--};
--
--#define FMAPSIZE              (sizeof(flav_map)/sizeof(flav_map[0]))
- #define MAX_USER_FLAVOUR      16
+       maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, return_ctx);
+       if (maj_stat != GSS_S_COMPLETE) {
+@@ -206,8 +560,8 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
+       }
  
- static int parse_sec(char *sec, int *pseudoflavour)
-@@ -104,13 +85,13 @@ static int parse_sec(char *sec, int *pse
-                                 "exceeded\n"));
-                       return 0;
-               }
--              for (i = 0; i < FMAPSIZE; i++) {
-+              for (i = 0; i < flav_map_size; i++) {
-                       if (strcmp(sec, flav_map[i].flavour) == 0) {
-                               pseudoflavour[num_flavour++] = flav_map[i].fnum;
-                               break;
-                       }
-               }
--              if (i == FMAPSIZE) {
-+              if (i == flav_map_size) {
-                       fprintf(stderr,
-                               _("mount: unknown security type %s\n"), sec);
-                       return 0;
-@@ -399,7 +380,7 @@ int nfs4mount(const char *spec, const ch
-               printf("sec = ");
-               for (pf_cnt = 0; pf_cnt < num_flavour; pf_cnt++) {
--                      for (i = 0; i < FMAPSIZE; i++) {
-+                      for (i = 0; i < flav_map_size; i++) {
-                               if (flav_map[i].fnum == pseudoflavour[pf_cnt]) {
-                                       printf("%s", flav_map[i].flavour);
-                                       break;
-diff -puN utils/mount/nfs4_mount.h~CITI_NFS4_ALL utils/mount/nfs4_mount.h
---- nfs-utils-1.1.0/utils/mount/nfs4_mount.h~CITI_NFS4_ALL     2007-06-22 10:52:21.626744000 -0400
-+++ nfs-utils-1.1.0-kwc/utils/mount/nfs4_mount.h       2007-06-22 10:52:24.715391000 -0400
-@@ -67,18 +67,6 @@ struct nfs4_mount_data {
- #define NFS4_MOUNT_STRICTLOCK 0x1000  /* 1 */
- #define NFS4_MOUNT_FLAGMASK   0xFFFF
--/* pseudoflavors: */
--
--#define RPC_AUTH_GSS_KRB5       390003
--#define RPC_AUTH_GSS_KRB5I      390004
--#define RPC_AUTH_GSS_KRB5P      390005
--#define RPC_AUTH_GSS_LKEY       390006
--#define RPC_AUTH_GSS_LKEYI      390007
--#define RPC_AUTH_GSS_LKEYP      390008
--#define RPC_AUTH_GSS_SPKM       390009
--#define RPC_AUTH_GSS_SPKMI      390010
--#define RPC_AUTH_GSS_SPKMP      390011
--
- int nfs4mount(const char *, const char *, int *, char **,
-       char **, int);
-diff -puN support/include/nfslib.h~CITI_NFS4_ALL support/include/nfslib.h
---- nfs-utils-1.1.0/support/include/nfslib.h~CITI_NFS4_ALL     2007-06-22 10:52:31.311234000 -0400
-+++ nfs-utils-1.1.0-kwc/support/include/nfslib.h       2007-06-22 10:52:39.718626000 -0400
-@@ -51,6 +51,14 @@
- #define       _PATH_PROC_EXPORTS_ALT  "/proc/fs/nfsd/exports"
- #endif
+       if (retcode) {
+-              printerr(1, "serialize_krb5_ctx: prepare_krb5_*_buffer "
+-                       "failed (retcode = %d)\n", retcode);
++              printerr(1, "%s: prepare_krb5_*_buffer failed (retcode = %d)\n",
++                       __FUNCTION__, retcode);
+               goto out_err;
+       }
  
-+/* Maximum number of security flavors on an export: */
-+#define SECFLAVOR_COUNT 8
+@@ -217,4 +571,7 @@ out_err:
+       printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
+       return -1;
+ }
 +
-+struct sec_entry {
-+      struct flav_info *flav;
-+      int flags;
-+};
 +
++
+ #endif /* HAVE_LUCID_CONTEXT_SUPPORT */
+diff -puN utils/gssd/context_mit.c~CITI_NFS4_ALL utils/gssd/context_mit.c
+--- nfs-utils-1.1.1/utils/gssd/context_mit.c~CITI_NFS4_ALL     2007-10-23 14:17:19.441626000 -0400
++++ nfs-utils-1.1.1-kwc/utils/gssd/context_mit.c       2007-10-23 14:17:19.473594000 -0400
+@@ -1,5 +1,5 @@
  /*
-  * Data related to a single exports entry as returned by getexportent.
-  * FIXME: export options should probably be parsed at a later time to
-@@ -76,6 +84,7 @@ struct exportent {
-       int             e_fslocmethod;
-       char *          e_fslocdata;
-       char *          e_uuid;
-+      struct sec_entry e_secinfo[SECFLAVOR_COUNT+1];
- };
+-  Copyright (c) 2004 The Regents of the University of Michigan.
++  Copyright (c) 2004-2006 The Regents of the University of Michigan.
+   All rights reserved.
  
- struct rmtabent {
-@@ -89,6 +98,7 @@ struct rmtabent {
-  */
- void                  setexportent(char *fname, char *type);
- struct exportent *    getexportent(int,int);
-+void                  secinfo_show(FILE *fp, struct exportent *ep);
- void                  putexportent(struct exportent *xep);
- void                  endexportent(void);
- struct exportent *    mkexportent(char *hname, char *path, char *opts);
-diff -puN utils/exportfs/exportfs.c~CITI_NFS4_ALL utils/exportfs/exportfs.c
---- nfs-utils-1.1.0/utils/exportfs/exportfs.c~CITI_NFS4_ALL    2007-06-22 10:52:33.386332000 -0400
-+++ nfs-utils-1.1.0-kwc/utils/exportfs/exportfs.c      2007-06-22 10:52:40.698175000 -0400
-@@ -515,6 +515,7 @@ dump(int verbose)
-                               break;
- #endif
-                       }
-+                      secinfo_show(stdout, ep);
-                       printf("%c\n", (c != '(')? ')' : ' ');
-               }
-       }
-diff -puN utils/mountd/cache.c~CITI_NFS4_ALL utils/mountd/cache.c
---- nfs-utils-1.1.0/utils/mountd/cache.c~CITI_NFS4_ALL 2007-06-22 10:52:38.862018000 -0400
-+++ nfs-utils-1.1.0-kwc/utils/mountd/cache.c   2007-06-22 10:52:40.837142000 -0400
-@@ -30,6 +30,7 @@
- #include "mountd.h"
- #include "xmalloc.h"
- #include "fsloc.h"
-+#include "pseudoflavors.h"
- #ifdef USE_BLKID
- #include "blkid/blkid.h"
-@@ -518,6 +519,25 @@ static void write_fsloc(FILE *f, struct 
-       release_replicas(servers);
+   Redistribution and use in source and binary forms, with or without
+@@ -36,6 +36,7 @@
+ #include <stdio.h>
+ #include <syslog.h>
+ #include <string.h>
++#include <errno.h>
+ #include <gssapi/gssapi.h>
+ #include <rpc/rpc.h>
+ #include <rpc/auth_gss.h>
+@@ -50,8 +51,7 @@
+ /* XXX argggg, there's gotta be a better way than just duplicating this
+  * whole struct.  Unfortunately, this is in a "private" header file,
+  * so this is our best choice at this point :-/
+- *
+- * XXX Does this match the Heimdal definition?  */
++ */
+ typedef struct _krb5_gss_ctx_id_rec {
+    unsigned int initiate : 1;   /* nonzero if initiating, zero if accepting */
+@@ -139,6 +139,124 @@ write_keyblock(char **p, char *end, stru
  }
  
-+static void write_secinfo(FILE *f, struct exportent *ep)
+ /*
++ * XXX Hack alert! XXX Do NOT submit upstream!
++ * XXX Hack alert! XXX Do NOT submit upstream!
++ *
++ * We shouldn't be using these definitions
++ *
++ * XXX Hack alert! XXX Do NOT submit upstream!
++ * XXX Hack alert! XXX Do NOT submit upstream!
++ */
++/* for 3DES */
++#define KG_USAGE_SEAL 22
++#define KG_USAGE_SIGN 23
++#define KG_USAGE_SEQ  24
++
++/* for rfc???? */
++#define KG_USAGE_ACCEPTOR_SEAL  22
++#define KG_USAGE_ACCEPTOR_SIGN  23
++#define KG_USAGE_INITIATOR_SEAL 24
++#define KG_USAGE_INITIATOR_SIGN 25
++
++/* Lifted from mit src/lib/gssapi/krb5/gssapiP_krb5.h */
++enum seal_alg {
++  SEAL_ALG_NONE            = 0xffff,
++  SEAL_ALG_DES             = 0x0000,
++  SEAL_ALG_1               = 0x0001, /* not published */
++  SEAL_ALG_MICROSOFT_RC4   = 0x0010, /* microsoft w2k;  */
++  SEAL_ALG_DES3KD          = 0x0002
++};
++
++#define KEY_USAGE_SEED_ENCRYPTION     0xAA
++#define KEY_USAGE_SEED_INTEGRITY      0x55
++#define KEY_USAGE_SEED_CHECKSUM               0x99
++#define K5CLENGTH 5
++
++extern void krb5_enc_des3;
++extern void krb5int_enc_des3;
++extern void krb5int_enc_arcfour;
++extern void krb5int_enc_aes128;
++extern void krb5int_enc_aes256;
++extern int krb5_derive_key();
++
++/*
++ * XXX Hack alert! XXX Do NOT submit upstream!
++ * XXX Hack alert! XXX Do NOT submit upstream!
++ *
++ * We should be passing down a single key to the kernel
++ * and it should be deriving the other keys.  We cannot
++ * depend on any of this stuff being accessible in the
++ * future.
++ *
++ * XXX Hack alert! XXX Do NOT submit upstream!
++ * XXX Hack alert! XXX Do NOT submit upstream!
++ */
++/*
++ * Function to derive a new key from a given key and given constant data.
++ */
++static krb5_error_code
++derive_key(const krb5_keyblock *in, krb5_keyblock *out, int usage, char extra)
 +{
-+      struct sec_entry *p;
++      krb5_error_code code;
++      unsigned char constant_data[K5CLENGTH];
++      krb5_data datain;
++      int keylength;
++      void *enc;
 +
-+      for (p = ep->e_secinfo; p->flav; p++)
-+              ; /* Do nothing */
-+      if (p == ep->e_secinfo) {
-+              /* There was no sec= option */
-+              return;
++      switch (in->enctype) {
++#ifdef ENCTYPE_DES3_CBC_RAW
++      case ENCTYPE_DES3_CBC_RAW:
++              keylength = 24;
++/* Extra hack, the structure was renamed as rc4 was added... */
++#if defined(ENCTYPE_ARCFOUR_HMAC)
++              enc = &krb5int_enc_des3;
++#else
++              enc = &krb5_enc_des3;
++#endif
++              break;
++#endif
++#ifdef ENCTYPE_ARCFOUR_HMAC
++      case ENCTYPE_ARCFOUR_HMAC:
++              keylength = 16;
++              enc = &krb5int_enc_arcfour;
++              break;
++#endif
++      default:
++              code = KRB5_BAD_ENCTYPE;
++              goto out;
 +      }
-+      qword_print(f, "secinfo");
-+      qword_printint(f, p - ep->e_secinfo);
-+      for (p = ep->e_secinfo; p->flav; p++) {
-+              qword_printint(f, p->flav->fnum);
-+              qword_printint(f, p->flags);
++
++      /* allocate memory for output key */
++      if ((out->contents = malloc(keylength)) == NULL) {
++              code = ENOMEM;
++              goto out;
++      }
++      out->length = keylength;
++      out->enctype = in->enctype;
++
++      datain.data = (char *) constant_data;
++      datain.length = K5CLENGTH;
++
++      datain.data[0] = (usage>>24)&0xff;
++      datain.data[1] = (usage>>16)&0xff;
++      datain.data[2] = (usage>>8)&0xff;
++      datain.data[3] = usage&0xff;
++
++      datain.data[4] = (char) extra;
++
++      if ((code = krb5_derive_key(enc, in, out, &datain))) {
++              free(out->contents);
++              out->contents = NULL;
 +      }
 +
++  out:
++      if (code)
++              printerr(0, "ERROR: derive_key returning error %d (%s)\n",
++                       code, error_message(code));
++      return (code);
 +}
 +
- static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *exp)
++/*
+  * We really shouldn't know about glue-layer context structure, but
+  * we need to get at the real krb5 context pointer.  This should be
+  * removed as soon as we say there is no support for MIT Kerberos
+@@ -154,48 +272,124 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss
  {
-       qword_print(f, domain);
-@@ -529,6 +549,7 @@ static int dump_to_cache(FILE *f, char *
-               qword_printint(f, exp->e_anongid);
-               qword_printint(f, exp->e_fsid);
-               write_fsloc(f, exp, path);
-+              write_secinfo(f, exp);
- #if USE_BLKID
-               if (exp->e_uuid == NULL) {
-                       char u[16];
-
-_
+       krb5_gss_ctx_id_t kctx = ((gss_union_ctx_id_t)ctx)->internal_ctx_id;
+       char *p, *end;
+-      static int constant_one = 1;
+       static int constant_zero = 0;
++      static int constant_one = 1;
++      static int constant_two = 2;
+       uint32_t word_seq_send;
++      u_int64_t seq_send_64bit;
++      uint32_t v2_flags = 0;
++      krb5_keyblock derived_key;
++      uint32_t numkeys;
+       if (!(buf->value = calloc(1, MAX_CTX_LEN)))
+               goto out_err;
+       p = buf->value;
+       end = buf->value + MAX_CTX_LEN;
+-      if (kctx->initiate) {
+-              if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
+-      }
+-      else {
+-              if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
+-      }
+-      if (kctx->seed_init) {
+-              if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
+-      }
+-      else {
+-              if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
+-      }
+-      if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
++      switch (kctx->sealalg) {
++      case SEAL_ALG_DES:
++              /* Old format of context to the kernel */
++              if (kctx->initiate) {
++                      if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
++              }
++              else {
++                      if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
++              }
++              if (kctx->seed_init) {
++                      if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
++              }
++              else {
++                      if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
++              }
++              if (write_bytes(&p, end, &kctx->seed, sizeof(kctx->seed)))
++                      goto out_err;
++              if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err;
++              if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err;
++              if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
++              word_seq_send = kctx->seq_send;
++              if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err;
++              if (write_oid(&p, end, kctx->mech_used)) goto out_err;
++
++              printerr(2, "serialize_krb5_ctx: serializing keys with "
++                       "enctype %d and length %d\n",
++                       kctx->enc->enctype, kctx->enc->length);
++
++              if (write_keyblock(&p, end, kctx->enc)) goto out_err;
++              if (write_keyblock(&p, end, kctx->seq)) goto out_err;
++              break;
++      case SEAL_ALG_MICROSOFT_RC4:
++      case SEAL_ALG_DES3KD:
++              /* New format of context to the kernel */
++              /* s32 endtime;
++               * u32 flags;
++               * #define KRB5_CTX_FLAG_INITIATOR        0x00000001
++               * #define KRB5_CTX_FLAG_CFX              0x00000002
++               * #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY  0x00000004
++               * u64 seq_send;
++               * u32  enctype;
++               * u32  size_of_each_key;    (  size in bytes )
++               * u32  number_of_keys;      (  N (assumed to be 3 for now) )
++               * keydata-1;                (  Ke  (Kenc for DES3) )
++               * keydata-2;                (  Ki  (Kseq for DES3) )
++               * keydata-3;                (  Kc (derived checksum key) )
++               */
++              if (kctx->initiate) {
++                      if (WRITE_BYTES(&p, end, constant_one)) goto out_err;
++              }
++              else {
++                      if (WRITE_BYTES(&p, end, constant_zero)) goto out_err;
++              }
++              if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
++
++              /* Only applicable flag for this is initiator */
++              if (kctx->initiate) v2_flags |= KRB5_CTX_FLAG_INITIATOR;
++              if (WRITE_BYTES(&p, end, v2_flags)) goto out_err;
++
++              seq_send_64bit = kctx->seq_send;
++              if (WRITE_BYTES(&p, end, seq_send_64bit)) goto out_err;
++
++              if (WRITE_BYTES(&p, end, kctx->enc->enctype)) goto out_err;
++              if (WRITE_BYTES(&p, end, kctx->enc->length)) goto out_err;
++              numkeys = 3;
++              if (WRITE_BYTES(&p, end, numkeys)) goto out_err;
++              printerr(2, "serialize_krb5_ctx: serializing %d keys with "
++                       "enctype %d and size %d\n",
++                       numkeys, kctx->enc->enctype, kctx->enc->length);
++
++              /* Ke */
++              if (write_bytes(&p, end, kctx->enc->contents,
++                              kctx->enc->length))
++                      goto out_err;
++
++              /* Ki */
++              if (write_bytes(&p, end, kctx->enc->contents,
++                              kctx->enc->length))
++                      goto out_err;
++
++              /* Kc */
++              if (derive_key(kctx->seq, &derived_key,
++                             KG_USAGE_SIGN, KEY_USAGE_SEED_CHECKSUM))
++                      goto out_err;
++              if (write_bytes(&p, end, derived_key.contents,
++                              derived_key.length))
++                      goto out_err;
++              free(derived_key.contents);
++              break;
++      default:
++              printerr(0, "ERROR: serialize_krb5_ctx: unsupported seal "
++                       "algorithm %d\n", kctx->sealalg);
+               goto out_err;
+-      if (WRITE_BYTES(&p, end, kctx->signalg)) goto out_err;
+-      if (WRITE_BYTES(&p, end, kctx->sealalg)) goto out_err;
+-      if (WRITE_BYTES(&p, end, kctx->endtime)) goto out_err;
+-      word_seq_send = kctx->seq_send;
+-      if (WRITE_BYTES(&p, end, word_seq_send)) goto out_err;
+-      if (write_oid(&p, end, kctx->mech_used)) goto out_err;
+-
+-      printerr(2, "serialize_krb5_ctx: serializing keys with "
+-               "enctype %d and length %d\n",
+-               kctx->enc->enctype, kctx->enc->length);
+-
+-      if (write_keyblock(&p, end, kctx->enc)) goto out_err;
+-      if (write_keyblock(&p, end, kctx->seq)) goto out_err;
++      }
+       buf->length = p - (char *)buf->value;
+       return 0;
++
+ out_err:
+       printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
+-      if (buf->value) free(buf->value);
++      if (buf->value) {
++              free(buf->value);
++      }
++      buf->value = NULL;
+       buf->length = 0;
+       return -1;
+ }
This page took 0.193524 seconds and 4 git commands to generate.