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)
This commit is contained in:
parent
b36d17c973
commit
08f63a0d18
@ -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
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -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.
|
||||
|
@ -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 @@ nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, char **errstr,
|
||||
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 @@ nfs_tryproto(struct addrinfo *ai, char *hostp, char *spec, char **errstr,
|
||||
}
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user