nfscl: Add a new NFSv4.1/4.2 mount option for Kerberized mounts

Without this patch, a Kerberized NFSv4.1/4.2 mount must provide
a Kerberos credential for the client at mount time.  This credential
is typically referred to as a "machine credential".  It can be
created one of two ways:
- The user (usually root) has a valid TGT at the time the mount
  is done and this becomes the machine credential.
  There are two problems with this.
  1 - The user doing the mount must have a valid TGT for a user
      principal at mount time.  As such, the mount cannot be put
      in fstab(5) or similar.
  2 - When the TGT expires, the mount breaks.
- The client machine has a service principal in its default keytab
  file and this service principal (typically called a host-based
  initiator credential) is used as the machine credential.
  There are problems with this approach as well:
  1 - There is a certain amount of administrative overhead creating
      the service principal for the NFS client, creating a keytab
      entry for this principal and then copying the keytab entry
      into the client's default keytab file via some secure means.
  2 - The NFS client must have a fixed, well known, DNS name, since
      that FQDN is in the service principal name as the instance.

This patch uses a feature of NFSv4.1/4.2 called SP4_NONE, which
allows the state maintenance operations to be performed by any
authentication mechanism, to do these operations via AUTH_SYS
instead of RPCSEC_GSS (Kerberos).  As such, neither of the above
mechanisms is needed.

It is hoped that this option will encourage adoption of Kerberized
NFS mounts using TLS, to provide a more secure NFS mount.

This new NFSv4.1/4.2 mount option, called "syskrb5" must be used
with "sec=krb5[ip]" to avoid the need for either of the above
Kerberos setups to be done by the client.

Note that all file access/modification operations still require
users on the NFS client to have a valid TGT recognized by the
NFSv4.1/4.2 server.  As such, this option allows, at most, a
malicious client to do some sort of DOS attack.

Although not required, use of "tls" with this new option is
encouraged, since it provides on-the-wire encryption plus,
optionally, client identity verification via a X.509
certificate provided to the server during TLS handshake.
Alternately, "sec=krb5p" does provide on-the-wire
encryption of file data.

A mount_nfs(8) man page update will be done in a separate commit.

