1191783Srmacklem/*- 2191783Srmacklem * Copyright (c) 1989, 1993 3191783Srmacklem * The Regents of the University of California. All rights reserved. 4191783Srmacklem * 5191783Srmacklem * This code is derived from software contributed to Berkeley by 6191783Srmacklem * Rick Macklem at The University of Guelph. 7191783Srmacklem * 8191783Srmacklem * Redistribution and use in source and binary forms, with or without 9191783Srmacklem * modification, are permitted provided that the following conditions 10191783Srmacklem * are met: 11191783Srmacklem * 1. Redistributions of source code must retain the above copyright 12191783Srmacklem * notice, this list of conditions and the following disclaimer. 13191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 14191783Srmacklem * notice, this list of conditions and the following disclaimer in the 15191783Srmacklem * documentation and/or other materials provided with the distribution. 16191783Srmacklem * 4. Neither the name of the University nor the names of its contributors 17191783Srmacklem * may be used to endorse or promote products derived from this software 18191783Srmacklem * without specific prior written permission. 19191783Srmacklem * 20191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23191783Srmacklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30191783Srmacklem * SUCH DAMAGE. 31191783Srmacklem * 32191783Srmacklem */ 33191783Srmacklem 34191783Srmacklem#include <sys/cdefs.h> 35191783Srmacklem__FBSDID("$FreeBSD$"); 36191783Srmacklem 37191783Srmacklem/* 38191783Srmacklem * These functions support the macros and help fiddle mbuf chains for 39191783Srmacklem * the nfs op functions. They do things like create the rpc header and 40191783Srmacklem * copy data between mbuf chains and uio lists. 41191783Srmacklem */ 42191783Srmacklem#ifndef APPLEKEXT 43229802Srmacklem#include "opt_inet6.h" 44229802Srmacklem 45191783Srmacklem#include <fs/nfs/nfsport.h> 46191783Srmacklem 47191783Srmacklem/* 48191783Srmacklem * Data items converted to xdr at startup, since they are constant 49191783Srmacklem * This is kinda hokey, but may save a little time doing byte swaps 50191783Srmacklem */ 51191783Srmacklemu_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1; 52191783Srmacklem 53191783Srmacklem/* And other global data */ 54191783Srmacklemnfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, 55191783Srmacklem NFFIFO, NFNON }; 56191783Srmacklemenum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; 57191783Srmacklemenum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 58191783Srmacklemstruct timeval nfsboottime; /* Copy boottime once, so it never changes */ 59191783Srmacklemint nfscl_ticks; 60191783Srmacklemint nfsrv_useacl = 1; 61191783Srmacklemstruct nfssockreq nfsrv_nfsuserdsock; 62191783Srmacklemint nfsrv_nfsuserd = 0; 63191783Srmacklemstruct nfsreqhead nfsd_reqq; 64191783Srmacklemuid_t nfsrv_defaultuid; 65191783Srmacklemgid_t nfsrv_defaultgid; 66191783Srmacklemint nfsrv_lease = NFSRV_LEASE; 67191783Srmacklemint ncl_mbuf_mlen = MLEN; 68191783SrmacklemNFSNAMEIDMUTEX; 69191783SrmacklemNFSSOCKMUTEX; 70191783Srmacklem 71191783Srmacklem/* 72191783Srmacklem * This array of structures indicates, for V4: 73191783Srmacklem * retfh - which of 3 types of calling args are used 74191783Srmacklem * 0 - doesn't change cfh or use a sfh 75191783Srmacklem * 1 - replaces cfh with a new one (unless it returns an error status) 76191783Srmacklem * 2 - uses cfh and sfh 77191783Srmacklem * needscfh - if the op wants a cfh and premtime 78191783Srmacklem * 0 - doesn't use a cfh 79191783Srmacklem * 1 - uses a cfh, but doesn't want pre-op attributes 80191783Srmacklem * 2 - uses a cfh and wants pre-op attributes 81191783Srmacklem * savereply - indicates a non-idempotent Op 82191783Srmacklem * 0 - not non-idempotent 83191783Srmacklem * 1 - non-idempotent 84191783Srmacklem * Ops that are ordered via seqid# are handled separately from these 85191783Srmacklem * non-idempotent Ops. 86191783Srmacklem * Define it here, since it is used by both the client and server. 87191783Srmacklem */ 88244042Srmacklemstruct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = { 89244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */ 90244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */ 91244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */ 92244042Srmacklem { 0, 1, 0, 0, LK_SHARED, 1 }, /* Access */ 93244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Close */ 94244042Srmacklem { 0, 2, 0, 1, LK_EXCLUSIVE, 1 }, /* Commit */ 95244042Srmacklem { 1, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Create */ 96244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegpurge */ 97244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegreturn */ 98244042Srmacklem { 0, 1, 0, 0, LK_SHARED, 1 }, /* Getattr */ 99244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* GetFH */ 100244042Srmacklem { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Link */ 101244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lock */ 102244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockT */ 103244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockU */ 104244042Srmacklem { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookup */ 105244042Srmacklem { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookupp */ 106244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* NVerify */ 107244042Srmacklem { 1, 1, 0, 1, LK_EXCLUSIVE, 1 }, /* Open */ 108244042Srmacklem { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenAttr */ 109244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenConfirm */ 110244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenDowngrade */ 111244042Srmacklem { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutFH */ 112244042Srmacklem { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutPubFH */ 113244042Srmacklem { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutRootFH */ 114244042Srmacklem { 0, 1, 0, 0, LK_SHARED, 1 }, /* Read */ 115244042Srmacklem { 0, 1, 0, 0, LK_SHARED, 1 }, /* Readdir */ 116244042Srmacklem { 0, 1, 0, 0, LK_SHARED, 1 }, /* ReadLink */ 117244042Srmacklem { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Remove */ 118244042Srmacklem { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Rename */ 119244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Renew */ 120244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* RestoreFH */ 121244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SaveFH */ 122244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SecInfo */ 123244042Srmacklem { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Setattr */ 124244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientID */ 125244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientIDConfirm */ 126244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Verify */ 127244042Srmacklem { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Write */ 128244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* ReleaseLockOwner */ 129244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Backchannel Ctrl */ 130244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Bind Conn to Sess */ 131244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Exchange ID */ 132244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Create Session */ 133244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy Session */ 134244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Free StateID */ 135244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Dir Deleg */ 136244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device Info */ 137244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device List */ 138244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Commit */ 139244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Get */ 140244042Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Return */ 141244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Secinfo No name */ 142244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Sequence */ 143244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Set SSV */ 144244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Test StateID */ 145244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Want Delegation */ 146244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy ClientID */ 147244042Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Reclaim Complete */ 148191783Srmacklem}; 149191783Srmacklem#endif /* !APPLEKEXT */ 150191783Srmacklem 151191783Srmacklemstatic int ncl_mbuf_mhlen = MHLEN; 152191783Srmacklemstatic int nfsrv_usercnt = 0; 153191783Srmacklemstatic int nfsrv_dnsnamelen; 154191783Srmacklemstatic u_char *nfsrv_dnsname = NULL; 155191783Srmacklemstatic int nfsrv_usermax = 999999999; 156191783Srmacklemstatic struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE]; 157191783Srmacklemstatic struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE]; 158191783Srmacklemstatic struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE]; 159191783Srmacklemstatic struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE]; 160191783Srmacklemstatic struct nfsuserlruhead nfsuserlruhead; 161191783Srmacklem 162191783Srmacklem/* 163191783Srmacklem * This static array indicates whether or not the RPC generates a large 164191783Srmacklem * reply. This is used by nfs_reply() to decide whether or not an mbuf 165191783Srmacklem * cluster should be allocated. (If a cluster is required by an RPC 166191783Srmacklem * marked 0 in this array, the code will still work, just not quite as 167191783Srmacklem * efficiently.) 168191783Srmacklem */ 169244042Srmacklemint nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 170191783Srmacklem 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 171244042Srmacklem 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }; 172191783Srmacklem 173191783Srmacklem/* local functions */ 174191783Srmacklemstatic int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); 175191783Srmacklemstatic void nfsv4_wanted(struct nfsv4lock *lp); 176191783Srmacklemstatic int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len); 177191783Srmacklemstatic int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, 178191783Srmacklem NFSPROC_T *p); 179191783Srmacklemstatic void nfsrv_removeuser(struct nfsusrgrp *usrp); 180191783Srmacklemstatic int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **, 181191783Srmacklem int *, int *); 182191783Srmacklemstatic void nfsrv_refstrbigenough(int, u_char **, u_char **, int *); 183191783Srmacklem 184191783Srmacklem 185191783Srmacklem#ifndef APPLE 186191783Srmacklem/* 187191783Srmacklem * copies mbuf chain to the uio scatter/gather list 188191783Srmacklem */ 189191783Srmacklemint 190191783Srmacklemnfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz) 191191783Srmacklem{ 192191783Srmacklem char *mbufcp, *uiocp; 193191783Srmacklem int xfer, left, len; 194191783Srmacklem mbuf_t mp; 195191783Srmacklem long uiosiz, rem; 196191783Srmacklem int error = 0; 197191783Srmacklem 198191783Srmacklem mp = nd->nd_md; 199191783Srmacklem mbufcp = nd->nd_dpos; 200191783Srmacklem len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp; 201191783Srmacklem rem = NFSM_RNDUP(siz) - siz; 202191783Srmacklem while (siz > 0) { 203224086Szack if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) { 204224086Szack error = EBADRPC; 205224086Szack goto out; 206224086Szack } 207191783Srmacklem left = uiop->uio_iov->iov_len; 208191783Srmacklem uiocp = uiop->uio_iov->iov_base; 209191783Srmacklem if (left > siz) 210191783Srmacklem left = siz; 211191783Srmacklem uiosiz = left; 212191783Srmacklem while (left > 0) { 213191783Srmacklem while (len == 0) { 214191783Srmacklem mp = mbuf_next(mp); 215224086Szack if (mp == NULL) { 216224086Szack error = EBADRPC; 217224086Szack goto out; 218224086Szack } 219191783Srmacklem mbufcp = NFSMTOD(mp, caddr_t); 220191783Srmacklem len = mbuf_len(mp); 221246213Skib KASSERT(len > 0, ("len %d", len)); 222191783Srmacklem } 223191783Srmacklem xfer = (left > len) ? len : left; 224191783Srmacklem#ifdef notdef 225191783Srmacklem /* Not Yet.. */ 226191783Srmacklem if (uiop->uio_iov->iov_op != NULL) 227191783Srmacklem (*(uiop->uio_iov->iov_op)) 228191783Srmacklem (mbufcp, uiocp, xfer); 229191783Srmacklem else 230191783Srmacklem#endif 231191783Srmacklem if (uiop->uio_segflg == UIO_SYSSPACE) 232191783Srmacklem NFSBCOPY(mbufcp, uiocp, xfer); 233191783Srmacklem else 234191783Srmacklem copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer); 235191783Srmacklem left -= xfer; 236191783Srmacklem len -= xfer; 237191783Srmacklem mbufcp += xfer; 238191783Srmacklem uiocp += xfer; 239191783Srmacklem uiop->uio_offset += xfer; 240191783Srmacklem uiop->uio_resid -= xfer; 241191783Srmacklem } 242191783Srmacklem if (uiop->uio_iov->iov_len <= siz) { 243191783Srmacklem uiop->uio_iovcnt--; 244191783Srmacklem uiop->uio_iov++; 245191783Srmacklem } else { 246191783Srmacklem uiop->uio_iov->iov_base = (void *) 247191783Srmacklem ((char *)uiop->uio_iov->iov_base + uiosiz); 248191783Srmacklem uiop->uio_iov->iov_len -= uiosiz; 249191783Srmacklem } 250191783Srmacklem siz -= uiosiz; 251191783Srmacklem } 252191783Srmacklem nd->nd_dpos = mbufcp; 253191783Srmacklem nd->nd_md = mp; 254191783Srmacklem if (rem > 0) { 255191783Srmacklem if (len < rem) 256191783Srmacklem error = nfsm_advance(nd, rem, len); 257191783Srmacklem else 258191783Srmacklem nd->nd_dpos += rem; 259191783Srmacklem } 260224086Szack 261224086Szackout: 262224086Szack NFSEXITCODE2(error, nd); 263191783Srmacklem return (error); 264191783Srmacklem} 265191783Srmacklem#endif /* !APPLE */ 266191783Srmacklem 267191783Srmacklem/* 268191783Srmacklem * Help break down an mbuf chain by setting the first siz bytes contiguous 269191783Srmacklem * pointed to by returned val. 270191783Srmacklem * This is used by the macro NFSM_DISSECT for tough 271191783Srmacklem * cases. 272191783Srmacklem */ 273191783SrmacklemAPPLESTATIC void * 274249592Skennfsm_dissct(struct nfsrv_descript *nd, int siz, int how) 275191783Srmacklem{ 276191783Srmacklem mbuf_t mp2; 277191783Srmacklem int siz2, xfer; 278191783Srmacklem caddr_t p; 279191783Srmacklem int left; 280191783Srmacklem caddr_t retp; 281191783Srmacklem 282191783Srmacklem retp = NULL; 283191783Srmacklem left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos; 284191783Srmacklem while (left == 0) { 285191783Srmacklem nd->nd_md = mbuf_next(nd->nd_md); 286191783Srmacklem if (nd->nd_md == NULL) 287191783Srmacklem return (retp); 288191783Srmacklem left = mbuf_len(nd->nd_md); 289191783Srmacklem nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); 290191783Srmacklem } 291191783Srmacklem if (left >= siz) { 292191783Srmacklem retp = nd->nd_dpos; 293191783Srmacklem nd->nd_dpos += siz; 294191783Srmacklem } else if (mbuf_next(nd->nd_md) == NULL) { 295191783Srmacklem return (retp); 296191783Srmacklem } else if (siz > ncl_mbuf_mhlen) { 297191783Srmacklem panic("nfs S too big"); 298191783Srmacklem } else { 299249592Sken MGET(mp2, MT_DATA, how); 300249592Sken if (mp2 == NULL) 301249592Sken return (NULL); 302191783Srmacklem mbuf_setnext(mp2, mbuf_next(nd->nd_md)); 303191783Srmacklem mbuf_setnext(nd->nd_md, mp2); 304191783Srmacklem mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left); 305191783Srmacklem nd->nd_md = mp2; 306191783Srmacklem retp = p = NFSMTOD(mp2, caddr_t); 307191783Srmacklem NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */ 308191783Srmacklem siz2 = siz - left; 309191783Srmacklem p += left; 310191783Srmacklem mp2 = mbuf_next(mp2); 311191783Srmacklem /* Loop around copying up the siz2 bytes */ 312191783Srmacklem while (siz2 > 0) { 313191783Srmacklem if (mp2 == NULL) 314191783Srmacklem return (NULL); 315191783Srmacklem xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2; 316191783Srmacklem if (xfer > 0) { 317191783Srmacklem NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer); 318191783Srmacklem NFSM_DATAP(mp2, xfer); 319191783Srmacklem mbuf_setlen(mp2, mbuf_len(mp2) - xfer); 320191783Srmacklem p += xfer; 321191783Srmacklem siz2 -= xfer; 322191783Srmacklem } 323191783Srmacklem if (siz2 > 0) 324191783Srmacklem mp2 = mbuf_next(mp2); 325191783Srmacklem } 326191783Srmacklem mbuf_setlen(nd->nd_md, siz); 327191783Srmacklem nd->nd_md = mp2; 328191783Srmacklem nd->nd_dpos = NFSMTOD(mp2, caddr_t); 329191783Srmacklem } 330191783Srmacklem return (retp); 331191783Srmacklem} 332191783Srmacklem 333191783Srmacklem/* 334191783Srmacklem * Advance the position in the mbuf chain. 335191783Srmacklem * If offs == 0, this is a no-op, but it is simpler to just return from 336191783Srmacklem * here than check for offs > 0 for all calls to nfsm_advance. 337191783Srmacklem * If left == -1, it should be calculated here. 338191783Srmacklem */ 339191783SrmacklemAPPLESTATIC int 340191783Srmacklemnfsm_advance(struct nfsrv_descript *nd, int offs, int left) 341191783Srmacklem{ 342224086Szack int error = 0; 343191783Srmacklem 344191783Srmacklem if (offs == 0) 345224086Szack goto out; 346191783Srmacklem /* 347191783Srmacklem * A negative offs should be considered a serious problem. 348191783Srmacklem */ 349191783Srmacklem if (offs < 0) 350191783Srmacklem panic("nfsrv_advance"); 351191783Srmacklem 352191783Srmacklem /* 353191783Srmacklem * If left == -1, calculate it here. 354191783Srmacklem */ 355191783Srmacklem if (left == -1) 356191783Srmacklem left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - 357191783Srmacklem nd->nd_dpos; 358191783Srmacklem 359191783Srmacklem /* 360191783Srmacklem * Loop around, advancing over the mbuf data. 361191783Srmacklem */ 362191783Srmacklem while (offs > left) { 363191783Srmacklem offs -= left; 364191783Srmacklem nd->nd_md = mbuf_next(nd->nd_md); 365224086Szack if (nd->nd_md == NULL) { 366224086Szack error = EBADRPC; 367224086Szack goto out; 368224086Szack } 369191783Srmacklem left = mbuf_len(nd->nd_md); 370191783Srmacklem nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); 371191783Srmacklem } 372191783Srmacklem nd->nd_dpos += offs; 373224086Szack 374224086Szackout: 375224086Szack NFSEXITCODE(error); 376224086Szack return (error); 377191783Srmacklem} 378191783Srmacklem 379191783Srmacklem/* 380191783Srmacklem * Copy a string into mbuf(s). 381191783Srmacklem * Return the number of bytes output, including XDR overheads. 382191783Srmacklem */ 383191783SrmacklemAPPLESTATIC int 384191783Srmacklemnfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz) 385191783Srmacklem{ 386191783Srmacklem mbuf_t m2; 387191783Srmacklem int xfer, left; 388191783Srmacklem mbuf_t m1; 389191783Srmacklem int rem, bytesize; 390191783Srmacklem u_int32_t *tl; 391191783Srmacklem char *cp2; 392191783Srmacklem 393191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 394191783Srmacklem *tl = txdr_unsigned(siz); 395191783Srmacklem rem = NFSM_RNDUP(siz) - siz; 396191783Srmacklem bytesize = NFSX_UNSIGNED + siz + rem; 397191783Srmacklem m2 = nd->nd_mb; 398191783Srmacklem cp2 = nd->nd_bpos; 399191783Srmacklem left = M_TRAILINGSPACE(m2); 400191783Srmacklem 401191783Srmacklem /* 402191783Srmacklem * Loop around copying the string to mbuf(s). 403191783Srmacklem */ 404191783Srmacklem while (siz > 0) { 405191783Srmacklem if (left == 0) { 406191783Srmacklem if (siz > ncl_mbuf_mlen) 407243882Sglebius NFSMCLGET(m1, M_WAITOK); 408191783Srmacklem else 409191783Srmacklem NFSMGET(m1); 410191783Srmacklem mbuf_setlen(m1, 0); 411191783Srmacklem mbuf_setnext(m2, m1); 412191783Srmacklem m2 = m1; 413191783Srmacklem cp2 = NFSMTOD(m2, caddr_t); 414191783Srmacklem left = M_TRAILINGSPACE(m2); 415191783Srmacklem } 416191783Srmacklem if (left >= siz) 417191783Srmacklem xfer = siz; 418191783Srmacklem else 419191783Srmacklem xfer = left; 420191783Srmacklem NFSBCOPY(cp, cp2, xfer); 421191783Srmacklem cp += xfer; 422191783Srmacklem mbuf_setlen(m2, mbuf_len(m2) + xfer); 423191783Srmacklem siz -= xfer; 424191783Srmacklem left -= xfer; 425191783Srmacklem if (siz == 0 && rem) { 426191783Srmacklem if (left < rem) 427191783Srmacklem panic("nfsm_strtom"); 428191783Srmacklem NFSBZERO(cp2 + xfer, rem); 429191783Srmacklem mbuf_setlen(m2, mbuf_len(m2) + rem); 430191783Srmacklem } 431191783Srmacklem } 432191783Srmacklem nd->nd_mb = m2; 433191783Srmacklem nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); 434191783Srmacklem return (bytesize); 435191783Srmacklem} 436191783Srmacklem 437191783Srmacklem/* 438191783Srmacklem * Called once to initialize data structures... 439191783Srmacklem */ 440191783SrmacklemAPPLESTATIC void 441191783Srmacklemnewnfs_init(void) 442191783Srmacklem{ 443191783Srmacklem static int nfs_inited = 0; 444191783Srmacklem 445191783Srmacklem if (nfs_inited) 446191783Srmacklem return; 447191783Srmacklem nfs_inited = 1; 448191783Srmacklem 449191783Srmacklem newnfs_true = txdr_unsigned(TRUE); 450191783Srmacklem newnfs_false = txdr_unsigned(FALSE); 451191783Srmacklem newnfs_xdrneg1 = txdr_unsigned(-1); 452191783Srmacklem nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 453191783Srmacklem if (nfscl_ticks < 1) 454191783Srmacklem nfscl_ticks = 1; 455191783Srmacklem NFSSETBOOTTIME(nfsboottime); 456191783Srmacklem 457191783Srmacklem /* 458191783Srmacklem * Initialize reply list and start timer 459191783Srmacklem */ 460191783Srmacklem TAILQ_INIT(&nfsd_reqq); 461191783Srmacklem NFS_TIMERINIT; 462191783Srmacklem} 463191783Srmacklem 464191783Srmacklem/* 465191783Srmacklem * Put a file handle in an mbuf list. 466191783Srmacklem * If the size argument == 0, just use the default size. 467191783Srmacklem * set_true == 1 if there should be an newnfs_true prepended on the file handle. 468191783Srmacklem * Return the number of bytes output, including XDR overhead. 469191783Srmacklem */ 470191783SrmacklemAPPLESTATIC int 471191783Srmacklemnfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true) 472191783Srmacklem{ 473191783Srmacklem u_int32_t *tl; 474191783Srmacklem u_int8_t *cp; 475191783Srmacklem int fullsiz, rem, bytesize = 0; 476191783Srmacklem 477191783Srmacklem if (size == 0) 478191783Srmacklem size = NFSX_MYFH; 479191783Srmacklem switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { 480191783Srmacklem case ND_NFSV2: 481191783Srmacklem if (size > NFSX_V2FH) 482191783Srmacklem panic("fh size > NFSX_V2FH for NFSv2"); 483191783Srmacklem NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH); 484191783Srmacklem NFSBCOPY(fhp, cp, size); 485191783Srmacklem if (size < NFSX_V2FH) 486191783Srmacklem NFSBZERO(cp + size, NFSX_V2FH - size); 487191783Srmacklem bytesize = NFSX_V2FH; 488191783Srmacklem break; 489191783Srmacklem case ND_NFSV3: 490191783Srmacklem case ND_NFSV4: 491191783Srmacklem fullsiz = NFSM_RNDUP(size); 492191783Srmacklem rem = fullsiz - size; 493191783Srmacklem if (set_true) { 494191783Srmacklem bytesize = 2 * NFSX_UNSIGNED + fullsiz; 495191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 496191783Srmacklem *tl = newnfs_true; 497191783Srmacklem } else { 498191783Srmacklem bytesize = NFSX_UNSIGNED + fullsiz; 499191783Srmacklem } 500191783Srmacklem (void) nfsm_strtom(nd, fhp, size); 501191783Srmacklem break; 502191783Srmacklem }; 503191783Srmacklem return (bytesize); 504191783Srmacklem} 505191783Srmacklem 506191783Srmacklem/* 507191783Srmacklem * This function compares two net addresses by family and returns TRUE 508191783Srmacklem * if they are the same host. 509191783Srmacklem * If there is any doubt, return FALSE. 510191783Srmacklem * The AF_INET family is handled as a special case so that address mbufs 511191783Srmacklem * don't need to be saved to store "struct in_addr", which is only 4 bytes. 512191783Srmacklem */ 513191783SrmacklemAPPLESTATIC int 514191783Srmacklemnfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam) 515191783Srmacklem{ 516191783Srmacklem struct sockaddr_in *inetaddr; 517191783Srmacklem 518191783Srmacklem switch (family) { 519191783Srmacklem case AF_INET: 520191783Srmacklem inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *); 521191783Srmacklem if (inetaddr->sin_family == AF_INET && 522191783Srmacklem inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr) 523191783Srmacklem return (1); 524191783Srmacklem break; 525191783Srmacklem#ifdef INET6 526191783Srmacklem case AF_INET6: 527191783Srmacklem { 528191783Srmacklem struct sockaddr_in6 *inetaddr6; 529191783Srmacklem 530191783Srmacklem inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *); 531191783Srmacklem /* XXX - should test sin6_scope_id ? */ 532191783Srmacklem if (inetaddr6->sin6_family == AF_INET6 && 533191783Srmacklem IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr, 534191783Srmacklem &haddr->had_inet6)) 535191783Srmacklem return (1); 536191783Srmacklem } 537191783Srmacklem break; 538191783Srmacklem#endif 539191783Srmacklem }; 540191783Srmacklem return (0); 541191783Srmacklem} 542191783Srmacklem 543191783Srmacklem/* 544191783Srmacklem * Similar to the above, but takes to NFSSOCKADDR_T args. 545191783Srmacklem */ 546191783SrmacklemAPPLESTATIC int 547191783Srmacklemnfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2) 548191783Srmacklem{ 549191783Srmacklem struct sockaddr_in *addr1, *addr2; 550191783Srmacklem struct sockaddr *inaddr; 551191783Srmacklem 552191783Srmacklem inaddr = NFSSOCKADDR(nam1, struct sockaddr *); 553191783Srmacklem switch (inaddr->sa_family) { 554191783Srmacklem case AF_INET: 555191783Srmacklem addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *); 556191783Srmacklem addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *); 557191783Srmacklem if (addr2->sin_family == AF_INET && 558191783Srmacklem addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) 559191783Srmacklem return (1); 560191783Srmacklem break; 561191783Srmacklem#ifdef INET6 562191783Srmacklem case AF_INET6: 563191783Srmacklem { 564191783Srmacklem struct sockaddr_in6 *inet6addr1, *inet6addr2; 565191783Srmacklem 566191783Srmacklem inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *); 567191783Srmacklem inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *); 568191783Srmacklem /* XXX - should test sin6_scope_id ? */ 569191783Srmacklem if (inet6addr2->sin6_family == AF_INET6 && 570191783Srmacklem IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 571191783Srmacklem &inet6addr2->sin6_addr)) 572191783Srmacklem return (1); 573191783Srmacklem } 574191783Srmacklem break; 575191783Srmacklem#endif 576191783Srmacklem }; 577191783Srmacklem return (0); 578191783Srmacklem} 579191783Srmacklem 580191783Srmacklem 581191783Srmacklem/* 582191783Srmacklem * Trim the stuff already dissected off the mbuf list. 583191783Srmacklem */ 584191783SrmacklemAPPLESTATIC void 585191783Srmacklemnewnfs_trimleading(nd) 586191783Srmacklem struct nfsrv_descript *nd; 587191783Srmacklem{ 588191783Srmacklem mbuf_t m, n; 589191783Srmacklem int offs; 590191783Srmacklem 591191783Srmacklem /* 592191783Srmacklem * First, free up leading mbufs. 593191783Srmacklem */ 594191783Srmacklem if (nd->nd_mrep != nd->nd_md) { 595191783Srmacklem m = nd->nd_mrep; 596191783Srmacklem while (mbuf_next(m) != nd->nd_md) { 597191783Srmacklem if (mbuf_next(m) == NULL) 598191783Srmacklem panic("nfsm trim leading"); 599191783Srmacklem m = mbuf_next(m); 600191783Srmacklem } 601191783Srmacklem mbuf_setnext(m, NULL); 602191783Srmacklem mbuf_freem(nd->nd_mrep); 603191783Srmacklem } 604191783Srmacklem m = nd->nd_md; 605191783Srmacklem 606191783Srmacklem /* 607191783Srmacklem * Now, adjust this mbuf, based on nd_dpos. 608191783Srmacklem */ 609191783Srmacklem offs = nd->nd_dpos - NFSMTOD(m, caddr_t); 610191783Srmacklem if (offs == mbuf_len(m)) { 611191783Srmacklem n = m; 612191783Srmacklem m = mbuf_next(m); 613191783Srmacklem if (m == NULL) 614191783Srmacklem panic("nfsm trim leading2"); 615191783Srmacklem mbuf_setnext(n, NULL); 616191783Srmacklem mbuf_freem(n); 617191783Srmacklem } else if (offs > 0) { 618191783Srmacklem mbuf_setlen(m, mbuf_len(m) - offs); 619191783Srmacklem NFSM_DATAP(m, offs); 620191783Srmacklem } else if (offs < 0) 621191783Srmacklem panic("nfsm trimleading offs"); 622191783Srmacklem nd->nd_mrep = m; 623191783Srmacklem nd->nd_md = m; 624191783Srmacklem nd->nd_dpos = NFSMTOD(m, caddr_t); 625191783Srmacklem} 626191783Srmacklem 627191783Srmacklem/* 628191783Srmacklem * Trim trailing data off the mbuf list being built. 629191783Srmacklem */ 630191783SrmacklemAPPLESTATIC void 631191783Srmacklemnewnfs_trimtrailing(nd, mb, bpos) 632191783Srmacklem struct nfsrv_descript *nd; 633191783Srmacklem mbuf_t mb; 634191783Srmacklem caddr_t bpos; 635191783Srmacklem{ 636191783Srmacklem 637191783Srmacklem if (mbuf_next(mb)) { 638191783Srmacklem mbuf_freem(mbuf_next(mb)); 639191783Srmacklem mbuf_setnext(mb, NULL); 640191783Srmacklem } 641191783Srmacklem mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t)); 642191783Srmacklem nd->nd_mb = mb; 643191783Srmacklem nd->nd_bpos = bpos; 644191783Srmacklem} 645191783Srmacklem 646191783Srmacklem/* 647191783Srmacklem * Dissect a file handle on the client. 648191783Srmacklem */ 649191783SrmacklemAPPLESTATIC int 650191783Srmacklemnfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp) 651191783Srmacklem{ 652191783Srmacklem u_int32_t *tl; 653191783Srmacklem struct nfsfh *nfhp; 654191783Srmacklem int error, len; 655191783Srmacklem 656191783Srmacklem *nfhpp = NULL; 657191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 658191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 659191783Srmacklem if ((len = fxdr_unsigned(int, *tl)) <= 0 || 660224086Szack len > NFSX_FHMAX) { 661224086Szack error = EBADRPC; 662224086Szack goto nfsmout; 663224086Szack } 664191783Srmacklem } else 665191783Srmacklem len = NFSX_V2FH; 666191783Srmacklem MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len, 667191783Srmacklem M_NFSFH, M_WAITOK); 668191783Srmacklem error = nfsrv_mtostr(nd, nfhp->nfh_fh, len); 669191783Srmacklem if (error) { 670191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 671224086Szack goto nfsmout; 672191783Srmacklem } 673191783Srmacklem nfhp->nfh_len = len; 674191783Srmacklem *nfhpp = nfhp; 675191783Srmacklemnfsmout: 676224086Szack NFSEXITCODE2(error, nd); 677191783Srmacklem return (error); 678191783Srmacklem} 679191783Srmacklem 680191783Srmacklem/* 681191783Srmacklem * Break down the nfsv4 acl. 682191783Srmacklem * If the aclp == NULL or won't fit in an acl, just discard the acl info. 683191783Srmacklem */ 684191783SrmacklemAPPLESTATIC int 685191783Srmacklemnfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp, 686191783Srmacklem int *aclsizep, __unused NFSPROC_T *p) 687191783Srmacklem{ 688191783Srmacklem u_int32_t *tl; 689191783Srmacklem int i, aclsize; 690191783Srmacklem int acecnt, error = 0, aceerr = 0, acesize; 691191783Srmacklem 692191783Srmacklem *aclerrp = 0; 693191783Srmacklem if (aclp) 694191783Srmacklem aclp->acl_cnt = 0; 695191783Srmacklem /* 696191783Srmacklem * Parse out the ace entries and expect them to conform to 697191783Srmacklem * what can be supported by R/W/X bits. 698191783Srmacklem */ 699191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 700191783Srmacklem aclsize = NFSX_UNSIGNED; 701191783Srmacklem acecnt = fxdr_unsigned(int, *tl); 702191783Srmacklem if (acecnt > ACL_MAX_ENTRIES) 703224077Szack aceerr = NFSERR_ATTRNOTSUPP; 704191783Srmacklem if (nfsrv_useacl == 0) 705224077Szack aceerr = NFSERR_ATTRNOTSUPP; 706191783Srmacklem for (i = 0; i < acecnt; i++) { 707191783Srmacklem if (aclp && !aceerr) 708191783Srmacklem error = nfsrv_dissectace(nd, &aclp->acl_entry[i], 709191783Srmacklem &aceerr, &acesize, p); 710191783Srmacklem else 711191783Srmacklem error = nfsrv_skipace(nd, &acesize); 712191783Srmacklem if (error) 713224086Szack goto nfsmout; 714191783Srmacklem aclsize += acesize; 715191783Srmacklem } 716191783Srmacklem if (aclp && !aceerr) 717191783Srmacklem aclp->acl_cnt = acecnt; 718191783Srmacklem if (aceerr) 719191783Srmacklem *aclerrp = aceerr; 720191783Srmacklem if (aclsizep) 721191783Srmacklem *aclsizep = aclsize; 722191783Srmacklemnfsmout: 723224086Szack NFSEXITCODE2(error, nd); 724191783Srmacklem return (error); 725191783Srmacklem} 726191783Srmacklem 727191783Srmacklem/* 728191783Srmacklem * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it. 729191783Srmacklem */ 730191783Srmacklemstatic int 731191783Srmacklemnfsrv_skipace(struct nfsrv_descript *nd, int *acesizep) 732191783Srmacklem{ 733191783Srmacklem u_int32_t *tl; 734191783Srmacklem int error, len = 0; 735191783Srmacklem 736191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 737191783Srmacklem len = fxdr_unsigned(int, *(tl + 3)); 738191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 739191783Srmacklemnfsmout: 740191783Srmacklem *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); 741224086Szack NFSEXITCODE2(error, nd); 742191783Srmacklem return (error); 743191783Srmacklem} 744191783Srmacklem 745191783Srmacklem/* 746191783Srmacklem * Get attribute bits from an mbuf list. 747191783Srmacklem * Returns EBADRPC for a parsing error, 0 otherwise. 748191783Srmacklem * If the clearinvalid flag is set, clear the bits not supported. 749191783Srmacklem */ 750191783SrmacklemAPPLESTATIC int 751191783Srmacklemnfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp, 752191783Srmacklem int *retnotsupp) 753191783Srmacklem{ 754191783Srmacklem u_int32_t *tl; 755191783Srmacklem int cnt, i, outcnt; 756191783Srmacklem int error = 0; 757191783Srmacklem 758191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 759191783Srmacklem cnt = fxdr_unsigned(int, *tl); 760224086Szack if (cnt < 0) { 761224086Szack error = NFSERR_BADXDR; 762224086Szack goto nfsmout; 763224086Szack } 764253506Srmacklem if (cnt > NFSATTRBIT_MAXWORDS) 765191783Srmacklem outcnt = NFSATTRBIT_MAXWORDS; 766253506Srmacklem else 767191783Srmacklem outcnt = cnt; 768191783Srmacklem NFSZERO_ATTRBIT(attrbitp); 769191783Srmacklem if (outcnt > 0) { 770191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED); 771191783Srmacklem for (i = 0; i < outcnt; i++) 772191783Srmacklem attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++); 773191783Srmacklem } 774253506Srmacklem for (i = 0; i < (cnt - outcnt); i++) { 775253506Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 776253506Srmacklem if (retnotsupp != NULL && *tl != 0) 777253506Srmacklem *retnotsupp = NFSERR_ATTRNOTSUPP; 778253506Srmacklem } 779191783Srmacklem if (cntp) 780191783Srmacklem *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED); 781191783Srmacklemnfsmout: 782224086Szack NFSEXITCODE2(error, nd); 783191783Srmacklem return (error); 784191783Srmacklem} 785191783Srmacklem 786191783Srmacklem/* 787191783Srmacklem * Get the attributes for V4. 788191783Srmacklem * If the compare flag is true, test for any attribute changes, 789191783Srmacklem * otherwise return the attribute values. 790191783Srmacklem * These attributes cover fields in "struct vattr", "struct statfs", 791191783Srmacklem * "struct nfsfsinfo", the file handle and the lease duration. 792191783Srmacklem * The value of retcmpp is set to 1 if all attributes are the same, 793191783Srmacklem * and 0 otherwise. 794191783Srmacklem * Returns EBADRPC if it can't be parsed, 0 otherwise. 795191783Srmacklem */ 796191783SrmacklemAPPLESTATIC int 797191783Srmacklemnfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, 798191783Srmacklem struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize, 799191783Srmacklem struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp, 800191783Srmacklem struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp, 801191783Srmacklem u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred) 802191783Srmacklem{ 803191783Srmacklem u_int32_t *tl; 804224086Szack int i = 0, j, k, l = 0, m, bitpos, attrsum = 0; 805191783Srmacklem int error, tfhsize, aceerr, attrsize, cnt, retnotsup; 806191783Srmacklem u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1]; 807191783Srmacklem nfsattrbit_t attrbits, retattrbits, checkattrbits; 808191783Srmacklem struct nfsfh *tnfhp; 809191783Srmacklem struct nfsreferral *refp; 810191783Srmacklem u_quad_t tquad; 811191783Srmacklem nfsquad_t tnfsquad; 812191783Srmacklem struct timespec temptime; 813191783Srmacklem uid_t uid; 814191783Srmacklem gid_t gid; 815191783Srmacklem long fid; 816191783Srmacklem u_int32_t freenum = 0, tuint; 817191783Srmacklem u_int64_t uquad = 0, thyp, thyp2; 818191783Srmacklem#ifdef QUOTA 819191783Srmacklem struct dqblk dqb; 820191783Srmacklem uid_t savuid; 821191783Srmacklem#endif 822191783Srmacklem 823191783Srmacklem if (compare) { 824191783Srmacklem retnotsup = 0; 825191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); 826191783Srmacklem } else { 827191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 828191783Srmacklem } 829191783Srmacklem if (error) 830224086Szack goto nfsmout; 831191783Srmacklem 832191783Srmacklem if (compare) { 833191783Srmacklem *retcmpp = retnotsup; 834191783Srmacklem } else { 835191783Srmacklem /* 836191783Srmacklem * Just set default values to some of the important ones. 837191783Srmacklem */ 838191783Srmacklem if (nap != NULL) { 839191783Srmacklem nap->na_type = VREG; 840191783Srmacklem nap->na_mode = 0; 841191783Srmacklem nap->na_rdev = (NFSDEV_T)0; 842191783Srmacklem nap->na_mtime.tv_sec = 0; 843191783Srmacklem nap->na_mtime.tv_nsec = 0; 844191783Srmacklem nap->na_gen = 0; 845191783Srmacklem nap->na_flags = 0; 846191783Srmacklem nap->na_blocksize = NFS_FABLKSIZE; 847191783Srmacklem } 848191783Srmacklem if (sbp != NULL) { 849191783Srmacklem sbp->f_bsize = NFS_FABLKSIZE; 850191783Srmacklem sbp->f_blocks = 0; 851191783Srmacklem sbp->f_bfree = 0; 852191783Srmacklem sbp->f_bavail = 0; 853191783Srmacklem sbp->f_files = 0; 854191783Srmacklem sbp->f_ffree = 0; 855191783Srmacklem } 856191783Srmacklem if (fsp != NULL) { 857191783Srmacklem fsp->fs_rtmax = 8192; 858191783Srmacklem fsp->fs_rtpref = 8192; 859191783Srmacklem fsp->fs_maxname = NFS_MAXNAMLEN; 860191783Srmacklem fsp->fs_wtmax = 8192; 861191783Srmacklem fsp->fs_wtpref = 8192; 862191783Srmacklem fsp->fs_wtmult = NFS_FABLKSIZE; 863191783Srmacklem fsp->fs_dtpref = 8192; 864191783Srmacklem fsp->fs_maxfilesize = 0xffffffffffffffffull; 865191783Srmacklem fsp->fs_timedelta.tv_sec = 0; 866191783Srmacklem fsp->fs_timedelta.tv_nsec = 1; 867191783Srmacklem fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK | 868191783Srmacklem NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME); 869191783Srmacklem } 870191783Srmacklem if (pc != NULL) { 871191783Srmacklem pc->pc_linkmax = LINK_MAX; 872191783Srmacklem pc->pc_namemax = NAME_MAX; 873191783Srmacklem pc->pc_notrunc = 0; 874191783Srmacklem pc->pc_chownrestricted = 0; 875191783Srmacklem pc->pc_caseinsensitive = 0; 876191783Srmacklem pc->pc_casepreserving = 1; 877191783Srmacklem } 878191783Srmacklem } 879191783Srmacklem 880191783Srmacklem /* 881191783Srmacklem * Loop around getting the attributes. 882191783Srmacklem */ 883191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 884191783Srmacklem attrsize = fxdr_unsigned(int, *tl); 885191783Srmacklem for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 886191783Srmacklem if (attrsum > attrsize) { 887191783Srmacklem error = NFSERR_BADXDR; 888191783Srmacklem goto nfsmout; 889191783Srmacklem } 890191783Srmacklem if (NFSISSET_ATTRBIT(&attrbits, bitpos)) 891191783Srmacklem switch (bitpos) { 892191783Srmacklem case NFSATTRBIT_SUPPORTEDATTRS: 893191783Srmacklem retnotsup = 0; 894191783Srmacklem if (compare || nap == NULL) 895191783Srmacklem error = nfsrv_getattrbits(nd, &retattrbits, 896191783Srmacklem &cnt, &retnotsup); 897191783Srmacklem else 898191783Srmacklem error = nfsrv_getattrbits(nd, &nap->na_suppattr, 899191783Srmacklem &cnt, &retnotsup); 900191783Srmacklem if (error) 901224086Szack goto nfsmout; 902191783Srmacklem if (compare && !(*retcmpp)) { 903191783Srmacklem NFSSETSUPP_ATTRBIT(&checkattrbits); 904191783Srmacklem if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 905191783Srmacklem || retnotsup) 906191783Srmacklem *retcmpp = NFSERR_NOTSAME; 907191783Srmacklem } 908191783Srmacklem attrsum += cnt; 909191783Srmacklem break; 910191783Srmacklem case NFSATTRBIT_TYPE: 911191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 912191783Srmacklem if (compare) { 913191783Srmacklem if (!(*retcmpp)) { 914191783Srmacklem if (nap->na_type != nfsv34tov_type(*tl)) 915191783Srmacklem *retcmpp = NFSERR_NOTSAME; 916191783Srmacklem } 917191783Srmacklem } else if (nap != NULL) { 918191783Srmacklem nap->na_type = nfsv34tov_type(*tl); 919191783Srmacklem } 920191783Srmacklem attrsum += NFSX_UNSIGNED; 921191783Srmacklem break; 922191783Srmacklem case NFSATTRBIT_FHEXPIRETYPE: 923191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 924191783Srmacklem if (compare && !(*retcmpp)) { 925191783Srmacklem if (fxdr_unsigned(int, *tl) != 926191783Srmacklem NFSV4FHTYPE_PERSISTENT) 927191783Srmacklem *retcmpp = NFSERR_NOTSAME; 928191783Srmacklem } 929191783Srmacklem attrsum += NFSX_UNSIGNED; 930191783Srmacklem break; 931191783Srmacklem case NFSATTRBIT_CHANGE: 932191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 933191783Srmacklem if (compare) { 934191783Srmacklem if (!(*retcmpp)) { 935191783Srmacklem if (nap->na_filerev != fxdr_hyper(tl)) 936191783Srmacklem *retcmpp = NFSERR_NOTSAME; 937191783Srmacklem } 938191783Srmacklem } else if (nap != NULL) { 939191783Srmacklem nap->na_filerev = fxdr_hyper(tl); 940191783Srmacklem } 941191783Srmacklem attrsum += NFSX_HYPER; 942191783Srmacklem break; 943191783Srmacklem case NFSATTRBIT_SIZE: 944191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 945191783Srmacklem if (compare) { 946191783Srmacklem if (!(*retcmpp)) { 947191783Srmacklem if (nap->na_size != fxdr_hyper(tl)) 948191783Srmacklem *retcmpp = NFSERR_NOTSAME; 949191783Srmacklem } 950191783Srmacklem } else if (nap != NULL) { 951191783Srmacklem nap->na_size = fxdr_hyper(tl); 952191783Srmacklem } 953191783Srmacklem attrsum += NFSX_HYPER; 954191783Srmacklem break; 955191783Srmacklem case NFSATTRBIT_LINKSUPPORT: 956191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 957191783Srmacklem if (compare) { 958191783Srmacklem if (!(*retcmpp)) { 959191783Srmacklem if (fsp->fs_properties & NFSV3_FSFLINK) { 960191783Srmacklem if (*tl == newnfs_false) 961191783Srmacklem *retcmpp = NFSERR_NOTSAME; 962191783Srmacklem } else { 963191783Srmacklem if (*tl == newnfs_true) 964191783Srmacklem *retcmpp = NFSERR_NOTSAME; 965191783Srmacklem } 966191783Srmacklem } 967191783Srmacklem } else if (fsp != NULL) { 968191783Srmacklem if (*tl == newnfs_true) 969191783Srmacklem fsp->fs_properties |= NFSV3_FSFLINK; 970191783Srmacklem else 971191783Srmacklem fsp->fs_properties &= ~NFSV3_FSFLINK; 972191783Srmacklem } 973191783Srmacklem attrsum += NFSX_UNSIGNED; 974191783Srmacklem break; 975191783Srmacklem case NFSATTRBIT_SYMLINKSUPPORT: 976191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 977191783Srmacklem if (compare) { 978191783Srmacklem if (!(*retcmpp)) { 979191783Srmacklem if (fsp->fs_properties & NFSV3_FSFSYMLINK) { 980191783Srmacklem if (*tl == newnfs_false) 981191783Srmacklem *retcmpp = NFSERR_NOTSAME; 982191783Srmacklem } else { 983191783Srmacklem if (*tl == newnfs_true) 984191783Srmacklem *retcmpp = NFSERR_NOTSAME; 985191783Srmacklem } 986191783Srmacklem } 987191783Srmacklem } else if (fsp != NULL) { 988191783Srmacklem if (*tl == newnfs_true) 989191783Srmacklem fsp->fs_properties |= NFSV3_FSFSYMLINK; 990191783Srmacklem else 991191783Srmacklem fsp->fs_properties &= ~NFSV3_FSFSYMLINK; 992191783Srmacklem } 993191783Srmacklem attrsum += NFSX_UNSIGNED; 994191783Srmacklem break; 995191783Srmacklem case NFSATTRBIT_NAMEDATTR: 996191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 997191783Srmacklem if (compare && !(*retcmpp)) { 998191783Srmacklem if (*tl != newnfs_false) 999191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1000191783Srmacklem } 1001191783Srmacklem attrsum += NFSX_UNSIGNED; 1002191783Srmacklem break; 1003191783Srmacklem case NFSATTRBIT_FSID: 1004191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1005191783Srmacklem thyp = fxdr_hyper(tl); 1006191783Srmacklem tl += 2; 1007191783Srmacklem thyp2 = fxdr_hyper(tl); 1008191783Srmacklem if (compare) { 1009191783Srmacklem if (*retcmpp == 0) { 1010191783Srmacklem if (thyp != (u_int64_t) 1011191783Srmacklem vfs_statfs(vnode_mount(vp))->f_fsid.val[0] || 1012191783Srmacklem thyp2 != (u_int64_t) 1013191783Srmacklem vfs_statfs(vnode_mount(vp))->f_fsid.val[1]) 1014191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1015191783Srmacklem } 1016191783Srmacklem } else if (nap != NULL) { 1017191783Srmacklem nap->na_filesid[0] = thyp; 1018191783Srmacklem nap->na_filesid[1] = thyp2; 1019191783Srmacklem } 1020191783Srmacklem attrsum += (4 * NFSX_UNSIGNED); 1021191783Srmacklem break; 1022191783Srmacklem case NFSATTRBIT_UNIQUEHANDLES: 1023191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1024191783Srmacklem if (compare && !(*retcmpp)) { 1025191783Srmacklem if (*tl != newnfs_true) 1026191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1027191783Srmacklem } 1028191783Srmacklem attrsum += NFSX_UNSIGNED; 1029191783Srmacklem break; 1030191783Srmacklem case NFSATTRBIT_LEASETIME: 1031191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1032191783Srmacklem if (compare) { 1033191783Srmacklem if (fxdr_unsigned(int, *tl) != nfsrv_lease && 1034191783Srmacklem !(*retcmpp)) 1035191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1036191783Srmacklem } else if (leasep != NULL) { 1037191783Srmacklem *leasep = fxdr_unsigned(u_int32_t, *tl); 1038191783Srmacklem } 1039191783Srmacklem attrsum += NFSX_UNSIGNED; 1040191783Srmacklem break; 1041191783Srmacklem case NFSATTRBIT_RDATTRERROR: 1042191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1043191783Srmacklem if (compare) { 1044191783Srmacklem if (!(*retcmpp)) 1045191783Srmacklem *retcmpp = NFSERR_INVAL; 1046191783Srmacklem } else if (rderrp != NULL) { 1047191783Srmacklem *rderrp = fxdr_unsigned(u_int32_t, *tl); 1048191783Srmacklem } 1049191783Srmacklem attrsum += NFSX_UNSIGNED; 1050191783Srmacklem break; 1051191783Srmacklem case NFSATTRBIT_ACL: 1052191783Srmacklem if (compare) { 1053191783Srmacklem if (!(*retcmpp)) { 1054191783Srmacklem if (nfsrv_useacl) { 1055191783Srmacklem NFSACL_T *naclp; 1056191783Srmacklem 1057192861Srmacklem naclp = acl_alloc(M_WAITOK); 1058191783Srmacklem error = nfsrv_dissectacl(nd, naclp, &aceerr, 1059191783Srmacklem &cnt, p); 1060191783Srmacklem if (error) { 1061191783Srmacklem acl_free(naclp); 1062224086Szack goto nfsmout; 1063191783Srmacklem } 1064224121Szack if (aceerr || aclp == NULL || 1065224121Szack nfsrv_compareacl(aclp, naclp)) 1066191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1067191783Srmacklem acl_free(naclp); 1068200069Strasz } else { 1069191783Srmacklem error = nfsrv_dissectacl(nd, NULL, &aceerr, 1070191783Srmacklem &cnt, p); 1071191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1072191783Srmacklem } 1073191783Srmacklem } 1074191783Srmacklem } else { 1075191783Srmacklem if (vp != NULL && aclp != NULL) 1076191783Srmacklem error = nfsrv_dissectacl(nd, aclp, &aceerr, 1077191783Srmacklem &cnt, p); 1078191783Srmacklem else 1079191783Srmacklem error = nfsrv_dissectacl(nd, NULL, &aceerr, 1080191783Srmacklem &cnt, p); 1081191783Srmacklem if (error) 1082224086Szack goto nfsmout; 1083191783Srmacklem } 1084191783Srmacklem attrsum += cnt; 1085191783Srmacklem break; 1086191783Srmacklem case NFSATTRBIT_ACLSUPPORT: 1087191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1088191783Srmacklem if (compare && !(*retcmpp)) { 1089191783Srmacklem if (nfsrv_useacl) { 1090191783Srmacklem if (fxdr_unsigned(u_int32_t, *tl) != 1091191783Srmacklem NFSV4ACE_SUPTYPES) 1092191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1093191783Srmacklem } else { 1094191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1095191783Srmacklem } 1096191783Srmacklem } 1097191783Srmacklem attrsum += NFSX_UNSIGNED; 1098191783Srmacklem break; 1099191783Srmacklem case NFSATTRBIT_ARCHIVE: 1100191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1101191783Srmacklem if (compare && !(*retcmpp)) 1102191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1103191783Srmacklem attrsum += NFSX_UNSIGNED; 1104191783Srmacklem break; 1105191783Srmacklem case NFSATTRBIT_CANSETTIME: 1106191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1107191783Srmacklem if (compare) { 1108191783Srmacklem if (!(*retcmpp)) { 1109191783Srmacklem if (fsp->fs_properties & NFSV3_FSFCANSETTIME) { 1110191783Srmacklem if (*tl == newnfs_false) 1111191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1112191783Srmacklem } else { 1113191783Srmacklem if (*tl == newnfs_true) 1114191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1115191783Srmacklem } 1116191783Srmacklem } 1117191783Srmacklem } else if (fsp != NULL) { 1118191783Srmacklem if (*tl == newnfs_true) 1119191783Srmacklem fsp->fs_properties |= NFSV3_FSFCANSETTIME; 1120191783Srmacklem else 1121191783Srmacklem fsp->fs_properties &= ~NFSV3_FSFCANSETTIME; 1122191783Srmacklem } 1123191783Srmacklem attrsum += NFSX_UNSIGNED; 1124191783Srmacklem break; 1125191783Srmacklem case NFSATTRBIT_CASEINSENSITIVE: 1126191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1127191783Srmacklem if (compare) { 1128191783Srmacklem if (!(*retcmpp)) { 1129191783Srmacklem if (*tl != newnfs_false) 1130191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1131191783Srmacklem } 1132191783Srmacklem } else if (pc != NULL) { 1133191783Srmacklem pc->pc_caseinsensitive = 1134191783Srmacklem fxdr_unsigned(u_int32_t, *tl); 1135191783Srmacklem } 1136191783Srmacklem attrsum += NFSX_UNSIGNED; 1137191783Srmacklem break; 1138191783Srmacklem case NFSATTRBIT_CASEPRESERVING: 1139191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1140191783Srmacklem if (compare) { 1141191783Srmacklem if (!(*retcmpp)) { 1142191783Srmacklem if (*tl != newnfs_true) 1143191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1144191783Srmacklem } 1145191783Srmacklem } else if (pc != NULL) { 1146191783Srmacklem pc->pc_casepreserving = 1147191783Srmacklem fxdr_unsigned(u_int32_t, *tl); 1148191783Srmacklem } 1149191783Srmacklem attrsum += NFSX_UNSIGNED; 1150191783Srmacklem break; 1151191783Srmacklem case NFSATTRBIT_CHOWNRESTRICTED: 1152191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1153191783Srmacklem if (compare) { 1154191783Srmacklem if (!(*retcmpp)) { 1155224121Szack if (*tl != newnfs_true) 1156224121Szack *retcmpp = NFSERR_NOTSAME; 1157191783Srmacklem } 1158191783Srmacklem } else if (pc != NULL) { 1159191783Srmacklem pc->pc_chownrestricted = 1160191783Srmacklem fxdr_unsigned(u_int32_t, *tl); 1161191783Srmacklem } 1162191783Srmacklem attrsum += NFSX_UNSIGNED; 1163191783Srmacklem break; 1164191783Srmacklem case NFSATTRBIT_FILEHANDLE: 1165191783Srmacklem error = nfsm_getfh(nd, &tnfhp); 1166191783Srmacklem if (error) 1167224086Szack goto nfsmout; 1168191783Srmacklem tfhsize = tnfhp->nfh_len; 1169191783Srmacklem if (compare) { 1170191783Srmacklem if (!(*retcmpp) && 1171191783Srmacklem !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize, 1172191783Srmacklem fhp, fhsize)) 1173191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1174191783Srmacklem FREE((caddr_t)tnfhp, M_NFSFH); 1175191783Srmacklem } else if (nfhpp != NULL) { 1176191783Srmacklem *nfhpp = tnfhp; 1177191783Srmacklem } else { 1178191783Srmacklem FREE((caddr_t)tnfhp, M_NFSFH); 1179191783Srmacklem } 1180191783Srmacklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize)); 1181191783Srmacklem break; 1182191783Srmacklem case NFSATTRBIT_FILEID: 1183191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1184191783Srmacklem thyp = fxdr_hyper(tl); 1185191783Srmacklem if (compare) { 1186191783Srmacklem if (!(*retcmpp)) { 1187191783Srmacklem if ((u_int64_t)nap->na_fileid != thyp) 1188191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1189191783Srmacklem } 1190191783Srmacklem } else if (nap != NULL) { 1191191783Srmacklem if (*tl++) 1192191783Srmacklem printf("NFSv4 fileid > 32bits\n"); 1193191783Srmacklem nap->na_fileid = thyp; 1194191783Srmacklem } 1195191783Srmacklem attrsum += NFSX_HYPER; 1196191783Srmacklem break; 1197191783Srmacklem case NFSATTRBIT_FILESAVAIL: 1198191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1199191783Srmacklem if (compare) { 1200191783Srmacklem if (!(*retcmpp) && 1201191783Srmacklem sfp->sf_afiles != fxdr_hyper(tl)) 1202191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1203191783Srmacklem } else if (sfp != NULL) { 1204191783Srmacklem sfp->sf_afiles = fxdr_hyper(tl); 1205191783Srmacklem } 1206191783Srmacklem attrsum += NFSX_HYPER; 1207191783Srmacklem break; 1208191783Srmacklem case NFSATTRBIT_FILESFREE: 1209191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1210191783Srmacklem if (compare) { 1211191783Srmacklem if (!(*retcmpp) && 1212191783Srmacklem sfp->sf_ffiles != fxdr_hyper(tl)) 1213191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1214191783Srmacklem } else if (sfp != NULL) { 1215191783Srmacklem sfp->sf_ffiles = fxdr_hyper(tl); 1216191783Srmacklem } 1217191783Srmacklem attrsum += NFSX_HYPER; 1218191783Srmacklem break; 1219191783Srmacklem case NFSATTRBIT_FILESTOTAL: 1220191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1221191783Srmacklem if (compare) { 1222191783Srmacklem if (!(*retcmpp) && 1223191783Srmacklem sfp->sf_tfiles != fxdr_hyper(tl)) 1224191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1225191783Srmacklem } else if (sfp != NULL) { 1226191783Srmacklem sfp->sf_tfiles = fxdr_hyper(tl); 1227191783Srmacklem } 1228191783Srmacklem attrsum += NFSX_HYPER; 1229191783Srmacklem break; 1230191783Srmacklem case NFSATTRBIT_FSLOCATIONS: 1231191783Srmacklem error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m); 1232191783Srmacklem if (error) 1233224086Szack goto nfsmout; 1234191783Srmacklem attrsum += l; 1235191783Srmacklem if (compare && !(*retcmpp)) { 1236191783Srmacklem refp = nfsv4root_getreferral(vp, NULL, 0); 1237191783Srmacklem if (refp != NULL) { 1238191783Srmacklem if (cp == NULL || cp2 == NULL || 1239191783Srmacklem strcmp(cp, "/") || 1240191783Srmacklem strcmp(cp2, refp->nfr_srvlist)) 1241191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1242191783Srmacklem } else if (m == 0) { 1243191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1244191783Srmacklem } 1245191783Srmacklem } 1246191783Srmacklem if (cp != NULL) 1247191783Srmacklem free(cp, M_NFSSTRING); 1248191783Srmacklem if (cp2 != NULL) 1249191783Srmacklem free(cp2, M_NFSSTRING); 1250191783Srmacklem break; 1251191783Srmacklem case NFSATTRBIT_HIDDEN: 1252191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1253191783Srmacklem if (compare && !(*retcmpp)) 1254191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1255191783Srmacklem attrsum += NFSX_UNSIGNED; 1256191783Srmacklem break; 1257191783Srmacklem case NFSATTRBIT_HOMOGENEOUS: 1258191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1259191783Srmacklem if (compare) { 1260191783Srmacklem if (!(*retcmpp)) { 1261191783Srmacklem if (fsp->fs_properties & 1262191783Srmacklem NFSV3_FSFHOMOGENEOUS) { 1263191783Srmacklem if (*tl == newnfs_false) 1264191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1265191783Srmacklem } else { 1266191783Srmacklem if (*tl == newnfs_true) 1267191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1268191783Srmacklem } 1269191783Srmacklem } 1270191783Srmacklem } else if (fsp != NULL) { 1271191783Srmacklem if (*tl == newnfs_true) 1272191783Srmacklem fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS; 1273191783Srmacklem else 1274191783Srmacklem fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS; 1275191783Srmacklem } 1276191783Srmacklem attrsum += NFSX_UNSIGNED; 1277191783Srmacklem break; 1278191783Srmacklem case NFSATTRBIT_MAXFILESIZE: 1279191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1280191783Srmacklem tnfsquad.qval = fxdr_hyper(tl); 1281191783Srmacklem if (compare) { 1282191783Srmacklem if (!(*retcmpp)) { 1283191783Srmacklem tquad = NFSRV_MAXFILESIZE; 1284191783Srmacklem if (tquad != tnfsquad.qval) 1285191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1286191783Srmacklem } 1287191783Srmacklem } else if (fsp != NULL) { 1288191783Srmacklem fsp->fs_maxfilesize = tnfsquad.qval; 1289191783Srmacklem } 1290191783Srmacklem attrsum += NFSX_HYPER; 1291191783Srmacklem break; 1292191783Srmacklem case NFSATTRBIT_MAXLINK: 1293191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1294191783Srmacklem if (compare) { 1295191783Srmacklem if (!(*retcmpp)) { 1296191783Srmacklem if (fxdr_unsigned(int, *tl) != LINK_MAX) 1297191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1298191783Srmacklem } 1299191783Srmacklem } else if (pc != NULL) { 1300191783Srmacklem pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl); 1301191783Srmacklem } 1302191783Srmacklem attrsum += NFSX_UNSIGNED; 1303191783Srmacklem break; 1304191783Srmacklem case NFSATTRBIT_MAXNAME: 1305191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1306191783Srmacklem if (compare) { 1307191783Srmacklem if (!(*retcmpp)) { 1308191783Srmacklem if (fsp->fs_maxname != 1309191783Srmacklem fxdr_unsigned(u_int32_t, *tl)) 1310191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1311191783Srmacklem } 1312191783Srmacklem } else { 1313191783Srmacklem tuint = fxdr_unsigned(u_int32_t, *tl); 1314191783Srmacklem /* 1315191783Srmacklem * Some Linux NFSv4 servers report this 1316191783Srmacklem * as 0 or 4billion, so I'll set it to 1317191783Srmacklem * NFS_MAXNAMLEN. If a server actually creates 1318191783Srmacklem * a name longer than NFS_MAXNAMLEN, it will 1319191783Srmacklem * get an error back. 1320191783Srmacklem */ 1321191783Srmacklem if (tuint == 0 || tuint > NFS_MAXNAMLEN) 1322191783Srmacklem tuint = NFS_MAXNAMLEN; 1323191783Srmacklem if (fsp != NULL) 1324191783Srmacklem fsp->fs_maxname = tuint; 1325191783Srmacklem if (pc != NULL) 1326191783Srmacklem pc->pc_namemax = tuint; 1327191783Srmacklem } 1328191783Srmacklem attrsum += NFSX_UNSIGNED; 1329191783Srmacklem break; 1330191783Srmacklem case NFSATTRBIT_MAXREAD: 1331191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1332191783Srmacklem if (compare) { 1333191783Srmacklem if (!(*retcmpp)) { 1334191783Srmacklem if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t, 1335191783Srmacklem *(tl + 1)) || *tl != 0) 1336191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1337191783Srmacklem } 1338191783Srmacklem } else if (fsp != NULL) { 1339191783Srmacklem fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl); 1340191783Srmacklem fsp->fs_rtpref = fsp->fs_rtmax; 1341191783Srmacklem fsp->fs_dtpref = fsp->fs_rtpref; 1342191783Srmacklem } 1343191783Srmacklem attrsum += NFSX_HYPER; 1344191783Srmacklem break; 1345191783Srmacklem case NFSATTRBIT_MAXWRITE: 1346191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1347191783Srmacklem if (compare) { 1348191783Srmacklem if (!(*retcmpp)) { 1349191783Srmacklem if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t, 1350191783Srmacklem *(tl + 1)) || *tl != 0) 1351191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1352191783Srmacklem } 1353191783Srmacklem } else if (fsp != NULL) { 1354191783Srmacklem fsp->fs_wtmax = fxdr_unsigned(int, *++tl); 1355191783Srmacklem fsp->fs_wtpref = fsp->fs_wtmax; 1356191783Srmacklem } 1357191783Srmacklem attrsum += NFSX_HYPER; 1358191783Srmacklem break; 1359191783Srmacklem case NFSATTRBIT_MIMETYPE: 1360191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1361191783Srmacklem i = fxdr_unsigned(int, *tl); 1362191783Srmacklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); 1363191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 1364191783Srmacklem if (error) 1365191783Srmacklem goto nfsmout; 1366191783Srmacklem if (compare && !(*retcmpp)) 1367191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1368191783Srmacklem break; 1369191783Srmacklem case NFSATTRBIT_MODE: 1370191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1371191783Srmacklem if (compare) { 1372191783Srmacklem if (!(*retcmpp)) { 1373191783Srmacklem if (nap->na_mode != nfstov_mode(*tl)) 1374191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1375191783Srmacklem } 1376191783Srmacklem } else if (nap != NULL) { 1377191783Srmacklem nap->na_mode = nfstov_mode(*tl); 1378191783Srmacklem } 1379191783Srmacklem attrsum += NFSX_UNSIGNED; 1380191783Srmacklem break; 1381191783Srmacklem case NFSATTRBIT_NOTRUNC: 1382191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1383191783Srmacklem if (compare) { 1384191783Srmacklem if (!(*retcmpp)) { 1385191783Srmacklem if (*tl != newnfs_true) 1386191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1387191783Srmacklem } 1388191783Srmacklem } else if (pc != NULL) { 1389191783Srmacklem pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl); 1390191783Srmacklem } 1391191783Srmacklem attrsum += NFSX_UNSIGNED; 1392191783Srmacklem break; 1393191783Srmacklem case NFSATTRBIT_NUMLINKS: 1394191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1395191783Srmacklem tuint = fxdr_unsigned(u_int32_t, *tl); 1396191783Srmacklem if (compare) { 1397191783Srmacklem if (!(*retcmpp)) { 1398191783Srmacklem if ((u_int32_t)nap->na_nlink != tuint) 1399191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1400191783Srmacklem } 1401191783Srmacklem } else if (nap != NULL) { 1402191783Srmacklem nap->na_nlink = tuint; 1403191783Srmacklem } 1404191783Srmacklem attrsum += NFSX_UNSIGNED; 1405191783Srmacklem break; 1406191783Srmacklem case NFSATTRBIT_OWNER: 1407191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1408191783Srmacklem j = fxdr_unsigned(int, *tl); 1409224086Szack if (j < 0) { 1410224086Szack error = NFSERR_BADXDR; 1411224086Szack goto nfsmout; 1412224086Szack } 1413191783Srmacklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1414191783Srmacklem if (j > NFSV4_SMALLSTR) 1415191783Srmacklem cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1416191783Srmacklem else 1417191783Srmacklem cp = namestr; 1418191783Srmacklem error = nfsrv_mtostr(nd, cp, j); 1419191783Srmacklem if (error) { 1420191783Srmacklem if (j > NFSV4_SMALLSTR) 1421191783Srmacklem free(cp, M_NFSSTRING); 1422224086Szack goto nfsmout; 1423191783Srmacklem } 1424191783Srmacklem if (compare) { 1425191783Srmacklem if (!(*retcmpp)) { 1426240720Srmacklem if (nfsv4_strtouid(nd, cp, j, &uid, p) || 1427191783Srmacklem nap->na_uid != uid) 1428191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1429191783Srmacklem } 1430191783Srmacklem } else if (nap != NULL) { 1431240720Srmacklem if (nfsv4_strtouid(nd, cp, j, &uid, p)) 1432191783Srmacklem nap->na_uid = nfsrv_defaultuid; 1433191783Srmacklem else 1434191783Srmacklem nap->na_uid = uid; 1435191783Srmacklem } 1436191783Srmacklem if (j > NFSV4_SMALLSTR) 1437191783Srmacklem free(cp, M_NFSSTRING); 1438191783Srmacklem break; 1439191783Srmacklem case NFSATTRBIT_OWNERGROUP: 1440191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1441191783Srmacklem j = fxdr_unsigned(int, *tl); 1442224086Szack if (j < 0) { 1443224086Szack error = NFSERR_BADXDR; 1444224086Szack goto nfsmout; 1445224086Szack } 1446191783Srmacklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1447191783Srmacklem if (j > NFSV4_SMALLSTR) 1448191783Srmacklem cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1449191783Srmacklem else 1450191783Srmacklem cp = namestr; 1451191783Srmacklem error = nfsrv_mtostr(nd, cp, j); 1452191783Srmacklem if (error) { 1453191783Srmacklem if (j > NFSV4_SMALLSTR) 1454191783Srmacklem free(cp, M_NFSSTRING); 1455224086Szack goto nfsmout; 1456191783Srmacklem } 1457191783Srmacklem if (compare) { 1458191783Srmacklem if (!(*retcmpp)) { 1459240720Srmacklem if (nfsv4_strtogid(nd, cp, j, &gid, p) || 1460191783Srmacklem nap->na_gid != gid) 1461191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1462191783Srmacklem } 1463191783Srmacklem } else if (nap != NULL) { 1464240720Srmacklem if (nfsv4_strtogid(nd, cp, j, &gid, p)) 1465191783Srmacklem nap->na_gid = nfsrv_defaultgid; 1466191783Srmacklem else 1467191783Srmacklem nap->na_gid = gid; 1468191783Srmacklem } 1469191783Srmacklem if (j > NFSV4_SMALLSTR) 1470191783Srmacklem free(cp, M_NFSSTRING); 1471191783Srmacklem break; 1472191783Srmacklem case NFSATTRBIT_QUOTAHARD: 1473191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1474191783Srmacklem if (sbp != NULL) { 1475191783Srmacklem if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1476191783Srmacklem freenum = sbp->f_bfree; 1477191783Srmacklem else 1478191783Srmacklem freenum = sbp->f_bavail; 1479191783Srmacklem#ifdef QUOTA 1480191783Srmacklem /* 1481191783Srmacklem * ufs_quotactl() insists that the uid argument 1482191783Srmacklem * equal p_ruid for non-root quota access, so 1483191783Srmacklem * we'll just make sure that's the case. 1484191783Srmacklem */ 1485191783Srmacklem savuid = p->p_cred->p_ruid; 1486191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 1487191783Srmacklem if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1488191990Sattilio USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1489191783Srmacklem freenum = min(dqb.dqb_bhardlimit, freenum); 1490191783Srmacklem p->p_cred->p_ruid = savuid; 1491191783Srmacklem#endif /* QUOTA */ 1492191783Srmacklem uquad = (u_int64_t)freenum; 1493191783Srmacklem NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1494191783Srmacklem } 1495191783Srmacklem if (compare && !(*retcmpp)) { 1496191783Srmacklem if (uquad != fxdr_hyper(tl)) 1497191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1498191783Srmacklem } 1499191783Srmacklem attrsum += NFSX_HYPER; 1500191783Srmacklem break; 1501191783Srmacklem case NFSATTRBIT_QUOTASOFT: 1502191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1503191783Srmacklem if (sbp != NULL) { 1504191783Srmacklem if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1505191783Srmacklem freenum = sbp->f_bfree; 1506191783Srmacklem else 1507191783Srmacklem freenum = sbp->f_bavail; 1508191783Srmacklem#ifdef QUOTA 1509191783Srmacklem /* 1510191783Srmacklem * ufs_quotactl() insists that the uid argument 1511191783Srmacklem * equal p_ruid for non-root quota access, so 1512191783Srmacklem * we'll just make sure that's the case. 1513191783Srmacklem */ 1514191783Srmacklem savuid = p->p_cred->p_ruid; 1515191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 1516191783Srmacklem if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1517191990Sattilio USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1518191783Srmacklem freenum = min(dqb.dqb_bsoftlimit, freenum); 1519191783Srmacklem p->p_cred->p_ruid = savuid; 1520191783Srmacklem#endif /* QUOTA */ 1521191783Srmacklem uquad = (u_int64_t)freenum; 1522191783Srmacklem NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1523191783Srmacklem } 1524191783Srmacklem if (compare && !(*retcmpp)) { 1525191783Srmacklem if (uquad != fxdr_hyper(tl)) 1526191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1527191783Srmacklem } 1528191783Srmacklem attrsum += NFSX_HYPER; 1529191783Srmacklem break; 1530191783Srmacklem case NFSATTRBIT_QUOTAUSED: 1531191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1532191783Srmacklem if (sbp != NULL) { 1533191783Srmacklem freenum = 0; 1534191783Srmacklem#ifdef QUOTA 1535191783Srmacklem /* 1536191783Srmacklem * ufs_quotactl() insists that the uid argument 1537191783Srmacklem * equal p_ruid for non-root quota access, so 1538191783Srmacklem * we'll just make sure that's the case. 1539191783Srmacklem */ 1540191783Srmacklem savuid = p->p_cred->p_ruid; 1541191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 1542191783Srmacklem if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1543191990Sattilio USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1544191783Srmacklem freenum = dqb.dqb_curblocks; 1545191783Srmacklem p->p_cred->p_ruid = savuid; 1546191783Srmacklem#endif /* QUOTA */ 1547191783Srmacklem uquad = (u_int64_t)freenum; 1548191783Srmacklem NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1549191783Srmacklem } 1550191783Srmacklem if (compare && !(*retcmpp)) { 1551191783Srmacklem if (uquad != fxdr_hyper(tl)) 1552191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1553191783Srmacklem } 1554191783Srmacklem attrsum += NFSX_HYPER; 1555191783Srmacklem break; 1556191783Srmacklem case NFSATTRBIT_RAWDEV: 1557191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA); 1558191783Srmacklem j = fxdr_unsigned(int, *tl++); 1559191783Srmacklem k = fxdr_unsigned(int, *tl); 1560191783Srmacklem if (compare) { 1561191783Srmacklem if (!(*retcmpp)) { 1562191783Srmacklem if (nap->na_rdev != NFSMAKEDEV(j, k)) 1563191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1564191783Srmacklem } 1565191783Srmacklem } else if (nap != NULL) { 1566191783Srmacklem nap->na_rdev = NFSMAKEDEV(j, k); 1567191783Srmacklem } 1568191783Srmacklem attrsum += NFSX_V4SPECDATA; 1569191783Srmacklem break; 1570191783Srmacklem case NFSATTRBIT_SPACEAVAIL: 1571191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1572191783Srmacklem if (compare) { 1573191783Srmacklem if (!(*retcmpp) && 1574191783Srmacklem sfp->sf_abytes != fxdr_hyper(tl)) 1575191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1576191783Srmacklem } else if (sfp != NULL) { 1577191783Srmacklem sfp->sf_abytes = fxdr_hyper(tl); 1578191783Srmacklem } 1579191783Srmacklem attrsum += NFSX_HYPER; 1580191783Srmacklem break; 1581191783Srmacklem case NFSATTRBIT_SPACEFREE: 1582191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1583191783Srmacklem if (compare) { 1584191783Srmacklem if (!(*retcmpp) && 1585191783Srmacklem sfp->sf_fbytes != fxdr_hyper(tl)) 1586191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1587191783Srmacklem } else if (sfp != NULL) { 1588191783Srmacklem sfp->sf_fbytes = fxdr_hyper(tl); 1589191783Srmacklem } 1590191783Srmacklem attrsum += NFSX_HYPER; 1591191783Srmacklem break; 1592191783Srmacklem case NFSATTRBIT_SPACETOTAL: 1593191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1594191783Srmacklem if (compare) { 1595191783Srmacklem if (!(*retcmpp) && 1596191783Srmacklem sfp->sf_tbytes != fxdr_hyper(tl)) 1597191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1598191783Srmacklem } else if (sfp != NULL) { 1599191783Srmacklem sfp->sf_tbytes = fxdr_hyper(tl); 1600191783Srmacklem } 1601191783Srmacklem attrsum += NFSX_HYPER; 1602191783Srmacklem break; 1603191783Srmacklem case NFSATTRBIT_SPACEUSED: 1604191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1605191783Srmacklem thyp = fxdr_hyper(tl); 1606191783Srmacklem if (compare) { 1607191783Srmacklem if (!(*retcmpp)) { 1608191783Srmacklem if ((u_int64_t)nap->na_bytes != thyp) 1609191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1610191783Srmacklem } 1611191783Srmacklem } else if (nap != NULL) { 1612191783Srmacklem nap->na_bytes = thyp; 1613191783Srmacklem } 1614191783Srmacklem attrsum += NFSX_HYPER; 1615191783Srmacklem break; 1616191783Srmacklem case NFSATTRBIT_SYSTEM: 1617191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1618191783Srmacklem if (compare && !(*retcmpp)) 1619191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1620191783Srmacklem attrsum += NFSX_UNSIGNED; 1621191783Srmacklem break; 1622191783Srmacklem case NFSATTRBIT_TIMEACCESS: 1623191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1624191783Srmacklem fxdr_nfsv4time(tl, &temptime); 1625191783Srmacklem if (compare) { 1626191783Srmacklem if (!(*retcmpp)) { 1627191783Srmacklem if (!NFS_CMPTIME(temptime, nap->na_atime)) 1628191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1629191783Srmacklem } 1630191783Srmacklem } else if (nap != NULL) { 1631191783Srmacklem nap->na_atime = temptime; 1632191783Srmacklem } 1633191783Srmacklem attrsum += NFSX_V4TIME; 1634191783Srmacklem break; 1635191783Srmacklem case NFSATTRBIT_TIMEACCESSSET: 1636191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1637191783Srmacklem attrsum += NFSX_UNSIGNED; 1638191783Srmacklem i = fxdr_unsigned(int, *tl); 1639191783Srmacklem if (i == NFSV4SATTRTIME_TOCLIENT) { 1640191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1641191783Srmacklem attrsum += NFSX_V4TIME; 1642191783Srmacklem } 1643191783Srmacklem if (compare && !(*retcmpp)) 1644191783Srmacklem *retcmpp = NFSERR_INVAL; 1645191783Srmacklem break; 1646191783Srmacklem case NFSATTRBIT_TIMEBACKUP: 1647191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1648191783Srmacklem if (compare && !(*retcmpp)) 1649191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1650191783Srmacklem attrsum += NFSX_V4TIME; 1651191783Srmacklem break; 1652191783Srmacklem case NFSATTRBIT_TIMECREATE: 1653191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1654191783Srmacklem if (compare && !(*retcmpp)) 1655191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1656191783Srmacklem attrsum += NFSX_V4TIME; 1657191783Srmacklem break; 1658191783Srmacklem case NFSATTRBIT_TIMEDELTA: 1659191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1660191783Srmacklem if (fsp != NULL) { 1661191783Srmacklem if (compare) { 1662191783Srmacklem if (!(*retcmpp)) { 1663191783Srmacklem if ((u_int32_t)fsp->fs_timedelta.tv_sec != 1664191783Srmacklem fxdr_unsigned(u_int32_t, *(tl + 1)) || 1665191783Srmacklem (u_int32_t)fsp->fs_timedelta.tv_nsec != 1666191783Srmacklem (fxdr_unsigned(u_int32_t, *(tl + 2)) % 1667191783Srmacklem 1000000000) || 1668191783Srmacklem *tl != 0) 1669191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1670191783Srmacklem } 1671191783Srmacklem } else { 1672191783Srmacklem fxdr_nfsv4time(tl, &fsp->fs_timedelta); 1673191783Srmacklem } 1674191783Srmacklem } 1675191783Srmacklem attrsum += NFSX_V4TIME; 1676191783Srmacklem break; 1677191783Srmacklem case NFSATTRBIT_TIMEMETADATA: 1678191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1679191783Srmacklem fxdr_nfsv4time(tl, &temptime); 1680191783Srmacklem if (compare) { 1681191783Srmacklem if (!(*retcmpp)) { 1682191783Srmacklem if (!NFS_CMPTIME(temptime, nap->na_ctime)) 1683191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1684191783Srmacklem } 1685191783Srmacklem } else if (nap != NULL) { 1686191783Srmacklem nap->na_ctime = temptime; 1687191783Srmacklem } 1688191783Srmacklem attrsum += NFSX_V4TIME; 1689191783Srmacklem break; 1690191783Srmacklem case NFSATTRBIT_TIMEMODIFY: 1691191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1692191783Srmacklem fxdr_nfsv4time(tl, &temptime); 1693191783Srmacklem if (compare) { 1694191783Srmacklem if (!(*retcmpp)) { 1695191783Srmacklem if (!NFS_CMPTIME(temptime, nap->na_mtime)) 1696191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1697191783Srmacklem } 1698191783Srmacklem } else if (nap != NULL) { 1699191783Srmacklem nap->na_mtime = temptime; 1700191783Srmacklem } 1701191783Srmacklem attrsum += NFSX_V4TIME; 1702191783Srmacklem break; 1703191783Srmacklem case NFSATTRBIT_TIMEMODIFYSET: 1704191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1705191783Srmacklem attrsum += NFSX_UNSIGNED; 1706191783Srmacklem i = fxdr_unsigned(int, *tl); 1707191783Srmacklem if (i == NFSV4SATTRTIME_TOCLIENT) { 1708191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1709191783Srmacklem attrsum += NFSX_V4TIME; 1710191783Srmacklem } 1711191783Srmacklem if (compare && !(*retcmpp)) 1712191783Srmacklem *retcmpp = NFSERR_INVAL; 1713191783Srmacklem break; 1714191783Srmacklem case NFSATTRBIT_MOUNTEDONFILEID: 1715191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1716191783Srmacklem thyp = fxdr_hyper(tl); 1717191783Srmacklem if (compare) { 1718191783Srmacklem if (!(*retcmpp)) { 1719191783Srmacklem if (*tl++) { 1720191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1721191783Srmacklem } else { 1722191783Srmacklem if (!vp || !nfsrv_atroot(vp, &fid)) 1723191783Srmacklem fid = nap->na_fileid; 1724191783Srmacklem if ((u_int64_t)fid != thyp) 1725191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1726191783Srmacklem } 1727191783Srmacklem } 1728191783Srmacklem } else if (nap != NULL) { 1729191783Srmacklem if (*tl++) 1730191783Srmacklem printf("NFSv4 mounted on fileid > 32bits\n"); 1731191783Srmacklem nap->na_mntonfileno = thyp; 1732191783Srmacklem } 1733191783Srmacklem attrsum += NFSX_HYPER; 1734191783Srmacklem break; 1735191783Srmacklem default: 1736191783Srmacklem printf("EEK! nfsv4_loadattr unknown attr=%d\n", 1737191783Srmacklem bitpos); 1738191783Srmacklem if (compare && !(*retcmpp)) 1739191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1740191783Srmacklem /* 1741191783Srmacklem * and get out of the loop, since we can't parse 1742191783Srmacklem * the unknown attrbute data. 1743191783Srmacklem */ 1744191783Srmacklem bitpos = NFSATTRBIT_MAX; 1745191783Srmacklem break; 1746191783Srmacklem }; 1747191783Srmacklem } 1748191783Srmacklem 1749191783Srmacklem /* 1750191783Srmacklem * some clients pad the attrlist, so we need to skip over the 1751191783Srmacklem * padding. 1752191783Srmacklem */ 1753191783Srmacklem if (attrsum > attrsize) { 1754191783Srmacklem error = NFSERR_BADXDR; 1755191783Srmacklem } else { 1756191783Srmacklem attrsize = NFSM_RNDUP(attrsize); 1757191783Srmacklem if (attrsum < attrsize) 1758191783Srmacklem error = nfsm_advance(nd, attrsize - attrsum, -1); 1759191783Srmacklem } 1760191783Srmacklemnfsmout: 1761224086Szack NFSEXITCODE2(error, nd); 1762191783Srmacklem return (error); 1763191783Srmacklem} 1764191783Srmacklem 1765191783Srmacklem/* 1766191783Srmacklem * Implement sleep locks for newnfs. The nfslock_usecnt allows for a 1767191783Srmacklem * shared lock and the NFSXXX_LOCK flag permits an exclusive lock. 1768191783Srmacklem * The first argument is a pointer to an nfsv4lock structure. 1769191783Srmacklem * The second argument is 1 iff a blocking lock is wanted. 1770191783Srmacklem * If this argument is 0, the call waits until no thread either wants nor 1771191783Srmacklem * holds an exclusive lock. 1772191783Srmacklem * It returns 1 if the lock was acquired, 0 otherwise. 1773191783Srmacklem * If several processes call this function concurrently wanting the exclusive 1774191783Srmacklem * lock, one will get the lock and the rest will return without getting the 1775191783Srmacklem * lock. (If the caller must have the lock, it simply calls this function in a 1776191783Srmacklem * loop until the function returns 1 to indicate the lock was acquired.) 1777191783Srmacklem * Any usecnt must be decremented by calling nfsv4_relref() before 1778191783Srmacklem * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could 1779191783Srmacklem * be called in a loop. 1780222389Srmacklem * The isleptp argument is set to indicate if the call slept, iff not NULL 1781222389Srmacklem * and the mp argument indicates to check for a forced dismount, iff not 1782222389Srmacklem * NULL. 1783191783Srmacklem */ 1784191783SrmacklemAPPLESTATIC int 1785191783Srmacklemnfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp, 1786222389Srmacklem void *mutex, struct mount *mp) 1787191783Srmacklem{ 1788191783Srmacklem 1789191783Srmacklem if (isleptp) 1790191783Srmacklem *isleptp = 0; 1791191783Srmacklem /* 1792191783Srmacklem * If a lock is wanted, loop around until the lock is acquired by 1793191783Srmacklem * someone and then released. If I want the lock, try to acquire it. 1794191783Srmacklem * For a lock to be issued, no lock must be in force and the usecnt 1795191783Srmacklem * must be zero. 1796191783Srmacklem */ 1797191783Srmacklem if (iwantlock) { 1798191783Srmacklem if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1799191783Srmacklem lp->nfslock_usecnt == 0) { 1800191783Srmacklem lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1801191783Srmacklem lp->nfslock_lock |= NFSV4LOCK_LOCK; 1802191783Srmacklem return (1); 1803191783Srmacklem } 1804191783Srmacklem lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED; 1805191783Srmacklem } 1806191783Srmacklem while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) { 1807222389Srmacklem if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1808222389Srmacklem lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1809222389Srmacklem return (0); 1810222389Srmacklem } 1811191783Srmacklem lp->nfslock_lock |= NFSV4LOCK_WANTED; 1812191783Srmacklem if (isleptp) 1813191783Srmacklem *isleptp = 1; 1814191783Srmacklem (void) nfsmsleep(&lp->nfslock_lock, mutex, 1815191783Srmacklem PZERO - 1, "nfsv4lck", NULL); 1816191783Srmacklem if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1817191783Srmacklem lp->nfslock_usecnt == 0) { 1818191783Srmacklem lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1819191783Srmacklem lp->nfslock_lock |= NFSV4LOCK_LOCK; 1820191783Srmacklem return (1); 1821191783Srmacklem } 1822191783Srmacklem } 1823191783Srmacklem return (0); 1824191783Srmacklem} 1825191783Srmacklem 1826191783Srmacklem/* 1827191783Srmacklem * Release the lock acquired by nfsv4_lock(). 1828191783Srmacklem * The second argument is set to 1 to indicate the nfslock_usecnt should be 1829191783Srmacklem * incremented, as well. 1830191783Srmacklem */ 1831191783SrmacklemAPPLESTATIC void 1832191783Srmacklemnfsv4_unlock(struct nfsv4lock *lp, int incref) 1833191783Srmacklem{ 1834191783Srmacklem 1835191783Srmacklem lp->nfslock_lock &= ~NFSV4LOCK_LOCK; 1836191783Srmacklem if (incref) 1837191783Srmacklem lp->nfslock_usecnt++; 1838191783Srmacklem nfsv4_wanted(lp); 1839191783Srmacklem} 1840191783Srmacklem 1841191783Srmacklem/* 1842191783Srmacklem * Release a reference cnt. 1843191783Srmacklem */ 1844191783SrmacklemAPPLESTATIC void 1845191783Srmacklemnfsv4_relref(struct nfsv4lock *lp) 1846191783Srmacklem{ 1847191783Srmacklem 1848191783Srmacklem if (lp->nfslock_usecnt <= 0) 1849191783Srmacklem panic("nfsv4root ref cnt"); 1850191783Srmacklem lp->nfslock_usecnt--; 1851191783Srmacklem if (lp->nfslock_usecnt == 0) 1852191783Srmacklem nfsv4_wanted(lp); 1853191783Srmacklem} 1854191783Srmacklem 1855191783Srmacklem/* 1856191783Srmacklem * Get a reference cnt. 1857191783Srmacklem * This function will wait for any exclusive lock to be released, but will 1858191783Srmacklem * not wait for threads that want the exclusive lock. If priority needs 1859191783Srmacklem * to be given to threads that need the exclusive lock, a call to nfsv4_lock() 1860191783Srmacklem * with the 2nd argument == 0 should be done before calling nfsv4_getref(). 1861222389Srmacklem * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and 1862222389Srmacklem * return without getting a refcnt for that case. 1863191783Srmacklem */ 1864191783SrmacklemAPPLESTATIC void 1865222389Srmacklemnfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex, 1866222389Srmacklem struct mount *mp) 1867191783Srmacklem{ 1868191783Srmacklem 1869191783Srmacklem if (isleptp) 1870191783Srmacklem *isleptp = 0; 1871191783Srmacklem 1872191783Srmacklem /* 1873191783Srmacklem * Wait for a lock held. 1874191783Srmacklem */ 1875191783Srmacklem while (lp->nfslock_lock & NFSV4LOCK_LOCK) { 1876222389Srmacklem if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1877222389Srmacklem return; 1878191783Srmacklem lp->nfslock_lock |= NFSV4LOCK_WANTED; 1879191783Srmacklem if (isleptp) 1880191783Srmacklem *isleptp = 1; 1881191783Srmacklem (void) nfsmsleep(&lp->nfslock_lock, mutex, 1882244042Srmacklem PZERO - 1, "nfsv4gr", NULL); 1883191783Srmacklem } 1884222389Srmacklem if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1885222389Srmacklem return; 1886191783Srmacklem 1887191783Srmacklem lp->nfslock_usecnt++; 1888191783Srmacklem} 1889191783Srmacklem 1890191783Srmacklem/* 1891211951Srmacklem * Get a reference as above, but return failure instead of sleeping if 1892211951Srmacklem * an exclusive lock is held. 1893211951Srmacklem */ 1894211951SrmacklemAPPLESTATIC int 1895211951Srmacklemnfsv4_getref_nonblock(struct nfsv4lock *lp) 1896211951Srmacklem{ 1897211951Srmacklem 1898211951Srmacklem if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0) 1899211951Srmacklem return (0); 1900211951Srmacklem 1901211951Srmacklem lp->nfslock_usecnt++; 1902211951Srmacklem return (1); 1903211951Srmacklem} 1904211951Srmacklem 1905211951Srmacklem/* 1906205941Srmacklem * Test for a lock. Return 1 if locked, 0 otherwise. 1907205941Srmacklem */ 1908205941SrmacklemAPPLESTATIC int 1909205941Srmacklemnfsv4_testlock(struct nfsv4lock *lp) 1910205941Srmacklem{ 1911205941Srmacklem 1912205941Srmacklem if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 && 1913205941Srmacklem lp->nfslock_usecnt == 0) 1914205941Srmacklem return (0); 1915205941Srmacklem return (1); 1916205941Srmacklem} 1917205941Srmacklem 1918205941Srmacklem/* 1919191783Srmacklem * Wake up anyone sleeping, waiting for this lock. 1920191783Srmacklem */ 1921191783Srmacklemstatic void 1922191783Srmacklemnfsv4_wanted(struct nfsv4lock *lp) 1923191783Srmacklem{ 1924191783Srmacklem 1925191783Srmacklem if (lp->nfslock_lock & NFSV4LOCK_WANTED) { 1926191783Srmacklem lp->nfslock_lock &= ~NFSV4LOCK_WANTED; 1927191783Srmacklem wakeup((caddr_t)&lp->nfslock_lock); 1928191783Srmacklem } 1929191783Srmacklem} 1930191783Srmacklem 1931191783Srmacklem/* 1932191783Srmacklem * Copy a string from an mbuf list into a character array. 1933191783Srmacklem * Return EBADRPC if there is an mbuf error, 1934191783Srmacklem * 0 otherwise. 1935191783Srmacklem */ 1936191783SrmacklemAPPLESTATIC int 1937191783Srmacklemnfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) 1938191783Srmacklem{ 1939191783Srmacklem char *cp; 1940191783Srmacklem int xfer, len; 1941191783Srmacklem mbuf_t mp; 1942191783Srmacklem int rem, error = 0; 1943191783Srmacklem 1944191783Srmacklem mp = nd->nd_md; 1945191783Srmacklem cp = nd->nd_dpos; 1946191783Srmacklem len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp; 1947191783Srmacklem rem = NFSM_RNDUP(siz) - siz; 1948191783Srmacklem while (siz > 0) { 1949191783Srmacklem if (len > siz) 1950191783Srmacklem xfer = siz; 1951191783Srmacklem else 1952191783Srmacklem xfer = len; 1953191783Srmacklem NFSBCOPY(cp, str, xfer); 1954191783Srmacklem str += xfer; 1955191783Srmacklem siz -= xfer; 1956191783Srmacklem if (siz > 0) { 1957191783Srmacklem mp = mbuf_next(mp); 1958224086Szack if (mp == NULL) { 1959224086Szack error = EBADRPC; 1960224086Szack goto out; 1961224086Szack } 1962191783Srmacklem cp = NFSMTOD(mp, caddr_t); 1963191783Srmacklem len = mbuf_len(mp); 1964191783Srmacklem } else { 1965191783Srmacklem cp += xfer; 1966191783Srmacklem len -= xfer; 1967191783Srmacklem } 1968191783Srmacklem } 1969191783Srmacklem *str = '\0'; 1970191783Srmacklem nd->nd_dpos = cp; 1971191783Srmacklem nd->nd_md = mp; 1972191783Srmacklem if (rem > 0) { 1973191783Srmacklem if (len < rem) 1974191783Srmacklem error = nfsm_advance(nd, rem, len); 1975191783Srmacklem else 1976191783Srmacklem nd->nd_dpos += rem; 1977191783Srmacklem } 1978224086Szack 1979224086Szackout: 1980224086Szack NFSEXITCODE2(error, nd); 1981191783Srmacklem return (error); 1982191783Srmacklem} 1983191783Srmacklem 1984191783Srmacklem/* 1985191783Srmacklem * Fill in the attributes as marked by the bitmap (V4). 1986191783Srmacklem */ 1987191783SrmacklemAPPLESTATIC int 1988220645Srmacklemnfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, 1989220645Srmacklem NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror, 1990220645Srmacklem nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram, 1991220648Srmacklem int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno) 1992191783Srmacklem{ 1993191783Srmacklem int bitpos, retnum = 0; 1994191783Srmacklem u_int32_t *tl; 1995191783Srmacklem int siz, prefixnum, error; 1996191783Srmacklem u_char *cp, namestr[NFSV4_SMALLSTR]; 1997191783Srmacklem nfsattrbit_t attrbits, retbits; 1998191783Srmacklem nfsattrbit_t *retbitp = &retbits; 1999191783Srmacklem u_int32_t freenum, *retnump; 2000191783Srmacklem u_int64_t uquad; 2001191783Srmacklem struct statfs fs; 2002191783Srmacklem struct nfsfsinfo fsinf; 2003191783Srmacklem struct timespec temptime; 2004191783Srmacklem NFSACL_T *aclp, *naclp = NULL; 2005191783Srmacklem#ifdef QUOTA 2006191783Srmacklem struct dqblk dqb; 2007191783Srmacklem uid_t savuid; 2008191783Srmacklem#endif 2009191783Srmacklem 2010191783Srmacklem /* 2011191783Srmacklem * First, set the bits that can be filled and get fsinfo. 2012191783Srmacklem */ 2013191783Srmacklem NFSSET_ATTRBIT(retbitp, attrbitp); 2014191783Srmacklem /* If p and cred are NULL, it is a client side call */ 2015191783Srmacklem if (p == NULL && cred == NULL) { 2016191783Srmacklem NFSCLRNOTSETABLE_ATTRBIT(retbitp); 2017191783Srmacklem aclp = saclp; 2018191783Srmacklem } else { 2019191783Srmacklem NFSCLRNOTFILLABLE_ATTRBIT(retbitp); 2020192861Srmacklem naclp = acl_alloc(M_WAITOK); 2021191783Srmacklem aclp = naclp; 2022191783Srmacklem } 2023191783Srmacklem nfsvno_getfs(&fsinf, isdgram); 2024191783Srmacklem#ifndef APPLE 2025191783Srmacklem /* 2026191783Srmacklem * Get the VFS_STATFS(), since some attributes need them. 2027191783Srmacklem */ 2028191783Srmacklem if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 2029220645Srmacklem error = VFS_STATFS(mp, &fs); 2030191783Srmacklem if (error != 0) { 2031191783Srmacklem if (reterr) { 2032191783Srmacklem nd->nd_repstat = NFSERR_ACCES; 2033191783Srmacklem return (0); 2034191783Srmacklem } 2035191783Srmacklem NFSCLRSTATFS_ATTRBIT(retbitp); 2036191783Srmacklem } 2037191783Srmacklem } 2038191783Srmacklem#endif 2039191783Srmacklem 2040191783Srmacklem /* 2041191783Srmacklem * And the NFSv4 ACL... 2042191783Srmacklem */ 2043200069Strasz if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 2044200069Strasz (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2045220648Srmacklem supports_nfsv4acls == 0))) { 2046191783Srmacklem NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 2047191783Srmacklem } 2048191783Srmacklem if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 2049191783Srmacklem if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2050220648Srmacklem supports_nfsv4acls == 0)) { 2051191783Srmacklem NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2052191783Srmacklem } else if (naclp != NULL) { 2053224081Szack if (NFSVOPLOCK(vp, LK_SHARED) == 0) { 2054217535Srmacklem error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); 2055216700Srmacklem if (error == 0) 2056216700Srmacklem error = VOP_GETACL(vp, ACL_TYPE_NFS4, 2057216700Srmacklem naclp, cred, p); 2058224082Szack NFSVOPUNLOCK(vp, 0); 2059216700Srmacklem } else 2060216700Srmacklem error = NFSERR_PERM; 2061191783Srmacklem if (error != 0) { 2062191783Srmacklem if (reterr) { 2063191783Srmacklem nd->nd_repstat = NFSERR_ACCES; 2064191783Srmacklem return (0); 2065191783Srmacklem } 2066191783Srmacklem NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2067191783Srmacklem } 2068191783Srmacklem } 2069191783Srmacklem } 2070191783Srmacklem /* 2071191783Srmacklem * Put out the attribute bitmap for the ones being filled in 2072191783Srmacklem * and get the field for the number of attributes returned. 2073191783Srmacklem */ 2074191783Srmacklem prefixnum = nfsrv_putattrbit(nd, retbitp); 2075191783Srmacklem NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 2076191783Srmacklem prefixnum += NFSX_UNSIGNED; 2077191783Srmacklem 2078191783Srmacklem /* 2079191783Srmacklem * Now, loop around filling in the attributes for each bit set. 2080191783Srmacklem */ 2081191783Srmacklem for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 2082191783Srmacklem if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 2083191783Srmacklem switch (bitpos) { 2084191783Srmacklem case NFSATTRBIT_SUPPORTEDATTRS: 2085191783Srmacklem NFSSETSUPP_ATTRBIT(&attrbits); 2086191783Srmacklem if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 2087220648Srmacklem && supports_nfsv4acls == 0)) { 2088191783Srmacklem NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 2089191783Srmacklem NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 2090191783Srmacklem } 2091191783Srmacklem retnum += nfsrv_putattrbit(nd, &attrbits); 2092191783Srmacklem break; 2093191783Srmacklem case NFSATTRBIT_TYPE: 2094191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2095191783Srmacklem *tl = vtonfsv34_type(vap->va_type); 2096191783Srmacklem retnum += NFSX_UNSIGNED; 2097191783Srmacklem break; 2098191783Srmacklem case NFSATTRBIT_FHEXPIRETYPE: 2099191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2100191783Srmacklem *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2101191783Srmacklem retnum += NFSX_UNSIGNED; 2102191783Srmacklem break; 2103191783Srmacklem case NFSATTRBIT_CHANGE: 2104191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2105191783Srmacklem txdr_hyper(vap->va_filerev, tl); 2106191783Srmacklem retnum += NFSX_HYPER; 2107191783Srmacklem break; 2108191783Srmacklem case NFSATTRBIT_SIZE: 2109191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2110191783Srmacklem txdr_hyper(vap->va_size, tl); 2111191783Srmacklem retnum += NFSX_HYPER; 2112191783Srmacklem break; 2113191783Srmacklem case NFSATTRBIT_LINKSUPPORT: 2114191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2115191783Srmacklem if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2116191783Srmacklem *tl = newnfs_true; 2117191783Srmacklem else 2118191783Srmacklem *tl = newnfs_false; 2119191783Srmacklem retnum += NFSX_UNSIGNED; 2120191783Srmacklem break; 2121191783Srmacklem case NFSATTRBIT_SYMLINKSUPPORT: 2122191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2123191783Srmacklem if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2124191783Srmacklem *tl = newnfs_true; 2125191783Srmacklem else 2126191783Srmacklem *tl = newnfs_false; 2127191783Srmacklem retnum += NFSX_UNSIGNED; 2128191783Srmacklem break; 2129191783Srmacklem case NFSATTRBIT_NAMEDATTR: 2130191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2131191783Srmacklem *tl = newnfs_false; 2132191783Srmacklem retnum += NFSX_UNSIGNED; 2133191783Srmacklem break; 2134191783Srmacklem case NFSATTRBIT_FSID: 2135191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2136191783Srmacklem *tl++ = 0; 2137220645Srmacklem *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]); 2138191783Srmacklem *tl++ = 0; 2139220645Srmacklem *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]); 2140191783Srmacklem retnum += NFSX_V4FSID; 2141191783Srmacklem break; 2142191783Srmacklem case NFSATTRBIT_UNIQUEHANDLES: 2143191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2144191783Srmacklem *tl = newnfs_true; 2145191783Srmacklem retnum += NFSX_UNSIGNED; 2146191783Srmacklem break; 2147191783Srmacklem case NFSATTRBIT_LEASETIME: 2148191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2149191783Srmacklem *tl = txdr_unsigned(nfsrv_lease); 2150191783Srmacklem retnum += NFSX_UNSIGNED; 2151191783Srmacklem break; 2152191783Srmacklem case NFSATTRBIT_RDATTRERROR: 2153191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2154191783Srmacklem *tl = txdr_unsigned(rderror); 2155191783Srmacklem retnum += NFSX_UNSIGNED; 2156191783Srmacklem break; 2157191783Srmacklem /* 2158191783Srmacklem * Recommended Attributes. (Only the supported ones.) 2159191783Srmacklem */ 2160191783Srmacklem case NFSATTRBIT_ACL: 2161191783Srmacklem retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2162191783Srmacklem break; 2163191783Srmacklem case NFSATTRBIT_ACLSUPPORT: 2164191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2165191783Srmacklem *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2166191783Srmacklem retnum += NFSX_UNSIGNED; 2167191783Srmacklem break; 2168191783Srmacklem case NFSATTRBIT_CANSETTIME: 2169191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2170191783Srmacklem if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2171191783Srmacklem *tl = newnfs_true; 2172191783Srmacklem else 2173191783Srmacklem *tl = newnfs_false; 2174191783Srmacklem retnum += NFSX_UNSIGNED; 2175191783Srmacklem break; 2176191783Srmacklem case NFSATTRBIT_CASEINSENSITIVE: 2177191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2178191783Srmacklem *tl = newnfs_false; 2179191783Srmacklem retnum += NFSX_UNSIGNED; 2180191783Srmacklem break; 2181191783Srmacklem case NFSATTRBIT_CASEPRESERVING: 2182191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2183191783Srmacklem *tl = newnfs_true; 2184191783Srmacklem retnum += NFSX_UNSIGNED; 2185191783Srmacklem break; 2186191783Srmacklem case NFSATTRBIT_CHOWNRESTRICTED: 2187191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2188224121Szack *tl = newnfs_true; 2189191783Srmacklem retnum += NFSX_UNSIGNED; 2190191783Srmacklem break; 2191191783Srmacklem case NFSATTRBIT_FILEHANDLE: 2192191783Srmacklem retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2193191783Srmacklem break; 2194191783Srmacklem case NFSATTRBIT_FILEID: 2195191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2196191783Srmacklem *tl++ = 0; 2197191783Srmacklem *tl = txdr_unsigned(vap->va_fileid); 2198191783Srmacklem retnum += NFSX_HYPER; 2199191783Srmacklem break; 2200191783Srmacklem case NFSATTRBIT_FILESAVAIL: 2201191783Srmacklem /* 2202191783Srmacklem * Check quota and use min(quota, f_ffree). 2203191783Srmacklem */ 2204191783Srmacklem freenum = fs.f_ffree; 2205191783Srmacklem#ifdef QUOTA 2206191783Srmacklem /* 2207191783Srmacklem * ufs_quotactl() insists that the uid argument 2208191783Srmacklem * equal p_ruid for non-root quota access, so 2209191783Srmacklem * we'll just make sure that's the case. 2210191783Srmacklem */ 2211191783Srmacklem savuid = p->p_cred->p_ruid; 2212191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 2213220645Srmacklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2214191990Sattilio cred->cr_uid, (caddr_t)&dqb)) 2215191783Srmacklem freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2216191783Srmacklem freenum); 2217191783Srmacklem p->p_cred->p_ruid = savuid; 2218191783Srmacklem#endif /* QUOTA */ 2219191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2220191783Srmacklem *tl++ = 0; 2221191783Srmacklem *tl = txdr_unsigned(freenum); 2222191783Srmacklem retnum += NFSX_HYPER; 2223191783Srmacklem break; 2224191783Srmacklem case NFSATTRBIT_FILESFREE: 2225191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2226191783Srmacklem *tl++ = 0; 2227191783Srmacklem *tl = txdr_unsigned(fs.f_ffree); 2228191783Srmacklem retnum += NFSX_HYPER; 2229191783Srmacklem break; 2230191783Srmacklem case NFSATTRBIT_FILESTOTAL: 2231191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2232191783Srmacklem *tl++ = 0; 2233191783Srmacklem *tl = txdr_unsigned(fs.f_files); 2234191783Srmacklem retnum += NFSX_HYPER; 2235191783Srmacklem break; 2236191783Srmacklem case NFSATTRBIT_FSLOCATIONS: 2237191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2238191783Srmacklem *tl++ = 0; 2239191783Srmacklem *tl = 0; 2240191783Srmacklem retnum += 2 * NFSX_UNSIGNED; 2241191783Srmacklem break; 2242191783Srmacklem case NFSATTRBIT_HOMOGENEOUS: 2243191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2244191783Srmacklem if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2245191783Srmacklem *tl = newnfs_true; 2246191783Srmacklem else 2247191783Srmacklem *tl = newnfs_false; 2248191783Srmacklem retnum += NFSX_UNSIGNED; 2249191783Srmacklem break; 2250191783Srmacklem case NFSATTRBIT_MAXFILESIZE: 2251191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2252191783Srmacklem uquad = NFSRV_MAXFILESIZE; 2253191783Srmacklem txdr_hyper(uquad, tl); 2254191783Srmacklem retnum += NFSX_HYPER; 2255191783Srmacklem break; 2256191783Srmacklem case NFSATTRBIT_MAXLINK: 2257191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2258191783Srmacklem *tl = txdr_unsigned(LINK_MAX); 2259191783Srmacklem retnum += NFSX_UNSIGNED; 2260191783Srmacklem break; 2261191783Srmacklem case NFSATTRBIT_MAXNAME: 2262191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2263191783Srmacklem *tl = txdr_unsigned(NFS_MAXNAMLEN); 2264191783Srmacklem retnum += NFSX_UNSIGNED; 2265191783Srmacklem break; 2266191783Srmacklem case NFSATTRBIT_MAXREAD: 2267191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2268191783Srmacklem *tl++ = 0; 2269191783Srmacklem *tl = txdr_unsigned(fsinf.fs_rtmax); 2270191783Srmacklem retnum += NFSX_HYPER; 2271191783Srmacklem break; 2272191783Srmacklem case NFSATTRBIT_MAXWRITE: 2273191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2274191783Srmacklem *tl++ = 0; 2275191783Srmacklem *tl = txdr_unsigned(fsinf.fs_wtmax); 2276191783Srmacklem retnum += NFSX_HYPER; 2277191783Srmacklem break; 2278191783Srmacklem case NFSATTRBIT_MODE: 2279191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2280191783Srmacklem *tl = vtonfsv34_mode(vap->va_mode); 2281191783Srmacklem retnum += NFSX_UNSIGNED; 2282191783Srmacklem break; 2283191783Srmacklem case NFSATTRBIT_NOTRUNC: 2284191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2285191783Srmacklem *tl = newnfs_true; 2286191783Srmacklem retnum += NFSX_UNSIGNED; 2287191783Srmacklem break; 2288191783Srmacklem case NFSATTRBIT_NUMLINKS: 2289191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2290191783Srmacklem *tl = txdr_unsigned(vap->va_nlink); 2291191783Srmacklem retnum += NFSX_UNSIGNED; 2292191783Srmacklem break; 2293191783Srmacklem case NFSATTRBIT_OWNER: 2294191783Srmacklem cp = namestr; 2295191783Srmacklem nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); 2296191783Srmacklem retnum += nfsm_strtom(nd, cp, siz); 2297191783Srmacklem if (cp != namestr) 2298191783Srmacklem free(cp, M_NFSSTRING); 2299191783Srmacklem break; 2300191783Srmacklem case NFSATTRBIT_OWNERGROUP: 2301191783Srmacklem cp = namestr; 2302191783Srmacklem nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); 2303191783Srmacklem retnum += nfsm_strtom(nd, cp, siz); 2304191783Srmacklem if (cp != namestr) 2305191783Srmacklem free(cp, M_NFSSTRING); 2306191783Srmacklem break; 2307191783Srmacklem case NFSATTRBIT_QUOTAHARD: 2308191783Srmacklem if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2309191783Srmacklem freenum = fs.f_bfree; 2310191783Srmacklem else 2311191783Srmacklem freenum = fs.f_bavail; 2312191783Srmacklem#ifdef QUOTA 2313191783Srmacklem /* 2314191783Srmacklem * ufs_quotactl() insists that the uid argument 2315191783Srmacklem * equal p_ruid for non-root quota access, so 2316191783Srmacklem * we'll just make sure that's the case. 2317191783Srmacklem */ 2318191783Srmacklem savuid = p->p_cred->p_ruid; 2319191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 2320220645Srmacklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2321191990Sattilio cred->cr_uid, (caddr_t)&dqb)) 2322191783Srmacklem freenum = min(dqb.dqb_bhardlimit, freenum); 2323191783Srmacklem p->p_cred->p_ruid = savuid; 2324191783Srmacklem#endif /* QUOTA */ 2325191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2326191783Srmacklem uquad = (u_int64_t)freenum; 2327191783Srmacklem NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2328191783Srmacklem txdr_hyper(uquad, tl); 2329191783Srmacklem retnum += NFSX_HYPER; 2330191783Srmacklem break; 2331191783Srmacklem case NFSATTRBIT_QUOTASOFT: 2332191783Srmacklem if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2333191783Srmacklem freenum = fs.f_bfree; 2334191783Srmacklem else 2335191783Srmacklem freenum = fs.f_bavail; 2336191783Srmacklem#ifdef QUOTA 2337191783Srmacklem /* 2338191783Srmacklem * ufs_quotactl() insists that the uid argument 2339191783Srmacklem * equal p_ruid for non-root quota access, so 2340191783Srmacklem * we'll just make sure that's the case. 2341191783Srmacklem */ 2342191783Srmacklem savuid = p->p_cred->p_ruid; 2343191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 2344220645Srmacklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2345191990Sattilio cred->cr_uid, (caddr_t)&dqb)) 2346191783Srmacklem freenum = min(dqb.dqb_bsoftlimit, freenum); 2347191783Srmacklem p->p_cred->p_ruid = savuid; 2348191783Srmacklem#endif /* QUOTA */ 2349191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2350191783Srmacklem uquad = (u_int64_t)freenum; 2351191783Srmacklem NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2352191783Srmacklem txdr_hyper(uquad, tl); 2353191783Srmacklem retnum += NFSX_HYPER; 2354191783Srmacklem break; 2355191783Srmacklem case NFSATTRBIT_QUOTAUSED: 2356191783Srmacklem freenum = 0; 2357191783Srmacklem#ifdef QUOTA 2358191783Srmacklem /* 2359191783Srmacklem * ufs_quotactl() insists that the uid argument 2360191783Srmacklem * equal p_ruid for non-root quota access, so 2361191783Srmacklem * we'll just make sure that's the case. 2362191783Srmacklem */ 2363191783Srmacklem savuid = p->p_cred->p_ruid; 2364191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 2365220645Srmacklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2366191990Sattilio cred->cr_uid, (caddr_t)&dqb)) 2367191783Srmacklem freenum = dqb.dqb_curblocks; 2368191783Srmacklem p->p_cred->p_ruid = savuid; 2369191783Srmacklem#endif /* QUOTA */ 2370191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2371191783Srmacklem uquad = (u_int64_t)freenum; 2372191783Srmacklem NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2373191783Srmacklem txdr_hyper(uquad, tl); 2374191783Srmacklem retnum += NFSX_HYPER; 2375191783Srmacklem break; 2376191783Srmacklem case NFSATTRBIT_RAWDEV: 2377191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2378191783Srmacklem *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2379191783Srmacklem *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2380191783Srmacklem retnum += NFSX_V4SPECDATA; 2381191783Srmacklem break; 2382191783Srmacklem case NFSATTRBIT_SPACEAVAIL: 2383191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2384191783Srmacklem if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) 2385191783Srmacklem uquad = (u_int64_t)fs.f_bfree; 2386191783Srmacklem else 2387191783Srmacklem uquad = (u_int64_t)fs.f_bavail; 2388191783Srmacklem uquad *= fs.f_bsize; 2389191783Srmacklem txdr_hyper(uquad, tl); 2390191783Srmacklem retnum += NFSX_HYPER; 2391191783Srmacklem break; 2392191783Srmacklem case NFSATTRBIT_SPACEFREE: 2393191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2394191783Srmacklem uquad = (u_int64_t)fs.f_bfree; 2395191783Srmacklem uquad *= fs.f_bsize; 2396191783Srmacklem txdr_hyper(uquad, tl); 2397191783Srmacklem retnum += NFSX_HYPER; 2398191783Srmacklem break; 2399191783Srmacklem case NFSATTRBIT_SPACETOTAL: 2400191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2401191783Srmacklem uquad = (u_int64_t)fs.f_blocks; 2402191783Srmacklem uquad *= fs.f_bsize; 2403191783Srmacklem txdr_hyper(uquad, tl); 2404191783Srmacklem retnum += NFSX_HYPER; 2405191783Srmacklem break; 2406191783Srmacklem case NFSATTRBIT_SPACEUSED: 2407191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2408191783Srmacklem txdr_hyper(vap->va_bytes, tl); 2409191783Srmacklem retnum += NFSX_HYPER; 2410191783Srmacklem break; 2411191783Srmacklem case NFSATTRBIT_TIMEACCESS: 2412191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2413191783Srmacklem txdr_nfsv4time(&vap->va_atime, tl); 2414191783Srmacklem retnum += NFSX_V4TIME; 2415191783Srmacklem break; 2416191783Srmacklem case NFSATTRBIT_TIMEACCESSSET: 2417245508Sjhb if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2418191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2419191783Srmacklem *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2420191783Srmacklem txdr_nfsv4time(&vap->va_atime, tl); 2421191783Srmacklem retnum += NFSX_V4SETTIME; 2422191783Srmacklem } else { 2423191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2424191783Srmacklem *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2425191783Srmacklem retnum += NFSX_UNSIGNED; 2426191783Srmacklem } 2427191783Srmacklem break; 2428191783Srmacklem case NFSATTRBIT_TIMEDELTA: 2429191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2430191783Srmacklem temptime.tv_sec = 0; 2431191783Srmacklem temptime.tv_nsec = 1000000000 / hz; 2432191783Srmacklem txdr_nfsv4time(&temptime, tl); 2433191783Srmacklem retnum += NFSX_V4TIME; 2434191783Srmacklem break; 2435191783Srmacklem case NFSATTRBIT_TIMEMETADATA: 2436191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2437191783Srmacklem txdr_nfsv4time(&vap->va_ctime, tl); 2438191783Srmacklem retnum += NFSX_V4TIME; 2439191783Srmacklem break; 2440191783Srmacklem case NFSATTRBIT_TIMEMODIFY: 2441191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2442191783Srmacklem txdr_nfsv4time(&vap->va_mtime, tl); 2443191783Srmacklem retnum += NFSX_V4TIME; 2444191783Srmacklem break; 2445191783Srmacklem case NFSATTRBIT_TIMEMODIFYSET: 2446245508Sjhb if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2447191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2448191783Srmacklem *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2449191783Srmacklem txdr_nfsv4time(&vap->va_mtime, tl); 2450191783Srmacklem retnum += NFSX_V4SETTIME; 2451191783Srmacklem } else { 2452191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2453191783Srmacklem *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2454191783Srmacklem retnum += NFSX_UNSIGNED; 2455191783Srmacklem } 2456191783Srmacklem break; 2457191783Srmacklem case NFSATTRBIT_MOUNTEDONFILEID: 2458191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2459220645Srmacklem if (at_root != 0) 2460220645Srmacklem uquad = mounted_on_fileno; 2461191783Srmacklem else 2462220645Srmacklem uquad = (u_int64_t)vap->va_fileid; 2463220645Srmacklem txdr_hyper(uquad, tl); 2464191783Srmacklem retnum += NFSX_HYPER; 2465191783Srmacklem break; 2466191783Srmacklem default: 2467191783Srmacklem printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2468191783Srmacklem }; 2469191783Srmacklem } 2470191783Srmacklem } 2471191783Srmacklem if (naclp != NULL) 2472191783Srmacklem acl_free(naclp); 2473191783Srmacklem *retnump = txdr_unsigned(retnum); 2474191783Srmacklem return (retnum + prefixnum); 2475191783Srmacklem} 2476191783Srmacklem 2477191783Srmacklem/* 2478191783Srmacklem * Put the attribute bits onto an mbuf list. 2479191783Srmacklem * Return the number of bytes of output generated. 2480191783Srmacklem */ 2481191783SrmacklemAPPLESTATIC int 2482191783Srmacklemnfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 2483191783Srmacklem{ 2484191783Srmacklem u_int32_t *tl; 2485191783Srmacklem int cnt, i, bytesize; 2486191783Srmacklem 2487191783Srmacklem for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 2488191783Srmacklem if (attrbitp->bits[cnt - 1]) 2489191783Srmacklem break; 2490191783Srmacklem bytesize = (cnt + 1) * NFSX_UNSIGNED; 2491191783Srmacklem NFSM_BUILD(tl, u_int32_t *, bytesize); 2492191783Srmacklem *tl++ = txdr_unsigned(cnt); 2493191783Srmacklem for (i = 0; i < cnt; i++) 2494191783Srmacklem *tl++ = txdr_unsigned(attrbitp->bits[i]); 2495191783Srmacklem return (bytesize); 2496191783Srmacklem} 2497191783Srmacklem 2498191783Srmacklem/* 2499191783Srmacklem * Convert a uid to a string. 2500191783Srmacklem * If the lookup fails, just output the digits. 2501191783Srmacklem * uid - the user id 2502191783Srmacklem * cpp - points to a buffer of size NFSV4_SMALLSTR 2503191783Srmacklem * (malloc a larger one, as required) 2504191783Srmacklem * retlenp - pointer to length to be returned 2505191783Srmacklem */ 2506191783SrmacklemAPPLESTATIC void 2507191783Srmacklemnfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2508191783Srmacklem{ 2509191783Srmacklem int i; 2510191783Srmacklem struct nfsusrgrp *usrp; 2511191783Srmacklem u_char *cp = *cpp; 2512191783Srmacklem uid_t tmp; 2513191783Srmacklem int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2514191783Srmacklem 2515191783Srmacklem cnt = 0; 2516191783Srmacklemtryagain: 2517191783Srmacklem NFSLOCKNAMEID(); 2518191783Srmacklem if (nfsrv_dnsname) { 2519191783Srmacklem /* 2520191783Srmacklem * Always map nfsrv_defaultuid to "nobody". 2521191783Srmacklem */ 2522191783Srmacklem if (uid == nfsrv_defaultuid) { 2523191783Srmacklem i = nfsrv_dnsnamelen + 7; 2524191783Srmacklem if (i > len) { 2525191783Srmacklem NFSUNLOCKNAMEID(); 2526191783Srmacklem if (len > NFSV4_SMALLSTR) 2527191783Srmacklem free(cp, M_NFSSTRING); 2528191783Srmacklem cp = malloc(i, M_NFSSTRING, M_WAITOK); 2529191783Srmacklem *cpp = cp; 2530191783Srmacklem len = i; 2531191783Srmacklem goto tryagain; 2532191783Srmacklem } 2533191783Srmacklem *retlenp = i; 2534191783Srmacklem NFSBCOPY("nobody@", cp, 7); 2535191783Srmacklem cp += 7; 2536191783Srmacklem NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2537191783Srmacklem NFSUNLOCKNAMEID(); 2538191783Srmacklem return; 2539191783Srmacklem } 2540191783Srmacklem hasampersand = 0; 2541191783Srmacklem LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) { 2542191783Srmacklem if (usrp->lug_uid == uid) { 2543191783Srmacklem if (usrp->lug_expiry < NFSD_MONOSEC) 2544191783Srmacklem break; 2545191783Srmacklem /* 2546191783Srmacklem * If the name doesn't already have an '@' 2547191783Srmacklem * in it, append @domainname to it. 2548191783Srmacklem */ 2549191783Srmacklem for (i = 0; i < usrp->lug_namelen; i++) { 2550191783Srmacklem if (usrp->lug_name[i] == '@') { 2551191783Srmacklem hasampersand = 1; 2552191783Srmacklem break; 2553191783Srmacklem } 2554191783Srmacklem } 2555191783Srmacklem if (hasampersand) 2556191783Srmacklem i = usrp->lug_namelen; 2557191783Srmacklem else 2558191783Srmacklem i = usrp->lug_namelen + 2559191783Srmacklem nfsrv_dnsnamelen + 1; 2560191783Srmacklem if (i > len) { 2561191783Srmacklem NFSUNLOCKNAMEID(); 2562191783Srmacklem if (len > NFSV4_SMALLSTR) 2563191783Srmacklem free(cp, M_NFSSTRING); 2564191783Srmacklem cp = malloc(i, M_NFSSTRING, M_WAITOK); 2565191783Srmacklem *cpp = cp; 2566191783Srmacklem len = i; 2567191783Srmacklem goto tryagain; 2568191783Srmacklem } 2569191783Srmacklem *retlenp = i; 2570191783Srmacklem NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2571191783Srmacklem if (!hasampersand) { 2572191783Srmacklem cp += usrp->lug_namelen; 2573191783Srmacklem *cp++ = '@'; 2574191783Srmacklem NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2575191783Srmacklem } 2576191783Srmacklem TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2577191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2578191783Srmacklem NFSUNLOCKNAMEID(); 2579191783Srmacklem return; 2580191783Srmacklem } 2581191783Srmacklem } 2582191783Srmacklem NFSUNLOCKNAMEID(); 2583191783Srmacklem cnt++; 2584191783Srmacklem ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2585191783Srmacklem NULL, p); 2586191783Srmacklem if (ret == 0 && cnt < 2) 2587191783Srmacklem goto tryagain; 2588191783Srmacklem } else { 2589191783Srmacklem NFSUNLOCKNAMEID(); 2590191783Srmacklem } 2591191783Srmacklem 2592191783Srmacklem /* 2593191783Srmacklem * No match, just return a string of digits. 2594191783Srmacklem */ 2595191783Srmacklem tmp = uid; 2596191783Srmacklem i = 0; 2597191783Srmacklem while (tmp || i == 0) { 2598191783Srmacklem tmp /= 10; 2599191783Srmacklem i++; 2600191783Srmacklem } 2601191783Srmacklem len = (i > len) ? len : i; 2602191783Srmacklem *retlenp = len; 2603191783Srmacklem cp += (len - 1); 2604191783Srmacklem tmp = uid; 2605191783Srmacklem for (i = 0; i < len; i++) { 2606191783Srmacklem *cp-- = '0' + (tmp % 10); 2607191783Srmacklem tmp /= 10; 2608191783Srmacklem } 2609191783Srmacklem return; 2610191783Srmacklem} 2611191783Srmacklem 2612191783Srmacklem/* 2613191783Srmacklem * Convert a string to a uid. 2614191783Srmacklem * If no conversion is possible return NFSERR_BADOWNER, otherwise 2615191783Srmacklem * return 0. 2616240720Srmacklem * If this is called from a client side mount using AUTH_SYS and the 2617240720Srmacklem * string is made up entirely of digits, just convert the string to 2618240720Srmacklem * a number. 2619191783Srmacklem */ 2620191783SrmacklemAPPLESTATIC int 2621240720Srmacklemnfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp, 2622240720Srmacklem NFSPROC_T *p) 2623191783Srmacklem{ 2624191783Srmacklem int i; 2625240720Srmacklem char *cp, *endstr, *str0; 2626191783Srmacklem struct nfsusrgrp *usrp; 2627191783Srmacklem int cnt, ret; 2628224086Szack int error = 0; 2629240720Srmacklem uid_t tuid; 2630191783Srmacklem 2631224086Szack if (len == 0) { 2632224086Szack error = NFSERR_BADOWNER; 2633224086Szack goto out; 2634224086Szack } 2635240720Srmacklem /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2636240720Srmacklem str0 = str; 2637240720Srmacklem tuid = (uid_t)strtoul(str0, &endstr, 10); 2638240720Srmacklem if ((endstr - str0) == len && 2639240720Srmacklem (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) { 2640240720Srmacklem *uidp = tuid; 2641240720Srmacklem goto out; 2642240720Srmacklem } 2643191783Srmacklem /* 2644191783Srmacklem * Look for an '@'. 2645191783Srmacklem */ 2646240720Srmacklem cp = strchr(str0, '@'); 2647240720Srmacklem if (cp != NULL) 2648240720Srmacklem i = (int)(cp++ - str0); 2649240720Srmacklem else 2650240720Srmacklem i = len; 2651191783Srmacklem 2652191783Srmacklem cnt = 0; 2653191783Srmacklemtryagain: 2654191783Srmacklem NFSLOCKNAMEID(); 2655191783Srmacklem /* 2656191783Srmacklem * If an '@' is found and the domain name matches, search for the name 2657191783Srmacklem * with dns stripped off. 2658191783Srmacklem * Mixed case alpahbetics will match for the domain name, but all 2659191783Srmacklem * upper case will not. 2660191783Srmacklem */ 2661191783Srmacklem if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2662191783Srmacklem (len - 1 - i) == nfsrv_dnsnamelen && 2663191783Srmacklem !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2664191783Srmacklem len -= (nfsrv_dnsnamelen + 1); 2665191783Srmacklem *(cp - 1) = '\0'; 2666191783Srmacklem } 2667191783Srmacklem 2668191783Srmacklem /* 2669191783Srmacklem * Check for the special case of "nobody". 2670191783Srmacklem */ 2671191783Srmacklem if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 2672191783Srmacklem *uidp = nfsrv_defaultuid; 2673191783Srmacklem NFSUNLOCKNAMEID(); 2674224086Szack error = 0; 2675224086Szack goto out; 2676191783Srmacklem } 2677191783Srmacklem 2678191783Srmacklem LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) { 2679191783Srmacklem if (usrp->lug_namelen == len && 2680191783Srmacklem !NFSBCMP(usrp->lug_name, str, len)) { 2681191783Srmacklem if (usrp->lug_expiry < NFSD_MONOSEC) 2682191783Srmacklem break; 2683191783Srmacklem *uidp = usrp->lug_uid; 2684191783Srmacklem TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2685191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2686191783Srmacklem NFSUNLOCKNAMEID(); 2687224086Szack error = 0; 2688224086Szack goto out; 2689191783Srmacklem } 2690191783Srmacklem } 2691191783Srmacklem NFSUNLOCKNAMEID(); 2692191783Srmacklem cnt++; 2693191783Srmacklem ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 2694191783Srmacklem str, p); 2695191783Srmacklem if (ret == 0 && cnt < 2) 2696191783Srmacklem goto tryagain; 2697224086Szack error = NFSERR_BADOWNER; 2698224086Szack 2699224086Szackout: 2700224086Szack NFSEXITCODE(error); 2701224086Szack return (error); 2702191783Srmacklem} 2703191783Srmacklem 2704191783Srmacklem/* 2705191783Srmacklem * Convert a gid to a string. 2706191783Srmacklem * gid - the group id 2707191783Srmacklem * cpp - points to a buffer of size NFSV4_SMALLSTR 2708191783Srmacklem * (malloc a larger one, as required) 2709191783Srmacklem * retlenp - pointer to length to be returned 2710191783Srmacklem */ 2711191783SrmacklemAPPLESTATIC void 2712191783Srmacklemnfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2713191783Srmacklem{ 2714191783Srmacklem int i; 2715191783Srmacklem struct nfsusrgrp *usrp; 2716191783Srmacklem u_char *cp = *cpp; 2717191783Srmacklem gid_t tmp; 2718191783Srmacklem int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2719191783Srmacklem 2720191783Srmacklem cnt = 0; 2721191783Srmacklemtryagain: 2722191783Srmacklem NFSLOCKNAMEID(); 2723191783Srmacklem if (nfsrv_dnsname) { 2724191783Srmacklem /* 2725191783Srmacklem * Always map nfsrv_defaultgid to "nogroup". 2726191783Srmacklem */ 2727191783Srmacklem if (gid == nfsrv_defaultgid) { 2728191783Srmacklem i = nfsrv_dnsnamelen + 8; 2729191783Srmacklem if (i > len) { 2730191783Srmacklem NFSUNLOCKNAMEID(); 2731191783Srmacklem if (len > NFSV4_SMALLSTR) 2732191783Srmacklem free(cp, M_NFSSTRING); 2733191783Srmacklem cp = malloc(i, M_NFSSTRING, M_WAITOK); 2734191783Srmacklem *cpp = cp; 2735191783Srmacklem len = i; 2736191783Srmacklem goto tryagain; 2737191783Srmacklem } 2738191783Srmacklem *retlenp = i; 2739191783Srmacklem NFSBCOPY("nogroup@", cp, 8); 2740191783Srmacklem cp += 8; 2741191783Srmacklem NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2742191783Srmacklem NFSUNLOCKNAMEID(); 2743191783Srmacklem return; 2744191783Srmacklem } 2745191783Srmacklem hasampersand = 0; 2746191783Srmacklem LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) { 2747191783Srmacklem if (usrp->lug_gid == gid) { 2748191783Srmacklem if (usrp->lug_expiry < NFSD_MONOSEC) 2749191783Srmacklem break; 2750191783Srmacklem /* 2751191783Srmacklem * If the name doesn't already have an '@' 2752191783Srmacklem * in it, append @domainname to it. 2753191783Srmacklem */ 2754191783Srmacklem for (i = 0; i < usrp->lug_namelen; i++) { 2755191783Srmacklem if (usrp->lug_name[i] == '@') { 2756191783Srmacklem hasampersand = 1; 2757191783Srmacklem break; 2758191783Srmacklem } 2759191783Srmacklem } 2760191783Srmacklem if (hasampersand) 2761191783Srmacklem i = usrp->lug_namelen; 2762191783Srmacklem else 2763191783Srmacklem i = usrp->lug_namelen + 2764191783Srmacklem nfsrv_dnsnamelen + 1; 2765191783Srmacklem if (i > len) { 2766191783Srmacklem NFSUNLOCKNAMEID(); 2767191783Srmacklem if (len > NFSV4_SMALLSTR) 2768191783Srmacklem free(cp, M_NFSSTRING); 2769191783Srmacklem cp = malloc(i, M_NFSSTRING, M_WAITOK); 2770191783Srmacklem *cpp = cp; 2771191783Srmacklem len = i; 2772191783Srmacklem goto tryagain; 2773191783Srmacklem } 2774191783Srmacklem *retlenp = i; 2775191783Srmacklem NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2776191783Srmacklem if (!hasampersand) { 2777191783Srmacklem cp += usrp->lug_namelen; 2778191783Srmacklem *cp++ = '@'; 2779191783Srmacklem NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2780191783Srmacklem } 2781191783Srmacklem TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2782191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2783191783Srmacklem NFSUNLOCKNAMEID(); 2784191783Srmacklem return; 2785191783Srmacklem } 2786191783Srmacklem } 2787191783Srmacklem NFSUNLOCKNAMEID(); 2788191783Srmacklem cnt++; 2789191783Srmacklem ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, 2790191783Srmacklem NULL, p); 2791191783Srmacklem if (ret == 0 && cnt < 2) 2792191783Srmacklem goto tryagain; 2793191783Srmacklem } else { 2794191783Srmacklem NFSUNLOCKNAMEID(); 2795191783Srmacklem } 2796191783Srmacklem 2797191783Srmacklem /* 2798191783Srmacklem * No match, just return a string of digits. 2799191783Srmacklem */ 2800191783Srmacklem tmp = gid; 2801191783Srmacklem i = 0; 2802191783Srmacklem while (tmp || i == 0) { 2803191783Srmacklem tmp /= 10; 2804191783Srmacklem i++; 2805191783Srmacklem } 2806191783Srmacklem len = (i > len) ? len : i; 2807191783Srmacklem *retlenp = len; 2808191783Srmacklem cp += (len - 1); 2809191783Srmacklem tmp = gid; 2810191783Srmacklem for (i = 0; i < len; i++) { 2811191783Srmacklem *cp-- = '0' + (tmp % 10); 2812191783Srmacklem tmp /= 10; 2813191783Srmacklem } 2814191783Srmacklem return; 2815191783Srmacklem} 2816191783Srmacklem 2817191783Srmacklem/* 2818191783Srmacklem * Convert a string to a gid. 2819240720Srmacklem * If no conversion is possible return NFSERR_BADOWNER, otherwise 2820240720Srmacklem * return 0. 2821240720Srmacklem * If this is called from a client side mount using AUTH_SYS and the 2822240720Srmacklem * string is made up entirely of digits, just convert the string to 2823240720Srmacklem * a number. 2824191783Srmacklem */ 2825191783SrmacklemAPPLESTATIC int 2826240720Srmacklemnfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp, 2827240720Srmacklem NFSPROC_T *p) 2828191783Srmacklem{ 2829191783Srmacklem int i; 2830240720Srmacklem char *cp, *endstr, *str0; 2831191783Srmacklem struct nfsusrgrp *usrp; 2832191783Srmacklem int cnt, ret; 2833224086Szack int error = 0; 2834240720Srmacklem gid_t tgid; 2835191783Srmacklem 2836224086Szack if (len == 0) { 2837224086Szack error = NFSERR_BADOWNER; 2838224086Szack goto out; 2839224086Szack } 2840240720Srmacklem /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2841240720Srmacklem str0 = str; 2842240720Srmacklem tgid = (gid_t)strtoul(str0, &endstr, 10); 2843240720Srmacklem if ((endstr - str0) == len && 2844240720Srmacklem (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) { 2845240720Srmacklem *gidp = tgid; 2846240720Srmacklem goto out; 2847240720Srmacklem } 2848191783Srmacklem /* 2849191783Srmacklem * Look for an '@'. 2850191783Srmacklem */ 2851240720Srmacklem cp = strchr(str0, '@'); 2852240720Srmacklem if (cp != NULL) 2853240720Srmacklem i = (int)(cp++ - str0); 2854240720Srmacklem else 2855240720Srmacklem i = len; 2856191783Srmacklem 2857191783Srmacklem cnt = 0; 2858191783Srmacklemtryagain: 2859191783Srmacklem NFSLOCKNAMEID(); 2860191783Srmacklem /* 2861191783Srmacklem * If an '@' is found and the dns name matches, search for the name 2862191783Srmacklem * with the dns stripped off. 2863191783Srmacklem */ 2864191783Srmacklem if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2865191783Srmacklem (len - 1 - i) == nfsrv_dnsnamelen && 2866191783Srmacklem !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2867191783Srmacklem len -= (nfsrv_dnsnamelen + 1); 2868191783Srmacklem *(cp - 1) = '\0'; 2869191783Srmacklem } 2870191783Srmacklem 2871191783Srmacklem /* 2872191783Srmacklem * Check for the special case of "nogroup". 2873191783Srmacklem */ 2874191783Srmacklem if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 2875191783Srmacklem *gidp = nfsrv_defaultgid; 2876191783Srmacklem NFSUNLOCKNAMEID(); 2877224086Szack error = 0; 2878224086Szack goto out; 2879191783Srmacklem } 2880191783Srmacklem 2881191783Srmacklem LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) { 2882191783Srmacklem if (usrp->lug_namelen == len && 2883191783Srmacklem !NFSBCMP(usrp->lug_name, str, len)) { 2884191783Srmacklem if (usrp->lug_expiry < NFSD_MONOSEC) 2885191783Srmacklem break; 2886191783Srmacklem *gidp = usrp->lug_gid; 2887191783Srmacklem TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2888191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2889191783Srmacklem NFSUNLOCKNAMEID(); 2890224086Szack error = 0; 2891224086Szack goto out; 2892191783Srmacklem } 2893191783Srmacklem } 2894191783Srmacklem NFSUNLOCKNAMEID(); 2895191783Srmacklem cnt++; 2896191783Srmacklem ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 2897191783Srmacklem str, p); 2898191783Srmacklem if (ret == 0 && cnt < 2) 2899191783Srmacklem goto tryagain; 2900224086Szack error = NFSERR_BADOWNER; 2901224086Szack 2902224086Szackout: 2903224086Szack NFSEXITCODE(error); 2904224086Szack return (error); 2905191783Srmacklem} 2906191783Srmacklem 2907191783Srmacklem/* 2908191783Srmacklem * Cmp len chars, allowing mixed case in the first argument to match lower 2909191783Srmacklem * case in the second, but not if the first argument is all upper case. 2910191783Srmacklem * Return 0 for a match, 1 otherwise. 2911191783Srmacklem */ 2912191783Srmacklemstatic int 2913191783Srmacklemnfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 2914191783Srmacklem{ 2915191783Srmacklem int i; 2916191783Srmacklem u_char tmp; 2917191783Srmacklem int fndlower = 0; 2918191783Srmacklem 2919191783Srmacklem for (i = 0; i < len; i++) { 2920191783Srmacklem if (*cp >= 'A' && *cp <= 'Z') { 2921191783Srmacklem tmp = *cp++ + ('a' - 'A'); 2922191783Srmacklem } else { 2923191783Srmacklem tmp = *cp++; 2924191783Srmacklem if (tmp >= 'a' && tmp <= 'z') 2925191783Srmacklem fndlower = 1; 2926191783Srmacklem } 2927191783Srmacklem if (tmp != *cp2++) 2928191783Srmacklem return (1); 2929191783Srmacklem } 2930191783Srmacklem if (fndlower) 2931191783Srmacklem return (0); 2932191783Srmacklem else 2933191783Srmacklem return (1); 2934191783Srmacklem} 2935191783Srmacklem 2936191783Srmacklem/* 2937191783Srmacklem * Set the port for the nfsuserd. 2938191783Srmacklem */ 2939191783SrmacklemAPPLESTATIC int 2940191783Srmacklemnfsrv_nfsuserdport(u_short port, NFSPROC_T *p) 2941191783Srmacklem{ 2942191783Srmacklem struct nfssockreq *rp; 2943191783Srmacklem struct sockaddr_in *ad; 2944191783Srmacklem int error; 2945191783Srmacklem 2946191783Srmacklem NFSLOCKNAMEID(); 2947191783Srmacklem if (nfsrv_nfsuserd) { 2948191783Srmacklem NFSUNLOCKNAMEID(); 2949224086Szack error = EPERM; 2950224086Szack goto out; 2951191783Srmacklem } 2952191783Srmacklem nfsrv_nfsuserd = 1; 2953191783Srmacklem NFSUNLOCKNAMEID(); 2954191783Srmacklem /* 2955191783Srmacklem * Set up the socket record and connect. 2956191783Srmacklem */ 2957191783Srmacklem rp = &nfsrv_nfsuserdsock; 2958191783Srmacklem rp->nr_client = NULL; 2959191783Srmacklem rp->nr_sotype = SOCK_DGRAM; 2960191783Srmacklem rp->nr_soproto = IPPROTO_UDP; 2961191783Srmacklem rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 2962191783Srmacklem rp->nr_cred = NULL; 2963191783Srmacklem NFSSOCKADDRALLOC(rp->nr_nam); 2964191783Srmacklem NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in)); 2965191783Srmacklem ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *); 2966191783Srmacklem ad->sin_family = AF_INET; 2967191783Srmacklem ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */ 2968191783Srmacklem ad->sin_port = port; 2969191783Srmacklem rp->nr_prog = RPCPROG_NFSUSERD; 2970191783Srmacklem rp->nr_vers = RPCNFSUSERD_VERS; 2971191783Srmacklem error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 2972191783Srmacklem if (error) { 2973191783Srmacklem NFSSOCKADDRFREE(rp->nr_nam); 2974191783Srmacklem nfsrv_nfsuserd = 0; 2975191783Srmacklem } 2976224086Szackout: 2977224086Szack NFSEXITCODE(error); 2978191783Srmacklem return (error); 2979191783Srmacklem} 2980191783Srmacklem 2981191783Srmacklem/* 2982191783Srmacklem * Delete the nfsuserd port. 2983191783Srmacklem */ 2984191783SrmacklemAPPLESTATIC void 2985191783Srmacklemnfsrv_nfsuserddelport(void) 2986191783Srmacklem{ 2987191783Srmacklem 2988191783Srmacklem NFSLOCKNAMEID(); 2989191783Srmacklem if (nfsrv_nfsuserd == 0) { 2990191783Srmacklem NFSUNLOCKNAMEID(); 2991191783Srmacklem return; 2992191783Srmacklem } 2993191783Srmacklem nfsrv_nfsuserd = 0; 2994191783Srmacklem NFSUNLOCKNAMEID(); 2995191783Srmacklem newnfs_disconnect(&nfsrv_nfsuserdsock); 2996191783Srmacklem NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); 2997191783Srmacklem} 2998191783Srmacklem 2999191783Srmacklem/* 3000191783Srmacklem * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 3001191783Srmacklem * name<-->id cache. 3002191783Srmacklem * Returns 0 upon success, non-zero otherwise. 3003191783Srmacklem */ 3004191783Srmacklemstatic int 3005191783Srmacklemnfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) 3006191783Srmacklem{ 3007191783Srmacklem u_int32_t *tl; 3008191783Srmacklem struct nfsrv_descript *nd; 3009191783Srmacklem int len; 3010191783Srmacklem struct nfsrv_descript nfsd; 3011191783Srmacklem struct ucred *cred; 3012191783Srmacklem int error; 3013191783Srmacklem 3014191783Srmacklem NFSLOCKNAMEID(); 3015191783Srmacklem if (nfsrv_nfsuserd == 0) { 3016191783Srmacklem NFSUNLOCKNAMEID(); 3017224086Szack error = EPERM; 3018224086Szack goto out; 3019191783Srmacklem } 3020191783Srmacklem NFSUNLOCKNAMEID(); 3021191783Srmacklem nd = &nfsd; 3022191783Srmacklem cred = newnfs_getcred(); 3023191783Srmacklem nd->nd_flag = ND_GSSINITREPLY; 3024191783Srmacklem nfsrvd_rephead(nd); 3025191783Srmacklem 3026191783Srmacklem nd->nd_procnum = procnum; 3027191783Srmacklem if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3028191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3029191783Srmacklem if (procnum == RPCNFSUSERD_GETUID) 3030191783Srmacklem *tl = txdr_unsigned(uid); 3031191783Srmacklem else 3032191783Srmacklem *tl = txdr_unsigned(gid); 3033191783Srmacklem } else { 3034191783Srmacklem len = strlen(name); 3035191783Srmacklem (void) nfsm_strtom(nd, name, len); 3036191783Srmacklem } 3037191783Srmacklem error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 3038244042Srmacklem cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL); 3039191783Srmacklem NFSFREECRED(cred); 3040191783Srmacklem if (!error) { 3041191783Srmacklem mbuf_freem(nd->nd_mrep); 3042191783Srmacklem error = nd->nd_repstat; 3043191783Srmacklem } 3044224086Szackout: 3045224086Szack NFSEXITCODE(error); 3046191783Srmacklem return (error); 3047191783Srmacklem} 3048191783Srmacklem 3049191783Srmacklem/* 3050191783Srmacklem * This function is called from the nfssvc(2) system call, to update the 3051191783Srmacklem * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3052191783Srmacklem */ 3053191783SrmacklemAPPLESTATIC int 3054191783Srmacklemnfssvc_idname(struct nfsd_idargs *nidp) 3055191783Srmacklem{ 3056191783Srmacklem struct nfsusrgrp *nusrp, *usrp, *newusrp; 3057191783Srmacklem struct nfsuserhashhead *hp; 3058191783Srmacklem int i; 3059191783Srmacklem int error = 0; 3060191783Srmacklem u_char *cp; 3061191783Srmacklem 3062191783Srmacklem if (nidp->nid_flag & NFSID_INITIALIZE) { 3063191783Srmacklem cp = (u_char *)malloc(nidp->nid_namelen + 1, 3064191783Srmacklem M_NFSSTRING, M_WAITOK); 3065191783Srmacklem error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 3066191783Srmacklem nidp->nid_namelen); 3067191783Srmacklem NFSLOCKNAMEID(); 3068191783Srmacklem if (nfsrv_dnsname) { 3069191783Srmacklem /* 3070191783Srmacklem * Free up all the old stuff and reinitialize hash lists. 3071191783Srmacklem */ 3072191783Srmacklem TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 3073191783Srmacklem nfsrv_removeuser(usrp); 3074191783Srmacklem } 3075191783Srmacklem free(nfsrv_dnsname, M_NFSSTRING); 3076191783Srmacklem nfsrv_dnsname = NULL; 3077191783Srmacklem } 3078191783Srmacklem TAILQ_INIT(&nfsuserlruhead); 3079191783Srmacklem for (i = 0; i < NFSUSERHASHSIZE; i++) 3080191783Srmacklem LIST_INIT(&nfsuserhash[i]); 3081191783Srmacklem for (i = 0; i < NFSGROUPHASHSIZE; i++) 3082191783Srmacklem LIST_INIT(&nfsgrouphash[i]); 3083191783Srmacklem for (i = 0; i < NFSUSERHASHSIZE; i++) 3084191783Srmacklem LIST_INIT(&nfsusernamehash[i]); 3085191783Srmacklem for (i = 0; i < NFSGROUPHASHSIZE; i++) 3086191783Srmacklem LIST_INIT(&nfsgroupnamehash[i]); 3087191783Srmacklem 3088191783Srmacklem /* 3089191783Srmacklem * Put name in "DNS" string. 3090191783Srmacklem */ 3091191783Srmacklem if (!error) { 3092191783Srmacklem nfsrv_dnsname = cp; 3093191783Srmacklem nfsrv_dnsnamelen = nidp->nid_namelen; 3094191783Srmacklem nfsrv_defaultuid = nidp->nid_uid; 3095191783Srmacklem nfsrv_defaultgid = nidp->nid_gid; 3096191783Srmacklem nfsrv_usercnt = 0; 3097191783Srmacklem nfsrv_usermax = nidp->nid_usermax; 3098191783Srmacklem } 3099191783Srmacklem NFSUNLOCKNAMEID(); 3100191783Srmacklem if (error) 3101191783Srmacklem free(cp, M_NFSSTRING); 3102224086Szack goto out; 3103191783Srmacklem } 3104191783Srmacklem 3105191783Srmacklem /* 3106191783Srmacklem * malloc the new one now, so any potential sleep occurs before 3107191783Srmacklem * manipulation of the lists. 3108191783Srmacklem */ 3109191783Srmacklem MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) + 3110191783Srmacklem nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK); 3111191783Srmacklem error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 3112191783Srmacklem nidp->nid_namelen); 3113191783Srmacklem if (error) { 3114191783Srmacklem free((caddr_t)newusrp, M_NFSUSERGROUP); 3115224086Szack goto out; 3116191783Srmacklem } 3117191783Srmacklem newusrp->lug_namelen = nidp->nid_namelen; 3118191783Srmacklem 3119191783Srmacklem NFSLOCKNAMEID(); 3120191783Srmacklem /* 3121191783Srmacklem * Delete old entries, as required. 3122191783Srmacklem */ 3123191783Srmacklem if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3124191783Srmacklem hp = NFSUSERHASH(nidp->nid_uid); 3125191783Srmacklem LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 3126191783Srmacklem if (usrp->lug_uid == nidp->nid_uid) 3127191783Srmacklem nfsrv_removeuser(usrp); 3128191783Srmacklem } 3129191783Srmacklem } 3130191783Srmacklem if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3131191783Srmacklem hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3132191783Srmacklem LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 3133191783Srmacklem if (usrp->lug_namelen == newusrp->lug_namelen && 3134191783Srmacklem !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3135191783Srmacklem usrp->lug_namelen)) 3136191783Srmacklem nfsrv_removeuser(usrp); 3137191783Srmacklem } 3138191783Srmacklem } 3139191783Srmacklem if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3140191783Srmacklem hp = NFSGROUPHASH(nidp->nid_gid); 3141191783Srmacklem LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 3142191783Srmacklem if (usrp->lug_gid == nidp->nid_gid) 3143191783Srmacklem nfsrv_removeuser(usrp); 3144191783Srmacklem } 3145191783Srmacklem } 3146191783Srmacklem if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3147191783Srmacklem hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3148191783Srmacklem LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 3149191783Srmacklem if (usrp->lug_namelen == newusrp->lug_namelen && 3150191783Srmacklem !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3151191783Srmacklem usrp->lug_namelen)) 3152191783Srmacklem nfsrv_removeuser(usrp); 3153191783Srmacklem } 3154191783Srmacklem } 3155191783Srmacklem TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 3156191783Srmacklem if (usrp->lug_expiry < NFSD_MONOSEC) 3157191783Srmacklem nfsrv_removeuser(usrp); 3158191783Srmacklem } 3159191783Srmacklem while (nfsrv_usercnt >= nfsrv_usermax) { 3160191783Srmacklem usrp = TAILQ_FIRST(&nfsuserlruhead); 3161191783Srmacklem nfsrv_removeuser(usrp); 3162191783Srmacklem } 3163191783Srmacklem 3164191783Srmacklem /* 3165191783Srmacklem * Now, we can add the new one. 3166191783Srmacklem */ 3167191783Srmacklem if (nidp->nid_usertimeout) 3168191783Srmacklem newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3169191783Srmacklem else 3170191783Srmacklem newusrp->lug_expiry = NFSD_MONOSEC + 5; 3171191783Srmacklem if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3172191783Srmacklem newusrp->lug_uid = nidp->nid_uid; 3173191783Srmacklem LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp, 3174191783Srmacklem lug_numhash); 3175191783Srmacklem LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name, 3176191783Srmacklem newusrp->lug_namelen), newusrp, lug_namehash); 3177191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3178191783Srmacklem nfsrv_usercnt++; 3179191783Srmacklem } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3180191783Srmacklem newusrp->lug_gid = nidp->nid_gid; 3181191783Srmacklem LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp, 3182191783Srmacklem lug_numhash); 3183191783Srmacklem LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name, 3184191783Srmacklem newusrp->lug_namelen), newusrp, lug_namehash); 3185191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3186191783Srmacklem nfsrv_usercnt++; 3187191783Srmacklem } else 3188191783Srmacklem FREE((caddr_t)newusrp, M_NFSUSERGROUP); 3189191783Srmacklem NFSUNLOCKNAMEID(); 3190224086Szackout: 3191224086Szack NFSEXITCODE(error); 3192191783Srmacklem return (error); 3193191783Srmacklem} 3194191783Srmacklem 3195191783Srmacklem/* 3196191783Srmacklem * Remove a user/group name element. 3197191783Srmacklem */ 3198191783Srmacklemstatic void 3199191783Srmacklemnfsrv_removeuser(struct nfsusrgrp *usrp) 3200191783Srmacklem{ 3201191783Srmacklem 3202191783Srmacklem NFSNAMEIDREQUIRED(); 3203191783Srmacklem LIST_REMOVE(usrp, lug_numhash); 3204191783Srmacklem LIST_REMOVE(usrp, lug_namehash); 3205191783Srmacklem TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 3206191783Srmacklem nfsrv_usercnt--; 3207191783Srmacklem FREE((caddr_t)usrp, M_NFSUSERGROUP); 3208191783Srmacklem} 3209191783Srmacklem 3210191783Srmacklem/* 3211191783Srmacklem * This function scans a byte string and checks for UTF-8 compliance. 3212191783Srmacklem * It returns 0 if it conforms and NFSERR_INVAL if not. 3213191783Srmacklem */ 3214191783SrmacklemAPPLESTATIC int 3215191783Srmacklemnfsrv_checkutf8(u_int8_t *cp, int len) 3216191783Srmacklem{ 3217191783Srmacklem u_int32_t val = 0x0; 3218191783Srmacklem int cnt = 0, gotd = 0, shift = 0; 3219191783Srmacklem u_int8_t byte; 3220191783Srmacklem static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 3221224086Szack int error = 0; 3222191783Srmacklem 3223191783Srmacklem /* 3224191783Srmacklem * Here are what the variables are used for: 3225191783Srmacklem * val - the calculated value of a multibyte char, used to check 3226191783Srmacklem * that it was coded with the correct range 3227191783Srmacklem * cnt - the number of 10xxxxxx bytes to follow 3228191783Srmacklem * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 3229191783Srmacklem * shift - lower order bits of range (ie. "val >> shift" should 3230191783Srmacklem * not be 0, in other words, dividing by the lower bound 3231191783Srmacklem * of the range should get a non-zero value) 3232191783Srmacklem * byte - used to calculate cnt 3233191783Srmacklem */ 3234191783Srmacklem while (len > 0) { 3235191783Srmacklem if (cnt > 0) { 3236191783Srmacklem /* This handles the 10xxxxxx bytes */ 3237191783Srmacklem if ((*cp & 0xc0) != 0x80 || 3238224086Szack (gotd && (*cp & 0x20))) { 3239224086Szack error = NFSERR_INVAL; 3240224086Szack goto out; 3241224086Szack } 3242191783Srmacklem gotd = 0; 3243191783Srmacklem val <<= 6; 3244191783Srmacklem val |= (*cp & 0x3f); 3245191783Srmacklem cnt--; 3246224086Szack if (cnt == 0 && (val >> shift) == 0x0) { 3247224086Szack error = NFSERR_INVAL; 3248224086Szack goto out; 3249224086Szack } 3250191783Srmacklem } else if (*cp & 0x80) { 3251191783Srmacklem /* first byte of multi byte char */ 3252191783Srmacklem byte = *cp; 3253191783Srmacklem while ((byte & 0x40) && cnt < 6) { 3254191783Srmacklem cnt++; 3255191783Srmacklem byte <<= 1; 3256191783Srmacklem } 3257224086Szack if (cnt == 0 || cnt == 6) { 3258224086Szack error = NFSERR_INVAL; 3259224086Szack goto out; 3260224086Szack } 3261191783Srmacklem val = (*cp & (0x3f >> cnt)); 3262191783Srmacklem shift = utf8_shift[cnt - 1]; 3263191783Srmacklem if (cnt == 2 && val == 0xd) 3264191783Srmacklem /* Check for the 0xd800-0xdfff case */ 3265191783Srmacklem gotd = 1; 3266191783Srmacklem } 3267191783Srmacklem cp++; 3268191783Srmacklem len--; 3269191783Srmacklem } 3270191783Srmacklem if (cnt > 0) 3271224086Szack error = NFSERR_INVAL; 3272224086Szack 3273224086Szackout: 3274224086Szack NFSEXITCODE(error); 3275224086Szack return (error); 3276191783Srmacklem} 3277191783Srmacklem 3278191783Srmacklem/* 3279191783Srmacklem * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 3280191783Srmacklem * strings, one with the root path in it and the other with the list of 3281191783Srmacklem * locations. The list is in the same format as is found in nfr_refs. 3282191783Srmacklem * It is a "," separated list of entries, where each of them is of the 3283191783Srmacklem * form <server>:<rootpath>. For example 3284191783Srmacklem * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 3285191783Srmacklem * The nilp argument is set to 1 for the special case of a null fs_root 3286191783Srmacklem * and an empty server list. 3287191783Srmacklem * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 3288191783Srmacklem * number of xdr bytes parsed in sump. 3289191783Srmacklem */ 3290191783Srmacklemstatic int 3291191783Srmacklemnfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 3292191783Srmacklem int *sump, int *nilp) 3293191783Srmacklem{ 3294191783Srmacklem u_int32_t *tl; 3295191783Srmacklem u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 3296224086Szack int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 3297191783Srmacklem struct list { 3298191783Srmacklem SLIST_ENTRY(list) next; 3299191783Srmacklem int len; 3300191783Srmacklem u_char host[1]; 3301191783Srmacklem } *lsp, *nlsp; 3302191783Srmacklem SLIST_HEAD(, list) head; 3303191783Srmacklem 3304191783Srmacklem *fsrootp = NULL; 3305191783Srmacklem *srvp = NULL; 3306191783Srmacklem *nilp = 0; 3307191783Srmacklem 3308191783Srmacklem /* 3309191783Srmacklem * Get the fs_root path and check for the special case of null path 3310191783Srmacklem * and 0 length server list. 3311191783Srmacklem */ 3312191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3313191783Srmacklem len = fxdr_unsigned(int, *tl); 3314224086Szack if (len < 0 || len > 10240) { 3315224086Szack error = NFSERR_BADXDR; 3316224086Szack goto nfsmout; 3317224086Szack } 3318191783Srmacklem if (len == 0) { 3319191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3320224086Szack if (*tl != 0) { 3321224086Szack error = NFSERR_BADXDR; 3322224086Szack goto nfsmout; 3323224086Szack } 3324191783Srmacklem *nilp = 1; 3325191783Srmacklem *sump = 2 * NFSX_UNSIGNED; 3326224086Szack error = 0; 3327224086Szack goto nfsmout; 3328191783Srmacklem } 3329191783Srmacklem cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 3330191783Srmacklem error = nfsrv_mtostr(nd, cp, len); 3331191783Srmacklem if (!error) { 3332191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3333191783Srmacklem cnt = fxdr_unsigned(int, *tl); 3334191783Srmacklem if (cnt <= 0) 3335191783Srmacklem error = NFSERR_BADXDR; 3336191783Srmacklem } 3337224086Szack if (error) 3338224086Szack goto nfsmout; 3339191783Srmacklem 3340191783Srmacklem /* 3341191783Srmacklem * Now, loop through the location list and make up the srvlist. 3342191783Srmacklem */ 3343191783Srmacklem xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3344191783Srmacklem cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 3345191783Srmacklem slen = 1024; 3346191783Srmacklem siz = 0; 3347191783Srmacklem for (i = 0; i < cnt; i++) { 3348191783Srmacklem SLIST_INIT(&head); 3349191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3350191783Srmacklem nsrv = fxdr_unsigned(int, *tl); 3351191783Srmacklem if (nsrv <= 0) { 3352224086Szack error = NFSERR_BADXDR; 3353224086Szack goto nfsmout; 3354191783Srmacklem } 3355191783Srmacklem 3356191783Srmacklem /* 3357191783Srmacklem * Handle the first server by putting it in the srvstr. 3358191783Srmacklem */ 3359191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3360191783Srmacklem len = fxdr_unsigned(int, *tl); 3361191783Srmacklem if (len <= 0 || len > 1024) { 3362224086Szack error = NFSERR_BADXDR; 3363224086Szack goto nfsmout; 3364191783Srmacklem } 3365191783Srmacklem nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 3366191783Srmacklem if (cp3 != cp2) { 3367191783Srmacklem *cp3++ = ','; 3368191783Srmacklem siz++; 3369191783Srmacklem } 3370191783Srmacklem error = nfsrv_mtostr(nd, cp3, len); 3371224086Szack if (error) 3372224086Szack goto nfsmout; 3373191783Srmacklem cp3 += len; 3374191783Srmacklem *cp3++ = ':'; 3375191783Srmacklem siz += (len + 1); 3376191783Srmacklem xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3377191783Srmacklem for (j = 1; j < nsrv; j++) { 3378191783Srmacklem /* 3379191783Srmacklem * Yuck, put them in an slist and process them later. 3380191783Srmacklem */ 3381191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3382191783Srmacklem len = fxdr_unsigned(int, *tl); 3383191783Srmacklem if (len <= 0 || len > 1024) { 3384224086Szack error = NFSERR_BADXDR; 3385224086Szack goto nfsmout; 3386191783Srmacklem } 3387191783Srmacklem lsp = (struct list *)malloc(sizeof (struct list) 3388191783Srmacklem + len, M_TEMP, M_WAITOK); 3389191783Srmacklem error = nfsrv_mtostr(nd, lsp->host, len); 3390224086Szack if (error) 3391224086Szack goto nfsmout; 3392191783Srmacklem xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3393191783Srmacklem lsp->len = len; 3394191783Srmacklem SLIST_INSERT_HEAD(&head, lsp, next); 3395191783Srmacklem } 3396191783Srmacklem 3397191783Srmacklem /* 3398191783Srmacklem * Finally, we can get the path. 3399191783Srmacklem */ 3400191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3401191783Srmacklem len = fxdr_unsigned(int, *tl); 3402191783Srmacklem if (len <= 0 || len > 1024) { 3403224086Szack error = NFSERR_BADXDR; 3404224086Szack goto nfsmout; 3405191783Srmacklem } 3406191783Srmacklem nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 3407191783Srmacklem error = nfsrv_mtostr(nd, cp3, len); 3408224086Szack if (error) 3409224086Szack goto nfsmout; 3410191783Srmacklem xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3411191783Srmacklem str = cp3; 3412191783Srmacklem stringlen = len; 3413191783Srmacklem cp3 += len; 3414191783Srmacklem siz += len; 3415191783Srmacklem SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 3416191783Srmacklem nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 3417191783Srmacklem &cp2, &cp3, &slen); 3418191783Srmacklem *cp3++ = ','; 3419191783Srmacklem NFSBCOPY(lsp->host, cp3, lsp->len); 3420191783Srmacklem cp3 += lsp->len; 3421191783Srmacklem *cp3++ = ':'; 3422191783Srmacklem NFSBCOPY(str, cp3, stringlen); 3423191783Srmacklem cp3 += stringlen; 3424191783Srmacklem *cp3 = '\0'; 3425191783Srmacklem siz += (lsp->len + stringlen + 2); 3426191783Srmacklem free((caddr_t)lsp, M_TEMP); 3427191783Srmacklem } 3428191783Srmacklem } 3429191783Srmacklem *fsrootp = cp; 3430191783Srmacklem *srvp = cp2; 3431191783Srmacklem *sump = xdrsum; 3432224086Szack NFSEXITCODE2(0, nd); 3433191783Srmacklem return (0); 3434191783Srmacklemnfsmout: 3435191783Srmacklem if (cp != NULL) 3436191783Srmacklem free(cp, M_NFSSTRING); 3437191783Srmacklem if (cp2 != NULL) 3438191783Srmacklem free(cp2, M_NFSSTRING); 3439224086Szack NFSEXITCODE2(error, nd); 3440191783Srmacklem return (error); 3441191783Srmacklem} 3442191783Srmacklem 3443191783Srmacklem/* 3444191783Srmacklem * Make the malloc'd space large enough. This is a pain, but the xdr 3445191783Srmacklem * doesn't set an upper bound on the side, so... 3446191783Srmacklem */ 3447191783Srmacklemstatic void 3448191783Srmacklemnfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 3449191783Srmacklem{ 3450191783Srmacklem u_char *cp; 3451191783Srmacklem int i; 3452191783Srmacklem 3453191783Srmacklem if (siz <= *slenp) 3454191783Srmacklem return; 3455191783Srmacklem cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 3456191783Srmacklem NFSBCOPY(*cpp, cp, *slenp); 3457191783Srmacklem free(*cpp, M_NFSSTRING); 3458191783Srmacklem i = *cpp2 - *cpp; 3459191783Srmacklem *cpp = cp; 3460191783Srmacklem *cpp2 = cp + i; 3461191783Srmacklem *slenp = siz + 1024; 3462191783Srmacklem} 3463191783Srmacklem 3464191783Srmacklem/* 3465191783Srmacklem * Initialize the reply header data structures. 3466191783Srmacklem */ 3467191783SrmacklemAPPLESTATIC void 3468191783Srmacklemnfsrvd_rephead(struct nfsrv_descript *nd) 3469191783Srmacklem{ 3470191783Srmacklem mbuf_t mreq; 3471191783Srmacklem 3472191783Srmacklem /* 3473191783Srmacklem * If this is a big reply, use a cluster. 3474191783Srmacklem */ 3475191783Srmacklem if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 3476191783Srmacklem nfs_bigreply[nd->nd_procnum]) { 3477243882Sglebius NFSMCLGET(mreq, M_WAITOK); 3478191783Srmacklem nd->nd_mreq = mreq; 3479191783Srmacklem nd->nd_mb = mreq; 3480191783Srmacklem } else { 3481191783Srmacklem NFSMGET(mreq); 3482191783Srmacklem nd->nd_mreq = mreq; 3483191783Srmacklem nd->nd_mb = mreq; 3484191783Srmacklem } 3485191783Srmacklem nd->nd_bpos = NFSMTOD(mreq, caddr_t); 3486191783Srmacklem mbuf_setlen(mreq, 0); 3487191783Srmacklem 3488191783Srmacklem if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 3489191783Srmacklem NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 3490191783Srmacklem} 3491191783Srmacklem 3492191783Srmacklem/* 3493191783Srmacklem * Lock a socket against others. 3494191783Srmacklem * Currently used to serialize connect/disconnect attempts. 3495191783Srmacklem */ 3496191783Srmacklemint 3497191783Srmacklemnewnfs_sndlock(int *flagp) 3498191783Srmacklem{ 3499191783Srmacklem struct timespec ts; 3500191783Srmacklem 3501191783Srmacklem NFSLOCKSOCK(); 3502191783Srmacklem while (*flagp & NFSR_SNDLOCK) { 3503191783Srmacklem *flagp |= NFSR_WANTSND; 3504191783Srmacklem ts.tv_sec = 0; 3505191783Srmacklem ts.tv_nsec = 0; 3506191783Srmacklem (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 3507191783Srmacklem PZERO - 1, "nfsndlck", &ts); 3508191783Srmacklem } 3509191783Srmacklem *flagp |= NFSR_SNDLOCK; 3510191783Srmacklem NFSUNLOCKSOCK(); 3511191783Srmacklem return (0); 3512191783Srmacklem} 3513191783Srmacklem 3514191783Srmacklem/* 3515191783Srmacklem * Unlock the stream socket for others. 3516191783Srmacklem */ 3517191783Srmacklemvoid 3518191783Srmacklemnewnfs_sndunlock(int *flagp) 3519191783Srmacklem{ 3520191783Srmacklem 3521191783Srmacklem NFSLOCKSOCK(); 3522191783Srmacklem if ((*flagp & NFSR_SNDLOCK) == 0) 3523191783Srmacklem panic("nfs sndunlock"); 3524191783Srmacklem *flagp &= ~NFSR_SNDLOCK; 3525191783Srmacklem if (*flagp & NFSR_WANTSND) { 3526191783Srmacklem *flagp &= ~NFSR_WANTSND; 3527191783Srmacklem wakeup((caddr_t)flagp); 3528191783Srmacklem } 3529191783Srmacklem NFSUNLOCKSOCK(); 3530191783Srmacklem} 3531191783Srmacklem 3532244042SrmacklemAPPLESTATIC int 3533244042Srmacklemnfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa, 3534244042Srmacklem int *isudp) 3535244042Srmacklem{ 3536244042Srmacklem struct sockaddr_in *sad; 3537244042Srmacklem struct sockaddr_in6 *sad6; 3538244042Srmacklem struct in_addr saddr; 3539244042Srmacklem uint32_t portnum, *tl; 3540244042Srmacklem int af = 0, i, j, k; 3541244042Srmacklem char addr[64], protocol[5], *cp; 3542244042Srmacklem int cantparse = 0, error = 0; 3543244042Srmacklem uint16_t portv; 3544244042Srmacklem 3545244042Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3546244042Srmacklem i = fxdr_unsigned(int, *tl); 3547244042Srmacklem if (i >= 3 && i <= 4) { 3548244042Srmacklem error = nfsrv_mtostr(nd, protocol, i); 3549244042Srmacklem if (error) 3550244042Srmacklem goto nfsmout; 3551244042Srmacklem if (strcmp(protocol, "tcp") == 0) { 3552244042Srmacklem af = AF_INET; 3553244042Srmacklem *isudp = 0; 3554244042Srmacklem } else if (strcmp(protocol, "udp") == 0) { 3555244042Srmacklem af = AF_INET; 3556244042Srmacklem *isudp = 1; 3557244042Srmacklem } else if (strcmp(protocol, "tcp6") == 0) { 3558244042Srmacklem af = AF_INET6; 3559244042Srmacklem *isudp = 0; 3560244042Srmacklem } else if (strcmp(protocol, "udp6") == 0) { 3561244042Srmacklem af = AF_INET6; 3562244042Srmacklem *isudp = 1; 3563244042Srmacklem } else 3564244042Srmacklem cantparse = 1; 3565244042Srmacklem } else { 3566244042Srmacklem cantparse = 1; 3567244042Srmacklem if (i > 0) { 3568244042Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3569244042Srmacklem if (error) 3570244042Srmacklem goto nfsmout; 3571244042Srmacklem } 3572244042Srmacklem } 3573244042Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3574244042Srmacklem i = fxdr_unsigned(int, *tl); 3575244042Srmacklem if (i < 0) { 3576244042Srmacklem error = NFSERR_BADXDR; 3577244042Srmacklem goto nfsmout; 3578244042Srmacklem } else if (cantparse == 0 && i >= 11 && i < 64) { 3579244042Srmacklem /* 3580244042Srmacklem * The shortest address is 11chars and the longest is < 64. 3581244042Srmacklem */ 3582244042Srmacklem error = nfsrv_mtostr(nd, addr, i); 3583244042Srmacklem if (error) 3584244042Srmacklem goto nfsmout; 3585244042Srmacklem 3586244042Srmacklem /* Find the port# at the end and extract that. */ 3587244042Srmacklem i = strlen(addr); 3588244042Srmacklem k = 0; 3589244042Srmacklem cp = &addr[i - 1]; 3590244042Srmacklem /* Count back two '.'s from end to get port# field. */ 3591244042Srmacklem for (j = 0; j < i; j++) { 3592244042Srmacklem if (*cp == '.') { 3593244042Srmacklem k++; 3594244042Srmacklem if (k == 2) 3595244042Srmacklem break; 3596244042Srmacklem } 3597244042Srmacklem cp--; 3598244042Srmacklem } 3599244042Srmacklem if (k == 2) { 3600244042Srmacklem /* 3601244042Srmacklem * The NFSv4 port# is appended as .N.N, where N is 3602244042Srmacklem * a decimal # in the range 0-255, just like an inet4 3603244042Srmacklem * address. Cheat and use inet_aton(), which will 3604244042Srmacklem * return a Class A address and then shift the high 3605244042Srmacklem * order 8bits over to convert it to the port#. 3606244042Srmacklem */ 3607244042Srmacklem *cp++ = '\0'; 3608244042Srmacklem if (inet_aton(cp, &saddr) == 1) { 3609244042Srmacklem portnum = ntohl(saddr.s_addr); 3610244042Srmacklem portv = (uint16_t)((portnum >> 16) | 3611244042Srmacklem (portnum & 0xff)); 3612244042Srmacklem } else 3613244042Srmacklem cantparse = 1; 3614244042Srmacklem } else 3615244042Srmacklem cantparse = 1; 3616244042Srmacklem if (cantparse == 0) { 3617244042Srmacklem if (af == AF_INET) { 3618244042Srmacklem sad = (struct sockaddr_in *)sa; 3619244042Srmacklem if (inet_pton(af, addr, &sad->sin_addr) == 1) { 3620244042Srmacklem sad->sin_len = sizeof(*sad); 3621244042Srmacklem sad->sin_family = AF_INET; 3622244042Srmacklem sad->sin_port = htons(portv); 3623244042Srmacklem return (0); 3624244042Srmacklem } 3625244042Srmacklem } else { 3626244042Srmacklem sad6 = (struct sockaddr_in6 *)sa; 3627244042Srmacklem if (inet_pton(af, addr, &sad6->sin6_addr) 3628244042Srmacklem == 1) { 3629244042Srmacklem sad6->sin6_len = sizeof(*sad6); 3630244042Srmacklem sad6->sin6_family = AF_INET6; 3631244042Srmacklem sad6->sin6_port = htons(portv); 3632244042Srmacklem return (0); 3633244042Srmacklem } 3634244042Srmacklem } 3635244042Srmacklem } 3636244042Srmacklem } else { 3637244042Srmacklem if (i > 0) { 3638244042Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3639244042Srmacklem if (error) 3640244042Srmacklem goto nfsmout; 3641244042Srmacklem } 3642244042Srmacklem } 3643244042Srmacklem error = EPERM; 3644244042Srmacklemnfsmout: 3645244042Srmacklem return (error); 3646244042Srmacklem} 3647244042Srmacklem 3648244042Srmacklem/* 3649244042Srmacklem * Handle an NFSv4.1 Sequence request for the session. 3650244042Srmacklem */ 3651244042Srmacklemint 3652244042Srmacklemnfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 3653244042Srmacklem struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 3654244042Srmacklem{ 3655244042Srmacklem int error; 3656244042Srmacklem 3657244042Srmacklem error = 0; 3658244042Srmacklem *reply = NULL; 3659244042Srmacklem if (slotid > maxslot) 3660244042Srmacklem return (NFSERR_BADSLOT); 3661244042Srmacklem if (seqid == slots[slotid].nfssl_seq) { 3662244042Srmacklem /* A retry. */ 3663244042Srmacklem if (slots[slotid].nfssl_inprog != 0) 3664244042Srmacklem error = NFSERR_DELAY; 3665244042Srmacklem else if (slots[slotid].nfssl_reply != NULL) { 3666244042Srmacklem *reply = slots[slotid].nfssl_reply; 3667244042Srmacklem slots[slotid].nfssl_reply = NULL; 3668244042Srmacklem slots[slotid].nfssl_inprog = 1; 3669244042Srmacklem } else 3670244042Srmacklem error = NFSERR_SEQMISORDERED; 3671244042Srmacklem } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 3672244042Srmacklem m_freem(slots[slotid].nfssl_reply); 3673244042Srmacklem slots[slotid].nfssl_reply = NULL; 3674244042Srmacklem slots[slotid].nfssl_inprog = 1; 3675244042Srmacklem slots[slotid].nfssl_seq++; 3676244042Srmacklem } else 3677244042Srmacklem error = NFSERR_SEQMISORDERED; 3678244042Srmacklem return (error); 3679244042Srmacklem} 3680244042Srmacklem 3681244042Srmacklem/* 3682244042Srmacklem * Cache this reply for the slot. 3683244042Srmacklem */ 3684244042Srmacklemvoid 3685244042Srmacklemnfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep) 3686244042Srmacklem{ 3687244042Srmacklem 3688244042Srmacklem slots[slotid].nfssl_reply = rep; 3689244042Srmacklem slots[slotid].nfssl_inprog = 0; 3690244042Srmacklem} 3691244042Srmacklem 3692244042Srmacklem/* 3693244042Srmacklem * Generate the xdr for an NFSv4.1 Sequence Operation. 3694244042Srmacklem */ 3695244042SrmacklemAPPLESTATIC void 3696244042Srmacklemnfsv4_setsequence(struct nfsrv_descript *nd, struct nfsclsession *sep, 3697244042Srmacklem int dont_replycache) 3698244042Srmacklem{ 3699244042Srmacklem uint32_t *tl, slotseq = 0; 3700244042Srmacklem int i, maxslot, slotpos; 3701244042Srmacklem uint64_t bitval; 3702244042Srmacklem uint8_t sessionid[NFSX_V4SESSIONID]; 3703244042Srmacklem 3704244042Srmacklem /* Find an unused slot. */ 3705244042Srmacklem slotpos = -1; 3706244042Srmacklem maxslot = -1; 3707244042Srmacklem mtx_lock(&sep->nfsess_mtx); 3708244042Srmacklem do { 3709244042Srmacklem bitval = 1; 3710244042Srmacklem for (i = 0; i < sep->nfsess_foreslots; i++) { 3711244042Srmacklem if ((bitval & sep->nfsess_slots) == 0) { 3712244042Srmacklem slotpos = i; 3713244042Srmacklem sep->nfsess_slots |= bitval; 3714244042Srmacklem sep->nfsess_slotseq[i]++; 3715244042Srmacklem slotseq = sep->nfsess_slotseq[i]; 3716244042Srmacklem break; 3717244042Srmacklem } 3718244042Srmacklem bitval <<= 1; 3719244042Srmacklem } 3720244042Srmacklem if (slotpos == -1) 3721244042Srmacklem (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 3722244042Srmacklem PZERO, "nfsclseq", 0); 3723244042Srmacklem } while (slotpos == -1); 3724244042Srmacklem /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 3725244042Srmacklem bitval = 1; 3726244042Srmacklem for (i = 0; i < 64; i++) { 3727244042Srmacklem if ((bitval & sep->nfsess_slots) != 0) 3728244042Srmacklem maxslot = i; 3729244042Srmacklem bitval <<= 1; 3730244042Srmacklem } 3731244042Srmacklem bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 3732244042Srmacklem mtx_unlock(&sep->nfsess_mtx); 3733244042Srmacklem KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot")); 3734244042Srmacklem 3735244042Srmacklem /* Build the Sequence arguments. */ 3736244042Srmacklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 3737244042Srmacklem bcopy(sessionid, tl, NFSX_V4SESSIONID); 3738244042Srmacklem tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 3739244042Srmacklem nd->nd_slotseq = tl; 3740244042Srmacklem *tl++ = txdr_unsigned(slotseq); 3741244042Srmacklem *tl++ = txdr_unsigned(slotpos); 3742244042Srmacklem *tl++ = txdr_unsigned(maxslot); 3743244042Srmacklem if (dont_replycache == 0) 3744244042Srmacklem *tl = newnfs_true; 3745244042Srmacklem else 3746244042Srmacklem *tl = newnfs_false; 3747244042Srmacklem nd->nd_flag |= ND_HASSEQUENCE; 3748244042Srmacklem} 3749244042Srmacklem 3750244042Srmacklem/* 3751244042Srmacklem * Free a session slot. 3752244042Srmacklem */ 3753244042SrmacklemAPPLESTATIC void 3754244042Srmacklemnfsv4_freeslot(struct nfsclsession *sep, int slot) 3755244042Srmacklem{ 3756244042Srmacklem uint64_t bitval; 3757244042Srmacklem 3758244042Srmacklem bitval = 1; 3759244042Srmacklem if (slot > 0) 3760244042Srmacklem bitval <<= slot; 3761244042Srmacklem mtx_lock(&sep->nfsess_mtx); 3762244042Srmacklem if ((bitval & sep->nfsess_slots) == 0) 3763244042Srmacklem printf("freeing free slot!!\n"); 3764244042Srmacklem sep->nfsess_slots &= ~bitval; 3765244042Srmacklem wakeup(&sep->nfsess_slots); 3766244042Srmacklem mtx_unlock(&sep->nfsess_mtx); 3767244042Srmacklem} 3768244042Srmacklem 3769