Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 May 2009 19:56:51 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r192930 - in head/sbin: mount mount_nfs
Message-ID:  <200905271956.n4RJup4u010211@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Wed May 27 19:56:51 2009
New Revision: 192930
URL: http://svn.freebsd.org/changeset/base/192930

Log:
  Add support for the experimental nfs client to mount_nfs. The
  experimental client is used when the fstype is "newnfs" or the "nfsv4"
  option is specified. It includes the addition of the option:
    gssname - to specify a client side initiator host based principal name
  which is specific to NFSv4.
  It also includes a change to mount.c, so that it knows about
  mount_newnfs, but not mount_nfs4.
  
  Reviewed by:	dfr
  Approved by:	kib (mentor)

Modified:
  head/sbin/mount/mount.c
  head/sbin/mount_nfs/Makefile
  head/sbin/mount_nfs/mount_nfs.8
  head/sbin/mount_nfs/mount_nfs.c

Modified: head/sbin/mount/mount.c
==============================================================================
--- head/sbin/mount/mount.c	Wed May 27 19:45:04 2009	(r192929)
+++ head/sbin/mount/mount.c	Wed May 27 19:56:51 2009	(r192930)
@@ -140,7 +140,7 @@ use_mountprog(const char *vfstype)
 	 */
 	unsigned int i;
 	const char *fs[] = {
-	"cd9660", "mfs", "msdosfs", "nfs", "nfs4", "ntfs",
+	"cd9660", "mfs", "msdosfs", "newnfs", "nfs", "ntfs",
 	"nwfs", "nullfs", "portalfs", "smbfs", "udf", "unionfs",
 	NULL
 	};

Modified: head/sbin/mount_nfs/Makefile
==============================================================================
--- head/sbin/mount_nfs/Makefile	Wed May 27 19:45:04 2009	(r192929)
+++ head/sbin/mount_nfs/Makefile	Wed May 27 19:56:51 2009	(r192930)
@@ -5,13 +5,15 @@
 PROG=	mount_nfs
 SRCS=	mount_nfs.c getmntopts.c mounttab.c
 MAN=	mount_nfs.8
-MLINKS=	mount_nfs.8
+MLINKS=	mount_nfs.8 mount_newnfs.8
 
 MOUNT=	${.CURDIR}/../mount
 UMNTALL= ${.CURDIR}/../../usr.sbin/rpc.umntall
 CFLAGS+= -DNFS -I${MOUNT} -I${UMNTALL}
 WARNS?=	3
 
+LINKS=	${BINDIR}/mount_nfs ${BINDIR}/mount_newnfs
+
 .PATH: ${MOUNT} ${UMNTALL}
 
 .include <bsd.prog.mk>

Modified: head/sbin/mount_nfs/mount_nfs.8
==============================================================================
--- head/sbin/mount_nfs/mount_nfs.8	Wed May 27 19:45:04 2009	(r192929)
+++ head/sbin/mount_nfs/mount_nfs.8	Wed May 27 19:56:51 2009	(r192930)
@@ -132,6 +132,47 @@ short.
 .It Cm fg
 Same as not specifying
 .Cm bg .