Discussed on:	freebsd-current@
MFC after:	3 months
This commit is contained in:
Rick Macklem
2023-03-16 15:55:36 -07:00
parent 58436df347
commit 896516e54a
14 changed files with 377 additions and 59 deletions
+7
View File
@@ -522,6 +522,13 @@ typedef struct {
(b)->bits[2] = NFSGETATTRBIT_STATFS2; \ (b)->bits[2] = NFSGETATTRBIT_STATFS2; \
} while (0) } while (0)
#define NFSROOTFS_GETATTRBIT(b) do { \
(b)->bits[0] = NFSGETATTRBIT_STATFS0 | NFSATTRBIT_GETATTR0 | \
NFSATTRBM_LEASETIME; \
(b)->bits[1] = NFSGETATTRBIT_STATFS1 | NFSATTRBIT_GETATTR1; \
(b)->bits[2] = NFSGETATTRBIT_STATFS2 | NFSATTRBIT_GETATTR2; \
} while (0)
#define NFSISSETSTATFS_ATTRBIT(b) \ #define NFSISSETSTATFS_ATTRBIT(b) \
(((b)->bits[0] & NFSATTRBIT_STATFS0) || \ (((b)->bits[0] & NFSATTRBIT_STATFS0) || \
((b)->bits[1] & NFSATTRBIT_STATFS1) || \ ((b)->bits[1] & NFSATTRBIT_STATFS1) || \
+84 -2
View File
@@ -162,6 +162,87 @@ static int nfsv2_procid[NFS_V3NPROCS] = {
NFSV2PROC_NOOP, NFSV2PROC_NOOP,
}; };
/*
* This static array indicates that a NFSv4 RPC should use
* RPCSEC_GSS, if the mount indicates that via sec=krb5[ip].
* System RPCs that do not use file handles will be false
* in this array so that they will use AUTH_SYS when the
* "syskrb5" mount option is specified, along with
* "sec=krb5[ip]".
*/
static bool nfscl_use_gss[NFSV42_NPROCS] = {
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
false, /* SetClientID */
false, /* SetClientIDConfirm */
true,
true,
true,
true,
true,
true,
true,
false, /* Renew */
true,
false, /* ReleaseLockOwn */
true,
true,
true,
true,
true,
true,
false, /* ExchangeID */
false, /* CreateSession */
false, /* DestroySession */
false, /* DestroyClientID */
false, /* FreeStateID */
true,
true,
true,
true,
false, /* ReclaimComplete */
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
true,
false, /* BindConnectionToSession */
true,
true,
true,
true,
};
/* /*
* Initialize sockets and congestion for a new NFS connection. * Initialize sockets and congestion for a new NFS connection.
* We do not free the sockaddr if error. * We do not free the sockaddr if error.
@@ -679,7 +760,8 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
} }
NFSUNLOCKSTATE(); NFSUNLOCKSTATE();
} else if (nmp != NULL && NFSHASKERB(nmp) && } else if (nmp != NULL && NFSHASKERB(nmp) &&
nd->nd_procnum != NFSPROC_NULL) { nd->nd_procnum != NFSPROC_NULL && (!NFSHASSYSKRB5(nmp) ||
nfscl_use_gss[nd->nd_procnum])) {
if (NFSHASALLGSSNAME(nmp) && nmp->nm_krbnamelen > 0) if (NFSHASALLGSSNAME(nmp) && nmp->nm_krbnamelen > 0)
nd->nd_flag |= ND_USEGSSNAME; nd->nd_flag |= ND_USEGSSNAME;
if ((nd->nd_flag & ND_USEGSSNAME) != 0) { if ((nd->nd_flag & ND_USEGSSNAME) != 0) {
@@ -720,7 +802,7 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp,
else else
secflavour = RPCSEC_GSS_KRB5; secflavour = RPCSEC_GSS_KRB5;
srv_principal = NFSMNT_SRVKRBNAME(nmp); srv_principal = NFSMNT_SRVKRBNAME(nmp);
} else if (nmp != NULL && !NFSHASKERB(nmp) && } else if (nmp != NULL && (!NFSHASKERB(nmp) || NFSHASSYSKRB5(nmp)) &&
nd->nd_procnum != NFSPROC_NULL && nd->nd_procnum != NFSPROC_NULL &&
(nd->nd_flag & ND_USEGSSNAME) != 0) { (nd->nd_flag & ND_USEGSSNAME) != 0) {
/* /*
+13 -4
View File
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include "opt_inet6.h" #include "opt_inet6.h"
#include <fs/nfs/nfsport.h> #include <fs/nfs/nfsport.h>
#include <fs/nfsclient/nfsmount.h>
#include <sys/extattr.h> #include <sys/extattr.h>
@@ -436,7 +437,7 @@ nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) { if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) {
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_PUTFH); *tl = txdr_unsigned(NFSV4OP_PUTFH);
(void) nfsm_fhtom(nd, nfhp, fhlen, 0); nfsm_fhtom(nmp, nd, nfhp, fhlen, 0);
if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh
== 2 && procnum != NFSPROC_WRITEDS && == 2 && procnum != NFSPROC_WRITEDS &&
procnum != NFSPROC_COMMITDS) { procnum != NFSPROC_COMMITDS) {
@@ -467,7 +468,7 @@ nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp,
*tl = txdr_unsigned(nfsv4_opmap[procnum].op); *tl = txdr_unsigned(nfsv4_opmap[procnum].op);
} }
} else { } else {
(void) nfsm_fhtom(nd, nfhp, fhlen, 0); nfsm_fhtom(NULL, nd, nfhp, fhlen, 0);
} }
if (procnum < NFSV42_NPROCS) if (procnum < NFSV42_NPROCS)
NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]); NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]);
@@ -953,12 +954,15 @@ newnfs_init(void)
* Return the number of bytes output, including XDR overhead. * Return the number of bytes output, including XDR overhead.
*/ */
int int
nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true) nfsm_fhtom(struct nfsmount *nmp, struct nfsrv_descript *nd, u_int8_t *fhp,
int size, int set_true)
{ {
u_int32_t *tl; u_int32_t *tl;
u_int8_t *cp; u_int8_t *cp;
int fullsiz, bytesize = 0; int fullsiz, bytesize = 0;
KASSERT(nmp == NULL || nmp->nm_fhsize > 0,
("nfsm_fhtom: 0 length fh"));
if (size == 0) if (size == 0)
size = NFSX_MYFH; size = NFSX_MYFH;
switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) {
@@ -973,6 +977,11 @@ nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true)
break; break;
case ND_NFSV3: case ND_NFSV3:
case ND_NFSV4: case ND_NFSV4:
if (size == NFSX_FHMAX + 1 && nmp != NULL &&
(nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
fhp = nmp->nm_fh;
size = nmp->nm_fhsize;
}
fullsiz = NFSM_RNDUP(size); fullsiz = NFSM_RNDUP(size);
if (set_true) { if (set_true) {
bytesize = 2 * NFSX_UNSIGNED + fullsiz; bytesize = 2 * NFSX_UNSIGNED + fullsiz;
@@ -2737,7 +2746,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
retnum += NFSX_UNSIGNED; retnum += NFSX_UNSIGNED;
break; break;
case NFSATTRBIT_FILEHANDLE: case NFSATTRBIT_FILEHANDLE:
retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); retnum += nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
break; break;
case NFSATTRBIT_FILEID: case NFSATTRBIT_FILEID:
NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER);
+3 -2
View File
@@ -327,7 +327,8 @@ int nfsaddr_match(int, union nethostaddr *, NFSSOCKADDR_T);
int nfsaddr2_match(NFSSOCKADDR_T, NFSSOCKADDR_T); int nfsaddr2_match(NFSSOCKADDR_T, NFSSOCKADDR_T);
int nfsm_strtom(struct nfsrv_descript *, const char *, int); int nfsm_strtom(struct nfsrv_descript *, const char *, int);
int nfsm_mbufuio(struct nfsrv_descript *, struct uio *, int); int nfsm_mbufuio(struct nfsrv_descript *, struct uio *, int);
int nfsm_fhtom(struct nfsrv_descript *, u_int8_t *, int, int); int nfsm_fhtom(struct nfsmount *, struct nfsrv_descript *, u_int8_t *, int,
int);
int nfsm_advance(struct nfsrv_descript *, int, int); int nfsm_advance(struct nfsrv_descript *, int, int);
void *nfsm_dissct(struct nfsrv_descript *, int, int); void *nfsm_dissct(struct nfsrv_descript *, int, int);
void newnfs_copycred(struct nfscred *, struct ucred *); void newnfs_copycred(struct nfscred *, struct ucred *);
@@ -510,7 +511,7 @@ int nfsrpc_lockt(struct nfsrv_descript *, vnode_t,
int nfsrpc_lock(struct nfsrv_descript *, struct nfsmount *, vnode_t, int nfsrpc_lock(struct nfsrv_descript *, struct nfsmount *, vnode_t,
u_int8_t *, int, struct nfscllockowner *, int, int, u_int64_t, u_int8_t *, int, struct nfscllockowner *, int, int, u_int64_t,
u_int64_t, short, struct ucred *, NFSPROC_T *, int); u_int64_t, short, struct ucred *, NFSPROC_T *, int);
int nfsrpc_statfs(vnode_t, struct nfsstatfs *, struct nfsfsinfo *, int nfsrpc_statfs(vnode_t, struct nfsstatfs *, struct nfsfsinfo *, uint32_t *,
struct ucred *, NFSPROC_T *, struct nfsvattr *, int *); struct ucred *, NFSPROC_T *, struct nfsvattr *, int *);
int nfsrpc_fsinfo(vnode_t, struct nfsfsinfo *, struct ucred *, int nfsrpc_fsinfo(vnode_t, struct nfsfsinfo *, struct ucred *,
NFSPROC_T *, struct nfsvattr *, int *); NFSPROC_T *, struct nfsvattr *, int *);
+1
View File
@@ -1085,6 +1085,7 @@ void ncl_copy_vattr(struct vattr *dst, struct vattr *src);
#define NFSHASONEOPENOWN(n) (((n)->nm_flag & NFSMNT_ONEOPENOWN) != 0 && \ #define NFSHASONEOPENOWN(n) (((n)->nm_flag & NFSMNT_ONEOPENOWN) != 0 && \
(n)->nm_minorvers > 0) (n)->nm_minorvers > 0)
#define NFSHASTLS(n) (((n)->nm_newflag & NFSMNT_TLS) != 0) #define NFSHASTLS(n) (((n)->nm_newflag & NFSMNT_TLS) != 0)
#define NFSHASSYSKRB5(n) (((n)->nm_newflag & NFSMNT_SYSKRB5) != 0)
/* /*
* Set boottime. * Set boottime.
+2 -2
View File
@@ -156,8 +156,8 @@ ncl_nget(struct mount *mntp, u_int8_t *fhp, int fhsize, struct nfsnode **npp,
* Are we getting the root? If so, make sure the vnode flags * Are we getting the root? If so, make sure the vnode flags
* are correct * are correct
*/ */
if ((fhsize == nmp->nm_fhsize) && if (fhsize == NFSX_FHMAX + 1 || (fhsize == nmp->nm_fhsize &&
!bcmp(fhp, nmp->nm_fh, fhsize)) { !bcmp(fhp, nmp->nm_fh, fhsize))) {
if (vp->v_type == VNON) if (vp->v_type == VNON)
vp->v_type = VDIR; vp->v_type = VDIR;
vp->v_vflag |= VV_ROOT; vp->v_vflag |= VV_ROOT;
+23 -3
View File
@@ -140,6 +140,19 @@ nfscl_nget(struct mount *mntp, struct vnode *dvp, struct nfsfh *nfhp,
dnp = VTONFS(dvp); dnp = VTONFS(dvp);
*npp = NULL; *npp = NULL;
/*
* If this is the mount point fh and NFSMNTP_FAKEROOT is set, replace
* it with the fake fh.
*/
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
nmp->nm_fhsize > 0 && nmp->nm_fhsize == nfhp->nfh_len &&
!NFSBCMP(nmp->nm_fh, nfhp->nfh_fh, nmp->nm_fhsize)) {
free(nfhp, M_NFSFH);
nfhp = malloc(sizeof(struct nfsfh) + NFSX_FHMAX + 1,
M_NFSFH, M_WAITOK | M_ZERO);
nfhp->nfh_len = NFSX_FHMAX + 1;
}
hash = fnv_32_buf(nfhp->nfh_fh, nfhp->nfh_len, FNV1_32_INIT); hash = fnv_32_buf(nfhp->nfh_fh, nfhp->nfh_len, FNV1_32_INIT);
error = vfs_hash_get(mntp, hash, lkflags, error = vfs_hash_get(mntp, hash, lkflags,
@@ -241,8 +254,9 @@ nfscl_nget(struct mount *mntp, struct vnode *dvp, struct nfsfh *nfhp,
* Are we getting the root? If so, make sure the vnode flags * Are we getting the root? If so, make sure the vnode flags
* are correct * are correct
*/ */
if ((nfhp->nfh_len == nmp->nm_fhsize) && if (nfhp->nfh_len == NFSX_FHMAX + 1 ||
!bcmp(nfhp->nfh_fh, nmp->nm_fh, nfhp->nfh_len)) { (nfhp->nfh_len == nmp->nm_fhsize &&
!bcmp(nfhp->nfh_fh, nmp->nm_fh, nfhp->nfh_len))) {
if (vp->v_type == VNON) if (vp->v_type == VNON)
vp->v_type = VDIR; vp->v_type = VDIR;
vp->v_vflag |= VV_ROOT; vp->v_vflag |= VV_ROOT;
@@ -493,9 +507,15 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
* this reliably with Clang and .c files during parallel build. * this reliably with Clang and .c files during parallel build.
* A pcap revealed packet fragmentation and GETATTR RPC * A pcap revealed packet fragmentation and GETATTR RPC
* responses with wholly wrong fileids. * responses with wholly wrong fileids.
* For the case where the file handle is a fake one
* generated via the "syskrb5" mount option and
* the old fileid is 2, ignore the test, since this might
* be replacing the fake attributes with correct ones.
*/ */
if ((np->n_vattr.na_fileid != 0 && if ((np->n_vattr.na_fileid != 0 &&
np->n_vattr.na_fileid != nap->na_fileid) || np->n_vattr.na_fileid != nap->na_fileid &&
(np->n_vattr.na_fileid != 2 || !NFSHASSYSKRB5(nmp) ||
np->n_fhp->nfh_len != NFSX_FHMAX + 1)) ||
force_fid_err) { force_fid_err) {
nfscl_warn_fileid(nmp, &np->n_vattr, nap); nfscl_warn_fileid(nmp, &np->n_vattr, nap);
error = EIDRM; error = EIDRM;
+103 -18
View File
@@ -229,6 +229,7 @@ static int nfsrpc_copyrpc(vnode_t, off_t, vnode_t, off_t, size_t *,
static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *, static int nfsrpc_seekrpc(vnode_t, off_t *, nfsv4stateid_t *, bool *,
int, struct nfsvattr *, int *, struct ucred *); int, struct nfsvattr *, int *, struct ucred *);
static struct mbuf *nfsm_split(struct mbuf *, uint64_t); static struct mbuf *nfsm_split(struct mbuf *, uint64_t);
static void nfscl_statfs(struct vnode *, struct ucred *, NFSPROC_T *);
int nfs_pnfsio(task_fn_t *, void *); int nfs_pnfsio(task_fn_t *, void *);
@@ -305,9 +306,22 @@ nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
int error; int error;
struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsrv_descript nfsd, *nd = &nfsd;
nfsattrbit_t attrbits; nfsattrbit_t attrbits;
struct nfsmount *nmp;
struct nfsnode *np;
*attrflagp = 0; *attrflagp = 0;
supported = mode; supported = mode;
nmp = VFSTONFS(vp->v_mount);
np = VTONFS(vp);
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
nmp->nm_fhsize == 0) {
/* Attempt to get the actual root file handle. */
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), cred, p);
if (error != 0)
return (EACCES);
if (np->n_fhp->nfh_len == NFSX_FHMAX + 1)
nfscl_statfs(vp, cred, p);
}
NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp, cred); NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp, cred);
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(mode); *tl = txdr_unsigned(mode);
@@ -1207,7 +1221,20 @@ nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsrv_descript nfsd, *nd = &nfsd;
int error; int error;
nfsattrbit_t attrbits; nfsattrbit_t attrbits;
struct nfsnode *np;
struct nfsmount *nmp;
nmp = VFSTONFS(vp->v_mount);
np = VTONFS(vp);
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
nmp->nm_fhsize == 0) {
/* Attempt to get the actual root file handle. */
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), cred, p);
if (error != 0)
return (EACCES);
if (np->n_fhp->nfh_len == NFSX_FHMAX + 1)
nfscl_statfs(vp, cred, p);
}
NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred); NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred);
if (nd->nd_flag & ND_NFSV4) { if (nd->nd_flag & ND_NFSV4) {
NFSGETATTR_ATTRBIT(&attrbits); NFSGETATTR_ATTRBIT(&attrbits);
@@ -2558,7 +2585,7 @@ nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
/* Get the directory's post-op attributes. */ /* Get the directory's post-op attributes. */
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_PUTFH); *tl = txdr_unsigned(NFSV4OP_PUTFH);
(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_GETATTR); *tl = txdr_unsigned(NFSV4OP_GETATTR);
(void) nfsrv_putattrbit(nd, &attrbits); (void) nfsrv_putattrbit(nd, &attrbits);
@@ -2758,7 +2785,7 @@ nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
*tl++ = dstateid.other[2]; *tl++ = dstateid.other[2];
*tl = txdr_unsigned(NFSV4OP_PUTFH); *tl = txdr_unsigned(NFSV4OP_PUTFH);
np = VTONFS(dvp); np = VTONFS(dvp);
(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh,
np->n_fhp->nfh_len, 0); np->n_fhp->nfh_len, 0);
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_REMOVE); *tl = txdr_unsigned(NFSV4OP_REMOVE);
@@ -2846,7 +2873,7 @@ nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_PUTFH); *tl = txdr_unsigned(NFSV4OP_PUTFH);
np = VTONFS(tvp); np = VTONFS(tvp);
(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh,
np->n_fhp->nfh_len, 0); np->n_fhp->nfh_len, 0);
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_DELEGRETURN); *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
@@ -2866,7 +2893,7 @@ nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_PUTFH); *tl = txdr_unsigned(NFSV4OP_PUTFH);
np = VTONFS(fdvp); np = VTONFS(fdvp);
(void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh,
np->n_fhp->nfh_len, 0); np->n_fhp->nfh_len, 0);
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_SAVEFH); *tl = txdr_unsigned(NFSV4OP_SAVEFH);
@@ -2883,7 +2910,7 @@ nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
(void) nfsrv_putattrbit(nd, &attrbits); (void) nfsrv_putattrbit(nd, &attrbits);
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_PUTFH); *tl = txdr_unsigned(NFSV4OP_PUTFH);
(void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh,
VTONFS(tdvp)->n_fhp->nfh_len, 0); VTONFS(tdvp)->n_fhp->nfh_len, 0);
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_GETATTR); *tl = txdr_unsigned(NFSV4OP_GETATTR);
@@ -2894,7 +2921,7 @@ nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
} }
(void) nfsm_strtom(nd, fnameptr, fnamelen); (void) nfsm_strtom(nd, fnameptr, fnamelen);
if (!(nd->nd_flag & ND_NFSV4)) if (!(nd->nd_flag & ND_NFSV4))
(void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh,
VTONFS(tdvp)->n_fhp->nfh_len, 0); VTONFS(tdvp)->n_fhp->nfh_len, 0);
(void) nfsm_strtom(nd, tnameptr, tnamelen); (void) nfsm_strtom(nd, tnameptr, tnamelen);
error = nfscl_request(nd, fdvp, p, cred); error = nfscl_request(nd, fdvp, p, cred);
@@ -2979,7 +3006,7 @@ nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_PUTFH); *tl = txdr_unsigned(NFSV4OP_PUTFH);
} }
(void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh, nfsm_fhtom(VFSTONFS(dvp->v_mount), nd, VTONFS(dvp)->n_fhp->nfh_fh,
VTONFS(dvp)->n_fhp->nfh_len, 0); VTONFS(dvp)->n_fhp->nfh_len, 0);
if (nd->nd_flag & ND_NFSV4) { if (nd->nd_flag & ND_NFSV4) {
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
@@ -3119,7 +3146,7 @@ nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
(void) nfsrv_putattrbit(nd, &attrbits); (void) nfsrv_putattrbit(nd, &attrbits);
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_PUTFH); *tl = txdr_unsigned(NFSV4OP_PUTFH);
(void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0); nfsm_fhtom(nmp, nd, fhp->nfh_fh, fhp->nfh_len, 0);
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_GETATTR); *tl = txdr_unsigned(NFSV4OP_GETATTR);
(void) nfsrv_putattrbit(nd, &attrbits); (void) nfsrv_putattrbit(nd, &attrbits);
@@ -4634,7 +4661,8 @@ nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
*/ */
int int
nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) uint32_t *leasep, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap,
int *attrflagp)
{ {
u_int32_t *tl = NULL; u_int32_t *tl = NULL;
struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsrv_descript nfsd, *nd = &nfsd;
@@ -4649,7 +4677,10 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
* For V4, you actually do a getattr. * For V4, you actually do a getattr.
*/ */
NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred); NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred);
NFSSTATFS_GETATTRBIT(&attrbits); if (leasep != NULL)
NFSROOTFS_GETATTRBIT(&attrbits);
else
NFSSTATFS_GETATTRBIT(&attrbits);
(void) nfsrv_putattrbit(nd, &attrbits); (void) nfsrv_putattrbit(nd, &attrbits);
nd->nd_flag |= ND_USEGSSNAME; nd->nd_flag |= ND_USEGSSNAME;
error = nfscl_request(nd, vp, p, cred); error = nfscl_request(nd, vp, p, cred);
@@ -4657,8 +4688,8 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
return (error); return (error);
if (nd->nd_repstat == 0) { if (nd->nd_repstat == 0) {
error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p, NULL, NULL, sbp, fsp, NULL, 0, NULL, leasep, NULL,
cred); p, cred);
if (!error) { if (!error) {
nmp->nm_fsid[0] = nap->na_filesid[0]; nmp->nm_fsid[0] = nap->na_filesid[0];
nmp->nm_fsid[1] = nap->na_filesid[1]; nmp->nm_fsid[1] = nap->na_filesid[1];
@@ -4719,10 +4750,22 @@ nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
u_int32_t *tl; u_int32_t *tl;
nfsattrbit_t attrbits; nfsattrbit_t attrbits;
int error; int error;
struct nfsnode *np;
*attrflagp = 0; *attrflagp = 0;
nmp = VFSTONFS(vp->v_mount); nmp = VFSTONFS(vp->v_mount);
if (NFSHASNFSV4(nmp)) { if (NFSHASNFSV4(nmp)) {
np = VTONFS(vp);
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
nmp->nm_fhsize == 0) {
/* Attempt to get the actual root file handle. */
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
cred, p);
if (error != 0)
return (EACCES);
if (np->n_fhp->nfh_len == NFSX_FHMAX + 1)
nfscl_statfs(vp, cred, p);
}
/* /*
* For V4, you actually do a getattr. * For V4, you actually do a getattr.
*/ */
@@ -4909,7 +4952,7 @@ nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
u_int32_t *tl; u_int32_t *tl;
struct nfsrv_descript nfsd; struct nfsrv_descript nfsd;
struct nfsrv_descript *nd = &nfsd; struct nfsrv_descript *nd = &nfsd;
u_char *cp, *cp2; u_char *cp, *cp2, *fhp;
int error, cnt, len, setnil; int error, cnt, len, setnil;
u_int32_t *opcntp; u_int32_t *opcntp;
@@ -4957,9 +5000,17 @@ nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
len > NFSX_FHMAX) { len > NFSX_FHMAX) {
nd->nd_repstat = NFSERR_BADXDR; nd->nd_repstat = NFSERR_BADXDR;
} else { } else {
nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len); fhp = malloc(len + 1, M_TEMP, M_WAITOK);
if (nd->nd_repstat == 0) nd->nd_repstat = nfsrv_mtostr(nd, fhp, len);
nmp->nm_fhsize = len; if (nd->nd_repstat == 0) {
NFSLOCKMNT(nmp);
if (nmp->nm_fhsize == 0) {
NFSBCOPY(fhp, nmp->nm_fh, len);
nmp->nm_fhsize = len;
}
NFSUNLOCKMNT(nmp);
}
free(fhp, M_TEMP);
} }
} }
error = nd->nd_repstat; error = nd->nd_repstat;
@@ -8179,7 +8230,7 @@ nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
/* Get the directory's post-op attributes. */ /* Get the directory's post-op attributes. */
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_PUTFH); *tl = txdr_unsigned(NFSV4OP_PUTFH);
nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_GETATTR); *tl = txdr_unsigned(NFSV4OP_GETATTR);
nfsrv_putattrbit(nd, &attrbits); nfsrv_putattrbit(nd, &attrbits);
@@ -8584,7 +8635,7 @@ nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff,
nfsrv_putattrbit(nd, &attrbits); nfsrv_putattrbit(nd, &attrbits);
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_PUTFH); *tl = txdr_unsigned(NFSV4OP_PUTFH);
nfsm_fhtom(nd, VTONFS(outvp)->n_fhp->nfh_fh, nfsm_fhtom(nmp, nd, VTONFS(outvp)->n_fhp->nfh_fh,
VTONFS(outvp)->n_fhp->nfh_len, 0); VTONFS(outvp)->n_fhp->nfh_len, 0);
NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
*tl = txdr_unsigned(NFSV4OP_COPY); *tl = txdr_unsigned(NFSV4OP_COPY);
@@ -9173,3 +9224,37 @@ nfsrpc_bindconnsess(CLIENT *cl, void *arg, struct ucred *cr)
printf("nfsrpc_bindconnsess: reply bad xdr\n"); printf("nfsrpc_bindconnsess: reply bad xdr\n");
m_freem(nd->nd_mrep); m_freem(nd->nd_mrep);
} }
/*
* Do roughly what nfs_statfs() does for NFSv4, but when called with a shared
* locked vnode.
*/
static void
nfscl_statfs(struct vnode *vp, struct ucred *cred, NFSPROC_T *td)
{
struct nfsvattr nfsva;
struct nfsfsinfo fs;
struct nfsstatfs sb;
struct mount *mp;
struct nfsmount *nmp;
uint32_t lease;
int attrflag, error;
mp = vp->v_mount;
nmp = VFSTONFS(mp);
error = nfsrpc_statfs(vp, &sb, &fs, &lease, cred, td, &nfsva,
&attrflag);
if (attrflag != 0)
nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1);
if (error == 0) {
NFSLOCKCLSTATE();
if (nmp->nm_clp != NULL)
nmp->nm_clp->nfsc_renew = NFSCL_RENEW(lease);
NFSUNLOCKCLSTATE();
mtx_lock(&nmp->nm_mtx);
nfscl_loadfsinfo(nmp, &fs);
nfscl_loadsbinfo(nmp, &sb, &mp->mnt_stat);
mp->mnt_stat.f_iosize = newnfs_iosize(nmp);
mtx_unlock(&nmp->nm_mtx);
}
}
+120 -14
View File
@@ -293,13 +293,37 @@ nfs_statfs(struct mount *mp, struct statfs *sbp)
struct nfsstatfs sb; struct nfsstatfs sb;
int error = 0, attrflag, gotfsinfo = 0, ret; int error = 0, attrflag, gotfsinfo = 0, ret;
struct nfsnode *np; struct nfsnode *np;
char *fakefh;
td = curthread; td = curthread;
error = vfs_busy(mp, MBF_NOWAIT); error = vfs_busy(mp, MBF_NOWAIT);
if (error) if (error)
return (error); return (error);
error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, LK_EXCLUSIVE); if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
if (nmp->nm_fhsize == 0) {
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
td->td_ucred, td);
if (error != 0) {
/*
* We cannot do anything yet. Hopefully what
* is in mnt_stat is sufficient.
*/
if (sbp != &mp->mnt_stat)
*sbp = mp->mnt_stat;
strncpy(&sbp->f_fstypename[0],
mp->mnt_vfc->vfc_name, MFSNAMELEN);
vfs_unbusy(mp);
return (0);
}
}
fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | M_ZERO);
error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, LK_EXCLUSIVE);
free(fakefh, M_TEMP);
} else {
error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
LK_EXCLUSIVE);
}
if (error) { if (error) {
vfs_unbusy(mp); vfs_unbusy(mp);
return (error); return (error);
@@ -315,8 +339,19 @@ nfs_statfs(struct mount *mp, struct statfs *sbp)
} else } else
mtx_unlock(&nmp->nm_mtx); mtx_unlock(&nmp->nm_mtx);
if (!error) if (!error)
error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, error = nfsrpc_statfs(vp, &sb, &fs, NULL, td->td_ucred, td,
&attrflag); &nfsva, &attrflag);
if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 &&
error == NFSERR_WRONGSEC) {
/* Cannot get new stats, so return what is in mnt_stat. */
if (sbp != &mp->mnt_stat)
*sbp = mp->mnt_stat;
strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name,
MFSNAMELEN);
vput(vp);
vfs_unbusy(mp);
return (0);
}
if (error != 0) if (error != 0)
NFSCL_DEBUG(2, "statfs=%d\n", error); NFSCL_DEBUG(2, "statfs=%d\n", error);
if (attrflag == 0) { if (attrflag == 0) {
@@ -750,7 +785,7 @@ static const char *nfs_opts[] = { "from", "nfs_args",
"nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath", "nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath",
"minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr", "minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr",
"pnfs", "wcommitsize", "oneopenown", "tls", "tlscertname", "nconnect", "pnfs", "wcommitsize", "oneopenown", "tls", "tlscertname", "nconnect",
NULL }; "syskrb5", NULL };
/* /*
* Parse the "from" mountarg, passed by the generic mount(8) program * Parse the "from" mountarg, passed by the generic mount(8) program
@@ -1206,6 +1241,8 @@ nfs_mount(struct mount *mp)
*/ */
aconn--; aconn--;
} }
if (vfs_getopt(mp->mnt_optnew, "syskrb5", NULL, NULL) == 0)
newflag |= NFSMNT_SYSKRB5;
if (vfs_getopt(mp->mnt_optnew, "sec", if (vfs_getopt(mp->mnt_optnew, "sec",
(void **) &secname, NULL) == 0) (void **) &secname, NULL) == 0)
nfs_sec_name(secname, &args.flags); nfs_sec_name(secname, &args.flags);
@@ -1388,6 +1425,39 @@ nfs_mount(struct mount *mp)
goto out; goto out;
} }
if ((newflag & NFSMNT_SYSKRB5) != 0 &&
((args.flags & NFSMNT_NFSV4) == 0 || minvers == 0)) {
/*
* This option requires the use of SP4_NONE, which
* is only in NFSv4.1/4.2.
*/
vfs_mount_error(mp, "syskrb5 should only be used "
"for NFSv4.1/4.2 mounts");
error = EINVAL;
goto out;
}
if ((newflag & NFSMNT_SYSKRB5) != 0 &&
(args.flags & NFSMNT_KERB) == 0) {
/*
* This option modifies the behaviour of sec=krb5[ip].
*/
vfs_mount_error(mp, "syskrb5 should only be used "
"for sec=krb5[ip] mounts");
error = EINVAL;
goto out;
}
if ((newflag & NFSMNT_SYSKRB5) != 0 && krbname[0] != '\0') {
/*
* This option is used as an alternative to "gssname".
*/
vfs_mount_error(mp, "syskrb5 should not be used "
"with the gssname option");
error = EINVAL;
goto out;
}
args.fh = nfh; args.fh = nfh;
error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath, error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath,
dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td, dirlen, srvkrbname, srvkrbnamelen, &vp, td->td_ucred, td,
@@ -1449,6 +1519,7 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
struct nfsclds *dsp, *tdsp; struct nfsclds *dsp, *tdsp;
uint32_t lease; uint32_t lease;
bool tryminvers; bool tryminvers;
char *fakefh;
static u_int64_t clval = 0; static u_int64_t clval = 0;
#ifdef KERN_TLS #ifdef KERN_TLS
u_int maxlen; u_int maxlen;
@@ -1622,6 +1693,12 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
error = EINVAL; error = EINVAL;
goto bad; goto bad;
} }
if (NFSHASSYSKRB5(nmp) && nmp->nm_minorvers == 0) {
vfs_mount_error(mp, "syskrb5 should only be used "
"for NFSv4.1/4.2 mounts");
error = EINVAL;
goto bad;
}
} }
if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) && if (nmp->nm_fhsize == 0 && (nmp->nm_flag & NFSMNT_NFSV4) &&
@@ -1636,10 +1713,13 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
cred, td); cred, td);
NFSCL_DEBUG(3, "aft dirp=%d\n", error); NFSCL_DEBUG(3, "aft dirp=%d\n", error);
if (error) if (error != 0 && (!NFSHASSYSKRB5(nmp) ||
error != NFSERR_WRONGSEC))
(void) nfs_catnap(PZERO, error, "nfsgetdirp"); (void) nfs_catnap(PZERO, error, "nfsgetdirp");
} while (error && --trycnt > 0); } while (error != 0 && --trycnt > 0 &&
if (error) (!NFSHASSYSKRB5(nmp) || error != NFSERR_WRONGSEC));
if (error != 0 && (!NFSHASSYSKRB5(nmp) ||
error != NFSERR_WRONGSEC))
goto bad; goto bad;
} }
@@ -1650,16 +1730,27 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
* the nfsnode gets flushed out of the cache. Ufs does not have * the nfsnode gets flushed out of the cache. Ufs does not have
* this problem, because one can identify root inodes by their * this problem, because one can identify root inodes by their
* number == UFS_ROOTINO (2). * number == UFS_ROOTINO (2).
* For the "syskrb5" mount, the file handle might not have
* been acquired. As such, use a "fake" file handle which
* can never be returned by a server for the root vnode.
*/ */
if (nmp->nm_fhsize > 0) { if (nmp->nm_fhsize > 0 || NFSHASSYSKRB5(nmp)) {
/* /*
* Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set * Set f_iosize to NFS_DIRBLKSIZ so that bo_bsize gets set
* non-zero for the root vnode. f_iosize will be set correctly * non-zero for the root vnode. f_iosize will be set correctly
* by nfs_statfs() before any I/O occurs. * by nfs_statfs() before any I/O occurs.
*/ */
mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ; mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ;
error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, if (nmp->nm_fhsize == 0) {
LK_EXCLUSIVE); fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK |
M_ZERO);
error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np,
LK_EXCLUSIVE);
free(fakefh, M_TEMP);
nmp->nm_privflag |= NFSMNTP_FAKEROOTFH;
} else
error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np,
LK_EXCLUSIVE);
if (error) if (error)
goto bad; goto bad;
*vpp = NFSTOV(np); *vpp = NFSTOV(np);
@@ -1669,8 +1760,10 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
* mountpoint. This has the side effect of filling in * mountpoint. This has the side effect of filling in
* (*vpp)->v_type with the correct value. * (*vpp)->v_type with the correct value.
*/ */
ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, ret = ENXIO;
cred, td, &nfsva, NULL, &lease); if (nmp->nm_fhsize > 0)
ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh,
nmp->nm_fhsize, 1, cred, td, &nfsva, NULL, &lease);
if (ret) { if (ret) {
/* /*
* Just set default values to get things going. * Just set default values to get things going.
@@ -1685,7 +1778,7 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam,
nfsva.na_vattr.va_gen = 1; nfsva.na_vattr.va_gen = 1;
nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE; nfsva.na_vattr.va_blocksize = NFS_FABLKSIZE;
nfsva.na_vattr.va_size = 512 * 1024; nfsva.na_vattr.va_size = 512 * 1024;
lease = 60; lease = 20;
} }
(void) nfscl_loadattrcache(vpp, &nfsva, NULL, 0, 1); (void) nfscl_loadattrcache(vpp, &nfsva, NULL, 0, 1);
if ((argp->flags & NFSMNT_NFSV4) != 0) { if ((argp->flags & NFSMNT_NFSV4) != 0) {
@@ -1871,9 +1964,20 @@ nfs_root(struct mount *mp, int flags, struct vnode **vpp)
struct nfsmount *nmp; struct nfsmount *nmp;
struct nfsnode *np; struct nfsnode *np;
int error; int error;
char *fakefh;
nmp = VFSTONFS(mp); nmp = VFSTONFS(mp);
error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags); if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0) {
/* Attempt to get the actual root file handle. */
if (nmp->nm_fhsize == 0)
error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp),
curthread->td_ucred, curthread);
fakefh = malloc(NFSX_FHMAX + 1, M_TEMP, M_WAITOK | M_ZERO);
error = ncl_nget(mp, fakefh, NFSX_FHMAX + 1, &np, flags);
free(fakefh, M_TEMP);
} else {
error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, flags);
}
if (error) if (error)
return error; return error;
vp = NFSTOV(np); vp = NFSTOV(np);
@@ -2116,6 +2220,8 @@ void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen)
&buf, &blen); &buf, &blen);
nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf, nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf,
&blen); &blen);
nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_SYSKRB5) != 0,
",syskrb5", &buf, &blen);
nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn", nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn",
&buf, &blen); &buf, &blen);
nfscl_printoptval(nmp, nmp->nm_aconnect + 1, ",nconnect", &buf, &blen); nfscl_printoptval(nmp, nmp->nm_aconnect + 1, ",nconnect", &buf, &blen);
+5 -1
View File
@@ -997,7 +997,9 @@ nfs_getattr(struct vop_getattr_args *ap)
struct nfsvattr nfsva; struct nfsvattr nfsva;
struct vattr *vap = ap->a_vap; struct vattr *vap = ap->a_vap;
struct vattr vattr; struct vattr vattr;
struct nfsmount *nmp;
nmp = VFSTONFS(vp->v_mount);
/* /*
* Update local times for special files. * Update local times for special files.
*/ */
@@ -1007,8 +1009,10 @@ nfs_getattr(struct vop_getattr_args *ap)
NFSUNLOCKNODE(np); NFSUNLOCKNODE(np);
/* /*
* First look in the cache. * First look in the cache.
* For "syskrb5" mounts, nm_fhsize might still be zero and
* cached attributes should be ignored.
*/ */
if (ncl_getattrcache(vp, &vattr) == 0) { if (nmp->nm_fhsize > 0 && ncl_getattrcache(vp, &vattr) == 0) {
ncl_copy_vattr(vap, &vattr); ncl_copy_vattr(vap, &vattr);
/* /*
+2
View File
@@ -125,9 +125,11 @@ struct nfsmount {
#define NFSMNTP_NOALLOCATE 0x00000200 #define NFSMNTP_NOALLOCATE 0x00000200
#define NFSMNTP_DELEGISSUED 0x00000400 #define NFSMNTP_DELEGISSUED 0x00000400
#define NFSMNTP_NODEALLOCATE 0x00000800 #define NFSMNTP_NODEALLOCATE 0x00000800
#define NFSMNTP_FAKEROOTFH 0x00001000
/* New mount flags only used by the kernel via nmount(2). */ /* New mount flags only used by the kernel via nmount(2). */
#define NFSMNT_TLS 0x00000001 #define NFSMNT_TLS 0x00000001
#define NFSMNT_SYSKRB5 0x00000002
#define NFSMNT_DIRPATH(m) (&((m)->nm_name[(m)->nm_krbnamelen + 1])) #define NFSMNT_DIRPATH(m) (&((m)->nm_name[(m)->nm_krbnamelen + 1]))
#define NFSMNT_SRVKRBNAME(m) \ #define NFSMNT_SRVKRBNAME(m) \
+2 -1
View File
@@ -2759,7 +2759,8 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
txdr_hyper(*cookiep, tl); txdr_hyper(*cookiep, tl);
nfsrv_postopattr(nd, 0, nvap); nfsrv_postopattr(nd, 0, nvap);
dirlen += nfsm_fhtom(nd,(u_int8_t *)&nfh,0,1); dirlen += nfsm_fhtom(NULL, nd, (u_int8_t *)&nfh,
0, 1);
dirlen += (5*NFSX_UNSIGNED+NFSX_V3POSTOPATTR); dirlen += (5*NFSX_UNSIGNED+NFSX_V3POSTOPATTR);
if (nvp != NULL) if (nvp != NULL)
vput(nvp); vput(nvp);
+9 -9
View File
@@ -672,10 +672,10 @@ nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
goto out; goto out;
} }
if (nd->nd_flag & ND_NFSV2) { if (nd->nd_flag & ND_NFSV2) {
(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
nfsrv_fillattr(nd, &nva); nfsrv_fillattr(nd, &nva);
} else if (nd->nd_flag & ND_NFSV3) { } else if (nd->nd_flag & ND_NFSV3) {
(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
nfsrv_postopattr(nd, 0, &nva); nfsrv_postopattr(nd, 0, &nva);
nfsrv_postopattr(nd, dattr_ret, &dattr); nfsrv_postopattr(nd, dattr_ret, &dattr);
} }
@@ -1282,7 +1282,7 @@ nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
} }
if (nd->nd_flag & ND_NFSV2) { if (nd->nd_flag & ND_NFSV2) {
if (!nd->nd_repstat) { if (!nd->nd_repstat) {
(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0);
nfsrv_fillattr(nd, &nva); nfsrv_fillattr(nd, &nva);
} }
} else { } else {
@@ -1292,7 +1292,7 @@ nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
vrele(dirp); vrele(dirp);
if (!nd->nd_repstat) { if (!nd->nd_repstat) {
(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1); nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 1);
nfsrv_postopattr(nd, 0, &nva); nfsrv_postopattr(nd, 0, &nva);
} }
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
@@ -1492,7 +1492,7 @@ nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
vrele(dirp); vrele(dirp);
if (!nd->nd_repstat) { if (!nd->nd_repstat) {
if (nd->nd_flag & ND_NFSV3) { if (nd->nd_flag & ND_NFSV3) {
(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
nfsrv_postopattr(nd, 0, &nva); nfsrv_postopattr(nd, 0, &nva);
} else { } else {
NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
@@ -1946,7 +1946,7 @@ nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
if (nd->nd_flag & ND_NFSV3) { if (nd->nd_flag & ND_NFSV3) {
if (!nd->nd_repstat) { if (!nd->nd_repstat) {
(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
nfsrv_postopattr(nd, 0, &nva); nfsrv_postopattr(nd, 0, &nva);
} }
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
@@ -2070,12 +2070,12 @@ nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
if (nd->nd_flag & ND_NFSV3) { if (nd->nd_flag & ND_NFSV3) {
if (!nd->nd_repstat) { if (!nd->nd_repstat) {
(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1);
nfsrv_postopattr(nd, 0, &nva); nfsrv_postopattr(nd, 0, &nva);
} }
nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
} else if (!nd->nd_repstat) { } else if (!nd->nd_repstat) {
(void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0);
nfsrv_fillattr(nd, &nva); nfsrv_fillattr(nd, &nva);
} }
@@ -3462,7 +3462,7 @@ nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
nd->nd_repstat = nfsvno_getfh(vp, &fh, p); nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
vput(vp); vput(vp);
if (!nd->nd_repstat) if (!nd->nd_repstat)
(void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0);
NFSEXITCODE2(0, nd); NFSEXITCODE2(0, nd);
return (0); return (0);
} }
+3 -3
View File
@@ -4529,7 +4529,7 @@ nfsrv_docallback(struct nfsclient *clp, int procnum, nfsv4stateid_t *stateidp,
m_freem(nd->nd_mreq); m_freem(nd->nd_mreq);
goto errout; goto errout;
} }
(void)nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0); nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, NFSX_MYFH, 0);
(void)nfsrv_putattrbit(nd, attrbitp); (void)nfsrv_putattrbit(nd, attrbitp);
} else if (procnum == NFSV4OP_CBRECALL) { } else if (procnum == NFSV4OP_CBRECALL) {
nd->nd_procnum = NFSV4PROC_CBCOMPOUND; nd->nd_procnum = NFSV4PROC_CBCOMPOUND;
@@ -4548,7 +4548,7 @@ nfsrv_docallback(struct nfsclient *clp, int procnum, nfsv4stateid_t *stateidp,
*tl = newnfs_true; *tl = newnfs_true;
else else
*tl = newnfs_false; *tl = newnfs_false;
(void)nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0); nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, NFSX_MYFH, 0);
} else if (procnum == NFSV4OP_CBLAYOUTRECALL) { } else if (procnum == NFSV4OP_CBLAYOUTRECALL) {
NFSD_DEBUG(4, "docallback layout recall\n"); NFSD_DEBUG(4, "docallback layout recall\n");
nd->nd_procnum = NFSV4PROC_CBCOMPOUND; nd->nd_procnum = NFSV4PROC_CBCOMPOUND;
@@ -4567,7 +4567,7 @@ nfsrv_docallback(struct nfsclient *clp, int procnum, nfsv4stateid_t *stateidp,
else else
*tl++ = newnfs_false; *tl++ = newnfs_false;
*tl = txdr_unsigned(NFSV4LAYOUTRET_FILE); *tl = txdr_unsigned(NFSV4LAYOUTRET_FILE);
nfsm_fhtom(nd, (uint8_t *)fhp, NFSX_MYFH, 0); nfsm_fhtom(NULL, nd, (uint8_t *)fhp, NFSX_MYFH, 0);
NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER + NFSX_STATEID); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER + NFSX_STATEID);
tval = 0; tval = 0;
txdr_hyper(tval, tl); tl += 2; txdr_hyper(tval, tl); tl += 2;