Add support for mounting NFSv3 with gss security. From Frank Cusack. Modified to define all the security flavors mentioned in rfc3530, even if they aren't implemented yet, and to fail in the case of an unrecognized security flavor instead of giving a warning and falling back on auth_sys. mount/nfs.5 | 13 ++++++- mount/nfs_mount4.h | 4 +- mount/nfsmount.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 4 deletions(-) diff -puN mount/nfs.5~fc-nfsv3-sec mount/nfs.5 --- util-linux-2.11z/mount/nfs.5~fc-nfsv3-sec 2003-12-18 17:06:44.000000000 -0500 +++ util-linux-2.11z-bfields/mount/nfs.5 2003-12-18 17:06:44.000000000 -0500 @@ -128,7 +128,7 @@ mount daemon program number. Use an alternate RPC version number to contact the mount daemon on the remote host. This option is useful for hosts that can run multiple NFS servers. -The default value is version 1. +The default value is kernel dependent. .TP 1.5i .I nfsprog=n Use an alternate RPC program number to contact the @@ -141,7 +141,7 @@ NFS daemon program number. Use an alternate RPC version number to contact the NFS daemon on the remote host. This option is useful for hosts that can run multiple NFS servers. -The default value is version 2. +The default value is kernel dependent. .TP 1.5i .I nolock Disable NFS locking. Do not start lockd. @@ -197,6 +197,15 @@ server performance penalty but it allows to get reasonable good results when both clients are actively writing to common filesystem on the server. .TP 1.5i +.I sec=flavor +Set the security flavor for NFS transactions. The default flavor +is \f3sys\f1, +which uses local unix uid/gid credentials. Other allowable values are +\f3krb5\f1, using Kerberos for authentication; +\f3krb5i\f1, using Kerberos for authentication and integrity protection; and +\f3krb5p\f1, using Kerberos for authentication, integrity protection, +and privacy. +.TP 1.5i .I tcp Mount the NFS filesystem using the TCP protocol instead of the default UDP protocol. Many NFS servers only support UDP. diff -puN mount/nfs_mount4.h~fc-nfsv3-sec mount/nfs_mount4.h --- util-linux-2.11z/mount/nfs_mount4.h~fc-nfsv3-sec 2003-12-18 17:06:44.000000000 -0500 +++ util-linux-2.11z-bfields/mount/nfs_mount4.h 2003-12-18 17:06:44.000000000 -0500 @@ -8,7 +8,7 @@ * so it is easiest to ignore the kernel altogether (at compile time). */ -#define NFS_MOUNT_VERSION 4 +#define NFS_MOUNT_VERSION 5 struct nfs2_fh { char data[32]; @@ -36,6 +36,7 @@ struct nfs_mount_data { int namlen; /* 2 */ unsigned int bsize; /* 3 */ struct nfs3_fh root; /* 4 */ + int pseudoflavor; /* 5 */ }; /* bits in the flags field */ @@ -51,4 +52,5 @@ struct nfs_mount_data { #define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ #define NFS_MOUNT_NONLM 0x0200 /* 3 */ #define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */ +#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ diff -puN mount/nfsmount.c~fc-nfsv3-sec mount/nfsmount.c --- util-linux-2.11z/mount/nfsmount.c~fc-nfsv3-sec 2003-12-18 17:06:44.000000000 -0500 +++ util-linux-2.11z-bfields/mount/nfsmount.c 2003-12-18 17:06:44.000000000 -0500 @@ -72,6 +72,18 @@ #define NFS_FHSIZE 32 #endif +#ifndef AUTH_GSS_KRB5 +#define AUTH_GSS_KRB5 390003 +#define AUTH_GSS_KRB5I 390004 +#define AUTH_GSS_KRB5P 390005 +#define AUTH_GSS_LKEY 390006 +#define AUTH_GSS_LKEYI 390007 +#define AUTH_GSS_LKEYP 390008 +#define AUTH_GSS_SPKM 390009 +#define AUTH_GSS_SPKMI 390010 +#define AUTH_GSS_SPKMP 390011 +#endif + static char *nfs_strerror(int stat); #define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) @@ -119,8 +131,10 @@ find_kernel_nfs_mount_version(void) { nfs_mount_version = 4; /* since 2.2.18pre9 */ else if (kernel_version < MAKE_VERSION(2,3,99)) nfs_mount_version = 3; + else if (kernel_version < MAKE_VERSION(2,6,0)) + nfs_mount_version = 4; else - nfs_mount_version = 4; /* since 2.3.99pre4 */ + nfs_mount_version = 5; } if (nfs_mount_version > NFS_MOUNT_VERSION) nfs_mount_version = NFS_MOUNT_VERSION; @@ -219,6 +233,7 @@ int nfsmount(const char *spec, const cha int posix, nocto, noac, nolock, broken_suid; int retry, tcp; int mountprog, mountvers, nfsprog, nfsvers; + char *secflavor; int retval; time_t t; time_t prevt; @@ -308,6 +323,7 @@ int nfsmount(const char *spec, const cha #if NFS_MOUNT_VERSION >= 2 data.namlen = NAME_MAX; #endif + data.pseudoflavor = AUTH_SYS; bg = 0; soft = 0; @@ -326,6 +342,7 @@ int nfsmount(const char *spec, const cha mountport = 0; nfsprog = NFS_PROGRAM; nfsvers = 0; + secflavor = NULL; /* parse options */ @@ -389,6 +406,39 @@ int nfsmount(const char *spec, const cha printf(_("Warning: Option namlen is not supported.\n")); } else if (!strcmp(opt, "addr")) { /* ignore */; + } else if (!strcmp(opt, "sec")) { + secflavor = opteq+1; /* save for error */ + /* see RFC 2623 */ + if (nfs_mount_version < 5) { + printf(_("Warning: ignoring sec=%s option\n"),secflavor); + goto fail; + } else if (!strcmp(secflavor, "sys")) + data.pseudoflavor = AUTH_SYS; + else if (!strcmp(secflavor, "krb5")) + data.pseudoflavor = AUTH_GSS_KRB5; + else if (!strcmp(secflavor, "krb5i")) + data.pseudoflavor = AUTH_GSS_KRB5I; + else if (!strcmp(secflavor, "krb5p")) + data.pseudoflavor = AUTH_GSS_KRB5P; + else if (!strcmp(secflavor, "lkey")) + data.pseudoflavor = AUTH_GSS_LKEY; + else if (!strcmp(secflavor, "lkeyi")) + data.pseudoflavor = AUTH_GSS_LKEYI; + else if (!strcmp(secflavor, "lkeyp")) + data.pseudoflavor = AUTH_GSS_LKEYP; + else if (!strcmp(secflavor, "spkm")) + data.pseudoflavor = AUTH_GSS_SPKM; + else if (!strcmp(secflavor, "spkmi")) + data.pseudoflavor = AUTH_GSS_SPKMI; + else if (!strcmp(secflavor, "spkmp")) + data.pseudoflavor = AUTH_GSS_SPKMP; + else { + printf(_("Warning: Unrecognized " + "security flavor %s.\n"), + secflavor); + goto fail; + } + } else { printf(_("unknown nfs mount parameter: " "%s=%d\n"), opt, val); @@ -455,6 +505,10 @@ int nfsmount(const char *spec, const cha if (nfs_mount_version >= 4) data.flags |= (broken_suid ? NFS_MOUNT_BROKEN_SUID : 0); #endif +#if NFS_MOUNT_VERSION >= 5 + if (nfs_mount_version >= 5) + data.flags |= (secflavor ? NFS_MOUNT_SECFLAVOUR : 0); +#endif if (nfsvers > MAX_NFSPROT) { fprintf(stderr, "NFSv%d not supported!\n", nfsvers); return 0; @@ -491,6 +545,9 @@ int nfsmount(const char *spec, const cha printf("tcp = %d\n", (data.flags & NFS_MOUNT_TCP) != 0); #endif +#if NFS_MOUNT_VERSION >= 5 + printf("sec = %s\n", secflavor); +#endif #endif data.version = nfs_mount_version; @@ -689,7 +746,9 @@ int nfsmount(const char *spec, const cha #endif } else { #if NFS_MOUNT_VERSION >= 4 + mountres3_ok *mountres; fhandle3 *fhandle; + int i, *flavor, yum = 0; if (status.nfsv3.fhs_status != 0) { fprintf(stderr, "mount: %s:%s failed, reason given by server: %s\n", @@ -697,6 +756,42 @@ int nfsmount(const char *spec, const cha nfs_strerror(status.nfsv3.fhs_status)); goto fail; } + mountres = &status.nfsv3.mountres3_u.mountinfo; + i = mountres->auth_flavours.auth_flavours_len; + flavor = mountres->auth_flavours.auth_flavours_val; + while (--i >= 0) { + if (flavor[i] == data.pseudoflavor) + yum = 1; +#ifdef NFS_MOUNT_DEBUG + printf("auth flavor %d: %d\n", + i, flavor[i]); +#endif + } + if (!yum) { + fprintf(stderr, + "mount: %s:%s failed, " + "security flavor %s not supported\n", + hostname, dirname, secflavor); + + /* server has registered us in mtab, send umount */ + if (pm_mnt->pm_vers == 3) + clnt_stat = clnt_call(mclient, + MOUNTPROC3_UMNT, + (xdrproc_t) xdr_dirpath, + (caddr_t) &dirname, + (xdrproc_t) xdr_void, + (caddr_t) 0, + total_timeout); + else + clnt_stat = clnt_call(mclient, + MOUNTPROC_UMNT, + (xdrproc_t) xdr_dirpath, + (caddr_t) &dirname, + (xdrproc_t) xdr_void, + (caddr_t) 0, + total_timeout); + goto fail; + } fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle; memset(data.old_root.data, 0, NFS_FHSIZE); memset(&data.root, 0, sizeof(data.root)); _