+.It Cm gssname Ns = Ns Aq Ar name
+For the RPCSEC_GSS security flavors, such as krb5, krb5i and krb5p when being
+used for an NFSv4 mount, this option specifies the host based principal
+name to be used for the state related operations SetClientID,
+SetClientIDConfirm, ReleaseLockOwner and Renew.
+It is also used for other operations, such as Getattr for
+.Xr statfs 2
+information and during open/lock state recovery.
+An entry for this principal must exist
+in the client machine's default keytab file.
+If possible, the keytab entry should be created using DES_CBC_CRC
+encryption. If another encryption algorithm is used, the sysctl variable
+.Va vfs.newnfs.keytab_enctype
+must be set to the numeric value representing that encryption algorithm.
+(The numeric values can be found in /usr/include/krb5_asn1.h. Look
+for constants named ETYPE_xxx.)
+If this option is given
+as a name without an ``@<client-fqdn>'', such as ``root'' or ``nfs'',
+``@<client-fqdn>'' will be appended to it.
+.sp
+If this option is not specified
+for NFSv4 mounts using krb5[ip], the above operations will be done using the
+user principal for the user that performed the mount. This
+only works for mounts done by a user other than ``root'' and the user must
+have a valid TGT in their credentials cache at the time the mount is done.
+(Setting the
+.Va vfs.usermount
+to non-zero will allow users to do mounts.)
+Because the user's TGT is used to acquire credentials for these operations,
+it is important that that user's TGT does not expire before
+.Xr umount 8
+is done.
+.It Cm allgssname
+This option can be used along with
+.Cm gssname
+to indicate that all accesses to the mount point are to be done using
+the host based principal specified by the
+.Cm gssname
+option.
+This might be useful for nfsv4 mounts using sec=krb5[ip] that are being accessed
+by batch utilities over long periods of time.
 .It Cm hard
 Same as not specifying
 .Cm soft .
@@ -157,6 +198,12 @@ then version 2).
 Note that NFS version 2 has a file size limit of 2 gigabytes.
 .It Cm nfsv3
 Use the NFS Version 3 protocol.
+.It Cm nfsv4
+Use the NFS Version 4 protocol.
+This option will force the mount to use the experimental nfs subsystem and
+TCP transport.
+To use the experimental nfs subsystem for nfsv2 and nfsv3 mounts, you
+must specify the ``newnfs'' file system type instead of ``nfs''.
 .It Cm noconn
 For UDP mount points, do not do a
 .Xr connect 2 .
@@ -192,6 +239,11 @@ servers on the client.
 Note that this option will only be honored when performing the
 initial mount, it will be silently ignored if used while updating
 the mount options.
+.It Cm principal
+For the RPCSEC_GSS security flavors, such as krb5, krb5i and krb5p,
+this option sets the name of the host based principal name expected
+by the server. This option overrides the default, which will be
+``nfs@<server-fqdn>'' and should normally be sufficient.
 .It Cm noresvport
 Do
 .Em not
@@ -200,8 +252,10 @@ use a reserved socket port number (see b
 Use specified port number for NFS requests.
 The default is to query the portmapper for the NFS port.
 .It Cm rdirplus
-Used with NQNFS and NFSV3 to specify that the \fBReaddirPlus\fR RPC should
+Used with NFSV3 to specify that the \fBReaddirPlus\fR RPC should
 be used.
+For NFSV4, setting this option has a similar effect, in that it will make
+the Readdir Operation get more attributes.
 This option reduces RPC traffic for cases such as
 .Dq "ls -l" ,
 but tends to flood the attribute and name caches with prefetched entries.
@@ -248,6 +302,18 @@ with the
 option to see what the
 .Dq "fragments dropped due to timeout"
 value is.)
+.It Cm sec Ns = Ns Aq Ar flavor
+This option specifies what security flavor should be used for the mount.
+Currently, they are:
+.Bd -literal
+krb5 -  Use KerberosV authentication
+krb5i - Use KerberosV authentication and
+        apply integrity checksums to RPCs
+krb5p - Use KerberosV authentication and
+        encrypt the RPC data
+sys -   The default AUTH_SYS, which uses a
+        uid + gid list authenticator
+.Ed
 .It Cm soft
 A soft mount, which implies that file system calls will fail
 after
@@ -368,8 +434,19 @@ Same as
 .Sh SEE ALSO
 .Xr nmount 2 ,
 .Xr unmount 2 ,
+.Xr nfsv4 4 ,
 .Xr fstab 5 ,
+.Xr gssd 8 ,
 .Xr mount 8 ,
 .Xr nfsd 8 ,
 .Xr nfsiod 8 ,
 .Xr showmount 8
+.Sh BUGS
+Since nfsv4 performs open/lock operations that have their ordering strictly
+enforced by the server, the options
+.Cm intr
+and
+.Cm soft
+cannot be safely used.
+.Cm hard
+nfsv4 mounts are strongly recommended.

