From nobody Thu Mar 16 22:59:54 2023 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4Pd2lZ2zF7z3yjXK; Thu, 16 Mar 2023 22:59:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Pd2lZ2jqnz4YbR; Thu, 16 Mar 2023 22:59:54 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1679007594; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=+2bF6FElfvnO3ZK/Vanx7eN9NtgT9ncdfK90n6moLlg=; b=dkVEy+AqrkPyR5rCw2WMQowIKOKeY9deti8C5aCt0Wnyz9KVxYI/Gjn6fO+SghtKXSjwV8 dGJsQBVu4hyiC9OuPl8jS00znZFxHBztOrHHckS9Kw8Ri872+qOBZE32wKlxiFEeeemGuB 6WAB6ArFwJ0hH4IjKCI8m8KYC+GDmOBhIFTrKPeS/3akSnuFbt1tRIIUvGujQUfRdlwHji DnzVBC+KIiyc2NZtKKXmkiuG0f7U1AQORzfnCRdEHW9ZmxiAL5EGnFpUOK9Lt+bv/2KujS DnB1gB7H3wnLWbrgXqScg9c1h8y4SBBMGRCWdgp7E3bB9VAjIUXU70GB14GgqA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1679007594; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=+2bF6FElfvnO3ZK/Vanx7eN9NtgT9ncdfK90n6moLlg=; b=T7VuIUzmCNbWYiYFzz8j5Crw0o9pS1PQaUcutsRY/5fgkAjIuAr5EedT9I90TzaGoRsoOI WDR4j4wJwh5eR2fRBh7lCEF7Aacya+NPrQWJ2Omh1VepdZbrpEo2olviqMDLwGkAtg8jAp LtR3JB4bhnnQoirkCKNr0Yrdn20miH7AO3/1c6PNW4KXxXlc+ntk+VJKBwR1CZ5H70oXP/ tPAdSB7A0i386mpGfMMG/T2F+uRyJWreCaOmJ3PSrFMVz119g3j5BcHe7/uTGdcw41Cfy1 pmAuo2dBpcreFT++d2aF6nmn8iSd7cXKTHOpUNKWsWouVclVJuGCPMfV9W4XmQ== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1679007594; a=rsa-sha256; cv=none; b=niDNFcOXt1kMxacvNo/CrVOTBSLWUdFG6cAfjl8SX8tygeUihobBb46Di7Yj8A0guVTdRz tSb4htjq9F3M5hZbL8Zf1JYoh5jSJTFVRtSKfvIGvPnNPcJEFNAvwO4W/uN/cXfynN6gei U4pSkD0aAzjy3ALNaus2EVNYV5AwD3h+4VV3VQMyPFqcMeGm7aThkRK9SwWd36dL6/iIHg tVCqvyFLB6ugF6yY87ZCk1PF8Ki+HpUYw+MRXdMRZxxjZUW8gq1bBetkpYC5TH7BtFHaCS 9u++W8hrbGMrc5bK0n4WscaGFoGa6EML1xB9E0pCIkTQKMWnk0Sa3deSF7QpfQ== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4Pd2lZ1n36z12d4; Thu, 16 Mar 2023 22:59:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 32GMxs4K030489; Thu, 16 Mar 2023 22:59:54 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 32GMxs4t030488; Thu, 16 Mar 2023 22:59:54 GMT (envelope-from git) Date: Thu, 16 Mar 2023 22:59:54 GMT Message-Id: <202303162259.32GMxs4t030488@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Rick Macklem Subject: git: 896516e54a8c - main - nfscl: Add a new NFSv4.1/4.2 mount option for Kerberized mounts List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: rmacklem X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 896516e54a8c39c1c8be3ad918f38fbf196b57ed Auto-Submitted: auto-generated X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=896516e54a8c39c1c8be3ad918f38fbf196b57ed commit 896516e54a8c39c1c8be3ad918f38fbf196b57ed Author: Rick Macklem AuthorDate: 2023-03-16 22:55:36 +0000 Commit: Rick Macklem CommitDate: 2023-03-16 22:55:36 +0000 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 --- sys/fs/nfs/nfs.h | 7 ++ sys/fs/nfs/nfs_commonkrpc.c | 86 ++++++++++++++++++++++++- sys/fs/nfs/nfs_commonsubs.c | 17 +++-- sys/fs/nfs/nfs_var.h | 5 +- sys/fs/nfs/nfsport.h | 1 + sys/fs/nfsclient/nfs_clnode.c | 4 +- sys/fs/nfsclient/nfs_clport.c | 26 +++++++- sys/fs/nfsclient/nfs_clrpcops.c | 121 +++++++++++++++++++++++++++++------ sys/fs/nfsclient/nfs_clvfsops.c | 134 +++++++++++++++++++++++++++++++++++---- sys/fs/nfsclient/nfs_clvnops.c | 6 +- sys/fs/nfsclient/nfsmount.h | 2 + sys/fs/nfsserver/nfs_nfsdport.c | 3 +- sys/fs/nfsserver/nfs_nfsdserv.c | 18 +++--- sys/fs/nfsserver/nfs_nfsdstate.c | 6 +- 14 files changed, 377 insertions(+), 59 deletions(-) diff --git a/sys/fs/nfs/nfs.h b/sys/fs/nfs/nfs.h index ffd612331c1f..eac318512a35 100644 --- a/sys/fs/nfs/nfs.h +++ b/sys/fs/nfs/nfs.h @@ -522,6 +522,13 @@ typedef struct { (b)->bits[2] = NFSGETATTRBIT_STATFS2; \ } 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) \ (((b)->bits[0] & NFSATTRBIT_STATFS0) || \ ((b)->bits[1] & NFSATTRBIT_STATFS1) || \ diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c index 9badd8be47d4..f98d9f8df99a 100644 --- a/sys/fs/nfs/nfs_commonkrpc.c +++ b/sys/fs/nfs/nfs_commonkrpc.c @@ -162,6 +162,87 @@ static int nfsv2_procid[NFS_V3NPROCS] = { 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. * We do not free the sockaddr if error. @@ -679,7 +760,8 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp, } NFSUNLOCKSTATE(); } 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) nd->nd_flag |= ND_USEGSSNAME; if ((nd->nd_flag & ND_USEGSSNAME) != 0) { @@ -720,7 +802,7 @@ newnfs_request(struct nfsrv_descript *nd, struct nfsmount *nmp, else secflavour = RPCSEC_GSS_KRB5; 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_flag & ND_USEGSSNAME) != 0) { /* diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index e2e15063cf99..9e70eea522c4 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include "opt_inet6.h" #include +#include #include @@ -436,7 +437,7 @@ nfscl_reqstart(struct nfsrv_descript *nd, int procnum, struct nfsmount *nmp, if (nfsv4_opflag[nfsv4_opmap[procnum].op].needscfh > 0) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *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 == 2 && procnum != NFSPROC_WRITEDS && 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); } } else { - (void) nfsm_fhtom(nd, nfhp, fhlen, 0); + nfsm_fhtom(NULL, nd, nfhp, fhlen, 0); } if (procnum < NFSV42_NPROCS) NFSINCRGLOBAL(nfsstatsv1.rpccnt[procnum]); @@ -953,12 +954,15 @@ newnfs_init(void) * Return the number of bytes output, including XDR overhead. */ 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_int8_t *cp; int fullsiz, bytesize = 0; + KASSERT(nmp == NULL || nmp->nm_fhsize > 0, + ("nfsm_fhtom: 0 length fh")); if (size == 0) size = NFSX_MYFH; 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; case ND_NFSV3: 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); if (set_true) { bytesize = 2 * NFSX_UNSIGNED + fullsiz; @@ -2737,7 +2746,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, retnum += NFSX_UNSIGNED; break; 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; case NFSATTRBIT_FILEID: NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 0a6d46964ffd..55396bfb0902 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -327,7 +327,8 @@ int nfsaddr_match(int, union nethostaddr *, NFSSOCKADDR_T); int nfsaddr2_match(NFSSOCKADDR_T, NFSSOCKADDR_T); int nfsm_strtom(struct nfsrv_descript *, const char *, 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); void *nfsm_dissct(struct nfsrv_descript *, int, int); 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, u_int8_t *, int, struct nfscllockowner *, int, int, u_int64_t, 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 *); int nfsrpc_fsinfo(vnode_t, struct nfsfsinfo *, struct ucred *, NFSPROC_T *, struct nfsvattr *, int *); diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h index 3a07d140950c..23e806ab8c47 100644 --- a/sys/fs/nfs/nfsport.h +++ b/sys/fs/nfs/nfsport.h @@ -1085,6 +1085,7 @@ void ncl_copy_vattr(struct vattr *dst, struct vattr *src); #define NFSHASONEOPENOWN(n) (((n)->nm_flag & NFSMNT_ONEOPENOWN) != 0 && \ (n)->nm_minorvers > 0) #define NFSHASTLS(n) (((n)->nm_newflag & NFSMNT_TLS) != 0) +#define NFSHASSYSKRB5(n) (((n)->nm_newflag & NFSMNT_SYSKRB5) != 0) /* * Set boottime. diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c index bc38739ce04c..1fcd243d11d6 100644 --- a/sys/fs/nfsclient/nfs_clnode.c +++ b/sys/fs/nfsclient/nfs_clnode.c @@ -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 correct */ - if ((fhsize == nmp->nm_fhsize) && - !bcmp(fhp, nmp->nm_fh, fhsize)) { + if (fhsize == NFSX_FHMAX + 1 || (fhsize == nmp->nm_fhsize && + !bcmp(fhp, nmp->nm_fh, fhsize))) { if (vp->v_type == VNON) vp->v_type = VDIR; vp->v_vflag |= VV_ROOT; diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index 7a47da3c07bf..495ff3d3c6d1 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -140,6 +140,19 @@ nfscl_nget(struct mount *mntp, struct vnode *dvp, struct nfsfh *nfhp, dnp = VTONFS(dvp); *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); 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 correct */ - if ((nfhp->nfh_len == nmp->nm_fhsize) && - !bcmp(nfhp->nfh_fh, nmp->nm_fh, nfhp->nfh_len)) { + if (nfhp->nfh_len == NFSX_FHMAX + 1 || + (nfhp->nfh_len == nmp->nm_fhsize && + !bcmp(nfhp->nfh_fh, nmp->nm_fh, nfhp->nfh_len))) { if (vp->v_type == VNON) vp->v_type = VDIR; 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. * A pcap revealed packet fragmentation and GETATTR RPC * 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 && - 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) { nfscl_warn_fileid(nmp, &np->n_vattr, nap); error = EIDRM; diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index a26345cb362f..559bf8646625 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -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 *, int, struct nfsvattr *, int *, struct ucred *); 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 *); @@ -305,9 +306,22 @@ nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred, int error; struct nfsrv_descript nfsd, *nd = &nfsd; nfsattrbit_t attrbits; + struct nfsmount *nmp; + struct nfsnode *np; *attrflagp = 0; 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); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *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; int error; 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); if (nd->nd_flag & ND_NFSV4) { 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. */ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *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); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); @@ -2758,7 +2785,7 @@ tryagain: *tl++ = dstateid.other[2]; *tl = txdr_unsigned(NFSV4OP_PUTFH); 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); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_REMOVE); @@ -2846,7 +2873,7 @@ tryagain: NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_PUTFH); 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); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_DELEGRETURN); @@ -2866,7 +2893,7 @@ tryagain: NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_PUTFH); 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); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_SAVEFH); @@ -2883,7 +2910,7 @@ tryagain: (void) nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *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); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); @@ -2894,7 +2921,7 @@ tryagain: } (void) nfsm_strtom(nd, fnameptr, fnamelen); 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); (void) nfsm_strtom(nd, tnameptr, tnamelen); 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); *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); if (nd->nd_flag & ND_NFSV4) { 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); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *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); *tl = txdr_unsigned(NFSV4OP_GETATTR); (void) nfsrv_putattrbit(nd, &attrbits); @@ -4634,7 +4661,8 @@ nfsmout: */ int 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; 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. */ 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); nd->nd_flag |= ND_USEGSSNAME; error = nfscl_request(nd, vp, p, cred); @@ -4657,8 +4688,8 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, return (error); if (nd->nd_repstat == 0) { error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, - NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p, - cred); + NULL, NULL, sbp, fsp, NULL, 0, NULL, leasep, NULL, + p, cred); if (!error) { nmp->nm_fsid[0] = nap->na_filesid[0]; 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; nfsattrbit_t attrbits; int error; + struct nfsnode *np; *attrflagp = 0; nmp = VFSTONFS(vp->v_mount); 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. */ @@ -4909,7 +4952,7 @@ nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, u_int32_t *tl; struct nfsrv_descript nfsd; struct nfsrv_descript *nd = &nfsd; - u_char *cp, *cp2; + u_char *cp, *cp2, *fhp; int error, cnt, len, setnil; u_int32_t *opcntp; @@ -4957,9 +5000,17 @@ nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, len > NFSX_FHMAX) { nd->nd_repstat = NFSERR_BADXDR; } else { - nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len); - if (nd->nd_repstat == 0) - nmp->nm_fhsize = len; + fhp = malloc(len + 1, M_TEMP, M_WAITOK); + nd->nd_repstat = nfsrv_mtostr(nd, fhp, 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; @@ -8179,7 +8230,7 @@ nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, /* Get the directory's post-op attributes. */ NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *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); *tl = txdr_unsigned(NFSV4OP_GETATTR); 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); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *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); NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_COPY); @@ -9173,3 +9224,37 @@ nfsmout: printf("nfsrpc_bindconnsess: reply bad xdr\n"); 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); + } +} diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c index efc92f6e7e19..53f3e7bb1864 100644 --- a/sys/fs/nfsclient/nfs_clvfsops.c +++ b/sys/fs/nfsclient/nfs_clvfsops.c @@ -293,13 +293,37 @@ nfs_statfs(struct mount *mp, struct statfs *sbp) struct nfsstatfs sb; int error = 0, attrflag, gotfsinfo = 0, ret; struct nfsnode *np; + char *fakefh; td = curthread; error = vfs_busy(mp, MBF_NOWAIT); if (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) { vfs_unbusy(mp); return (error); @@ -315,8 +339,19 @@ nfs_statfs(struct mount *mp, struct statfs *sbp) } else mtx_unlock(&nmp->nm_mtx); if (!error) - error = nfsrpc_statfs(vp, &sb, &fs, td->td_ucred, td, &nfsva, - &attrflag); + error = nfsrpc_statfs(vp, &sb, &fs, NULL, td->td_ucred, td, + &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) NFSCL_DEBUG(2, "statfs=%d\n", error); if (attrflag == 0) { @@ -750,7 +785,7 @@ static const char *nfs_opts[] = { "from", "nfs_args", "nfsv3", "sec", "principal", "nfsv4", "gssname", "allgssname", "dirpath", "minorversion", "nametimeo", "negnametimeo", "nocto", "noncontigwr", "pnfs", "wcommitsize", "oneopenown", "tls", "tlscertname", "nconnect", - NULL }; + "syskrb5", NULL }; /* * Parse the "from" mountarg, passed by the generic mount(8) program @@ -1206,6 +1241,8 @@ nfs_mount(struct mount *mp) */ aconn--; } + if (vfs_getopt(mp->mnt_optnew, "syskrb5", NULL, NULL) == 0) + newflag |= NFSMNT_SYSKRB5; if (vfs_getopt(mp->mnt_optnew, "sec", (void **) &secname, NULL) == 0) nfs_sec_name(secname, &args.flags); @@ -1388,6 +1425,39 @@ nfs_mount(struct mount *mp) 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; error = mountnfs(&args, mp, nam, hst, krbname, krbnamelen, dirpath, 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; uint32_t lease; bool tryminvers; + char *fakefh; static u_int64_t clval = 0; #ifdef KERN_TLS u_int maxlen; @@ -1622,6 +1693,12 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, error = EINVAL; 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) && @@ -1636,10 +1713,13 @@ mountnfs(struct nfs_args *argp, struct mount *mp, struct sockaddr *nam, error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), cred, td); NFSCL_DEBUG(3, "aft dirp=%d\n", error); - if (error) + if (error != 0 && (!NFSHASSYSKRB5(nmp) || + error != NFSERR_WRONGSEC)) (void) nfs_catnap(PZERO, error, "nfsgetdirp"); - } while (error && --trycnt > 0); - if (error) + } while (error != 0 && --trycnt > 0 && + (!NFSHASSYSKRB5(nmp) || error != NFSERR_WRONGSEC)); + if (error != 0 && (!NFSHASSYSKRB5(nmp) || + error != NFSERR_WRONGSEC)) 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 * this problem, because one can identify root inodes by their * 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 * non-zero for the root vnode. f_iosize will be set correctly * by nfs_statfs() before any I/O occurs. */ mp->mnt_stat.f_iosize = NFS_DIRBLKSIZ; - error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, - LK_EXCLUSIVE); + if (nmp->nm_fhsize == 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); + nmp->nm_privflag |= NFSMNTP_FAKEROOTFH; + } else + error = ncl_nget(mp, nmp->nm_fh, nmp->nm_fhsize, &np, + LK_EXCLUSIVE); if (error) goto bad; *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 * (*vpp)->v_type with the correct value. */ - ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, nmp->nm_fhsize, 1, - cred, td, &nfsva, NULL, &lease); + ret = ENXIO; + if (nmp->nm_fhsize > 0) + ret = nfsrpc_getattrnovp(nmp, nmp->nm_fh, + nmp->nm_fhsize, 1, cred, td, &nfsva, NULL, &lease); if (ret) { /* * 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_blocksize = NFS_FABLKSIZE; nfsva.na_vattr.va_size = 512 * 1024; - lease = 60; + lease = 20; } (void) nfscl_loadattrcache(vpp, &nfsva, NULL, 0, 1); if ((argp->flags & NFSMNT_NFSV4) != 0) { @@ -1871,9 +1964,20 @@ nfs_root(struct mount *mp, int flags, struct vnode **vpp) struct nfsmount *nmp; struct nfsnode *np; int error; + char *fakefh; 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) return error; vp = NFSTOV(np); @@ -2116,6 +2220,8 @@ void nfscl_retopts(struct nfsmount *nmp, char *buffer, size_t buflen) &buf, &blen); nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_TLS) != 0, ",tls", &buf, &blen); + nfscl_printopt(nmp, (nmp->nm_newflag & NFSMNT_SYSKRB5) != 0, + ",syskrb5", &buf, &blen); nfscl_printopt(nmp, (nmp->nm_flag & NFSMNT_NOCONN) != 0, ",noconn", &buf, &blen); nfscl_printoptval(nmp, nmp->nm_aconnect + 1, ",nconnect", &buf, &blen); diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c index 3e9cf7e3a475..39409852e86f 100644 --- a/sys/fs/nfsclient/nfs_clvnops.c +++ b/sys/fs/nfsclient/nfs_clvnops.c @@ -997,7 +997,9 @@ nfs_getattr(struct vop_getattr_args *ap) struct nfsvattr nfsva; struct vattr *vap = ap->a_vap; struct vattr vattr; + struct nfsmount *nmp; + nmp = VFSTONFS(vp->v_mount); /* * Update local times for special files. */ @@ -1007,8 +1009,10 @@ nfs_getattr(struct vop_getattr_args *ap) NFSUNLOCKNODE(np); /* * 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); /* diff --git a/sys/fs/nfsclient/nfsmount.h b/sys/fs/nfsclient/nfsmount.h index d5771f157034..c9183ebe919f 100644 --- a/sys/fs/nfsclient/nfsmount.h +++ b/sys/fs/nfsclient/nfsmount.h @@ -125,9 +125,11 @@ struct nfsmount { #define NFSMNTP_NOALLOCATE 0x00000200 #define NFSMNTP_DELEGISSUED 0x00000400 #define NFSMNTP_NODEALLOCATE 0x00000800 +#define NFSMNTP_FAKEROOTFH 0x00001000 /* New mount flags only used by the kernel via nmount(2). */ #define NFSMNT_TLS 0x00000001 +#define NFSMNT_SYSKRB5 0x00000002 #define NFSMNT_DIRPATH(m) (&((m)->nm_name[(m)->nm_krbnamelen + 1])) #define NFSMNT_SRVKRBNAME(m) \ diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 9c7169d7daac..56f5c00d0aed 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -2759,7 +2759,8 @@ again: NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); txdr_hyper(*cookiep, tl); 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); if (nvp != NULL) vput(nvp); diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c index 569ddc9141bb..cf88e5ea4ebe 100644 --- a/sys/fs/nfsserver/nfs_nfsdserv.c +++ b/sys/fs/nfsserver/nfs_nfsdserv.c @@ -672,10 +672,10 @@ nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, goto out; } 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); } 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, 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_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); } } else { @@ -1292,7 +1292,7 @@ nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); vrele(dirp); 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_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); @@ -1492,7 +1492,7 @@ nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, *** 72 LINES SKIPPED ***