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 ⅇ
+- 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;
+ }