Modified: head/sbin/mount_nfs/mount_nfs.c
==============================================================================
--- head/sbin/mount_nfs/mount_nfs.c	Wed May 27 19:45:04 2009	(r192929)
+++ head/sbin/mount_nfs/mount_nfs.c	Wed May 27 19:56:51 2009	(r192930)
@@ -45,6 +45,8 @@ static char sccsid[] = "@(#)mount_nfs.c	
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/module.h>
 #include <sys/mount.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -111,11 +113,13 @@ int addrlen = 0;
 u_char *fh = NULL;
 int fhsize = 0;
 int secflavor = -1;
+int got_principal = 0;
 
 enum mountmode {
 	ANY,
 	V2,
 	V3,
+	V4
 } mountmode = ANY;
 
 /* Return codes for nfs_tryproto. */
@@ -150,11 +154,13 @@ main(int argc, char *argv[])
 	int osversion;
 	char *name, *p, *spec, *fstype;
 	char mntpath[MAXPATHLEN], errmsg[255];
+	char hostname[MAXHOSTNAMELEN + 1], *gssname, gssn[MAXHOSTNAMELEN + 50];
 
 	mntflags = 0;
 	iov = NULL;
 	iovlen = 0;
 	memset(errmsg, 0, sizeof(errmsg));
+	gssname = NULL;
 
 	fstype = strrchr(argv[0], '_');
 	if (fstype == NULL)
