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 43230446Srmacklem#include "opt_inet6.h" 44230446Srmacklem 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; 68265724Srmacklemint nfsd_enable_stringtouid = 0; 69191783SrmacklemNFSNAMEIDMUTEX; 70191783SrmacklemNFSSOCKMUTEX; 71191783Srmacklem 72191783Srmacklem/* 73191783Srmacklem * This array of structures indicates, for V4: 74191783Srmacklem * retfh - which of 3 types of calling args are used 75191783Srmacklem * 0 - doesn't change cfh or use a sfh 76191783Srmacklem * 1 - replaces cfh with a new one (unless it returns an error status) 77191783Srmacklem * 2 - uses cfh and sfh 78191783Srmacklem * needscfh - if the op wants a cfh and premtime 79191783Srmacklem * 0 - doesn't use a cfh 80191783Srmacklem * 1 - uses a cfh, but doesn't want pre-op attributes 81191783Srmacklem * 2 - uses a cfh and wants pre-op attributes 82191783Srmacklem * savereply - indicates a non-idempotent Op 83191783Srmacklem * 0 - not non-idempotent 84191783Srmacklem * 1 - non-idempotent 85191783Srmacklem * Ops that are ordered via seqid# are handled separately from these 86191783Srmacklem * non-idempotent Ops. 87191783Srmacklem * Define it here, since it is used by both the client and server. 88191783Srmacklem */ 89191783Srmacklemstruct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS] = { 90216700Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */ 91216700Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */ 92216700Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE }, /* undef */ 93216700Srmacklem { 0, 1, 0, 0, LK_SHARED }, /* Access */ 94216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Close */ 95216700Srmacklem { 0, 2, 0, 1, LK_EXCLUSIVE }, /* Commit */ 96216700Srmacklem { 1, 2, 1, 1, LK_EXCLUSIVE }, /* Create */ 97216700Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE }, /* Delegpurge */ 98216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Delegreturn */ 99216700Srmacklem { 0, 1, 0, 0, LK_SHARED }, /* Getattr */ 100216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* GetFH */ 101216700Srmacklem { 2, 1, 1, 1, LK_EXCLUSIVE }, /* Link */ 102216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Lock */ 103216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* LockT */ 104216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* LockU */ 105265339Srmacklem { 1, 2, 0, 0, LK_EXCLUSIVE }, /* Lookup */ 106265339Srmacklem { 1, 2, 0, 0, LK_EXCLUSIVE }, /* Lookupp */ 107216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* NVerify */ 108216700Srmacklem { 1, 1, 0, 1, LK_EXCLUSIVE }, /* Open */ 109216700Srmacklem { 1, 1, 0, 0, LK_EXCLUSIVE }, /* OpenAttr */ 110216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* OpenConfirm */ 111216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* OpenDowngrade */ 112216700Srmacklem { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutFH */ 113216700Srmacklem { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutPubFH */ 114216700Srmacklem { 1, 0, 0, 0, LK_EXCLUSIVE }, /* PutRootFH */ 115216875Srmacklem { 0, 1, 0, 0, LK_SHARED }, /* Read */ 116216700Srmacklem { 0, 1, 0, 0, LK_SHARED }, /* Readdir */ 117216700Srmacklem { 0, 1, 0, 0, LK_SHARED }, /* ReadLink */ 118216700Srmacklem { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Remove */ 119216700Srmacklem { 2, 1, 1, 1, LK_EXCLUSIVE }, /* Rename */ 120216700Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE }, /* Renew */ 121216700Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE }, /* RestoreFH */ 122216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* SaveFH */ 123216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* SecInfo */ 124216700Srmacklem { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Setattr */ 125216700Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE }, /* SetClientID */ 126216700Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE }, /* SetClientIDConfirm */ 127216700Srmacklem { 0, 1, 0, 0, LK_EXCLUSIVE }, /* Verify */ 128216700Srmacklem { 0, 2, 1, 1, LK_EXCLUSIVE }, /* Write */ 129216700Srmacklem { 0, 0, 0, 0, LK_EXCLUSIVE }, /* ReleaseLockOwner */ 130191783Srmacklem}; 131191783Srmacklem#endif /* !APPLEKEXT */ 132191783Srmacklem 133191783Srmacklemstatic int ncl_mbuf_mhlen = MHLEN; 134191783Srmacklemstatic int nfsrv_usercnt = 0; 135191783Srmacklemstatic int nfsrv_dnsnamelen; 136191783Srmacklemstatic u_char *nfsrv_dnsname = NULL; 137191783Srmacklemstatic int nfsrv_usermax = 999999999; 138191783Srmacklemstatic struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE]; 139191783Srmacklemstatic struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE]; 140191783Srmacklemstatic struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE]; 141191783Srmacklemstatic struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE]; 142191783Srmacklemstatic struct nfsuserlruhead nfsuserlruhead; 143191783Srmacklem 144191783Srmacklem/* 145191783Srmacklem * This static array indicates whether or not the RPC generates a large 146191783Srmacklem * reply. This is used by nfs_reply() to decide whether or not an mbuf 147191783Srmacklem * cluster should be allocated. (If a cluster is required by an RPC 148191783Srmacklem * marked 0 in this array, the code will still work, just not quite as 149191783Srmacklem * efficiently.) 150191783Srmacklem */ 151191783Srmacklemstatic int nfs_bigreply[NFS_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 152191783Srmacklem 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, 153191783Srmacklem 0, 0, 0, 0, 0 }; 154191783Srmacklem 155191783Srmacklem/* local functions */ 156191783Srmacklemstatic int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); 157191783Srmacklemstatic void nfsv4_wanted(struct nfsv4lock *lp); 158191783Srmacklemstatic int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len); 159191783Srmacklemstatic int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, 160191783Srmacklem NFSPROC_T *p); 161191783Srmacklemstatic void nfsrv_removeuser(struct nfsusrgrp *usrp); 162191783Srmacklemstatic int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **, 163191783Srmacklem int *, int *); 164191783Srmacklemstatic void nfsrv_refstrbigenough(int, u_char **, u_char **, int *); 165191783Srmacklem 166191783Srmacklem 167191783Srmacklem#ifndef APPLE 168191783Srmacklem/* 169191783Srmacklem * copies mbuf chain to the uio scatter/gather list 170191783Srmacklem */ 171191783Srmacklemint 172191783Srmacklemnfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz) 173191783Srmacklem{ 174191783Srmacklem char *mbufcp, *uiocp; 175191783Srmacklem int xfer, left, len; 176191783Srmacklem mbuf_t mp; 177191783Srmacklem long uiosiz, rem; 178191783Srmacklem int error = 0; 179191783Srmacklem 180191783Srmacklem mp = nd->nd_md; 181191783Srmacklem mbufcp = nd->nd_dpos; 182191783Srmacklem len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp; 183191783Srmacklem rem = NFSM_RNDUP(siz) - siz; 184191783Srmacklem while (siz > 0) { 185224086Szack if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) { 186224086Szack error = EBADRPC; 187224086Szack goto out; 188224086Szack } 189191783Srmacklem left = uiop->uio_iov->iov_len; 190191783Srmacklem uiocp = uiop->uio_iov->iov_base; 191191783Srmacklem if (left > siz) 192191783Srmacklem left = siz; 193191783Srmacklem uiosiz = left; 194191783Srmacklem while (left > 0) { 195191783Srmacklem while (len == 0) { 196191783Srmacklem mp = mbuf_next(mp); 197224086Szack if (mp == NULL) { 198224086Szack error = EBADRPC; 199224086Szack goto out; 200224086Szack } 201191783Srmacklem mbufcp = NFSMTOD(mp, caddr_t); 202191783Srmacklem len = mbuf_len(mp); 203246539Skib KASSERT(len > 0, ("len %d", len)); 204191783Srmacklem } 205191783Srmacklem xfer = (left > len) ? len : left; 206191783Srmacklem#ifdef notdef 207191783Srmacklem /* Not Yet.. */ 208191783Srmacklem if (uiop->uio_iov->iov_op != NULL) 209191783Srmacklem (*(uiop->uio_iov->iov_op)) 210191783Srmacklem (mbufcp, uiocp, xfer); 211191783Srmacklem else 212191783Srmacklem#endif 213191783Srmacklem if (uiop->uio_segflg == UIO_SYSSPACE) 214191783Srmacklem NFSBCOPY(mbufcp, uiocp, xfer); 215191783Srmacklem else 216191783Srmacklem copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer); 217191783Srmacklem left -= xfer; 218191783Srmacklem len -= xfer; 219191783Srmacklem mbufcp += xfer; 220191783Srmacklem uiocp += xfer; 221191783Srmacklem uiop->uio_offset += xfer; 222191783Srmacklem uiop->uio_resid -= xfer; 223191783Srmacklem } 224191783Srmacklem if (uiop->uio_iov->iov_len <= siz) { 225191783Srmacklem uiop->uio_iovcnt--; 226191783Srmacklem uiop->uio_iov++; 227191783Srmacklem } else { 228191783Srmacklem uiop->uio_iov->iov_base = (void *) 229191783Srmacklem ((char *)uiop->uio_iov->iov_base + uiosiz); 230191783Srmacklem uiop->uio_iov->iov_len -= uiosiz; 231191783Srmacklem } 232191783Srmacklem siz -= uiosiz; 233191783Srmacklem } 234191783Srmacklem nd->nd_dpos = mbufcp; 235191783Srmacklem nd->nd_md = mp; 236191783Srmacklem if (rem > 0) { 237191783Srmacklem if (len < rem) 238191783Srmacklem error = nfsm_advance(nd, rem, len); 239191783Srmacklem else 240191783Srmacklem nd->nd_dpos += rem; 241191783Srmacklem } 242224086Szack 243224086Szackout: 244224086Szack NFSEXITCODE2(error, nd); 245191783Srmacklem return (error); 246191783Srmacklem} 247191783Srmacklem#endif /* !APPLE */ 248191783Srmacklem 249191783Srmacklem/* 250191783Srmacklem * Help break down an mbuf chain by setting the first siz bytes contiguous 251191783Srmacklem * pointed to by returned val. 252191783Srmacklem * This is used by the macro NFSM_DISSECT for tough 253191783Srmacklem * cases. 254191783Srmacklem */ 255191783SrmacklemAPPLESTATIC void * 256251641Skennfsm_dissct(struct nfsrv_descript *nd, int siz, int how) 257191783Srmacklem{ 258191783Srmacklem mbuf_t mp2; 259191783Srmacklem int siz2, xfer; 260191783Srmacklem caddr_t p; 261191783Srmacklem int left; 262191783Srmacklem caddr_t retp; 263191783Srmacklem 264191783Srmacklem retp = NULL; 265191783Srmacklem left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos; 266191783Srmacklem while (left == 0) { 267191783Srmacklem nd->nd_md = mbuf_next(nd->nd_md); 268191783Srmacklem if (nd->nd_md == NULL) 269191783Srmacklem return (retp); 270191783Srmacklem left = mbuf_len(nd->nd_md); 271191783Srmacklem nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); 272191783Srmacklem } 273191783Srmacklem if (left >= siz) { 274191783Srmacklem retp = nd->nd_dpos; 275191783Srmacklem nd->nd_dpos += siz; 276191783Srmacklem } else if (mbuf_next(nd->nd_md) == NULL) { 277191783Srmacklem return (retp); 278191783Srmacklem } else if (siz > ncl_mbuf_mhlen) { 279191783Srmacklem panic("nfs S too big"); 280191783Srmacklem } else { 281251641Sken MGET(mp2, MT_DATA, how); 282251641Sken if (mp2 == NULL) 283251641Sken return (NULL); 284191783Srmacklem mbuf_setnext(mp2, mbuf_next(nd->nd_md)); 285191783Srmacklem mbuf_setnext(nd->nd_md, mp2); 286191783Srmacklem mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left); 287191783Srmacklem nd->nd_md = mp2; 288191783Srmacklem retp = p = NFSMTOD(mp2, caddr_t); 289191783Srmacklem NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */ 290191783Srmacklem siz2 = siz - left; 291191783Srmacklem p += left; 292191783Srmacklem mp2 = mbuf_next(mp2); 293191783Srmacklem /* Loop around copying up the siz2 bytes */ 294191783Srmacklem while (siz2 > 0) { 295191783Srmacklem if (mp2 == NULL) 296191783Srmacklem return (NULL); 297191783Srmacklem xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2; 298191783Srmacklem if (xfer > 0) { 299191783Srmacklem NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer); 300191783Srmacklem NFSM_DATAP(mp2, xfer); 301191783Srmacklem mbuf_setlen(mp2, mbuf_len(mp2) - xfer); 302191783Srmacklem p += xfer; 303191783Srmacklem siz2 -= xfer; 304191783Srmacklem } 305191783Srmacklem if (siz2 > 0) 306191783Srmacklem mp2 = mbuf_next(mp2); 307191783Srmacklem } 308191783Srmacklem mbuf_setlen(nd->nd_md, siz); 309191783Srmacklem nd->nd_md = mp2; 310191783Srmacklem nd->nd_dpos = NFSMTOD(mp2, caddr_t); 311191783Srmacklem } 312191783Srmacklem return (retp); 313191783Srmacklem} 314191783Srmacklem 315191783Srmacklem/* 316191783Srmacklem * Advance the position in the mbuf chain. 317191783Srmacklem * If offs == 0, this is a no-op, but it is simpler to just return from 318191783Srmacklem * here than check for offs > 0 for all calls to nfsm_advance. 319191783Srmacklem * If left == -1, it should be calculated here. 320191783Srmacklem */ 321191783SrmacklemAPPLESTATIC int 322191783Srmacklemnfsm_advance(struct nfsrv_descript *nd, int offs, int left) 323191783Srmacklem{ 324224086Szack int error = 0; 325191783Srmacklem 326191783Srmacklem if (offs == 0) 327224086Szack goto out; 328191783Srmacklem /* 329191783Srmacklem * A negative offs should be considered a serious problem. 330191783Srmacklem */ 331191783Srmacklem if (offs < 0) 332191783Srmacklem panic("nfsrv_advance"); 333191783Srmacklem 334191783Srmacklem /* 335191783Srmacklem * If left == -1, calculate it here. 336191783Srmacklem */ 337191783Srmacklem if (left == -1) 338191783Srmacklem left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - 339191783Srmacklem nd->nd_dpos; 340191783Srmacklem 341191783Srmacklem /* 342191783Srmacklem * Loop around, advancing over the mbuf data. 343191783Srmacklem */ 344191783Srmacklem while (offs > left) { 345191783Srmacklem offs -= left; 346191783Srmacklem nd->nd_md = mbuf_next(nd->nd_md); 347224086Szack if (nd->nd_md == NULL) { 348224086Szack error = EBADRPC; 349224086Szack goto out; 350224086Szack } 351191783Srmacklem left = mbuf_len(nd->nd_md); 352191783Srmacklem nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); 353191783Srmacklem } 354191783Srmacklem nd->nd_dpos += offs; 355224086Szack 356224086Szackout: 357224086Szack NFSEXITCODE(error); 358224086Szack return (error); 359191783Srmacklem} 360191783Srmacklem 361191783Srmacklem/* 362191783Srmacklem * Copy a string into mbuf(s). 363191783Srmacklem * Return the number of bytes output, including XDR overheads. 364191783Srmacklem */ 365191783SrmacklemAPPLESTATIC int 366191783Srmacklemnfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz) 367191783Srmacklem{ 368191783Srmacklem mbuf_t m2; 369191783Srmacklem int xfer, left; 370191783Srmacklem mbuf_t m1; 371191783Srmacklem int rem, bytesize; 372191783Srmacklem u_int32_t *tl; 373191783Srmacklem char *cp2; 374191783Srmacklem 375191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 376191783Srmacklem *tl = txdr_unsigned(siz); 377191783Srmacklem rem = NFSM_RNDUP(siz) - siz; 378191783Srmacklem bytesize = NFSX_UNSIGNED + siz + rem; 379191783Srmacklem m2 = nd->nd_mb; 380191783Srmacklem cp2 = nd->nd_bpos; 381191783Srmacklem left = M_TRAILINGSPACE(m2); 382191783Srmacklem 383191783Srmacklem /* 384191783Srmacklem * Loop around copying the string to mbuf(s). 385191783Srmacklem */ 386191783Srmacklem while (siz > 0) { 387191783Srmacklem if (left == 0) { 388191783Srmacklem if (siz > ncl_mbuf_mlen) 389191783Srmacklem NFSMCLGET(m1, M_WAIT); 390191783Srmacklem else 391191783Srmacklem NFSMGET(m1); 392191783Srmacklem mbuf_setlen(m1, 0); 393191783Srmacklem mbuf_setnext(m2, m1); 394191783Srmacklem m2 = m1; 395191783Srmacklem cp2 = NFSMTOD(m2, caddr_t); 396191783Srmacklem left = M_TRAILINGSPACE(m2); 397191783Srmacklem } 398191783Srmacklem if (left >= siz) 399191783Srmacklem xfer = siz; 400191783Srmacklem else 401191783Srmacklem xfer = left; 402191783Srmacklem NFSBCOPY(cp, cp2, xfer); 403191783Srmacklem cp += xfer; 404191783Srmacklem mbuf_setlen(m2, mbuf_len(m2) + xfer); 405191783Srmacklem siz -= xfer; 406191783Srmacklem left -= xfer; 407191783Srmacklem if (siz == 0 && rem) { 408191783Srmacklem if (left < rem) 409191783Srmacklem panic("nfsm_strtom"); 410191783Srmacklem NFSBZERO(cp2 + xfer, rem); 411191783Srmacklem mbuf_setlen(m2, mbuf_len(m2) + rem); 412191783Srmacklem } 413191783Srmacklem } 414191783Srmacklem nd->nd_mb = m2; 415191783Srmacklem nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); 416191783Srmacklem return (bytesize); 417191783Srmacklem} 418191783Srmacklem 419191783Srmacklem/* 420191783Srmacklem * Called once to initialize data structures... 421191783Srmacklem */ 422191783SrmacklemAPPLESTATIC void 423191783Srmacklemnewnfs_init(void) 424191783Srmacklem{ 425191783Srmacklem static int nfs_inited = 0; 426191783Srmacklem 427191783Srmacklem if (nfs_inited) 428191783Srmacklem return; 429191783Srmacklem nfs_inited = 1; 430191783Srmacklem 431191783Srmacklem newnfs_true = txdr_unsigned(TRUE); 432191783Srmacklem newnfs_false = txdr_unsigned(FALSE); 433191783Srmacklem newnfs_xdrneg1 = txdr_unsigned(-1); 434191783Srmacklem nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 435191783Srmacklem if (nfscl_ticks < 1) 436191783Srmacklem nfscl_ticks = 1; 437191783Srmacklem NFSSETBOOTTIME(nfsboottime); 438191783Srmacklem 439191783Srmacklem /* 440191783Srmacklem * Initialize reply list and start timer 441191783Srmacklem */ 442191783Srmacklem TAILQ_INIT(&nfsd_reqq); 443191783Srmacklem NFS_TIMERINIT; 444191783Srmacklem} 445191783Srmacklem 446191783Srmacklem/* 447191783Srmacklem * Put a file handle in an mbuf list. 448191783Srmacklem * If the size argument == 0, just use the default size. 449191783Srmacklem * set_true == 1 if there should be an newnfs_true prepended on the file handle. 450191783Srmacklem * Return the number of bytes output, including XDR overhead. 451191783Srmacklem */ 452191783SrmacklemAPPLESTATIC int 453191783Srmacklemnfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true) 454191783Srmacklem{ 455191783Srmacklem u_int32_t *tl; 456191783Srmacklem u_int8_t *cp; 457191783Srmacklem int fullsiz, rem, bytesize = 0; 458191783Srmacklem 459191783Srmacklem if (size == 0) 460191783Srmacklem size = NFSX_MYFH; 461191783Srmacklem switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { 462191783Srmacklem case ND_NFSV2: 463191783Srmacklem if (size > NFSX_V2FH) 464191783Srmacklem panic("fh size > NFSX_V2FH for NFSv2"); 465191783Srmacklem NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH); 466191783Srmacklem NFSBCOPY(fhp, cp, size); 467191783Srmacklem if (size < NFSX_V2FH) 468191783Srmacklem NFSBZERO(cp + size, NFSX_V2FH - size); 469191783Srmacklem bytesize = NFSX_V2FH; 470191783Srmacklem break; 471191783Srmacklem case ND_NFSV3: 472191783Srmacklem case ND_NFSV4: 473191783Srmacklem fullsiz = NFSM_RNDUP(size); 474191783Srmacklem rem = fullsiz - size; 475191783Srmacklem if (set_true) { 476191783Srmacklem bytesize = 2 * NFSX_UNSIGNED + fullsiz; 477191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 478191783Srmacklem *tl = newnfs_true; 479191783Srmacklem } else { 480191783Srmacklem bytesize = NFSX_UNSIGNED + fullsiz; 481191783Srmacklem } 482191783Srmacklem (void) nfsm_strtom(nd, fhp, size); 483191783Srmacklem break; 484191783Srmacklem }; 485191783Srmacklem return (bytesize); 486191783Srmacklem} 487191783Srmacklem 488191783Srmacklem/* 489191783Srmacklem * This function compares two net addresses by family and returns TRUE 490191783Srmacklem * if they are the same host. 491191783Srmacklem * If there is any doubt, return FALSE. 492191783Srmacklem * The AF_INET family is handled as a special case so that address mbufs 493191783Srmacklem * don't need to be saved to store "struct in_addr", which is only 4 bytes. 494191783Srmacklem */ 495191783SrmacklemAPPLESTATIC int 496191783Srmacklemnfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam) 497191783Srmacklem{ 498191783Srmacklem struct sockaddr_in *inetaddr; 499191783Srmacklem 500191783Srmacklem switch (family) { 501191783Srmacklem case AF_INET: 502191783Srmacklem inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *); 503191783Srmacklem if (inetaddr->sin_family == AF_INET && 504191783Srmacklem inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr) 505191783Srmacklem return (1); 506191783Srmacklem break; 507191783Srmacklem#ifdef INET6 508191783Srmacklem case AF_INET6: 509191783Srmacklem { 510191783Srmacklem struct sockaddr_in6 *inetaddr6; 511191783Srmacklem 512191783Srmacklem inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *); 513191783Srmacklem /* XXX - should test sin6_scope_id ? */ 514191783Srmacklem if (inetaddr6->sin6_family == AF_INET6 && 515191783Srmacklem IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr, 516191783Srmacklem &haddr->had_inet6)) 517191783Srmacklem return (1); 518191783Srmacklem } 519191783Srmacklem break; 520191783Srmacklem#endif 521191783Srmacklem }; 522191783Srmacklem return (0); 523191783Srmacklem} 524191783Srmacklem 525191783Srmacklem/* 526191783Srmacklem * Similar to the above, but takes to NFSSOCKADDR_T args. 527191783Srmacklem */ 528191783SrmacklemAPPLESTATIC int 529191783Srmacklemnfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2) 530191783Srmacklem{ 531191783Srmacklem struct sockaddr_in *addr1, *addr2; 532191783Srmacklem struct sockaddr *inaddr; 533191783Srmacklem 534191783Srmacklem inaddr = NFSSOCKADDR(nam1, struct sockaddr *); 535191783Srmacklem switch (inaddr->sa_family) { 536191783Srmacklem case AF_INET: 537191783Srmacklem addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *); 538191783Srmacklem addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *); 539191783Srmacklem if (addr2->sin_family == AF_INET && 540191783Srmacklem addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) 541191783Srmacklem return (1); 542191783Srmacklem break; 543191783Srmacklem#ifdef INET6 544191783Srmacklem case AF_INET6: 545191783Srmacklem { 546191783Srmacklem struct sockaddr_in6 *inet6addr1, *inet6addr2; 547191783Srmacklem 548191783Srmacklem inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *); 549191783Srmacklem inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *); 550191783Srmacklem /* XXX - should test sin6_scope_id ? */ 551191783Srmacklem if (inet6addr2->sin6_family == AF_INET6 && 552191783Srmacklem IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 553191783Srmacklem &inet6addr2->sin6_addr)) 554191783Srmacklem return (1); 555191783Srmacklem } 556191783Srmacklem break; 557191783Srmacklem#endif 558191783Srmacklem }; 559191783Srmacklem return (0); 560191783Srmacklem} 561191783Srmacklem 562191783Srmacklem 563191783Srmacklem/* 564191783Srmacklem * Trim the stuff already dissected off the mbuf list. 565191783Srmacklem */ 566191783SrmacklemAPPLESTATIC void 567191783Srmacklemnewnfs_trimleading(nd) 568191783Srmacklem struct nfsrv_descript *nd; 569191783Srmacklem{ 570191783Srmacklem mbuf_t m, n; 571191783Srmacklem int offs; 572191783Srmacklem 573191783Srmacklem /* 574191783Srmacklem * First, free up leading mbufs. 575191783Srmacklem */ 576191783Srmacklem if (nd->nd_mrep != nd->nd_md) { 577191783Srmacklem m = nd->nd_mrep; 578191783Srmacklem while (mbuf_next(m) != nd->nd_md) { 579191783Srmacklem if (mbuf_next(m) == NULL) 580191783Srmacklem panic("nfsm trim leading"); 581191783Srmacklem m = mbuf_next(m); 582191783Srmacklem } 583191783Srmacklem mbuf_setnext(m, NULL); 584191783Srmacklem mbuf_freem(nd->nd_mrep); 585191783Srmacklem } 586191783Srmacklem m = nd->nd_md; 587191783Srmacklem 588191783Srmacklem /* 589191783Srmacklem * Now, adjust this mbuf, based on nd_dpos. 590191783Srmacklem */ 591191783Srmacklem offs = nd->nd_dpos - NFSMTOD(m, caddr_t); 592191783Srmacklem if (offs == mbuf_len(m)) { 593191783Srmacklem n = m; 594191783Srmacklem m = mbuf_next(m); 595191783Srmacklem if (m == NULL) 596191783Srmacklem panic("nfsm trim leading2"); 597191783Srmacklem mbuf_setnext(n, NULL); 598191783Srmacklem mbuf_freem(n); 599191783Srmacklem } else if (offs > 0) { 600191783Srmacklem mbuf_setlen(m, mbuf_len(m) - offs); 601191783Srmacklem NFSM_DATAP(m, offs); 602191783Srmacklem } else if (offs < 0) 603191783Srmacklem panic("nfsm trimleading offs"); 604191783Srmacklem nd->nd_mrep = m; 605191783Srmacklem nd->nd_md = m; 606191783Srmacklem nd->nd_dpos = NFSMTOD(m, caddr_t); 607191783Srmacklem} 608191783Srmacklem 609191783Srmacklem/* 610191783Srmacklem * Trim trailing data off the mbuf list being built. 611191783Srmacklem */ 612191783SrmacklemAPPLESTATIC void 613191783Srmacklemnewnfs_trimtrailing(nd, mb, bpos) 614191783Srmacklem struct nfsrv_descript *nd; 615191783Srmacklem mbuf_t mb; 616191783Srmacklem caddr_t bpos; 617191783Srmacklem{ 618191783Srmacklem 619191783Srmacklem if (mbuf_next(mb)) { 620191783Srmacklem mbuf_freem(mbuf_next(mb)); 621191783Srmacklem mbuf_setnext(mb, NULL); 622191783Srmacklem } 623191783Srmacklem mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t)); 624191783Srmacklem nd->nd_mb = mb; 625191783Srmacklem nd->nd_bpos = bpos; 626191783Srmacklem} 627191783Srmacklem 628191783Srmacklem/* 629191783Srmacklem * Dissect a file handle on the client. 630191783Srmacklem */ 631191783SrmacklemAPPLESTATIC int 632191783Srmacklemnfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp) 633191783Srmacklem{ 634191783Srmacklem u_int32_t *tl; 635191783Srmacklem struct nfsfh *nfhp; 636191783Srmacklem int error, len; 637191783Srmacklem 638191783Srmacklem *nfhpp = NULL; 639191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 640191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 641191783Srmacklem if ((len = fxdr_unsigned(int, *tl)) <= 0 || 642224086Szack len > NFSX_FHMAX) { 643224086Szack error = EBADRPC; 644224086Szack goto nfsmout; 645224086Szack } 646191783Srmacklem } else 647191783Srmacklem len = NFSX_V2FH; 648191783Srmacklem MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len, 649191783Srmacklem M_NFSFH, M_WAITOK); 650191783Srmacklem error = nfsrv_mtostr(nd, nfhp->nfh_fh, len); 651191783Srmacklem if (error) { 652191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 653224086Szack goto nfsmout; 654191783Srmacklem } 655191783Srmacklem nfhp->nfh_len = len; 656191783Srmacklem *nfhpp = nfhp; 657191783Srmacklemnfsmout: 658224086Szack NFSEXITCODE2(error, nd); 659191783Srmacklem return (error); 660191783Srmacklem} 661191783Srmacklem 662191783Srmacklem/* 663191783Srmacklem * Break down the nfsv4 acl. 664191783Srmacklem * If the aclp == NULL or won't fit in an acl, just discard the acl info. 665191783Srmacklem */ 666191783SrmacklemAPPLESTATIC int 667191783Srmacklemnfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp, 668191783Srmacklem int *aclsizep, __unused NFSPROC_T *p) 669191783Srmacklem{ 670191783Srmacklem u_int32_t *tl; 671191783Srmacklem int i, aclsize; 672191783Srmacklem int acecnt, error = 0, aceerr = 0, acesize; 673191783Srmacklem 674191783Srmacklem *aclerrp = 0; 675191783Srmacklem if (aclp) 676191783Srmacklem aclp->acl_cnt = 0; 677191783Srmacklem /* 678191783Srmacklem * Parse out the ace entries and expect them to conform to 679191783Srmacklem * what can be supported by R/W/X bits. 680191783Srmacklem */ 681191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 682191783Srmacklem aclsize = NFSX_UNSIGNED; 683191783Srmacklem acecnt = fxdr_unsigned(int, *tl); 684191783Srmacklem if (acecnt > ACL_MAX_ENTRIES) 685224077Szack aceerr = NFSERR_ATTRNOTSUPP; 686191783Srmacklem if (nfsrv_useacl == 0) 687224077Szack aceerr = NFSERR_ATTRNOTSUPP; 688191783Srmacklem for (i = 0; i < acecnt; i++) { 689191783Srmacklem if (aclp && !aceerr) 690191783Srmacklem error = nfsrv_dissectace(nd, &aclp->acl_entry[i], 691191783Srmacklem &aceerr, &acesize, p); 692191783Srmacklem else 693191783Srmacklem error = nfsrv_skipace(nd, &acesize); 694191783Srmacklem if (error) 695224086Szack goto nfsmout; 696191783Srmacklem aclsize += acesize; 697191783Srmacklem } 698191783Srmacklem if (aclp && !aceerr) 699191783Srmacklem aclp->acl_cnt = acecnt; 700191783Srmacklem if (aceerr) 701191783Srmacklem *aclerrp = aceerr; 702191783Srmacklem if (aclsizep) 703191783Srmacklem *aclsizep = aclsize; 704191783Srmacklemnfsmout: 705224086Szack NFSEXITCODE2(error, nd); 706191783Srmacklem return (error); 707191783Srmacklem} 708191783Srmacklem 709191783Srmacklem/* 710191783Srmacklem * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it. 711191783Srmacklem */ 712191783Srmacklemstatic int 713191783Srmacklemnfsrv_skipace(struct nfsrv_descript *nd, int *acesizep) 714191783Srmacklem{ 715191783Srmacklem u_int32_t *tl; 716191783Srmacklem int error, len = 0; 717191783Srmacklem 718191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 719191783Srmacklem len = fxdr_unsigned(int, *(tl + 3)); 720191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 721191783Srmacklemnfsmout: 722191783Srmacklem *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); 723224086Szack NFSEXITCODE2(error, nd); 724191783Srmacklem return (error); 725191783Srmacklem} 726191783Srmacklem 727191783Srmacklem/* 728191783Srmacklem * Get attribute bits from an mbuf list. 729191783Srmacklem * Returns EBADRPC for a parsing error, 0 otherwise. 730191783Srmacklem * If the clearinvalid flag is set, clear the bits not supported. 731191783Srmacklem */ 732191783SrmacklemAPPLESTATIC int 733191783Srmacklemnfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp, 734191783Srmacklem int *retnotsupp) 735191783Srmacklem{ 736191783Srmacklem u_int32_t *tl; 737191783Srmacklem int cnt, i, outcnt; 738191783Srmacklem int error = 0; 739191783Srmacklem 740191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 741191783Srmacklem cnt = fxdr_unsigned(int, *tl); 742224086Szack if (cnt < 0) { 743224086Szack error = NFSERR_BADXDR; 744224086Szack goto nfsmout; 745224086Szack } 746253608Srmacklem if (cnt > NFSATTRBIT_MAXWORDS) 747191783Srmacklem outcnt = NFSATTRBIT_MAXWORDS; 748253608Srmacklem else 749191783Srmacklem outcnt = cnt; 750191783Srmacklem NFSZERO_ATTRBIT(attrbitp); 751191783Srmacklem if (outcnt > 0) { 752191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED); 753191783Srmacklem for (i = 0; i < outcnt; i++) 754191783Srmacklem attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++); 755191783Srmacklem } 756253608Srmacklem for (i = 0; i < (cnt - outcnt); i++) { 757253608Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 758253608Srmacklem if (retnotsupp != NULL && *tl != 0) 759253608Srmacklem *retnotsupp = NFSERR_ATTRNOTSUPP; 760253608Srmacklem } 761191783Srmacklem if (cntp) 762191783Srmacklem *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED); 763191783Srmacklemnfsmout: 764224086Szack NFSEXITCODE2(error, nd); 765191783Srmacklem return (error); 766191783Srmacklem} 767191783Srmacklem 768191783Srmacklem/* 769191783Srmacklem * Get the attributes for V4. 770191783Srmacklem * If the compare flag is true, test for any attribute changes, 771191783Srmacklem * otherwise return the attribute values. 772191783Srmacklem * These attributes cover fields in "struct vattr", "struct statfs", 773191783Srmacklem * "struct nfsfsinfo", the file handle and the lease duration. 774191783Srmacklem * The value of retcmpp is set to 1 if all attributes are the same, 775191783Srmacklem * and 0 otherwise. 776191783Srmacklem * Returns EBADRPC if it can't be parsed, 0 otherwise. 777191783Srmacklem */ 778191783SrmacklemAPPLESTATIC int 779191783Srmacklemnfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, 780191783Srmacklem struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize, 781191783Srmacklem struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp, 782191783Srmacklem struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp, 783191783Srmacklem u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred) 784191783Srmacklem{ 785191783Srmacklem u_int32_t *tl; 786224086Szack int i = 0, j, k, l = 0, m, bitpos, attrsum = 0; 787191783Srmacklem int error, tfhsize, aceerr, attrsize, cnt, retnotsup; 788191783Srmacklem u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1]; 789191783Srmacklem nfsattrbit_t attrbits, retattrbits, checkattrbits; 790191783Srmacklem struct nfsfh *tnfhp; 791191783Srmacklem struct nfsreferral *refp; 792191783Srmacklem u_quad_t tquad; 793191783Srmacklem nfsquad_t tnfsquad; 794191783Srmacklem struct timespec temptime; 795191783Srmacklem uid_t uid; 796191783Srmacklem gid_t gid; 797191783Srmacklem long fid; 798191783Srmacklem u_int32_t freenum = 0, tuint; 799191783Srmacklem u_int64_t uquad = 0, thyp, thyp2; 800191783Srmacklem#ifdef QUOTA 801191783Srmacklem struct dqblk dqb; 802191783Srmacklem uid_t savuid; 803191783Srmacklem#endif 804191783Srmacklem 805191783Srmacklem if (compare) { 806191783Srmacklem retnotsup = 0; 807191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); 808191783Srmacklem } else { 809191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 810191783Srmacklem } 811191783Srmacklem if (error) 812224086Szack goto nfsmout; 813191783Srmacklem 814191783Srmacklem if (compare) { 815191783Srmacklem *retcmpp = retnotsup; 816191783Srmacklem } else { 817191783Srmacklem /* 818191783Srmacklem * Just set default values to some of the important ones. 819191783Srmacklem */ 820191783Srmacklem if (nap != NULL) { 821191783Srmacklem nap->na_type = VREG; 822191783Srmacklem nap->na_mode = 0; 823191783Srmacklem nap->na_rdev = (NFSDEV_T)0; 824191783Srmacklem nap->na_mtime.tv_sec = 0; 825191783Srmacklem nap->na_mtime.tv_nsec = 0; 826191783Srmacklem nap->na_gen = 0; 827191783Srmacklem nap->na_flags = 0; 828191783Srmacklem nap->na_blocksize = NFS_FABLKSIZE; 829191783Srmacklem } 830191783Srmacklem if (sbp != NULL) { 831191783Srmacklem sbp->f_bsize = NFS_FABLKSIZE; 832191783Srmacklem sbp->f_blocks = 0; 833191783Srmacklem sbp->f_bfree = 0; 834191783Srmacklem sbp->f_bavail = 0; 835191783Srmacklem sbp->f_files = 0; 836191783Srmacklem sbp->f_ffree = 0; 837191783Srmacklem } 838191783Srmacklem if (fsp != NULL) { 839191783Srmacklem fsp->fs_rtmax = 8192; 840191783Srmacklem fsp->fs_rtpref = 8192; 841191783Srmacklem fsp->fs_maxname = NFS_MAXNAMLEN; 842191783Srmacklem fsp->fs_wtmax = 8192; 843191783Srmacklem fsp->fs_wtpref = 8192; 844191783Srmacklem fsp->fs_wtmult = NFS_FABLKSIZE; 845191783Srmacklem fsp->fs_dtpref = 8192; 846191783Srmacklem fsp->fs_maxfilesize = 0xffffffffffffffffull; 847191783Srmacklem fsp->fs_timedelta.tv_sec = 0; 848191783Srmacklem fsp->fs_timedelta.tv_nsec = 1; 849191783Srmacklem fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK | 850191783Srmacklem NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME); 851191783Srmacklem } 852191783Srmacklem if (pc != NULL) { 853191783Srmacklem pc->pc_linkmax = LINK_MAX; 854191783Srmacklem pc->pc_namemax = NAME_MAX; 855191783Srmacklem pc->pc_notrunc = 0; 856191783Srmacklem pc->pc_chownrestricted = 0; 857191783Srmacklem pc->pc_caseinsensitive = 0; 858191783Srmacklem pc->pc_casepreserving = 1; 859191783Srmacklem } 860191783Srmacklem } 861191783Srmacklem 862191783Srmacklem /* 863191783Srmacklem * Loop around getting the attributes. 864191783Srmacklem */ 865191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 866191783Srmacklem attrsize = fxdr_unsigned(int, *tl); 867191783Srmacklem for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 868191783Srmacklem if (attrsum > attrsize) { 869191783Srmacklem error = NFSERR_BADXDR; 870191783Srmacklem goto nfsmout; 871191783Srmacklem } 872191783Srmacklem if (NFSISSET_ATTRBIT(&attrbits, bitpos)) 873191783Srmacklem switch (bitpos) { 874191783Srmacklem case NFSATTRBIT_SUPPORTEDATTRS: 875191783Srmacklem retnotsup = 0; 876191783Srmacklem if (compare || nap == NULL) 877191783Srmacklem error = nfsrv_getattrbits(nd, &retattrbits, 878191783Srmacklem &cnt, &retnotsup); 879191783Srmacklem else 880191783Srmacklem error = nfsrv_getattrbits(nd, &nap->na_suppattr, 881191783Srmacklem &cnt, &retnotsup); 882191783Srmacklem if (error) 883224086Szack goto nfsmout; 884191783Srmacklem if (compare && !(*retcmpp)) { 885191783Srmacklem NFSSETSUPP_ATTRBIT(&checkattrbits); 886191783Srmacklem if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 887191783Srmacklem || retnotsup) 888191783Srmacklem *retcmpp = NFSERR_NOTSAME; 889191783Srmacklem } 890191783Srmacklem attrsum += cnt; 891191783Srmacklem break; 892191783Srmacklem case NFSATTRBIT_TYPE: 893191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 894191783Srmacklem if (compare) { 895191783Srmacklem if (!(*retcmpp)) { 896191783Srmacklem if (nap->na_type != nfsv34tov_type(*tl)) 897191783Srmacklem *retcmpp = NFSERR_NOTSAME; 898191783Srmacklem } 899191783Srmacklem } else if (nap != NULL) { 900191783Srmacklem nap->na_type = nfsv34tov_type(*tl); 901191783Srmacklem } 902191783Srmacklem attrsum += NFSX_UNSIGNED; 903191783Srmacklem break; 904191783Srmacklem case NFSATTRBIT_FHEXPIRETYPE: 905191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 906191783Srmacklem if (compare && !(*retcmpp)) { 907191783Srmacklem if (fxdr_unsigned(int, *tl) != 908191783Srmacklem NFSV4FHTYPE_PERSISTENT) 909191783Srmacklem *retcmpp = NFSERR_NOTSAME; 910191783Srmacklem } 911191783Srmacklem attrsum += NFSX_UNSIGNED; 912191783Srmacklem break; 913191783Srmacklem case NFSATTRBIT_CHANGE: 914191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 915191783Srmacklem if (compare) { 916191783Srmacklem if (!(*retcmpp)) { 917191783Srmacklem if (nap->na_filerev != fxdr_hyper(tl)) 918191783Srmacklem *retcmpp = NFSERR_NOTSAME; 919191783Srmacklem } 920191783Srmacklem } else if (nap != NULL) { 921191783Srmacklem nap->na_filerev = fxdr_hyper(tl); 922191783Srmacklem } 923191783Srmacklem attrsum += NFSX_HYPER; 924191783Srmacklem break; 925191783Srmacklem case NFSATTRBIT_SIZE: 926191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 927191783Srmacklem if (compare) { 928191783Srmacklem if (!(*retcmpp)) { 929191783Srmacklem if (nap->na_size != fxdr_hyper(tl)) 930191783Srmacklem *retcmpp = NFSERR_NOTSAME; 931191783Srmacklem } 932191783Srmacklem } else if (nap != NULL) { 933191783Srmacklem nap->na_size = fxdr_hyper(tl); 934191783Srmacklem } 935191783Srmacklem attrsum += NFSX_HYPER; 936191783Srmacklem break; 937191783Srmacklem case NFSATTRBIT_LINKSUPPORT: 938191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 939191783Srmacklem if (compare) { 940191783Srmacklem if (!(*retcmpp)) { 941191783Srmacklem if (fsp->fs_properties & NFSV3_FSFLINK) { 942191783Srmacklem if (*tl == newnfs_false) 943191783Srmacklem *retcmpp = NFSERR_NOTSAME; 944191783Srmacklem } else { 945191783Srmacklem if (*tl == newnfs_true) 946191783Srmacklem *retcmpp = NFSERR_NOTSAME; 947191783Srmacklem } 948191783Srmacklem } 949191783Srmacklem } else if (fsp != NULL) { 950191783Srmacklem if (*tl == newnfs_true) 951191783Srmacklem fsp->fs_properties |= NFSV3_FSFLINK; 952191783Srmacklem else 953191783Srmacklem fsp->fs_properties &= ~NFSV3_FSFLINK; 954191783Srmacklem } 955191783Srmacklem attrsum += NFSX_UNSIGNED; 956191783Srmacklem break; 957191783Srmacklem case NFSATTRBIT_SYMLINKSUPPORT: 958191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 959191783Srmacklem if (compare) { 960191783Srmacklem if (!(*retcmpp)) { 961191783Srmacklem if (fsp->fs_properties & NFSV3_FSFSYMLINK) { 962191783Srmacklem if (*tl == newnfs_false) 963191783Srmacklem *retcmpp = NFSERR_NOTSAME; 964191783Srmacklem } else { 965191783Srmacklem if (*tl == newnfs_true) 966191783Srmacklem *retcmpp = NFSERR_NOTSAME; 967191783Srmacklem } 968191783Srmacklem } 969191783Srmacklem } else if (fsp != NULL) { 970191783Srmacklem if (*tl == newnfs_true) 971191783Srmacklem fsp->fs_properties |= NFSV3_FSFSYMLINK; 972191783Srmacklem else 973191783Srmacklem fsp->fs_properties &= ~NFSV3_FSFSYMLINK; 974191783Srmacklem } 975191783Srmacklem attrsum += NFSX_UNSIGNED; 976191783Srmacklem break; 977191783Srmacklem case NFSATTRBIT_NAMEDATTR: 978191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 979191783Srmacklem if (compare && !(*retcmpp)) { 980191783Srmacklem if (*tl != newnfs_false) 981191783Srmacklem *retcmpp = NFSERR_NOTSAME; 982191783Srmacklem } 983191783Srmacklem attrsum += NFSX_UNSIGNED; 984191783Srmacklem break; 985191783Srmacklem case NFSATTRBIT_FSID: 986191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 987191783Srmacklem thyp = fxdr_hyper(tl); 988191783Srmacklem tl += 2; 989191783Srmacklem thyp2 = fxdr_hyper(tl); 990191783Srmacklem if (compare) { 991191783Srmacklem if (*retcmpp == 0) { 992191783Srmacklem if (thyp != (u_int64_t) 993191783Srmacklem vfs_statfs(vnode_mount(vp))->f_fsid.val[0] || 994191783Srmacklem thyp2 != (u_int64_t) 995191783Srmacklem vfs_statfs(vnode_mount(vp))->f_fsid.val[1]) 996191783Srmacklem *retcmpp = NFSERR_NOTSAME; 997191783Srmacklem } 998191783Srmacklem } else if (nap != NULL) { 999191783Srmacklem nap->na_filesid[0] = thyp; 1000191783Srmacklem nap->na_filesid[1] = thyp2; 1001191783Srmacklem } 1002191783Srmacklem attrsum += (4 * NFSX_UNSIGNED); 1003191783Srmacklem break; 1004191783Srmacklem case NFSATTRBIT_UNIQUEHANDLES: 1005191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1006191783Srmacklem if (compare && !(*retcmpp)) { 1007191783Srmacklem if (*tl != newnfs_true) 1008191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1009191783Srmacklem } 1010191783Srmacklem attrsum += NFSX_UNSIGNED; 1011191783Srmacklem break; 1012191783Srmacklem case NFSATTRBIT_LEASETIME: 1013191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1014191783Srmacklem if (compare) { 1015191783Srmacklem if (fxdr_unsigned(int, *tl) != nfsrv_lease && 1016191783Srmacklem !(*retcmpp)) 1017191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1018191783Srmacklem } else if (leasep != NULL) { 1019191783Srmacklem *leasep = fxdr_unsigned(u_int32_t, *tl); 1020191783Srmacklem } 1021191783Srmacklem attrsum += NFSX_UNSIGNED; 1022191783Srmacklem break; 1023191783Srmacklem case NFSATTRBIT_RDATTRERROR: 1024191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1025191783Srmacklem if (compare) { 1026191783Srmacklem if (!(*retcmpp)) 1027191783Srmacklem *retcmpp = NFSERR_INVAL; 1028191783Srmacklem } else if (rderrp != NULL) { 1029191783Srmacklem *rderrp = fxdr_unsigned(u_int32_t, *tl); 1030191783Srmacklem } 1031191783Srmacklem attrsum += NFSX_UNSIGNED; 1032191783Srmacklem break; 1033191783Srmacklem case NFSATTRBIT_ACL: 1034191783Srmacklem if (compare) { 1035191783Srmacklem if (!(*retcmpp)) { 1036191783Srmacklem if (nfsrv_useacl) { 1037191783Srmacklem NFSACL_T *naclp; 1038191783Srmacklem 1039192861Srmacklem naclp = acl_alloc(M_WAITOK); 1040191783Srmacklem error = nfsrv_dissectacl(nd, naclp, &aceerr, 1041191783Srmacklem &cnt, p); 1042191783Srmacklem if (error) { 1043191783Srmacklem acl_free(naclp); 1044224086Szack goto nfsmout; 1045191783Srmacklem } 1046224121Szack if (aceerr || aclp == NULL || 1047224121Szack nfsrv_compareacl(aclp, naclp)) 1048191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1049191783Srmacklem acl_free(naclp); 1050200069Strasz } else { 1051191783Srmacklem error = nfsrv_dissectacl(nd, NULL, &aceerr, 1052191783Srmacklem &cnt, p); 1053191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1054191783Srmacklem } 1055191783Srmacklem } 1056191783Srmacklem } else { 1057191783Srmacklem if (vp != NULL && aclp != NULL) 1058191783Srmacklem error = nfsrv_dissectacl(nd, aclp, &aceerr, 1059191783Srmacklem &cnt, p); 1060191783Srmacklem else 1061191783Srmacklem error = nfsrv_dissectacl(nd, NULL, &aceerr, 1062191783Srmacklem &cnt, p); 1063191783Srmacklem if (error) 1064224086Szack goto nfsmout; 1065191783Srmacklem } 1066191783Srmacklem attrsum += cnt; 1067191783Srmacklem break; 1068191783Srmacklem case NFSATTRBIT_ACLSUPPORT: 1069191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1070191783Srmacklem if (compare && !(*retcmpp)) { 1071191783Srmacklem if (nfsrv_useacl) { 1072191783Srmacklem if (fxdr_unsigned(u_int32_t, *tl) != 1073191783Srmacklem NFSV4ACE_SUPTYPES) 1074191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1075191783Srmacklem } else { 1076191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1077191783Srmacklem } 1078191783Srmacklem } 1079191783Srmacklem attrsum += NFSX_UNSIGNED; 1080191783Srmacklem break; 1081191783Srmacklem case NFSATTRBIT_ARCHIVE: 1082191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1083191783Srmacklem if (compare && !(*retcmpp)) 1084191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1085191783Srmacklem attrsum += NFSX_UNSIGNED; 1086191783Srmacklem break; 1087191783Srmacklem case NFSATTRBIT_CANSETTIME: 1088191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1089191783Srmacklem if (compare) { 1090191783Srmacklem if (!(*retcmpp)) { 1091191783Srmacklem if (fsp->fs_properties & NFSV3_FSFCANSETTIME) { 1092191783Srmacklem if (*tl == newnfs_false) 1093191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1094191783Srmacklem } else { 1095191783Srmacklem if (*tl == newnfs_true) 1096191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1097191783Srmacklem } 1098191783Srmacklem } 1099191783Srmacklem } else if (fsp != NULL) { 1100191783Srmacklem if (*tl == newnfs_true) 1101191783Srmacklem fsp->fs_properties |= NFSV3_FSFCANSETTIME; 1102191783Srmacklem else 1103191783Srmacklem fsp->fs_properties &= ~NFSV3_FSFCANSETTIME; 1104191783Srmacklem } 1105191783Srmacklem attrsum += NFSX_UNSIGNED; 1106191783Srmacklem break; 1107191783Srmacklem case NFSATTRBIT_CASEINSENSITIVE: 1108191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1109191783Srmacklem if (compare) { 1110191783Srmacklem if (!(*retcmpp)) { 1111191783Srmacklem if (*tl != newnfs_false) 1112191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1113191783Srmacklem } 1114191783Srmacklem } else if (pc != NULL) { 1115191783Srmacklem pc->pc_caseinsensitive = 1116191783Srmacklem fxdr_unsigned(u_int32_t, *tl); 1117191783Srmacklem } 1118191783Srmacklem attrsum += NFSX_UNSIGNED; 1119191783Srmacklem break; 1120191783Srmacklem case NFSATTRBIT_CASEPRESERVING: 1121191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1122191783Srmacklem if (compare) { 1123191783Srmacklem if (!(*retcmpp)) { 1124191783Srmacklem if (*tl != newnfs_true) 1125191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1126191783Srmacklem } 1127191783Srmacklem } else if (pc != NULL) { 1128191783Srmacklem pc->pc_casepreserving = 1129191783Srmacklem fxdr_unsigned(u_int32_t, *tl); 1130191783Srmacklem } 1131191783Srmacklem attrsum += NFSX_UNSIGNED; 1132191783Srmacklem break; 1133191783Srmacklem case NFSATTRBIT_CHOWNRESTRICTED: 1134191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1135191783Srmacklem if (compare) { 1136191783Srmacklem if (!(*retcmpp)) { 1137224121Szack if (*tl != newnfs_true) 1138224121Szack *retcmpp = NFSERR_NOTSAME; 1139191783Srmacklem } 1140191783Srmacklem } else if (pc != NULL) { 1141191783Srmacklem pc->pc_chownrestricted = 1142191783Srmacklem fxdr_unsigned(u_int32_t, *tl); 1143191783Srmacklem } 1144191783Srmacklem attrsum += NFSX_UNSIGNED; 1145191783Srmacklem break; 1146191783Srmacklem case NFSATTRBIT_FILEHANDLE: 1147191783Srmacklem error = nfsm_getfh(nd, &tnfhp); 1148191783Srmacklem if (error) 1149224086Szack goto nfsmout; 1150191783Srmacklem tfhsize = tnfhp->nfh_len; 1151191783Srmacklem if (compare) { 1152191783Srmacklem if (!(*retcmpp) && 1153191783Srmacklem !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize, 1154191783Srmacklem fhp, fhsize)) 1155191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1156191783Srmacklem FREE((caddr_t)tnfhp, M_NFSFH); 1157191783Srmacklem } else if (nfhpp != NULL) { 1158191783Srmacklem *nfhpp = tnfhp; 1159191783Srmacklem } else { 1160191783Srmacklem FREE((caddr_t)tnfhp, M_NFSFH); 1161191783Srmacklem } 1162191783Srmacklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize)); 1163191783Srmacklem break; 1164191783Srmacklem case NFSATTRBIT_FILEID: 1165191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1166191783Srmacklem thyp = fxdr_hyper(tl); 1167191783Srmacklem if (compare) { 1168191783Srmacklem if (!(*retcmpp)) { 1169191783Srmacklem if ((u_int64_t)nap->na_fileid != thyp) 1170191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1171191783Srmacklem } 1172191783Srmacklem } else if (nap != NULL) { 1173191783Srmacklem if (*tl++) 1174191783Srmacklem printf("NFSv4 fileid > 32bits\n"); 1175191783Srmacklem nap->na_fileid = thyp; 1176191783Srmacklem } 1177191783Srmacklem attrsum += NFSX_HYPER; 1178191783Srmacklem break; 1179191783Srmacklem case NFSATTRBIT_FILESAVAIL: 1180191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1181191783Srmacklem if (compare) { 1182191783Srmacklem if (!(*retcmpp) && 1183191783Srmacklem sfp->sf_afiles != fxdr_hyper(tl)) 1184191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1185191783Srmacklem } else if (sfp != NULL) { 1186191783Srmacklem sfp->sf_afiles = fxdr_hyper(tl); 1187191783Srmacklem } 1188191783Srmacklem attrsum += NFSX_HYPER; 1189191783Srmacklem break; 1190191783Srmacklem case NFSATTRBIT_FILESFREE: 1191191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1192191783Srmacklem if (compare) { 1193191783Srmacklem if (!(*retcmpp) && 1194191783Srmacklem sfp->sf_ffiles != fxdr_hyper(tl)) 1195191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1196191783Srmacklem } else if (sfp != NULL) { 1197191783Srmacklem sfp->sf_ffiles = fxdr_hyper(tl); 1198191783Srmacklem } 1199191783Srmacklem attrsum += NFSX_HYPER; 1200191783Srmacklem break; 1201191783Srmacklem case NFSATTRBIT_FILESTOTAL: 1202191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1203191783Srmacklem if (compare) { 1204191783Srmacklem if (!(*retcmpp) && 1205191783Srmacklem sfp->sf_tfiles != fxdr_hyper(tl)) 1206191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1207191783Srmacklem } else if (sfp != NULL) { 1208191783Srmacklem sfp->sf_tfiles = fxdr_hyper(tl); 1209191783Srmacklem } 1210191783Srmacklem attrsum += NFSX_HYPER; 1211191783Srmacklem break; 1212191783Srmacklem case NFSATTRBIT_FSLOCATIONS: 1213191783Srmacklem error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m); 1214191783Srmacklem if (error) 1215224086Szack goto nfsmout; 1216191783Srmacklem attrsum += l; 1217191783Srmacklem if (compare && !(*retcmpp)) { 1218191783Srmacklem refp = nfsv4root_getreferral(vp, NULL, 0); 1219191783Srmacklem if (refp != NULL) { 1220191783Srmacklem if (cp == NULL || cp2 == NULL || 1221191783Srmacklem strcmp(cp, "/") || 1222191783Srmacklem strcmp(cp2, refp->nfr_srvlist)) 1223191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1224191783Srmacklem } else if (m == 0) { 1225191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1226191783Srmacklem } 1227191783Srmacklem } 1228191783Srmacklem if (cp != NULL) 1229191783Srmacklem free(cp, M_NFSSTRING); 1230191783Srmacklem if (cp2 != NULL) 1231191783Srmacklem free(cp2, M_NFSSTRING); 1232191783Srmacklem break; 1233191783Srmacklem case NFSATTRBIT_HIDDEN: 1234191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1235191783Srmacklem if (compare && !(*retcmpp)) 1236191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1237191783Srmacklem attrsum += NFSX_UNSIGNED; 1238191783Srmacklem break; 1239191783Srmacklem case NFSATTRBIT_HOMOGENEOUS: 1240191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1241191783Srmacklem if (compare) { 1242191783Srmacklem if (!(*retcmpp)) { 1243191783Srmacklem if (fsp->fs_properties & 1244191783Srmacklem NFSV3_FSFHOMOGENEOUS) { 1245191783Srmacklem if (*tl == newnfs_false) 1246191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1247191783Srmacklem } else { 1248191783Srmacklem if (*tl == newnfs_true) 1249191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1250191783Srmacklem } 1251191783Srmacklem } 1252191783Srmacklem } else if (fsp != NULL) { 1253191783Srmacklem if (*tl == newnfs_true) 1254191783Srmacklem fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS; 1255191783Srmacklem else 1256191783Srmacklem fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS; 1257191783Srmacklem } 1258191783Srmacklem attrsum += NFSX_UNSIGNED; 1259191783Srmacklem break; 1260191783Srmacklem case NFSATTRBIT_MAXFILESIZE: 1261191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1262191783Srmacklem tnfsquad.qval = fxdr_hyper(tl); 1263191783Srmacklem if (compare) { 1264191783Srmacklem if (!(*retcmpp)) { 1265191783Srmacklem tquad = NFSRV_MAXFILESIZE; 1266191783Srmacklem if (tquad != tnfsquad.qval) 1267191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1268191783Srmacklem } 1269191783Srmacklem } else if (fsp != NULL) { 1270191783Srmacklem fsp->fs_maxfilesize = tnfsquad.qval; 1271191783Srmacklem } 1272191783Srmacklem attrsum += NFSX_HYPER; 1273191783Srmacklem break; 1274191783Srmacklem case NFSATTRBIT_MAXLINK: 1275191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1276191783Srmacklem if (compare) { 1277191783Srmacklem if (!(*retcmpp)) { 1278191783Srmacklem if (fxdr_unsigned(int, *tl) != LINK_MAX) 1279191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1280191783Srmacklem } 1281191783Srmacklem } else if (pc != NULL) { 1282191783Srmacklem pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl); 1283191783Srmacklem } 1284191783Srmacklem attrsum += NFSX_UNSIGNED; 1285191783Srmacklem break; 1286191783Srmacklem case NFSATTRBIT_MAXNAME: 1287191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1288191783Srmacklem if (compare) { 1289191783Srmacklem if (!(*retcmpp)) { 1290191783Srmacklem if (fsp->fs_maxname != 1291191783Srmacklem fxdr_unsigned(u_int32_t, *tl)) 1292191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1293191783Srmacklem } 1294191783Srmacklem } else { 1295191783Srmacklem tuint = fxdr_unsigned(u_int32_t, *tl); 1296191783Srmacklem /* 1297191783Srmacklem * Some Linux NFSv4 servers report this 1298191783Srmacklem * as 0 or 4billion, so I'll set it to 1299191783Srmacklem * NFS_MAXNAMLEN. If a server actually creates 1300191783Srmacklem * a name longer than NFS_MAXNAMLEN, it will 1301191783Srmacklem * get an error back. 1302191783Srmacklem */ 1303191783Srmacklem if (tuint == 0 || tuint > NFS_MAXNAMLEN) 1304191783Srmacklem tuint = NFS_MAXNAMLEN; 1305191783Srmacklem if (fsp != NULL) 1306191783Srmacklem fsp->fs_maxname = tuint; 1307191783Srmacklem if (pc != NULL) 1308191783Srmacklem pc->pc_namemax = tuint; 1309191783Srmacklem } 1310191783Srmacklem attrsum += NFSX_UNSIGNED; 1311191783Srmacklem break; 1312191783Srmacklem case NFSATTRBIT_MAXREAD: 1313191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1314191783Srmacklem if (compare) { 1315191783Srmacklem if (!(*retcmpp)) { 1316191783Srmacklem if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t, 1317191783Srmacklem *(tl + 1)) || *tl != 0) 1318191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1319191783Srmacklem } 1320191783Srmacklem } else if (fsp != NULL) { 1321191783Srmacklem fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl); 1322191783Srmacklem fsp->fs_rtpref = fsp->fs_rtmax; 1323191783Srmacklem fsp->fs_dtpref = fsp->fs_rtpref; 1324191783Srmacklem } 1325191783Srmacklem attrsum += NFSX_HYPER; 1326191783Srmacklem break; 1327191783Srmacklem case NFSATTRBIT_MAXWRITE: 1328191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1329191783Srmacklem if (compare) { 1330191783Srmacklem if (!(*retcmpp)) { 1331191783Srmacklem if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t, 1332191783Srmacklem *(tl + 1)) || *tl != 0) 1333191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1334191783Srmacklem } 1335191783Srmacklem } else if (fsp != NULL) { 1336191783Srmacklem fsp->fs_wtmax = fxdr_unsigned(int, *++tl); 1337191783Srmacklem fsp->fs_wtpref = fsp->fs_wtmax; 1338191783Srmacklem } 1339191783Srmacklem attrsum += NFSX_HYPER; 1340191783Srmacklem break; 1341191783Srmacklem case NFSATTRBIT_MIMETYPE: 1342191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1343191783Srmacklem i = fxdr_unsigned(int, *tl); 1344191783Srmacklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); 1345191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 1346191783Srmacklem if (error) 1347191783Srmacklem goto nfsmout; 1348191783Srmacklem if (compare && !(*retcmpp)) 1349191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1350191783Srmacklem break; 1351191783Srmacklem case NFSATTRBIT_MODE: 1352191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1353191783Srmacklem if (compare) { 1354191783Srmacklem if (!(*retcmpp)) { 1355191783Srmacklem if (nap->na_mode != nfstov_mode(*tl)) 1356191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1357191783Srmacklem } 1358191783Srmacklem } else if (nap != NULL) { 1359191783Srmacklem nap->na_mode = nfstov_mode(*tl); 1360191783Srmacklem } 1361191783Srmacklem attrsum += NFSX_UNSIGNED; 1362191783Srmacklem break; 1363191783Srmacklem case NFSATTRBIT_NOTRUNC: 1364191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1365191783Srmacklem if (compare) { 1366191783Srmacklem if (!(*retcmpp)) { 1367191783Srmacklem if (*tl != newnfs_true) 1368191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1369191783Srmacklem } 1370191783Srmacklem } else if (pc != NULL) { 1371191783Srmacklem pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl); 1372191783Srmacklem } 1373191783Srmacklem attrsum += NFSX_UNSIGNED; 1374191783Srmacklem break; 1375191783Srmacklem case NFSATTRBIT_NUMLINKS: 1376191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1377191783Srmacklem tuint = fxdr_unsigned(u_int32_t, *tl); 1378191783Srmacklem if (compare) { 1379191783Srmacklem if (!(*retcmpp)) { 1380191783Srmacklem if ((u_int32_t)nap->na_nlink != tuint) 1381191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1382191783Srmacklem } 1383191783Srmacklem } else if (nap != NULL) { 1384191783Srmacklem nap->na_nlink = tuint; 1385191783Srmacklem } 1386191783Srmacklem attrsum += NFSX_UNSIGNED; 1387191783Srmacklem break; 1388191783Srmacklem case NFSATTRBIT_OWNER: 1389191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1390191783Srmacklem j = fxdr_unsigned(int, *tl); 1391224086Szack if (j < 0) { 1392224086Szack error = NFSERR_BADXDR; 1393224086Szack goto nfsmout; 1394224086Szack } 1395191783Srmacklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1396191783Srmacklem if (j > NFSV4_SMALLSTR) 1397191783Srmacklem cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1398191783Srmacklem else 1399191783Srmacklem cp = namestr; 1400191783Srmacklem error = nfsrv_mtostr(nd, cp, j); 1401191783Srmacklem if (error) { 1402191783Srmacklem if (j > NFSV4_SMALLSTR) 1403191783Srmacklem free(cp, M_NFSSTRING); 1404224086Szack goto nfsmout; 1405191783Srmacklem } 1406191783Srmacklem if (compare) { 1407191783Srmacklem if (!(*retcmpp)) { 1408241194Srmacklem if (nfsv4_strtouid(nd, cp, j, &uid, p) || 1409191783Srmacklem nap->na_uid != uid) 1410191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1411191783Srmacklem } 1412191783Srmacklem } else if (nap != NULL) { 1413241194Srmacklem if (nfsv4_strtouid(nd, cp, j, &uid, p)) 1414191783Srmacklem nap->na_uid = nfsrv_defaultuid; 1415191783Srmacklem else 1416191783Srmacklem nap->na_uid = uid; 1417191783Srmacklem } 1418191783Srmacklem if (j > NFSV4_SMALLSTR) 1419191783Srmacklem free(cp, M_NFSSTRING); 1420191783Srmacklem break; 1421191783Srmacklem case NFSATTRBIT_OWNERGROUP: 1422191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1423191783Srmacklem j = fxdr_unsigned(int, *tl); 1424224086Szack if (j < 0) { 1425224086Szack error = NFSERR_BADXDR; 1426224086Szack goto nfsmout; 1427224086Szack } 1428191783Srmacklem attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1429191783Srmacklem if (j > NFSV4_SMALLSTR) 1430191783Srmacklem cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1431191783Srmacklem else 1432191783Srmacklem cp = namestr; 1433191783Srmacklem error = nfsrv_mtostr(nd, cp, j); 1434191783Srmacklem if (error) { 1435191783Srmacklem if (j > NFSV4_SMALLSTR) 1436191783Srmacklem free(cp, M_NFSSTRING); 1437224086Szack goto nfsmout; 1438191783Srmacklem } 1439191783Srmacklem if (compare) { 1440191783Srmacklem if (!(*retcmpp)) { 1441241194Srmacklem if (nfsv4_strtogid(nd, cp, j, &gid, p) || 1442191783Srmacklem nap->na_gid != gid) 1443191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1444191783Srmacklem } 1445191783Srmacklem } else if (nap != NULL) { 1446241194Srmacklem if (nfsv4_strtogid(nd, cp, j, &gid, p)) 1447191783Srmacklem nap->na_gid = nfsrv_defaultgid; 1448191783Srmacklem else 1449191783Srmacklem nap->na_gid = gid; 1450191783Srmacklem } 1451191783Srmacklem if (j > NFSV4_SMALLSTR) 1452191783Srmacklem free(cp, M_NFSSTRING); 1453191783Srmacklem break; 1454191783Srmacklem case NFSATTRBIT_QUOTAHARD: 1455191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1456191783Srmacklem if (sbp != NULL) { 1457191783Srmacklem if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1458191783Srmacklem freenum = sbp->f_bfree; 1459191783Srmacklem else 1460191783Srmacklem freenum = sbp->f_bavail; 1461191783Srmacklem#ifdef QUOTA 1462191783Srmacklem /* 1463191783Srmacklem * ufs_quotactl() insists that the uid argument 1464191783Srmacklem * equal p_ruid for non-root quota access, so 1465191783Srmacklem * we'll just make sure that's the case. 1466191783Srmacklem */ 1467191783Srmacklem savuid = p->p_cred->p_ruid; 1468191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 1469191783Srmacklem if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1470191990Sattilio USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1471191783Srmacklem freenum = min(dqb.dqb_bhardlimit, freenum); 1472191783Srmacklem p->p_cred->p_ruid = savuid; 1473191783Srmacklem#endif /* QUOTA */ 1474191783Srmacklem uquad = (u_int64_t)freenum; 1475191783Srmacklem NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1476191783Srmacklem } 1477191783Srmacklem if (compare && !(*retcmpp)) { 1478191783Srmacklem if (uquad != fxdr_hyper(tl)) 1479191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1480191783Srmacklem } 1481191783Srmacklem attrsum += NFSX_HYPER; 1482191783Srmacklem break; 1483191783Srmacklem case NFSATTRBIT_QUOTASOFT: 1484191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1485191783Srmacklem if (sbp != NULL) { 1486191783Srmacklem if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1487191783Srmacklem freenum = sbp->f_bfree; 1488191783Srmacklem else 1489191783Srmacklem freenum = sbp->f_bavail; 1490191783Srmacklem#ifdef QUOTA 1491191783Srmacklem /* 1492191783Srmacklem * ufs_quotactl() insists that the uid argument 1493191783Srmacklem * equal p_ruid for non-root quota access, so 1494191783Srmacklem * we'll just make sure that's the case. 1495191783Srmacklem */ 1496191783Srmacklem savuid = p->p_cred->p_ruid; 1497191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 1498191783Srmacklem if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1499191990Sattilio USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1500191783Srmacklem freenum = min(dqb.dqb_bsoftlimit, freenum); 1501191783Srmacklem p->p_cred->p_ruid = savuid; 1502191783Srmacklem#endif /* QUOTA */ 1503191783Srmacklem uquad = (u_int64_t)freenum; 1504191783Srmacklem NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1505191783Srmacklem } 1506191783Srmacklem if (compare && !(*retcmpp)) { 1507191783Srmacklem if (uquad != fxdr_hyper(tl)) 1508191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1509191783Srmacklem } 1510191783Srmacklem attrsum += NFSX_HYPER; 1511191783Srmacklem break; 1512191783Srmacklem case NFSATTRBIT_QUOTAUSED: 1513191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1514191783Srmacklem if (sbp != NULL) { 1515191783Srmacklem freenum = 0; 1516191783Srmacklem#ifdef QUOTA 1517191783Srmacklem /* 1518191783Srmacklem * ufs_quotactl() insists that the uid argument 1519191783Srmacklem * equal p_ruid for non-root quota access, so 1520191783Srmacklem * we'll just make sure that's the case. 1521191783Srmacklem */ 1522191783Srmacklem savuid = p->p_cred->p_ruid; 1523191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 1524191783Srmacklem if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1525191990Sattilio USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1526191783Srmacklem freenum = dqb.dqb_curblocks; 1527191783Srmacklem p->p_cred->p_ruid = savuid; 1528191783Srmacklem#endif /* QUOTA */ 1529191783Srmacklem uquad = (u_int64_t)freenum; 1530191783Srmacklem NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1531191783Srmacklem } 1532191783Srmacklem if (compare && !(*retcmpp)) { 1533191783Srmacklem if (uquad != fxdr_hyper(tl)) 1534191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1535191783Srmacklem } 1536191783Srmacklem attrsum += NFSX_HYPER; 1537191783Srmacklem break; 1538191783Srmacklem case NFSATTRBIT_RAWDEV: 1539191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA); 1540191783Srmacklem j = fxdr_unsigned(int, *tl++); 1541191783Srmacklem k = fxdr_unsigned(int, *tl); 1542191783Srmacklem if (compare) { 1543191783Srmacklem if (!(*retcmpp)) { 1544191783Srmacklem if (nap->na_rdev != NFSMAKEDEV(j, k)) 1545191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1546191783Srmacklem } 1547191783Srmacklem } else if (nap != NULL) { 1548191783Srmacklem nap->na_rdev = NFSMAKEDEV(j, k); 1549191783Srmacklem } 1550191783Srmacklem attrsum += NFSX_V4SPECDATA; 1551191783Srmacklem break; 1552191783Srmacklem case NFSATTRBIT_SPACEAVAIL: 1553191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1554191783Srmacklem if (compare) { 1555191783Srmacklem if (!(*retcmpp) && 1556191783Srmacklem sfp->sf_abytes != fxdr_hyper(tl)) 1557191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1558191783Srmacklem } else if (sfp != NULL) { 1559191783Srmacklem sfp->sf_abytes = fxdr_hyper(tl); 1560191783Srmacklem } 1561191783Srmacklem attrsum += NFSX_HYPER; 1562191783Srmacklem break; 1563191783Srmacklem case NFSATTRBIT_SPACEFREE: 1564191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1565191783Srmacklem if (compare) { 1566191783Srmacklem if (!(*retcmpp) && 1567191783Srmacklem sfp->sf_fbytes != fxdr_hyper(tl)) 1568191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1569191783Srmacklem } else if (sfp != NULL) { 1570191783Srmacklem sfp->sf_fbytes = fxdr_hyper(tl); 1571191783Srmacklem } 1572191783Srmacklem attrsum += NFSX_HYPER; 1573191783Srmacklem break; 1574191783Srmacklem case NFSATTRBIT_SPACETOTAL: 1575191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1576191783Srmacklem if (compare) { 1577191783Srmacklem if (!(*retcmpp) && 1578191783Srmacklem sfp->sf_tbytes != fxdr_hyper(tl)) 1579191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1580191783Srmacklem } else if (sfp != NULL) { 1581191783Srmacklem sfp->sf_tbytes = fxdr_hyper(tl); 1582191783Srmacklem } 1583191783Srmacklem attrsum += NFSX_HYPER; 1584191783Srmacklem break; 1585191783Srmacklem case NFSATTRBIT_SPACEUSED: 1586191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1587191783Srmacklem thyp = fxdr_hyper(tl); 1588191783Srmacklem if (compare) { 1589191783Srmacklem if (!(*retcmpp)) { 1590191783Srmacklem if ((u_int64_t)nap->na_bytes != thyp) 1591191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1592191783Srmacklem } 1593191783Srmacklem } else if (nap != NULL) { 1594191783Srmacklem nap->na_bytes = thyp; 1595191783Srmacklem } 1596191783Srmacklem attrsum += NFSX_HYPER; 1597191783Srmacklem break; 1598191783Srmacklem case NFSATTRBIT_SYSTEM: 1599191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1600191783Srmacklem if (compare && !(*retcmpp)) 1601191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1602191783Srmacklem attrsum += NFSX_UNSIGNED; 1603191783Srmacklem break; 1604191783Srmacklem case NFSATTRBIT_TIMEACCESS: 1605191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1606191783Srmacklem fxdr_nfsv4time(tl, &temptime); 1607191783Srmacklem if (compare) { 1608191783Srmacklem if (!(*retcmpp)) { 1609191783Srmacklem if (!NFS_CMPTIME(temptime, nap->na_atime)) 1610191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1611191783Srmacklem } 1612191783Srmacklem } else if (nap != NULL) { 1613191783Srmacklem nap->na_atime = temptime; 1614191783Srmacklem } 1615191783Srmacklem attrsum += NFSX_V4TIME; 1616191783Srmacklem break; 1617191783Srmacklem case NFSATTRBIT_TIMEACCESSSET: 1618191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1619191783Srmacklem attrsum += NFSX_UNSIGNED; 1620191783Srmacklem i = fxdr_unsigned(int, *tl); 1621191783Srmacklem if (i == NFSV4SATTRTIME_TOCLIENT) { 1622191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1623191783Srmacklem attrsum += NFSX_V4TIME; 1624191783Srmacklem } 1625191783Srmacklem if (compare && !(*retcmpp)) 1626191783Srmacklem *retcmpp = NFSERR_INVAL; 1627191783Srmacklem break; 1628191783Srmacklem case NFSATTRBIT_TIMEBACKUP: 1629191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1630191783Srmacklem if (compare && !(*retcmpp)) 1631191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1632191783Srmacklem attrsum += NFSX_V4TIME; 1633191783Srmacklem break; 1634191783Srmacklem case NFSATTRBIT_TIMECREATE: 1635191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1636191783Srmacklem if (compare && !(*retcmpp)) 1637191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1638191783Srmacklem attrsum += NFSX_V4TIME; 1639191783Srmacklem break; 1640191783Srmacklem case NFSATTRBIT_TIMEDELTA: 1641191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1642191783Srmacklem if (fsp != NULL) { 1643191783Srmacklem if (compare) { 1644191783Srmacklem if (!(*retcmpp)) { 1645191783Srmacklem if ((u_int32_t)fsp->fs_timedelta.tv_sec != 1646191783Srmacklem fxdr_unsigned(u_int32_t, *(tl + 1)) || 1647191783Srmacklem (u_int32_t)fsp->fs_timedelta.tv_nsec != 1648191783Srmacklem (fxdr_unsigned(u_int32_t, *(tl + 2)) % 1649191783Srmacklem 1000000000) || 1650191783Srmacklem *tl != 0) 1651191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1652191783Srmacklem } 1653191783Srmacklem } else { 1654191783Srmacklem fxdr_nfsv4time(tl, &fsp->fs_timedelta); 1655191783Srmacklem } 1656191783Srmacklem } 1657191783Srmacklem attrsum += NFSX_V4TIME; 1658191783Srmacklem break; 1659191783Srmacklem case NFSATTRBIT_TIMEMETADATA: 1660191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1661191783Srmacklem fxdr_nfsv4time(tl, &temptime); 1662191783Srmacklem if (compare) { 1663191783Srmacklem if (!(*retcmpp)) { 1664191783Srmacklem if (!NFS_CMPTIME(temptime, nap->na_ctime)) 1665191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1666191783Srmacklem } 1667191783Srmacklem } else if (nap != NULL) { 1668191783Srmacklem nap->na_ctime = temptime; 1669191783Srmacklem } 1670191783Srmacklem attrsum += NFSX_V4TIME; 1671191783Srmacklem break; 1672191783Srmacklem case NFSATTRBIT_TIMEMODIFY: 1673191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1674191783Srmacklem fxdr_nfsv4time(tl, &temptime); 1675191783Srmacklem if (compare) { 1676191783Srmacklem if (!(*retcmpp)) { 1677191783Srmacklem if (!NFS_CMPTIME(temptime, nap->na_mtime)) 1678191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1679191783Srmacklem } 1680191783Srmacklem } else if (nap != NULL) { 1681191783Srmacklem nap->na_mtime = temptime; 1682191783Srmacklem } 1683191783Srmacklem attrsum += NFSX_V4TIME; 1684191783Srmacklem break; 1685191783Srmacklem case NFSATTRBIT_TIMEMODIFYSET: 1686191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1687191783Srmacklem attrsum += NFSX_UNSIGNED; 1688191783Srmacklem i = fxdr_unsigned(int, *tl); 1689191783Srmacklem if (i == NFSV4SATTRTIME_TOCLIENT) { 1690191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1691191783Srmacklem attrsum += NFSX_V4TIME; 1692191783Srmacklem } 1693191783Srmacklem if (compare && !(*retcmpp)) 1694191783Srmacklem *retcmpp = NFSERR_INVAL; 1695191783Srmacklem break; 1696191783Srmacklem case NFSATTRBIT_MOUNTEDONFILEID: 1697191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1698191783Srmacklem thyp = fxdr_hyper(tl); 1699191783Srmacklem if (compare) { 1700191783Srmacklem if (!(*retcmpp)) { 1701191783Srmacklem if (*tl++) { 1702191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1703191783Srmacklem } else { 1704191783Srmacklem if (!vp || !nfsrv_atroot(vp, &fid)) 1705191783Srmacklem fid = nap->na_fileid; 1706191783Srmacklem if ((u_int64_t)fid != thyp) 1707191783Srmacklem *retcmpp = NFSERR_NOTSAME; 1708191783Srmacklem } 1709191783Srmacklem } 1710191783Srmacklem } else if (nap != NULL) { 1711191783Srmacklem if (*tl++) 1712191783Srmacklem printf("NFSv4 mounted on fileid > 32bits\n"); 1713191783Srmacklem nap->na_mntonfileno = thyp; 1714191783Srmacklem } 1715191783Srmacklem attrsum += NFSX_HYPER; 1716191783Srmacklem break; 1717191783Srmacklem default: 1718191783Srmacklem printf("EEK! nfsv4_loadattr unknown attr=%d\n", 1719191783Srmacklem bitpos); 1720191783Srmacklem if (compare && !(*retcmpp)) 1721191783Srmacklem *retcmpp = NFSERR_ATTRNOTSUPP; 1722191783Srmacklem /* 1723191783Srmacklem * and get out of the loop, since we can't parse 1724191783Srmacklem * the unknown attrbute data. 1725191783Srmacklem */ 1726191783Srmacklem bitpos = NFSATTRBIT_MAX; 1727191783Srmacklem break; 1728191783Srmacklem }; 1729191783Srmacklem } 1730191783Srmacklem 1731191783Srmacklem /* 1732191783Srmacklem * some clients pad the attrlist, so we need to skip over the 1733191783Srmacklem * padding. 1734191783Srmacklem */ 1735191783Srmacklem if (attrsum > attrsize) { 1736191783Srmacklem error = NFSERR_BADXDR; 1737191783Srmacklem } else { 1738191783Srmacklem attrsize = NFSM_RNDUP(attrsize); 1739191783Srmacklem if (attrsum < attrsize) 1740191783Srmacklem error = nfsm_advance(nd, attrsize - attrsum, -1); 1741191783Srmacklem } 1742191783Srmacklemnfsmout: 1743224086Szack NFSEXITCODE2(error, nd); 1744191783Srmacklem return (error); 1745191783Srmacklem} 1746191783Srmacklem 1747191783Srmacklem/* 1748191783Srmacklem * Implement sleep locks for newnfs. The nfslock_usecnt allows for a 1749191783Srmacklem * shared lock and the NFSXXX_LOCK flag permits an exclusive lock. 1750191783Srmacklem * The first argument is a pointer to an nfsv4lock structure. 1751191783Srmacklem * The second argument is 1 iff a blocking lock is wanted. 1752191783Srmacklem * If this argument is 0, the call waits until no thread either wants nor 1753191783Srmacklem * holds an exclusive lock. 1754191783Srmacklem * It returns 1 if the lock was acquired, 0 otherwise. 1755191783Srmacklem * If several processes call this function concurrently wanting the exclusive 1756191783Srmacklem * lock, one will get the lock and the rest will return without getting the 1757191783Srmacklem * lock. (If the caller must have the lock, it simply calls this function in a 1758191783Srmacklem * loop until the function returns 1 to indicate the lock was acquired.) 1759191783Srmacklem * Any usecnt must be decremented by calling nfsv4_relref() before 1760191783Srmacklem * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could 1761191783Srmacklem * be called in a loop. 1762222389Srmacklem * The isleptp argument is set to indicate if the call slept, iff not NULL 1763222389Srmacklem * and the mp argument indicates to check for a forced dismount, iff not 1764222389Srmacklem * NULL. 1765191783Srmacklem */ 1766191783SrmacklemAPPLESTATIC int 1767191783Srmacklemnfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp, 1768222389Srmacklem void *mutex, struct mount *mp) 1769191783Srmacklem{ 1770191783Srmacklem 1771191783Srmacklem if (isleptp) 1772191783Srmacklem *isleptp = 0; 1773191783Srmacklem /* 1774191783Srmacklem * If a lock is wanted, loop around until the lock is acquired by 1775191783Srmacklem * someone and then released. If I want the lock, try to acquire it. 1776191783Srmacklem * For a lock to be issued, no lock must be in force and the usecnt 1777191783Srmacklem * must be zero. 1778191783Srmacklem */ 1779191783Srmacklem if (iwantlock) { 1780191783Srmacklem if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1781191783Srmacklem lp->nfslock_usecnt == 0) { 1782191783Srmacklem lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1783191783Srmacklem lp->nfslock_lock |= NFSV4LOCK_LOCK; 1784191783Srmacklem return (1); 1785191783Srmacklem } 1786191783Srmacklem lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED; 1787191783Srmacklem } 1788191783Srmacklem while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) { 1789222389Srmacklem if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1790222389Srmacklem lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1791222389Srmacklem return (0); 1792222389Srmacklem } 1793191783Srmacklem lp->nfslock_lock |= NFSV4LOCK_WANTED; 1794191783Srmacklem if (isleptp) 1795191783Srmacklem *isleptp = 1; 1796191783Srmacklem (void) nfsmsleep(&lp->nfslock_lock, mutex, 1797191783Srmacklem PZERO - 1, "nfsv4lck", NULL); 1798191783Srmacklem if (iwantlock && !(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 } 1805191783Srmacklem return (0); 1806191783Srmacklem} 1807191783Srmacklem 1808191783Srmacklem/* 1809191783Srmacklem * Release the lock acquired by nfsv4_lock(). 1810191783Srmacklem * The second argument is set to 1 to indicate the nfslock_usecnt should be 1811191783Srmacklem * incremented, as well. 1812191783Srmacklem */ 1813191783SrmacklemAPPLESTATIC void 1814191783Srmacklemnfsv4_unlock(struct nfsv4lock *lp, int incref) 1815191783Srmacklem{ 1816191783Srmacklem 1817191783Srmacklem lp->nfslock_lock &= ~NFSV4LOCK_LOCK; 1818191783Srmacklem if (incref) 1819191783Srmacklem lp->nfslock_usecnt++; 1820191783Srmacklem nfsv4_wanted(lp); 1821191783Srmacklem} 1822191783Srmacklem 1823191783Srmacklem/* 1824191783Srmacklem * Release a reference cnt. 1825191783Srmacklem */ 1826191783SrmacklemAPPLESTATIC void 1827191783Srmacklemnfsv4_relref(struct nfsv4lock *lp) 1828191783Srmacklem{ 1829191783Srmacklem 1830191783Srmacklem if (lp->nfslock_usecnt <= 0) 1831191783Srmacklem panic("nfsv4root ref cnt"); 1832191783Srmacklem lp->nfslock_usecnt--; 1833191783Srmacklem if (lp->nfslock_usecnt == 0) 1834191783Srmacklem nfsv4_wanted(lp); 1835191783Srmacklem} 1836191783Srmacklem 1837191783Srmacklem/* 1838191783Srmacklem * Get a reference cnt. 1839191783Srmacklem * This function will wait for any exclusive lock to be released, but will 1840191783Srmacklem * not wait for threads that want the exclusive lock. If priority needs 1841191783Srmacklem * to be given to threads that need the exclusive lock, a call to nfsv4_lock() 1842191783Srmacklem * with the 2nd argument == 0 should be done before calling nfsv4_getref(). 1843222389Srmacklem * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and 1844222389Srmacklem * return without getting a refcnt for that case. 1845191783Srmacklem */ 1846191783SrmacklemAPPLESTATIC void 1847222389Srmacklemnfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex, 1848222389Srmacklem struct mount *mp) 1849191783Srmacklem{ 1850191783Srmacklem 1851191783Srmacklem if (isleptp) 1852191783Srmacklem *isleptp = 0; 1853191783Srmacklem 1854191783Srmacklem /* 1855191783Srmacklem * Wait for a lock held. 1856191783Srmacklem */ 1857191783Srmacklem while (lp->nfslock_lock & NFSV4LOCK_LOCK) { 1858222389Srmacklem if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1859222389Srmacklem return; 1860191783Srmacklem lp->nfslock_lock |= NFSV4LOCK_WANTED; 1861191783Srmacklem if (isleptp) 1862191783Srmacklem *isleptp = 1; 1863191783Srmacklem (void) nfsmsleep(&lp->nfslock_lock, mutex, 1864191783Srmacklem PZERO - 1, "nfsv4lck", NULL); 1865191783Srmacklem } 1866222389Srmacklem if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1867222389Srmacklem return; 1868191783Srmacklem 1869191783Srmacklem lp->nfslock_usecnt++; 1870191783Srmacklem} 1871191783Srmacklem 1872191783Srmacklem/* 1873211951Srmacklem * Get a reference as above, but return failure instead of sleeping if 1874211951Srmacklem * an exclusive lock is held. 1875211951Srmacklem */ 1876211951SrmacklemAPPLESTATIC int 1877211951Srmacklemnfsv4_getref_nonblock(struct nfsv4lock *lp) 1878211951Srmacklem{ 1879211951Srmacklem 1880211951Srmacklem if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0) 1881211951Srmacklem return (0); 1882211951Srmacklem 1883211951Srmacklem lp->nfslock_usecnt++; 1884211951Srmacklem return (1); 1885211951Srmacklem} 1886211951Srmacklem 1887211951Srmacklem/* 1888205941Srmacklem * Test for a lock. Return 1 if locked, 0 otherwise. 1889205941Srmacklem */ 1890205941SrmacklemAPPLESTATIC int 1891205941Srmacklemnfsv4_testlock(struct nfsv4lock *lp) 1892205941Srmacklem{ 1893205941Srmacklem 1894205941Srmacklem if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 && 1895205941Srmacklem lp->nfslock_usecnt == 0) 1896205941Srmacklem return (0); 1897205941Srmacklem return (1); 1898205941Srmacklem} 1899205941Srmacklem 1900205941Srmacklem/* 1901191783Srmacklem * Wake up anyone sleeping, waiting for this lock. 1902191783Srmacklem */ 1903191783Srmacklemstatic void 1904191783Srmacklemnfsv4_wanted(struct nfsv4lock *lp) 1905191783Srmacklem{ 1906191783Srmacklem 1907191783Srmacklem if (lp->nfslock_lock & NFSV4LOCK_WANTED) { 1908191783Srmacklem lp->nfslock_lock &= ~NFSV4LOCK_WANTED; 1909191783Srmacklem wakeup((caddr_t)&lp->nfslock_lock); 1910191783Srmacklem } 1911191783Srmacklem} 1912191783Srmacklem 1913191783Srmacklem/* 1914191783Srmacklem * Copy a string from an mbuf list into a character array. 1915191783Srmacklem * Return EBADRPC if there is an mbuf error, 1916191783Srmacklem * 0 otherwise. 1917191783Srmacklem */ 1918191783SrmacklemAPPLESTATIC int 1919191783Srmacklemnfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) 1920191783Srmacklem{ 1921191783Srmacklem char *cp; 1922191783Srmacklem int xfer, len; 1923191783Srmacklem mbuf_t mp; 1924191783Srmacklem int rem, error = 0; 1925191783Srmacklem 1926191783Srmacklem mp = nd->nd_md; 1927191783Srmacklem cp = nd->nd_dpos; 1928191783Srmacklem len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp; 1929191783Srmacklem rem = NFSM_RNDUP(siz) - siz; 1930191783Srmacklem while (siz > 0) { 1931191783Srmacklem if (len > siz) 1932191783Srmacklem xfer = siz; 1933191783Srmacklem else 1934191783Srmacklem xfer = len; 1935191783Srmacklem NFSBCOPY(cp, str, xfer); 1936191783Srmacklem str += xfer; 1937191783Srmacklem siz -= xfer; 1938191783Srmacklem if (siz > 0) { 1939191783Srmacklem mp = mbuf_next(mp); 1940224086Szack if (mp == NULL) { 1941224086Szack error = EBADRPC; 1942224086Szack goto out; 1943224086Szack } 1944191783Srmacklem cp = NFSMTOD(mp, caddr_t); 1945191783Srmacklem len = mbuf_len(mp); 1946191783Srmacklem } else { 1947191783Srmacklem cp += xfer; 1948191783Srmacklem len -= xfer; 1949191783Srmacklem } 1950191783Srmacklem } 1951191783Srmacklem *str = '\0'; 1952191783Srmacklem nd->nd_dpos = cp; 1953191783Srmacklem nd->nd_md = mp; 1954191783Srmacklem if (rem > 0) { 1955191783Srmacklem if (len < rem) 1956191783Srmacklem error = nfsm_advance(nd, rem, len); 1957191783Srmacklem else 1958191783Srmacklem nd->nd_dpos += rem; 1959191783Srmacklem } 1960224086Szack 1961224086Szackout: 1962224086Szack NFSEXITCODE2(error, nd); 1963191783Srmacklem return (error); 1964191783Srmacklem} 1965191783Srmacklem 1966191783Srmacklem/* 1967191783Srmacklem * Fill in the attributes as marked by the bitmap (V4). 1968191783Srmacklem */ 1969191783SrmacklemAPPLESTATIC int 1970220645Srmacklemnfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, 1971220645Srmacklem NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror, 1972220645Srmacklem nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram, 1973220648Srmacklem int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno) 1974191783Srmacklem{ 1975191783Srmacklem int bitpos, retnum = 0; 1976191783Srmacklem u_int32_t *tl; 1977191783Srmacklem int siz, prefixnum, error; 1978191783Srmacklem u_char *cp, namestr[NFSV4_SMALLSTR]; 1979191783Srmacklem nfsattrbit_t attrbits, retbits; 1980191783Srmacklem nfsattrbit_t *retbitp = &retbits; 1981191783Srmacklem u_int32_t freenum, *retnump; 1982191783Srmacklem u_int64_t uquad; 1983191783Srmacklem struct statfs fs; 1984191783Srmacklem struct nfsfsinfo fsinf; 1985191783Srmacklem struct timespec temptime; 1986191783Srmacklem NFSACL_T *aclp, *naclp = NULL; 1987191783Srmacklem#ifdef QUOTA 1988191783Srmacklem struct dqblk dqb; 1989191783Srmacklem uid_t savuid; 1990191783Srmacklem#endif 1991191783Srmacklem 1992191783Srmacklem /* 1993191783Srmacklem * First, set the bits that can be filled and get fsinfo. 1994191783Srmacklem */ 1995191783Srmacklem NFSSET_ATTRBIT(retbitp, attrbitp); 1996260172Srmacklem /* 1997260172Srmacklem * If both p and cred are NULL, it is a client side setattr call. 1998260172Srmacklem * If both p and cred are not NULL, it is a server side reply call. 1999260172Srmacklem * If p is not NULL and cred is NULL, it is a client side callback 2000260172Srmacklem * reply call. 2001260172Srmacklem */ 2002191783Srmacklem if (p == NULL && cred == NULL) { 2003191783Srmacklem NFSCLRNOTSETABLE_ATTRBIT(retbitp); 2004191783Srmacklem aclp = saclp; 2005191783Srmacklem } else { 2006191783Srmacklem NFSCLRNOTFILLABLE_ATTRBIT(retbitp); 2007192861Srmacklem naclp = acl_alloc(M_WAITOK); 2008191783Srmacklem aclp = naclp; 2009191783Srmacklem } 2010191783Srmacklem nfsvno_getfs(&fsinf, isdgram); 2011191783Srmacklem#ifndef APPLE 2012191783Srmacklem /* 2013191783Srmacklem * Get the VFS_STATFS(), since some attributes need them. 2014191783Srmacklem */ 2015191783Srmacklem if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 2016220645Srmacklem error = VFS_STATFS(mp, &fs); 2017191783Srmacklem if (error != 0) { 2018191783Srmacklem if (reterr) { 2019191783Srmacklem nd->nd_repstat = NFSERR_ACCES; 2020191783Srmacklem return (0); 2021191783Srmacklem } 2022191783Srmacklem NFSCLRSTATFS_ATTRBIT(retbitp); 2023191783Srmacklem } 2024191783Srmacklem } 2025191783Srmacklem#endif 2026191783Srmacklem 2027191783Srmacklem /* 2028191783Srmacklem * And the NFSv4 ACL... 2029191783Srmacklem */ 2030200069Strasz if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 2031200069Strasz (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2032220648Srmacklem supports_nfsv4acls == 0))) { 2033191783Srmacklem NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 2034191783Srmacklem } 2035191783Srmacklem if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 2036191783Srmacklem if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2037220648Srmacklem supports_nfsv4acls == 0)) { 2038191783Srmacklem NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2039191783Srmacklem } else if (naclp != NULL) { 2040224081Szack if (NFSVOPLOCK(vp, LK_SHARED) == 0) { 2041217535Srmacklem error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); 2042216700Srmacklem if (error == 0) 2043216700Srmacklem error = VOP_GETACL(vp, ACL_TYPE_NFS4, 2044216700Srmacklem naclp, cred, p); 2045224082Szack NFSVOPUNLOCK(vp, 0); 2046216700Srmacklem } else 2047216700Srmacklem error = NFSERR_PERM; 2048191783Srmacklem if (error != 0) { 2049191783Srmacklem if (reterr) { 2050191783Srmacklem nd->nd_repstat = NFSERR_ACCES; 2051191783Srmacklem return (0); 2052191783Srmacklem } 2053191783Srmacklem NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2054191783Srmacklem } 2055191783Srmacklem } 2056191783Srmacklem } 2057191783Srmacklem /* 2058191783Srmacklem * Put out the attribute bitmap for the ones being filled in 2059191783Srmacklem * and get the field for the number of attributes returned. 2060191783Srmacklem */ 2061191783Srmacklem prefixnum = nfsrv_putattrbit(nd, retbitp); 2062191783Srmacklem NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 2063191783Srmacklem prefixnum += NFSX_UNSIGNED; 2064191783Srmacklem 2065191783Srmacklem /* 2066191783Srmacklem * Now, loop around filling in the attributes for each bit set. 2067191783Srmacklem */ 2068191783Srmacklem for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 2069191783Srmacklem if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 2070191783Srmacklem switch (bitpos) { 2071191783Srmacklem case NFSATTRBIT_SUPPORTEDATTRS: 2072191783Srmacklem NFSSETSUPP_ATTRBIT(&attrbits); 2073191783Srmacklem if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 2074220648Srmacklem && supports_nfsv4acls == 0)) { 2075191783Srmacklem NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 2076191783Srmacklem NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 2077191783Srmacklem } 2078191783Srmacklem retnum += nfsrv_putattrbit(nd, &attrbits); 2079191783Srmacklem break; 2080191783Srmacklem case NFSATTRBIT_TYPE: 2081191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2082191783Srmacklem *tl = vtonfsv34_type(vap->va_type); 2083191783Srmacklem retnum += NFSX_UNSIGNED; 2084191783Srmacklem break; 2085191783Srmacklem case NFSATTRBIT_FHEXPIRETYPE: 2086191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2087191783Srmacklem *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2088191783Srmacklem retnum += NFSX_UNSIGNED; 2089191783Srmacklem break; 2090191783Srmacklem case NFSATTRBIT_CHANGE: 2091191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2092191783Srmacklem txdr_hyper(vap->va_filerev, tl); 2093191783Srmacklem retnum += NFSX_HYPER; 2094191783Srmacklem break; 2095191783Srmacklem case NFSATTRBIT_SIZE: 2096191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2097191783Srmacklem txdr_hyper(vap->va_size, tl); 2098191783Srmacklem retnum += NFSX_HYPER; 2099191783Srmacklem break; 2100191783Srmacklem case NFSATTRBIT_LINKSUPPORT: 2101191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2102191783Srmacklem if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2103191783Srmacklem *tl = newnfs_true; 2104191783Srmacklem else 2105191783Srmacklem *tl = newnfs_false; 2106191783Srmacklem retnum += NFSX_UNSIGNED; 2107191783Srmacklem break; 2108191783Srmacklem case NFSATTRBIT_SYMLINKSUPPORT: 2109191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2110191783Srmacklem if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2111191783Srmacklem *tl = newnfs_true; 2112191783Srmacklem else 2113191783Srmacklem *tl = newnfs_false; 2114191783Srmacklem retnum += NFSX_UNSIGNED; 2115191783Srmacklem break; 2116191783Srmacklem case NFSATTRBIT_NAMEDATTR: 2117191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2118191783Srmacklem *tl = newnfs_false; 2119191783Srmacklem retnum += NFSX_UNSIGNED; 2120191783Srmacklem break; 2121191783Srmacklem case NFSATTRBIT_FSID: 2122191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2123191783Srmacklem *tl++ = 0; 2124220645Srmacklem *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]); 2125191783Srmacklem *tl++ = 0; 2126220645Srmacklem *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]); 2127191783Srmacklem retnum += NFSX_V4FSID; 2128191783Srmacklem break; 2129191783Srmacklem case NFSATTRBIT_UNIQUEHANDLES: 2130191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2131191783Srmacklem *tl = newnfs_true; 2132191783Srmacklem retnum += NFSX_UNSIGNED; 2133191783Srmacklem break; 2134191783Srmacklem case NFSATTRBIT_LEASETIME: 2135191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2136191783Srmacklem *tl = txdr_unsigned(nfsrv_lease); 2137191783Srmacklem retnum += NFSX_UNSIGNED; 2138191783Srmacklem break; 2139191783Srmacklem case NFSATTRBIT_RDATTRERROR: 2140191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2141191783Srmacklem *tl = txdr_unsigned(rderror); 2142191783Srmacklem retnum += NFSX_UNSIGNED; 2143191783Srmacklem break; 2144191783Srmacklem /* 2145191783Srmacklem * Recommended Attributes. (Only the supported ones.) 2146191783Srmacklem */ 2147191783Srmacklem case NFSATTRBIT_ACL: 2148191783Srmacklem retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2149191783Srmacklem break; 2150191783Srmacklem case NFSATTRBIT_ACLSUPPORT: 2151191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2152191783Srmacklem *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2153191783Srmacklem retnum += NFSX_UNSIGNED; 2154191783Srmacklem break; 2155191783Srmacklem case NFSATTRBIT_CANSETTIME: 2156191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2157191783Srmacklem if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2158191783Srmacklem *tl = newnfs_true; 2159191783Srmacklem else 2160191783Srmacklem *tl = newnfs_false; 2161191783Srmacklem retnum += NFSX_UNSIGNED; 2162191783Srmacklem break; 2163191783Srmacklem case NFSATTRBIT_CASEINSENSITIVE: 2164191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2165191783Srmacklem *tl = newnfs_false; 2166191783Srmacklem retnum += NFSX_UNSIGNED; 2167191783Srmacklem break; 2168191783Srmacklem case NFSATTRBIT_CASEPRESERVING: 2169191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2170191783Srmacklem *tl = newnfs_true; 2171191783Srmacklem retnum += NFSX_UNSIGNED; 2172191783Srmacklem break; 2173191783Srmacklem case NFSATTRBIT_CHOWNRESTRICTED: 2174191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2175224121Szack *tl = newnfs_true; 2176191783Srmacklem retnum += NFSX_UNSIGNED; 2177191783Srmacklem break; 2178191783Srmacklem case NFSATTRBIT_FILEHANDLE: 2179191783Srmacklem retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2180191783Srmacklem break; 2181191783Srmacklem case NFSATTRBIT_FILEID: 2182191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2183191783Srmacklem *tl++ = 0; 2184191783Srmacklem *tl = txdr_unsigned(vap->va_fileid); 2185191783Srmacklem retnum += NFSX_HYPER; 2186191783Srmacklem break; 2187191783Srmacklem case NFSATTRBIT_FILESAVAIL: 2188191783Srmacklem /* 2189191783Srmacklem * Check quota and use min(quota, f_ffree). 2190191783Srmacklem */ 2191191783Srmacklem freenum = fs.f_ffree; 2192191783Srmacklem#ifdef QUOTA 2193191783Srmacklem /* 2194191783Srmacklem * ufs_quotactl() insists that the uid argument 2195191783Srmacklem * equal p_ruid for non-root quota access, so 2196191783Srmacklem * we'll just make sure that's the case. 2197191783Srmacklem */ 2198191783Srmacklem savuid = p->p_cred->p_ruid; 2199191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 2200220645Srmacklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2201191990Sattilio cred->cr_uid, (caddr_t)&dqb)) 2202191783Srmacklem freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2203191783Srmacklem freenum); 2204191783Srmacklem p->p_cred->p_ruid = savuid; 2205191783Srmacklem#endif /* QUOTA */ 2206191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2207191783Srmacklem *tl++ = 0; 2208191783Srmacklem *tl = txdr_unsigned(freenum); 2209191783Srmacklem retnum += NFSX_HYPER; 2210191783Srmacklem break; 2211191783Srmacklem case NFSATTRBIT_FILESFREE: 2212191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2213191783Srmacklem *tl++ = 0; 2214191783Srmacklem *tl = txdr_unsigned(fs.f_ffree); 2215191783Srmacklem retnum += NFSX_HYPER; 2216191783Srmacklem break; 2217191783Srmacklem case NFSATTRBIT_FILESTOTAL: 2218191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2219191783Srmacklem *tl++ = 0; 2220191783Srmacklem *tl = txdr_unsigned(fs.f_files); 2221191783Srmacklem retnum += NFSX_HYPER; 2222191783Srmacklem break; 2223191783Srmacklem case NFSATTRBIT_FSLOCATIONS: 2224191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2225191783Srmacklem *tl++ = 0; 2226191783Srmacklem *tl = 0; 2227191783Srmacklem retnum += 2 * NFSX_UNSIGNED; 2228191783Srmacklem break; 2229191783Srmacklem case NFSATTRBIT_HOMOGENEOUS: 2230191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2231191783Srmacklem if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2232191783Srmacklem *tl = newnfs_true; 2233191783Srmacklem else 2234191783Srmacklem *tl = newnfs_false; 2235191783Srmacklem retnum += NFSX_UNSIGNED; 2236191783Srmacklem break; 2237191783Srmacklem case NFSATTRBIT_MAXFILESIZE: 2238191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2239191783Srmacklem uquad = NFSRV_MAXFILESIZE; 2240191783Srmacklem txdr_hyper(uquad, tl); 2241191783Srmacklem retnum += NFSX_HYPER; 2242191783Srmacklem break; 2243191783Srmacklem case NFSATTRBIT_MAXLINK: 2244191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2245191783Srmacklem *tl = txdr_unsigned(LINK_MAX); 2246191783Srmacklem retnum += NFSX_UNSIGNED; 2247191783Srmacklem break; 2248191783Srmacklem case NFSATTRBIT_MAXNAME: 2249191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2250191783Srmacklem *tl = txdr_unsigned(NFS_MAXNAMLEN); 2251191783Srmacklem retnum += NFSX_UNSIGNED; 2252191783Srmacklem break; 2253191783Srmacklem case NFSATTRBIT_MAXREAD: 2254191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2255191783Srmacklem *tl++ = 0; 2256191783Srmacklem *tl = txdr_unsigned(fsinf.fs_rtmax); 2257191783Srmacklem retnum += NFSX_HYPER; 2258191783Srmacklem break; 2259191783Srmacklem case NFSATTRBIT_MAXWRITE: 2260191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2261191783Srmacklem *tl++ = 0; 2262191783Srmacklem *tl = txdr_unsigned(fsinf.fs_wtmax); 2263191783Srmacklem retnum += NFSX_HYPER; 2264191783Srmacklem break; 2265191783Srmacklem case NFSATTRBIT_MODE: 2266191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2267191783Srmacklem *tl = vtonfsv34_mode(vap->va_mode); 2268191783Srmacklem retnum += NFSX_UNSIGNED; 2269191783Srmacklem break; 2270191783Srmacklem case NFSATTRBIT_NOTRUNC: 2271191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2272191783Srmacklem *tl = newnfs_true; 2273191783Srmacklem retnum += NFSX_UNSIGNED; 2274191783Srmacklem break; 2275191783Srmacklem case NFSATTRBIT_NUMLINKS: 2276191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2277191783Srmacklem *tl = txdr_unsigned(vap->va_nlink); 2278191783Srmacklem retnum += NFSX_UNSIGNED; 2279191783Srmacklem break; 2280191783Srmacklem case NFSATTRBIT_OWNER: 2281191783Srmacklem cp = namestr; 2282191783Srmacklem nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); 2283191783Srmacklem retnum += nfsm_strtom(nd, cp, siz); 2284191783Srmacklem if (cp != namestr) 2285191783Srmacklem free(cp, M_NFSSTRING); 2286191783Srmacklem break; 2287191783Srmacklem case NFSATTRBIT_OWNERGROUP: 2288191783Srmacklem cp = namestr; 2289191783Srmacklem nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); 2290191783Srmacklem retnum += nfsm_strtom(nd, cp, siz); 2291191783Srmacklem if (cp != namestr) 2292191783Srmacklem free(cp, M_NFSSTRING); 2293191783Srmacklem break; 2294191783Srmacklem case NFSATTRBIT_QUOTAHARD: 2295191783Srmacklem if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2296191783Srmacklem freenum = fs.f_bfree; 2297191783Srmacklem else 2298191783Srmacklem freenum = fs.f_bavail; 2299191783Srmacklem#ifdef QUOTA 2300191783Srmacklem /* 2301191783Srmacklem * ufs_quotactl() insists that the uid argument 2302191783Srmacklem * equal p_ruid for non-root quota access, so 2303191783Srmacklem * we'll just make sure that's the case. 2304191783Srmacklem */ 2305191783Srmacklem savuid = p->p_cred->p_ruid; 2306191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 2307220645Srmacklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2308191990Sattilio cred->cr_uid, (caddr_t)&dqb)) 2309191783Srmacklem freenum = min(dqb.dqb_bhardlimit, freenum); 2310191783Srmacklem p->p_cred->p_ruid = savuid; 2311191783Srmacklem#endif /* QUOTA */ 2312191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2313191783Srmacklem uquad = (u_int64_t)freenum; 2314191783Srmacklem NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2315191783Srmacklem txdr_hyper(uquad, tl); 2316191783Srmacklem retnum += NFSX_HYPER; 2317191783Srmacklem break; 2318191783Srmacklem case NFSATTRBIT_QUOTASOFT: 2319191783Srmacklem if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2320191783Srmacklem freenum = fs.f_bfree; 2321191783Srmacklem else 2322191783Srmacklem freenum = fs.f_bavail; 2323191783Srmacklem#ifdef QUOTA 2324191783Srmacklem /* 2325191783Srmacklem * ufs_quotactl() insists that the uid argument 2326191783Srmacklem * equal p_ruid for non-root quota access, so 2327191783Srmacklem * we'll just make sure that's the case. 2328191783Srmacklem */ 2329191783Srmacklem savuid = p->p_cred->p_ruid; 2330191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 2331220645Srmacklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2332191990Sattilio cred->cr_uid, (caddr_t)&dqb)) 2333191783Srmacklem freenum = min(dqb.dqb_bsoftlimit, freenum); 2334191783Srmacklem p->p_cred->p_ruid = savuid; 2335191783Srmacklem#endif /* QUOTA */ 2336191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2337191783Srmacklem uquad = (u_int64_t)freenum; 2338191783Srmacklem NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2339191783Srmacklem txdr_hyper(uquad, tl); 2340191783Srmacklem retnum += NFSX_HYPER; 2341191783Srmacklem break; 2342191783Srmacklem case NFSATTRBIT_QUOTAUSED: 2343191783Srmacklem freenum = 0; 2344191783Srmacklem#ifdef QUOTA 2345191783Srmacklem /* 2346191783Srmacklem * ufs_quotactl() insists that the uid argument 2347191783Srmacklem * equal p_ruid for non-root quota access, so 2348191783Srmacklem * we'll just make sure that's the case. 2349191783Srmacklem */ 2350191783Srmacklem savuid = p->p_cred->p_ruid; 2351191783Srmacklem p->p_cred->p_ruid = cred->cr_uid; 2352220645Srmacklem if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2353191990Sattilio cred->cr_uid, (caddr_t)&dqb)) 2354191783Srmacklem freenum = dqb.dqb_curblocks; 2355191783Srmacklem p->p_cred->p_ruid = savuid; 2356191783Srmacklem#endif /* QUOTA */ 2357191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2358191783Srmacklem uquad = (u_int64_t)freenum; 2359191783Srmacklem NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2360191783Srmacklem txdr_hyper(uquad, tl); 2361191783Srmacklem retnum += NFSX_HYPER; 2362191783Srmacklem break; 2363191783Srmacklem case NFSATTRBIT_RAWDEV: 2364191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2365191783Srmacklem *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2366191783Srmacklem *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2367191783Srmacklem retnum += NFSX_V4SPECDATA; 2368191783Srmacklem break; 2369191783Srmacklem case NFSATTRBIT_SPACEAVAIL: 2370191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2371191783Srmacklem if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) 2372191783Srmacklem uquad = (u_int64_t)fs.f_bfree; 2373191783Srmacklem else 2374191783Srmacklem uquad = (u_int64_t)fs.f_bavail; 2375191783Srmacklem uquad *= fs.f_bsize; 2376191783Srmacklem txdr_hyper(uquad, tl); 2377191783Srmacklem retnum += NFSX_HYPER; 2378191783Srmacklem break; 2379191783Srmacklem case NFSATTRBIT_SPACEFREE: 2380191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2381191783Srmacklem uquad = (u_int64_t)fs.f_bfree; 2382191783Srmacklem uquad *= fs.f_bsize; 2383191783Srmacklem txdr_hyper(uquad, tl); 2384191783Srmacklem retnum += NFSX_HYPER; 2385191783Srmacklem break; 2386191783Srmacklem case NFSATTRBIT_SPACETOTAL: 2387191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2388191783Srmacklem uquad = (u_int64_t)fs.f_blocks; 2389191783Srmacklem uquad *= fs.f_bsize; 2390191783Srmacklem txdr_hyper(uquad, tl); 2391191783Srmacklem retnum += NFSX_HYPER; 2392191783Srmacklem break; 2393191783Srmacklem case NFSATTRBIT_SPACEUSED: 2394191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2395191783Srmacklem txdr_hyper(vap->va_bytes, tl); 2396191783Srmacklem retnum += NFSX_HYPER; 2397191783Srmacklem break; 2398191783Srmacklem case NFSATTRBIT_TIMEACCESS: 2399191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2400191783Srmacklem txdr_nfsv4time(&vap->va_atime, tl); 2401191783Srmacklem retnum += NFSX_V4TIME; 2402191783Srmacklem break; 2403191783Srmacklem case NFSATTRBIT_TIMEACCESSSET: 2404247502Sjhb if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2405191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2406191783Srmacklem *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2407191783Srmacklem txdr_nfsv4time(&vap->va_atime, tl); 2408191783Srmacklem retnum += NFSX_V4SETTIME; 2409191783Srmacklem } else { 2410191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2411191783Srmacklem *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2412191783Srmacklem retnum += NFSX_UNSIGNED; 2413191783Srmacklem } 2414191783Srmacklem break; 2415191783Srmacklem case NFSATTRBIT_TIMEDELTA: 2416191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2417191783Srmacklem temptime.tv_sec = 0; 2418191783Srmacklem temptime.tv_nsec = 1000000000 / hz; 2419191783Srmacklem txdr_nfsv4time(&temptime, tl); 2420191783Srmacklem retnum += NFSX_V4TIME; 2421191783Srmacklem break; 2422191783Srmacklem case NFSATTRBIT_TIMEMETADATA: 2423191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2424191783Srmacklem txdr_nfsv4time(&vap->va_ctime, tl); 2425191783Srmacklem retnum += NFSX_V4TIME; 2426191783Srmacklem break; 2427191783Srmacklem case NFSATTRBIT_TIMEMODIFY: 2428191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2429191783Srmacklem txdr_nfsv4time(&vap->va_mtime, tl); 2430191783Srmacklem retnum += NFSX_V4TIME; 2431191783Srmacklem break; 2432191783Srmacklem case NFSATTRBIT_TIMEMODIFYSET: 2433247502Sjhb if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2434191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2435191783Srmacklem *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2436191783Srmacklem txdr_nfsv4time(&vap->va_mtime, tl); 2437191783Srmacklem retnum += NFSX_V4SETTIME; 2438191783Srmacklem } else { 2439191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2440191783Srmacklem *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2441191783Srmacklem retnum += NFSX_UNSIGNED; 2442191783Srmacklem } 2443191783Srmacklem break; 2444191783Srmacklem case NFSATTRBIT_MOUNTEDONFILEID: 2445191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2446220645Srmacklem if (at_root != 0) 2447220645Srmacklem uquad = mounted_on_fileno; 2448191783Srmacklem else 2449220645Srmacklem uquad = (u_int64_t)vap->va_fileid; 2450220645Srmacklem txdr_hyper(uquad, tl); 2451191783Srmacklem retnum += NFSX_HYPER; 2452191783Srmacklem break; 2453191783Srmacklem default: 2454191783Srmacklem printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2455191783Srmacklem }; 2456191783Srmacklem } 2457191783Srmacklem } 2458191783Srmacklem if (naclp != NULL) 2459191783Srmacklem acl_free(naclp); 2460191783Srmacklem *retnump = txdr_unsigned(retnum); 2461191783Srmacklem return (retnum + prefixnum); 2462191783Srmacklem} 2463191783Srmacklem 2464191783Srmacklem/* 2465191783Srmacklem * Put the attribute bits onto an mbuf list. 2466191783Srmacklem * Return the number of bytes of output generated. 2467191783Srmacklem */ 2468191783SrmacklemAPPLESTATIC int 2469191783Srmacklemnfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 2470191783Srmacklem{ 2471191783Srmacklem u_int32_t *tl; 2472191783Srmacklem int cnt, i, bytesize; 2473191783Srmacklem 2474191783Srmacklem for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 2475191783Srmacklem if (attrbitp->bits[cnt - 1]) 2476191783Srmacklem break; 2477191783Srmacklem bytesize = (cnt + 1) * NFSX_UNSIGNED; 2478191783Srmacklem NFSM_BUILD(tl, u_int32_t *, bytesize); 2479191783Srmacklem *tl++ = txdr_unsigned(cnt); 2480191783Srmacklem for (i = 0; i < cnt; i++) 2481191783Srmacklem *tl++ = txdr_unsigned(attrbitp->bits[i]); 2482191783Srmacklem return (bytesize); 2483191783Srmacklem} 2484191783Srmacklem 2485191783Srmacklem/* 2486191783Srmacklem * Convert a uid to a string. 2487191783Srmacklem * If the lookup fails, just output the digits. 2488191783Srmacklem * uid - the user id 2489191783Srmacklem * cpp - points to a buffer of size NFSV4_SMALLSTR 2490191783Srmacklem * (malloc a larger one, as required) 2491191783Srmacklem * retlenp - pointer to length to be returned 2492191783Srmacklem */ 2493191783SrmacklemAPPLESTATIC void 2494191783Srmacklemnfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2495191783Srmacklem{ 2496191783Srmacklem int i; 2497191783Srmacklem struct nfsusrgrp *usrp; 2498191783Srmacklem u_char *cp = *cpp; 2499191783Srmacklem uid_t tmp; 2500191783Srmacklem int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2501191783Srmacklem 2502191783Srmacklem cnt = 0; 2503191783Srmacklemtryagain: 2504191783Srmacklem NFSLOCKNAMEID(); 2505191783Srmacklem if (nfsrv_dnsname) { 2506191783Srmacklem /* 2507191783Srmacklem * Always map nfsrv_defaultuid to "nobody". 2508191783Srmacklem */ 2509191783Srmacklem if (uid == nfsrv_defaultuid) { 2510191783Srmacklem i = nfsrv_dnsnamelen + 7; 2511191783Srmacklem if (i > len) { 2512191783Srmacklem NFSUNLOCKNAMEID(); 2513191783Srmacklem if (len > NFSV4_SMALLSTR) 2514191783Srmacklem free(cp, M_NFSSTRING); 2515191783Srmacklem cp = malloc(i, M_NFSSTRING, M_WAITOK); 2516191783Srmacklem *cpp = cp; 2517191783Srmacklem len = i; 2518191783Srmacklem goto tryagain; 2519191783Srmacklem } 2520191783Srmacklem *retlenp = i; 2521191783Srmacklem NFSBCOPY("nobody@", cp, 7); 2522191783Srmacklem cp += 7; 2523191783Srmacklem NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2524191783Srmacklem NFSUNLOCKNAMEID(); 2525191783Srmacklem return; 2526191783Srmacklem } 2527191783Srmacklem hasampersand = 0; 2528191783Srmacklem LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) { 2529191783Srmacklem if (usrp->lug_uid == uid) { 2530191783Srmacklem if (usrp->lug_expiry < NFSD_MONOSEC) 2531191783Srmacklem break; 2532191783Srmacklem /* 2533191783Srmacklem * If the name doesn't already have an '@' 2534191783Srmacklem * in it, append @domainname to it. 2535191783Srmacklem */ 2536191783Srmacklem for (i = 0; i < usrp->lug_namelen; i++) { 2537191783Srmacklem if (usrp->lug_name[i] == '@') { 2538191783Srmacklem hasampersand = 1; 2539191783Srmacklem break; 2540191783Srmacklem } 2541191783Srmacklem } 2542191783Srmacklem if (hasampersand) 2543191783Srmacklem i = usrp->lug_namelen; 2544191783Srmacklem else 2545191783Srmacklem i = usrp->lug_namelen + 2546191783Srmacklem nfsrv_dnsnamelen + 1; 2547191783Srmacklem if (i > len) { 2548191783Srmacklem NFSUNLOCKNAMEID(); 2549191783Srmacklem if (len > NFSV4_SMALLSTR) 2550191783Srmacklem free(cp, M_NFSSTRING); 2551191783Srmacklem cp = malloc(i, M_NFSSTRING, M_WAITOK); 2552191783Srmacklem *cpp = cp; 2553191783Srmacklem len = i; 2554191783Srmacklem goto tryagain; 2555191783Srmacklem } 2556191783Srmacklem *retlenp = i; 2557191783Srmacklem NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2558191783Srmacklem if (!hasampersand) { 2559191783Srmacklem cp += usrp->lug_namelen; 2560191783Srmacklem *cp++ = '@'; 2561191783Srmacklem NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2562191783Srmacklem } 2563191783Srmacklem TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2564191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2565191783Srmacklem NFSUNLOCKNAMEID(); 2566191783Srmacklem return; 2567191783Srmacklem } 2568191783Srmacklem } 2569191783Srmacklem NFSUNLOCKNAMEID(); 2570191783Srmacklem cnt++; 2571191783Srmacklem ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2572191783Srmacklem NULL, p); 2573191783Srmacklem if (ret == 0 && cnt < 2) 2574191783Srmacklem goto tryagain; 2575191783Srmacklem } else { 2576191783Srmacklem NFSUNLOCKNAMEID(); 2577191783Srmacklem } 2578191783Srmacklem 2579191783Srmacklem /* 2580191783Srmacklem * No match, just return a string of digits. 2581191783Srmacklem */ 2582191783Srmacklem tmp = uid; 2583191783Srmacklem i = 0; 2584191783Srmacklem while (tmp || i == 0) { 2585191783Srmacklem tmp /= 10; 2586191783Srmacklem i++; 2587191783Srmacklem } 2588191783Srmacklem len = (i > len) ? len : i; 2589191783Srmacklem *retlenp = len; 2590191783Srmacklem cp += (len - 1); 2591191783Srmacklem tmp = uid; 2592191783Srmacklem for (i = 0; i < len; i++) { 2593191783Srmacklem *cp-- = '0' + (tmp % 10); 2594191783Srmacklem tmp /= 10; 2595191783Srmacklem } 2596191783Srmacklem return; 2597191783Srmacklem} 2598191783Srmacklem 2599191783Srmacklem/* 2600191783Srmacklem * Convert a string to a uid. 2601191783Srmacklem * If no conversion is possible return NFSERR_BADOWNER, otherwise 2602191783Srmacklem * return 0. 2603241194Srmacklem * If this is called from a client side mount using AUTH_SYS and the 2604241194Srmacklem * string is made up entirely of digits, just convert the string to 2605241194Srmacklem * a number. 2606191783Srmacklem */ 2607191783SrmacklemAPPLESTATIC int 2608241194Srmacklemnfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp, 2609241194Srmacklem NFSPROC_T *p) 2610191783Srmacklem{ 2611191783Srmacklem int i; 2612241194Srmacklem char *cp, *endstr, *str0; 2613191783Srmacklem struct nfsusrgrp *usrp; 2614191783Srmacklem int cnt, ret; 2615224086Szack int error = 0; 2616241194Srmacklem uid_t tuid; 2617191783Srmacklem 2618224086Szack if (len == 0) { 2619224086Szack error = NFSERR_BADOWNER; 2620224086Szack goto out; 2621224086Szack } 2622241194Srmacklem /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2623241194Srmacklem str0 = str; 2624241194Srmacklem tuid = (uid_t)strtoul(str0, &endstr, 10); 2625265724Srmacklem if ((endstr - str0) == len) { 2626265724Srmacklem /* A numeric string. */ 2627265724Srmacklem if ((nd->nd_flag & ND_KERBV) == 0 && 2628265724Srmacklem ((nd->nd_flag & ND_NFSCL) != 0 || 2629265724Srmacklem nfsd_enable_stringtouid != 0)) 2630265724Srmacklem *uidp = tuid; 2631265724Srmacklem else 2632265724Srmacklem error = NFSERR_BADOWNER; 2633241194Srmacklem goto out; 2634241194Srmacklem } 2635191783Srmacklem /* 2636191783Srmacklem * Look for an '@'. 2637191783Srmacklem */ 2638241194Srmacklem cp = strchr(str0, '@'); 2639241194Srmacklem if (cp != NULL) 2640241194Srmacklem i = (int)(cp++ - str0); 2641241194Srmacklem else 2642241194Srmacklem i = len; 2643191783Srmacklem 2644191783Srmacklem cnt = 0; 2645191783Srmacklemtryagain: 2646191783Srmacklem NFSLOCKNAMEID(); 2647191783Srmacklem /* 2648191783Srmacklem * If an '@' is found and the domain name matches, search for the name 2649191783Srmacklem * with dns stripped off. 2650191783Srmacklem * Mixed case alpahbetics will match for the domain name, but all 2651191783Srmacklem * upper case will not. 2652191783Srmacklem */ 2653191783Srmacklem if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2654191783Srmacklem (len - 1 - i) == nfsrv_dnsnamelen && 2655191783Srmacklem !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2656191783Srmacklem len -= (nfsrv_dnsnamelen + 1); 2657191783Srmacklem *(cp - 1) = '\0'; 2658191783Srmacklem } 2659191783Srmacklem 2660191783Srmacklem /* 2661191783Srmacklem * Check for the special case of "nobody". 2662191783Srmacklem */ 2663191783Srmacklem if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 2664191783Srmacklem *uidp = nfsrv_defaultuid; 2665191783Srmacklem NFSUNLOCKNAMEID(); 2666224086Szack error = 0; 2667224086Szack goto out; 2668191783Srmacklem } 2669191783Srmacklem 2670191783Srmacklem LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) { 2671191783Srmacklem if (usrp->lug_namelen == len && 2672191783Srmacklem !NFSBCMP(usrp->lug_name, str, len)) { 2673191783Srmacklem if (usrp->lug_expiry < NFSD_MONOSEC) 2674191783Srmacklem break; 2675191783Srmacklem *uidp = usrp->lug_uid; 2676191783Srmacklem TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2677191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2678191783Srmacklem NFSUNLOCKNAMEID(); 2679224086Szack error = 0; 2680224086Szack goto out; 2681191783Srmacklem } 2682191783Srmacklem } 2683191783Srmacklem NFSUNLOCKNAMEID(); 2684191783Srmacklem cnt++; 2685191783Srmacklem ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 2686191783Srmacklem str, p); 2687191783Srmacklem if (ret == 0 && cnt < 2) 2688191783Srmacklem goto tryagain; 2689224086Szack error = NFSERR_BADOWNER; 2690224086Szack 2691224086Szackout: 2692224086Szack NFSEXITCODE(error); 2693224086Szack return (error); 2694191783Srmacklem} 2695191783Srmacklem 2696191783Srmacklem/* 2697191783Srmacklem * Convert a gid to a string. 2698191783Srmacklem * gid - the group id 2699191783Srmacklem * cpp - points to a buffer of size NFSV4_SMALLSTR 2700191783Srmacklem * (malloc a larger one, as required) 2701191783Srmacklem * retlenp - pointer to length to be returned 2702191783Srmacklem */ 2703191783SrmacklemAPPLESTATIC void 2704191783Srmacklemnfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2705191783Srmacklem{ 2706191783Srmacklem int i; 2707191783Srmacklem struct nfsusrgrp *usrp; 2708191783Srmacklem u_char *cp = *cpp; 2709191783Srmacklem gid_t tmp; 2710191783Srmacklem int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2711191783Srmacklem 2712191783Srmacklem cnt = 0; 2713191783Srmacklemtryagain: 2714191783Srmacklem NFSLOCKNAMEID(); 2715191783Srmacklem if (nfsrv_dnsname) { 2716191783Srmacklem /* 2717191783Srmacklem * Always map nfsrv_defaultgid to "nogroup". 2718191783Srmacklem */ 2719191783Srmacklem if (gid == nfsrv_defaultgid) { 2720191783Srmacklem i = nfsrv_dnsnamelen + 8; 2721191783Srmacklem if (i > len) { 2722191783Srmacklem NFSUNLOCKNAMEID(); 2723191783Srmacklem if (len > NFSV4_SMALLSTR) 2724191783Srmacklem free(cp, M_NFSSTRING); 2725191783Srmacklem cp = malloc(i, M_NFSSTRING, M_WAITOK); 2726191783Srmacklem *cpp = cp; 2727191783Srmacklem len = i; 2728191783Srmacklem goto tryagain; 2729191783Srmacklem } 2730191783Srmacklem *retlenp = i; 2731191783Srmacklem NFSBCOPY("nogroup@", cp, 8); 2732191783Srmacklem cp += 8; 2733191783Srmacklem NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2734191783Srmacklem NFSUNLOCKNAMEID(); 2735191783Srmacklem return; 2736191783Srmacklem } 2737191783Srmacklem hasampersand = 0; 2738191783Srmacklem LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) { 2739191783Srmacklem if (usrp->lug_gid == gid) { 2740191783Srmacklem if (usrp->lug_expiry < NFSD_MONOSEC) 2741191783Srmacklem break; 2742191783Srmacklem /* 2743191783Srmacklem * If the name doesn't already have an '@' 2744191783Srmacklem * in it, append @domainname to it. 2745191783Srmacklem */ 2746191783Srmacklem for (i = 0; i < usrp->lug_namelen; i++) { 2747191783Srmacklem if (usrp->lug_name[i] == '@') { 2748191783Srmacklem hasampersand = 1; 2749191783Srmacklem break; 2750191783Srmacklem } 2751191783Srmacklem } 2752191783Srmacklem if (hasampersand) 2753191783Srmacklem i = usrp->lug_namelen; 2754191783Srmacklem else 2755191783Srmacklem i = usrp->lug_namelen + 2756191783Srmacklem nfsrv_dnsnamelen + 1; 2757191783Srmacklem if (i > len) { 2758191783Srmacklem NFSUNLOCKNAMEID(); 2759191783Srmacklem if (len > NFSV4_SMALLSTR) 2760191783Srmacklem free(cp, M_NFSSTRING); 2761191783Srmacklem cp = malloc(i, M_NFSSTRING, M_WAITOK); 2762191783Srmacklem *cpp = cp; 2763191783Srmacklem len = i; 2764191783Srmacklem goto tryagain; 2765191783Srmacklem } 2766191783Srmacklem *retlenp = i; 2767191783Srmacklem NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2768191783Srmacklem if (!hasampersand) { 2769191783Srmacklem cp += usrp->lug_namelen; 2770191783Srmacklem *cp++ = '@'; 2771191783Srmacklem NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2772191783Srmacklem } 2773191783Srmacklem TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2774191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2775191783Srmacklem NFSUNLOCKNAMEID(); 2776191783Srmacklem return; 2777191783Srmacklem } 2778191783Srmacklem } 2779191783Srmacklem NFSUNLOCKNAMEID(); 2780191783Srmacklem cnt++; 2781191783Srmacklem ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, 2782191783Srmacklem NULL, p); 2783191783Srmacklem if (ret == 0 && cnt < 2) 2784191783Srmacklem goto tryagain; 2785191783Srmacklem } else { 2786191783Srmacklem NFSUNLOCKNAMEID(); 2787191783Srmacklem } 2788191783Srmacklem 2789191783Srmacklem /* 2790191783Srmacklem * No match, just return a string of digits. 2791191783Srmacklem */ 2792191783Srmacklem tmp = gid; 2793191783Srmacklem i = 0; 2794191783Srmacklem while (tmp || i == 0) { 2795191783Srmacklem tmp /= 10; 2796191783Srmacklem i++; 2797191783Srmacklem } 2798191783Srmacklem len = (i > len) ? len : i; 2799191783Srmacklem *retlenp = len; 2800191783Srmacklem cp += (len - 1); 2801191783Srmacklem tmp = gid; 2802191783Srmacklem for (i = 0; i < len; i++) { 2803191783Srmacklem *cp-- = '0' + (tmp % 10); 2804191783Srmacklem tmp /= 10; 2805191783Srmacklem } 2806191783Srmacklem return; 2807191783Srmacklem} 2808191783Srmacklem 2809191783Srmacklem/* 2810191783Srmacklem * Convert a string to a gid. 2811241194Srmacklem * If no conversion is possible return NFSERR_BADOWNER, otherwise 2812241194Srmacklem * return 0. 2813241194Srmacklem * If this is called from a client side mount using AUTH_SYS and the 2814241194Srmacklem * string is made up entirely of digits, just convert the string to 2815241194Srmacklem * a number. 2816191783Srmacklem */ 2817191783SrmacklemAPPLESTATIC int 2818241194Srmacklemnfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp, 2819241194Srmacklem NFSPROC_T *p) 2820191783Srmacklem{ 2821191783Srmacklem int i; 2822241194Srmacklem char *cp, *endstr, *str0; 2823191783Srmacklem struct nfsusrgrp *usrp; 2824191783Srmacklem int cnt, ret; 2825224086Szack int error = 0; 2826241194Srmacklem gid_t tgid; 2827191783Srmacklem 2828224086Szack if (len == 0) { 2829224086Szack error = NFSERR_BADOWNER; 2830224086Szack goto out; 2831224086Szack } 2832241194Srmacklem /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2833241194Srmacklem str0 = str; 2834241194Srmacklem tgid = (gid_t)strtoul(str0, &endstr, 10); 2835265724Srmacklem if ((endstr - str0) == len) { 2836265724Srmacklem /* A numeric string. */ 2837265724Srmacklem if ((nd->nd_flag & ND_KERBV) == 0 && 2838265724Srmacklem ((nd->nd_flag & ND_NFSCL) != 0 || 2839265724Srmacklem nfsd_enable_stringtouid != 0)) 2840265724Srmacklem *gidp = tgid; 2841265724Srmacklem else 2842265724Srmacklem error = NFSERR_BADOWNER; 2843241194Srmacklem goto out; 2844241194Srmacklem } 2845191783Srmacklem /* 2846191783Srmacklem * Look for an '@'. 2847191783Srmacklem */ 2848241194Srmacklem cp = strchr(str0, '@'); 2849241194Srmacklem if (cp != NULL) 2850241194Srmacklem i = (int)(cp++ - str0); 2851241194Srmacklem else 2852241194Srmacklem i = len; 2853191783Srmacklem 2854191783Srmacklem cnt = 0; 2855191783Srmacklemtryagain: 2856191783Srmacklem NFSLOCKNAMEID(); 2857191783Srmacklem /* 2858191783Srmacklem * If an '@' is found and the dns name matches, search for the name 2859191783Srmacklem * with the dns stripped off. 2860191783Srmacklem */ 2861191783Srmacklem if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2862191783Srmacklem (len - 1 - i) == nfsrv_dnsnamelen && 2863191783Srmacklem !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2864191783Srmacklem len -= (nfsrv_dnsnamelen + 1); 2865191783Srmacklem *(cp - 1) = '\0'; 2866191783Srmacklem } 2867191783Srmacklem 2868191783Srmacklem /* 2869191783Srmacklem * Check for the special case of "nogroup". 2870191783Srmacklem */ 2871191783Srmacklem if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 2872191783Srmacklem *gidp = nfsrv_defaultgid; 2873191783Srmacklem NFSUNLOCKNAMEID(); 2874224086Szack error = 0; 2875224086Szack goto out; 2876191783Srmacklem } 2877191783Srmacklem 2878191783Srmacklem LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) { 2879191783Srmacklem if (usrp->lug_namelen == len && 2880191783Srmacklem !NFSBCMP(usrp->lug_name, str, len)) { 2881191783Srmacklem if (usrp->lug_expiry < NFSD_MONOSEC) 2882191783Srmacklem break; 2883191783Srmacklem *gidp = usrp->lug_gid; 2884191783Srmacklem TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2885191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2886191783Srmacklem NFSUNLOCKNAMEID(); 2887224086Szack error = 0; 2888224086Szack goto out; 2889191783Srmacklem } 2890191783Srmacklem } 2891191783Srmacklem NFSUNLOCKNAMEID(); 2892191783Srmacklem cnt++; 2893191783Srmacklem ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 2894191783Srmacklem str, p); 2895191783Srmacklem if (ret == 0 && cnt < 2) 2896191783Srmacklem goto tryagain; 2897224086Szack error = NFSERR_BADOWNER; 2898224086Szack 2899224086Szackout: 2900224086Szack NFSEXITCODE(error); 2901224086Szack return (error); 2902191783Srmacklem} 2903191783Srmacklem 2904191783Srmacklem/* 2905191783Srmacklem * Cmp len chars, allowing mixed case in the first argument to match lower 2906191783Srmacklem * case in the second, but not if the first argument is all upper case. 2907191783Srmacklem * Return 0 for a match, 1 otherwise. 2908191783Srmacklem */ 2909191783Srmacklemstatic int 2910191783Srmacklemnfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 2911191783Srmacklem{ 2912191783Srmacklem int i; 2913191783Srmacklem u_char tmp; 2914191783Srmacklem int fndlower = 0; 2915191783Srmacklem 2916191783Srmacklem for (i = 0; i < len; i++) { 2917191783Srmacklem if (*cp >= 'A' && *cp <= 'Z') { 2918191783Srmacklem tmp = *cp++ + ('a' - 'A'); 2919191783Srmacklem } else { 2920191783Srmacklem tmp = *cp++; 2921191783Srmacklem if (tmp >= 'a' && tmp <= 'z') 2922191783Srmacklem fndlower = 1; 2923191783Srmacklem } 2924191783Srmacklem if (tmp != *cp2++) 2925191783Srmacklem return (1); 2926191783Srmacklem } 2927191783Srmacklem if (fndlower) 2928191783Srmacklem return (0); 2929191783Srmacklem else 2930191783Srmacklem return (1); 2931191783Srmacklem} 2932191783Srmacklem 2933191783Srmacklem/* 2934191783Srmacklem * Set the port for the nfsuserd. 2935191783Srmacklem */ 2936191783SrmacklemAPPLESTATIC int 2937191783Srmacklemnfsrv_nfsuserdport(u_short port, NFSPROC_T *p) 2938191783Srmacklem{ 2939191783Srmacklem struct nfssockreq *rp; 2940191783Srmacklem struct sockaddr_in *ad; 2941191783Srmacklem int error; 2942191783Srmacklem 2943191783Srmacklem NFSLOCKNAMEID(); 2944191783Srmacklem if (nfsrv_nfsuserd) { 2945191783Srmacklem NFSUNLOCKNAMEID(); 2946224086Szack error = EPERM; 2947224086Szack goto out; 2948191783Srmacklem } 2949191783Srmacklem nfsrv_nfsuserd = 1; 2950191783Srmacklem NFSUNLOCKNAMEID(); 2951191783Srmacklem /* 2952191783Srmacklem * Set up the socket record and connect. 2953191783Srmacklem */ 2954191783Srmacklem rp = &nfsrv_nfsuserdsock; 2955191783Srmacklem rp->nr_client = NULL; 2956191783Srmacklem rp->nr_sotype = SOCK_DGRAM; 2957191783Srmacklem rp->nr_soproto = IPPROTO_UDP; 2958191783Srmacklem rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 2959191783Srmacklem rp->nr_cred = NULL; 2960191783Srmacklem NFSSOCKADDRALLOC(rp->nr_nam); 2961191783Srmacklem NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in)); 2962191783Srmacklem ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *); 2963191783Srmacklem ad->sin_family = AF_INET; 2964191783Srmacklem ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */ 2965191783Srmacklem ad->sin_port = port; 2966191783Srmacklem rp->nr_prog = RPCPROG_NFSUSERD; 2967191783Srmacklem rp->nr_vers = RPCNFSUSERD_VERS; 2968191783Srmacklem error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 2969191783Srmacklem if (error) { 2970191783Srmacklem NFSSOCKADDRFREE(rp->nr_nam); 2971191783Srmacklem nfsrv_nfsuserd = 0; 2972191783Srmacklem } 2973224086Szackout: 2974224086Szack NFSEXITCODE(error); 2975191783Srmacklem return (error); 2976191783Srmacklem} 2977191783Srmacklem 2978191783Srmacklem/* 2979191783Srmacklem * Delete the nfsuserd port. 2980191783Srmacklem */ 2981191783SrmacklemAPPLESTATIC void 2982191783Srmacklemnfsrv_nfsuserddelport(void) 2983191783Srmacklem{ 2984191783Srmacklem 2985191783Srmacklem NFSLOCKNAMEID(); 2986191783Srmacklem if (nfsrv_nfsuserd == 0) { 2987191783Srmacklem NFSUNLOCKNAMEID(); 2988191783Srmacklem return; 2989191783Srmacklem } 2990191783Srmacklem nfsrv_nfsuserd = 0; 2991191783Srmacklem NFSUNLOCKNAMEID(); 2992191783Srmacklem newnfs_disconnect(&nfsrv_nfsuserdsock); 2993191783Srmacklem NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); 2994191783Srmacklem} 2995191783Srmacklem 2996191783Srmacklem/* 2997191783Srmacklem * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 2998191783Srmacklem * name<-->id cache. 2999191783Srmacklem * Returns 0 upon success, non-zero otherwise. 3000191783Srmacklem */ 3001191783Srmacklemstatic int 3002191783Srmacklemnfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) 3003191783Srmacklem{ 3004191783Srmacklem u_int32_t *tl; 3005191783Srmacklem struct nfsrv_descript *nd; 3006191783Srmacklem int len; 3007191783Srmacklem struct nfsrv_descript nfsd; 3008191783Srmacklem struct ucred *cred; 3009191783Srmacklem int error; 3010191783Srmacklem 3011191783Srmacklem NFSLOCKNAMEID(); 3012191783Srmacklem if (nfsrv_nfsuserd == 0) { 3013191783Srmacklem NFSUNLOCKNAMEID(); 3014224086Szack error = EPERM; 3015224086Szack goto out; 3016191783Srmacklem } 3017191783Srmacklem NFSUNLOCKNAMEID(); 3018191783Srmacklem nd = &nfsd; 3019191783Srmacklem cred = newnfs_getcred(); 3020191783Srmacklem nd->nd_flag = ND_GSSINITREPLY; 3021191783Srmacklem nfsrvd_rephead(nd); 3022191783Srmacklem 3023191783Srmacklem nd->nd_procnum = procnum; 3024191783Srmacklem if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3025191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3026191783Srmacklem if (procnum == RPCNFSUSERD_GETUID) 3027191783Srmacklem *tl = txdr_unsigned(uid); 3028191783Srmacklem else 3029191783Srmacklem *tl = txdr_unsigned(gid); 3030191783Srmacklem } else { 3031191783Srmacklem len = strlen(name); 3032191783Srmacklem (void) nfsm_strtom(nd, name, len); 3033191783Srmacklem } 3034191783Srmacklem error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 3035191783Srmacklem cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL); 3036191783Srmacklem NFSFREECRED(cred); 3037191783Srmacklem if (!error) { 3038191783Srmacklem mbuf_freem(nd->nd_mrep); 3039191783Srmacklem error = nd->nd_repstat; 3040191783Srmacklem } 3041224086Szackout: 3042224086Szack NFSEXITCODE(error); 3043191783Srmacklem return (error); 3044191783Srmacklem} 3045191783Srmacklem 3046191783Srmacklem/* 3047191783Srmacklem * This function is called from the nfssvc(2) system call, to update the 3048191783Srmacklem * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3049191783Srmacklem */ 3050191783SrmacklemAPPLESTATIC int 3051191783Srmacklemnfssvc_idname(struct nfsd_idargs *nidp) 3052191783Srmacklem{ 3053191783Srmacklem struct nfsusrgrp *nusrp, *usrp, *newusrp; 3054191783Srmacklem struct nfsuserhashhead *hp; 3055191783Srmacklem int i; 3056191783Srmacklem int error = 0; 3057191783Srmacklem u_char *cp; 3058191783Srmacklem 3059191783Srmacklem if (nidp->nid_flag & NFSID_INITIALIZE) { 3060191783Srmacklem cp = (u_char *)malloc(nidp->nid_namelen + 1, 3061191783Srmacklem M_NFSSTRING, M_WAITOK); 3062191783Srmacklem error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 3063191783Srmacklem nidp->nid_namelen); 3064191783Srmacklem NFSLOCKNAMEID(); 3065191783Srmacklem if (nfsrv_dnsname) { 3066191783Srmacklem /* 3067191783Srmacklem * Free up all the old stuff and reinitialize hash lists. 3068191783Srmacklem */ 3069191783Srmacklem TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 3070191783Srmacklem nfsrv_removeuser(usrp); 3071191783Srmacklem } 3072191783Srmacklem free(nfsrv_dnsname, M_NFSSTRING); 3073191783Srmacklem nfsrv_dnsname = NULL; 3074191783Srmacklem } 3075191783Srmacklem TAILQ_INIT(&nfsuserlruhead); 3076191783Srmacklem for (i = 0; i < NFSUSERHASHSIZE; i++) 3077191783Srmacklem LIST_INIT(&nfsuserhash[i]); 3078191783Srmacklem for (i = 0; i < NFSGROUPHASHSIZE; i++) 3079191783Srmacklem LIST_INIT(&nfsgrouphash[i]); 3080191783Srmacklem for (i = 0; i < NFSUSERHASHSIZE; i++) 3081191783Srmacklem LIST_INIT(&nfsusernamehash[i]); 3082191783Srmacklem for (i = 0; i < NFSGROUPHASHSIZE; i++) 3083191783Srmacklem LIST_INIT(&nfsgroupnamehash[i]); 3084191783Srmacklem 3085191783Srmacklem /* 3086191783Srmacklem * Put name in "DNS" string. 3087191783Srmacklem */ 3088191783Srmacklem if (!error) { 3089191783Srmacklem nfsrv_dnsname = cp; 3090191783Srmacklem nfsrv_dnsnamelen = nidp->nid_namelen; 3091191783Srmacklem nfsrv_defaultuid = nidp->nid_uid; 3092191783Srmacklem nfsrv_defaultgid = nidp->nid_gid; 3093191783Srmacklem nfsrv_usercnt = 0; 3094191783Srmacklem nfsrv_usermax = nidp->nid_usermax; 3095191783Srmacklem } 3096191783Srmacklem NFSUNLOCKNAMEID(); 3097191783Srmacklem if (error) 3098191783Srmacklem free(cp, M_NFSSTRING); 3099224086Szack goto out; 3100191783Srmacklem } 3101191783Srmacklem 3102191783Srmacklem /* 3103191783Srmacklem * malloc the new one now, so any potential sleep occurs before 3104191783Srmacklem * manipulation of the lists. 3105191783Srmacklem */ 3106191783Srmacklem MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) + 3107191783Srmacklem nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK); 3108191783Srmacklem error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 3109191783Srmacklem nidp->nid_namelen); 3110191783Srmacklem if (error) { 3111191783Srmacklem free((caddr_t)newusrp, M_NFSUSERGROUP); 3112224086Szack goto out; 3113191783Srmacklem } 3114191783Srmacklem newusrp->lug_namelen = nidp->nid_namelen; 3115191783Srmacklem 3116191783Srmacklem NFSLOCKNAMEID(); 3117191783Srmacklem /* 3118191783Srmacklem * Delete old entries, as required. 3119191783Srmacklem */ 3120191783Srmacklem if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3121191783Srmacklem hp = NFSUSERHASH(nidp->nid_uid); 3122191783Srmacklem LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 3123191783Srmacklem if (usrp->lug_uid == nidp->nid_uid) 3124191783Srmacklem nfsrv_removeuser(usrp); 3125191783Srmacklem } 3126191783Srmacklem } 3127191783Srmacklem if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3128191783Srmacklem hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3129191783Srmacklem LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 3130191783Srmacklem if (usrp->lug_namelen == newusrp->lug_namelen && 3131191783Srmacklem !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3132191783Srmacklem usrp->lug_namelen)) 3133191783Srmacklem nfsrv_removeuser(usrp); 3134191783Srmacklem } 3135191783Srmacklem } 3136191783Srmacklem if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3137191783Srmacklem hp = NFSGROUPHASH(nidp->nid_gid); 3138191783Srmacklem LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 3139191783Srmacklem if (usrp->lug_gid == nidp->nid_gid) 3140191783Srmacklem nfsrv_removeuser(usrp); 3141191783Srmacklem } 3142191783Srmacklem } 3143191783Srmacklem if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3144191783Srmacklem hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3145191783Srmacklem LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 3146191783Srmacklem if (usrp->lug_namelen == newusrp->lug_namelen && 3147191783Srmacklem !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3148191783Srmacklem usrp->lug_namelen)) 3149191783Srmacklem nfsrv_removeuser(usrp); 3150191783Srmacklem } 3151191783Srmacklem } 3152191783Srmacklem TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 3153191783Srmacklem if (usrp->lug_expiry < NFSD_MONOSEC) 3154191783Srmacklem nfsrv_removeuser(usrp); 3155191783Srmacklem } 3156191783Srmacklem while (nfsrv_usercnt >= nfsrv_usermax) { 3157191783Srmacklem usrp = TAILQ_FIRST(&nfsuserlruhead); 3158191783Srmacklem nfsrv_removeuser(usrp); 3159191783Srmacklem } 3160191783Srmacklem 3161191783Srmacklem /* 3162191783Srmacklem * Now, we can add the new one. 3163191783Srmacklem */ 3164191783Srmacklem if (nidp->nid_usertimeout) 3165191783Srmacklem newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3166191783Srmacklem else 3167191783Srmacklem newusrp->lug_expiry = NFSD_MONOSEC + 5; 3168191783Srmacklem if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3169191783Srmacklem newusrp->lug_uid = nidp->nid_uid; 3170191783Srmacklem LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp, 3171191783Srmacklem lug_numhash); 3172191783Srmacklem LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name, 3173191783Srmacklem newusrp->lug_namelen), newusrp, lug_namehash); 3174191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3175191783Srmacklem nfsrv_usercnt++; 3176191783Srmacklem } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3177191783Srmacklem newusrp->lug_gid = nidp->nid_gid; 3178191783Srmacklem LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp, 3179191783Srmacklem lug_numhash); 3180191783Srmacklem LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name, 3181191783Srmacklem newusrp->lug_namelen), newusrp, lug_namehash); 3182191783Srmacklem TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3183191783Srmacklem nfsrv_usercnt++; 3184191783Srmacklem } else 3185191783Srmacklem FREE((caddr_t)newusrp, M_NFSUSERGROUP); 3186191783Srmacklem NFSUNLOCKNAMEID(); 3187224086Szackout: 3188224086Szack NFSEXITCODE(error); 3189191783Srmacklem return (error); 3190191783Srmacklem} 3191191783Srmacklem 3192191783Srmacklem/* 3193191783Srmacklem * Remove a user/group name element. 3194191783Srmacklem */ 3195191783Srmacklemstatic void 3196191783Srmacklemnfsrv_removeuser(struct nfsusrgrp *usrp) 3197191783Srmacklem{ 3198191783Srmacklem 3199191783Srmacklem NFSNAMEIDREQUIRED(); 3200191783Srmacklem LIST_REMOVE(usrp, lug_numhash); 3201191783Srmacklem LIST_REMOVE(usrp, lug_namehash); 3202191783Srmacklem TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 3203191783Srmacklem nfsrv_usercnt--; 3204191783Srmacklem FREE((caddr_t)usrp, M_NFSUSERGROUP); 3205191783Srmacklem} 3206191783Srmacklem 3207191783Srmacklem/* 3208191783Srmacklem * This function scans a byte string and checks for UTF-8 compliance. 3209191783Srmacklem * It returns 0 if it conforms and NFSERR_INVAL if not. 3210191783Srmacklem */ 3211191783SrmacklemAPPLESTATIC int 3212191783Srmacklemnfsrv_checkutf8(u_int8_t *cp, int len) 3213191783Srmacklem{ 3214191783Srmacklem u_int32_t val = 0x0; 3215191783Srmacklem int cnt = 0, gotd = 0, shift = 0; 3216191783Srmacklem u_int8_t byte; 3217191783Srmacklem static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 3218224086Szack int error = 0; 3219191783Srmacklem 3220191783Srmacklem /* 3221191783Srmacklem * Here are what the variables are used for: 3222191783Srmacklem * val - the calculated value of a multibyte char, used to check 3223191783Srmacklem * that it was coded with the correct range 3224191783Srmacklem * cnt - the number of 10xxxxxx bytes to follow 3225191783Srmacklem * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 3226191783Srmacklem * shift - lower order bits of range (ie. "val >> shift" should 3227191783Srmacklem * not be 0, in other words, dividing by the lower bound 3228191783Srmacklem * of the range should get a non-zero value) 3229191783Srmacklem * byte - used to calculate cnt 3230191783Srmacklem */ 3231191783Srmacklem while (len > 0) { 3232191783Srmacklem if (cnt > 0) { 3233191783Srmacklem /* This handles the 10xxxxxx bytes */ 3234191783Srmacklem if ((*cp & 0xc0) != 0x80 || 3235224086Szack (gotd && (*cp & 0x20))) { 3236224086Szack error = NFSERR_INVAL; 3237224086Szack goto out; 3238224086Szack } 3239191783Srmacklem gotd = 0; 3240191783Srmacklem val <<= 6; 3241191783Srmacklem val |= (*cp & 0x3f); 3242191783Srmacklem cnt--; 3243224086Szack if (cnt == 0 && (val >> shift) == 0x0) { 3244224086Szack error = NFSERR_INVAL; 3245224086Szack goto out; 3246224086Szack } 3247191783Srmacklem } else if (*cp & 0x80) { 3248191783Srmacklem /* first byte of multi byte char */ 3249191783Srmacklem byte = *cp; 3250191783Srmacklem while ((byte & 0x40) && cnt < 6) { 3251191783Srmacklem cnt++; 3252191783Srmacklem byte <<= 1; 3253191783Srmacklem } 3254224086Szack if (cnt == 0 || cnt == 6) { 3255224086Szack error = NFSERR_INVAL; 3256224086Szack goto out; 3257224086Szack } 3258191783Srmacklem val = (*cp & (0x3f >> cnt)); 3259191783Srmacklem shift = utf8_shift[cnt - 1]; 3260191783Srmacklem if (cnt == 2 && val == 0xd) 3261191783Srmacklem /* Check for the 0xd800-0xdfff case */ 3262191783Srmacklem gotd = 1; 3263191783Srmacklem } 3264191783Srmacklem cp++; 3265191783Srmacklem len--; 3266191783Srmacklem } 3267191783Srmacklem if (cnt > 0) 3268224086Szack error = NFSERR_INVAL; 3269224086Szack 3270224086Szackout: 3271224086Szack NFSEXITCODE(error); 3272224086Szack return (error); 3273191783Srmacklem} 3274191783Srmacklem 3275191783Srmacklem/* 3276191783Srmacklem * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 3277191783Srmacklem * strings, one with the root path in it and the other with the list of 3278191783Srmacklem * locations. The list is in the same format as is found in nfr_refs. 3279191783Srmacklem * It is a "," separated list of entries, where each of them is of the 3280191783Srmacklem * form <server>:<rootpath>. For example 3281191783Srmacklem * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 3282191783Srmacklem * The nilp argument is set to 1 for the special case of a null fs_root 3283191783Srmacklem * and an empty server list. 3284191783Srmacklem * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 3285191783Srmacklem * number of xdr bytes parsed in sump. 3286191783Srmacklem */ 3287191783Srmacklemstatic int 3288191783Srmacklemnfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 3289191783Srmacklem int *sump, int *nilp) 3290191783Srmacklem{ 3291191783Srmacklem u_int32_t *tl; 3292191783Srmacklem u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 3293224086Szack int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 3294191783Srmacklem struct list { 3295191783Srmacklem SLIST_ENTRY(list) next; 3296191783Srmacklem int len; 3297191783Srmacklem u_char host[1]; 3298191783Srmacklem } *lsp, *nlsp; 3299191783Srmacklem SLIST_HEAD(, list) head; 3300191783Srmacklem 3301191783Srmacklem *fsrootp = NULL; 3302191783Srmacklem *srvp = NULL; 3303191783Srmacklem *nilp = 0; 3304191783Srmacklem 3305191783Srmacklem /* 3306191783Srmacklem * Get the fs_root path and check for the special case of null path 3307191783Srmacklem * and 0 length server list. 3308191783Srmacklem */ 3309191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3310191783Srmacklem len = fxdr_unsigned(int, *tl); 3311224086Szack if (len < 0 || len > 10240) { 3312224086Szack error = NFSERR_BADXDR; 3313224086Szack goto nfsmout; 3314224086Szack } 3315191783Srmacklem if (len == 0) { 3316191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3317224086Szack if (*tl != 0) { 3318224086Szack error = NFSERR_BADXDR; 3319224086Szack goto nfsmout; 3320224086Szack } 3321191783Srmacklem *nilp = 1; 3322191783Srmacklem *sump = 2 * NFSX_UNSIGNED; 3323224086Szack error = 0; 3324224086Szack goto nfsmout; 3325191783Srmacklem } 3326191783Srmacklem cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 3327191783Srmacklem error = nfsrv_mtostr(nd, cp, len); 3328191783Srmacklem if (!error) { 3329191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3330191783Srmacklem cnt = fxdr_unsigned(int, *tl); 3331191783Srmacklem if (cnt <= 0) 3332191783Srmacklem error = NFSERR_BADXDR; 3333191783Srmacklem } 3334224086Szack if (error) 3335224086Szack goto nfsmout; 3336191783Srmacklem 3337191783Srmacklem /* 3338191783Srmacklem * Now, loop through the location list and make up the srvlist. 3339191783Srmacklem */ 3340191783Srmacklem xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3341191783Srmacklem cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 3342191783Srmacklem slen = 1024; 3343191783Srmacklem siz = 0; 3344191783Srmacklem for (i = 0; i < cnt; i++) { 3345191783Srmacklem SLIST_INIT(&head); 3346191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3347191783Srmacklem nsrv = fxdr_unsigned(int, *tl); 3348191783Srmacklem if (nsrv <= 0) { 3349224086Szack error = NFSERR_BADXDR; 3350224086Szack goto nfsmout; 3351191783Srmacklem } 3352191783Srmacklem 3353191783Srmacklem /* 3354191783Srmacklem * Handle the first server by putting it in the srvstr. 3355191783Srmacklem */ 3356191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3357191783Srmacklem len = fxdr_unsigned(int, *tl); 3358191783Srmacklem if (len <= 0 || len > 1024) { 3359224086Szack error = NFSERR_BADXDR; 3360224086Szack goto nfsmout; 3361191783Srmacklem } 3362191783Srmacklem nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 3363191783Srmacklem if (cp3 != cp2) { 3364191783Srmacklem *cp3++ = ','; 3365191783Srmacklem siz++; 3366191783Srmacklem } 3367191783Srmacklem error = nfsrv_mtostr(nd, cp3, len); 3368224086Szack if (error) 3369224086Szack goto nfsmout; 3370191783Srmacklem cp3 += len; 3371191783Srmacklem *cp3++ = ':'; 3372191783Srmacklem siz += (len + 1); 3373191783Srmacklem xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3374191783Srmacklem for (j = 1; j < nsrv; j++) { 3375191783Srmacklem /* 3376191783Srmacklem * Yuck, put them in an slist and process them later. 3377191783Srmacklem */ 3378191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3379191783Srmacklem len = fxdr_unsigned(int, *tl); 3380191783Srmacklem if (len <= 0 || len > 1024) { 3381224086Szack error = NFSERR_BADXDR; 3382224086Szack goto nfsmout; 3383191783Srmacklem } 3384191783Srmacklem lsp = (struct list *)malloc(sizeof (struct list) 3385191783Srmacklem + len, M_TEMP, M_WAITOK); 3386191783Srmacklem error = nfsrv_mtostr(nd, lsp->host, len); 3387224086Szack if (error) 3388224086Szack goto nfsmout; 3389191783Srmacklem xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3390191783Srmacklem lsp->len = len; 3391191783Srmacklem SLIST_INSERT_HEAD(&head, lsp, next); 3392191783Srmacklem } 3393191783Srmacklem 3394191783Srmacklem /* 3395191783Srmacklem * Finally, we can get the path. 3396191783Srmacklem */ 3397191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3398191783Srmacklem len = fxdr_unsigned(int, *tl); 3399191783Srmacklem if (len <= 0 || len > 1024) { 3400224086Szack error = NFSERR_BADXDR; 3401224086Szack goto nfsmout; 3402191783Srmacklem } 3403191783Srmacklem nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 3404191783Srmacklem error = nfsrv_mtostr(nd, cp3, len); 3405224086Szack if (error) 3406224086Szack goto nfsmout; 3407191783Srmacklem xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3408191783Srmacklem str = cp3; 3409191783Srmacklem stringlen = len; 3410191783Srmacklem cp3 += len; 3411191783Srmacklem siz += len; 3412191783Srmacklem SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 3413191783Srmacklem nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 3414191783Srmacklem &cp2, &cp3, &slen); 3415191783Srmacklem *cp3++ = ','; 3416191783Srmacklem NFSBCOPY(lsp->host, cp3, lsp->len); 3417191783Srmacklem cp3 += lsp->len; 3418191783Srmacklem *cp3++ = ':'; 3419191783Srmacklem NFSBCOPY(str, cp3, stringlen); 3420191783Srmacklem cp3 += stringlen; 3421191783Srmacklem *cp3 = '\0'; 3422191783Srmacklem siz += (lsp->len + stringlen + 2); 3423191783Srmacklem free((caddr_t)lsp, M_TEMP); 3424191783Srmacklem } 3425191783Srmacklem } 3426191783Srmacklem *fsrootp = cp; 3427191783Srmacklem *srvp = cp2; 3428191783Srmacklem *sump = xdrsum; 3429224086Szack NFSEXITCODE2(0, nd); 3430191783Srmacklem return (0); 3431191783Srmacklemnfsmout: 3432191783Srmacklem if (cp != NULL) 3433191783Srmacklem free(cp, M_NFSSTRING); 3434191783Srmacklem if (cp2 != NULL) 3435191783Srmacklem free(cp2, M_NFSSTRING); 3436224086Szack NFSEXITCODE2(error, nd); 3437191783Srmacklem return (error); 3438191783Srmacklem} 3439191783Srmacklem 3440191783Srmacklem/* 3441191783Srmacklem * Make the malloc'd space large enough. This is a pain, but the xdr 3442191783Srmacklem * doesn't set an upper bound on the side, so... 3443191783Srmacklem */ 3444191783Srmacklemstatic void 3445191783Srmacklemnfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 3446191783Srmacklem{ 3447191783Srmacklem u_char *cp; 3448191783Srmacklem int i; 3449191783Srmacklem 3450191783Srmacklem if (siz <= *slenp) 3451191783Srmacklem return; 3452191783Srmacklem cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 3453191783Srmacklem NFSBCOPY(*cpp, cp, *slenp); 3454191783Srmacklem free(*cpp, M_NFSSTRING); 3455191783Srmacklem i = *cpp2 - *cpp; 3456191783Srmacklem *cpp = cp; 3457191783Srmacklem *cpp2 = cp + i; 3458191783Srmacklem *slenp = siz + 1024; 3459191783Srmacklem} 3460191783Srmacklem 3461191783Srmacklem/* 3462191783Srmacklem * Initialize the reply header data structures. 3463191783Srmacklem */ 3464191783SrmacklemAPPLESTATIC void 3465191783Srmacklemnfsrvd_rephead(struct nfsrv_descript *nd) 3466191783Srmacklem{ 3467191783Srmacklem mbuf_t mreq; 3468191783Srmacklem 3469191783Srmacklem /* 3470191783Srmacklem * If this is a big reply, use a cluster. 3471191783Srmacklem */ 3472191783Srmacklem if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 3473191783Srmacklem nfs_bigreply[nd->nd_procnum]) { 3474191783Srmacklem NFSMCLGET(mreq, M_WAIT); 3475191783Srmacklem nd->nd_mreq = mreq; 3476191783Srmacklem nd->nd_mb = mreq; 3477191783Srmacklem } else { 3478191783Srmacklem NFSMGET(mreq); 3479191783Srmacklem nd->nd_mreq = mreq; 3480191783Srmacklem nd->nd_mb = mreq; 3481191783Srmacklem } 3482191783Srmacklem nd->nd_bpos = NFSMTOD(mreq, caddr_t); 3483191783Srmacklem mbuf_setlen(mreq, 0); 3484191783Srmacklem 3485191783Srmacklem if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 3486191783Srmacklem NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 3487191783Srmacklem} 3488191783Srmacklem 3489191783Srmacklem/* 3490191783Srmacklem * Lock a socket against others. 3491191783Srmacklem * Currently used to serialize connect/disconnect attempts. 3492191783Srmacklem */ 3493191783Srmacklemint 3494191783Srmacklemnewnfs_sndlock(int *flagp) 3495191783Srmacklem{ 3496191783Srmacklem struct timespec ts; 3497191783Srmacklem 3498191783Srmacklem NFSLOCKSOCK(); 3499191783Srmacklem while (*flagp & NFSR_SNDLOCK) { 3500191783Srmacklem *flagp |= NFSR_WANTSND; 3501191783Srmacklem ts.tv_sec = 0; 3502191783Srmacklem ts.tv_nsec = 0; 3503191783Srmacklem (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 3504191783Srmacklem PZERO - 1, "nfsndlck", &ts); 3505191783Srmacklem } 3506191783Srmacklem *flagp |= NFSR_SNDLOCK; 3507191783Srmacklem NFSUNLOCKSOCK(); 3508191783Srmacklem return (0); 3509191783Srmacklem} 3510191783Srmacklem 3511191783Srmacklem/* 3512191783Srmacklem * Unlock the stream socket for others. 3513191783Srmacklem */ 3514191783Srmacklemvoid 3515191783Srmacklemnewnfs_sndunlock(int *flagp) 3516191783Srmacklem{ 3517191783Srmacklem 3518191783Srmacklem NFSLOCKSOCK(); 3519191783Srmacklem if ((*flagp & NFSR_SNDLOCK) == 0) 3520191783Srmacklem panic("nfs sndunlock"); 3521191783Srmacklem *flagp &= ~NFSR_SNDLOCK; 3522191783Srmacklem if (*flagp & NFSR_WANTSND) { 3523191783Srmacklem *flagp &= ~NFSR_WANTSND; 3524191783Srmacklem wakeup((caddr_t)flagp); 3525191783Srmacklem } 3526191783Srmacklem NFSUNLOCKSOCK(); 3527191783Srmacklem} 3528191783Srmacklem 3529