/*
- * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2020 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* unlawful or unlicensed copies of an Apple operating system, or to
* circumvent, violate, or enable the circumvention or violation of, any
* terms of an Apple operating system software license agreement.
- *
+ *
* Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_OSREFERENCE_LICENSE_HEADER_END@
*/
/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
* FreeBSD-Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk Exp $
*/
+#include <nfs/nfs_conf.h>
+#if CONFIG_NFS
+
/*
* These functions support the macros and help fiddle mbuf chains for
* the nfs op functions. They do things like create the rpc header and
#include <sys/vnode_internal.h>
#include <sys/kpi_mbuf.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <sys/stat.h>
#include <sys/malloc.h>
#include <sys/syscall.h>
#include <sys/domain.h>
#include <libkern/OSAtomic.h>
#include <kern/thread_call.h>
+#include <kern/task.h>
#include <sys/vm.h>
#include <sys/vmparam.h>
#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <nfs/nfsnode.h>
-#if NFSCLIENT
+#if CONFIG_NFS_CLIENT
#define _NFS_XDR_SUBS_FUNCS_ /* define this to get xdrbuf function definitions */
#endif
#include <nfs/xdr_subs.h>
/*
* NFS globals
*/
-struct nfsstats __attribute__((aligned(8))) nfsstats;
+struct nfsstats __attribute__((aligned(8))) nfsstats;
size_t nfs_mbuf_mhlen = 0, nfs_mbuf_minclsize = 0;
/*
case VLNK:
return NFLNK;
case VSOCK:
- if (nfsvers > NFS_VER2)
+ if (nfsvers > NFS_VER2) {
return NFSOCK;
+ }
+ return NFNON;
case VFIFO:
- if (nfsvers > NFS_VER2)
+ if (nfsvers > NFS_VER2) {
return NFFIFO;
+ }
+ return NFNON;
case VBAD:
case VSTR:
case VCPLX:
case NFLNK:
return VLNK;
case NFSOCK:
- if (nfsvers > NFS_VER2)
+ if (nfsvers > NFS_VER2) {
return VSOCK;
+ }
+ OS_FALLTHROUGH;
case NFFIFO:
- if (nfsvers > NFS_VER2)
+ if (nfsvers > NFS_VER2) {
return VFIFO;
+ }
+ OS_FALLTHROUGH;
case NFATTRDIR:
- if (nfsvers > NFS_VER3)
+ if (nfsvers > NFS_VER3) {
return VDIR;
+ }
+ OS_FALLTHROUGH;
case NFNAMEDATTR:
- if (nfsvers > NFS_VER3)
+ if (nfsvers > NFS_VER3) {
return VREG;
+ }
+ OS_FALLTHROUGH;
default:
return VNON;
}
}
}
-#if NFSSERVER
+#if CONFIG_NFS_SERVER
/*
* Mapping of old NFS Version 2 RPC numbers to generic numbers.
NFSPROC_NOOP
};
-#endif /* NFSSERVER */
+#endif /* CONFIG_NFS_SERVER */
/*
* and the reverse mapping from generic to Version 2 procedure numbers
nfs_mbuf_minclsize = ms.minclsize;
}
-#if NFSSERVER
+#if CONFIG_NFS_SERVER
/*
* allocate a list of mbufs to hold the given amount of data
len = 0;
while (len < size) {
- nfsm_mbuf_get(error, &m, (size - len));
- if (error)
+ nfsm_mbuf_getcluster(error, &m, (size - len));
+ if (error) {
break;
- if (!mhead)
+ }
+ if (!mhead) {
mhead = m;
+ }
if (mlast && ((error = mbuf_setnext(mlast, m)))) {
mbuf_free(m);
break;
}
mlen = mbuf_maxlen(m);
- if ((len + mlen) > size)
+ if ((len + mlen) > size) {
mlen = size - len;
+ }
mbuf_setlen(m, mlen);
len += mlen;
cnt++;
*mp = mhead;
*mbcnt = cnt;
}
- return (error);
+ return error;
}
-#endif /* NFSSERVER */
+#endif /* CONFIG_NFS_SERVER */
/*
* nfsm_chain_new_mbuf()
mbuf_t mb;
int error = 0;
- if (nmc->nmc_flags & NFSM_CHAIN_FLAG_ADD_CLUSTERS)
+ if (nmc->nmc_flags & NFSM_CHAIN_FLAG_ADD_CLUSTERS) {
sizehint = nfs_mbuf_minclsize;
+ }
/* allocate a new mbuf */
- nfsm_mbuf_get(error, &mb, sizehint);
- if (error)
- return (error);
- if (mb == NULL)
+ nfsm_mbuf_getcluster(error, &mb, sizehint);
+ if (error) {
+ return error;
+ }
+ if (mb == NULL) {
panic("got NULL mbuf?");
+ }
/* do we have a current mbuf? */
if (nmc->nmc_mcur) {
error = mbuf_setnext(nmc->nmc_mcur, mb);
if (error) {
mbuf_free(mb);
- return (error);
+ return error;
}
}
nmc->nmc_ptr = mbuf_data(mb);
nmc->nmc_left = mbuf_trailingspace(mb);
- return (0);
+ return 0;
}
/*
* Add "len" bytes of opaque data pointed to by "buf" to the given chain.
*/
int
-nfsm_chain_add_opaque_f(struct nfsm_chain *nmc, const u_char *buf, uint32_t len)
+nfsm_chain_add_opaque_f(struct nfsm_chain *nmc, const u_char *buf, size_t len)
{
- uint32_t paddedlen, tlen;
+ size_t paddedlen, tlen;
int error;
paddedlen = nfsm_rndup(len);
while (paddedlen) {
if (!nmc->nmc_left) {
error = nfsm_chain_new_mbuf(nmc, paddedlen);
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
}
tlen = MIN(nmc->nmc_left, paddedlen);
if (tlen) {
if (len) {
- if (tlen > len)
+ if (tlen > len) {
tlen = len;
+ }
bcopy(buf, nmc->nmc_ptr, tlen);
} else {
bzero(nmc->nmc_ptr, tlen);
}
}
}
- return (0);
+ return 0;
}
/*
* Do not XDR pad.
*/
int
-nfsm_chain_add_opaque_nopad_f(struct nfsm_chain *nmc, const u_char *buf, uint32_t len)
+nfsm_chain_add_opaque_nopad_f(struct nfsm_chain *nmc, const u_char *buf, size_t len)
{
- uint32_t tlen;
+ size_t tlen;
int error;
while (len > 0) {
if (nmc->nmc_left <= 0) {
error = nfsm_chain_new_mbuf(nmc, len);
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
}
tlen = MIN(nmc->nmc_left, len);
bcopy(buf, nmc->nmc_ptr, tlen);
len -= tlen;
buf += tlen;
}
- return (0);
+ return 0;
}
/*
* Add "len" bytes of data from "uio" to the given chain.
*/
int
-nfsm_chain_add_uio(struct nfsm_chain *nmc, uio_t uio, uint32_t len)
+nfsm_chain_add_uio(struct nfsm_chain *nmc, uio_t uio, size_t len)
{
- uint32_t paddedlen, tlen;
+ size_t paddedlen, tlen;
int error;
paddedlen = nfsm_rndup(len);
while (paddedlen) {
if (!nmc->nmc_left) {
error = nfsm_chain_new_mbuf(nmc, paddedlen);
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
}
tlen = MIN(nmc->nmc_left, paddedlen);
if (tlen) {
if (len) {
- if (tlen > len)
- tlen = len;
- uiomove(nmc->nmc_ptr, tlen, uio);
+ tlen = MIN(INT32_MAX, MIN(tlen, len));
+ uiomove(nmc->nmc_ptr, (int)tlen, uio);
} else {
bzero(nmc->nmc_ptr, tlen);
}
nmc->nmc_ptr += tlen;
nmc->nmc_left -= tlen;
paddedlen -= tlen;
- if (len)
+ if (len) {
len -= tlen;
+ }
}
}
- return (0);
+ return 0;
}
/*
* Find the length of the NFS mbuf chain
* up to the current encoding/decoding offset.
*/
-int
+size_t
nfsm_chain_offset(struct nfsm_chain *nmc)
{
mbuf_t mb;
- int len = 0;
+ size_t len = 0;
for (mb = nmc->nmc_mhead; mb; mb = mbuf_next(mb)) {
- if (mb == nmc->nmc_mcur)
- return (len + (nmc->nmc_ptr - (caddr_t) mbuf_data(mb)));
+ if (mb == nmc->nmc_mcur) {
+ return len + (nmc->nmc_ptr - (caddr_t) mbuf_data(mb));
+ }
len += mbuf_len(mb);
}
- return (len);
+ return len;
}
/*
* Advance an nfsm_chain by "len" bytes.
*/
int
-nfsm_chain_advance(struct nfsm_chain *nmc, uint32_t len)
+nfsm_chain_advance(struct nfsm_chain *nmc, size_t len)
{
mbuf_t mb;
if (nmc->nmc_left >= len) {
nmc->nmc_left -= len;
nmc->nmc_ptr += len;
- return (0);
+ return 0;
}
len -= nmc->nmc_left;
nmc->nmc_mcur = mb = mbuf_next(nmc->nmc_mcur);
- if (!mb)
- return (EBADRPC);
+ if (!mb) {
+ return EBADRPC;
+ }
nmc->nmc_ptr = mbuf_data(mb);
nmc->nmc_left = mbuf_len(mb);
}
- return (0);
+ return 0;
}
/*
* Reverse decode offset in an nfsm_chain by "len" bytes.
*/
int
-nfsm_chain_reverse(struct nfsm_chain *nmc, uint32_t len)
+nfsm_chain_reverse(struct nfsm_chain *nmc, size_t len)
{
- uint32_t mlen, new_offset;
+ size_t mlen, new_offset;
int error = 0;
mlen = nmc->nmc_ptr - (caddr_t) mbuf_data(nmc->nmc_mcur);
if (len <= mlen) {
nmc->nmc_ptr -= len;
nmc->nmc_left += len;
- return (0);
+ return 0;
}
new_offset = nfsm_chain_offset(nmc) - len;
nfsm_chain_dissect_init(error, nmc, nmc->nmc_mhead);
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
- return (nfsm_chain_advance(nmc, new_offset));
+ return nfsm_chain_advance(nmc, new_offset);
}
/*
nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **pptr)
{
mbuf_t mbcur, mb;
- uint32_t left, need, mblen, cplen, padlen;
+ uint32_t padlen;
+ size_t mblen, cplen, need, left;
u_char *ptr;
int error = 0;
while (nmc->nmc_mcur && (nmc->nmc_left == 0)) {
mb = mbuf_next(nmc->nmc_mcur);
nmc->nmc_mcur = mb;
- if (!mb)
+ if (!mb) {
break;
+ }
nmc->nmc_ptr = mbuf_data(mb);
nmc->nmc_left = mbuf_len(mb);
}
/* check if we've run out of data */
- if (!nmc->nmc_mcur)
- return (EBADRPC);
+ if (!nmc->nmc_mcur) {
+ return EBADRPC;
+ }
/* do we already have a contiguous buffer? */
if (nmc->nmc_left >= len) {
/* the returned pointer will be the current pointer */
*pptr = (u_char*)nmc->nmc_ptr;
error = nfsm_chain_advance(nmc, nfsm_rndup(len));
- return (error);
+ return error;
}
padlen = nfsm_rndup(len) - len;
* The needed bytes won't fit in the current mbuf so we'll
* allocate a new mbuf to hold the contiguous range of data.
*/
- nfsm_mbuf_get(error, &mb, len);
- if (error)
- return (error);
+ nfsm_mbuf_getcluster(error, &mb, len);
+ if (error) {
+ return error;
+ }
/* double check that this mbuf can hold all the data */
if (mbuf_maxlen(mb) < len) {
mbuf_free(mb);
- return (EOVERFLOW);
+ return EOVERFLOW;
}
/* the returned pointer will be the new mbuf's data pointer */
/* insert the new mbuf between the current and next mbufs */
error = mbuf_setnext(mb, mbuf_next(mbcur));
- if (!error)
+ if (!error) {
error = mbuf_setnext(mbcur, mb);
+ }
if (error) {
mbuf_free(mb);
- return (error);
+ return error;
}
/* reduce current mbuf's length by "left" */
error = mbuf_setdata(mb, ptr + cplen, mblen - cplen);
if (error) {
mbuf_setlen(mbcur, mbuf_len(mbcur) - need);
- return (error);
+ return error;
}
/* update pointer/need */
nmc->nmc_ptr += cplen;
need -= cplen;
}
/* if more needed, go to next mbuf */
- if (need)
+ if (need) {
mb = mbuf_next(mb);
+ }
}
/* did we run out of data in the mbuf chain? */
if (need) {
mbuf_setlen(mbcur, mbuf_len(mbcur) - need);
- return (EBADRPC);
+ return EBADRPC;
}
/*
nmc->nmc_left = mbuf_len(mb);
/* move past any padding */
- if (padlen)
+ if (padlen) {
error = nfsm_chain_advance(nmc, padlen);
+ }
- return (error);
+ return error;
}
/*
* The nfsm_chain is advanced by nfsm_rndup("len") bytes.
*/
int
-nfsm_chain_get_opaque_f(struct nfsm_chain *nmc, uint32_t len, u_char *buf)
+nfsm_chain_get_opaque_f(struct nfsm_chain *nmc, size_t len, u_char *buf)
{
- uint32_t cplen, padlen;
+ size_t cplen, padlen;
int error = 0;
padlen = nfsm_rndup(len) - len;
}
/* did we run out of data in the mbuf chain? */
- if (len)
- return (EBADRPC);
+ if (len) {
+ return EBADRPC;
+ }
- if (padlen)
+ if (padlen) {
nfsm_chain_adv(error, nmc, padlen);
+ }
- return (error);
+ return error;
}
/*
* The nfsm_chain is advanced by nfsm_rndup("len") bytes.
*/
int
-nfsm_chain_get_uio(struct nfsm_chain *nmc, uint32_t len, uio_t uio)
+nfsm_chain_get_uio(struct nfsm_chain *nmc, size_t len, uio_t uio)
{
- uint32_t cplen, padlen;
+ size_t cplen, padlen;
int error = 0;
padlen = nfsm_rndup(len) - len;
/* copy as much as we need/can */
cplen = MIN(nmc->nmc_left, len);
if (cplen) {
- error = uiomove(nmc->nmc_ptr, cplen, uio);
- if (error)
- return (error);
+ cplen = MIN(cplen, INT32_MAX);
+ error = uiomove(nmc->nmc_ptr, (int)cplen, uio);
+ if (error) {
+ return error;
+ }
nmc->nmc_ptr += cplen;
nmc->nmc_left -= cplen;
len -= cplen;
}
/* did we run out of data in the mbuf chain? */
- if (len)
- return (EBADRPC);
+ if (len) {
+ return EBADRPC;
+ }
- if (padlen)
+ if (padlen) {
nfsm_chain_adv(error, nmc, padlen);
+ }
- return (error);
+ return error;
}
-#if NFSCLIENT
+#if CONFIG_NFS_CLIENT
int
-nfsm_chain_add_string_nfc(struct nfsm_chain *nmc, const uint8_t *s, uint32_t slen)
+nfsm_chain_add_string_nfc(struct nfsm_chain *nmc, const uint8_t *s, size_t slen)
{
uint8_t smallbuf[64];
uint8_t *nfcname = smallbuf;
size_t buflen = sizeof(smallbuf), nfclen;
int error;
- error = utf8_normalizestr(s, slen, nfcname, &nfclen, buflen, UTF_PRECOMPOSED|UTF_NO_NULL_TERM);
+ error = utf8_normalizestr(s, slen, nfcname, &nfclen, buflen, UTF_PRECOMPOSED | UTF_NO_NULL_TERM);
if (error == ENAMETOOLONG) {
buflen = MAXPATHLEN;
- MALLOC_ZONE(nfcname, uint8_t *, MAXPATHLEN, M_NAMEI, M_WAITOK);
- if (nfcname)
- error = utf8_normalizestr(s, slen, nfcname, &nfclen, buflen, UTF_PRECOMPOSED|UTF_NO_NULL_TERM);
+ nfcname = zalloc(ZV_NAMEI);
+ error = utf8_normalizestr(s, slen, nfcname, &nfclen, buflen, UTF_PRECOMPOSED | UTF_NO_NULL_TERM);
}
/* if we got an error, just use the original string */
- if (error)
+ if (error) {
nfsm_chain_add_string(error, nmc, s, slen);
- else
+ } else {
nfsm_chain_add_string(error, nmc, nfcname, nfclen);
+ }
- if (nfcname && (nfcname != smallbuf))
- FREE_ZONE(nfcname, MAXPATHLEN, M_NAMEI);
- return (error);
+ if (nfcname && (nfcname != smallbuf)) {
+ NFS_ZFREE(ZV_NAMEI, nfcname);
+ }
+ return error;
}
/*
int error = 0;
nfsm_chain_add_32(error, nmc, vtonfsv2_mode(vap->va_type,
- (VATTR_IS_ACTIVE(vap, va_mode) ? vap->va_mode : 0600)));
+ (VATTR_IS_ACTIVE(vap, va_mode) ? vap->va_mode : 0600)));
nfsm_chain_add_32(error, nmc,
- VATTR_IS_ACTIVE(vap, va_uid) ? vap->va_uid : (uint32_t)-1);
+ VATTR_IS_ACTIVE(vap, va_uid) ? vap->va_uid : (uint32_t)-1);
nfsm_chain_add_32(error, nmc,
- VATTR_IS_ACTIVE(vap, va_gid) ? vap->va_gid : (uint32_t)-1);
+ VATTR_IS_ACTIVE(vap, va_gid) ? vap->va_gid : (uint32_t)-1);
nfsm_chain_add_32(error, nmc, szrdev);
nfsm_chain_add_v2time(error, nmc,
- VATTR_IS_ACTIVE(vap, va_access_time) ?
- &vap->va_access_time : NULL);
+ VATTR_IS_ACTIVE(vap, va_access_time) ?
+ &vap->va_access_time : NULL);
nfsm_chain_add_v2time(error, nmc,
- VATTR_IS_ACTIVE(vap, va_modify_time) ?
- &vap->va_modify_time : NULL);
+ VATTR_IS_ACTIVE(vap, va_modify_time) ?
+ &vap->va_modify_time : NULL);
- return (error);
+ return error;
}
/*
* Add an NFSv3 "sattr" structure to an mbuf chain
*/
int
-nfsm_chain_add_v3sattr_f(struct nfsm_chain *nmc, struct vnode_attr *vap)
+nfsm_chain_add_v3sattr_f(
+ __unused struct nfsmount *nmp,
+ struct nfsm_chain *nmc,
+ struct vnode_attr *vap)
{
int error = 0;
}
}
- return (error);
+
+ return error;
}
*/
int
nfsm_chain_get_fh_attr(
+ struct nfsmount *nmp,
struct nfsm_chain *nmc,
nfsnode_t dnp,
vfs_context_t ctx,
gotfh = gotattr = 1;
- if (nfsvers == NFS_VER3) /* check for file handle */
+ if (nfsvers == NFS_VER3) { /* check for file handle */
nfsm_chain_get_32(error, nmc, gotfh);
- if (!error && gotfh) /* get file handle */
+ }
+ if (!error && gotfh) { /* get file handle */
nfsm_chain_get_fh(error, nmc, nfsvers, fhp);
- else
+ } else {
fhp->fh_len = 0;
- if (nfsvers == NFS_VER3) /* check for file attributes */
+ }
+ if (nfsvers == NFS_VER3) { /* check for file attributes */
nfsm_chain_get_32(error, nmc, gotattr);
+ }
nfsmout_if(error);
if (gotattr) {
- if (!gotfh) /* skip attributes */
+ if (!gotfh) { /* skip attributes */
nfsm_chain_adv(error, nmc, NFSX_V3FATTR);
- else /* get attributes */
- error = nfs_parsefattr(nmc, nfsvers, nvap);
+ } else { /* get attributes */
+ error = nfs_parsefattr(nmp, nmc, nfsvers, nvap);
+ }
} else if (gotfh) {
/* we need valid attributes in order to call nfs_nget() */
if (nfs3_getattr_rpc(NULL, NFSTOMP(dnp), fhp->fh_data, fhp->fh_len, 0, ctx, nvap, xidp)) {
}
}
nfsmout:
- return (error);
+ return error;
}
/*
}
nfsm_chain_postop_attr_update_flag(error, nmc, np, *newpostattr, xidp);
- return (error);
+ return error;
}
/*
{
struct timeval tv;
- lck_mtx_lock(nfs_request_mutex);
+ lck_mtx_lock(&nfs_request_mutex);
if (!nfs_xid) {
/*
* Derive initial xid from system time.
nfs_xidwrap++;
nfs_xid++;
}
- *xidp = nfs_xid + ((uint64_t)nfs_xidwrap << 32);
- lck_mtx_unlock(nfs_request_mutex);
+ *xidp = nfs_xid + (nfs_xidwrap << 32);
+ lck_mtx_unlock(&nfs_request_mutex);
}
/*
int proc = ((nfsvers == NFS_VER2) ? nfsv2_procid[req->r_procnum] : (int)req->r_procnum);
return nfsm_rpchead2(nmp, nmp->nm_sotype, NFS_PROG, nfsvers, proc,
- req->r_auth, req->r_cred, req, mrest, xidp, mreqp);
+ req->r_auth, req->r_cred, req, mrest, xidp, mreqp);
+}
+
+/*
+ * get_auiliary_groups: Gets the supplementary groups from a credential.
+ *
+ * IN: cred: credential to get the associated groups from.
+ * OUT: groups: An array of gids of NGROUPS size.
+ * IN: count: The number of groups to get; i.e.; the number of groups the server supports
+ *
+ * returns: The number of groups found.
+ *
+ * Just a wrapper around kauth_cred_getgroups to handle the case of a server supporting less
+ * than NGROUPS.
+ */
+static size_t
+get_auxiliary_groups(kauth_cred_t cred, gid_t groups[NGROUPS], size_t count)
+{
+ gid_t pgid;
+ size_t maxcount = count < NGROUPS ? count + 1 : NGROUPS;
+ size_t i;
+
+ for (i = 0; i < NGROUPS; i++) {
+ groups[i] = -2; /* Initialize to the nobody group */
+ }
+ (void)kauth_cred_getgroups(cred, groups, &maxcount);
+ if (maxcount < 1) {
+ return maxcount;
+ }
+
+ /*
+ * kauth_get_groups returns the primary group followed by the
+ * users auxiliary groups. If the number of groups the server supports
+ * is less than NGROUPS, then we will drop the first group so that
+ * we can send one more group over the wire.
+ */
+
+
+ if (count < NGROUPS) {
+ pgid = kauth_cred_getgid(cred);
+ if (pgid == groups[0]) {
+ maxcount -= 1;
+ for (i = 0; i < maxcount; i++) {
+ groups[i] = groups[i + 1];
+ }
+ }
+ }
+
+ return maxcount;
}
int
-nfsm_rpchead2(struct nfsmount *nmp, int sotype, int prog, int vers, int proc, int auth_type,
- kauth_cred_t cred, struct nfsreq *req, mbuf_t mrest, u_int64_t *xidp, mbuf_t *mreqp)
+nfsm_rpchead2(__unused struct nfsmount *nmp, int sotype, int prog, int vers, int proc, int auth_type,
+ kauth_cred_t cred, struct nfsreq *req, mbuf_t mrest, u_int64_t *xidp, mbuf_t *mreqp)
{
mbuf_t mreq, mb;
- int error, i, grpsiz, auth_len = 0, authsiz, reqlen;
+ size_t i;
+ int error, auth_len = 0, authsiz, reqlen;
size_t headlen;
struct nfsm_chain nmreq;
+ gid_t grouplist[NGROUPS];
+ size_t groupcount = 0;
/* calculate expected auth length */
switch (auth_type) {
- case RPCAUTH_NONE:
- auth_len = 0;
- break;
- case RPCAUTH_SYS:
- {
- gid_t grouplist[NGROUPS];
- int groupcount = NGROUPS;
-
- if (!cred)
- return (EINVAL);
-
- (void)kauth_cred_getgroups(cred, grouplist, &groupcount);
- if (groupcount < 1)
- return (EINVAL);
+ case RPCAUTH_NONE:
+ auth_len = 0;
+ break;
+ case RPCAUTH_SYS:
+ {
+ size_t count = nmp->nm_numgrps < NGROUPS ? nmp->nm_numgrps : NGROUPS;
- auth_len = (((((uint32_t)groupcount - 1) > nmp->nm_numgrps) ?
- nmp->nm_numgrps : (groupcount - 1)) << 2) +
- 5 * NFSX_UNSIGNED;
- break;
- }
- case RPCAUTH_KRB5:
- case RPCAUTH_KRB5I:
- case RPCAUTH_KRB5P:
- if (!req || !cred)
- return (EINVAL);
- auth_len = 5 * NFSX_UNSIGNED + 0; // zero context handle for now
- break;
- default:
- return (EINVAL);
+ if (!cred) {
+ return EINVAL;
}
+ groupcount = get_auxiliary_groups(cred, grouplist, count);
+ auth_len = ((uint32_t)groupcount + 5) * NFSX_UNSIGNED;
+ break;
+ }
+#if CONFIG_NFS_GSS
+ case RPCAUTH_KRB5:
+ case RPCAUTH_KRB5I:
+ case RPCAUTH_KRB5P:
+ if (!req || !cred) {
+ return EINVAL;
+ }
+ auth_len = 5 * NFSX_UNSIGNED + 0; // zero context handle for now
+ break;
+#endif /* CONFIG_NFS_GSS */
+ default:
+ return EINVAL;
+ }
authsiz = nfsm_rndup(auth_len);
/* allocate the packet */
headlen = authsiz + 10 * NFSX_UNSIGNED;
- if (sotype == SOCK_STREAM) /* also include room for any RPC Record Mark */
+ if (sotype == SOCK_STREAM) { /* also include room for any RPC Record Mark */
headlen += NFSX_UNSIGNED;
+ }
if (headlen >= nfs_mbuf_minclsize) {
error = mbuf_getpacket(MBUF_WAITOK, &mreq);
} else {
error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &mreq);
if (!error) {
- if (headlen < nfs_mbuf_mhlen)
+ if (headlen < nfs_mbuf_mhlen) {
mbuf_align_32(mreq, headlen);
- else
+ } else {
mbuf_align_32(mreq, 8 * NFSX_UNSIGNED);
+ }
}
}
if (error) {
/* unable to allocate packet */
/* XXX should we keep statistics for these errors? */
- return (error);
+ return error;
}
/*
* it may be a higher-level resend with a GSSAPI credential.
* Otherwise, allocate a new one.
*/
- if (*xidp == 0)
+ if (*xidp == 0) {
nfs_get_xid(xidp);
+ }
/* build the header(s) */
nfsm_chain_init(&nmreq, mreq);
/* First, if it's a TCP stream insert space for an RPC record mark */
- if (sotype == SOCK_STREAM)
+ if (sotype == SOCK_STREAM) {
nfsm_chain_add_32(error, &nmreq, 0);
+ }
/* Then the RPC header. */
nfsm_chain_add_32(error, &nmreq, (*xidp & 0xffffffff));
nfsm_chain_add_32(error, &nmreq, vers);
nfsm_chain_add_32(error, &nmreq, proc);
+#if CONFIG_NFS_GSS
add_cred:
+#endif
switch (auth_type) {
case RPCAUTH_NONE:
nfsm_chain_add_32(error, &nmreq, RPCAUTH_NONE); /* auth */
- nfsm_chain_add_32(error, &nmreq, 0); /* length */
- nfsm_chain_add_32(error, &nmreq, RPCAUTH_NONE); /* verf */
- nfsm_chain_add_32(error, &nmreq, 0); /* length */
+ nfsm_chain_add_32(error, &nmreq, 0); /* length */
+ nfsm_chain_add_32(error, &nmreq, RPCAUTH_NONE); /* verf */
+ nfsm_chain_add_32(error, &nmreq, 0); /* length */
nfsm_chain_build_done(error, &nmreq);
/* Append the args mbufs */
- if (!error)
+ if (!error) {
error = mbuf_setnext(nmreq.nmc_mcur, mrest);
+ }
break;
case RPCAUTH_SYS: {
- gid_t grouplist[NGROUPS];
- int groupcount;
-
nfsm_chain_add_32(error, &nmreq, RPCAUTH_SYS);
nfsm_chain_add_32(error, &nmreq, authsiz);
- nfsm_chain_add_32(error, &nmreq, 0); /* stamp */
- nfsm_chain_add_32(error, &nmreq, 0); /* zero-length hostname */
- nfsm_chain_add_32(error, &nmreq, kauth_cred_getuid(cred)); /* UID */
- nfsm_chain_add_32(error, &nmreq, kauth_cred_getgid(cred)); /* GID */
- grpsiz = (auth_len >> 2) - 5;
- nfsm_chain_add_32(error, &nmreq, grpsiz);/* additional GIDs */
- memset(grouplist, 0, sizeof(grouplist));
- groupcount = grpsiz;
- (void)kauth_cred_getgroups(cred, grouplist, &groupcount);
- for (i = 1; i <= grpsiz; i++)
+ {
+ nfsm_chain_add_32(error, &nmreq, 0); /* stamp */
+ }
+ nfsm_chain_add_32(error, &nmreq, 0); /* zero-length hostname */
+ nfsm_chain_add_32(error, &nmreq, kauth_cred_getuid(cred)); /* UID */
+ nfsm_chain_add_32(error, &nmreq, kauth_cred_getgid(cred)); /* GID */
+ nfsm_chain_add_32(error, &nmreq, groupcount);/* additional GIDs */
+ for (i = 0; i < groupcount; i++) {
nfsm_chain_add_32(error, &nmreq, grouplist[i]);
+ }
/* And the verifier... */
- nfsm_chain_add_32(error, &nmreq, RPCAUTH_NONE); /* flavor */
- nfsm_chain_add_32(error, &nmreq, 0); /* length */
+ nfsm_chain_add_32(error, &nmreq, RPCAUTH_NONE); /* flavor */
+ nfsm_chain_add_32(error, &nmreq, 0); /* length */
nfsm_chain_build_done(error, &nmreq);
/* Append the args mbufs */
- if (!error)
+ if (!error) {
error = mbuf_setnext(nmreq.nmc_mcur, mrest);
+ }
break;
}
+#if CONFIG_NFS_GSS
case RPCAUTH_KRB5:
case RPCAUTH_KRB5I:
case RPCAUTH_KRB5P:
error = nfs_gss_clnt_cred_put(req, &nmreq, mrest);
if (error == ENEEDAUTH) {
- gid_t grouplist[NGROUPS];
- int groupcount = NGROUPS;
+ size_t count = nmp->nm_numgrps < NGROUPS ? nmp->nm_numgrps : NGROUPS;
+
/*
* Use sec=sys for this user
*/
error = 0;
req->r_auth = auth_type = RPCAUTH_SYS;
- (void)kauth_cred_getgroups(cred, grouplist, &groupcount);
- auth_len = (((((uint32_t)groupcount - 1) > nmp->nm_numgrps) ?
- nmp->nm_numgrps : (groupcount - 1)) << 2) +
- 5 * NFSX_UNSIGNED;
+ groupcount = get_auxiliary_groups(cred, grouplist, count);
+ auth_len = ((uint32_t)groupcount + 5) * NFSX_UNSIGNED;
authsiz = nfsm_rndup(auth_len);
goto add_cred;
}
break;
- };
+#endif /* CONFIG_NFS_GSS */
+ }
+ ;
/* finish setting up the packet */
- if (!error)
+ if (!error) {
error = mbuf_pkthdr_setrcvif(mreq, 0);
+ }
if (error) {
mbuf_freem(mreq);
- return (error);
+ return error;
}
/* Calculate the size of the request */
reqlen = 0;
- for (mb = nmreq.nmc_mhead; mb; mb = mbuf_next(mb))
+ for (mb = nmreq.nmc_mhead; mb; mb = mbuf_next(mb)) {
reqlen += mbuf_len(mb);
+ }
mbuf_pkthdr_setlen(mreq, reqlen);
* The record mark count doesn't include itself
* and the last fragment bit is set.
*/
- if (sotype == SOCK_STREAM)
+ if (sotype == SOCK_STREAM) {
nfsm_chain_set_recmark(error, &nmreq,
- (reqlen - NFSX_UNSIGNED) | 0x80000000);
+ (reqlen - NFSX_UNSIGNED) | 0x80000000);
+ }
*mreqp = mreq;
- return (0);
+ return 0;
}
/*
* Parse an NFS file attribute structure out of an mbuf chain.
*/
int
-nfs_parsefattr(struct nfsm_chain *nmc, int nfsvers, struct nfs_vattr *nvap)
+nfs_parsefattr(
+ __unused struct nfsmount *nmp,
+ struct nfsm_chain *nmc,
+ int nfsvers,
+ struct nfs_vattr *nvap)
{
int error = 0;
enum vtype vtype;
nfstype nvtype;
- u_short vmode;
- uint32_t val, val2;
+ uint32_t vmode, val, val2;
dev_t rdev;
val = val2 = 0;
* sockets and FIFOs for fa_type).
*/
vtype = nfstov_type(nvtype, nfsvers);
- if ((vtype == VNON) || ((vtype == VREG) && ((vmode & S_IFMT) != 0)))
+ if ((vtype == VNON) || ((vtype == VREG) && ((vmode & S_IFMT) != 0))) {
vtype = IFTOVT(vmode);
+ }
nvap->nva_type = vtype;
}
nfsmout_if(error);
nvap->nva_fileid = (uint64_t)val;
/* Really ugly NFSv2 kludge. */
- if ((vtype == VCHR) && (rdev == (dev_t)0xffffffff))
+ if ((vtype == VCHR) && (rdev == (dev_t)0xffffffff)) {
nvap->nva_type = VFIFO;
+ }
}
nfsm_chain_get_time(error, nmc, nfsvers,
- nvap->nva_timesec[NFSTIME_ACCESS],
- nvap->nva_timensec[NFSTIME_ACCESS]);
+ nvap->nva_timesec[NFSTIME_ACCESS],
+ nvap->nva_timensec[NFSTIME_ACCESS]);
nfsm_chain_get_time(error, nmc, nfsvers,
- nvap->nva_timesec[NFSTIME_MODIFY],
- nvap->nva_timensec[NFSTIME_MODIFY]);
+ nvap->nva_timesec[NFSTIME_MODIFY],
+ nvap->nva_timensec[NFSTIME_MODIFY]);
nfsm_chain_get_time(error, nmc, nfsvers,
- nvap->nva_timesec[NFSTIME_CHANGE],
- nvap->nva_timensec[NFSTIME_CHANGE]);
+ nvap->nva_timesec[NFSTIME_CHANGE],
+ nvap->nva_timensec[NFSTIME_CHANGE]);
+
nfsmout:
- return (error);
+ return error;
}
+
/*
* Load the attribute cache (that lives in the nfsnode entry) with
* the value pointed to by nvap, unless the file type in the attribute
if (!((nmp = VFSTONFS(mp)))) {
FSDBG_BOT(527, ENXIO, 1, 0, *xidp);
- return (ENXIO);
+ return ENXIO;
}
if (*xidp < np->n_xid) {
NATTRINVALIDATE(np);
FSDBG_BOT(527, 0, np, np->n_xid, *xidp);
*xidp = 0;
- return (0);
+ return 0;
}
if (vp && (nvap->nva_type != vnode_vtype(vp))) {
* object type.
*/
printf("nfs loadattrcache vnode changed type, was %d now %d\n",
- vnode_vtype(vp), nvap->nva_type);
+ vnode_vtype(vp), nvap->nva_type);
error = ESTALE;
- if (monitored)
+ if (monitored) {
events |= VNODE_EVENT_DELETE;
+ }
goto out;
}
* For monitored nodes, check for attribute changes that should generate events.
*/
if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_NUMLINKS) &&
- (nvap->nva_nlink != npnvap->nva_nlink))
+ (nvap->nva_nlink != npnvap->nva_nlink)) {
events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_LINK;
- if (events & VNODE_EVENT_PERMS)
+ }
+ if (events & VNODE_EVENT_PERMS) {
/* no need to do all the checking if it's already set */;
- else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_MODE) &&
- (nvap->nva_mode != npnvap->nva_mode))
+ } else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_MODE) &&
+ (nvap->nva_mode != npnvap->nva_mode)) {
events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
- else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER) &&
- (nvap->nva_uid != npnvap->nva_uid))
+ } else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER) &&
+ (nvap->nva_uid != npnvap->nva_uid)) {
events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
- else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP) &&
- (nvap->nva_gid != npnvap->nva_gid))
+ } else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP) &&
+ (nvap->nva_gid != npnvap->nva_gid)) {
events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
- else if (nmp->nm_vers >= NFS_VER4) {
+#if CONFIG_NFS4
+ } else if (nmp->nm_vers >= NFS_VER4) {
if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER) &&
- !kauth_guid_equal(&nvap->nva_uuuid, &npnvap->nva_uuuid))
+ !kauth_guid_equal(&nvap->nva_uuuid, &npnvap->nva_uuuid)) {
events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
- else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP) &&
- !kauth_guid_equal(&nvap->nva_guuid, &npnvap->nva_guuid))
+ } else if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_OWNER_GROUP) &&
+ !kauth_guid_equal(&nvap->nva_guuid, &npnvap->nva_guuid)) {
events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
- else if ((NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_ACL) &&
- nvap->nva_acl && npnvap->nva_acl &&
- ((nvap->nva_acl->acl_entrycount != npnvap->nva_acl->acl_entrycount) ||
- bcmp(nvap->nva_acl, npnvap->nva_acl, KAUTH_ACL_COPYSIZE(nvap->nva_acl)))))
+ } else if ((NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_ACL) &&
+ nvap->nva_acl && npnvap->nva_acl &&
+ ((nvap->nva_acl->acl_entrycount != npnvap->nva_acl->acl_entrycount) ||
+ bcmp(nvap->nva_acl, npnvap->nva_acl, KAUTH_ACL_COPYSIZE(nvap->nva_acl))))) {
events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_PERMS;
+ }
+#endif
}
- if (((nmp->nm_vers >= NFS_VER4) && (nvap->nva_change != npnvap->nva_change)) ||
- (NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_TIME_MODIFY) &&
- ((nvap->nva_timesec[NFSTIME_MODIFY] != npnvap->nva_timesec[NFSTIME_MODIFY]) ||
- (nvap->nva_timensec[NFSTIME_MODIFY] != npnvap->nva_timensec[NFSTIME_MODIFY]))))
+ if (/* Oh, C... */
+#if CONFIG_NFS4
+ ((nmp->nm_vers >= NFS_VER4) && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_CHANGE) && (nvap->nva_change != npnvap->nva_change)) ||
+#endif
+ (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_MODIFY) &&
+ ((nvap->nva_timesec[NFSTIME_MODIFY] != npnvap->nva_timesec[NFSTIME_MODIFY]) ||
+ (nvap->nva_timensec[NFSTIME_MODIFY] != npnvap->nva_timensec[NFSTIME_MODIFY])))) {
events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_WRITE;
- if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_RAWDEV) &&
+ }
+ if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_RAWDEV) &&
((nvap->nva_rawdev.specdata1 != npnvap->nva_rawdev.specdata1) ||
- (nvap->nva_rawdev.specdata2 != npnvap->nva_rawdev.specdata2)))
+ (nvap->nva_rawdev.specdata2 != npnvap->nva_rawdev.specdata2))) {
events |= VNODE_EVENT_ATTRIB;
- if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_FILEID) &&
- (nvap->nva_fileid != npnvap->nva_fileid))
+ }
+ if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_FILEID) &&
+ (nvap->nva_fileid != npnvap->nva_fileid)) {
events |= VNODE_EVENT_ATTRIB;
- if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_ARCHIVE) &&
- ((nvap->nva_flags & NFS_FFLAG_ARCHIVED) != (npnvap->nva_flags & NFS_FFLAG_ARCHIVED)))
+ }
+ if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_ARCHIVE) &&
+ ((nvap->nva_flags & NFS_FFLAG_ARCHIVED) != (npnvap->nva_flags & NFS_FFLAG_ARCHIVED))) {
events |= VNODE_EVENT_ATTRIB;
- if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_HIDDEN) &&
- ((nvap->nva_flags & NFS_FFLAG_HIDDEN) != (npnvap->nva_flags & NFS_FFLAG_HIDDEN)))
+ }
+ if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_HIDDEN) &&
+ ((nvap->nva_flags & NFS_FFLAG_HIDDEN) != (npnvap->nva_flags & NFS_FFLAG_HIDDEN))) {
events |= VNODE_EVENT_ATTRIB;
- if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_TIME_CREATE) &&
+ }
+ if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_CREATE) &&
((nvap->nva_timesec[NFSTIME_CREATE] != npnvap->nva_timesec[NFSTIME_CREATE]) ||
- (nvap->nva_timensec[NFSTIME_CREATE] != npnvap->nva_timensec[NFSTIME_CREATE])))
+ (nvap->nva_timensec[NFSTIME_CREATE] != npnvap->nva_timensec[NFSTIME_CREATE]))) {
events |= VNODE_EVENT_ATTRIB;
- if (!events && NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_TIME_BACKUP) &&
+ }
+ if (!events && NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_TIME_BACKUP) &&
((nvap->nva_timesec[NFSTIME_BACKUP] != npnvap->nva_timesec[NFSTIME_BACKUP]) ||
- (nvap->nva_timensec[NFSTIME_BACKUP] != npnvap->nva_timensec[NFSTIME_BACKUP])))
+ (nvap->nva_timensec[NFSTIME_BACKUP] != npnvap->nva_timensec[NFSTIME_BACKUP]))) {
events |= VNODE_EVENT_ATTRIB;
+ }
}
+#if CONFIG_NFS4
/* Copy the attributes to the attribute cache */
- bcopy((caddr_t)nvap, (caddr_t)npnvap, sizeof(*nvap));
+ if (nmp->nm_vers >= NFS_VER4 && npnvap->nva_flags & NFS_FFLAG_PARTIAL_WRITE) {
+ /*
+ * NFSv4 WRITE RPCs contain partial GETATTR requests - only type, change, size, metadatatime and modifytime are requested.
+ * In such cases, we do not update the time stamp - but the requested attributes.
+ */
+ NFS_BITMAP_COPY_ATTR(nvap, npnvap, TYPE, type);
+ NFS_BITMAP_COPY_ATTR(nvap, npnvap, CHANGE, change);
+ NFS_BITMAP_COPY_ATTR(nvap, npnvap, SIZE, size);
+ NFS_BITMAP_COPY_TIME(nvap, npnvap, METADATA, CHANGE);
+ NFS_BITMAP_COPY_TIME(nvap, npnvap, MODIFY, MODIFY);
+ } else
+#endif /* CONFIG_NFS4 */
+ {
+ bcopy((caddr_t)nvap, (caddr_t)npnvap, sizeof(*nvap));
+ microuptime(&now);
+ np->n_attrstamp = now.tv_sec;
+ }
- microuptime(&now);
- np->n_attrstamp = now.tv_sec;
np->n_xid = *xidp;
/* NFS_FFLAG_IS_ATTR and NFS_FFLAG_TRIGGER_REFERRAL need to be sticky... */
- if (vp && xattr)
+ if (vp && xattr) {
nvap->nva_flags |= xattr;
- if (vp && referral)
+ }
+ if (vp && referral) {
nvap->nva_flags |= referral;
+ }
- if (NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_ACL)) {
+ if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_ACL)) {
/* we're updating the ACL */
if (nvap->nva_acl) {
/* make a copy of the acl for the cache */
acl = NULL;
}
}
- if (NFS_BITMAP_ISSET(npnvap->nva_bitmap, NFS_FATTR_ACL)) {
+ if (NFS_BITMAP_ISSET(nvap->nva_bitmap, NFS_FATTR_ACL)) {
/* update the ACL timestamp */
np->n_aclstamp = now.tv_sec;
} else {
/* we aren't updating the ACL, so restore original values */
- if (aclbit)
+ if (aclbit) {
NFS_BITMAP_SET(npnvap->nva_bitmap, NFS_FATTR_ACL);
+ }
npnvap->nva_acl = acl;
}
#if CONFIG_TRIGGERS
+#if CONFIG_NFS4
/*
* For NFSv4, if the fsid doesn't match the fsid for the mount, then
* this node is for a different file system on the server. So we mark
*/
if ((nmp->nm_vers >= NFS_VER4) && (nvap->nva_type == VDIR) &&
((np->n_vattr.nva_fsid.major != nmp->nm_fsid.major) ||
- (np->n_vattr.nva_fsid.minor != nmp->nm_fsid.minor)))
+ (np->n_vattr.nva_fsid.minor != nmp->nm_fsid.minor))) {
np->n_vattr.nva_flags |= NFS_FFLAG_TRIGGER;
-#endif
+ }
+#endif /* CONFIG_NFS4 */
+#endif /* CONFIG_TRIGGERS */
if (!vp || (nvap->nva_type != VREG)) {
np->n_size = nvap->nva_size;
*/
np->n_newsize = nvap->nva_size;
SET(np->n_flag, NUPDATESIZE);
- if (monitored)
+ if (monitored) {
events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_EXTEND;
+ }
}
}
}
out:
- if (monitored && events)
+ if (monitored && events) {
nfs_vnode_notify(np, events);
+ }
FSDBG_BOT(527, error, np, np->n_size, *xidp);
- return (error);
+ return error;
}
/*
* Calculate the attribute timeout based on
* how recently the file has been modified.
*/
-int
+long
nfs_attrcachetimeout(nfsnode_t np)
{
struct nfsmount *nmp;
struct timeval now;
int isdir;
- uint32_t timeo;
+ long timeo;
- if (!(nmp = NFSTONMP(np)))
- return (0);
+ nmp = NFSTONMP(np);
+ if (nfs_mount_gone(nmp)) {
+ return 0;
+ }
isdir = vnode_isdir(NFSTOV(np));
-
+#if CONFIG_NFS4
if ((nmp->nm_vers >= NFS_VER4) && (np->n_openflags & N_DELEG_MASK)) {
/* If we have a delegation, we always use the max timeout. */
timeo = isdir ? nmp->nm_acdirmax : nmp->nm_acregmax;
- } else if ((np)->n_flag & NMODIFIED) {
+ } else
+#endif
+ if ((np)->n_flag & NMODIFIED) {
/* If we have modifications, we always use the min timeout. */
timeo = isdir ? nmp->nm_acdirmin : nmp->nm_acregmin;
} else {
microtime(&now);
timeo = (now.tv_sec - (np)->n_vattr.nva_timesec[NFSTIME_MODIFY]) / 10;
if (isdir) {
- if (timeo < nmp->nm_acdirmin)
+ if (timeo < nmp->nm_acdirmin) {
timeo = nmp->nm_acdirmin;
- else if (timeo > nmp->nm_acdirmax)
+ } else if (timeo > nmp->nm_acdirmax) {
timeo = nmp->nm_acdirmax;
+ }
} else {
- if (timeo < nmp->nm_acregmin)
+ if (timeo < nmp->nm_acregmin) {
timeo = nmp->nm_acregmin;
- else if (timeo > nmp->nm_acregmax)
+ } else if (timeo > nmp->nm_acregmax) {
timeo = nmp->nm_acregmax;
+ }
}
}
- return (timeo);
+ return timeo;
}
/*
{
struct nfs_vattr *nvap;
struct timeval nowup;
- int32_t timeo;
+ long timeo;
+ struct nfsmount *nmp;
/* Check if the attributes are valid. */
if (!NATTRVALID(np) || ((flags & NGA_ACL) && !NACLVALID(np))) {
FSDBG(528, np, 0, 0xffffff01, ENOENT);
OSAddAtomic64(1, &nfsstats.attrcache_misses);
- return (ENOENT);
+ return ENOENT;
}
- /* Verify the cached attributes haven't timed out. */
- timeo = nfs_attrcachetimeout(np);
- microuptime(&nowup);
- if ((nowup.tv_sec - np->n_attrstamp) >= timeo) {
- FSDBG(528, np, 0, 0xffffff02, ENOENT);
- OSAddAtomic64(1, &nfsstats.attrcache_misses);
- return (ENOENT);
+ nmp = NFSTONMP(np);
+ if (nfs_mount_gone(nmp)) {
+ return ENXIO;
}
- if ((flags & NGA_ACL) && ((nowup.tv_sec - np->n_aclstamp) >= timeo)) {
- FSDBG(528, np, 0, 0xffffff02, ENOENT);
- OSAddAtomic64(1, &nfsstats.attrcache_misses);
- return (ENOENT);
+ /*
+ * Verify the cached attributes haven't timed out.
+ * If the server isn't responding, skip the check
+ * and return cached attributes.
+ */
+ if (!nfs_use_cache(nmp)) {
+ microuptime(&nowup);
+ if (np->n_attrstamp > nowup.tv_sec) {
+ printf("NFS: Attribute time stamp is in the future by %ld seconds. Invalidating cache\n",
+ np->n_attrstamp - nowup.tv_sec);
+ NATTRINVALIDATE(np);
+ NACCESSINVALIDATE(np);
+ return ENOENT;
+ }
+ timeo = nfs_attrcachetimeout(np);
+ if ((nowup.tv_sec - np->n_attrstamp) >= timeo) {
+ FSDBG(528, np, 0, 0xffffff02, ENOENT);
+ OSAddAtomic64(1, &nfsstats.attrcache_misses);
+ return ENOENT;
+ }
+ if ((flags & NGA_ACL) && ((nowup.tv_sec - np->n_aclstamp) >= timeo)) {
+ FSDBG(528, np, 0, 0xffffff02, ENOENT);
+ OSAddAtomic64(1, &nfsstats.attrcache_misses);
+ return ENOENT;
+ }
}
nvap = &np->n_vattr;
if (nvap->nva_acl) {
if (flags & NGA_ACL) {
nvaper->nva_acl = kauth_acl_alloc(nvap->nva_acl->acl_entrycount);
- if (!nvaper->nva_acl)
- return (ENOMEM);
+ if (!nvaper->nva_acl) {
+ return ENOMEM;
+ }
bcopy(nvap->nva_acl, nvaper->nva_acl, KAUTH_ACL_COPYSIZE(nvap->nva_acl));
} else {
nvaper->nva_acl = NULL;
}
}
- return (0);
+ return 0;
}
/*
int
nfs_uaddr2sockaddr(const char *uaddr, struct sockaddr *addr)
{
- const char *p, *pd; /* pointers to current character in scan */
- const char *pnum; /* pointer to current number to decode */
- const char *pscope; /* pointer to IPv6 scope ID */
- uint8_t a[18]; /* octet array to store address bytes */
- int i; /* index of next octet to decode */
- int dci; /* index of octet to insert double-colon zeroes */
- int dcount, xdcount; /* count of digits in current number */
- int needmore; /* set when we know we need more input (e.g. after colon, period) */
- int dots; /* # of dots */
- int hex; /* contains hex values */
- unsigned long val; /* decoded value */
- int s; /* index used for sliding array to insert elided zeroes */
-
-#define HEXVALUE 0
-#define DECIMALVALUE 1
+ const char *p, *pd; /* pointers to current character in scan */
+ const char *pnum; /* pointer to current number to decode */
+ const char *pscope; /* pointer to IPv6 scope ID */
+ uint8_t a[18]; /* octet array to store address bytes */
+ int i; /* index of next octet to decode */
+ int dci; /* index of octet to insert double-colon zeroes */
+ int dcount, xdcount; /* count of digits in current number */
+ int needmore; /* set when we know we need more input (e.g. after colon, period) */
+ int dots; /* # of dots */
+ int hex; /* contains hex values */
+ unsigned long val; /* decoded value */
+ int s; /* index used for sliding array to insert elided zeroes */
+
+ /* AF_LOCAL address are paths that start with '/' or are empty */
+ if (*uaddr == '/' || *uaddr == '\0') { /* AF_LOCAL address */
+ struct sockaddr_un *sun = (struct sockaddr_un *)addr;
+ sun->sun_family = AF_LOCAL;
+ sun->sun_len = sizeof(struct sockaddr_un);
+ strlcpy(sun->sun_path, uaddr, sizeof(sun->sun_path));
+
+ return 1;
+ }
+
+#define HEXVALUE 0
+#define DECIMALVALUE 1
+
#define GET(TYPE) \
do { \
- if ((dcount <= 0) || (dcount > (((TYPE) == DECIMALVALUE) ? 3 : 4))) \
- return (0); \
- if (((TYPE) == DECIMALVALUE) && xdcount) \
- return (0); \
- val = strtoul(pnum, NULL, ((TYPE) == DECIMALVALUE) ? 10 : 16); \
- if (((TYPE) == DECIMALVALUE) && (val >= 256)) \
- return (0); \
- /* check if there is room left in the array */ \
- if (i > (int)(sizeof(a) - (((TYPE) == HEXVALUE) ? 2 : 1) - ((dci != -1) ? 2 : 0))) \
- return (0); \
- if ((TYPE) == HEXVALUE) \
- a[i++] = ((val >> 8) & 0xff); \
- a[i++] = (val & 0xff); \
+ if ((dcount <= 0) || (dcount > (((TYPE) == DECIMALVALUE) ? 3 : 4))) \
+ return (0); \
+ if (((TYPE) == DECIMALVALUE) && xdcount) \
+ return (0); \
+ val = strtoul(pnum, NULL, ((TYPE) == DECIMALVALUE) ? 10 : 16); \
+ if (((TYPE) == DECIMALVALUE) && (val >= 256)) \
+ return (0); \
+ /* check if there is room left in the array */ \
+ if (i > (int)(sizeof(a) - (((TYPE) == HEXVALUE) ? 2 : 1) - ((dci != -1) ? 2 : 0))) \
+ return (0); \
+ if ((TYPE) == HEXVALUE) \
+ a[i++] = ((val >> 8) & 0xff); \
+ a[i++] = (val & 0xff); \
} while (0)
hex = 0;
pnum = p = uaddr;
pscope = NULL;
needmore = 1;
- if ((*p == ':') && (*++p != ':')) /* if it starts with colon, gotta be a double */
- return (0);
+ if ((*p == ':') && (*++p != ':')) { /* if it starts with colon, gotta be a double */
+ return 0;
+ }
while (*p) {
if (IS_XDIGIT(*p)) {
dcount++;
- if (!IS_DIGIT(*p))
+ if (!IS_DIGIT(*p)) {
xdcount++;
+ }
needmore = 0;
p++;
} else if (*p == '.') {
/* this is the first, so count them */
for (pd = p; *pd; pd++) {
if (*pd == '.') {
- if (++dots > 5)
- return (0);
+ if (++dots > 5) {
+ return 0;
+ }
} else if (hex && (*pd == '%')) {
break;
} else if ((*pd < '0') || (*pd > '9')) {
- return (0);
+ return 0;
}
}
- if ((dots != 2) && (dots != 3) && (dots != 5))
- return (0);
+ if ((dots != 2) && (dots != 3) && (dots != 5)) {
+ return 0;
+ }
if (hex && (dots == 2)) { /* hex+port */
- if (!dcount && needmore)
- return (0);
- if (dcount) /* last hex may be elided zero */
+ if (!dcount && needmore) {
+ return 0;
+ }
+ if (dcount) { /* last hex may be elided zero */
GET(HEXVALUE);
+ }
} else {
GET(DECIMALVALUE);
}
pnum = ++p;
} else if (*p == ':') {
hex = 1;
- if (dots)
- return (0);
+ if (dots) {
+ return 0;
+ }
if (!dcount) { /* missing number, probably double colon */
- if (dci >= 0) /* can only have one double colon */
- return (0);
+ if (dci >= 0) { /* can only have one double colon */
+ return 0;
+ }
dci = i;
needmore = 0;
} else {
}
pnum = ++p;
} else if (*p == '%') { /* scope ID delimiter */
- if (!hex)
- return (0);
+ if (!hex) {
+ return 0;
+ }
p++;
pscope = p;
break;
} else { /* unexpected character */
- return (0);
+ return 0;
}
}
- if (needmore && !dcount)
- return (0);
- if (dcount) /* decode trailing number */
+ if (needmore && !dcount) {
+ return 0;
+ }
+ if (dcount) { /* decode trailing number */
GET(dots ? DECIMALVALUE : HEXVALUE);
+ }
if (dci >= 0) { /* got a double-colon at i, need to insert a range of zeroes */
/* if we got a port, slide to end of array */
/* otherwise, slide to end of address (non-port) values */
int end = ((dots == 2) || (dots == 5)) ? sizeof(a) : (sizeof(a) - 2);
- if (i % 2) /* length of zero range must be multiple of 2 */
- return (0);
- if (i >= end) /* no room? */
- return (0);
+ if (i % 2) { /* length of zero range must be multiple of 2 */
+ return 0;
+ }
+ if (i >= end) { /* no room? */
+ return 0;
+ }
/* slide (i-dci) numbers up from index dci */
- for (s=0; s < (i - dci); s++)
- a[end-1-s] = a[i-1-s];
+ for (s = 0; s < (i - dci); s++) {
+ a[end - 1 - s] = a[i - 1 - s];
+ }
/* zero (end-i) numbers at index dci */
- for (s=0; s < (end - i); s++)
- a[dci+s] = 0;
+ for (s = 0; s < (end - i); s++) {
+ a[dci + s] = 0;
+ }
i = end;
}
/* copy out resulting socket address */
if (hex) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)addr;
- if ((((dots == 0) || (dots == 3)) && (i != (sizeof(a)-2))))
- return (0);
- if ((((dots == 2) || (dots == 5)) && (i != sizeof(a))))
- return (0);
+ if ((((dots == 0) || (dots == 3)) && (i != (sizeof(a) - 2)))) {
+ return 0;
+ }
+ if ((((dots == 2) || (dots == 5)) && (i != sizeof(a)))) {
+ return 0;
+ }
bzero(sin6, sizeof(struct sockaddr_in6));
sin6->sin6_len = sizeof(struct sockaddr_in6);
sin6->sin6_family = AF_INET6;
bcopy(a, &sin6->sin6_addr.s6_addr, sizeof(struct in6_addr));
- if ((dots == 5) || (dots == 2))
- sin6->sin6_port = htons((a[16] << 8) | a[17]);
+ if ((dots == 5) || (dots == 2)) {
+ sin6->sin6_port = htons((in_port_t)((a[16] << 8) | a[17]));
+ }
if (pscope) {
- for (p=pscope; IS_DIGIT(*p); p++)
+ for (p = pscope; IS_DIGIT(*p); p++) {
;
+ }
if (*p && !IS_DIGIT(*p)) { /* name */
ifnet_t interface = NULL;
- if (ifnet_find_by_name(pscope, &interface) == 0)
+ if (ifnet_find_by_name(pscope, &interface) == 0) {
sin6->sin6_scope_id = ifnet_index(interface);
- if (interface)
+ }
+ if (interface) {
ifnet_release(interface);
+ }
} else { /* decimal number */
- sin6->sin6_scope_id = strtoul(pscope, NULL, 10);
+ sin6->sin6_scope_id = (uint32_t)strtoul(pscope, NULL, 10);
}
/* XXX should we also embed scope id for linklocal? */
}
} else {
struct sockaddr_in *sin = (struct sockaddr_in*)addr;
- if ((dots != 3) && (dots != 5))
- return (0);
- if ((dots == 3) && (i != 4))
- return (0);
- if ((dots == 5) && (i != 6))
- return (0);
+ if ((dots != 3) && (dots != 5)) {
+ return 0;
+ }
+ if ((dots == 3) && (i != 4)) {
+ return 0;
+ }
+ if ((dots == 5) && (i != 6)) {
+ return 0;
+ }
bzero(sin, sizeof(struct sockaddr_in));
sin->sin_len = sizeof(struct sockaddr_in);
sin->sin_family = AF_INET;
bcopy(a, &sin->sin_addr.s_addr, sizeof(struct in_addr));
- if (dots == 5)
- sin->sin_port = htons((a[4] << 8) | a[5]);
+ if (dots == 5) {
+ sin->sin_port = htons((in_port_t)((a[4] << 8) | a[5]));
+ }
+ }
+ return 1;
+}
+
+
+/* NFS Client debugging support */
+uint32_t nfs_debug_ctl;
+
+#include <libkern/libkern.h>
+#include <stdarg.h>
+
+void
+nfs_printf(unsigned int facility, unsigned int level, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (NFS_IS_DBG(facility, level)) {
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
}
- return (1);
}
-#endif /* NFSCLIENT */
+#define DISPLAYLEN 16
+
+static bool
+isprint(int ch)
+{
+ return ch >= 0x20 && ch <= 0x7e;
+}
+
+static void
+hexdump(void *data, size_t len)
+{
+ size_t i, j;
+ unsigned char *d = data;
+ char *p, disbuf[3 * DISPLAYLEN + 1];
+
+ for (i = 0; i < len; i += DISPLAYLEN) {
+ for (p = disbuf, j = 0; (j + i) < len && j < DISPLAYLEN; j++, p += 3) {
+ snprintf(p, 4, "%2.2x ", d[i + j]);
+ }
+ for (; j < DISPLAYLEN; j++, p += 3) {
+ snprintf(p, 4, " ");
+ }
+ printf("%s ", disbuf);
+ for (p = disbuf, j = 0; (j + i) < len && j < DISPLAYLEN; j++, p++) {
+ snprintf(p, 2, "%c", isprint(d[i + j]) ? d[i + j] : '.');
+ }
+ printf("%s\n", disbuf);
+ }
+}
+
+void
+nfs_dump_mbuf(const char *func, int lineno, const char *msg, mbuf_t mb)
+{
+ mbuf_t m;
+
+ printf("%s:%d %s\n", func, lineno, msg);
+ for (m = mb; m; m = mbuf_next(m)) {
+ hexdump(mbuf_data(m), mbuf_len(m));
+ }
+}
+
+/* Is a mount gone away? */
+int
+nfs_mount_gone(struct nfsmount *nmp)
+{
+ return !nmp || vfs_isforce(nmp->nm_mountp) || (nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD));
+}
+
+/*
+ * Return some of the more significant mount options
+ * as a string, e.g. "'ro,hard,intr,tcp,vers=3,sec=krb5,deadtimeout=0'
+ */
+int
+nfs_mountopts(struct nfsmount *nmp, char *buf, int buflen)
+{
+ int c;
+
+ c = snprintf(buf, buflen, "%s,%s,%s,%s,vers=%d,sec=%s,%sdeadtimeout=%d",
+ (vfs_flags(nmp->nm_mountp) & MNT_RDONLY) ? "ro" : "rw",
+ NMFLAG(nmp, SOFT) ? "soft" : "hard",
+ NMFLAG(nmp, INTR) ? "intr" : "nointr",
+ nmp->nm_sotype == SOCK_STREAM ? "tcp" : "udp",
+ nmp->nm_vers,
+ nmp->nm_auth == RPCAUTH_KRB5 ? "krb5" :
+ nmp->nm_auth == RPCAUTH_KRB5I ? "krb5i" :
+ nmp->nm_auth == RPCAUTH_KRB5P ? "krb5p" :
+ nmp->nm_auth == RPCAUTH_SYS ? "sys" : "none",
+ nmp->nm_lockmode == NFS_LOCK_MODE_ENABLED ? "locks," :
+ nmp->nm_lockmode == NFS_LOCK_MODE_DISABLED ? "nolocks," :
+ nmp->nm_lockmode == NFS_LOCK_MODE_LOCAL ? "locallocks," : "",
+ nmp->nm_deadtimeout);
+
+ return c > buflen ? ENOMEM : 0;
+}
+
+#endif /* CONFIG_NFS_CLIENT */
/*
* Schedule a callout thread to run an NFS timer function
* interval milliseconds in the future.
*/
void
-nfs_interval_timer_start(thread_call_t call, int interval)
+nfs_interval_timer_start(thread_call_t call, time_t interval)
{
uint64_t deadline;
- clock_interval_to_deadline(interval, 1000 * 1000, &deadline);
+ clock_interval_to_deadline((int)interval, 1000 * 1000, &deadline);
thread_call_enter_delayed(call, deadline);
}
-#if NFSSERVER
+#if CONFIG_NFS_SERVER
int nfsrv_cmp_secflavs(struct nfs_sec *, struct nfs_sec *);
int nfsrv_hang_addrlist(struct nfs_export *, struct user_nfs_export_args *);
}
nfsm_chain_add_postop_attr(error, nd, nmc, postattrerr, postvap);
- return (error);
+ return error;
}
/*
int error = 0;
char *cp;
- if (len > (MAXPATHLEN - 1))
- return (ENAMETOOLONG);
+ if (len > (MAXPATHLEN - 1)) {
+ return ENAMETOOLONG;
+ }
/*
* Get a buffer for the name to be translated, and copy the
* name into the buffer.
*/
- MALLOC_ZONE(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK);
- if (!cnp->cn_pnbuf)
- return (ENOMEM);
+ cnp->cn_pnbuf = zalloc(ZV_NAMEI);
cnp->cn_pnlen = MAXPATHLEN;
cnp->cn_flags |= HASBUF;
/* Copy the name from the mbuf list to the string */
cp = cnp->cn_pnbuf;
nfsm_chain_get_opaque(error, nmc, len, cp);
- if (error)
+ if (error) {
goto out;
+ }
cnp->cn_pnbuf[len] = '\0';
/* sanity check the string */
- if ((strlen(cp) != len) || strchr(cp, '/'))
+ if ((strlen(cp) != len) || strchr(cp, '/')) {
error = EACCES;
+ }
out:
if (error) {
- if (cnp->cn_pnbuf)
- FREE_ZONE(cnp->cn_pnbuf, MAXPATHLEN, M_NAMEI);
+ if (cnp->cn_pnbuf) {
+ NFS_ZFREE(ZV_NAMEI, cnp->cn_pnbuf);
+ }
cnp->cn_flags &= ~HASBUF;
} else {
nip->ni_pathlen = len;
}
- return (error);
+ return error;
}
/*
* Extract and set starting directory.
*/
error = nfsrv_fhtovp(nfhp, nd, &dp, nxp, nxop);
- if (error)
+ if (error) {
goto out;
+ }
error = nfsrv_credcheck(nd, ctx, *nxp, *nxop);
if (error || (vnode_vtype(dp) != VDIR)) {
vnode_put(dp);
nip->ni_cnd.cn_context = ctx;
- if (*nxop && ((*nxop)->nxo_flags & NX_READONLY))
+ if (*nxop && ((*nxop)->nxo_flags & NX_READONLY)) {
cnp->cn_flags |= RDONLY;
+ }
cnp->cn_flags |= NOCROSSMOUNT;
cnp->cn_nameptr = cnp->cn_pnbuf;
nip->ni_usedvp = nip->ni_startdir = dp;
+ nip->ni_rootdir = rootvnode;
/*
* And call lookup() to do the real work
cnp->cn_nameptr = cnp->cn_pnbuf;
nip->ni_usedvp = nip->ni_dvp = nip->ni_startdir = dp;
}
- if (error)
+ if (error) {
goto out;
+ }
/* Check for encountering a symbolic link */
if (cnp->cn_flags & ISSYMLINK) {
-#if CONFIG_VFS_FUNNEL
- if ((cnp->cn_flags & FSNODELOCKHELD)) {
- cnp->cn_flags &= ~FSNODELOCKHELD;
- unlock_fsnode(nip->ni_dvp, NULL);
- }
-#endif /* CONFIG_VFS_FUNNEL */
- if (cnp->cn_flags & (LOCKPARENT | WANTPARENT))
+ if (cnp->cn_flags & (LOCKPARENT | WANTPARENT)) {
vnode_put(nip->ni_dvp);
+ }
if (nip->ni_vp) {
vnode_put(nip->ni_vp);
nip->ni_vp = NULL;
tmppn = cnp->cn_pnbuf;
cnp->cn_pnbuf = NULL;
cnp->cn_flags &= ~HASBUF;
- FREE_ZONE(tmppn, cnp->cn_pnlen, M_NAMEI);
+ NFS_ZFREE(ZV_NAMEI, tmppn);
}
- return (error);
+ return error;
}
/*
nfsm_adj(mbuf_t mp, int len, int nul)
{
mbuf_t m, mnext;
- int count, i, mlen;
+ int count, i;
+ long mlen;
char *cp;
/*
mlen = mbuf_len(m);
count += mlen;
mnext = mbuf_next(m);
- if (mnext == NULL)
+ if (mnext == NULL) {
break;
+ }
m = mnext;
}
if (mlen > len) {
mbuf_setlen(m, mlen);
if (nul > 0) {
cp = (caddr_t)mbuf_data(m) + mlen - nul;
- for (i = 0; i < nul; i++)
+ for (i = 0; i < nul; i++) {
*cp++ = '\0';
+ }
}
return;
}
count -= len;
- if (count < 0)
+ if (count < 0) {
count = 0;
+ }
/*
* Correct length for chain is "count".
* Find the mbuf with last data, adjust its length,
mbuf_setlen(m, count);
if (nul > 0) {
cp = (caddr_t)mbuf_data(m) + mlen - nul;
- for (i = 0; i < nul; i++)
+ for (i = 0; i < nul; i++) {
*cp++ = '\0';
+ }
}
break;
}
count -= mlen;
}
- for (m = mbuf_next(m); m; m = mbuf_next(m))
+ for (m = mbuf_next(m); m; m = mbuf_next(m)) {
mbuf_setlen(m, 0);
+ }
}
/*
int
nfsm_chain_trim_data(struct nfsm_chain *nmc, int len, int *mlen)
{
- int cnt = 0, dlen, adjust;
+ int cnt = 0;
+ long dlen, adjust;
caddr_t data;
mbuf_t m;
- if (mlen)
+ if (mlen) {
*mlen = 0;
+ }
/* trim header */
- for (m = nmc->nmc_mhead; m && (m != nmc->nmc_mcur); m = mbuf_next(m))
+ for (m = nmc->nmc_mhead; m && (m != nmc->nmc_mcur); m = mbuf_next(m)) {
mbuf_setlen(m, 0);
- if (!m)
- return (EIO);
+ }
+ if (!m) {
+ return EIO;
+ }
/* trim current mbuf */
data = mbuf_data(m);
adjust = nmc->nmc_ptr - data;
dlen -= adjust;
if ((dlen > 0) && (adjust > 0)) {
- if (mbuf_setdata(m, nmc->nmc_ptr, dlen))
- return(EIO);
- } else
+ if (mbuf_setdata(m, nmc->nmc_ptr, dlen)) {
+ return EIO;
+ }
+ } else {
mbuf_setlen(m, dlen);
+ }
/* skip next len bytes */
for (; m && (cnt < len); m = mbuf_next(m)) {
if (cnt > len) {
/* truncate to end of data */
mbuf_setlen(m, dlen - (cnt - len));
- if (m == nmc->nmc_mcur)
+ if (m == nmc->nmc_mcur) {
nmc->nmc_left -= (cnt - len);
+ }
cnt = len;
}
}
- if (mlen)
+ if (mlen) {
*mlen = cnt;
+ }
/* trim any trailing data */
- if (m == nmc->nmc_mcur)
+ if (m == nmc->nmc_mcur) {
nmc->nmc_left = 0;
- for (; m; m = mbuf_next(m))
+ }
+ for (; m; m = mbuf_next(m)) {
mbuf_setlen(m, 0);
+ }
- return (0);
+ return 0;
}
int
} else {
nfsm_chain_add_32(error, nmc, vap->va_data_size);
nfsm_chain_add_32(error, nmc, NFS_FABLKSIZE);
- if (vap->va_type == VFIFO)
+ if (vap->va_type == VFIFO) {
nfsm_chain_add_32(error, nmc, 0xffffffff);
- else
+ } else {
nfsm_chain_add_32(error, nmc, vap->va_rdev);
+ }
nfsm_chain_add_32(error, nmc, vap->va_data_alloc / NFS_FABLKSIZE);
nfsm_chain_add_32(error, nmc, vap->va_fsid);
nfsm_chain_add_32(error, nmc, vap->va_fileid);
nfsm_chain_add_time(error, nmc, nd->nd_vers, &vap->va_modify_time);
nfsm_chain_add_time(error, nmc, nd->nd_vers, &vap->va_change_time);
- return (error);
+ return error;
}
int
{
int error = 0;
uint32_t val = 0;
- uint64_t val64;
+ uint64_t val64 = 0;
struct timespec now;
if (nd->nd_vers == NFS_VER2) {
VATTR_CLEAR_ACTIVE(vap, va_type);
}
nfsm_chain_get_32(error, nmc, val);
- if (val != (uint32_t)-1)
+ if (val != (uint32_t)-1) {
VATTR_SET(vap, va_uid, val);
+ }
nfsm_chain_get_32(error, nmc, val);
- if (val != (uint32_t)-1)
+ if (val != (uint32_t)-1) {
VATTR_SET(vap, va_gid, val);
+ }
/* save the "size" bits for NFSv2 create (even if they appear unset) */
nfsm_chain_get_32(error, nmc, val);
VATTR_SET(vap, va_data_size, val);
- if (val == (uint32_t)-1)
+ if (val == (uint32_t)-1) {
VATTR_CLEAR_ACTIVE(vap, va_data_size);
+ }
nfsm_chain_get_time(error, nmc, NFS_VER2,
- vap->va_access_time.tv_sec,
- vap->va_access_time.tv_nsec);
- if (vap->va_access_time.tv_sec != -1)
+ vap->va_access_time.tv_sec,
+ vap->va_access_time.tv_nsec);
+ if (vap->va_access_time.tv_sec != -1) {
VATTR_SET_ACTIVE(vap, va_access_time);
+ }
nfsm_chain_get_time(error, nmc, NFS_VER2,
- vap->va_modify_time.tv_sec,
- vap->va_modify_time.tv_nsec);
- if (vap->va_modify_time.tv_sec != -1)
+ vap->va_modify_time.tv_sec,
+ vap->va_modify_time.tv_nsec);
+ if (vap->va_modify_time.tv_sec != -1) {
VATTR_SET_ACTIVE(vap, va_modify_time);
- return (error);
+ }
+ return error;
}
/* NFSv3 */
switch (val) {
case NFS_TIME_SET_TO_CLIENT:
nfsm_chain_get_time(error, nmc, nd->nd_vers,
- vap->va_access_time.tv_sec,
- vap->va_access_time.tv_nsec);
+ vap->va_access_time.tv_sec,
+ vap->va_access_time.tv_nsec);
VATTR_SET_ACTIVE(vap, va_access_time);
vap->va_vaflags &= ~VA_UTIMES_NULL;
break;
switch (val) {
case NFS_TIME_SET_TO_CLIENT:
nfsm_chain_get_time(error, nmc, nd->nd_vers,
- vap->va_modify_time.tv_sec,
- vap->va_modify_time.tv_nsec);
+ vap->va_modify_time.tv_sec,
+ vap->va_modify_time.tv_nsec);
VATTR_SET_ACTIVE(vap, va_modify_time);
vap->va_vaflags &= ~VA_UTIMES_NULL;
break;
case NFS_TIME_SET_TO_SERVER:
VATTR_SET(vap, va_modify_time, now);
- if (!VATTR_IS_ACTIVE(vap, va_access_time))
+ if (!VATTR_IS_ACTIVE(vap, va_access_time)) {
vap->va_vaflags |= VA_UTIMES_NULL;
+ }
break;
}
- return (error);
+ return error;
}
/*
{
int i;
- if (sf1->count != sf2->count)
+ if (sf1->count != sf2->count) {
return 1;
- for (i = 0; i < sf1->count; i++)
- if (sf1->flavors[i] != sf2->flavors[i])
+ }
+ for (i = 0; i < sf1->count; i++) {
+ if (sf1->flavors[i] != sf2->flavors[i]) {
return 1;
+ }
+ }
return 0;
}
struct radix_node *rn;
struct sockaddr *saddr, *smask;
struct domain *dom;
- int i, error;
+ size_t i, ss_minsize;
+ int error;
unsigned int net;
user_addr_t uaddr;
kauth_cred_t cred;
uaddr = unxa->nxa_nets;
+ ss_minsize = sizeof(((struct sockaddr_storage *)0)->ss_len) + sizeof(((struct sockaddr_storage *)0)->ss_family);
for (net = 0; net < unxa->nxa_netcount; net++, uaddr += sizeof(nxna)) {
error = copyin(uaddr, &nxna, sizeof(nxna));
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
+
+ if (nxna.nxna_addr.ss_len > sizeof(struct sockaddr_storage) ||
+ (nxna.nxna_addr.ss_len != 0 && nxna.nxna_addr.ss_len < ss_minsize) ||
+ nxna.nxna_mask.ss_len > sizeof(struct sockaddr_storage) ||
+ (nxna.nxna_mask.ss_len != 0 && nxna.nxna_mask.ss_len < ss_minsize) ||
+ nxna.nxna_addr.ss_family > AF_MAX ||
+ nxna.nxna_mask.ss_family > AF_MAX) {
+ return EINVAL;
+ }
- if (nxna.nxna_flags & (NX_MAPROOT|NX_MAPALL)) {
+ if (nxna.nxna_flags & (NX_MAPROOT | NX_MAPALL)) {
struct posix_cred temp_pcred;
- bzero(&temp_pcred, sizeof(temp_pcred));
+ bzero(&temp_pcred, sizeof(temp_pcred));
temp_pcred.cr_uid = nxna.nxna_cred.cr_uid;
temp_pcred.cr_ngroups = nxna.nxna_cred.cr_ngroups;
- for (i=0; i < nxna.nxna_cred.cr_ngroups && i < NGROUPS; i++)
+ for (i = 0; i < (size_t)nxna.nxna_cred.cr_ngroups && i < NGROUPS; i++) {
temp_pcred.cr_groups[i] = nxna.nxna_cred.cr_groups[i];
+ }
cred = posix_cred_create(&temp_pcred);
- if (!IS_VALID_CRED(cred))
- return (ENOMEM);
+ if (!IS_VALID_CRED(cred)) {
+ return ENOMEM;
+ }
} else {
cred = NOCRED;
}
if (nxna.nxna_addr.ss_len == 0) {
/* No address means this is a default/world export */
if (nx->nx_flags & NX_DEFAULTEXPORT) {
- if (IS_VALID_CRED(cred))
- kauth_cred_unref(&cred);
- return (EEXIST);
+ if (IS_VALID_CRED(cred)) {
+ kauth_cred_unref(&cred);
+ }
+ return EEXIST;
}
nx->nx_flags |= NX_DEFAULTEXPORT;
nx->nx_defopt.nxo_flags = nxna.nxna_flags;
i += nxna.nxna_addr.ss_len + nxna.nxna_mask.ss_len;
MALLOC(no, struct nfs_netopt *, i, M_NETADDR, M_WAITOK);
if (!no) {
- if (IS_VALID_CRED(cred))
+ if (IS_VALID_CRED(cred)) {
kauth_cred_unref(&cred);
- return (ENOMEM);
+ }
+ return ENOMEM;
}
bzero(no, sizeof(struct nfs_netopt));
no->no_opt.nxo_flags = nxna.nxna_flags;
} else {
smask = NULL;
}
- i = saddr->sa_family;
- if ((rnh = nx->nx_rtable[i]) == 0) {
+ sa_family_t family = saddr->sa_family;
+ if ((rnh = nx->nx_rtable[family]) == 0) {
/*
* Seems silly to initialize every AF when most are not
* used, do so on demand here
*/
- for (dom = domains; dom; dom = dom->dom_next)
- if (dom->dom_family == i && dom->dom_rtattach) {
- dom->dom_rtattach((void **)&nx->nx_rtable[i],
- dom->dom_rtoffset);
+ TAILQ_FOREACH(dom, &domains, dom_entry) {
+ if (dom->dom_family == family && dom->dom_rtattach) {
+ dom->dom_rtattach((void **)&nx->nx_rtable[family],
+ dom->dom_rtoffset);
break;
}
- if ((rnh = nx->nx_rtable[i]) == 0) {
- if (IS_VALID_CRED(cred))
- kauth_cred_unref(&cred);
+ }
+ if ((rnh = nx->nx_rtable[family]) == 0) {
+ if (IS_VALID_CRED(cred)) {
+ kauth_cred_unref(&cred);
+ }
_FREE(no, M_NETADDR);
- return (ENOBUFS);
+ return ENOBUFS;
}
}
rn = (*rnh->rnh_addaddr)((caddr_t)saddr, (caddr_t)smask, rnh, no->no_rnodes);
/* creds are same (or both NULL) */
matched = 1;
} else if (cred && cred2 && (kauth_cred_getuid(cred) == kauth_cred_getuid(cred2))) {
- /*
- * Now compare the effective and
- * supplementary groups...
- *
- * Note: This comparison, as written,
- * does not correctly indicate that
- * the groups are equivalent, since
- * other than the first supplementary
- * group, which is also the effective
- * group, order on the remaining groups
- * doesn't matter, and this is an
- * ordered compare.
- */
- gid_t groups[NGROUPS];
- gid_t groups2[NGROUPS];
- int groupcount = NGROUPS;
- int group2count = NGROUPS;
-
- if (!kauth_cred_getgroups(cred, groups, &groupcount) &&
- !kauth_cred_getgroups(cred2, groups2, &group2count) &&
- groupcount == group2count) {
- for (i=0; i < group2count; i++)
- if (groups[i] != groups2[i])
- break;
- if (i >= group2count || i >= NGROUPS)
- matched = 1;
- }
+ /*
+ * Now compare the effective and
+ * supplementary groups...
+ *
+ * Note: This comparison, as written,
+ * does not correctly indicate that
+ * the groups are equivalent, since
+ * other than the first supplementary
+ * group, which is also the effective
+ * group, order on the remaining groups
+ * doesn't matter, and this is an
+ * ordered compare.
+ */
+ gid_t groups[NGROUPS];
+ gid_t groups2[NGROUPS];
+ size_t groupcount = NGROUPS;
+ size_t group2count = NGROUPS;
+
+ if (!kauth_cred_getgroups(cred, groups, &groupcount) &&
+ !kauth_cred_getgroups(cred2, groups2, &group2count) &&
+ groupcount == group2count) {
+ for (i = 0; i < group2count; i++) {
+ if (groups[i] != groups2[i]) {
+ break;
+ }
+ }
+ if (i >= group2count || i >= NGROUPS) {
+ matched = 1;
+ }
+ }
}
}
- if (IS_VALID_CRED(cred))
- kauth_cred_unref(&cred);
+ if (IS_VALID_CRED(cred)) {
+ kauth_cred_unref(&cred);
+ }
_FREE(no, M_NETADDR);
- if (matched)
+ if (matched) {
continue;
- return (EPERM);
+ }
+ return EPERM;
}
nx->nx_expcnt++;
}
- return (0);
+ return 0;
}
/*
struct nfs_netopt *nno = (struct nfs_netopt *)rn;
(*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);
- if (IS_VALID_CRED(nno->no_opt.nxo_cred))
+ if (IS_VALID_CRED(nno->no_opt.nxo_cred)) {
kauth_cred_unref(&nno->no_opt.nxo_cred);
+ }
_FREE((caddr_t)rn, M_NETADDR);
*cnt -= 1;
- return (0);
+ return 0;
}
/*
struct radix_node *rn;
struct nfsrv_free_netopt_arg fna;
struct nfs_netopt *nno;
+ size_t ss_minsize;
user_addr_t uaddr;
unsigned int net;
int i, error;
if (!unxa || !unxa->nxa_netcount) {
/* delete everything */
- for (i = 0; i <= AF_MAX; i++)
- if ( (rnh = nx->nx_rtable[i]) ) {
+ for (i = 0; i <= AF_MAX; i++) {
+ if ((rnh = nx->nx_rtable[i])) {
fna.rnh = rnh;
fna.cnt = &nx->nx_expcnt;
(*rnh->rnh_walktree)(rnh, nfsrv_free_netopt, (caddr_t)&fna);
_FREE((caddr_t)rnh, M_RTABLE);
nx->nx_rtable[i] = 0;
}
- return (0);
+ }
+ return 0;
}
/* delete only the exports specified */
uaddr = unxa->nxa_nets;
+ ss_minsize = sizeof(((struct sockaddr_storage *)0)->ss_len) + sizeof(((struct sockaddr_storage *)0)->ss_family);
for (net = 0; net < unxa->nxa_netcount; net++, uaddr += sizeof(nxna)) {
error = copyin(uaddr, &nxna, sizeof(nxna));
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
if (nxna.nxna_addr.ss_len == 0) {
/* No address means this is a default/world export */
continue;
}
+ if (nxna.nxna_addr.ss_len > sizeof(struct sockaddr_storage) ||
+ (nxna.nxna_addr.ss_len != 0 && nxna.nxna_addr.ss_len < ss_minsize) ||
+ nxna.nxna_addr.ss_family > AF_MAX) {
+ printf("nfsrv_free_addrlist: invalid socket address (%u)\n", net);
+ continue;
+ }
+
+ if (nxna.nxna_mask.ss_len > sizeof(struct sockaddr_storage) ||
+ (nxna.nxna_mask.ss_len != 0 && nxna.nxna_mask.ss_len < ss_minsize) ||
+ nxna.nxna_mask.ss_family > AF_MAX) {
+ printf("nfsrv_free_addrlist: invalid socket mask (%u)\n", net);
+ continue;
+ }
+
if ((rnh = nx->nx_rtable[nxna.nxna_addr.ss_family]) == 0) {
/* AF not initialized? */
- if (!(unxa->nxa_flags & NXA_ADD))
+ if (!(unxa->nxa_flags & NXA_ADD)) {
printf("nfsrv_free_addrlist: address not found (0)\n");
+ }
continue;
}
rn = (*rnh->rnh_lookup)(&nxna.nxna_addr,
- nxna.nxna_mask.ss_len ? &nxna.nxna_mask : NULL, rnh);
+ nxna.nxna_mask.ss_len ? &nxna.nxna_mask : NULL, rnh);
if (!rn || (rn->rn_flags & RNF_ROOT)) {
- if (!(unxa->nxa_flags & NXA_ADD))
+ if (!(unxa->nxa_flags & NXA_ADD)) {
printf("nfsrv_free_addrlist: address not found (1)\n");
+ }
continue;
}
(*rnh->rnh_deladdr)(rn->rn_key, rn->rn_mask, rnh);
nno = (struct nfs_netopt *)rn;
- if (IS_VALID_CRED(nno->no_opt.nxo_cred))
+ if (IS_VALID_CRED(nno->no_opt.nxo_cred)) {
kauth_cred_unref(&nno->no_opt.nxo_cred);
+ }
_FREE((caddr_t)rn, M_NETADDR);
nx->nx_expcnt--;
}
}
- return (0);
+ return 0;
}
void enablequotas(struct mount *mp, vfs_context_t ctx); // XXX
+#define DATA_VOLUME_MP "/System/Volumes/Data" // PLATFORM_DATA_VOLUME_MOUNT_POINT
+
int
nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx)
{
int error = 0;
- size_t pathlen;
+ size_t pathlen, nxfs_pathlen;
struct nfs_exportfs *nxfs, *nxfs2, *nxfs3;
struct nfs_export *nx, *nx2, *nx3;
struct nfs_filehandle nfh;
struct nameidata mnd, xnd;
vnode_t mvp = NULL, xvp = NULL;
mount_t mp = NULL;
- char path[MAXPATHLEN];
+ char path[MAXPATHLEN], *nxfs_path;
+ char fl_pathbuff[MAXPATHLEN];
+ int fl_pathbuff_len = MAXPATHLEN;
int expisroot;
+ size_t datavol_len = strlen(DATA_VOLUME_MP);
if (unxa->nxa_flags == NXA_CHECK) {
/* just check if the path is an NFS-exportable file system */
error = copyinstr(unxa->nxa_fspath, path, MAXPATHLEN, &pathlen);
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
NDINIT(&mnd, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
- UIO_SYSSPACE, CAST_USER_ADDR_T(path), ctx);
+ UIO_SYSSPACE, CAST_USER_ADDR_T(path), ctx);
error = namei(&mnd);
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
mvp = mnd.ni_vp;
mp = vnode_mount(mvp);
/* make sure it's the root of a file system */
- if (!vnode_isvroot(mvp))
+ if (!vnode_isvroot(mvp)) {
error = EINVAL;
+ }
/* make sure the file system is NFS-exportable */
if (!error) {
nfh.nfh_len = NFSV3_MAX_FID_SIZE;
error = VFS_VPTOFH(mvp, (int*)&nfh.nfh_len, &nfh.nfh_fid[0], NULL);
}
- if (!error && (nfh.nfh_len > (int)NFSV3_MAX_FID_SIZE))
+ if (!error && (nfh.nfh_len > (int)NFSV3_MAX_FID_SIZE)) {
error = EIO;
- if (!error && !(mp->mnt_vtable->vfc_vfsflags & VFC_VFSREADDIR_EXTENDED))
+ }
+ if (!error && !(mp->mnt_vtable->vfc_vfsflags & VFC_VFSREADDIR_EXTENDED)) {
error = EISDIR;
+ }
vnode_put(mvp);
nameidone(&mnd);
- return (error);
+ return error;
}
/* all other operations: must be super user */
- if ((error = vfs_context_suser(ctx)))
- return (error);
+ if ((error = vfs_context_suser(ctx))) {
+ return error;
+ }
if (unxa->nxa_flags & NXA_DELETE_ALL) {
/* delete all exports on all file systems */
nfsrv_export_hashtbl = NULL;
}
lck_rw_done(&nfsrv_export_rwlock);
- return (0);
+ return 0;
}
error = copyinstr(unxa->nxa_fspath, path, MAXPATHLEN, &pathlen);
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
lck_rw_lock_exclusive(&nfsrv_export_rwlock);
/* init export hash table if not already */
if (!nfsrv_export_hashtbl) {
- if (nfsrv_export_hash_size <= 0)
+ if (nfsrv_export_hash_size <= 0) {
nfsrv_export_hash_size = NFSRVEXPHASHSZ;
+ }
nfsrv_export_hashtbl = hashinit(nfsrv_export_hash_size, M_TEMP, &nfsrv_export_hash);
}
// first check if we've already got an exportfs with the given ID
LIST_FOREACH(nxfs, &nfsrv_exports, nxfs_next) {
- if (nxfs->nxfs_id == unxa->nxa_fsid)
+ if (nxfs->nxfs_id == unxa->nxa_fsid) {
break;
+ }
}
if (nxfs) {
/* verify exported FS path matches given path */
- if (strncmp(path, nxfs->nxfs_path, MAXPATHLEN)) {
+ if (strncmp(path, nxfs->nxfs_path, MAXPATHLEN) &&
+ (strncmp(path, DATA_VOLUME_MP, datavol_len) || strncmp(path + datavol_len, nxfs->nxfs_path, MAXPATHLEN - datavol_len))) {
error = EEXIST;
goto unlock_out;
}
- if ((unxa->nxa_flags & (NXA_ADD|NXA_OFFLINE)) == NXA_ADD) {
- /* if adding, verify that the mount is still what we expect */
- mp = vfs_getvfs_by_mntonname(nxfs->nxfs_path);
- if (mp) {
- mount_ref(mp, 0);
- mount_iterdrop(mp);
- }
+ if ((unxa->nxa_flags & (NXA_ADD | NXA_OFFLINE)) == NXA_ADD) {
/* find exported FS root vnode */
NDINIT(&mnd, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
- UIO_SYSSPACE, CAST_USER_ADDR_T(nxfs->nxfs_path), ctx);
+ UIO_SYSSPACE, CAST_USER_ADDR_T(nxfs->nxfs_path), ctx);
error = namei(&mnd);
- if (error)
+ if (error) {
goto unlock_out;
+ }
mvp = mnd.ni_vp;
/* make sure it's (still) the root of a file system */
if (!vnode_isvroot(mvp)) {
error = EINVAL;
goto out;
}
+ /* if adding, verify that the mount is still what we expect */
+ mp = vfs_getvfs_by_mntonname(nxfs->nxfs_path);
+ if (!mp) {
+ /* check for firmlink-free path */
+ if (vn_getpath_no_firmlink(mvp, fl_pathbuff, &fl_pathbuff_len) == 0 &&
+ fl_pathbuff_len > 0 &&
+ !strncmp(nxfs->nxfs_path, fl_pathbuff, MAXPATHLEN)) {
+ mp = vfs_getvfs_by_mntonname(vnode_mount(mvp)->mnt_vfsstat.f_mntonname);
+ }
+ }
+ if (mp) {
+ mount_ref(mp, 0);
+ mount_iterdrop(mp);
+ }
/* sanity check: this should be same mount */
if (mp != vnode_mount(mvp)) {
error = EINVAL;
/* find exported FS root vnode */
NDINIT(&mnd, LOOKUP, OP_LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1,
- UIO_SYSSPACE, CAST_USER_ADDR_T(path), ctx);
+ UIO_SYSSPACE, CAST_USER_ADDR_T(path), ctx);
error = namei(&mnd);
if (error) {
- if (!(unxa->nxa_flags & NXA_OFFLINE))
+ if (!(unxa->nxa_flags & NXA_OFFLINE)) {
goto unlock_out;
+ }
} else {
mvp = mnd.ni_vp;
/* make sure it's the root of a file system */
/* make sure the file system is NFS-exportable */
nfh.nfh_len = NFSV3_MAX_FID_SIZE;
error = VFS_VPTOFH(mvp, (int*)&nfh.nfh_len, &nfh.nfh_fid[0], NULL);
- if (!error && (nfh.nfh_len > (int)NFSV3_MAX_FID_SIZE))
+ if (!error && (nfh.nfh_len > (int)NFSV3_MAX_FID_SIZE)) {
error = EIO;
- if (!error && !(mp->mnt_vtable->vfc_vfsflags & VFC_VFSREADDIR_EXTENDED))
+ }
+ if (!error && !(mp->mnt_vtable->vfc_vfsflags & VFC_VFSREADDIR_EXTENDED)) {
error = EISDIR;
- if (error)
+ }
+ if (error) {
goto out;
+ }
}
}
}
bzero(nxfs, sizeof(struct nfs_exportfs));
nxfs->nxfs_id = unxa->nxa_fsid;
- MALLOC(nxfs->nxfs_path, char*, pathlen, M_TEMP, M_WAITOK);
+ if (mp) {
+ nxfs_path = mp->mnt_vfsstat.f_mntonname;
+ nxfs_pathlen = sizeof(mp->mnt_vfsstat.f_mntonname);
+ } else {
+ nxfs_path = path;
+ nxfs_pathlen = pathlen;
+ }
+ MALLOC(nxfs->nxfs_path, char*, nxfs_pathlen, M_TEMP, M_WAITOK);
if (!nxfs->nxfs_path) {
FREE(nxfs, M_TEMP);
error = ENOMEM;
goto out;
}
- bcopy(path, nxfs->nxfs_path, pathlen);
+ bcopy(nxfs_path, nxfs->nxfs_path, nxfs_pathlen);
/* insert into list in reverse-sorted order */
nxfs3 = NULL;
LIST_FOREACH(nxfs2, &nfsrv_exports, nxfs_next) {
- if (strncmp(nxfs->nxfs_path, nxfs2->nxfs_path, MAXPATHLEN) > 0)
+ if (strncmp(nxfs->nxfs_path, nxfs2->nxfs_path, MAXPATHLEN) > 0) {
break;
+ }
nxfs3 = nxfs2;
}
- if (nxfs2)
+ if (nxfs2) {
LIST_INSERT_BEFORE(nxfs2, nxfs, nxfs_next);
- else if (nxfs3)
+ } else if (nxfs3) {
LIST_INSERT_AFTER(nxfs3, nxfs, nxfs_next);
- else
+ } else {
LIST_INSERT_HEAD(&nfsrv_exports, nxfs, nxfs_next);
+ }
/* make sure any quotas are enabled before we export the file system */
- if (mp)
+ if (mp) {
enablequotas(mp, ctx);
+ }
}
if (unxa->nxa_exppath) {
error = copyinstr(unxa->nxa_exppath, path, MAXPATHLEN, &pathlen);
- if (error)
+ if (error) {
goto out;
+ }
LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next) {
- if (nx->nx_id == unxa->nxa_expid)
+ if (nx->nx_id == unxa->nxa_expid) {
break;
+ }
}
if (nx) {
/* verify exported FS path matches given path */
/* insert into list in reverse-sorted order */
nx3 = NULL;
LIST_FOREACH(nx2, &nxfs->nxfs_exports, nx_next) {
- if (strncmp(nx->nx_path, nx2->nx_path, MAXPATHLEN) > 0)
+ if (strncmp(nx->nx_path, nx2->nx_path, MAXPATHLEN) > 0) {
break;
+ }
nx3 = nx2;
}
- if (nx2)
+ if (nx2) {
LIST_INSERT_BEFORE(nx2, nx, nx_next);
- else if (nx3)
+ } else if (nx3) {
LIST_INSERT_AFTER(nx3, nx, nx_next);
- else
+ } else {
LIST_INSERT_HEAD(&nxfs->nxfs_exports, nx, nx_next);
+ }
/* insert into hash */
LIST_INSERT_HEAD(NFSRVEXPHASH(nxfs->nxfs_id, nx->nx_id), nx, nx_hash);
*/
error = 0;
if ((nx3 && !strncmp(nx3->nx_path, nx->nx_path, pathlen - 1) &&
- (nx3->nx_path[pathlen-1] == '/')) ||
+ (nx3->nx_path[pathlen - 1] == '/')) ||
(nx2 && !strncmp(nx2->nx_path, nx->nx_path, strlen(nx2->nx_path)) &&
- (nx->nx_path[strlen(nx2->nx_path)] == '/')))
+ (nx->nx_path[strlen(nx2->nx_path)] == '/'))) {
error = EINVAL;
+ }
if (!error) {
/* check export conflict with fs root export and vice versa */
expisroot = !nx->nx_path[0] ||
- ((nx->nx_path[0] == '.') && !nx->nx_path[1]);
+ ((nx->nx_path[0] == '.') && !nx->nx_path[1]);
LIST_FOREACH(nx2, &nxfs->nxfs_exports, nx_next) {
if (expisroot) {
- if (nx2 != nx)
+ if (nx2 != nx) {
break;
- } else if (!nx2->nx_path[0])
+ }
+ } else if (!nx2->nx_path[0]) {
break;
- else if ((nx2->nx_path[0] == '.') && !nx2->nx_path[1])
+ } else if ((nx2->nx_path[0] == '.') && !nx2->nx_path[1]) {
break;
+ }
}
- if (nx2)
+ if (nx2) {
error = EINVAL;
+ }
}
if (error) {
/*
* complexity of mountd for very little overall benefit.
*/
printf("nfsrv_export: warning: nested exports: %s/%s\n",
- nxfs->nxfs_path, nx->nx_path);
+ nxfs->nxfs_path, nx->nx_path);
error = 0;
}
nx->nx_fh.nfh_xh.nxh_flags = NXHF_INVALIDFH;
xnd.ni_op = OP_LOOKUP;
#endif
xnd.ni_cnd.cn_flags = LOCKLEAF;
- xnd.ni_pathlen = pathlen - 1;
+ xnd.ni_pathlen = (uint32_t)pathlen - 1; // pathlen max value is equal to MAXPATHLEN
xnd.ni_cnd.cn_nameptr = xnd.ni_cnd.cn_pnbuf = path;
xnd.ni_startdir = mvp;
xnd.ni_usedvp = mvp;
+ xnd.ni_rootdir = rootvnode;
xnd.ni_cnd.cn_context = ctx;
while ((error = lookup(&xnd)) == ERECYCLE) {
xnd.ni_cnd.cn_flags = LOCKLEAF;
xnd.ni_cnd.cn_nameptr = xnd.ni_cnd.cn_pnbuf;
xnd.ni_usedvp = xnd.ni_dvp = xnd.ni_startdir = mvp;
}
- if (error)
+ if (error) {
goto out1;
+ }
xvp = xnd.ni_vp;
}
}
vnode_put(xvp);
- if (error)
+ if (error) {
goto out1;
+ }
} else {
nx->nx_fh.nfh_xh.nxh_flags = NXHF_INVALIDFH;
nx->nx_fh.nfh_xh.nxh_fidlen = 0;
} else {
/* delete only the netopts for the given addresses */
error = nfsrv_free_addrlist(nx, unxa);
- if (error)
+ if (error) {
goto out1;
+ }
}
}
if (unxa->nxa_flags & NXA_ADD) {
- /*
+ /*
* If going offline set the export time so that when
* coming back on line we will present a new write verifier
* to the client.
*/
- if (unxa->nxa_flags & NXA_OFFLINE)
+ if (unxa->nxa_flags & NXA_OFFLINE) {
microtime(&nx->nx_exptime);
+ }
error = nfsrv_hang_addrlist(nx, unxa);
- if (!error && mp)
+ if (!error && mp) {
vfs_setflags(mp, MNT_EXPORTED);
+ }
}
out1:
LIST_REMOVE(nxfs, nxfs_next);
FREE(nxfs->nxfs_path, M_TEMP);
FREE(nxfs, M_TEMP);
- if (mp)
+ if (mp) {
vfs_clearflags(mp, MNT_EXPORTED);
+ }
}
out:
nameidone(&mnd);
}
unlock_out:
- if (mp)
+ if (mp) {
mount_drop(mp, 0);
+ }
+ lck_rw_done(&nfsrv_export_rwlock);
+ return error;
+}
+
+/*
+ * Check if there is a least one export that will allow this address.
+ *
+ * Return 0, if there is an export that will allow this address,
+ * else return EACCES
+ */
+int
+nfsrv_check_exports_allow_address(mbuf_t nam)
+{
+ struct nfs_exportfs *nxfs;
+ struct nfs_export *nx;
+ struct nfs_export_options *nxo = NULL;
+
+ if (nam == NULL) {
+ return EACCES;
+ }
+
+ lck_rw_lock_shared(&nfsrv_export_rwlock);
+ LIST_FOREACH(nxfs, &nfsrv_exports, nxfs_next) {
+ LIST_FOREACH(nx, &nxfs->nxfs_exports, nx_next) {
+ /* A little optimizing by checking for the default first */
+ if (nx->nx_flags & NX_DEFAULTEXPORT) {
+ nxo = &nx->nx_defopt;
+ }
+ if (nxo || (nxo = nfsrv_export_lookup(nx, nam))) {
+ goto found;
+ }
+ }
+ }
+found:
lck_rw_done(&nfsrv_export_rwlock);
- return (error);
+
+ return nxo ? 0 : EACCES;
}
struct nfs_export_options *
/* Lookup in the export list first. */
if (nam != NULL) {
saddr = mbuf_data(nam);
+ if (saddr->sa_family > AF_MAX) {
+ /* Bogus sockaddr? Don't match anything. */
+ return NULL;
+ }
rnh = nx->nx_rtable[saddr->sa_family];
if (rnh != NULL) {
no = (struct nfs_netopt *)
- (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh);
- if (no && no->no_rnodes->rn_flags & RNF_ROOT)
+ (*rnh->rnh_matchaddr)((caddr_t)saddr, rnh);
+ if (no && no->no_rnodes->rn_flags & RNF_ROOT) {
no = NULL;
- if (no)
+ }
+ if (no) {
nxo = &no->no_opt;
+ }
}
}
/* If no address match, use the default if it exists. */
- if ((nxo == NULL) && (nx->nx_flags & NX_DEFAULTEXPORT))
+ if ((nxo == NULL) && (nx->nx_flags & NX_DEFAULTEXPORT)) {
nxo = &nx->nx_defopt;
- return (nxo);
+ }
+ return nxo;
}
/* find an export for the given handle */
struct nfs_export *nx;
uint32_t fsid, expid;
- if (!nfsrv_export_hashtbl)
- return (NULL);
+ if (!nfsrv_export_hashtbl) {
+ return NULL;
+ }
fsid = ntohl(nxh->nxh_fsid);
expid = ntohl(nxh->nxh_expid);
nx = NFSRVEXPHASH(fsid, expid)->lh_first;
for (; nx; nx = LIST_NEXT(nx, nx_hash)) {
- if (nx->nx_fs->nxfs_id != fsid)
+ if (nx->nx_fs->nxfs_id != fsid) {
continue;
- if (nx->nx_id != expid)
+ }
+ if (nx->nx_id != expid) {
continue;
+ }
break;
}
- return (nx);
+ return nx;
+}
+
+struct nfsrv_getvfs_by_mntonname_callback_args {
+ const char *path; /* IN */
+ mount_t mp; /* OUT */
+};
+
+static int
+nfsrv_getvfs_by_mntonname_callback(mount_t mp, void *v)
+{
+ struct nfsrv_getvfs_by_mntonname_callback_args * const args = v;
+ char real_mntonname[MAXPATHLEN];
+ int pathbuflen = MAXPATHLEN;
+ vnode_t rvp;
+ int error;
+
+ error = VFS_ROOT(mp, &rvp, vfs_context_current());
+ if (error) {
+ goto out;
+ }
+ error = vn_getpath_ext(rvp, NULLVP, real_mntonname, &pathbuflen,
+ VN_GETPATH_FSENTER | VN_GETPATH_NO_FIRMLINK);
+ vnode_put(rvp);
+ if (error) {
+ goto out;
+ }
+ if (strcmp(args->path, real_mntonname) == 0) {
+ error = vfs_busy(mp, LK_NOWAIT);
+ if (error == 0) {
+ args->mp = mp;
+ }
+ return VFS_RETURNED_DONE;
+ }
+out:
+ return VFS_RETURNED;
+}
+
+static mount_t
+nfsrv_getvfs_by_mntonname(char *path)
+{
+ struct nfsrv_getvfs_by_mntonname_callback_args args = {
+ .path = path,
+ .mp = NULL,
+ };
+ mount_t mp;
+ int error;
+
+ mp = vfs_getvfs_by_mntonname(path);
+ if (mp) {
+ error = vfs_busy(mp, LK_NOWAIT);
+ mount_iterdrop(mp);
+ if (error) {
+ mp = NULL;
+ }
+ } else if (vfs_iterate(0, nfsrv_getvfs_by_mntonname_callback,
+ &args) == 0) {
+ mp = args.mp;
+ }
+ return mp;
}
/*
*nxp = NULL;
*nxop = NULL;
- if (nd != NULL)
+ if (nd != NULL) {
nam = nd->nd_nam;
+ }
v = ntohl(nxh->nxh_version);
if (v != NFS_FH_VERSION) {
/* file handle format not supported */
- return (ESTALE);
+ return ESTALE;
+ }
+ if (nfhp->nfh_len > NFSV3_MAX_FH_SIZE) {
+ return EBADRPC;
+ }
+ if (nfhp->nfh_len < (int)sizeof(struct nfs_exphandle)) {
+ return ESTALE;
}
- if (nfhp->nfh_len > NFSV3_MAX_FH_SIZE)
- return (EBADRPC);
- if (nfhp->nfh_len < (int)sizeof(struct nfs_exphandle))
- return (ESTALE);
v = ntohs(nxh->nxh_flags);
- if (v & NXHF_INVALIDFH)
- return (ESTALE);
+ if (v & NXHF_INVALIDFH) {
+ return ESTALE;
+ }
*nxp = nfsrv_fhtoexport(nfhp);
- if (!*nxp)
- return (ESTALE);
+ if (!*nxp) {
+ return ESTALE;
+ }
/* Get the export option structure for this <export, client> tuple. */
*nxop = nxo = nfsrv_export_lookup(*nxp, nam);
- if (nam && (*nxop == NULL))
- return (EACCES);
+ if (nam && (*nxop == NULL)) {
+ return EACCES;
+ }
if (nd != NULL) {
/* Validate the security flavor of the request */
* This allows an unauthenticated superuser on the client
* to do mounts for the benefit of authenticated users.
*/
- if (nd->nd_vers == NFS_VER2)
+ if (nd->nd_vers == NFS_VER2) {
if (nd->nd_procnum == NFSV2PROC_GETATTR ||
- nd->nd_procnum == NFSV2PROC_STATFS)
+ nd->nd_procnum == NFSV2PROC_STATFS) {
valid = 1;
- if (nd->nd_vers == NFS_VER3)
- if (nd->nd_procnum == NFSPROC_FSINFO)
+ }
+ }
+ if (nd->nd_vers == NFS_VER3) {
+ if (nd->nd_procnum == NFSPROC_FSINFO) {
valid = 1;
+ }
+ }
- if (!valid)
- return (NFSERR_AUTHERR | AUTH_REJECTCRED);
+ if (!valid) {
+ return NFSERR_AUTHERR | AUTH_REJECTCRED;
+ }
}
}
- if (nxo && (nxo->nxo_flags & NX_OFFLINE))
- return ((nd == NULL || nd->nd_vers == NFS_VER2) ? ESTALE : NFSERR_TRYLATER);
+ if (nxo && (nxo->nxo_flags & NX_OFFLINE)) {
+ return (nd == NULL || nd->nd_vers == NFS_VER2) ? ESTALE : NFSERR_TRYLATER;
+ }
/* find mount structure */
- mp = vfs_getvfs_by_mntonname((*nxp)->nx_fs->nxfs_path);
- if (mp) {
- error = vfs_busy(mp, LK_NOWAIT);
- mount_iterdrop(mp);
- if (error)
- mp = NULL;
- }
+ mp = nfsrv_getvfs_by_mntonname((*nxp)->nx_fs->nxfs_path);
if (!mp) {
/*
* We have an export, but no mount?
* Perhaps the export just hasn't been marked offline yet.
*/
- return ((nd == NULL || nd->nd_vers == NFS_VER2) ? ESTALE : NFSERR_TRYLATER);
+ return (nd == NULL || nd->nd_vers == NFS_VER2) ? ESTALE : NFSERR_TRYLATER;
}
fidp = nfhp->nfh_fhp + sizeof(*nxh);
error = VFS_FHTOVP(mp, nxh->nxh_fidlen, fidp, vpp, NULL);
vfs_unbusy(mp);
- if (error)
- return (error);
+ if (error) {
+ return error;
+ }
/* vnode pointer should be good at this point or ... */
- if (*vpp == NULL)
- return (ESTALE);
- return (0);
+ if (*vpp == NULL) {
+ return ESTALE;
+ }
+ return 0;
}
/*
}
}
ctx->vc_ucred = nd->nd_cr;
- return (0);
+ return 0;
}
/*
nfhp->nfh_xh.nxh_flags = 0;
nfhp->nfh_xh.nxh_reserved = 0;
- if (nfsvers == NFS_VER2)
+ if (nfsvers == NFS_VER2) {
bzero(&nfhp->nfh_fid[0], NFSV2_MAX_FID_SIZE);
+ }
/* if directory FH matches export root, return invalid FH */
if (dnfhp && nfsrv_fhmatch(dnfhp, &nx->nx_fh)) {
- if (nfsvers == NFS_VER2)
+ if (nfsvers == NFS_VER2) {
nfhp->nfh_len = NFSX_V2FH;
- else
+ } else {
nfhp->nfh_len = sizeof(nfhp->nfh_xh);
+ }
nfhp->nfh_xh.nxh_fidlen = 0;
nfhp->nfh_xh.nxh_flags = htons(NXHF_INVALIDFH);
- return (0);
+ return 0;
}
- if (nfsvers == NFS_VER2)
+ if (nfsvers == NFS_VER2) {
maxfidsize = NFSV2_MAX_FID_SIZE;
- else
+ } else {
maxfidsize = NFSV3_MAX_FID_SIZE;
+ }
nfhp->nfh_len = maxfidsize;
error = VFS_VPTOFH(vp, (int*)&nfhp->nfh_len, &nfhp->nfh_fid[0], ctx);
- if (error)
- return (error);
- if (nfhp->nfh_len > maxfidsize)
- return (EOVERFLOW);
+ if (error) {
+ return error;
+ }
+ if (nfhp->nfh_len > maxfidsize) {
+ return EOVERFLOW;
+ }
nfhp->nfh_xh.nxh_fidlen = nfhp->nfh_len;
nfhp->nfh_len += sizeof(nfhp->nfh_xh);
- if ((nfsvers == NFS_VER2) && (nfhp->nfh_len < NFSX_V2FH))
+ if ((nfsvers == NFS_VER2) && (nfhp->nfh_len < NFSX_V2FH)) {
nfhp->nfh_len = NFSX_V2FH;
+ }
- return (0);
+ return 0;
}
/*
nxh2 = (struct nfs_exphandle *)fh2->nfh_fhp;
len1 = sizeof(fh1->nfh_xh) + nxh1->nxh_fidlen;
len2 = sizeof(fh2->nfh_xh) + nxh2->nxh_fidlen;
- if (len1 != len2)
- return (0);
- if (bcmp(nxh1, nxh2, len1))
- return (0);
- return (1);
+ if (len1 != len2) {
+ return 0;
+ }
+ if (bcmp(nxh1, nxh2, len1)) {
+ return 0;
+ }
+ return 1;
}
/*
* If found, the node's tm_last timestamp is updated and the node is returned.
*
* If not found, a new node is allocated (or reclaimed via LRU), initialized, and returned.
- * Returns NULL if a new node could not be allcoated.
+ * Returns NULL if a new node could not be allocated OR saddr length exceeds sizeof(unode->sock).
*
* The list's user_mutex lock MUST be held.
*/
struct nfs_user_stat_node *
nfsrv_get_user_stat_node(struct nfs_active_user_list *list, struct sockaddr *saddr, uid_t uid)
{
- struct nfs_user_stat_node *unode;
- struct timeval now;
- struct nfs_user_stat_hashtbl_head *head;
+ struct nfs_user_stat_node *unode;
+ struct timeval now;
+ struct nfs_user_stat_hashtbl_head *head;
/* seach the hash table */
head = NFS_USER_STAT_HASH(list->user_hashtbl, uid);
return unode;
}
+ if (saddr->sa_len > sizeof(((struct nfs_user_stat_node *)0)->sock)) {
+ /* saddr length exceeds maximum value */
+ return NULL;
+ }
+
if (list->node_count < nfsrv_user_stat_max_nodes) {
/* Allocate a new node */
MALLOC(unode, struct nfs_user_stat_node *, sizeof(struct nfs_user_stat_node),
- M_TEMP, M_WAITOK | M_ZERO);
+ M_TEMP, M_WAITOK | M_ZERO);
- if (!unode)
+ if (!unode) {
return NULL;
+ }
/* increment node count */
OSAddAtomic(1, &nfsrv_user_stat_node_count);
/* reuse the oldest node in the lru list */
unode = TAILQ_FIRST(&list->user_lru);
- if (!unode)
+ if (!unode) {
return NULL;
+ }
/* Remove the node */
TAILQ_REMOVE(&list->user_lru, unode, lru_link);
/* Initialize the node */
unode->uid = uid;
- bcopy(saddr, &unode->sock, saddr->sa_len);
+ bcopy(saddr, &unode->sock, MIN(saddr->sa_len, sizeof(unode->sock)));
microtime(&now);
unode->ops = 0;
unode->bytes_read = 0;
void
nfsrv_update_user_stat(struct nfs_export *nx, struct nfsrv_descript *nd, uid_t uid, u_int ops, u_int rd_bytes, u_int wr_bytes)
{
- struct nfs_user_stat_node *unode;
- struct nfs_active_user_list *ulist;
- struct sockaddr *saddr;
+ struct nfs_user_stat_node *unode;
+ struct nfs_active_user_list *ulist;
+ struct sockaddr *saddr;
- if ((!nfsrv_user_stat_enabled) || (!nx) || (!nd) || (!nd->nd_nam))
+ if ((!nfsrv_user_stat_enabled) || (!nx) || (!nd) || (!nd->nd_nam)) {
return;
+ }
saddr = (struct sockaddr *)mbuf_data(nd->nd_nam);
/* check address family before going any further */
- if ((saddr->sa_family != AF_INET) && (saddr->sa_family != AF_INET6))
+ if ((saddr->sa_family != AF_INET) && (saddr->sa_family != AF_INET6)) {
return;
+ }
ulist = &nx->nx_user_list;
TAILQ_INIT(&ulist->user_lru);
/* initialize the hash table */
- for(i = 0; i < NFS_USER_STAT_HASH_SIZE; i++)
+ for (i = 0; i < NFS_USER_STAT_HASH_SIZE; i++) {
LIST_INIT(&ulist->user_hashtbl[i]);
+ }
ulist->node_count = 0;
- lck_mtx_init(&ulist->user_mutex, nfsrv_active_user_mutex_group, LCK_ATTR_NULL);
+ lck_mtx_init(&ulist->user_mutex, &nfsrv_active_user_mutex_group, LCK_ATTR_NULL);
}
/* Free all nodes in an active user list */
{
struct nfs_user_stat_node *unode;
- if (!ulist)
+ if (!ulist) {
return;
+ }
while ((unode = TAILQ_FIRST(&ulist->user_lru))) {
/* Remove node and free */
}
ulist->node_count = 0;
- lck_mtx_destroy(&ulist->user_mutex, nfsrv_active_user_mutex_group);
+ lck_mtx_destroy(&ulist->user_mutex, &nfsrv_active_user_mutex_group);
}
/* Reclaim old expired user nodes from active user lists. */
void
nfsrv_active_user_list_reclaim(void)
{
- struct nfs_exportfs *nxfs;
- struct nfs_export *nx;
- struct nfs_active_user_list *ulist;
- struct nfs_user_stat_hashtbl_head oldlist;
- struct nfs_user_stat_node *unode, *unode_next;
- struct timeval now;
- uint32_t tstale;
+ struct nfs_exportfs *nxfs;
+ struct nfs_export *nx;
+ struct nfs_active_user_list *ulist;
+ struct nfs_user_stat_hashtbl_head oldlist;
+ struct nfs_user_stat_node *unode, *unode_next;
+ struct timeval now;
+ long tstale;
LIST_INIT(&oldlist);
unode_next = TAILQ_NEXT(unode, lru_link);
/* check if this node has expired */
- if (unode->tm_last >= tstale)
+ if (unode->tm_last >= tstale) {
break;
+ }
/* Remove node from the active user list */
TAILQ_REMOVE(&ulist->user_lru, unode, lru_link);
lck_mtx_unlock(&ulist->user_mutex);
}
}
- lck_rw_done(&nfsrv_export_rwlock);
+ lck_rw_done(&nfsrv_export_rwlock);
/* Free expired nodes */
- while ((unode = LIST_FIRST(&oldlist))) {
+ while ((unode = LIST_FIRST(&oldlist))) {
LIST_REMOVE(unode, hash_link);
FREE(unode, M_TEMP);
}
* RFC 1094.
*/
static u_char nfsrv_v2errmap[] = {
- NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
- NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
- NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
- NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
+ NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR,
+ NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO,
+ NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO,
+ NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE,
};
/*
short *defaulterrp, *errp;
if (nd->nd_vers == NFS_VER2) {
- if (err <= (int)sizeof(nfsrv_v2errmap))
- return ((int)nfsrv_v2errmap[err - 1]);
- return (NFSERR_IO);
+ if (err <= (int)sizeof(nfsrv_v2errmap)) {
+ return (int)nfsrv_v2errmap[err - 1];
+ }
+ return NFSERR_IO;
}
/* NFSv3 */
- if (nd->nd_procnum > NFSPROC_COMMIT)
- return (err & 0xffff);
+ if (nd->nd_procnum > NFSPROC_COMMIT) {
+ return err & 0xffff;
+ }
errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
while (*++errp) {
- if (*errp == err)
- return (err);
- else if (*errp > err)
+ if (*errp == err) {
+ return err;
+ } else if (*errp > err) {
break;
+ }
}
- return ((int)*defaulterrp);
+ return (int)*defaulterrp;
}
-#endif /* NFSSERVER */
+#endif /* CONFIG_NFS_SERVER */
+#endif /* CONFIG_NFS */