@@ -242,6 +248,9 @@ main(int argc, char *argv[])
 				} else if (strcmp(opt, "fg") == 0) {
 					/* same as not specifying -o bg */
 					pass_flag_to_nmount=0;
+				} else if (strcmp(opt, "gssname") == 0) {
+					pass_flag_to_nmount = 0;
+					gssname = val;
 				} else if (strcmp(opt, "mntudp") == 0) {
 					mnttcp_ok = 0;
 					nfsproto = IPPROTO_UDP;
@@ -262,12 +271,21 @@ main(int argc, char *argv[])
 					mountmode = V2;
 				} else if (strcmp(opt, "nfsv3") == 0) {
 					mountmode = V3;
+				} else if (strcmp(opt, "nfsv4") == 0) {
+					pass_flag_to_nmount=0;
+					mountmode = V4;
+					fstype = "newnfs";
+					nfsproto = IPPROTO_TCP;
+					if (portspec == NULL)
+						portspec = "2049";
 				} else if (strcmp(opt, "port") == 0) {
 					pass_flag_to_nmount=0;
 					asprintf(&portspec, "%d",
 					    atoi(val));
 					if (portspec == NULL)
 						err(1, "asprintf");
+				} else if (strcmp(opt, "principal") == 0) {
+					got_principal = 1;
 				} else if (strcmp(opt, "sec") == 0) {
 					/*
 					 * Don't add this option to
@@ -363,6 +381,37 @@ main(int argc, char *argv[])
 		/* The default is to keep retrying forever. */
 		retrycnt = 0;
 
+	/*
+	 * If the experimental nfs subsystem is loaded into the kernel
+	 * and the regular one is not, use it. Otherwise, use it if the
+	 * fstype is set to "newnfs", either via "mount -t newnfs ..."
+	 * or by specifying an nfsv4 mount.
+	 */
+	if (modfind("nfscl") >= 0 && modfind("nfs") < 0) {
+		fstype = "newnfs";
+	} else if (strcmp(fstype, "newnfs") == 0) {
+		if (modfind("nfscl") < 0) {
+			/* Not present in kernel, try loading it */
+			if (kldload("nfscl") < 0 ||
+			    modfind("nfscl") < 0)
+				errx(1, "nfscl is not available");
+		}
+	}
+
+	/*
+	 * Add the fqdn to the gssname, as required.
+	 */
+	if (gssname != NULL) {
+		if (strchr(gssname, '@') == NULL &&
+		    gethostname(hostname, MAXHOSTNAMELEN) == 0) {
+			snprintf(gssn, sizeof (gssn), "%s@%s", gssname,
+			    hostname);
+			gssname = gssn;
+		}
+		build_iovec(&iov, &iovlen, "gssname", gssname,
+		    strlen(gssname) + 1);
+	}
+
 	if (!getnfsargs(spec, &iov, &iovlen))
 		exit(1);
 
@@ -652,7 +701,7 @@ getnfsargs(char *spec, struct iovec **io
 	int ecode, speclen, remoteerr;
 	char *hostp, *delimp, *errstr;
 	size_t len;
-	static char nam[MNAMELEN + 1];
+	static char nam[MNAMELEN + 1], pname[MAXHOSTNAMELEN + 5];
 
 	if ((delimp = strrchr(spec, ':')) != NULL) {
 		hostp = spec;
@@ -699,7 +748,7 @@ getnfsargs(char *spec, struct iovec **io
 		hints.ai_socktype = SOCK_DGRAM;
 
 	if (getaddrinfo(hostp, portspec, &hints, &ai_nfs) != 0) {
-		hints.ai_flags = 0;
+		hints.ai_flags = AI_CANONNAME;
 		if ((ecode = getaddrinfo(hostp, portspec, &hints, &ai_nfs))
 		    != 0) {
 			if (portspec == NULL)
@@ -709,6 +758,18 @@ getnfsargs(char *spec, struct iovec **io
 				    gai_strerror(ecode));
 			return (0);
 		}
+
+		/*
+		 * For a Kerberized nfs mount where the "principal"
+		 * argument has not been set, add it here.
+		 */
+		if (got_principal == 0 && secflavor >= 0 &&
+		    secflavor != AUTH_SYS && ai_nfs->ai_canonname != NULL) {
+			snprintf(pname, sizeof (pname), "nfs@%s",
+			    ai_nfs->ai_canonname);
+			build_iovec(iov, iovlen, "principal", pname,
+			    strlen(pname) + 1);
+		}
 	}
 
 	ret = TRYRET_LOCALERR;
@@ -834,7 +895,9 @@ nfs_tryproto(struct addrinfo *ai, char *
 	}
 
 tryagain:
-	if (trymntmode == V2) {
+	if (trymntmode == V4) {
+		nfsvers = 4;
+	} else if (trymntmode == V2) {
 		nfsvers = 2;
 		mntvers = 1;
 	} else {
@@ -894,8 +957,7 @@ tryagain:
 	try.tv_sec = 10;
 	try.tv_usec = 0;
 	stat = clnt_call(clp, NFSPROC_NULL, (xdrproc_t)xdr_void, NULL,
-			 (xdrproc_t)xdr_void, NULL,
-	    try);
+			 (xdrproc_t)xdr_void, NULL, try);
 	if (stat != RPC_SUCCESS) {
 		if (stat == RPC_PROGVERSMISMATCH && trymntmode == ANY) {
 			clnt_destroy(clp);
@@ -910,6 +972,30 @@ tryagain:
 	}
 	clnt_destroy(clp);
 
+	/*
+	 * For NFSv4, there is no mount protocol.
+	 */
+	if (trymntmode == V4) {
+		/*
+		 * Store the server address in nfsargsp, making
+		 * sure to copy any locally allocated structures.
+		 */
+		addrlen = nfs_nb.len;
+		addr = malloc(addrlen);
+		if (addr == NULL)
+			err(1, "malloc");
+		bcopy(nfs_nb.buf, addr, addrlen);
+
+		build_iovec(iov, iovlen, "addr", addr, addrlen);
+		secname = sec_num_to_name(secflavor);
+		if (secname != NULL)
+			build_iovec(iov, iovlen, "sec", secname, (size_t)-1);
+		build_iovec(iov, iovlen, "nfsv4", NULL, 0);
+		build_iovec(iov, iovlen, "dirpath", spec, (size_t)-1);
+
+		return (TRYRET_SUCCESS);
+	}
+
 	/* Send the RPCMNT_MOUNT RPC to get the root filehandle. */
 	try.tv_sec = 10;
 	try.tv_usec = 0;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905271956.n4RJup4u010211>