nfs_commonsubs.c revision 306809
167754Smsmith/*- 267754Smsmith * Copyright (c) 1989, 1993 377424Smsmith * The Regents of the University of California. All rights reserved. 467754Smsmith * 567754Smsmith * This code is derived from software contributed to Berkeley by 667754Smsmith * Rick Macklem at The University of Guelph. 7217365Sjkim * 8306536Sjkim * Redistribution and use in source and binary forms, with or without 970243Smsmith * modification, are permitted provided that the following conditions 1067754Smsmith * are met: 11217365Sjkim * 1. Redistributions of source code must retain the above copyright 12217365Sjkim * notice, this list of conditions and the following disclaimer. 13217365Sjkim * 2. Redistributions in binary form must reproduce the above copyright 14217365Sjkim * notice, this list of conditions and the following disclaimer in the 15217365Sjkim * documentation and/or other materials provided with the distribution. 16217365Sjkim * 4. Neither the name of the University nor the names of its contributors 17217365Sjkim * may be used to endorse or promote products derived from this software 18217365Sjkim * without specific prior written permission. 19217365Sjkim * 20217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21217365Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23217365Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24217365Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2567754Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28217365Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2967754Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30217365Sjkim * SUCH DAMAGE. 31217365Sjkim * 32217365Sjkim */ 33217365Sjkim 34217365Sjkim#include <sys/cdefs.h> 35217365Sjkim__FBSDID("$FreeBSD: stable/10/sys/fs/nfs/nfs_commonsubs.c 306809 2016-10-07 14:46:34Z emaste $"); 36217365Sjkim 37217365Sjkim/* 38217365Sjkim * These functions support the macros and help fiddle mbuf chains for 39217365Sjkim * the nfs op functions. They do things like create the rpc header and 40217365Sjkim * copy data between mbuf chains and uio lists. 41217365Sjkim */ 42217365Sjkim#ifndef APPLEKEXT 4367754Smsmith#include "opt_inet6.h" 44193341Sjkim 45193341Sjkim#include <fs/nfs/nfsport.h> 46193341Sjkim 47193341Sjkim#include <security/mac/mac_framework.h> 48193341Sjkim 4967754Smsmith/* 50193267Sjkim * Data items converted to xdr at startup, since they are constant 5177424Smsmith * This is kinda hokey, but may save a little time doing byte swaps 5291116Smsmith */ 5367754Smsmithu_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1; 5467754Smsmith 5567754Smsmith/* And other global data */ 5667754Smsmithnfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, 57102550Siwasaki NFFIFO, NFNON }; 5867754Smsmithenum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; 59151937Sjkimenum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 60151937Sjkimstruct timeval nfsboottime; /* Copy boottime once, so it never changes */ 61151937Sjkimint nfscl_ticks; 62151937Sjkimint nfsrv_useacl = 1; 63306536Sjkimstruct nfssockreq nfsrv_nfsuserdsock; 64306536Sjkimint nfsrv_nfsuserd = 0; 65151937Sjkimstruct nfsreqhead nfsd_reqq; 66151937Sjkimuid_t nfsrv_defaultuid; 67151937Sjkimgid_t nfsrv_defaultgid; 68306536Sjkimint nfsrv_lease = NFSRV_LEASE; 69306536Sjkimint ncl_mbuf_mlen = MLEN; 70151937Sjkimint nfsd_enable_stringtouid = 0; 71151937SjkimNFSNAMEIDMUTEX; 72167802SjkimNFSSOCKMUTEX; 73167802Sjkimextern int nfsrv_lughashsize; 74167802Sjkim 75151937Sjkim/* 76151937Sjkim * This array of structures indicates, for V4: 77167802Sjkim * retfh - which of 3 types of calling args are used 78151937Sjkim * 0 - doesn't change cfh or use a sfh 79151937Sjkim * 1 - replaces cfh with a new one (unless it returns an error status) 80151937Sjkim * 2 - uses cfh and sfh 81167802Sjkim * needscfh - if the op wants a cfh and premtime 82151937Sjkim * 0 - doesn't use a cfh 83151937Sjkim * 1 - uses a cfh, but doesn't want pre-op attributes 84151937Sjkim * 2 - uses a cfh and wants pre-op attributes 85151937Sjkim * savereply - indicates a non-idempotent Op 86151937Sjkim * 0 - not non-idempotent 87151937Sjkim * 1 - non-idempotent 8867754Smsmith * Ops that are ordered via seqid# are handled separately from these 89167802Sjkim * non-idempotent Ops. 90167802Sjkim * Define it here, since it is used by both the client and server. 91167802Sjkim */ 92167802Sjkimstruct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = { 93167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */ 94167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */ 95167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* undef */ 96167802Sjkim { 0, 1, 0, 0, LK_SHARED, 1 }, /* Access */ 97167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Close */ 98167802Sjkim { 0, 2, 0, 1, LK_EXCLUSIVE, 1 }, /* Commit */ 99167802Sjkim { 1, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Create */ 100167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegpurge */ 101167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Delegreturn */ 102167802Sjkim { 0, 1, 0, 0, LK_SHARED, 1 }, /* Getattr */ 103167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* GetFH */ 104167802Sjkim { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Link */ 105167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Lock */ 106167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockT */ 107167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* LockU */ 108167802Sjkim { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookup */ 109167802Sjkim { 1, 2, 0, 0, LK_EXCLUSIVE, 1 }, /* Lookupp */ 110167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* NVerify */ 111167802Sjkim { 1, 1, 0, 1, LK_EXCLUSIVE, 1 }, /* Open */ 112167802Sjkim { 1, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenAttr */ 113167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenConfirm */ 114167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* OpenDowngrade */ 115281075Sdim { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutFH */ 116167802Sjkim { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutPubFH */ 117167802Sjkim { 1, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* PutRootFH */ 118167802Sjkim { 0, 1, 0, 0, LK_SHARED, 1 }, /* Read */ 119281075Sdim { 0, 1, 0, 0, LK_SHARED, 1 }, /* Readdir */ 120167802Sjkim { 0, 1, 0, 0, LK_SHARED, 1 }, /* ReadLink */ 121167802Sjkim { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Remove */ 122281075Sdim { 2, 1, 1, 1, LK_EXCLUSIVE, 1 }, /* Rename */ 123167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Renew */ 124167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* RestoreFH */ 125167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SaveFH */ 126167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* SecInfo */ 127167802Sjkim { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Setattr */ 128167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientID */ 129167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* SetClientIDConfirm */ 130167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Verify */ 131167802Sjkim { 0, 2, 1, 1, LK_EXCLUSIVE, 1 }, /* Write */ 132234623Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* ReleaseLockOwner */ 133281075Sdim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Backchannel Ctrl */ 134281075Sdim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Bind Conn to Sess */ 135167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Exchange ID */ 136167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Create Session */ 137167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy Session */ 138167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Free StateID */ 139167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Dir Deleg */ 140167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device Info */ 141167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Get Device List */ 142167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Commit */ 143193267Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Get */ 144167802Sjkim { 0, 1, 0, 0, LK_EXCLUSIVE, 1 }, /* Layout Return */ 145167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Secinfo No name */ 146217365Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Sequence */ 147193267Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Set SSV */ 148167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Test StateID */ 149167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Want Delegation */ 150167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 0 }, /* Destroy ClientID */ 151167802Sjkim { 0, 0, 0, 0, LK_EXCLUSIVE, 1 }, /* Reclaim Complete */ 152167802Sjkim}; 153167802Sjkim#endif /* !APPLEKEXT */ 154167802Sjkim 155167802Sjkimstatic int ncl_mbuf_mhlen = MHLEN; 156281075Sdimstatic int nfsrv_usercnt = 0; 157167802Sjkimstatic int nfsrv_dnsnamelen; 158167802Sjkimstatic u_char *nfsrv_dnsname = NULL; 159167802Sjkimstatic int nfsrv_usermax = 999999999; 160281075Sdimstruct nfsrv_lughash { 161167802Sjkim struct mtx mtx; 162167802Sjkim struct nfsuserhashhead lughead; 163167802Sjkim}; 164167802Sjkimstatic struct nfsrv_lughash *nfsuserhash; 165167802Sjkimstatic struct nfsrv_lughash *nfsusernamehash; 166281075Sdimstatic struct nfsrv_lughash *nfsgrouphash; 167167802Sjkimstatic struct nfsrv_lughash *nfsgroupnamehash; 168167802Sjkim 169167802Sjkim/* 170167802Sjkim * This static array indicates whether or not the RPC generates a large 171281075Sdim * reply. This is used by nfs_reply() to decide whether or not an mbuf 172167802Sjkim * cluster should be allocated. (If a cluster is required by an RPC 173167802Sjkim * marked 0 in this array, the code will still work, just not quite as 174281075Sdim * efficiently.) 175167802Sjkim */ 176167802Sjkimint nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 177167802Sjkim 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, 178281075Sdim 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }; 179167802Sjkim 180167802Sjkim/* local functions */ 181167802Sjkimstatic int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); 182167802Sjkimstatic void nfsv4_wanted(struct nfsv4lock *lp); 183234623Sjkimstatic int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len); 184281075Sdimstatic int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, 185281075Sdim NFSPROC_T *p); 186167802Sjkimstatic void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser); 187167802Sjkimstatic int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **, 188167802Sjkim int *, int *); 189167802Sjkimstatic void nfsrv_refstrbigenough(int, u_char **, u_char **, int *); 190167802Sjkim 191167802Sjkim 192167802Sjkim#ifndef APPLE 193167802Sjkim/* 194234623Sjkim * copies mbuf chain to the uio scatter/gather list 195234623Sjkim */ 196167802Sjkimint 197167802Sjkimnfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz) 198167802Sjkim{ 199167802Sjkim char *mbufcp, *uiocp; 200167802Sjkim int xfer, left, len; 201167802Sjkim mbuf_t mp; 202234623Sjkim long uiosiz, rem; 203234623Sjkim int error = 0; 204167802Sjkim 205167802Sjkim mp = nd->nd_md; 206167802Sjkim mbufcp = nd->nd_dpos; 207167802Sjkim len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp; 208167802Sjkim rem = NFSM_RNDUP(siz) - siz; 209167802Sjkim while (siz > 0) { 210167802Sjkim if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) { 211167802Sjkim error = EBADRPC; 212167802Sjkim goto out; 213167802Sjkim } 214228110Sjkim left = uiop->uio_iov->iov_len; 215167802Sjkim uiocp = uiop->uio_iov->iov_base; 216167802Sjkim if (left > siz) 217167802Sjkim left = siz; 218228110Sjkim uiosiz = left; 219228110Sjkim while (left > 0) { 220228110Sjkim while (len == 0) { 221167802Sjkim mp = mbuf_next(mp); 222167802Sjkim if (mp == NULL) { 223167802Sjkim error = EBADRPC; 224167802Sjkim goto out; 225167802Sjkim } 226167802Sjkim mbufcp = NFSMTOD(mp, caddr_t); 227167802Sjkim len = mbuf_len(mp); 228167802Sjkim KASSERT(len >= 0, 229167802Sjkim ("len %d, corrupted mbuf?", len)); 230167802Sjkim } 231167802Sjkim xfer = (left > len) ? len : left; 232167802Sjkim#ifdef notdef 233167802Sjkim /* Not Yet.. */ 234167802Sjkim if (uiop->uio_iov->iov_op != NULL) 235167802Sjkim (*(uiop->uio_iov->iov_op)) 236167802Sjkim (mbufcp, uiocp, xfer); 237167802Sjkim else 238167802Sjkim#endif 239167802Sjkim if (uiop->uio_segflg == UIO_SYSSPACE) 240167802Sjkim NFSBCOPY(mbufcp, uiocp, xfer); 241306536Sjkim else 242167802Sjkim copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer); 243167802Sjkim left -= xfer; 244193267Sjkim len -= xfer; 245167802Sjkim mbufcp += xfer; 246193267Sjkim uiocp += xfer; 247167802Sjkim uiop->uio_offset += xfer; 248281075Sdim uiop->uio_resid -= xfer; 249167802Sjkim } 250306536Sjkim if (uiop->uio_iov->iov_len <= siz) { 251167802Sjkim uiop->uio_iovcnt--; 252167802Sjkim uiop->uio_iov++; 253167802Sjkim } else { 254167802Sjkim uiop->uio_iov->iov_base = (void *) 255167802Sjkim ((char *)uiop->uio_iov->iov_base + uiosiz); 256167802Sjkim uiop->uio_iov->iov_len -= uiosiz; 257167802Sjkim } 258281075Sdim siz -= uiosiz; 259281075Sdim } 260281075Sdim nd->nd_dpos = mbufcp; 261167802Sjkim nd->nd_md = mp; 262167802Sjkim if (rem > 0) { 263167802Sjkim if (len < rem) 264234623Sjkim error = nfsm_advance(nd, rem, len); 265167802Sjkim else 266167802Sjkim nd->nd_dpos += rem; 267281075Sdim } 268234623Sjkim 269234623Sjkimout: 270234623Sjkim NFSEXITCODE2(error, nd); 271234623Sjkim return (error); 272234623Sjkim} 273167802Sjkim#endif /* !APPLE */ 274167802Sjkim 275281075Sdim/* 276281075Sdim * Help break down an mbuf chain by setting the first siz bytes contiguous 277281075Sdim * pointed to by returned val. 278281075Sdim * This is used by the macro NFSM_DISSECT for tough 279281075Sdim * cases. 280281075Sdim */ 281281075SdimAPPLESTATIC void * 282281075Sdimnfsm_dissct(struct nfsrv_descript *nd, int siz, int how) 283281075Sdim{ 284167802Sjkim mbuf_t mp2; 285281075Sdim int siz2, xfer; 286281075Sdim caddr_t p; 287281075Sdim int left; 288281075Sdim caddr_t retp; 289281075Sdim 290281075Sdim retp = NULL; 291281075Sdim left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos; 292167802Sjkim while (left == 0) { 293167802Sjkim nd->nd_md = mbuf_next(nd->nd_md); 294281075Sdim if (nd->nd_md == NULL) 295167802Sjkim return (retp); 296167802Sjkim left = mbuf_len(nd->nd_md); 297167802Sjkim nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); 298167802Sjkim } 299281075Sdim if (left >= siz) { 300281075Sdim retp = nd->nd_dpos; 301167802Sjkim nd->nd_dpos += siz; 302167802Sjkim } else if (mbuf_next(nd->nd_md) == NULL) { 303167802Sjkim return (retp); 304167802Sjkim } else if (siz > ncl_mbuf_mhlen) { 305167802Sjkim panic("nfs S too big"); 306167802Sjkim } else { 307167802Sjkim MGET(mp2, MT_DATA, how); 308167802Sjkim if (mp2 == NULL) 309167802Sjkim return (NULL); 310167802Sjkim mbuf_setnext(mp2, mbuf_next(nd->nd_md)); 311281075Sdim mbuf_setnext(nd->nd_md, mp2); 312167802Sjkim mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left); 313167802Sjkim nd->nd_md = mp2; 314281075Sdim retp = p = NFSMTOD(mp2, caddr_t); 315167802Sjkim NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */ 316167802Sjkim siz2 = siz - left; 317167802Sjkim p += left; 318167802Sjkim mp2 = mbuf_next(mp2); 319281075Sdim /* Loop around copying up the siz2 bytes */ 320281075Sdim while (siz2 > 0) { 321281075Sdim if (mp2 == NULL) 322281075Sdim return (NULL); 323167802Sjkim xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2; 324167802Sjkim if (xfer > 0) { 325167802Sjkim NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer); 326167802Sjkim NFSM_DATAP(mp2, xfer); 327167802Sjkim mbuf_setlen(mp2, mbuf_len(mp2) - xfer); 328167802Sjkim p += xfer; 329167802Sjkim siz2 -= xfer; 330167802Sjkim } 331167802Sjkim if (siz2 > 0) 332167802Sjkim mp2 = mbuf_next(mp2); 333167802Sjkim } 334167802Sjkim mbuf_setlen(nd->nd_md, siz); 335167802Sjkim nd->nd_md = mp2; 336167802Sjkim nd->nd_dpos = NFSMTOD(mp2, caddr_t); 337167802Sjkim } 338167802Sjkim return (retp); 339167802Sjkim} 340167802Sjkim 341167802Sjkim/* 342167802Sjkim * Advance the position in the mbuf chain. 343167802Sjkim * If offs == 0, this is a no-op, but it is simpler to just return from 344167802Sjkim * here than check for offs > 0 for all calls to nfsm_advance. 345167802Sjkim * If left == -1, it should be calculated here. 346167802Sjkim */ 347167802SjkimAPPLESTATIC int 348167802Sjkimnfsm_advance(struct nfsrv_descript *nd, int offs, int left) 349167802Sjkim{ 350167802Sjkim int error = 0; 351167802Sjkim 352167802Sjkim if (offs == 0) 353167802Sjkim goto out; 354167802Sjkim /* 355167802Sjkim * A negative offs should be considered a serious problem. 356167802Sjkim */ 357281075Sdim if (offs < 0) 358281075Sdim panic("nfsrv_advance"); 359281075Sdim 360167802Sjkim /* 361167802Sjkim * If left == -1, calculate it here. 362167802Sjkim */ 363167802Sjkim if (left == -1) 364167802Sjkim left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - 365167802Sjkim nd->nd_dpos; 366167802Sjkim 367167802Sjkim /* 368167802Sjkim * Loop around, advancing over the mbuf data. 369167802Sjkim */ 370167802Sjkim while (offs > left) { 371167802Sjkim offs -= left; 372167802Sjkim nd->nd_md = mbuf_next(nd->nd_md); 373167802Sjkim if (nd->nd_md == NULL) { 374167802Sjkim error = EBADRPC; 375167802Sjkim goto out; 376167802Sjkim } 377167802Sjkim left = mbuf_len(nd->nd_md); 378167802Sjkim nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); 379167802Sjkim } 380167802Sjkim nd->nd_dpos += offs; 381167802Sjkim 382167802Sjkimout: 383306536Sjkim NFSEXITCODE(error); 384167802Sjkim return (error); 385281075Sdim} 386281075Sdim 387281075Sdim/* 388281075Sdim * Copy a string into mbuf(s). 389167802Sjkim * Return the number of bytes output, including XDR overheads. 390167802Sjkim */ 391167802SjkimAPPLESTATIC int 392167802Sjkimnfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz) 393167802Sjkim{ 394167802Sjkim mbuf_t m2; 395167802Sjkim int xfer, left; 396167802Sjkim mbuf_t m1; 397167802Sjkim int rem, bytesize; 398167802Sjkim u_int32_t *tl; 399167802Sjkim char *cp2; 400167802Sjkim 401167802Sjkim NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 402167802Sjkim *tl = txdr_unsigned(siz); 403167802Sjkim rem = NFSM_RNDUP(siz) - siz; 404167802Sjkim bytesize = NFSX_UNSIGNED + siz + rem; 405167802Sjkim m2 = nd->nd_mb; 406167802Sjkim cp2 = nd->nd_bpos; 407167802Sjkim left = M_TRAILINGSPACE(m2); 408167802Sjkim 409167802Sjkim /* 410167802Sjkim * Loop around copying the string to mbuf(s). 411250838Sjkim */ 412167802Sjkim while (siz > 0) { 413167802Sjkim if (left == 0) { 414167802Sjkim if (siz > ncl_mbuf_mlen) 415193267Sjkim NFSMCLGET(m1, M_WAITOK); 416281075Sdim else 417281075Sdim NFSMGET(m1); 418167802Sjkim mbuf_setlen(m1, 0); 419167802Sjkim mbuf_setnext(m2, m1); 420167802Sjkim m2 = m1; 421167802Sjkim cp2 = NFSMTOD(m2, caddr_t); 422167802Sjkim left = M_TRAILINGSPACE(m2); 423167802Sjkim } 424167802Sjkim if (left >= siz) 425167802Sjkim xfer = siz; 426167802Sjkim else 427167802Sjkim xfer = left; 428167802Sjkim NFSBCOPY(cp, cp2, xfer); 429167802Sjkim cp += xfer; 430167802Sjkim mbuf_setlen(m2, mbuf_len(m2) + xfer); 431167802Sjkim siz -= xfer; 432167802Sjkim left -= xfer; 433167802Sjkim if (siz == 0 && rem) { 434167802Sjkim if (left < rem) 435167802Sjkim panic("nfsm_strtom"); 436167802Sjkim NFSBZERO(cp2 + xfer, rem); 437167802Sjkim mbuf_setlen(m2, mbuf_len(m2) + rem); 438193267Sjkim } 439167802Sjkim } 440167802Sjkim nd->nd_mb = m2; 441167802Sjkim nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); 442167802Sjkim return (bytesize); 443167802Sjkim} 444167802Sjkim 445167802Sjkim/* 446167802Sjkim * Called once to initialize data structures... 447167802Sjkim */ 448167802SjkimAPPLESTATIC void 449167802Sjkimnewnfs_init(void) 450167802Sjkim{ 451167802Sjkim static int nfs_inited = 0; 452167802Sjkim 453167802Sjkim if (nfs_inited) 454167802Sjkim return; 455306536Sjkim nfs_inited = 1; 456306536Sjkim 457167802Sjkim newnfs_true = txdr_unsigned(TRUE); 458167802Sjkim newnfs_false = txdr_unsigned(FALSE); 459167802Sjkim newnfs_xdrneg1 = txdr_unsigned(-1); 460167802Sjkim nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 461167802Sjkim if (nfscl_ticks < 1) 462167802Sjkim nfscl_ticks = 1; 463167802Sjkim NFSSETBOOTTIME(nfsboottime); 464167802Sjkim 465167802Sjkim /* 466167802Sjkim * Initialize reply list and start timer 467167802Sjkim */ 468167802Sjkim TAILQ_INIT(&nfsd_reqq); 469167802Sjkim NFS_TIMERINIT; 470167802Sjkim} 471167802Sjkim 472167802Sjkim/* 473167802Sjkim * Put a file handle in an mbuf list. 474306536Sjkim * If the size argument == 0, just use the default size. 475167802Sjkim * set_true == 1 if there should be an newnfs_true prepended on the file handle. 476167802Sjkim * Return the number of bytes output, including XDR overhead. 477167802Sjkim */ 478281075SdimAPPLESTATIC int 479281075Sdimnfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true) 480281075Sdim{ 481281075Sdim u_int32_t *tl; 482281075Sdim u_int8_t *cp; 483281075Sdim int fullsiz, rem, bytesize = 0; 484281075Sdim 485281075Sdim if (size == 0) 486281075Sdim size = NFSX_MYFH; 487281075Sdim switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { 488281075Sdim case ND_NFSV2: 489281075Sdim if (size > NFSX_V2FH) 490281075Sdim panic("fh size > NFSX_V2FH for NFSv2"); 491281075Sdim NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH); 492281075Sdim NFSBCOPY(fhp, cp, size); 493281075Sdim if (size < NFSX_V2FH) 494281075Sdim NFSBZERO(cp + size, NFSX_V2FH - size); 495281075Sdim bytesize = NFSX_V2FH; 496281075Sdim break; 497281075Sdim case ND_NFSV3: 498281075Sdim case ND_NFSV4: 499281075Sdim fullsiz = NFSM_RNDUP(size); 500281075Sdim rem = fullsiz - size; 501281075Sdim if (set_true) { 502281075Sdim bytesize = 2 * NFSX_UNSIGNED + fullsiz; 503306536Sjkim NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 504306536Sjkim *tl = newnfs_true; 505281075Sdim } else { 506281075Sdim bytesize = NFSX_UNSIGNED + fullsiz; 507281075Sdim } 508281075Sdim (void) nfsm_strtom(nd, fhp, size); 509281075Sdim break; 510281075Sdim }; 511281075Sdim return (bytesize); 512281075Sdim} 513281075Sdim 514281075Sdim/* 515281075Sdim * This function compares two net addresses by family and returns TRUE 516281075Sdim * if they are the same host. 517281075Sdim * If there is any doubt, return FALSE. 518281075Sdim * The AF_INET family is handled as a special case so that address mbufs 519281075Sdim * don't need to be saved to store "struct in_addr", which is only 4 bytes. 520281075Sdim */ 521281075SdimAPPLESTATIC int 522306536Sjkimnfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam) 523306536Sjkim{ 524281075Sdim struct sockaddr_in *inetaddr; 525281075Sdim 526281075Sdim switch (family) { 527281075Sdim case AF_INET: 528281075Sdim inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *); 529281075Sdim if (inetaddr->sin_family == AF_INET && 530281075Sdim inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr) 531281075Sdim return (1); 532281075Sdim break; 533281075Sdim#ifdef INET6 534281075Sdim case AF_INET6: 535306536Sjkim { 536306536Sjkim struct sockaddr_in6 *inetaddr6; 537281075Sdim 538281075Sdim inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *); 539281075Sdim /* XXX - should test sin6_scope_id ? */ 540306536Sjkim if (inetaddr6->sin6_family == AF_INET6 && 541306536Sjkim IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr, 542281075Sdim &haddr->had_inet6)) 543281075Sdim return (1); 544281075Sdim } 545281075Sdim break; 546281075Sdim#endif 547281075Sdim }; 548281075Sdim return (0); 549281075Sdim} 550281075Sdim 551281075Sdim/* 552281075Sdim * Similar to the above, but takes to NFSSOCKADDR_T args. 553281075Sdim */ 554281075SdimAPPLESTATIC int 555281075Sdimnfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2) 556281075Sdim{ 557281075Sdim struct sockaddr_in *addr1, *addr2; 558281075Sdim struct sockaddr *inaddr; 559281075Sdim 560281075Sdim inaddr = NFSSOCKADDR(nam1, struct sockaddr *); 561281075Sdim switch (inaddr->sa_family) { 562281075Sdim case AF_INET: 563281075Sdim addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *); 564281075Sdim addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *); 565281075Sdim if (addr2->sin_family == AF_INET && 566281075Sdim addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) 567281075Sdim return (1); 568281075Sdim break; 569281075Sdim#ifdef INET6 570281075Sdim case AF_INET6: 571281075Sdim { 572281075Sdim struct sockaddr_in6 *inet6addr1, *inet6addr2; 573281075Sdim 574281075Sdim inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *); 575306536Sjkim inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *); 576306536Sjkim /* XXX - should test sin6_scope_id ? */ 577281075Sdim if (inet6addr2->sin6_family == AF_INET6 && 578281075Sdim IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 579281075Sdim &inet6addr2->sin6_addr)) 580281075Sdim return (1); 581281075Sdim } 582281075Sdim break; 583281075Sdim#endif 584281075Sdim }; 585281075Sdim return (0); 586281075Sdim} 587281075Sdim 588281075Sdim 589281075Sdim/* 590281075Sdim * Trim the stuff already dissected off the mbuf list. 591281075Sdim */ 592281075SdimAPPLESTATIC void 593281075Sdimnewnfs_trimleading(nd) 594281075Sdim struct nfsrv_descript *nd; 595281075Sdim{ 596281075Sdim mbuf_t m, n; 597167802Sjkim int offs; 598193267Sjkim 599193267Sjkim /* 600193267Sjkim * First, free up leading mbufs. 601167802Sjkim */ 602167802Sjkim if (nd->nd_mrep != nd->nd_md) { 603167802Sjkim m = nd->nd_mrep; 604167802Sjkim while (mbuf_next(m) != nd->nd_md) { 605167802Sjkim if (mbuf_next(m) == NULL) 606167802Sjkim panic("nfsm trim leading"); 607167802Sjkim m = mbuf_next(m); 608167802Sjkim } 609167802Sjkim mbuf_setnext(m, NULL); 610167802Sjkim mbuf_freem(nd->nd_mrep); 611167802Sjkim } 61277424Smsmith m = nd->nd_md; 61367754Smsmith 614151937Sjkim /* 615151937Sjkim * Now, adjust this mbuf, based on nd_dpos. 61667754Smsmith */ 617138287Smarks offs = nd->nd_dpos - NFSMTOD(m, caddr_t); 61867754Smsmith if (offs == mbuf_len(m)) { 61991116Smsmith n = m; 62067754Smsmith m = mbuf_next(m); 621151937Sjkim if (m == NULL) 62267754Smsmith panic("nfsm trim leading2"); 62399679Siwasaki mbuf_setnext(n, NULL); 62477424Smsmith mbuf_freem(n); 625138287Smarks } else if (offs > 0) { 626138287Smarks mbuf_setlen(m, mbuf_len(m) - offs); 62767754Smsmith NFSM_DATAP(m, offs); 62867754Smsmith } else if (offs < 0) 629138287Smarks panic("nfsm trimleading offs"); 63067754Smsmith nd->nd_mrep = m; 63167754Smsmith nd->nd_md = m; 632167802Sjkim nd->nd_dpos = NFSMTOD(m, caddr_t); 63377424Smsmith} 63477424Smsmith 635245582Sjkim/* 636245582Sjkim * Trim trailing data off the mbuf list being built. 637245582Sjkim */ 63887031SmsmithAPPLESTATIC void 63999679Siwasakinewnfs_trimtrailing(nd, mb, bpos) 64087031Smsmith struct nfsrv_descript *nd; 64187031Smsmith mbuf_t mb; 64291116Smsmith caddr_t bpos; 64367754Smsmith{ 644151937Sjkim 645151937Sjkim if (mbuf_next(mb)) { 646138287Smarks mbuf_freem(mbuf_next(mb)); 64799679Siwasaki mbuf_setnext(mb, NULL); 64867754Smsmith } 64967754Smsmith mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t)); 65091116Smsmith nd->nd_mb = mb; 65167754Smsmith nd->nd_bpos = bpos; 652151937Sjkim} 65399146Siwasaki 65499679Siwasaki/* 65567754Smsmith * Dissect a file handle on the client. 65667754Smsmith */ 65799679SiwasakiAPPLESTATIC int 65867754Smsmithnfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp) 659123315Snjl{ 660138287Smarks u_int32_t *tl; 661138287Smarks struct nfsfh *nfhp; 66291116Smsmith int error, len; 66399679Siwasaki 66467754Smsmith *nfhpp = NULL; 66567754Smsmith if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 666123315Snjl NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 66767754Smsmith if ((len = fxdr_unsigned(int, *tl)) <= 0 || 668138287Smarks len > NFSX_FHMAX) { 669138287Smarks error = EBADRPC; 670138287Smarks goto nfsmout; 671138287Smarks } 672138287Smarks } else 673138287Smarks len = NFSX_V2FH; 674138287Smarks MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len, 675138287Smarks M_NFSFH, M_WAITOK); 676138287Smarks error = nfsrv_mtostr(nd, nfhp->nfh_fh, len); 67767754Smsmith if (error) { 678151937Sjkim FREE((caddr_t)nfhp, M_NFSFH); 679138287Smarks goto nfsmout; 680193267Sjkim } 68167754Smsmith nfhp->nfh_len = len; 682107325Siwasaki *nfhpp = nfhp; 68367754Smsmithnfsmout: 684306536Sjkim NFSEXITCODE2(error, nd); 685306536Sjkim return (error); 686193267Sjkim} 687193267Sjkim 68867754Smsmith/* 689193267Sjkim * Break down the nfsv4 acl. 69067754Smsmith * If the aclp == NULL or won't fit in an acl, just discard the acl info. 691193267Sjkim */ 69267754SmsmithAPPLESTATIC int 69367754Smsmithnfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp, 694193267Sjkim int *aclsizep, __unused NFSPROC_T *p) 69567754Smsmith{ 696193267Sjkim u_int32_t *tl; 69767754Smsmith int i, aclsize; 69867754Smsmith int acecnt, error = 0, aceerr = 0, acesize; 699193267Sjkim 700100966Siwasaki *aclerrp = 0; 701193267Sjkim if (aclp) 702100966Siwasaki aclp->acl_cnt = 0; 703100966Siwasaki /* 704193267Sjkim * Parse out the ace entries and expect them to conform to 70567754Smsmith * what can be supported by R/W/X bits. 706193267Sjkim */ 707193267Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 708193267Sjkim aclsize = NFSX_UNSIGNED; 70967754Smsmith acecnt = fxdr_unsigned(int, *tl); 71067754Smsmith if (acecnt > ACL_MAX_ENTRIES) 711193267Sjkim aceerr = NFSERR_ATTRNOTSUPP; 71267754Smsmith if (nfsrv_useacl == 0) 713306536Sjkim aceerr = NFSERR_ATTRNOTSUPP; 714306536Sjkim for (i = 0; i < acecnt; i++) { 71567754Smsmith if (aclp && !aceerr) 71667754Smsmith error = nfsrv_dissectace(nd, &aclp->acl_entry[i], 717193267Sjkim &aceerr, &acesize, p); 718193267Sjkim else 719100966Siwasaki error = nfsrv_skipace(nd, &acesize); 720193267Sjkim if (error) 72167754Smsmith goto nfsmout; 72267754Smsmith aclsize += acesize; 723193267Sjkim } 72467754Smsmith if (aclp && !aceerr) 725193267Sjkim aclp->acl_cnt = acecnt; 72667754Smsmith if (aceerr) 72767754Smsmith *aclerrp = aceerr; 72867754Smsmith if (aclsizep) 72967754Smsmith *aclsizep = aclsize; 73067754Smsmithnfsmout: 73167754Smsmith NFSEXITCODE2(error, nd); 732193267Sjkim return (error); 733138287Smarks} 73467754Smsmith 73567754Smsmith/* 73667754Smsmith * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it. 73791116Smsmith */ 73867754Smsmithstatic int 739193267Sjkimnfsrv_skipace(struct nfsrv_descript *nd, int *acesizep) 740193267Sjkim{ 74167754Smsmith u_int32_t *tl; 742193267Sjkim int error, len = 0; 74367754Smsmith 744193267Sjkim NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 745306536Sjkim len = fxdr_unsigned(int, *(tl + 3)); 746306536Sjkim error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 747193267Sjkimnfsmout: 74867754Smsmith *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); 74967754Smsmith NFSEXITCODE2(error, nd); 75067754Smsmith return (error); 75171867Smsmith} 75267754Smsmith 75387031Smsmith/* 754138287Smarks * Get attribute bits from an mbuf list. 75567754Smsmith * Returns EBADRPC for a parsing error, 0 otherwise. 75667754Smsmith * If the clearinvalid flag is set, clear the bits not supported. 75767754Smsmith */ 75867754SmsmithAPPLESTATIC int 759138287Smarksnfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp, 760138287Smarks int *retnotsupp) 76167754Smsmith{ 76267754Smsmith u_int32_t *tl; 763138287Smarks int cnt, i, outcnt; 76467754Smsmith int error = 0; 76567754Smsmith 76691116Smsmith NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 76791116Smsmith cnt = fxdr_unsigned(int, *tl); 76883174Smsmith if (cnt < 0) { 76967754Smsmith error = NFSERR_BADXDR; 770138287Smarks goto nfsmout; 77167754Smsmith } 772306536Sjkim if (cnt > NFSATTRBIT_MAXWORDS) 773306536Sjkim outcnt = NFSATTRBIT_MAXWORDS; 77467754Smsmith else 77567754Smsmith outcnt = cnt; 77667754Smsmith NFSZERO_ATTRBIT(attrbitp); 77767754Smsmith if (outcnt > 0) { 77867754Smsmith NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED); 77967754Smsmith for (i = 0; i < outcnt; i++) 78087031Smsmith attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++); 78191116Smsmith } 78291116Smsmith for (i = 0; i < (cnt - outcnt); i++) { 78367754Smsmith NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 78467754Smsmith if (retnotsupp != NULL && *tl != 0) 78567754Smsmith *retnotsupp = NFSERR_ATTRNOTSUPP; 78667754Smsmith } 78767754Smsmith if (cntp) 78891116Smsmith *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED); 78967754Smsmithnfsmout: 79087031Smsmith NFSEXITCODE2(error, nd); 79167754Smsmith return (error); 79267754Smsmith} 79367754Smsmith 79487031Smsmith/* 795281687Sjkim * Get the attributes for V4. 79691116Smsmith * If the compare flag is true, test for any attribute changes, 79767754Smsmith * otherwise return the attribute values. 79867754Smsmith * These attributes cover fields in "struct vattr", "struct statfs", 79967754Smsmith * "struct nfsfsinfo", the file handle and the lease duration. 80067754Smsmith * The value of retcmpp is set to 1 if all attributes are the same, 80167754Smsmith * and 0 otherwise. 802107325Siwasaki * Returns EBADRPC if it can't be parsed, 0 otherwise. 803151937Sjkim */ 804151937SjkimAPPLESTATIC int 805151937Sjkimnfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, 806107325Siwasaki struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize, 807107325Siwasaki struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp, 80867754Smsmith struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp, 80967754Smsmith u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred) 810107325Siwasaki{ 81167754Smsmith u_int32_t *tl; 81287031Smsmith int i = 0, j, k, l = 0, m, bitpos, attrsum = 0; 81367754Smsmith int error, tfhsize, aceerr, attrsize, cnt, retnotsup; 81467754Smsmith u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1]; 815107325Siwasaki nfsattrbit_t attrbits, retattrbits, checkattrbits; 81667754Smsmith struct nfsfh *tnfhp; 817193267Sjkim struct nfsreferral *refp; 818193267Sjkim u_quad_t tquad; 819151937Sjkim nfsquad_t tnfsquad; 820151937Sjkim struct timespec temptime; 82191116Smsmith uid_t uid; 82291116Smsmith gid_t gid; 823151937Sjkim long fid; 824151937Sjkim u_int32_t freenum = 0, tuint; 825151937Sjkim u_int64_t uquad = 0, thyp, thyp2; 826306536Sjkim#ifdef QUOTA 82767754Smsmith struct dqblk dqb; 82867754Smsmith uid_t savuid; 829107325Siwasaki#endif 83067754Smsmith 83187031Smsmith if (compare) { 83267754Smsmith retnotsup = 0; 83367754Smsmith error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); 83477424Smsmith } else { 83567754Smsmith error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 836193267Sjkim } 837151937Sjkim if (error) 838151937Sjkim goto nfsmout; 83991116Smsmith 84067754Smsmith if (compare) { 84191116Smsmith *retcmpp = retnotsup; 84267754Smsmith } else { 843151937Sjkim /* 84467754Smsmith * Just set default values to some of the important ones. 845193267Sjkim */ 846306536Sjkim if (nap != NULL) { 84767754Smsmith nap->na_type = VREG; 848151937Sjkim nap->na_mode = 0; 84967754Smsmith nap->na_rdev = (NFSDEV_T)0; 85067754Smsmith nap->na_mtime.tv_sec = 0; 85167754Smsmith nap->na_mtime.tv_nsec = 0; 852306536Sjkim nap->na_gen = 0; 85367754Smsmith nap->na_flags = 0; 85467754Smsmith nap->na_blocksize = NFS_FABLKSIZE; 85567754Smsmith } 85667754Smsmith if (sbp != NULL) { 85767754Smsmith sbp->f_bsize = NFS_FABLKSIZE; 85887031Smsmith sbp->f_blocks = 0; 85967754Smsmith sbp->f_bfree = 0; 86067754Smsmith sbp->f_bavail = 0; 86167754Smsmith sbp->f_files = 0; 86267754Smsmith sbp->f_ffree = 0; 863151937Sjkim } 86491116Smsmith if (fsp != NULL) { 865151937Sjkim fsp->fs_rtmax = 8192; 866151937Sjkim fsp->fs_rtpref = 8192; 86767754Smsmith fsp->fs_maxname = NFS_MAXNAMLEN; 86867754Smsmith fsp->fs_wtmax = 8192; 86967754Smsmith fsp->fs_wtpref = 8192; 87067754Smsmith fsp->fs_wtmult = NFS_FABLKSIZE; 87187031Smsmith fsp->fs_dtpref = 8192; 87267754Smsmith fsp->fs_maxfilesize = 0xffffffffffffffffull; 87367754Smsmith fsp->fs_timedelta.tv_sec = 0; 87467754Smsmith fsp->fs_timedelta.tv_nsec = 1; 87567754Smsmith fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK | 87687031Smsmith NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME); 87767754Smsmith } 87867754Smsmith if (pc != NULL) { 87967754Smsmith pc->pc_linkmax = LINK_MAX; 88067754Smsmith pc->pc_namemax = NAME_MAX; 88187031Smsmith pc->pc_notrunc = 0; 88267754Smsmith pc->pc_chownrestricted = 0; 88367754Smsmith pc->pc_caseinsensitive = 0; 88467754Smsmith pc->pc_casepreserving = 1; 88567754Smsmith } 88687031Smsmith } 88767754Smsmith 88867754Smsmith /* 88967754Smsmith * Loop around getting the attributes. 89067754Smsmith */ 89187031Smsmith NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 89267754Smsmith attrsize = fxdr_unsigned(int, *tl); 89367754Smsmith for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 894250838Sjkim if (attrsum > attrsize) { 89567754Smsmith error = NFSERR_BADXDR; 89699679Siwasaki goto nfsmout; 89767754Smsmith } 898193267Sjkim if (NFSISSET_ATTRBIT(&attrbits, bitpos)) 89967754Smsmith switch (bitpos) { 90067754Smsmith case NFSATTRBIT_SUPPORTEDATTRS: 90167754Smsmith retnotsup = 0; 90299679Siwasaki if (compare || nap == NULL) 90367754Smsmith error = nfsrv_getattrbits(nd, &retattrbits, 90467754Smsmith &cnt, &retnotsup); 90567754Smsmith else 906151937Sjkim error = nfsrv_getattrbits(nd, &nap->na_suppattr, 90767754Smsmith &cnt, &retnotsup); 90877424Smsmith if (error) 90967754Smsmith goto nfsmout; 910193267Sjkim if (compare && !(*retcmpp)) { 911193267Sjkim NFSSETSUPP_ATTRBIT(&checkattrbits); 912193267Sjkim if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 91367754Smsmith || retnotsup) 914193267Sjkim *retcmpp = NFSERR_NOTSAME; 91567754Smsmith } 916151937Sjkim attrsum += cnt; 91767754Smsmith break; 91867754Smsmith case NFSATTRBIT_TYPE: 91977424Smsmith NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 92067754Smsmith if (compare) { 921193267Sjkim if (!(*retcmpp)) { 922193267Sjkim if (nap->na_type != nfsv34tov_type(*tl)) 92367754Smsmith *retcmpp = NFSERR_NOTSAME; 924167802Sjkim } 92582367Smsmith } else if (nap != NULL) { 92683174Smsmith nap->na_type = nfsv34tov_type(*tl); 927193267Sjkim } 92867754Smsmith attrsum += NFSX_UNSIGNED; 929193267Sjkim break; 93067754Smsmith case NFSATTRBIT_FHEXPIRETYPE: 93167754Smsmith NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 93299146Siwasaki if (compare && !(*retcmpp)) { 933209746Sjkim if (fxdr_unsigned(int, *tl) != 934193267Sjkim NFSV4FHTYPE_PERSISTENT) 93567754Smsmith *retcmpp = NFSERR_NOTSAME; 936193267Sjkim } 93777424Smsmith attrsum += NFSX_UNSIGNED; 938193267Sjkim break; 93977424Smsmith case NFSATTRBIT_CHANGE: 94067754Smsmith NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 941193267Sjkim if (compare) { 94267754Smsmith if (!(*retcmpp)) { 943193267Sjkim if (nap->na_filerev != fxdr_hyper(tl)) 94467754Smsmith *retcmpp = NFSERR_NOTSAME; 945193267Sjkim } 946193267Sjkim } else if (nap != NULL) { 947193267Sjkim nap->na_filerev = fxdr_hyper(tl); 94867754Smsmith } 94967754Smsmith attrsum += NFSX_HYPER; 95099146Siwasaki break; 951193267Sjkim case NFSATTRBIT_SIZE: 95267754Smsmith NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 95367754Smsmith if (compare) { 95467754Smsmith if (!(*retcmpp)) { 95567754Smsmith if (nap->na_size != fxdr_hyper(tl)) 956151937Sjkim *retcmpp = NFSERR_NOTSAME; 95767754Smsmith } 958151937Sjkim } else if (nap != NULL) { 95987031Smsmith nap->na_size = fxdr_hyper(tl); 96087031Smsmith } 96187031Smsmith attrsum += NFSX_HYPER; 96287031Smsmith break; 963241973Sjkim case NFSATTRBIT_LINKSUPPORT: 96487031Smsmith NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 96587031Smsmith if (compare) { 96687031Smsmith if (!(*retcmpp)) { 967151937Sjkim if (fsp->fs_properties & NFSV3_FSFLINK) { 96887031Smsmith if (*tl == newnfs_false) 969151937Sjkim *retcmpp = NFSERR_NOTSAME; 97087031Smsmith } else { 971306536Sjkim if (*tl == newnfs_true) 972306536Sjkim *retcmpp = NFSERR_NOTSAME; 97387031Smsmith } 97487031Smsmith } 97587031Smsmith } else if (fsp != NULL) { 97687031Smsmith if (*tl == newnfs_true) 977151937Sjkim fsp->fs_properties |= NFSV3_FSFLINK; 97887031Smsmith else 979306536Sjkim fsp->fs_properties &= ~NFSV3_FSFLINK; 980306536Sjkim } 98187031Smsmith attrsum += NFSX_UNSIGNED; 98287031Smsmith break; 98387031Smsmith case NFSATTRBIT_SYMLINKSUPPORT: 98487031Smsmith NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 98587031Smsmith if (compare) { 986151937Sjkim if (!(*retcmpp)) { 98787031Smsmith if (fsp->fs_properties & NFSV3_FSFSYMLINK) { 988167802Sjkim if (*tl == newnfs_false) 98967754Smsmith *retcmpp = NFSERR_NOTSAME; 990167802Sjkim } else { 991151937Sjkim if (*tl == newnfs_true) 99267754Smsmith *retcmpp = NFSERR_NOTSAME; 99367754Smsmith } 99467754Smsmith } 995151937Sjkim } else if (fsp != NULL) { 99667754Smsmith if (*tl == newnfs_true) 99767754Smsmith fsp->fs_properties |= NFSV3_FSFSYMLINK; 998167802Sjkim else 99967754Smsmith fsp->fs_properties &= ~NFSV3_FSFSYMLINK; 100067754Smsmith } 100167754Smsmith attrsum += NFSX_UNSIGNED; 100267754Smsmith break; 100391116Smsmith case NFSATTRBIT_NAMEDATTR: 100483174Smsmith NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 100583174Smsmith if (compare && !(*retcmpp)) { 100667754Smsmith if (*tl != newnfs_false) 100767754Smsmith *retcmpp = NFSERR_NOTSAME; 1008245582Sjkim } 1009245582Sjkim attrsum += NFSX_UNSIGNED; 1010245582Sjkim break; 101167754Smsmith case NFSATTRBIT_FSID: 101267754Smsmith NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 101367754Smsmith thyp = fxdr_hyper(tl); 101467754Smsmith tl += 2; 101567754Smsmith thyp2 = fxdr_hyper(tl); 1016193267Sjkim if (compare) { 1017281075Sdim if (*retcmpp == 0) { 1018281075Sdim if (thyp != (u_int64_t) 1019167802Sjkim vfs_statfs(vnode_mount(vp))->f_fsid.val[0] || 1020167802Sjkim thyp2 != (u_int64_t) 1021167802Sjkim vfs_statfs(vnode_mount(vp))->f_fsid.val[1]) 102267754Smsmith *retcmpp = NFSERR_NOTSAME; 102367754Smsmith } 102467754Smsmith } else if (nap != NULL) { 1025151937Sjkim nap->na_filesid[0] = thyp; 102667754Smsmith nap->na_filesid[1] = thyp2; 1027167802Sjkim } 1028151937Sjkim attrsum += (4 * NFSX_UNSIGNED); 1029151937Sjkim break; 1030151937Sjkim case NFSATTRBIT_UNIQUEHANDLES: 1031151937Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1032151937Sjkim if (compare && !(*retcmpp)) { 1033151937Sjkim if (*tl != newnfs_true) 1034151937Sjkim *retcmpp = NFSERR_NOTSAME; 1035151937Sjkim } 1036167802Sjkim attrsum += NFSX_UNSIGNED; 1037151937Sjkim break; 1038151937Sjkim case NFSATTRBIT_LEASETIME: 1039151937Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1040151937Sjkim if (compare) { 1041151937Sjkim if (fxdr_unsigned(int, *tl) != nfsrv_lease && 1042151937Sjkim !(*retcmpp)) 1043167802Sjkim *retcmpp = NFSERR_NOTSAME; 1044167802Sjkim } else if (leasep != NULL) { 1045193267Sjkim *leasep = fxdr_unsigned(u_int32_t, *tl); 1046151937Sjkim } 1047193267Sjkim attrsum += NFSX_UNSIGNED; 1048167802Sjkim break; 1049306536Sjkim case NFSATTRBIT_RDATTRERROR: 1050306536Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1051151937Sjkim if (compare) { 1052151937Sjkim if (!(*retcmpp)) 1053193267Sjkim *retcmpp = NFSERR_INVAL; 1054151937Sjkim } else if (rderrp != NULL) { 1055151937Sjkim *rderrp = fxdr_unsigned(u_int32_t, *tl); 1056151937Sjkim } 1057151937Sjkim attrsum += NFSX_UNSIGNED; 1058167802Sjkim break; 1059151937Sjkim case NFSATTRBIT_ACL: 1060151937Sjkim if (compare) { 1061151937Sjkim if (!(*retcmpp)) { 1062151937Sjkim if (nfsrv_useacl) { 1063193267Sjkim NFSACL_T *naclp; 1064193267Sjkim 1065306536Sjkim naclp = acl_alloc(M_WAITOK); 1066306536Sjkim error = nfsrv_dissectacl(nd, naclp, &aceerr, 1067193267Sjkim &cnt, p); 1068193267Sjkim if (error) { 1069306536Sjkim acl_free(naclp); 1070306536Sjkim goto nfsmout; 1071193267Sjkim } 1072193267Sjkim if (aceerr || aclp == NULL || 1073193267Sjkim nfsrv_compareacl(aclp, naclp)) 1074306536Sjkim *retcmpp = NFSERR_NOTSAME; 1075193267Sjkim acl_free(naclp); 1076306536Sjkim } else { 1077193267Sjkim error = nfsrv_dissectacl(nd, NULL, &aceerr, 1078193267Sjkim &cnt, p); 1079193267Sjkim *retcmpp = NFSERR_ATTRNOTSUPP; 1080193267Sjkim } 1081193267Sjkim } 1082193267Sjkim } else { 1083151937Sjkim if (vp != NULL && aclp != NULL) 1084151937Sjkim error = nfsrv_dissectacl(nd, aclp, &aceerr, 1085151937Sjkim &cnt, p); 1086151937Sjkim else 1087151937Sjkim error = nfsrv_dissectacl(nd, NULL, &aceerr, 1088151937Sjkim &cnt, p); 1089167802Sjkim if (error) 1090151937Sjkim goto nfsmout; 1091167802Sjkim } 1092151937Sjkim attrsum += cnt; 1093151937Sjkim break; 1094151937Sjkim case NFSATTRBIT_ACLSUPPORT: 1095151937Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1096151937Sjkim if (compare && !(*retcmpp)) { 1097151937Sjkim if (nfsrv_useacl) { 1098151937Sjkim if (fxdr_unsigned(u_int32_t, *tl) != 1099151937Sjkim NFSV4ACE_SUPTYPES) 1100167802Sjkim *retcmpp = NFSERR_NOTSAME; 1101151937Sjkim } else { 1102151937Sjkim *retcmpp = NFSERR_ATTRNOTSUPP; 1103151937Sjkim } 1104151937Sjkim } 1105151937Sjkim attrsum += NFSX_UNSIGNED; 1106151937Sjkim break; 1107151937Sjkim case NFSATTRBIT_ARCHIVE: 1108151937Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1109151937Sjkim if (compare && !(*retcmpp)) 1110151937Sjkim *retcmpp = NFSERR_ATTRNOTSUPP; 1111151937Sjkim attrsum += NFSX_UNSIGNED; 1112151937Sjkim break; 1113151937Sjkim case NFSATTRBIT_CANSETTIME: 1114151937Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1115151937Sjkim if (compare) { 1116151937Sjkim if (!(*retcmpp)) { 1117151937Sjkim if (fsp->fs_properties & NFSV3_FSFCANSETTIME) { 1118151937Sjkim if (*tl == newnfs_false) 1119151937Sjkim *retcmpp = NFSERR_NOTSAME; 1120151937Sjkim } else { 1121151937Sjkim if (*tl == newnfs_true) 1122151937Sjkim *retcmpp = NFSERR_NOTSAME; 1123151937Sjkim } 1124151937Sjkim } 1125151937Sjkim } else if (fsp != NULL) { 1126151937Sjkim if (*tl == newnfs_true) 1127151937Sjkim fsp->fs_properties |= NFSV3_FSFCANSETTIME; 1128151937Sjkim else 1129151937Sjkim fsp->fs_properties &= ~NFSV3_FSFCANSETTIME; 1130151937Sjkim } 1131151937Sjkim attrsum += NFSX_UNSIGNED; 1132193267Sjkim break; 1133151937Sjkim case NFSATTRBIT_CASEINSENSITIVE: 1134151937Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1135151937Sjkim if (compare) { 1136151937Sjkim if (!(*retcmpp)) { 1137193267Sjkim if (*tl != newnfs_false) 1138151937Sjkim *retcmpp = NFSERR_NOTSAME; 1139151937Sjkim } 1140151937Sjkim } else if (pc != NULL) { 1141151937Sjkim pc->pc_caseinsensitive = 1142151937Sjkim fxdr_unsigned(u_int32_t, *tl); 1143234623Sjkim } 1144151937Sjkim attrsum += NFSX_UNSIGNED; 1145151937Sjkim break; 1146151937Sjkim case NFSATTRBIT_CASEPRESERVING: 1147151937Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1148151937Sjkim if (compare) { 1149151937Sjkim if (!(*retcmpp)) { 1150151937Sjkim if (*tl != newnfs_true) 1151151937Sjkim *retcmpp = NFSERR_NOTSAME; 1152306536Sjkim } 1153306536Sjkim } else if (pc != NULL) { 1154193267Sjkim pc->pc_casepreserving = 1155151937Sjkim fxdr_unsigned(u_int32_t, *tl); 1156151937Sjkim } 1157151937Sjkim attrsum += NFSX_UNSIGNED; 1158151937Sjkim break; 1159151937Sjkim case NFSATTRBIT_CHOWNRESTRICTED: 1160151937Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1161151937Sjkim if (compare) { 1162151937Sjkim if (!(*retcmpp)) { 1163151937Sjkim if (*tl != newnfs_true) 1164209746Sjkim *retcmpp = NFSERR_NOTSAME; 1165193267Sjkim } 1166151937Sjkim } else if (pc != NULL) { 1167151937Sjkim pc->pc_chownrestricted = 1168151937Sjkim fxdr_unsigned(u_int32_t, *tl); 1169306536Sjkim } 1170306536Sjkim attrsum += NFSX_UNSIGNED; 1171151937Sjkim break; 1172151937Sjkim case NFSATTRBIT_FILEHANDLE: 1173151937Sjkim error = nfsm_getfh(nd, &tnfhp); 1174151937Sjkim if (error) 1175151937Sjkim goto nfsmout; 1176193267Sjkim tfhsize = tnfhp->nfh_len; 1177193267Sjkim if (compare) { 1178193267Sjkim if (!(*retcmpp) && 1179167802Sjkim !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize, 1180151937Sjkim fhp, fhsize)) 1181151937Sjkim *retcmpp = NFSERR_NOTSAME; 1182151937Sjkim FREE((caddr_t)tnfhp, M_NFSFH); 1183151937Sjkim } else if (nfhpp != NULL) { 1184193267Sjkim *nfhpp = tnfhp; 1185151937Sjkim } else { 1186151937Sjkim FREE((caddr_t)tnfhp, M_NFSFH); 1187151937Sjkim } 1188151937Sjkim attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize)); 1189151937Sjkim break; 1190151937Sjkim case NFSATTRBIT_FILEID: 1191151937Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 119277424Smsmith thyp = fxdr_hyper(tl); 119367754Smsmith if (compare) { 1194167802Sjkim if (!(*retcmpp)) { 1195151937Sjkim if ((u_int64_t)nap->na_fileid != thyp) 119667754Smsmith *retcmpp = NFSERR_NOTSAME; 119767754Smsmith } 119867754Smsmith } else if (nap != NULL) { 1199151937Sjkim if (*tl++) 120067754Smsmith printf("NFSv4 fileid > 32bits\n"); 120167754Smsmith nap->na_fileid = thyp; 120277424Smsmith } 120367754Smsmith attrsum += NFSX_HYPER; 120467754Smsmith break; 120567754Smsmith case NFSATTRBIT_FILESAVAIL: 1206167802Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 120782367Smsmith if (compare) { 120882367Smsmith if (!(*retcmpp) && 1209151937Sjkim sfp->sf_afiles != fxdr_hyper(tl)) 1210151937Sjkim *retcmpp = NFSERR_NOTSAME; 1211151937Sjkim } else if (sfp != NULL) { 1212151937Sjkim sfp->sf_afiles = fxdr_hyper(tl); 121367754Smsmith } 121467754Smsmith attrsum += NFSX_HYPER; 121567754Smsmith break; 1216245582Sjkim case NFSATTRBIT_FILESFREE: 1217245582Sjkim NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1218245582Sjkim if (compare) { 121967754Smsmith if (!(*retcmpp) && 1220100966Siwasaki sfp->sf_ffiles != fxdr_hyper(tl)) 122167754Smsmith *retcmpp = NFSERR_NOTSAME; 122267754Smsmith } else if (sfp != NULL) { 122367754Smsmith sfp->sf_ffiles = fxdr_hyper(tl); 1224104470Siwasaki } 1225104470Siwasaki attrsum += NFSX_HYPER; 1226167802Sjkim break; 1227167802Sjkim case NFSATTRBIT_FILESTOTAL: 1228138287Smarks NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1229138287Smarks if (compare) { 1230167802Sjkim if (!(*retcmpp) && 1231281075Sdim sfp->sf_tfiles != fxdr_hyper(tl)) 1232281075Sdim *retcmpp = NFSERR_NOTSAME; 1233104470Siwasaki } else if (sfp != NULL) { 1234104470Siwasaki sfp->sf_tfiles = fxdr_hyper(tl); 123599679Siwasaki } 123667754Smsmith attrsum += NFSX_HYPER; 1237138287Smarks break; 1238281075Sdim case NFSATTRBIT_FSLOCATIONS: 1239138287Smarks error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m); 1240100966Siwasaki if (error) 124167754Smsmith goto nfsmout; 124267754Smsmith attrsum += l; 1243281075Sdim if (compare && !(*retcmpp)) { 1244281075Sdim refp = nfsv4root_getreferral(vp, NULL, 0); 1245281075Sdim if (refp != NULL) { 124667754Smsmith if (cp == NULL || cp2 == NULL || 1247281075Sdim strcmp(cp, "/") || 1248281075Sdim strcmp(cp2, refp->nfr_srvlist)) 1249167802Sjkim *retcmpp = NFSERR_NOTSAME; 1250167802Sjkim } else if (m == 0) { 125167754Smsmith *retcmpp = NFSERR_NOTSAME; 1252281075Sdim } 1253281075Sdim } 1254281075Sdim if (cp != NULL) 1255167802Sjkim free(cp, M_NFSSTRING); 125667754Smsmith if (cp2 != NULL) 1257167802Sjkim free(cp2, M_NFSSTRING); 125867754Smsmith break; 1259167802Sjkim case NFSATTRBIT_HIDDEN: 126067754Smsmith NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1261167802Sjkim if (compare && !(*retcmpp)) 1262281075Sdim *retcmpp = NFSERR_ATTRNOTSUPP; 1263281075Sdim attrsum += NFSX_UNSIGNED; 1264281075Sdim break; 1265281075Sdim case NFSATTRBIT_HOMOGENEOUS: 1266281075Sdim NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1267281075Sdim if (compare) { 1268306536Sjkim if (!(*retcmpp)) { 1269306536Sjkim if (fsp->fs_properties & 1270281075Sdim NFSV3_FSFHOMOGENEOUS) { 1271281075Sdim if (*tl == newnfs_false) 1272281075Sdim *retcmpp = NFSERR_NOTSAME; 1273281075Sdim } else { 1274281075Sdim if (*tl == newnfs_true) 1275281075Sdim *retcmpp = NFSERR_NOTSAME; 1276281075Sdim } 1277281075Sdim } 1278281075Sdim } else if (fsp != NULL) { 127967754Smsmith if (*tl == newnfs_true) 128067754Smsmith fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS; 128167754Smsmith else 128267754Smsmith fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS; 1283 } 1284 attrsum += NFSX_UNSIGNED; 1285 break; 1286 case NFSATTRBIT_MAXFILESIZE: 1287 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1288 tnfsquad.qval = fxdr_hyper(tl); 1289 if (compare) { 1290 if (!(*retcmpp)) { 1291 tquad = NFSRV_MAXFILESIZE; 1292 if (tquad != tnfsquad.qval) 1293 *retcmpp = NFSERR_NOTSAME; 1294 } 1295 } else if (fsp != NULL) { 1296 fsp->fs_maxfilesize = tnfsquad.qval; 1297 } 1298 attrsum += NFSX_HYPER; 1299 break; 1300 case NFSATTRBIT_MAXLINK: 1301 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1302 if (compare) { 1303 if (!(*retcmpp)) { 1304 if (fxdr_unsigned(int, *tl) != LINK_MAX) 1305 *retcmpp = NFSERR_NOTSAME; 1306 } 1307 } else if (pc != NULL) { 1308 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl); 1309 } 1310 attrsum += NFSX_UNSIGNED; 1311 break; 1312 case NFSATTRBIT_MAXNAME: 1313 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1314 if (compare) { 1315 if (!(*retcmpp)) { 1316 if (fsp->fs_maxname != 1317 fxdr_unsigned(u_int32_t, *tl)) 1318 *retcmpp = NFSERR_NOTSAME; 1319 } 1320 } else { 1321 tuint = fxdr_unsigned(u_int32_t, *tl); 1322 /* 1323 * Some Linux NFSv4 servers report this 1324 * as 0 or 4billion, so I'll set it to 1325 * NFS_MAXNAMLEN. If a server actually creates 1326 * a name longer than NFS_MAXNAMLEN, it will 1327 * get an error back. 1328 */ 1329 if (tuint == 0 || tuint > NFS_MAXNAMLEN) 1330 tuint = NFS_MAXNAMLEN; 1331 if (fsp != NULL) 1332 fsp->fs_maxname = tuint; 1333 if (pc != NULL) 1334 pc->pc_namemax = tuint; 1335 } 1336 attrsum += NFSX_UNSIGNED; 1337 break; 1338 case NFSATTRBIT_MAXREAD: 1339 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1340 if (compare) { 1341 if (!(*retcmpp)) { 1342 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t, 1343 *(tl + 1)) || *tl != 0) 1344 *retcmpp = NFSERR_NOTSAME; 1345 } 1346 } else if (fsp != NULL) { 1347 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl); 1348 fsp->fs_rtpref = fsp->fs_rtmax; 1349 fsp->fs_dtpref = fsp->fs_rtpref; 1350 } 1351 attrsum += NFSX_HYPER; 1352 break; 1353 case NFSATTRBIT_MAXWRITE: 1354 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1355 if (compare) { 1356 if (!(*retcmpp)) { 1357 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t, 1358 *(tl + 1)) || *tl != 0) 1359 *retcmpp = NFSERR_NOTSAME; 1360 } 1361 } else if (fsp != NULL) { 1362 fsp->fs_wtmax = fxdr_unsigned(int, *++tl); 1363 fsp->fs_wtpref = fsp->fs_wtmax; 1364 } 1365 attrsum += NFSX_HYPER; 1366 break; 1367 case NFSATTRBIT_MIMETYPE: 1368 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1369 i = fxdr_unsigned(int, *tl); 1370 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); 1371 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 1372 if (error) 1373 goto nfsmout; 1374 if (compare && !(*retcmpp)) 1375 *retcmpp = NFSERR_ATTRNOTSUPP; 1376 break; 1377 case NFSATTRBIT_MODE: 1378 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1379 if (compare) { 1380 if (!(*retcmpp)) { 1381 if (nap->na_mode != nfstov_mode(*tl)) 1382 *retcmpp = NFSERR_NOTSAME; 1383 } 1384 } else if (nap != NULL) { 1385 nap->na_mode = nfstov_mode(*tl); 1386 } 1387 attrsum += NFSX_UNSIGNED; 1388 break; 1389 case NFSATTRBIT_NOTRUNC: 1390 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1391 if (compare) { 1392 if (!(*retcmpp)) { 1393 if (*tl != newnfs_true) 1394 *retcmpp = NFSERR_NOTSAME; 1395 } 1396 } else if (pc != NULL) { 1397 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl); 1398 } 1399 attrsum += NFSX_UNSIGNED; 1400 break; 1401 case NFSATTRBIT_NUMLINKS: 1402 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1403 tuint = fxdr_unsigned(u_int32_t, *tl); 1404 if (compare) { 1405 if (!(*retcmpp)) { 1406 if ((u_int32_t)nap->na_nlink != tuint) 1407 *retcmpp = NFSERR_NOTSAME; 1408 } 1409 } else if (nap != NULL) { 1410 nap->na_nlink = tuint; 1411 } 1412 attrsum += NFSX_UNSIGNED; 1413 break; 1414 case NFSATTRBIT_OWNER: 1415 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1416 j = fxdr_unsigned(int, *tl); 1417 if (j < 0) { 1418 error = NFSERR_BADXDR; 1419 goto nfsmout; 1420 } 1421 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1422 if (j > NFSV4_SMALLSTR) 1423 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1424 else 1425 cp = namestr; 1426 error = nfsrv_mtostr(nd, cp, j); 1427 if (error) { 1428 if (j > NFSV4_SMALLSTR) 1429 free(cp, M_NFSSTRING); 1430 goto nfsmout; 1431 } 1432 if (compare) { 1433 if (!(*retcmpp)) { 1434 if (nfsv4_strtouid(nd, cp, j, &uid, p) || 1435 nap->na_uid != uid) 1436 *retcmpp = NFSERR_NOTSAME; 1437 } 1438 } else if (nap != NULL) { 1439 if (nfsv4_strtouid(nd, cp, j, &uid, p)) 1440 nap->na_uid = nfsrv_defaultuid; 1441 else 1442 nap->na_uid = uid; 1443 } 1444 if (j > NFSV4_SMALLSTR) 1445 free(cp, M_NFSSTRING); 1446 break; 1447 case NFSATTRBIT_OWNERGROUP: 1448 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1449 j = fxdr_unsigned(int, *tl); 1450 if (j < 0) { 1451 error = NFSERR_BADXDR; 1452 goto nfsmout; 1453 } 1454 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1455 if (j > NFSV4_SMALLSTR) 1456 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1457 else 1458 cp = namestr; 1459 error = nfsrv_mtostr(nd, cp, j); 1460 if (error) { 1461 if (j > NFSV4_SMALLSTR) 1462 free(cp, M_NFSSTRING); 1463 goto nfsmout; 1464 } 1465 if (compare) { 1466 if (!(*retcmpp)) { 1467 if (nfsv4_strtogid(nd, cp, j, &gid, p) || 1468 nap->na_gid != gid) 1469 *retcmpp = NFSERR_NOTSAME; 1470 } 1471 } else if (nap != NULL) { 1472 if (nfsv4_strtogid(nd, cp, j, &gid, p)) 1473 nap->na_gid = nfsrv_defaultgid; 1474 else 1475 nap->na_gid = gid; 1476 } 1477 if (j > NFSV4_SMALLSTR) 1478 free(cp, M_NFSSTRING); 1479 break; 1480 case NFSATTRBIT_QUOTAHARD: 1481 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1482 if (sbp != NULL) { 1483 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1484 freenum = sbp->f_bfree; 1485 else 1486 freenum = sbp->f_bavail; 1487#ifdef QUOTA 1488 /* 1489 * ufs_quotactl() insists that the uid argument 1490 * equal p_ruid for non-root quota access, so 1491 * we'll just make sure that's the case. 1492 */ 1493 savuid = p->p_cred->p_ruid; 1494 p->p_cred->p_ruid = cred->cr_uid; 1495 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1496 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1497 freenum = min(dqb.dqb_bhardlimit, freenum); 1498 p->p_cred->p_ruid = savuid; 1499#endif /* QUOTA */ 1500 uquad = (u_int64_t)freenum; 1501 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1502 } 1503 if (compare && !(*retcmpp)) { 1504 if (uquad != fxdr_hyper(tl)) 1505 *retcmpp = NFSERR_NOTSAME; 1506 } 1507 attrsum += NFSX_HYPER; 1508 break; 1509 case NFSATTRBIT_QUOTASOFT: 1510 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1511 if (sbp != NULL) { 1512 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1513 freenum = sbp->f_bfree; 1514 else 1515 freenum = sbp->f_bavail; 1516#ifdef QUOTA 1517 /* 1518 * ufs_quotactl() insists that the uid argument 1519 * equal p_ruid for non-root quota access, so 1520 * we'll just make sure that's the case. 1521 */ 1522 savuid = p->p_cred->p_ruid; 1523 p->p_cred->p_ruid = cred->cr_uid; 1524 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1525 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1526 freenum = min(dqb.dqb_bsoftlimit, freenum); 1527 p->p_cred->p_ruid = savuid; 1528#endif /* QUOTA */ 1529 uquad = (u_int64_t)freenum; 1530 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1531 } 1532 if (compare && !(*retcmpp)) { 1533 if (uquad != fxdr_hyper(tl)) 1534 *retcmpp = NFSERR_NOTSAME; 1535 } 1536 attrsum += NFSX_HYPER; 1537 break; 1538 case NFSATTRBIT_QUOTAUSED: 1539 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1540 if (sbp != NULL) { 1541 freenum = 0; 1542#ifdef QUOTA 1543 /* 1544 * ufs_quotactl() insists that the uid argument 1545 * equal p_ruid for non-root quota access, so 1546 * we'll just make sure that's the case. 1547 */ 1548 savuid = p->p_cred->p_ruid; 1549 p->p_cred->p_ruid = cred->cr_uid; 1550 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1551 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1552 freenum = dqb.dqb_curblocks; 1553 p->p_cred->p_ruid = savuid; 1554#endif /* QUOTA */ 1555 uquad = (u_int64_t)freenum; 1556 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1557 } 1558 if (compare && !(*retcmpp)) { 1559 if (uquad != fxdr_hyper(tl)) 1560 *retcmpp = NFSERR_NOTSAME; 1561 } 1562 attrsum += NFSX_HYPER; 1563 break; 1564 case NFSATTRBIT_RAWDEV: 1565 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA); 1566 j = fxdr_unsigned(int, *tl++); 1567 k = fxdr_unsigned(int, *tl); 1568 if (compare) { 1569 if (!(*retcmpp)) { 1570 if (nap->na_rdev != NFSMAKEDEV(j, k)) 1571 *retcmpp = NFSERR_NOTSAME; 1572 } 1573 } else if (nap != NULL) { 1574 nap->na_rdev = NFSMAKEDEV(j, k); 1575 } 1576 attrsum += NFSX_V4SPECDATA; 1577 break; 1578 case NFSATTRBIT_SPACEAVAIL: 1579 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1580 if (compare) { 1581 if (!(*retcmpp) && 1582 sfp->sf_abytes != fxdr_hyper(tl)) 1583 *retcmpp = NFSERR_NOTSAME; 1584 } else if (sfp != NULL) { 1585 sfp->sf_abytes = fxdr_hyper(tl); 1586 } 1587 attrsum += NFSX_HYPER; 1588 break; 1589 case NFSATTRBIT_SPACEFREE: 1590 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1591 if (compare) { 1592 if (!(*retcmpp) && 1593 sfp->sf_fbytes != fxdr_hyper(tl)) 1594 *retcmpp = NFSERR_NOTSAME; 1595 } else if (sfp != NULL) { 1596 sfp->sf_fbytes = fxdr_hyper(tl); 1597 } 1598 attrsum += NFSX_HYPER; 1599 break; 1600 case NFSATTRBIT_SPACETOTAL: 1601 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1602 if (compare) { 1603 if (!(*retcmpp) && 1604 sfp->sf_tbytes != fxdr_hyper(tl)) 1605 *retcmpp = NFSERR_NOTSAME; 1606 } else if (sfp != NULL) { 1607 sfp->sf_tbytes = fxdr_hyper(tl); 1608 } 1609 attrsum += NFSX_HYPER; 1610 break; 1611 case NFSATTRBIT_SPACEUSED: 1612 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1613 thyp = fxdr_hyper(tl); 1614 if (compare) { 1615 if (!(*retcmpp)) { 1616 if ((u_int64_t)nap->na_bytes != thyp) 1617 *retcmpp = NFSERR_NOTSAME; 1618 } 1619 } else if (nap != NULL) { 1620 nap->na_bytes = thyp; 1621 } 1622 attrsum += NFSX_HYPER; 1623 break; 1624 case NFSATTRBIT_SYSTEM: 1625 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1626 if (compare && !(*retcmpp)) 1627 *retcmpp = NFSERR_ATTRNOTSUPP; 1628 attrsum += NFSX_UNSIGNED; 1629 break; 1630 case NFSATTRBIT_TIMEACCESS: 1631 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1632 fxdr_nfsv4time(tl, &temptime); 1633 if (compare) { 1634 if (!(*retcmpp)) { 1635 if (!NFS_CMPTIME(temptime, nap->na_atime)) 1636 *retcmpp = NFSERR_NOTSAME; 1637 } 1638 } else if (nap != NULL) { 1639 nap->na_atime = temptime; 1640 } 1641 attrsum += NFSX_V4TIME; 1642 break; 1643 case NFSATTRBIT_TIMEACCESSSET: 1644 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1645 attrsum += NFSX_UNSIGNED; 1646 i = fxdr_unsigned(int, *tl); 1647 if (i == NFSV4SATTRTIME_TOCLIENT) { 1648 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1649 attrsum += NFSX_V4TIME; 1650 } 1651 if (compare && !(*retcmpp)) 1652 *retcmpp = NFSERR_INVAL; 1653 break; 1654 case NFSATTRBIT_TIMEBACKUP: 1655 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1656 if (compare && !(*retcmpp)) 1657 *retcmpp = NFSERR_ATTRNOTSUPP; 1658 attrsum += NFSX_V4TIME; 1659 break; 1660 case NFSATTRBIT_TIMECREATE: 1661 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1662 if (compare && !(*retcmpp)) 1663 *retcmpp = NFSERR_ATTRNOTSUPP; 1664 attrsum += NFSX_V4TIME; 1665 break; 1666 case NFSATTRBIT_TIMEDELTA: 1667 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1668 if (fsp != NULL) { 1669 if (compare) { 1670 if (!(*retcmpp)) { 1671 if ((u_int32_t)fsp->fs_timedelta.tv_sec != 1672 fxdr_unsigned(u_int32_t, *(tl + 1)) || 1673 (u_int32_t)fsp->fs_timedelta.tv_nsec != 1674 (fxdr_unsigned(u_int32_t, *(tl + 2)) % 1675 1000000000) || 1676 *tl != 0) 1677 *retcmpp = NFSERR_NOTSAME; 1678 } 1679 } else { 1680 fxdr_nfsv4time(tl, &fsp->fs_timedelta); 1681 } 1682 } 1683 attrsum += NFSX_V4TIME; 1684 break; 1685 case NFSATTRBIT_TIMEMETADATA: 1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1687 fxdr_nfsv4time(tl, &temptime); 1688 if (compare) { 1689 if (!(*retcmpp)) { 1690 if (!NFS_CMPTIME(temptime, nap->na_ctime)) 1691 *retcmpp = NFSERR_NOTSAME; 1692 } 1693 } else if (nap != NULL) { 1694 nap->na_ctime = temptime; 1695 } 1696 attrsum += NFSX_V4TIME; 1697 break; 1698 case NFSATTRBIT_TIMEMODIFY: 1699 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1700 fxdr_nfsv4time(tl, &temptime); 1701 if (compare) { 1702 if (!(*retcmpp)) { 1703 if (!NFS_CMPTIME(temptime, nap->na_mtime)) 1704 *retcmpp = NFSERR_NOTSAME; 1705 } 1706 } else if (nap != NULL) { 1707 nap->na_mtime = temptime; 1708 } 1709 attrsum += NFSX_V4TIME; 1710 break; 1711 case NFSATTRBIT_TIMEMODIFYSET: 1712 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1713 attrsum += NFSX_UNSIGNED; 1714 i = fxdr_unsigned(int, *tl); 1715 if (i == NFSV4SATTRTIME_TOCLIENT) { 1716 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1717 attrsum += NFSX_V4TIME; 1718 } 1719 if (compare && !(*retcmpp)) 1720 *retcmpp = NFSERR_INVAL; 1721 break; 1722 case NFSATTRBIT_MOUNTEDONFILEID: 1723 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1724 thyp = fxdr_hyper(tl); 1725 if (compare) { 1726 if (!(*retcmpp)) { 1727 if (*tl++) { 1728 *retcmpp = NFSERR_NOTSAME; 1729 } else { 1730 if (!vp || !nfsrv_atroot(vp, &fid)) 1731 fid = nap->na_fileid; 1732 if ((u_int64_t)fid != thyp) 1733 *retcmpp = NFSERR_NOTSAME; 1734 } 1735 } 1736 } else if (nap != NULL) { 1737 if (*tl++) 1738 printf("NFSv4 mounted on fileid > 32bits\n"); 1739 nap->na_mntonfileno = thyp; 1740 } 1741 attrsum += NFSX_HYPER; 1742 break; 1743 case NFSATTRBIT_SUPPATTREXCLCREAT: 1744 retnotsup = 0; 1745 error = nfsrv_getattrbits(nd, &retattrbits, 1746 &cnt, &retnotsup); 1747 if (error) 1748 goto nfsmout; 1749 if (compare && !(*retcmpp)) { 1750 NFSSETSUPP_ATTRBIT(&checkattrbits); 1751 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits); 1752 NFSCLRBIT_ATTRBIT(&checkattrbits, 1753 NFSATTRBIT_TIMEACCESSSET); 1754 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 1755 || retnotsup) 1756 *retcmpp = NFSERR_NOTSAME; 1757 } 1758 attrsum += cnt; 1759 break; 1760 default: 1761 printf("EEK! nfsv4_loadattr unknown attr=%d\n", 1762 bitpos); 1763 if (compare && !(*retcmpp)) 1764 *retcmpp = NFSERR_ATTRNOTSUPP; 1765 /* 1766 * and get out of the loop, since we can't parse 1767 * the unknown attrbute data. 1768 */ 1769 bitpos = NFSATTRBIT_MAX; 1770 break; 1771 }; 1772 } 1773 1774 /* 1775 * some clients pad the attrlist, so we need to skip over the 1776 * padding. 1777 */ 1778 if (attrsum > attrsize) { 1779 error = NFSERR_BADXDR; 1780 } else { 1781 attrsize = NFSM_RNDUP(attrsize); 1782 if (attrsum < attrsize) 1783 error = nfsm_advance(nd, attrsize - attrsum, -1); 1784 } 1785nfsmout: 1786 NFSEXITCODE2(error, nd); 1787 return (error); 1788} 1789 1790/* 1791 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a 1792 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock. 1793 * The first argument is a pointer to an nfsv4lock structure. 1794 * The second argument is 1 iff a blocking lock is wanted. 1795 * If this argument is 0, the call waits until no thread either wants nor 1796 * holds an exclusive lock. 1797 * It returns 1 if the lock was acquired, 0 otherwise. 1798 * If several processes call this function concurrently wanting the exclusive 1799 * lock, one will get the lock and the rest will return without getting the 1800 * lock. (If the caller must have the lock, it simply calls this function in a 1801 * loop until the function returns 1 to indicate the lock was acquired.) 1802 * Any usecnt must be decremented by calling nfsv4_relref() before 1803 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could 1804 * be called in a loop. 1805 * The isleptp argument is set to indicate if the call slept, iff not NULL 1806 * and the mp argument indicates to check for a forced dismount, iff not 1807 * NULL. 1808 */ 1809APPLESTATIC int 1810nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp, 1811 void *mutex, struct mount *mp) 1812{ 1813 1814 if (isleptp) 1815 *isleptp = 0; 1816 /* 1817 * If a lock is wanted, loop around until the lock is acquired by 1818 * someone and then released. If I want the lock, try to acquire it. 1819 * For a lock to be issued, no lock must be in force and the usecnt 1820 * must be zero. 1821 */ 1822 if (iwantlock) { 1823 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1824 lp->nfslock_usecnt == 0) { 1825 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1826 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1827 return (1); 1828 } 1829 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED; 1830 } 1831 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) { 1832 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1833 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1834 return (0); 1835 } 1836 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1837 if (isleptp) 1838 *isleptp = 1; 1839 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1840 PZERO - 1, "nfsv4lck", NULL); 1841 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1842 lp->nfslock_usecnt == 0) { 1843 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1844 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1845 return (1); 1846 } 1847 } 1848 return (0); 1849} 1850 1851/* 1852 * Release the lock acquired by nfsv4_lock(). 1853 * The second argument is set to 1 to indicate the nfslock_usecnt should be 1854 * incremented, as well. 1855 */ 1856APPLESTATIC void 1857nfsv4_unlock(struct nfsv4lock *lp, int incref) 1858{ 1859 1860 lp->nfslock_lock &= ~NFSV4LOCK_LOCK; 1861 if (incref) 1862 lp->nfslock_usecnt++; 1863 nfsv4_wanted(lp); 1864} 1865 1866/* 1867 * Release a reference cnt. 1868 */ 1869APPLESTATIC void 1870nfsv4_relref(struct nfsv4lock *lp) 1871{ 1872 1873 if (lp->nfslock_usecnt <= 0) 1874 panic("nfsv4root ref cnt"); 1875 lp->nfslock_usecnt--; 1876 if (lp->nfslock_usecnt == 0) 1877 nfsv4_wanted(lp); 1878} 1879 1880/* 1881 * Get a reference cnt. 1882 * This function will wait for any exclusive lock to be released, but will 1883 * not wait for threads that want the exclusive lock. If priority needs 1884 * to be given to threads that need the exclusive lock, a call to nfsv4_lock() 1885 * with the 2nd argument == 0 should be done before calling nfsv4_getref(). 1886 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and 1887 * return without getting a refcnt for that case. 1888 */ 1889APPLESTATIC void 1890nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex, 1891 struct mount *mp) 1892{ 1893 1894 if (isleptp) 1895 *isleptp = 0; 1896 1897 /* 1898 * Wait for a lock held. 1899 */ 1900 while (lp->nfslock_lock & NFSV4LOCK_LOCK) { 1901 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1902 return; 1903 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1904 if (isleptp) 1905 *isleptp = 1; 1906 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1907 PZERO - 1, "nfsv4gr", NULL); 1908 } 1909 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1910 return; 1911 1912 lp->nfslock_usecnt++; 1913} 1914 1915/* 1916 * Get a reference as above, but return failure instead of sleeping if 1917 * an exclusive lock is held. 1918 */ 1919APPLESTATIC int 1920nfsv4_getref_nonblock(struct nfsv4lock *lp) 1921{ 1922 1923 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0) 1924 return (0); 1925 1926 lp->nfslock_usecnt++; 1927 return (1); 1928} 1929 1930/* 1931 * Test for a lock. Return 1 if locked, 0 otherwise. 1932 */ 1933APPLESTATIC int 1934nfsv4_testlock(struct nfsv4lock *lp) 1935{ 1936 1937 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 && 1938 lp->nfslock_usecnt == 0) 1939 return (0); 1940 return (1); 1941} 1942 1943/* 1944 * Wake up anyone sleeping, waiting for this lock. 1945 */ 1946static void 1947nfsv4_wanted(struct nfsv4lock *lp) 1948{ 1949 1950 if (lp->nfslock_lock & NFSV4LOCK_WANTED) { 1951 lp->nfslock_lock &= ~NFSV4LOCK_WANTED; 1952 wakeup((caddr_t)&lp->nfslock_lock); 1953 } 1954} 1955 1956/* 1957 * Copy a string from an mbuf list into a character array. 1958 * Return EBADRPC if there is an mbuf error, 1959 * 0 otherwise. 1960 */ 1961APPLESTATIC int 1962nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) 1963{ 1964 char *cp; 1965 int xfer, len; 1966 mbuf_t mp; 1967 int rem, error = 0; 1968 1969 mp = nd->nd_md; 1970 cp = nd->nd_dpos; 1971 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp; 1972 rem = NFSM_RNDUP(siz) - siz; 1973 while (siz > 0) { 1974 if (len > siz) 1975 xfer = siz; 1976 else 1977 xfer = len; 1978 NFSBCOPY(cp, str, xfer); 1979 str += xfer; 1980 siz -= xfer; 1981 if (siz > 0) { 1982 mp = mbuf_next(mp); 1983 if (mp == NULL) { 1984 error = EBADRPC; 1985 goto out; 1986 } 1987 cp = NFSMTOD(mp, caddr_t); 1988 len = mbuf_len(mp); 1989 } else { 1990 cp += xfer; 1991 len -= xfer; 1992 } 1993 } 1994 *str = '\0'; 1995 nd->nd_dpos = cp; 1996 nd->nd_md = mp; 1997 if (rem > 0) { 1998 if (len < rem) 1999 error = nfsm_advance(nd, rem, len); 2000 else 2001 nd->nd_dpos += rem; 2002 } 2003 2004out: 2005 NFSEXITCODE2(error, nd); 2006 return (error); 2007} 2008 2009/* 2010 * Fill in the attributes as marked by the bitmap (V4). 2011 */ 2012APPLESTATIC int 2013nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, 2014 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror, 2015 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram, 2016 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno) 2017{ 2018 int bitpos, retnum = 0; 2019 u_int32_t *tl; 2020 int siz, prefixnum, error; 2021 u_char *cp, namestr[NFSV4_SMALLSTR]; 2022 nfsattrbit_t attrbits, retbits; 2023 nfsattrbit_t *retbitp = &retbits; 2024 u_int32_t freenum, *retnump; 2025 u_int64_t uquad; 2026 struct statfs fs; 2027 struct nfsfsinfo fsinf; 2028 struct timespec temptime; 2029 NFSACL_T *aclp, *naclp = NULL; 2030#ifdef QUOTA 2031 struct dqblk dqb; 2032 uid_t savuid; 2033#endif 2034 2035 /* 2036 * First, set the bits that can be filled and get fsinfo. 2037 */ 2038 NFSSET_ATTRBIT(retbitp, attrbitp); 2039 /* 2040 * If both p and cred are NULL, it is a client side setattr call. 2041 * If both p and cred are not NULL, it is a server side reply call. 2042 * If p is not NULL and cred is NULL, it is a client side callback 2043 * reply call. 2044 */ 2045 if (p == NULL && cred == NULL) { 2046 NFSCLRNOTSETABLE_ATTRBIT(retbitp); 2047 aclp = saclp; 2048 } else { 2049 NFSCLRNOTFILLABLE_ATTRBIT(retbitp); 2050 naclp = acl_alloc(M_WAITOK); 2051 aclp = naclp; 2052 } 2053 nfsvno_getfs(&fsinf, isdgram); 2054#ifndef APPLE 2055 /* 2056 * Get the VFS_STATFS(), since some attributes need them. 2057 */ 2058 if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 2059 error = VFS_STATFS(mp, &fs); 2060 if (error != 0) { 2061 if (reterr) { 2062 nd->nd_repstat = NFSERR_ACCES; 2063 return (0); 2064 } 2065 NFSCLRSTATFS_ATTRBIT(retbitp); 2066 } 2067 } 2068#endif 2069 2070 /* 2071 * And the NFSv4 ACL... 2072 */ 2073 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 2074 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2075 supports_nfsv4acls == 0))) { 2076 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 2077 } 2078 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 2079 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2080 supports_nfsv4acls == 0)) { 2081 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2082 } else if (naclp != NULL) { 2083 if (NFSVOPLOCK(vp, LK_SHARED) == 0) { 2084 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); 2085 if (error == 0) 2086 error = VOP_GETACL(vp, ACL_TYPE_NFS4, 2087 naclp, cred, p); 2088 NFSVOPUNLOCK(vp, 0); 2089 } else 2090 error = NFSERR_PERM; 2091 if (error != 0) { 2092 if (reterr) { 2093 nd->nd_repstat = NFSERR_ACCES; 2094 return (0); 2095 } 2096 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2097 } 2098 } 2099 } 2100 /* 2101 * Put out the attribute bitmap for the ones being filled in 2102 * and get the field for the number of attributes returned. 2103 */ 2104 prefixnum = nfsrv_putattrbit(nd, retbitp); 2105 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 2106 prefixnum += NFSX_UNSIGNED; 2107 2108 /* 2109 * Now, loop around filling in the attributes for each bit set. 2110 */ 2111 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 2112 if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 2113 switch (bitpos) { 2114 case NFSATTRBIT_SUPPORTEDATTRS: 2115 NFSSETSUPP_ATTRBIT(&attrbits); 2116 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 2117 && supports_nfsv4acls == 0)) { 2118 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 2119 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 2120 } 2121 retnum += nfsrv_putattrbit(nd, &attrbits); 2122 break; 2123 case NFSATTRBIT_TYPE: 2124 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2125 *tl = vtonfsv34_type(vap->va_type); 2126 retnum += NFSX_UNSIGNED; 2127 break; 2128 case NFSATTRBIT_FHEXPIRETYPE: 2129 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2130 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2131 retnum += NFSX_UNSIGNED; 2132 break; 2133 case NFSATTRBIT_CHANGE: 2134 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2135 txdr_hyper(vap->va_filerev, tl); 2136 retnum += NFSX_HYPER; 2137 break; 2138 case NFSATTRBIT_SIZE: 2139 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2140 txdr_hyper(vap->va_size, tl); 2141 retnum += NFSX_HYPER; 2142 break; 2143 case NFSATTRBIT_LINKSUPPORT: 2144 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2145 if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2146 *tl = newnfs_true; 2147 else 2148 *tl = newnfs_false; 2149 retnum += NFSX_UNSIGNED; 2150 break; 2151 case NFSATTRBIT_SYMLINKSUPPORT: 2152 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2153 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2154 *tl = newnfs_true; 2155 else 2156 *tl = newnfs_false; 2157 retnum += NFSX_UNSIGNED; 2158 break; 2159 case NFSATTRBIT_NAMEDATTR: 2160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2161 *tl = newnfs_false; 2162 retnum += NFSX_UNSIGNED; 2163 break; 2164 case NFSATTRBIT_FSID: 2165 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2166 *tl++ = 0; 2167 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]); 2168 *tl++ = 0; 2169 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]); 2170 retnum += NFSX_V4FSID; 2171 break; 2172 case NFSATTRBIT_UNIQUEHANDLES: 2173 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2174 *tl = newnfs_true; 2175 retnum += NFSX_UNSIGNED; 2176 break; 2177 case NFSATTRBIT_LEASETIME: 2178 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2179 *tl = txdr_unsigned(nfsrv_lease); 2180 retnum += NFSX_UNSIGNED; 2181 break; 2182 case NFSATTRBIT_RDATTRERROR: 2183 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2184 *tl = txdr_unsigned(rderror); 2185 retnum += NFSX_UNSIGNED; 2186 break; 2187 /* 2188 * Recommended Attributes. (Only the supported ones.) 2189 */ 2190 case NFSATTRBIT_ACL: 2191 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2192 break; 2193 case NFSATTRBIT_ACLSUPPORT: 2194 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2195 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2196 retnum += NFSX_UNSIGNED; 2197 break; 2198 case NFSATTRBIT_CANSETTIME: 2199 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2200 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2201 *tl = newnfs_true; 2202 else 2203 *tl = newnfs_false; 2204 retnum += NFSX_UNSIGNED; 2205 break; 2206 case NFSATTRBIT_CASEINSENSITIVE: 2207 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2208 *tl = newnfs_false; 2209 retnum += NFSX_UNSIGNED; 2210 break; 2211 case NFSATTRBIT_CASEPRESERVING: 2212 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2213 *tl = newnfs_true; 2214 retnum += NFSX_UNSIGNED; 2215 break; 2216 case NFSATTRBIT_CHOWNRESTRICTED: 2217 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2218 *tl = newnfs_true; 2219 retnum += NFSX_UNSIGNED; 2220 break; 2221 case NFSATTRBIT_FILEHANDLE: 2222 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2223 break; 2224 case NFSATTRBIT_FILEID: 2225 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2226 *tl++ = 0; 2227 *tl = txdr_unsigned(vap->va_fileid); 2228 retnum += NFSX_HYPER; 2229 break; 2230 case NFSATTRBIT_FILESAVAIL: 2231 /* 2232 * Check quota and use min(quota, f_ffree). 2233 */ 2234 freenum = fs.f_ffree; 2235#ifdef QUOTA 2236 /* 2237 * ufs_quotactl() insists that the uid argument 2238 * equal p_ruid for non-root quota access, so 2239 * we'll just make sure that's the case. 2240 */ 2241 savuid = p->p_cred->p_ruid; 2242 p->p_cred->p_ruid = cred->cr_uid; 2243 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2244 cred->cr_uid, (caddr_t)&dqb)) 2245 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2246 freenum); 2247 p->p_cred->p_ruid = savuid; 2248#endif /* QUOTA */ 2249 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2250 *tl++ = 0; 2251 *tl = txdr_unsigned(freenum); 2252 retnum += NFSX_HYPER; 2253 break; 2254 case NFSATTRBIT_FILESFREE: 2255 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2256 *tl++ = 0; 2257 *tl = txdr_unsigned(fs.f_ffree); 2258 retnum += NFSX_HYPER; 2259 break; 2260 case NFSATTRBIT_FILESTOTAL: 2261 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2262 *tl++ = 0; 2263 *tl = txdr_unsigned(fs.f_files); 2264 retnum += NFSX_HYPER; 2265 break; 2266 case NFSATTRBIT_FSLOCATIONS: 2267 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2268 *tl++ = 0; 2269 *tl = 0; 2270 retnum += 2 * NFSX_UNSIGNED; 2271 break; 2272 case NFSATTRBIT_HOMOGENEOUS: 2273 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2274 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2275 *tl = newnfs_true; 2276 else 2277 *tl = newnfs_false; 2278 retnum += NFSX_UNSIGNED; 2279 break; 2280 case NFSATTRBIT_MAXFILESIZE: 2281 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2282 uquad = NFSRV_MAXFILESIZE; 2283 txdr_hyper(uquad, tl); 2284 retnum += NFSX_HYPER; 2285 break; 2286 case NFSATTRBIT_MAXLINK: 2287 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2288 *tl = txdr_unsigned(LINK_MAX); 2289 retnum += NFSX_UNSIGNED; 2290 break; 2291 case NFSATTRBIT_MAXNAME: 2292 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2293 *tl = txdr_unsigned(NFS_MAXNAMLEN); 2294 retnum += NFSX_UNSIGNED; 2295 break; 2296 case NFSATTRBIT_MAXREAD: 2297 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2298 *tl++ = 0; 2299 *tl = txdr_unsigned(fsinf.fs_rtmax); 2300 retnum += NFSX_HYPER; 2301 break; 2302 case NFSATTRBIT_MAXWRITE: 2303 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2304 *tl++ = 0; 2305 *tl = txdr_unsigned(fsinf.fs_wtmax); 2306 retnum += NFSX_HYPER; 2307 break; 2308 case NFSATTRBIT_MODE: 2309 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2310 *tl = vtonfsv34_mode(vap->va_mode); 2311 retnum += NFSX_UNSIGNED; 2312 break; 2313 case NFSATTRBIT_NOTRUNC: 2314 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2315 *tl = newnfs_true; 2316 retnum += NFSX_UNSIGNED; 2317 break; 2318 case NFSATTRBIT_NUMLINKS: 2319 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2320 *tl = txdr_unsigned(vap->va_nlink); 2321 retnum += NFSX_UNSIGNED; 2322 break; 2323 case NFSATTRBIT_OWNER: 2324 cp = namestr; 2325 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); 2326 retnum += nfsm_strtom(nd, cp, siz); 2327 if (cp != namestr) 2328 free(cp, M_NFSSTRING); 2329 break; 2330 case NFSATTRBIT_OWNERGROUP: 2331 cp = namestr; 2332 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); 2333 retnum += nfsm_strtom(nd, cp, siz); 2334 if (cp != namestr) 2335 free(cp, M_NFSSTRING); 2336 break; 2337 case NFSATTRBIT_QUOTAHARD: 2338 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2339 freenum = fs.f_bfree; 2340 else 2341 freenum = fs.f_bavail; 2342#ifdef QUOTA 2343 /* 2344 * ufs_quotactl() insists that the uid argument 2345 * equal p_ruid for non-root quota access, so 2346 * we'll just make sure that's the case. 2347 */ 2348 savuid = p->p_cred->p_ruid; 2349 p->p_cred->p_ruid = cred->cr_uid; 2350 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2351 cred->cr_uid, (caddr_t)&dqb)) 2352 freenum = min(dqb.dqb_bhardlimit, freenum); 2353 p->p_cred->p_ruid = savuid; 2354#endif /* QUOTA */ 2355 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2356 uquad = (u_int64_t)freenum; 2357 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2358 txdr_hyper(uquad, tl); 2359 retnum += NFSX_HYPER; 2360 break; 2361 case NFSATTRBIT_QUOTASOFT: 2362 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2363 freenum = fs.f_bfree; 2364 else 2365 freenum = fs.f_bavail; 2366#ifdef QUOTA 2367 /* 2368 * ufs_quotactl() insists that the uid argument 2369 * equal p_ruid for non-root quota access, so 2370 * we'll just make sure that's the case. 2371 */ 2372 savuid = p->p_cred->p_ruid; 2373 p->p_cred->p_ruid = cred->cr_uid; 2374 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2375 cred->cr_uid, (caddr_t)&dqb)) 2376 freenum = min(dqb.dqb_bsoftlimit, freenum); 2377 p->p_cred->p_ruid = savuid; 2378#endif /* QUOTA */ 2379 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2380 uquad = (u_int64_t)freenum; 2381 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2382 txdr_hyper(uquad, tl); 2383 retnum += NFSX_HYPER; 2384 break; 2385 case NFSATTRBIT_QUOTAUSED: 2386 freenum = 0; 2387#ifdef QUOTA 2388 /* 2389 * ufs_quotactl() insists that the uid argument 2390 * equal p_ruid for non-root quota access, so 2391 * we'll just make sure that's the case. 2392 */ 2393 savuid = p->p_cred->p_ruid; 2394 p->p_cred->p_ruid = cred->cr_uid; 2395 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2396 cred->cr_uid, (caddr_t)&dqb)) 2397 freenum = dqb.dqb_curblocks; 2398 p->p_cred->p_ruid = savuid; 2399#endif /* QUOTA */ 2400 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2401 uquad = (u_int64_t)freenum; 2402 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2403 txdr_hyper(uquad, tl); 2404 retnum += NFSX_HYPER; 2405 break; 2406 case NFSATTRBIT_RAWDEV: 2407 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2408 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2409 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2410 retnum += NFSX_V4SPECDATA; 2411 break; 2412 case NFSATTRBIT_SPACEAVAIL: 2413 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2414 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) 2415 uquad = (u_int64_t)fs.f_bfree; 2416 else 2417 uquad = (u_int64_t)fs.f_bavail; 2418 uquad *= fs.f_bsize; 2419 txdr_hyper(uquad, tl); 2420 retnum += NFSX_HYPER; 2421 break; 2422 case NFSATTRBIT_SPACEFREE: 2423 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2424 uquad = (u_int64_t)fs.f_bfree; 2425 uquad *= fs.f_bsize; 2426 txdr_hyper(uquad, tl); 2427 retnum += NFSX_HYPER; 2428 break; 2429 case NFSATTRBIT_SPACETOTAL: 2430 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2431 uquad = (u_int64_t)fs.f_blocks; 2432 uquad *= fs.f_bsize; 2433 txdr_hyper(uquad, tl); 2434 retnum += NFSX_HYPER; 2435 break; 2436 case NFSATTRBIT_SPACEUSED: 2437 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2438 txdr_hyper(vap->va_bytes, tl); 2439 retnum += NFSX_HYPER; 2440 break; 2441 case NFSATTRBIT_TIMEACCESS: 2442 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2443 txdr_nfsv4time(&vap->va_atime, tl); 2444 retnum += NFSX_V4TIME; 2445 break; 2446 case NFSATTRBIT_TIMEACCESSSET: 2447 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2448 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2449 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2450 txdr_nfsv4time(&vap->va_atime, tl); 2451 retnum += NFSX_V4SETTIME; 2452 } else { 2453 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2454 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2455 retnum += NFSX_UNSIGNED; 2456 } 2457 break; 2458 case NFSATTRBIT_TIMEDELTA: 2459 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2460 temptime.tv_sec = 0; 2461 temptime.tv_nsec = 1000000000 / hz; 2462 txdr_nfsv4time(&temptime, tl); 2463 retnum += NFSX_V4TIME; 2464 break; 2465 case NFSATTRBIT_TIMEMETADATA: 2466 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2467 txdr_nfsv4time(&vap->va_ctime, tl); 2468 retnum += NFSX_V4TIME; 2469 break; 2470 case NFSATTRBIT_TIMEMODIFY: 2471 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2472 txdr_nfsv4time(&vap->va_mtime, tl); 2473 retnum += NFSX_V4TIME; 2474 break; 2475 case NFSATTRBIT_TIMEMODIFYSET: 2476 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2477 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2478 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2479 txdr_nfsv4time(&vap->va_mtime, tl); 2480 retnum += NFSX_V4SETTIME; 2481 } else { 2482 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2483 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2484 retnum += NFSX_UNSIGNED; 2485 } 2486 break; 2487 case NFSATTRBIT_MOUNTEDONFILEID: 2488 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2489 if (at_root != 0) 2490 uquad = mounted_on_fileno; 2491 else 2492 uquad = (u_int64_t)vap->va_fileid; 2493 txdr_hyper(uquad, tl); 2494 retnum += NFSX_HYPER; 2495 break; 2496 case NFSATTRBIT_SUPPATTREXCLCREAT: 2497 NFSSETSUPP_ATTRBIT(&attrbits); 2498 NFSCLRNOTSETABLE_ATTRBIT(&attrbits); 2499 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); 2500 retnum += nfsrv_putattrbit(nd, &attrbits); 2501 break; 2502 default: 2503 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2504 }; 2505 } 2506 } 2507 if (naclp != NULL) 2508 acl_free(naclp); 2509 *retnump = txdr_unsigned(retnum); 2510 return (retnum + prefixnum); 2511} 2512 2513/* 2514 * Put the attribute bits onto an mbuf list. 2515 * Return the number of bytes of output generated. 2516 */ 2517APPLESTATIC int 2518nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 2519{ 2520 u_int32_t *tl; 2521 int cnt, i, bytesize; 2522 2523 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 2524 if (attrbitp->bits[cnt - 1]) 2525 break; 2526 bytesize = (cnt + 1) * NFSX_UNSIGNED; 2527 NFSM_BUILD(tl, u_int32_t *, bytesize); 2528 *tl++ = txdr_unsigned(cnt); 2529 for (i = 0; i < cnt; i++) 2530 *tl++ = txdr_unsigned(attrbitp->bits[i]); 2531 return (bytesize); 2532} 2533 2534/* 2535 * Convert a uid to a string. 2536 * If the lookup fails, just output the digits. 2537 * uid - the user id 2538 * cpp - points to a buffer of size NFSV4_SMALLSTR 2539 * (malloc a larger one, as required) 2540 * retlenp - pointer to length to be returned 2541 */ 2542APPLESTATIC void 2543nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2544{ 2545 int i; 2546 struct nfsusrgrp *usrp; 2547 u_char *cp = *cpp; 2548 uid_t tmp; 2549 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2550 struct nfsrv_lughash *hp; 2551 2552 cnt = 0; 2553tryagain: 2554 if (nfsrv_dnsnamelen > 0) { 2555 /* 2556 * Always map nfsrv_defaultuid to "nobody". 2557 */ 2558 if (uid == nfsrv_defaultuid) { 2559 i = nfsrv_dnsnamelen + 7; 2560 if (i > len) { 2561 if (len > NFSV4_SMALLSTR) 2562 free(cp, M_NFSSTRING); 2563 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2564 *cpp = cp; 2565 len = i; 2566 goto tryagain; 2567 } 2568 *retlenp = i; 2569 NFSBCOPY("nobody@", cp, 7); 2570 cp += 7; 2571 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2572 return; 2573 } 2574 hasampersand = 0; 2575 hp = NFSUSERHASH(uid); 2576 mtx_lock(&hp->mtx); 2577 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2578 if (usrp->lug_uid == uid) { 2579 if (usrp->lug_expiry < NFSD_MONOSEC) 2580 break; 2581 /* 2582 * If the name doesn't already have an '@' 2583 * in it, append @domainname to it. 2584 */ 2585 for (i = 0; i < usrp->lug_namelen; i++) { 2586 if (usrp->lug_name[i] == '@') { 2587 hasampersand = 1; 2588 break; 2589 } 2590 } 2591 if (hasampersand) 2592 i = usrp->lug_namelen; 2593 else 2594 i = usrp->lug_namelen + 2595 nfsrv_dnsnamelen + 1; 2596 if (i > len) { 2597 mtx_unlock(&hp->mtx); 2598 if (len > NFSV4_SMALLSTR) 2599 free(cp, M_NFSSTRING); 2600 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2601 *cpp = cp; 2602 len = i; 2603 goto tryagain; 2604 } 2605 *retlenp = i; 2606 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2607 if (!hasampersand) { 2608 cp += usrp->lug_namelen; 2609 *cp++ = '@'; 2610 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2611 } 2612 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2613 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2614 lug_numhash); 2615 mtx_unlock(&hp->mtx); 2616 return; 2617 } 2618 } 2619 mtx_unlock(&hp->mtx); 2620 cnt++; 2621 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2622 NULL, p); 2623 if (ret == 0 && cnt < 2) 2624 goto tryagain; 2625 } 2626 2627 /* 2628 * No match, just return a string of digits. 2629 */ 2630 tmp = uid; 2631 i = 0; 2632 while (tmp || i == 0) { 2633 tmp /= 10; 2634 i++; 2635 } 2636 len = (i > len) ? len : i; 2637 *retlenp = len; 2638 cp += (len - 1); 2639 tmp = uid; 2640 for (i = 0; i < len; i++) { 2641 *cp-- = '0' + (tmp % 10); 2642 tmp /= 10; 2643 } 2644 return; 2645} 2646 2647/* 2648 * Get a credential for the uid with the server's group list. 2649 * If none is found, just return the credential passed in after 2650 * logging a warning message. 2651 */ 2652struct ucred * 2653nfsrv_getgrpscred(struct ucred *oldcred) 2654{ 2655 struct nfsusrgrp *usrp; 2656 struct ucred *newcred; 2657 int cnt, ret; 2658 uid_t uid; 2659 struct nfsrv_lughash *hp; 2660 2661 cnt = 0; 2662 uid = oldcred->cr_uid; 2663tryagain: 2664 if (nfsrv_dnsnamelen > 0) { 2665 hp = NFSUSERHASH(uid); 2666 mtx_lock(&hp->mtx); 2667 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2668 if (usrp->lug_uid == uid) { 2669 if (usrp->lug_expiry < NFSD_MONOSEC) 2670 break; 2671 if (usrp->lug_cred != NULL) { 2672 newcred = crhold(usrp->lug_cred); 2673 crfree(oldcred); 2674 } else 2675 newcred = oldcred; 2676 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2677 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2678 lug_numhash); 2679 mtx_unlock(&hp->mtx); 2680 return (newcred); 2681 } 2682 } 2683 mtx_unlock(&hp->mtx); 2684 cnt++; 2685 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2686 NULL, curthread); 2687 if (ret == 0 && cnt < 2) 2688 goto tryagain; 2689 } 2690 return (oldcred); 2691} 2692 2693/* 2694 * Convert a string to a uid. 2695 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2696 * return 0. 2697 * If this is called from a client side mount using AUTH_SYS and the 2698 * string is made up entirely of digits, just convert the string to 2699 * a number. 2700 */ 2701APPLESTATIC int 2702nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp, 2703 NFSPROC_T *p) 2704{ 2705 int i; 2706 char *cp, *endstr, *str0; 2707 struct nfsusrgrp *usrp; 2708 int cnt, ret; 2709 int error = 0; 2710 uid_t tuid; 2711 struct nfsrv_lughash *hp, *hp2; 2712 2713 if (len == 0) { 2714 error = NFSERR_BADOWNER; 2715 goto out; 2716 } 2717 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2718 str0 = str; 2719 tuid = (uid_t)strtoul(str0, &endstr, 10); 2720 if ((endstr - str0) == len) { 2721 /* A numeric string. */ 2722 if ((nd->nd_flag & ND_KERBV) == 0 && 2723 ((nd->nd_flag & ND_NFSCL) != 0 || 2724 nfsd_enable_stringtouid != 0)) 2725 *uidp = tuid; 2726 else 2727 error = NFSERR_BADOWNER; 2728 goto out; 2729 } 2730 /* 2731 * Look for an '@'. 2732 */ 2733 cp = strchr(str0, '@'); 2734 if (cp != NULL) 2735 i = (int)(cp++ - str0); 2736 else 2737 i = len; 2738 2739 cnt = 0; 2740tryagain: 2741 if (nfsrv_dnsnamelen > 0) { 2742 /* 2743 * If an '@' is found and the domain name matches, search for 2744 * the name with dns stripped off. 2745 * Mixed case alpahbetics will match for the domain name, but 2746 * all upper case will not. 2747 */ 2748 if (cnt == 0 && i < len && i > 0 && 2749 (len - 1 - i) == nfsrv_dnsnamelen && 2750 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2751 len -= (nfsrv_dnsnamelen + 1); 2752 *(cp - 1) = '\0'; 2753 } 2754 2755 /* 2756 * Check for the special case of "nobody". 2757 */ 2758 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 2759 *uidp = nfsrv_defaultuid; 2760 error = 0; 2761 goto out; 2762 } 2763 2764 hp = NFSUSERNAMEHASH(str, len); 2765 mtx_lock(&hp->mtx); 2766 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 2767 if (usrp->lug_namelen == len && 2768 !NFSBCMP(usrp->lug_name, str, len)) { 2769 if (usrp->lug_expiry < NFSD_MONOSEC) 2770 break; 2771 hp2 = NFSUSERHASH(usrp->lug_uid); 2772 mtx_lock(&hp2->mtx); 2773 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 2774 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 2775 lug_numhash); 2776 *uidp = usrp->lug_uid; 2777 mtx_unlock(&hp2->mtx); 2778 mtx_unlock(&hp->mtx); 2779 error = 0; 2780 goto out; 2781 } 2782 } 2783 mtx_unlock(&hp->mtx); 2784 cnt++; 2785 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 2786 str, p); 2787 if (ret == 0 && cnt < 2) 2788 goto tryagain; 2789 } 2790 error = NFSERR_BADOWNER; 2791 2792out: 2793 NFSEXITCODE(error); 2794 return (error); 2795} 2796 2797/* 2798 * Convert a gid to a string. 2799 * gid - the group id 2800 * cpp - points to a buffer of size NFSV4_SMALLSTR 2801 * (malloc a larger one, as required) 2802 * retlenp - pointer to length to be returned 2803 */ 2804APPLESTATIC void 2805nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2806{ 2807 int i; 2808 struct nfsusrgrp *usrp; 2809 u_char *cp = *cpp; 2810 gid_t tmp; 2811 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2812 struct nfsrv_lughash *hp; 2813 2814 cnt = 0; 2815tryagain: 2816 if (nfsrv_dnsnamelen > 0) { 2817 /* 2818 * Always map nfsrv_defaultgid to "nogroup". 2819 */ 2820 if (gid == nfsrv_defaultgid) { 2821 i = nfsrv_dnsnamelen + 8; 2822 if (i > len) { 2823 if (len > NFSV4_SMALLSTR) 2824 free(cp, M_NFSSTRING); 2825 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2826 *cpp = cp; 2827 len = i; 2828 goto tryagain; 2829 } 2830 *retlenp = i; 2831 NFSBCOPY("nogroup@", cp, 8); 2832 cp += 8; 2833 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2834 return; 2835 } 2836 hasampersand = 0; 2837 hp = NFSGROUPHASH(gid); 2838 mtx_lock(&hp->mtx); 2839 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2840 if (usrp->lug_gid == gid) { 2841 if (usrp->lug_expiry < NFSD_MONOSEC) 2842 break; 2843 /* 2844 * If the name doesn't already have an '@' 2845 * in it, append @domainname to it. 2846 */ 2847 for (i = 0; i < usrp->lug_namelen; i++) { 2848 if (usrp->lug_name[i] == '@') { 2849 hasampersand = 1; 2850 break; 2851 } 2852 } 2853 if (hasampersand) 2854 i = usrp->lug_namelen; 2855 else 2856 i = usrp->lug_namelen + 2857 nfsrv_dnsnamelen + 1; 2858 if (i > len) { 2859 mtx_unlock(&hp->mtx); 2860 if (len > NFSV4_SMALLSTR) 2861 free(cp, M_NFSSTRING); 2862 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2863 *cpp = cp; 2864 len = i; 2865 goto tryagain; 2866 } 2867 *retlenp = i; 2868 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2869 if (!hasampersand) { 2870 cp += usrp->lug_namelen; 2871 *cp++ = '@'; 2872 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2873 } 2874 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2875 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2876 lug_numhash); 2877 mtx_unlock(&hp->mtx); 2878 return; 2879 } 2880 } 2881 mtx_unlock(&hp->mtx); 2882 cnt++; 2883 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, 2884 NULL, p); 2885 if (ret == 0 && cnt < 2) 2886 goto tryagain; 2887 } 2888 2889 /* 2890 * No match, just return a string of digits. 2891 */ 2892 tmp = gid; 2893 i = 0; 2894 while (tmp || i == 0) { 2895 tmp /= 10; 2896 i++; 2897 } 2898 len = (i > len) ? len : i; 2899 *retlenp = len; 2900 cp += (len - 1); 2901 tmp = gid; 2902 for (i = 0; i < len; i++) { 2903 *cp-- = '0' + (tmp % 10); 2904 tmp /= 10; 2905 } 2906 return; 2907} 2908 2909/* 2910 * Convert a string to a gid. 2911 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2912 * return 0. 2913 * If this is called from a client side mount using AUTH_SYS and the 2914 * string is made up entirely of digits, just convert the string to 2915 * a number. 2916 */ 2917APPLESTATIC int 2918nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp, 2919 NFSPROC_T *p) 2920{ 2921 int i; 2922 char *cp, *endstr, *str0; 2923 struct nfsusrgrp *usrp; 2924 int cnt, ret; 2925 int error = 0; 2926 gid_t tgid; 2927 struct nfsrv_lughash *hp, *hp2; 2928 2929 if (len == 0) { 2930 error = NFSERR_BADOWNER; 2931 goto out; 2932 } 2933 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2934 str0 = str; 2935 tgid = (gid_t)strtoul(str0, &endstr, 10); 2936 if ((endstr - str0) == len) { 2937 /* A numeric string. */ 2938 if ((nd->nd_flag & ND_KERBV) == 0 && 2939 ((nd->nd_flag & ND_NFSCL) != 0 || 2940 nfsd_enable_stringtouid != 0)) 2941 *gidp = tgid; 2942 else 2943 error = NFSERR_BADOWNER; 2944 goto out; 2945 } 2946 /* 2947 * Look for an '@'. 2948 */ 2949 cp = strchr(str0, '@'); 2950 if (cp != NULL) 2951 i = (int)(cp++ - str0); 2952 else 2953 i = len; 2954 2955 cnt = 0; 2956tryagain: 2957 if (nfsrv_dnsnamelen > 0) { 2958 /* 2959 * If an '@' is found and the dns name matches, search for the 2960 * name with the dns stripped off. 2961 */ 2962 if (cnt == 0 && i < len && i > 0 && 2963 (len - 1 - i) == nfsrv_dnsnamelen && 2964 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2965 len -= (nfsrv_dnsnamelen + 1); 2966 *(cp - 1) = '\0'; 2967 } 2968 2969 /* 2970 * Check for the special case of "nogroup". 2971 */ 2972 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 2973 *gidp = nfsrv_defaultgid; 2974 error = 0; 2975 goto out; 2976 } 2977 2978 hp = NFSGROUPNAMEHASH(str, len); 2979 mtx_lock(&hp->mtx); 2980 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 2981 if (usrp->lug_namelen == len && 2982 !NFSBCMP(usrp->lug_name, str, len)) { 2983 if (usrp->lug_expiry < NFSD_MONOSEC) 2984 break; 2985 hp2 = NFSGROUPHASH(usrp->lug_gid); 2986 mtx_lock(&hp2->mtx); 2987 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 2988 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 2989 lug_numhash); 2990 *gidp = usrp->lug_gid; 2991 mtx_unlock(&hp2->mtx); 2992 mtx_unlock(&hp->mtx); 2993 error = 0; 2994 goto out; 2995 } 2996 } 2997 mtx_unlock(&hp->mtx); 2998 cnt++; 2999 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 3000 str, p); 3001 if (ret == 0 && cnt < 2) 3002 goto tryagain; 3003 } 3004 error = NFSERR_BADOWNER; 3005 3006out: 3007 NFSEXITCODE(error); 3008 return (error); 3009} 3010 3011/* 3012 * Cmp len chars, allowing mixed case in the first argument to match lower 3013 * case in the second, but not if the first argument is all upper case. 3014 * Return 0 for a match, 1 otherwise. 3015 */ 3016static int 3017nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 3018{ 3019 int i; 3020 u_char tmp; 3021 int fndlower = 0; 3022 3023 for (i = 0; i < len; i++) { 3024 if (*cp >= 'A' && *cp <= 'Z') { 3025 tmp = *cp++ + ('a' - 'A'); 3026 } else { 3027 tmp = *cp++; 3028 if (tmp >= 'a' && tmp <= 'z') 3029 fndlower = 1; 3030 } 3031 if (tmp != *cp2++) 3032 return (1); 3033 } 3034 if (fndlower) 3035 return (0); 3036 else 3037 return (1); 3038} 3039 3040/* 3041 * Set the port for the nfsuserd. 3042 */ 3043APPLESTATIC int 3044nfsrv_nfsuserdport(u_short port, NFSPROC_T *p) 3045{ 3046 struct nfssockreq *rp; 3047 struct sockaddr_in *ad; 3048 int error; 3049 3050 NFSLOCKNAMEID(); 3051 if (nfsrv_nfsuserd) { 3052 NFSUNLOCKNAMEID(); 3053 error = EPERM; 3054 goto out; 3055 } 3056 nfsrv_nfsuserd = 1; 3057 NFSUNLOCKNAMEID(); 3058 /* 3059 * Set up the socket record and connect. 3060 */ 3061 rp = &nfsrv_nfsuserdsock; 3062 rp->nr_client = NULL; 3063 rp->nr_sotype = SOCK_DGRAM; 3064 rp->nr_soproto = IPPROTO_UDP; 3065 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 3066 rp->nr_cred = NULL; 3067 NFSSOCKADDRALLOC(rp->nr_nam); 3068 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in)); 3069 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *); 3070 ad->sin_family = AF_INET; 3071 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */ 3072 ad->sin_port = port; 3073 rp->nr_prog = RPCPROG_NFSUSERD; 3074 rp->nr_vers = RPCNFSUSERD_VERS; 3075 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 3076 if (error) { 3077 NFSSOCKADDRFREE(rp->nr_nam); 3078 nfsrv_nfsuserd = 0; 3079 } 3080out: 3081 NFSEXITCODE(error); 3082 return (error); 3083} 3084 3085/* 3086 * Delete the nfsuserd port. 3087 */ 3088APPLESTATIC void 3089nfsrv_nfsuserddelport(void) 3090{ 3091 3092 NFSLOCKNAMEID(); 3093 if (nfsrv_nfsuserd == 0) { 3094 NFSUNLOCKNAMEID(); 3095 return; 3096 } 3097 nfsrv_nfsuserd = 0; 3098 NFSUNLOCKNAMEID(); 3099 newnfs_disconnect(&nfsrv_nfsuserdsock); 3100 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); 3101} 3102 3103/* 3104 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 3105 * name<-->id cache. 3106 * Returns 0 upon success, non-zero otherwise. 3107 */ 3108static int 3109nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) 3110{ 3111 u_int32_t *tl; 3112 struct nfsrv_descript *nd; 3113 int len; 3114 struct nfsrv_descript nfsd; 3115 struct ucred *cred; 3116 int error; 3117 3118 NFSLOCKNAMEID(); 3119 if (nfsrv_nfsuserd == 0) { 3120 NFSUNLOCKNAMEID(); 3121 error = EPERM; 3122 goto out; 3123 } 3124 NFSUNLOCKNAMEID(); 3125 nd = &nfsd; 3126 cred = newnfs_getcred(); 3127 nd->nd_flag = ND_GSSINITREPLY; 3128 nfsrvd_rephead(nd); 3129 3130 nd->nd_procnum = procnum; 3131 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3132 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3133 if (procnum == RPCNFSUSERD_GETUID) 3134 *tl = txdr_unsigned(uid); 3135 else 3136 *tl = txdr_unsigned(gid); 3137 } else { 3138 len = strlen(name); 3139 (void) nfsm_strtom(nd, name, len); 3140 } 3141 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 3142 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL); 3143 NFSFREECRED(cred); 3144 if (!error) { 3145 mbuf_freem(nd->nd_mrep); 3146 error = nd->nd_repstat; 3147 } 3148out: 3149 NFSEXITCODE(error); 3150 return (error); 3151} 3152 3153/* 3154 * This function is called from the nfssvc(2) system call, to update the 3155 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3156 */ 3157APPLESTATIC int 3158nfssvc_idname(struct nfsd_idargs *nidp) 3159{ 3160 struct nfsusrgrp *nusrp, *usrp, *newusrp; 3161 struct nfsrv_lughash *hp_name, *hp_idnum, *thp; 3162 int i, group_locked, groupname_locked, user_locked, username_locked; 3163 int error = 0; 3164 u_char *cp; 3165 gid_t *grps; 3166 struct ucred *cr; 3167 static int onethread = 0; 3168 static time_t lasttime = 0; 3169 3170 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) { 3171 error = EINVAL; 3172 goto out; 3173 } 3174 if (nidp->nid_flag & NFSID_INITIALIZE) { 3175 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); 3176 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 3177 nidp->nid_namelen); 3178 if (error != 0) { 3179 free(cp, M_NFSSTRING); 3180 goto out; 3181 } 3182 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) { 3183 /* 3184 * Free up all the old stuff and reinitialize hash 3185 * lists. All mutexes for both lists must be locked, 3186 * with the user/group name ones before the uid/gid 3187 * ones, to avoid a LOR. 3188 */ 3189 for (i = 0; i < nfsrv_lughashsize; i++) 3190 mtx_lock(&nfsusernamehash[i].mtx); 3191 for (i = 0; i < nfsrv_lughashsize; i++) 3192 mtx_lock(&nfsuserhash[i].mtx); 3193 for (i = 0; i < nfsrv_lughashsize; i++) 3194 TAILQ_FOREACH_SAFE(usrp, 3195 &nfsuserhash[i].lughead, lug_numhash, nusrp) 3196 nfsrv_removeuser(usrp, 1); 3197 for (i = 0; i < nfsrv_lughashsize; i++) 3198 mtx_unlock(&nfsuserhash[i].mtx); 3199 for (i = 0; i < nfsrv_lughashsize; i++) 3200 mtx_unlock(&nfsusernamehash[i].mtx); 3201 for (i = 0; i < nfsrv_lughashsize; i++) 3202 mtx_lock(&nfsgroupnamehash[i].mtx); 3203 for (i = 0; i < nfsrv_lughashsize; i++) 3204 mtx_lock(&nfsgrouphash[i].mtx); 3205 for (i = 0; i < nfsrv_lughashsize; i++) 3206 TAILQ_FOREACH_SAFE(usrp, 3207 &nfsgrouphash[i].lughead, lug_numhash, 3208 nusrp) 3209 nfsrv_removeuser(usrp, 0); 3210 for (i = 0; i < nfsrv_lughashsize; i++) 3211 mtx_unlock(&nfsgrouphash[i].mtx); 3212 for (i = 0; i < nfsrv_lughashsize; i++) 3213 mtx_unlock(&nfsgroupnamehash[i].mtx); 3214 free(nfsrv_dnsname, M_NFSSTRING); 3215 nfsrv_dnsname = NULL; 3216 } 3217 if (nfsuserhash == NULL) { 3218 /* Allocate the hash tables. */ 3219 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) * 3220 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3221 M_ZERO); 3222 for (i = 0; i < nfsrv_lughashsize; i++) 3223 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash", 3224 NULL, MTX_DEF | MTX_DUPOK); 3225 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) * 3226 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3227 M_ZERO); 3228 for (i = 0; i < nfsrv_lughashsize; i++) 3229 mtx_init(&nfsusernamehash[i].mtx, 3230 "nfsusrhash", NULL, MTX_DEF | 3231 MTX_DUPOK); 3232 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) * 3233 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3234 M_ZERO); 3235 for (i = 0; i < nfsrv_lughashsize; i++) 3236 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash", 3237 NULL, MTX_DEF | MTX_DUPOK); 3238 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) * 3239 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3240 M_ZERO); 3241 for (i = 0; i < nfsrv_lughashsize; i++) 3242 mtx_init(&nfsgroupnamehash[i].mtx, 3243 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK); 3244 } 3245 /* (Re)initialize the list heads. */ 3246 for (i = 0; i < nfsrv_lughashsize; i++) 3247 TAILQ_INIT(&nfsuserhash[i].lughead); 3248 for (i = 0; i < nfsrv_lughashsize; i++) 3249 TAILQ_INIT(&nfsusernamehash[i].lughead); 3250 for (i = 0; i < nfsrv_lughashsize; i++) 3251 TAILQ_INIT(&nfsgrouphash[i].lughead); 3252 for (i = 0; i < nfsrv_lughashsize; i++) 3253 TAILQ_INIT(&nfsgroupnamehash[i].lughead); 3254 3255 /* 3256 * Put name in "DNS" string. 3257 */ 3258 nfsrv_dnsname = cp; 3259 nfsrv_defaultuid = nidp->nid_uid; 3260 nfsrv_defaultgid = nidp->nid_gid; 3261 nfsrv_usercnt = 0; 3262 nfsrv_usermax = nidp->nid_usermax; 3263 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen); 3264 goto out; 3265 } 3266 3267 /* 3268 * malloc the new one now, so any potential sleep occurs before 3269 * manipulation of the lists. 3270 */ 3271 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, 3272 M_NFSUSERGROUP, M_WAITOK | M_ZERO); 3273 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 3274 nidp->nid_namelen); 3275 if (error == 0 && nidp->nid_ngroup > 0 && 3276 (nidp->nid_flag & NFSID_ADDUID) != 0) { 3277 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP, 3278 M_WAITOK); 3279 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps, 3280 sizeof(gid_t) * nidp->nid_ngroup); 3281 if (error == 0) { 3282 /* 3283 * Create a credential just like svc_getcred(), 3284 * but using the group list provided. 3285 */ 3286 cr = crget(); 3287 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; 3288 crsetgroups(cr, nidp->nid_ngroup, grps); 3289 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; 3290 cr->cr_prison = &prison0; 3291 prison_hold(cr->cr_prison); 3292#ifdef MAC 3293 mac_cred_associate_nfsd(cr); 3294#endif 3295 newusrp->lug_cred = cr; 3296 } 3297 free(grps, M_TEMP); 3298 } 3299 if (error) { 3300 free(newusrp, M_NFSUSERGROUP); 3301 goto out; 3302 } 3303 newusrp->lug_namelen = nidp->nid_namelen; 3304 3305 /* 3306 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed 3307 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group. 3308 * The flags user_locked, username_locked, group_locked and 3309 * groupname_locked are set to indicate all of those hash lists are 3310 * locked. hp_name != NULL and hp_idnum != NULL indicates that 3311 * the respective one mutex is locked. 3312 */ 3313 user_locked = username_locked = group_locked = groupname_locked = 0; 3314 hp_name = hp_idnum = NULL; 3315 3316 /* 3317 * Delete old entries, as required. 3318 */ 3319 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3320 /* Must lock all username hash lists first, to avoid a LOR. */ 3321 for (i = 0; i < nfsrv_lughashsize; i++) 3322 mtx_lock(&nfsusernamehash[i].mtx); 3323 username_locked = 1; 3324 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3325 mtx_lock(&hp_idnum->mtx); 3326 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3327 nusrp) { 3328 if (usrp->lug_uid == nidp->nid_uid) 3329 nfsrv_removeuser(usrp, 1); 3330 } 3331 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3332 hp_name = NFSUSERNAMEHASH(newusrp->lug_name, 3333 newusrp->lug_namelen); 3334 mtx_lock(&hp_name->mtx); 3335 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3336 nusrp) { 3337 if (usrp->lug_namelen == newusrp->lug_namelen && 3338 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3339 usrp->lug_namelen)) { 3340 thp = NFSUSERHASH(usrp->lug_uid); 3341 mtx_lock(&thp->mtx); 3342 nfsrv_removeuser(usrp, 1); 3343 mtx_unlock(&thp->mtx); 3344 } 3345 } 3346 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3347 mtx_lock(&hp_idnum->mtx); 3348 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3349 /* Must lock all groupname hash lists first, to avoid a LOR. */ 3350 for (i = 0; i < nfsrv_lughashsize; i++) 3351 mtx_lock(&nfsgroupnamehash[i].mtx); 3352 groupname_locked = 1; 3353 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3354 mtx_lock(&hp_idnum->mtx); 3355 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3356 nusrp) { 3357 if (usrp->lug_gid == nidp->nid_gid) 3358 nfsrv_removeuser(usrp, 0); 3359 } 3360 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3361 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name, 3362 newusrp->lug_namelen); 3363 mtx_lock(&hp_name->mtx); 3364 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3365 nusrp) { 3366 if (usrp->lug_namelen == newusrp->lug_namelen && 3367 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3368 usrp->lug_namelen)) { 3369 thp = NFSGROUPHASH(usrp->lug_gid); 3370 mtx_lock(&thp->mtx); 3371 nfsrv_removeuser(usrp, 0); 3372 mtx_unlock(&thp->mtx); 3373 } 3374 } 3375 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3376 mtx_lock(&hp_idnum->mtx); 3377 } 3378 3379 /* 3380 * Now, we can add the new one. 3381 */ 3382 if (nidp->nid_usertimeout) 3383 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3384 else 3385 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3386 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3387 newusrp->lug_uid = nidp->nid_uid; 3388 thp = NFSUSERHASH(newusrp->lug_uid); 3389 mtx_assert(&thp->mtx, MA_OWNED); 3390 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3391 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3392 mtx_assert(&thp->mtx, MA_OWNED); 3393 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3394 atomic_add_int(&nfsrv_usercnt, 1); 3395 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3396 newusrp->lug_gid = nidp->nid_gid; 3397 thp = NFSGROUPHASH(newusrp->lug_gid); 3398 mtx_assert(&thp->mtx, MA_OWNED); 3399 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3400 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3401 mtx_assert(&thp->mtx, MA_OWNED); 3402 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3403 atomic_add_int(&nfsrv_usercnt, 1); 3404 } else { 3405 if (newusrp->lug_cred != NULL) 3406 crfree(newusrp->lug_cred); 3407 free(newusrp, M_NFSUSERGROUP); 3408 } 3409 3410 /* 3411 * Once per second, allow one thread to trim the cache. 3412 */ 3413 if (lasttime < NFSD_MONOSEC && 3414 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) { 3415 /* 3416 * First, unlock the single mutexes, so that all entries 3417 * can be locked and any LOR is avoided. 3418 */ 3419 if (hp_name != NULL) { 3420 mtx_unlock(&hp_name->mtx); 3421 hp_name = NULL; 3422 } 3423 if (hp_idnum != NULL) { 3424 mtx_unlock(&hp_idnum->mtx); 3425 hp_idnum = NULL; 3426 } 3427 3428 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID | 3429 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) { 3430 if (username_locked == 0) { 3431 for (i = 0; i < nfsrv_lughashsize; i++) 3432 mtx_lock(&nfsusernamehash[i].mtx); 3433 username_locked = 1; 3434 } 3435 KASSERT(user_locked == 0, 3436 ("nfssvc_idname: user_locked")); 3437 for (i = 0; i < nfsrv_lughashsize; i++) 3438 mtx_lock(&nfsuserhash[i].mtx); 3439 user_locked = 1; 3440 for (i = 0; i < nfsrv_lughashsize; i++) { 3441 TAILQ_FOREACH_SAFE(usrp, 3442 &nfsuserhash[i].lughead, lug_numhash, 3443 nusrp) 3444 if (usrp->lug_expiry < NFSD_MONOSEC) 3445 nfsrv_removeuser(usrp, 1); 3446 } 3447 for (i = 0; i < nfsrv_lughashsize; i++) { 3448 /* 3449 * Trim the cache using an approximate LRU 3450 * algorithm. This code deletes the least 3451 * recently used entry on each hash list. 3452 */ 3453 if (nfsrv_usercnt <= nfsrv_usermax) 3454 break; 3455 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead); 3456 if (usrp != NULL) 3457 nfsrv_removeuser(usrp, 1); 3458 } 3459 } else { 3460 if (groupname_locked == 0) { 3461 for (i = 0; i < nfsrv_lughashsize; i++) 3462 mtx_lock(&nfsgroupnamehash[i].mtx); 3463 groupname_locked = 1; 3464 } 3465 KASSERT(group_locked == 0, 3466 ("nfssvc_idname: group_locked")); 3467 for (i = 0; i < nfsrv_lughashsize; i++) 3468 mtx_lock(&nfsgrouphash[i].mtx); 3469 group_locked = 1; 3470 for (i = 0; i < nfsrv_lughashsize; i++) { 3471 TAILQ_FOREACH_SAFE(usrp, 3472 &nfsgrouphash[i].lughead, lug_numhash, 3473 nusrp) 3474 if (usrp->lug_expiry < NFSD_MONOSEC) 3475 nfsrv_removeuser(usrp, 0); 3476 } 3477 for (i = 0; i < nfsrv_lughashsize; i++) { 3478 /* 3479 * Trim the cache using an approximate LRU 3480 * algorithm. This code deletes the least 3481 * recently user entry on each hash list. 3482 */ 3483 if (nfsrv_usercnt <= nfsrv_usermax) 3484 break; 3485 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead); 3486 if (usrp != NULL) 3487 nfsrv_removeuser(usrp, 0); 3488 } 3489 } 3490 lasttime = NFSD_MONOSEC; 3491 atomic_store_rel_int(&onethread, 0); 3492 } 3493 3494 /* Now, unlock all locked mutexes. */ 3495 if (hp_idnum != NULL) 3496 mtx_unlock(&hp_idnum->mtx); 3497 if (hp_name != NULL) 3498 mtx_unlock(&hp_name->mtx); 3499 if (user_locked != 0) 3500 for (i = 0; i < nfsrv_lughashsize; i++) 3501 mtx_unlock(&nfsuserhash[i].mtx); 3502 if (username_locked != 0) 3503 for (i = 0; i < nfsrv_lughashsize; i++) 3504 mtx_unlock(&nfsusernamehash[i].mtx); 3505 if (group_locked != 0) 3506 for (i = 0; i < nfsrv_lughashsize; i++) 3507 mtx_unlock(&nfsgrouphash[i].mtx); 3508 if (groupname_locked != 0) 3509 for (i = 0; i < nfsrv_lughashsize; i++) 3510 mtx_unlock(&nfsgroupnamehash[i].mtx); 3511out: 3512 NFSEXITCODE(error); 3513 return (error); 3514} 3515 3516/* 3517 * Remove a user/group name element. 3518 */ 3519static void 3520nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser) 3521{ 3522 struct nfsrv_lughash *hp; 3523 3524 if (isuser != 0) { 3525 hp = NFSUSERHASH(usrp->lug_uid); 3526 mtx_assert(&hp->mtx, MA_OWNED); 3527 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3528 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3529 mtx_assert(&hp->mtx, MA_OWNED); 3530 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 3531 } else { 3532 hp = NFSGROUPHASH(usrp->lug_gid); 3533 mtx_assert(&hp->mtx, MA_OWNED); 3534 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3535 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3536 mtx_assert(&hp->mtx, MA_OWNED); 3537 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 3538 } 3539 atomic_add_int(&nfsrv_usercnt, -1); 3540 if (usrp->lug_cred != NULL) 3541 crfree(usrp->lug_cred); 3542 free(usrp, M_NFSUSERGROUP); 3543} 3544 3545/* 3546 * Free up all the allocations related to the name<-->id cache. 3547 * This function should only be called when the nfsuserd daemon isn't 3548 * running, since it doesn't do any locking. 3549 * This function is meant to be used when the nfscommon module is unloaded. 3550 */ 3551APPLESTATIC void 3552nfsrv_cleanusergroup(void) 3553{ 3554 struct nfsrv_lughash *hp, *hp2; 3555 struct nfsusrgrp *nusrp, *usrp; 3556 int i; 3557 3558 if (nfsuserhash == NULL) 3559 return; 3560 3561 for (i = 0; i < nfsrv_lughashsize; i++) { 3562 hp = &nfsuserhash[i]; 3563 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 3564 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3565 hp2 = NFSUSERNAMEHASH(usrp->lug_name, 3566 usrp->lug_namelen); 3567 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 3568 if (usrp->lug_cred != NULL) 3569 crfree(usrp->lug_cred); 3570 free(usrp, M_NFSUSERGROUP); 3571 } 3572 hp = &nfsgrouphash[i]; 3573 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 3574 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3575 hp2 = NFSGROUPNAMEHASH(usrp->lug_name, 3576 usrp->lug_namelen); 3577 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 3578 if (usrp->lug_cred != NULL) 3579 crfree(usrp->lug_cred); 3580 free(usrp, M_NFSUSERGROUP); 3581 } 3582 mtx_destroy(&nfsuserhash[i].mtx); 3583 mtx_destroy(&nfsusernamehash[i].mtx); 3584 mtx_destroy(&nfsgroupnamehash[i].mtx); 3585 mtx_destroy(&nfsgrouphash[i].mtx); 3586 } 3587 free(nfsuserhash, M_NFSUSERGROUP); 3588 free(nfsusernamehash, M_NFSUSERGROUP); 3589 free(nfsgrouphash, M_NFSUSERGROUP); 3590 free(nfsgroupnamehash, M_NFSUSERGROUP); 3591 free(nfsrv_dnsname, M_NFSSTRING); 3592} 3593 3594/* 3595 * This function scans a byte string and checks for UTF-8 compliance. 3596 * It returns 0 if it conforms and NFSERR_INVAL if not. 3597 */ 3598APPLESTATIC int 3599nfsrv_checkutf8(u_int8_t *cp, int len) 3600{ 3601 u_int32_t val = 0x0; 3602 int cnt = 0, gotd = 0, shift = 0; 3603 u_int8_t byte; 3604 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 3605 int error = 0; 3606 3607 /* 3608 * Here are what the variables are used for: 3609 * val - the calculated value of a multibyte char, used to check 3610 * that it was coded with the correct range 3611 * cnt - the number of 10xxxxxx bytes to follow 3612 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 3613 * shift - lower order bits of range (ie. "val >> shift" should 3614 * not be 0, in other words, dividing by the lower bound 3615 * of the range should get a non-zero value) 3616 * byte - used to calculate cnt 3617 */ 3618 while (len > 0) { 3619 if (cnt > 0) { 3620 /* This handles the 10xxxxxx bytes */ 3621 if ((*cp & 0xc0) != 0x80 || 3622 (gotd && (*cp & 0x20))) { 3623 error = NFSERR_INVAL; 3624 goto out; 3625 } 3626 gotd = 0; 3627 val <<= 6; 3628 val |= (*cp & 0x3f); 3629 cnt--; 3630 if (cnt == 0 && (val >> shift) == 0x0) { 3631 error = NFSERR_INVAL; 3632 goto out; 3633 } 3634 } else if (*cp & 0x80) { 3635 /* first byte of multi byte char */ 3636 byte = *cp; 3637 while ((byte & 0x40) && cnt < 6) { 3638 cnt++; 3639 byte <<= 1; 3640 } 3641 if (cnt == 0 || cnt == 6) { 3642 error = NFSERR_INVAL; 3643 goto out; 3644 } 3645 val = (*cp & (0x3f >> cnt)); 3646 shift = utf8_shift[cnt - 1]; 3647 if (cnt == 2 && val == 0xd) 3648 /* Check for the 0xd800-0xdfff case */ 3649 gotd = 1; 3650 } 3651 cp++; 3652 len--; 3653 } 3654 if (cnt > 0) 3655 error = NFSERR_INVAL; 3656 3657out: 3658 NFSEXITCODE(error); 3659 return (error); 3660} 3661 3662/* 3663 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 3664 * strings, one with the root path in it and the other with the list of 3665 * locations. The list is in the same format as is found in nfr_refs. 3666 * It is a "," separated list of entries, where each of them is of the 3667 * form <server>:<rootpath>. For example 3668 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 3669 * The nilp argument is set to 1 for the special case of a null fs_root 3670 * and an empty server list. 3671 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 3672 * number of xdr bytes parsed in sump. 3673 */ 3674static int 3675nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 3676 int *sump, int *nilp) 3677{ 3678 u_int32_t *tl; 3679 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 3680 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 3681 struct list { 3682 SLIST_ENTRY(list) next; 3683 int len; 3684 u_char host[1]; 3685 } *lsp, *nlsp; 3686 SLIST_HEAD(, list) head; 3687 3688 *fsrootp = NULL; 3689 *srvp = NULL; 3690 *nilp = 0; 3691 3692 /* 3693 * Get the fs_root path and check for the special case of null path 3694 * and 0 length server list. 3695 */ 3696 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3697 len = fxdr_unsigned(int, *tl); 3698 if (len < 0 || len > 10240) { 3699 error = NFSERR_BADXDR; 3700 goto nfsmout; 3701 } 3702 if (len == 0) { 3703 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3704 if (*tl != 0) { 3705 error = NFSERR_BADXDR; 3706 goto nfsmout; 3707 } 3708 *nilp = 1; 3709 *sump = 2 * NFSX_UNSIGNED; 3710 error = 0; 3711 goto nfsmout; 3712 } 3713 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 3714 error = nfsrv_mtostr(nd, cp, len); 3715 if (!error) { 3716 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3717 cnt = fxdr_unsigned(int, *tl); 3718 if (cnt <= 0) 3719 error = NFSERR_BADXDR; 3720 } 3721 if (error) 3722 goto nfsmout; 3723 3724 /* 3725 * Now, loop through the location list and make up the srvlist. 3726 */ 3727 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3728 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 3729 slen = 1024; 3730 siz = 0; 3731 for (i = 0; i < cnt; i++) { 3732 SLIST_INIT(&head); 3733 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3734 nsrv = fxdr_unsigned(int, *tl); 3735 if (nsrv <= 0) { 3736 error = NFSERR_BADXDR; 3737 goto nfsmout; 3738 } 3739 3740 /* 3741 * Handle the first server by putting it in the srvstr. 3742 */ 3743 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3744 len = fxdr_unsigned(int, *tl); 3745 if (len <= 0 || len > 1024) { 3746 error = NFSERR_BADXDR; 3747 goto nfsmout; 3748 } 3749 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 3750 if (cp3 != cp2) { 3751 *cp3++ = ','; 3752 siz++; 3753 } 3754 error = nfsrv_mtostr(nd, cp3, len); 3755 if (error) 3756 goto nfsmout; 3757 cp3 += len; 3758 *cp3++ = ':'; 3759 siz += (len + 1); 3760 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3761 for (j = 1; j < nsrv; j++) { 3762 /* 3763 * Yuck, put them in an slist and process them later. 3764 */ 3765 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3766 len = fxdr_unsigned(int, *tl); 3767 if (len <= 0 || len > 1024) { 3768 error = NFSERR_BADXDR; 3769 goto nfsmout; 3770 } 3771 lsp = (struct list *)malloc(sizeof (struct list) 3772 + len, M_TEMP, M_WAITOK); 3773 error = nfsrv_mtostr(nd, lsp->host, len); 3774 if (error) 3775 goto nfsmout; 3776 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3777 lsp->len = len; 3778 SLIST_INSERT_HEAD(&head, lsp, next); 3779 } 3780 3781 /* 3782 * Finally, we can get the path. 3783 */ 3784 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3785 len = fxdr_unsigned(int, *tl); 3786 if (len <= 0 || len > 1024) { 3787 error = NFSERR_BADXDR; 3788 goto nfsmout; 3789 } 3790 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 3791 error = nfsrv_mtostr(nd, cp3, len); 3792 if (error) 3793 goto nfsmout; 3794 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3795 str = cp3; 3796 stringlen = len; 3797 cp3 += len; 3798 siz += len; 3799 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 3800 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 3801 &cp2, &cp3, &slen); 3802 *cp3++ = ','; 3803 NFSBCOPY(lsp->host, cp3, lsp->len); 3804 cp3 += lsp->len; 3805 *cp3++ = ':'; 3806 NFSBCOPY(str, cp3, stringlen); 3807 cp3 += stringlen; 3808 *cp3 = '\0'; 3809 siz += (lsp->len + stringlen + 2); 3810 free((caddr_t)lsp, M_TEMP); 3811 } 3812 } 3813 *fsrootp = cp; 3814 *srvp = cp2; 3815 *sump = xdrsum; 3816 NFSEXITCODE2(0, nd); 3817 return (0); 3818nfsmout: 3819 if (cp != NULL) 3820 free(cp, M_NFSSTRING); 3821 if (cp2 != NULL) 3822 free(cp2, M_NFSSTRING); 3823 NFSEXITCODE2(error, nd); 3824 return (error); 3825} 3826 3827/* 3828 * Make the malloc'd space large enough. This is a pain, but the xdr 3829 * doesn't set an upper bound on the side, so... 3830 */ 3831static void 3832nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 3833{ 3834 u_char *cp; 3835 int i; 3836 3837 if (siz <= *slenp) 3838 return; 3839 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 3840 NFSBCOPY(*cpp, cp, *slenp); 3841 free(*cpp, M_NFSSTRING); 3842 i = *cpp2 - *cpp; 3843 *cpp = cp; 3844 *cpp2 = cp + i; 3845 *slenp = siz + 1024; 3846} 3847 3848/* 3849 * Initialize the reply header data structures. 3850 */ 3851APPLESTATIC void 3852nfsrvd_rephead(struct nfsrv_descript *nd) 3853{ 3854 mbuf_t mreq; 3855 3856 /* 3857 * If this is a big reply, use a cluster. 3858 */ 3859 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 3860 nfs_bigreply[nd->nd_procnum]) { 3861 NFSMCLGET(mreq, M_WAITOK); 3862 nd->nd_mreq = mreq; 3863 nd->nd_mb = mreq; 3864 } else { 3865 NFSMGET(mreq); 3866 nd->nd_mreq = mreq; 3867 nd->nd_mb = mreq; 3868 } 3869 nd->nd_bpos = NFSMTOD(mreq, caddr_t); 3870 mbuf_setlen(mreq, 0); 3871 3872 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 3873 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 3874} 3875 3876/* 3877 * Lock a socket against others. 3878 * Currently used to serialize connect/disconnect attempts. 3879 */ 3880int 3881newnfs_sndlock(int *flagp) 3882{ 3883 struct timespec ts; 3884 3885 NFSLOCKSOCK(); 3886 while (*flagp & NFSR_SNDLOCK) { 3887 *flagp |= NFSR_WANTSND; 3888 ts.tv_sec = 0; 3889 ts.tv_nsec = 0; 3890 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 3891 PZERO - 1, "nfsndlck", &ts); 3892 } 3893 *flagp |= NFSR_SNDLOCK; 3894 NFSUNLOCKSOCK(); 3895 return (0); 3896} 3897 3898/* 3899 * Unlock the stream socket for others. 3900 */ 3901void 3902newnfs_sndunlock(int *flagp) 3903{ 3904 3905 NFSLOCKSOCK(); 3906 if ((*flagp & NFSR_SNDLOCK) == 0) 3907 panic("nfs sndunlock"); 3908 *flagp &= ~NFSR_SNDLOCK; 3909 if (*flagp & NFSR_WANTSND) { 3910 *flagp &= ~NFSR_WANTSND; 3911 wakeup((caddr_t)flagp); 3912 } 3913 NFSUNLOCKSOCK(); 3914} 3915 3916APPLESTATIC int 3917nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa, 3918 int *isudp) 3919{ 3920 struct sockaddr_in *sad; 3921 struct sockaddr_in6 *sad6; 3922 struct in_addr saddr; 3923 uint32_t portnum, *tl; 3924 int af = 0, i, j, k; 3925 char addr[64], protocol[5], *cp; 3926 int cantparse = 0, error = 0; 3927 uint16_t portv; 3928 3929 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3930 i = fxdr_unsigned(int, *tl); 3931 if (i >= 3 && i <= 4) { 3932 error = nfsrv_mtostr(nd, protocol, i); 3933 if (error) 3934 goto nfsmout; 3935 if (strcmp(protocol, "tcp") == 0) { 3936 af = AF_INET; 3937 *isudp = 0; 3938 } else if (strcmp(protocol, "udp") == 0) { 3939 af = AF_INET; 3940 *isudp = 1; 3941 } else if (strcmp(protocol, "tcp6") == 0) { 3942 af = AF_INET6; 3943 *isudp = 0; 3944 } else if (strcmp(protocol, "udp6") == 0) { 3945 af = AF_INET6; 3946 *isudp = 1; 3947 } else 3948 cantparse = 1; 3949 } else { 3950 cantparse = 1; 3951 if (i > 0) { 3952 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3953 if (error) 3954 goto nfsmout; 3955 } 3956 } 3957 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3958 i = fxdr_unsigned(int, *tl); 3959 if (i < 0) { 3960 error = NFSERR_BADXDR; 3961 goto nfsmout; 3962 } else if (cantparse == 0 && i >= 11 && i < 64) { 3963 /* 3964 * The shortest address is 11chars and the longest is < 64. 3965 */ 3966 error = nfsrv_mtostr(nd, addr, i); 3967 if (error) 3968 goto nfsmout; 3969 3970 /* Find the port# at the end and extract that. */ 3971 i = strlen(addr); 3972 k = 0; 3973 cp = &addr[i - 1]; 3974 /* Count back two '.'s from end to get port# field. */ 3975 for (j = 0; j < i; j++) { 3976 if (*cp == '.') { 3977 k++; 3978 if (k == 2) 3979 break; 3980 } 3981 cp--; 3982 } 3983 if (k == 2) { 3984 /* 3985 * The NFSv4 port# is appended as .N.N, where N is 3986 * a decimal # in the range 0-255, just like an inet4 3987 * address. Cheat and use inet_aton(), which will 3988 * return a Class A address and then shift the high 3989 * order 8bits over to convert it to the port#. 3990 */ 3991 *cp++ = '\0'; 3992 if (inet_aton(cp, &saddr) == 1) { 3993 portnum = ntohl(saddr.s_addr); 3994 portv = (uint16_t)((portnum >> 16) | 3995 (portnum & 0xff)); 3996 } else 3997 cantparse = 1; 3998 } else 3999 cantparse = 1; 4000 if (cantparse == 0) { 4001 if (af == AF_INET) { 4002 sad = (struct sockaddr_in *)sa; 4003 if (inet_pton(af, addr, &sad->sin_addr) == 1) { 4004 sad->sin_len = sizeof(*sad); 4005 sad->sin_family = AF_INET; 4006 sad->sin_port = htons(portv); 4007 return (0); 4008 } 4009 } else { 4010 sad6 = (struct sockaddr_in6 *)sa; 4011 if (inet_pton(af, addr, &sad6->sin6_addr) 4012 == 1) { 4013 sad6->sin6_len = sizeof(*sad6); 4014 sad6->sin6_family = AF_INET6; 4015 sad6->sin6_port = htons(portv); 4016 return (0); 4017 } 4018 } 4019 } 4020 } else { 4021 if (i > 0) { 4022 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4023 if (error) 4024 goto nfsmout; 4025 } 4026 } 4027 error = EPERM; 4028nfsmout: 4029 return (error); 4030} 4031 4032/* 4033 * Handle an NFSv4.1 Sequence request for the session. 4034 * If reply != NULL, use it to return the cached reply, as required. 4035 * The client gets a cached reply via this call for callbacks, however the 4036 * server gets a cached reply via the nfsv4_seqsess_cachereply() call. 4037 */ 4038int 4039nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 4040 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 4041{ 4042 int error; 4043 4044 error = 0; 4045 if (reply != NULL) 4046 *reply = NULL; 4047 if (slotid > maxslot) 4048 return (NFSERR_BADSLOT); 4049 if (seqid == slots[slotid].nfssl_seq) { 4050 /* A retry. */ 4051 if (slots[slotid].nfssl_inprog != 0) 4052 error = NFSERR_DELAY; 4053 else if (slots[slotid].nfssl_reply != NULL) { 4054 if (reply != NULL) { 4055 *reply = slots[slotid].nfssl_reply; 4056 slots[slotid].nfssl_reply = NULL; 4057 } 4058 slots[slotid].nfssl_inprog = 1; 4059 error = NFSERR_REPLYFROMCACHE; 4060 } else 4061 /* No reply cached, so just do it. */ 4062 slots[slotid].nfssl_inprog = 1; 4063 } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 4064 if (slots[slotid].nfssl_reply != NULL) 4065 m_freem(slots[slotid].nfssl_reply); 4066 slots[slotid].nfssl_reply = NULL; 4067 slots[slotid].nfssl_inprog = 1; 4068 slots[slotid].nfssl_seq++; 4069 } else 4070 error = NFSERR_SEQMISORDERED; 4071 return (error); 4072} 4073 4074/* 4075 * Cache this reply for the slot. 4076 * Use the "rep" argument to return the cached reply if repstat is set to 4077 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value. 4078 */ 4079void 4080nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat, 4081 struct mbuf **rep) 4082{ 4083 4084 if (repstat == NFSERR_REPLYFROMCACHE) { 4085 *rep = slots[slotid].nfssl_reply; 4086 slots[slotid].nfssl_reply = NULL; 4087 } else { 4088 if (slots[slotid].nfssl_reply != NULL) 4089 m_freem(slots[slotid].nfssl_reply); 4090 slots[slotid].nfssl_reply = *rep; 4091 } 4092 slots[slotid].nfssl_inprog = 0; 4093} 4094 4095/* 4096 * Generate the xdr for an NFSv4.1 Sequence Operation. 4097 */ 4098APPLESTATIC void 4099nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, 4100 struct nfsclsession *sep, int dont_replycache) 4101{ 4102 uint32_t *tl, slotseq = 0; 4103 int error, maxslot, slotpos; 4104 uint8_t sessionid[NFSX_V4SESSIONID]; 4105 4106 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq, 4107 sessionid); 4108 if (error != 0) 4109 return; 4110 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot")); 4111 4112 /* Build the Sequence arguments. */ 4113 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 4114 bcopy(sessionid, tl, NFSX_V4SESSIONID); 4115 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4116 nd->nd_slotseq = tl; 4117 *tl++ = txdr_unsigned(slotseq); 4118 *tl++ = txdr_unsigned(slotpos); 4119 *tl++ = txdr_unsigned(maxslot); 4120 if (dont_replycache == 0) 4121 *tl = newnfs_true; 4122 else 4123 *tl = newnfs_false; 4124 nd->nd_flag |= ND_HASSEQUENCE; 4125} 4126 4127int 4128nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep, 4129 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid) 4130{ 4131 int i, maxslot, slotpos; 4132 uint64_t bitval; 4133 4134 /* Find an unused slot. */ 4135 slotpos = -1; 4136 maxslot = -1; 4137 mtx_lock(&sep->nfsess_mtx); 4138 do { 4139 bitval = 1; 4140 for (i = 0; i < sep->nfsess_foreslots; i++) { 4141 if ((bitval & sep->nfsess_slots) == 0) { 4142 slotpos = i; 4143 sep->nfsess_slots |= bitval; 4144 sep->nfsess_slotseq[i]++; 4145 *slotseqp = sep->nfsess_slotseq[i]; 4146 break; 4147 } 4148 bitval <<= 1; 4149 } 4150 if (slotpos == -1) { 4151 /* 4152 * If a forced dismount is in progress, just return. 4153 * This RPC attempt will fail when it calls 4154 * newnfs_request(). 4155 */ 4156 if (nmp != NULL && 4157 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) 4158 != 0) { 4159 mtx_unlock(&sep->nfsess_mtx); 4160 return (ESTALE); 4161 } 4162 /* Wake up once/sec, to check for a forced dismount. */ 4163 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 4164 PZERO, "nfsclseq", hz); 4165 } 4166 } while (slotpos == -1); 4167 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 4168 bitval = 1; 4169 for (i = 0; i < 64; i++) { 4170 if ((bitval & sep->nfsess_slots) != 0) 4171 maxslot = i; 4172 bitval <<= 1; 4173 } 4174 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 4175 mtx_unlock(&sep->nfsess_mtx); 4176 *slotposp = slotpos; 4177 *maxslotp = maxslot; 4178 return (0); 4179} 4180 4181/* 4182 * Free a session slot. 4183 */ 4184APPLESTATIC void 4185nfsv4_freeslot(struct nfsclsession *sep, int slot) 4186{ 4187 uint64_t bitval; 4188 4189 bitval = 1; 4190 if (slot > 0) 4191 bitval <<= slot; 4192 mtx_lock(&sep->nfsess_mtx); 4193 if ((bitval & sep->nfsess_slots) == 0) 4194 printf("freeing free slot!!\n"); 4195 sep->nfsess_slots &= ~bitval; 4196 wakeup(&sep->nfsess_slots); 4197 mtx_unlock(&sep->nfsess_mtx); 4198} 4199 4200