X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/3e170ce000f1506b7b5d2c5c7faec85ceabb573d..refs/heads/master:/bsd/nfs/nfs_subs.c diff --git a/bsd/nfs/nfs_subs.c b/bsd/nfs/nfs_subs.c index 8496093a9..a58fc7869 100644 --- a/bsd/nfs/nfs_subs.c +++ b/bsd/nfs/nfs_subs.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2000-2014 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 @@ -11,10 +11,10 @@ * 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, @@ -22,7 +22,7 @@ * 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 */ @@ -65,6 +65,9 @@ * FreeBSD-Id: nfs_subs.c,v 1.47 1997/11/07 08:53:24 phk Exp $ */ +#include +#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 @@ -79,6 +82,7 @@ #include #include #include +#include #include #include #include @@ -88,6 +92,7 @@ #include #include #include +#include #include #include @@ -99,7 +104,7 @@ #include #include #include -#if NFSCLIENT +#if CONFIG_NFS_CLIENT #define _NFS_XDR_SUBS_FUNCS_ /* define this to get xdrbuf function definitions */ #endif #include @@ -118,7 +123,7 @@ /* * NFS globals */ -struct nfsstats __attribute__((aligned(8))) nfsstats; +struct nfsstats __attribute__((aligned(8))) nfsstats; size_t nfs_mbuf_mhlen = 0, nfs_mbuf_minclsize = 0; /* @@ -141,11 +146,15 @@ vtonfs_type(enum vtype vtype, int nfsvers) 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: @@ -171,17 +180,25 @@ nfstov_type(nfstype nvtype, int nfsvers) 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; } @@ -209,7 +226,7 @@ vtonfsv2_mode(enum vtype vtype, mode_t m) } } -#if NFSSERVER +#if CONFIG_NFS_SERVER /* * Mapping of old NFS Version 2 RPC numbers to generic numbers. @@ -240,7 +257,7 @@ int nfsv3_procid[NFS_NPROCS] = { NFSPROC_NOOP }; -#endif /* NFSSERVER */ +#endif /* CONFIG_NFS_SERVER */ /* * and the reverse mapping from generic to Version 2 procedure numbers @@ -285,7 +302,7 @@ nfs_mbuf_init(void) nfs_mbuf_minclsize = ms.minclsize; } -#if NFSSERVER +#if CONFIG_NFS_SERVER /* * allocate a list of mbufs to hold the given amount of data @@ -302,18 +319,21 @@ nfsm_mbuf_get_list(size_t size, mbuf_t *mp, int *mbcnt) 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++; @@ -324,10 +344,10 @@ nfsm_mbuf_get_list(size_t size, mbuf_t *mp, int *mbcnt) *mp = mhead; *mbcnt = cnt; } - return (error); + return error; } -#endif /* NFSSERVER */ +#endif /* CONFIG_NFS_SERVER */ /* * nfsm_chain_new_mbuf() @@ -340,15 +360,18 @@ nfsm_chain_new_mbuf(struct nfsm_chain *nmc, size_t sizehint) 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) { @@ -358,7 +381,7 @@ nfsm_chain_new_mbuf(struct nfsm_chain *nmc, size_t sizehint) error = mbuf_setnext(nmc->nmc_mcur, mb); if (error) { mbuf_free(mb); - return (error); + return error; } } @@ -367,7 +390,7 @@ nfsm_chain_new_mbuf(struct nfsm_chain *nmc, size_t sizehint) nmc->nmc_ptr = mbuf_data(mb); nmc->nmc_left = mbuf_trailingspace(mb); - return (0); + return 0; } /* @@ -376,9 +399,9 @@ nfsm_chain_new_mbuf(struct nfsm_chain *nmc, size_t sizehint) * 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); @@ -386,14 +409,16 @@ nfsm_chain_add_opaque_f(struct nfsm_chain *nmc, const u_char *buf, uint32_t 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); @@ -407,7 +432,7 @@ nfsm_chain_add_opaque_f(struct nfsm_chain *nmc, const u_char *buf, uint32_t len) } } } - return (0); + return 0; } /* @@ -417,16 +442,17 @@ nfsm_chain_add_opaque_f(struct nfsm_chain *nmc, const u_char *buf, uint32_t len) * 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); @@ -435,7 +461,7 @@ nfsm_chain_add_opaque_nopad_f(struct nfsm_chain *nmc, const u_char *buf, uint32_ len -= tlen; buf += tlen; } - return (0); + return 0; } /* @@ -444,9 +470,9 @@ nfsm_chain_add_opaque_nopad_f(struct nfsm_chain *nmc, const u_char *buf, uint32_ * 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); @@ -454,45 +480,47 @@ nfsm_chain_add_uio(struct nfsm_chain *nmc, uio_t uio, uint32_t 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; } /* @@ -501,7 +529,7 @@ nfsm_chain_offset(struct nfsm_chain *nmc) * 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; @@ -509,17 +537,18 @@ nfsm_chain_advance(struct nfsm_chain *nmc, uint32_t len) 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; } /* @@ -528,24 +557,25 @@ nfsm_chain_advance(struct nfsm_chain *nmc, uint32_t len) * 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); } /* @@ -561,7 +591,8 @@ int 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; @@ -569,21 +600,23 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p 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; @@ -598,13 +631,14 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p * 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 */ @@ -617,11 +651,12 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p /* 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" */ @@ -673,21 +708,22 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p 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; } /* @@ -701,10 +737,11 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p nmc->nmc_left = mbuf_len(mb); /* move past any padding */ - if (padlen) + if (padlen) { error = nfsm_chain_advance(nmc, padlen); + } - return (error); + return error; } /* @@ -714,9 +751,9 @@ nfsm_chain_get_opaque_pointer_f(struct nfsm_chain *nmc, uint32_t len, u_char **p * 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; @@ -742,13 +779,15 @@ nfsm_chain_get_opaque_f(struct nfsm_chain *nmc, uint32_t len, u_char *buf) } /* 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; } /* @@ -758,9 +797,9 @@ nfsm_chain_get_opaque_f(struct nfsm_chain *nmc, uint32_t len, u_char *buf) * 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; @@ -770,9 +809,11 @@ nfsm_chain_get_uio(struct nfsm_chain *nmc, uint32_t len, uio_t uio) /* 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; @@ -787,42 +828,45 @@ nfsm_chain_get_uio(struct nfsm_chain *nmc, uint32_t len, uio_t uio) } /* 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; } /* @@ -834,27 +878,30 @@ nfsm_chain_add_v2sattr_f(struct nfsm_chain *nmc, struct vnode_attr *vap, uint32_ 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; @@ -902,7 +949,8 @@ nfsm_chain_add_v3sattr_f(struct nfsm_chain *nmc, struct vnode_attr *vap) } } - return (error); + + return error; } @@ -913,6 +961,7 @@ nfsm_chain_add_v3sattr_f(struct nfsm_chain *nmc, struct vnode_attr *vap) */ int nfsm_chain_get_fh_attr( + struct nfsmount *nmp, struct nfsm_chain *nmc, nfsnode_t dnp, vfs_context_t ctx, @@ -925,20 +974,24 @@ nfsm_chain_get_fh_attr( 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)) { @@ -947,7 +1000,7 @@ nfsm_chain_get_fh_attr( } } nfsmout: - return (error); + return error; } /* @@ -976,7 +1029,7 @@ nfsm_chain_get_wcc_data_f( } nfsm_chain_postop_attr_update_flag(error, nmc, np, *newpostattr, xidp); - return (error); + return error; } /* @@ -987,7 +1040,7 @@ nfs_get_xid(uint64_t *xidp) { struct timeval tv; - lck_mtx_lock(nfs_request_mutex); + lck_mtx_lock(&nfs_request_mutex); if (!nfs_xid) { /* * Derive initial xid from system time. @@ -1005,8 +1058,8 @@ nfs_get_xid(uint64_t *xidp) 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); } /* @@ -1026,7 +1079,7 @@ nfsm_rpchead( 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); } /* @@ -1036,25 +1089,26 @@ nfsm_rpchead( * 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. + * returns: The number of groups found. * * Just a wrapper around kauth_cred_getgroups to handle the case of a server supporting less - * than NGROUPS. + * than NGROUPS. */ -static int -get_auxiliary_groups(kauth_cred_t cred, gid_t groups[NGROUPS], int count) +static size_t +get_auxiliary_groups(kauth_cred_t cred, gid_t groups[NGROUPS], size_t count) { gid_t pgid; - int maxcount = count < NGROUPS ? count + 1 : NGROUPS; - int i; - - for (i = 0; i < NGROUPS; i++) - groups[i] = -2; /* Initialize to the nobody group */ + 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); - + 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 @@ -1067,74 +1121,79 @@ get_auxiliary_groups(kauth_cred_t cred, gid_t groups[NGROUPS], int count) pgid = kauth_cred_getgid(cred); if (pgid == groups[0]) { maxcount -= 1; - for (i = 0; i < maxcount; i++) { - groups[i] = groups[i+1]; + for (i = 0; i < maxcount; i++) { + groups[i] = groups[i + 1]; } } } - - return (maxcount); + + 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, 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]; - int groupcount; + size_t groupcount = 0; /* calculate expected auth length */ switch (auth_type) { - case RPCAUTH_NONE: - auth_len = 0; - break; - case RPCAUTH_SYS: - { - int count = nmp->nm_numgrps < NGROUPS ? nmp->nm_numgrps : NGROUPS; - - if (!cred) - return (EINVAL); - groupcount = get_auxiliary_groups(cred, grouplist, count); - if (groupcount < 0) - return (EINVAL); - auth_len = ((uint32_t)groupcount + 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); + case RPCAUTH_NONE: + auth_len = 0; + break; + case RPCAUTH_SYS: + { + size_t count = nmp->nm_numgrps < NGROUPS ? nmp->nm_numgrps : NGROUPS; + + 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; } /* @@ -1142,15 +1201,17 @@ nfsm_rpchead2(struct nfsmount *nmp, int sotype, int prog, int vers, int proc, in * 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)); @@ -1160,74 +1221,84 @@ nfsm_rpchead2(struct nfsmount *nmp, int sotype, int prog, int vers, int proc, in 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: { 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 */ + { + 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++) + 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) { - int count = nmp->nm_numgrps < NGROUPS ? nmp->nm_numgrps : 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; - groupcount = get_auxiliary_groups(cred, grouplist, count); - if (groupcount < 0) - return (EINVAL); - auth_len = ((uint32_t)groupcount + 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); @@ -1237,25 +1308,29 @@ add_cred: * 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; @@ -1300,8 +1375,9 @@ nfs_parsefattr(struct nfsm_chain *nmc, int nfsvers, struct nfs_vattr *nvap) * 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; } @@ -1338,22 +1414,25 @@ nfs_parsefattr(struct nfsm_chain *nmc, int nfsvers, struct nfs_vattr *nvap) 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 @@ -1394,7 +1473,7 @@ nfs_loadattrcache( if (!((nmp = VFSTONFS(mp)))) { FSDBG_BOT(527, ENXIO, 1, 0, *xidp); - return (ENXIO); + return ENXIO; } if (*xidp < np->n_xid) { @@ -1411,7 +1490,7 @@ nfs_loadattrcache( 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))) { @@ -1437,10 +1516,11 @@ nfs_loadattrcache( * 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; } @@ -1459,73 +1539,104 @@ nfs_loadattrcache( * 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 */ @@ -1544,17 +1655,19 @@ nfs_loadattrcache( 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 @@ -1562,9 +1675,11 @@ nfs_loadattrcache( */ 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; @@ -1589,8 +1704,9 @@ nfs_loadattrcache( */ np->n_newsize = nvap->nva_size; SET(np->n_flag, NUPDATESIZE); - if (monitored) + if (monitored) { events |= VNODE_EVENT_ATTRIB | VNODE_EVENT_EXTEND; + } } } @@ -1606,34 +1722,38 @@ nfs_loadattrcache( } 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; nmp = NFSTONMP(np); - if (nfs_mount_gone(nmp)) - return (0); + 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 { @@ -1643,19 +1763,21 @@ nfs_attrcachetimeout(nfsnode_t np) 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; } /* @@ -1669,36 +1791,44 @@ nfs_getattrcache(nfsnode_t np, struct nfs_vattr *nvaper, int flags) { 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; } nmp = NFSTONMP(np); - if (nfs_mount_gone(nmp)) - return (ENXIO); + if (nfs_mount_gone(nmp)) { + return ENXIO; + } /* * 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)) { - timeo = nfs_attrcachetimeout(np); 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); + 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); + return ENOENT; } } @@ -1739,14 +1869,15 @@ nfs_getattrcache(nfsnode_t np, struct nfs_vattr *nvaper, int flags) 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; } /* @@ -1816,36 +1947,47 @@ nfs_avoid_needless_id_setting_on_create(nfsnode_t dnp, struct vnode_attr *vap, v 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; @@ -1855,14 +1997,16 @@ nfs_uaddr2sockaddr(const char *uaddr, struct sockaddr *addr) 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 == '.') { @@ -1871,21 +2015,25 @@ nfs_uaddr2sockaddr(const char *uaddr, struct sockaddr *addr) /* 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); } @@ -1897,11 +2045,13 @@ nfs_uaddr2sockaddr(const char *uaddr, struct sockaddr *addr) 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 { @@ -1911,79 +2061,96 @@ nfs_uaddr2sockaddr(const char *uaddr, struct sockaddr *addr) } 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); + return 1; } @@ -1994,25 +2161,64 @@ uint32_t nfs_debug_ctl; #include void -nfs_printf(int facility, int level, const char *fmt, ...) +nfs_printf(unsigned int facility, unsigned int level, const char *fmt, ...) { va_list ap; - - if ((uint32_t)level > NFS_DEBUG_LEVEL) - return; - if (NFS_DEBUG_FACILITY && !((uint32_t)facility & NFS_DEBUG_FACILITY)) - return; - - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); + + if (NFS_IS_DBG(facility, level)) { + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + } +} + + +#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 !nmp || vfs_isforce(nmp->nm_mountp) || (nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD)); } /* @@ -2025,40 +2231,40 @@ 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); + (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 /* NFSCLIENT */ +#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 *); @@ -2094,7 +2300,7 @@ nfsm_chain_add_wcc_data_f( } nfsm_chain_add_postop_attr(error, nd, nmc, postattrerr, postvap); - return (error); + return error; } /* @@ -2111,38 +2317,40 @@ nfsm_chain_get_path_namei( 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; } /* @@ -2170,8 +2378,9 @@ nfsrv_namei( * 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); @@ -2182,12 +2391,14 @@ nfsrv_namei( 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 @@ -2198,13 +2409,15 @@ nfsrv_namei( 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 (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; @@ -2216,9 +2429,9 @@ out: 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; } /* @@ -2229,7 +2442,8 @@ void nfsm_adj(mbuf_t mp, int len, int nul) { mbuf_t m, mnext; - int count, i, mlen; + int count, i; + long mlen; char *cp; /* @@ -2245,8 +2459,9 @@ nfsm_adj(mbuf_t mp, int len, int nul) mlen = mbuf_len(m); count += mlen; mnext = mbuf_next(m); - if (mnext == NULL) + if (mnext == NULL) { break; + } m = mnext; } if (mlen > len) { @@ -2254,14 +2469,16 @@ nfsm_adj(mbuf_t mp, int len, int nul) 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, @@ -2274,15 +2491,17 @@ nfsm_adj(mbuf_t mp, int len, int nul) 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); + } } /* @@ -2292,18 +2511,22 @@ nfsm_adj(mbuf_t mp, int len, int nul) 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); @@ -2311,10 +2534,12 @@ nfsm_chain_trim_data(struct nfsm_chain *nmc, int len, int *mlen) 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)) { @@ -2323,21 +2548,25 @@ nfsm_chain_trim_data(struct nfsm_chain *nmc, int len, int *mlen) 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 @@ -2369,10 +2598,11 @@ nfsm_chain_add_fattr( } 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); @@ -2381,7 +2611,7 @@ nfsm_chain_add_fattr( 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 @@ -2409,27 +2639,32 @@ nfsm_chain_get_sattr( 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 */ @@ -2458,8 +2693,8 @@ nfsm_chain_get_sattr( 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; @@ -2472,19 +2707,20 @@ nfsm_chain_get_sattr( 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; } /* @@ -2495,11 +2731,14 @@ nfsrv_cmp_secflavs(struct nfs_sec *sf1, struct nfs_sec *sf2) { 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; } @@ -2516,33 +2755,41 @@ nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa) 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); + 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; } @@ -2550,9 +2797,10 @@ nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa) 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; @@ -2566,9 +2814,10 @@ nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa) 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; @@ -2583,24 +2832,25 @@ nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa) } 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 */ TAILQ_FOREACH(dom, &domains, dom_entry) { - if (dom->dom_family == i && dom->dom_rtattach) { - dom->dom_rtattach((void **)&nx->nx_rtable[i], - dom->dom_rtoffset); + 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); @@ -2624,46 +2874,51 @@ nfsrv_hang_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa) /* 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; } /* @@ -2685,11 +2940,12 @@ nfsrv_free_netopt(struct radix_node *rn, void *w) 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; } /* @@ -2703,29 +2959,33 @@ nfsrv_free_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa) 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 */ @@ -2739,25 +2999,42 @@ nfsrv_free_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa) 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--; @@ -2768,57 +3045,68 @@ nfsrv_free_addrlist(struct nfs_export *nx, struct user_nfs_export_args *unxa) } } - 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 */ @@ -2855,52 +3143,65 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx) 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; @@ -2916,11 +3217,12 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx) /* 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 */ @@ -2940,12 +3242,15 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx) /* 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; + } } } @@ -2957,39 +3262,51 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx) } 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 */ @@ -3026,16 +3343,18 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx) /* 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); @@ -3046,25 +3365,29 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx) */ 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) { /* @@ -3077,7 +3400,7 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx) * 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; @@ -3105,18 +3428,20 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx) 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; } @@ -3137,8 +3462,9 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx) } 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; @@ -3178,22 +3504,25 @@ nfsrv_export(struct user_nfs_export_args *unxa, vfs_context_t ctx) } 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: @@ -3211,8 +3540,9 @@ 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: @@ -3221,10 +3551,11 @@ out: nameidone(&mnd); } unlock_out: - if (mp) + if (mp) { mount_drop(mp, 0); + } lck_rw_done(&nfsrv_export_rwlock); - return (error); + return error; } /* @@ -3236,27 +3567,30 @@ unlock_out: int nfsrv_check_exports_allow_address(mbuf_t nam) { - struct nfs_exportfs *nxfs; - struct nfs_export *nx; - struct nfs_export_options *nxo; + struct nfs_exportfs *nxfs; + struct nfs_export *nx; + struct nfs_export_options *nxo = NULL; - if (nam == NULL) - return (EACCES); + 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) + if (nx->nx_flags & NX_DEFAULTEXPORT) { nxo = &nx->nx_defopt; - if (nxo || (nxo = nfsrv_export_lookup(nx, nam))) + } + if (nxo || (nxo = nfsrv_export_lookup(nx, nam))) { goto found; + } } } found: lck_rw_done(&nfsrv_export_rwlock); - return (nxo ? 0 : EACCES); + return nxo ? 0 : EACCES; } struct nfs_export_options * @@ -3270,20 +3604,27 @@ nfsrv_export_lookup(struct nfs_export *nx, mbuf_t nam) /* 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 */ @@ -3294,19 +3635,81 @@ nfsrv_fhtoexport(struct nfs_filehandle *nfhp) 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; } /* @@ -3333,30 +3736,36 @@ nfsrv_fhtovp( *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 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 */ @@ -3373,47 +3782,49 @@ nfsrv_fhtovp( * 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; } /* @@ -3436,7 +3847,7 @@ nfsrv_credcheck( } } ctx->vc_ucred = nd->nd_cr; - return (0); + return 0; } /* @@ -3466,37 +3877,43 @@ nfsrv_vptofh( 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; } /* @@ -3514,11 +3931,13 @@ nfsrv_fhmatch(struct nfs_filehandle *fh1, struct nfs_filehandle *fh2) 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; } /* @@ -3530,16 +3949,16 @@ nfsrv_fhmatch(struct nfs_filehandle *fh1, struct nfs_filehandle *fh2) * 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); @@ -3561,13 +3980,19 @@ nfsrv_get_user_stat_node(struct nfs_active_user_list *list, struct sockaddr *sad 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); @@ -3576,8 +4001,9 @@ nfsrv_get_user_stat_node(struct nfs_active_user_list *list, struct sockaddr *sad /* 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); @@ -3586,7 +4012,7 @@ nfsrv_get_user_stat_node(struct nfs_active_user_list *list, struct sockaddr *sad /* 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; @@ -3604,18 +4030,20 @@ nfsrv_get_user_stat_node(struct nfs_active_user_list *list, struct sockaddr *sad 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; @@ -3649,11 +4077,12 @@ nfsrv_init_user_list(struct nfs_active_user_list *ulist) 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 */ @@ -3662,8 +4091,9 @@ nfsrv_free_user_list(struct nfs_active_user_list *ulist) { struct nfs_user_stat_node *unode; - if (!ulist) + if (!ulist) { return; + } while ((unode = TAILQ_FIRST(&ulist->user_lru))) { /* Remove node and free */ @@ -3676,20 +4106,20 @@ nfsrv_free_user_list(struct nfs_active_user_list *ulist) } 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); @@ -3705,8 +4135,9 @@ nfsrv_active_user_list_reclaim(void) 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); @@ -3723,10 +4154,10 @@ nfsrv_active_user_list_reclaim(void) 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); } @@ -3738,20 +4169,20 @@ nfsrv_active_user_list_reclaim(void) * 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, }; /* @@ -4117,22 +4548,26 @@ nfsrv_errmap(struct nfsrv_descript *nd, int err) 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 */