summaryrefslogtreecommitdiffstats
path: root/sbin/mount_nfs
diff options
context:
space:
mode:
authorrmacklem <rmacklem@FreeBSD.org>2009-05-27 19:56:51 +0000
committerrmacklem <rmacklem@FreeBSD.org>2009-05-27 19:56:51 +0000
commit08f63a0d1856606c05d8acbbdf2842f53f0a5075 (patch)
treea15044ee609b196f8985b703a87ed2873177c22e /sbin/mount_nfs
parentb36d17c9734aa42ec7cdd0deaf6cfdba58515804 (diff)
downloadFreeBSD-src-08f63a0d1856606c05d8acbbdf2842f53f0a5075.zip
FreeBSD-src-08f63a0d1856606c05d8acbbdf2842f53f0a5075.tar.gz
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)
Diffstat (limited to 'sbin/mount_nfs')
-rw-r--r--sbin/mount_nfs/Makefile4
-rw-r--r--sbin/mount_nfs/mount_nfs.879
-rw-r--r--sbin/mount_nfs/mount_nfs.c96
3 files changed, 172 insertions, 7 deletions
diff --git a/sbin/mount_nfs/Makefile b/sbin/mount_nfs/Makefile
index 960f97c..2e255b2 100644
--- a/sbin/mount_nfs/Makefile
+++ b/sbin/mount_nfs/Makefile
@@ -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>
diff --git a/sbin/mount_nfs/mount_nfs.8 b/sbin/mount_nfs/mount_nfs.8
index 78a3b19..b1199d4 100644
--- a/sbin/mount_nfs/mount_nfs.8
+++ b/sbin/mount_nfs/mount_nfs.8
@@ -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 below).
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.
diff --git a/sbin/mount_nfs/mount_nfs.c b/sbin/mount_nfs/mount_nfs.c
index 102c51d..d7305e5 100644
--- a/sbin/mount_nfs/mount_nfs.c
+++ b/sbin/mount_nfs/mount_nfs.c
@@ -45,6 +45,8 @@ static char sccsid[] = "@(#)mount_nfs.c 8.11 (Berkeley) 5/4/95";
__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 **iov, int *iovlen)
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 **iov, int *iovlen)
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 **iov, int *iovlen)
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 *hostp, char *spec, char **errstr,
}
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;
OpenPOWER on IntegriCloud