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", 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), "n...@%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;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to