nfs_commonsubs.c revision 347040
1/*- 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: stable/10/sys/fs/nfs/nfs_commonsubs.c 347040 2019-05-03 02:30:01Z rmacklem $"); 36 37/* 38 * These functions support the macros and help fiddle mbuf chains for 39 * the nfs op functions. They do things like create the rpc header and 40 * copy data between mbuf chains and uio lists. 41 */ 42#ifndef APPLEKEXT 43#include "opt_inet.h" 44#include "opt_inet6.h" 45 46#include <fs/nfs/nfsport.h> 47 48#include <security/mac/mac_framework.h> 49 50/* 51 * Data items converted to xdr at startup, since they are constant 52 * This is kinda hokey, but may save a little time doing byte swaps 53 */ 54u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1; 55 56/* And other global data */ 57nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, 58 NFFIFO, NFNON }; 59enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; 60enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 61struct timeval nfsboottime; /* Copy boottime once, so it never changes */ 62int nfscl_ticks; 63int nfsrv_useacl = 1; 64struct nfssockreq nfsrv_nfsuserdsock; 65int nfsrv_nfsuserd = 0; 66struct nfsreqhead nfsd_reqq; 67uid_t nfsrv_defaultuid = UID_NOBODY; 68gid_t nfsrv_defaultgid = GID_NOGROUP; 69int nfsrv_lease = NFSRV_LEASE; 70int ncl_mbuf_mlen = MLEN; 71int nfsd_enable_stringtouid = 0; 72static int nfs_enable_uidtostring = 0; 73NFSNAMEIDMUTEX; 74NFSSOCKMUTEX; 75extern int nfsrv_lughashsize; 76 77SYSCTL_DECL(_vfs_nfs); 78SYSCTL_INT(_vfs_nfs, OID_AUTO, enable_uidtostring, CTLFLAG_RW, 79 &nfs_enable_uidtostring, 0, "Make nfs always send numeric owner_names"); 80 81/* 82 * This array of structures indicates, for V4: 83 * retfh - which of 3 types of calling args are used 84 * 0 - doesn't change cfh or use a sfh 85 * 1 - replaces cfh with a new one (unless it returns an error status) 86 * 2 - uses cfh and sfh 87 * needscfh - if the op wants a cfh and premtime 88 * 0 - doesn't use a cfh 89 * 1 - uses a cfh, but doesn't want pre-op attributes 90 * 2 - uses a cfh and wants pre-op attributes 91 * savereply - indicates a non-idempotent Op 92 * 0 - not non-idempotent 93 * 1 - non-idempotent 94 * Ops that are ordered via seqid# are handled separately from these 95 * non-idempotent Ops. 96 * Define it here, since it is used by both the client and server. 97 */ 98struct nfsv4_opflag nfsv4_opflag[NFSV41_NOPS] = { 99 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ 100 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ 101 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* undef */ 102 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Access */ 103 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Close */ 104 { 0, 2, 0, 1, LK_EXCLUSIVE, 1, 1 }, /* Commit */ 105 { 1, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Create */ 106 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegpurge */ 107 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Delegreturn */ 108 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Getattr */ 109 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* GetFH */ 110 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Link */ 111 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Lock */ 112 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockT */ 113 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* LockU */ 114 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookup */ 115 { 1, 2, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Lookupp */ 116 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* NVerify */ 117 { 1, 1, 0, 1, LK_EXCLUSIVE, 1, 0 }, /* Open */ 118 { 1, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenAttr */ 119 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenConfirm */ 120 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* OpenDowngrade */ 121 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutFH */ 122 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutPubFH */ 123 { 1, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* PutRootFH */ 124 { 0, 1, 0, 0, LK_SHARED, 1, 0 }, /* Read */ 125 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* Readdir */ 126 { 0, 1, 0, 0, LK_SHARED, 1, 1 }, /* ReadLink */ 127 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Remove */ 128 { 2, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Rename */ 129 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Renew */ 130 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* RestoreFH */ 131 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SaveFH */ 132 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SecInfo */ 133 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Setattr */ 134 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientID */ 135 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* SetClientIDConfirm */ 136 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Verify */ 137 { 0, 2, 1, 1, LK_EXCLUSIVE, 1, 0 }, /* Write */ 138 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* ReleaseLockOwner */ 139 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Backchannel Ctrl */ 140 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Bind Conn to Sess */ 141 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Exchange ID */ 142 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Create Session */ 143 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy Session */ 144 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Free StateID */ 145 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Dir Deleg */ 146 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device Info */ 147 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Get Device List */ 148 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Commit */ 149 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Layout Get */ 150 { 0, 1, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Layout Return */ 151 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Secinfo No name */ 152 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Sequence */ 153 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Set SSV */ 154 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Test StateID */ 155 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 1 }, /* Want Delegation */ 156 { 0, 0, 0, 0, LK_EXCLUSIVE, 0, 0 }, /* Destroy ClientID */ 157 { 0, 0, 0, 0, LK_EXCLUSIVE, 1, 0 }, /* Reclaim Complete */ 158}; 159#endif /* !APPLEKEXT */ 160 161static int ncl_mbuf_mhlen = MHLEN; 162static int nfsrv_usercnt = 0; 163static int nfsrv_dnsnamelen; 164static u_char *nfsrv_dnsname = NULL; 165static int nfsrv_usermax = 999999999; 166struct nfsrv_lughash { 167 struct mtx mtx; 168 struct nfsuserhashhead lughead; 169}; 170static struct nfsrv_lughash *nfsuserhash; 171static struct nfsrv_lughash *nfsusernamehash; 172static struct nfsrv_lughash *nfsgrouphash; 173static struct nfsrv_lughash *nfsgroupnamehash; 174 175/* 176 * This static array indicates whether or not the RPC generates a large 177 * reply. This is used by nfs_reply() to decide whether or not an mbuf 178 * cluster should be allocated. (If a cluster is required by an RPC 179 * marked 0 in this array, the code will still work, just not quite as 180 * efficiently.) 181 */ 182int nfs_bigreply[NFSV41_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 183 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, 184 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }; 185 186/* local functions */ 187static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); 188static void nfsv4_wanted(struct nfsv4lock *lp); 189static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len); 190static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, 191 NFSPROC_T *p); 192static void nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser); 193static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **, 194 int *, int *); 195static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *); 196 197 198#ifndef APPLE 199/* 200 * copies mbuf chain to the uio scatter/gather list 201 */ 202int 203nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz) 204{ 205 char *mbufcp, *uiocp; 206 int xfer, left, len; 207 mbuf_t mp; 208 long uiosiz, rem; 209 int error = 0; 210 211 mp = nd->nd_md; 212 mbufcp = nd->nd_dpos; 213 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp; 214 rem = NFSM_RNDUP(siz) - siz; 215 while (siz > 0) { 216 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) { 217 error = EBADRPC; 218 goto out; 219 } 220 left = uiop->uio_iov->iov_len; 221 uiocp = uiop->uio_iov->iov_base; 222 if (left > siz) 223 left = siz; 224 uiosiz = left; 225 while (left > 0) { 226 while (len == 0) { 227 mp = mbuf_next(mp); 228 if (mp == NULL) { 229 error = EBADRPC; 230 goto out; 231 } 232 mbufcp = NFSMTOD(mp, caddr_t); 233 len = mbuf_len(mp); 234 KASSERT(len >= 0, 235 ("len %d, corrupted mbuf?", len)); 236 } 237 xfer = (left > len) ? len : left; 238#ifdef notdef 239 /* Not Yet.. */ 240 if (uiop->uio_iov->iov_op != NULL) 241 (*(uiop->uio_iov->iov_op)) 242 (mbufcp, uiocp, xfer); 243 else 244#endif 245 if (uiop->uio_segflg == UIO_SYSSPACE) 246 NFSBCOPY(mbufcp, uiocp, xfer); 247 else 248 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer); 249 left -= xfer; 250 len -= xfer; 251 mbufcp += xfer; 252 uiocp += xfer; 253 uiop->uio_offset += xfer; 254 uiop->uio_resid -= xfer; 255 } 256 if (uiop->uio_iov->iov_len <= siz) { 257 uiop->uio_iovcnt--; 258 uiop->uio_iov++; 259 } else { 260 uiop->uio_iov->iov_base = (void *) 261 ((char *)uiop->uio_iov->iov_base + uiosiz); 262 uiop->uio_iov->iov_len -= uiosiz; 263 } 264 siz -= uiosiz; 265 } 266 nd->nd_dpos = mbufcp; 267 nd->nd_md = mp; 268 if (rem > 0) { 269 if (len < rem) 270 error = nfsm_advance(nd, rem, len); 271 else 272 nd->nd_dpos += rem; 273 } 274 275out: 276 NFSEXITCODE2(error, nd); 277 return (error); 278} 279#endif /* !APPLE */ 280 281/* 282 * Help break down an mbuf chain by setting the first siz bytes contiguous 283 * pointed to by returned val. 284 * This is used by the macro NFSM_DISSECT for tough 285 * cases. 286 */ 287APPLESTATIC void * 288nfsm_dissct(struct nfsrv_descript *nd, int siz, int how) 289{ 290 mbuf_t mp2; 291 int siz2, xfer; 292 caddr_t p; 293 int left; 294 caddr_t retp; 295 296 retp = NULL; 297 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos; 298 while (left == 0) { 299 nd->nd_md = mbuf_next(nd->nd_md); 300 if (nd->nd_md == NULL) 301 return (retp); 302 left = mbuf_len(nd->nd_md); 303 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); 304 } 305 if (left >= siz) { 306 retp = nd->nd_dpos; 307 nd->nd_dpos += siz; 308 } else if (mbuf_next(nd->nd_md) == NULL) { 309 return (retp); 310 } else if (siz > ncl_mbuf_mhlen) { 311 panic("nfs S too big"); 312 } else { 313 MGET(mp2, MT_DATA, how); 314 if (mp2 == NULL) 315 return (NULL); 316 mbuf_setnext(mp2, mbuf_next(nd->nd_md)); 317 mbuf_setnext(nd->nd_md, mp2); 318 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left); 319 nd->nd_md = mp2; 320 retp = p = NFSMTOD(mp2, caddr_t); 321 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */ 322 siz2 = siz - left; 323 p += left; 324 mp2 = mbuf_next(mp2); 325 /* Loop around copying up the siz2 bytes */ 326 while (siz2 > 0) { 327 if (mp2 == NULL) 328 return (NULL); 329 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2; 330 if (xfer > 0) { 331 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer); 332 NFSM_DATAP(mp2, xfer); 333 mbuf_setlen(mp2, mbuf_len(mp2) - xfer); 334 p += xfer; 335 siz2 -= xfer; 336 } 337 if (siz2 > 0) 338 mp2 = mbuf_next(mp2); 339 } 340 mbuf_setlen(nd->nd_md, siz); 341 nd->nd_md = mp2; 342 nd->nd_dpos = NFSMTOD(mp2, caddr_t); 343 } 344 return (retp); 345} 346 347/* 348 * Advance the position in the mbuf chain. 349 * If offs == 0, this is a no-op, but it is simpler to just return from 350 * here than check for offs > 0 for all calls to nfsm_advance. 351 * If left == -1, it should be calculated here. 352 */ 353APPLESTATIC int 354nfsm_advance(struct nfsrv_descript *nd, int offs, int left) 355{ 356 int error = 0; 357 358 if (offs == 0) 359 goto out; 360 /* 361 * A negative offs should be considered a serious problem. 362 */ 363 if (offs < 0) 364 panic("nfsrv_advance"); 365 366 /* 367 * If left == -1, calculate it here. 368 */ 369 if (left == -1) 370 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - 371 nd->nd_dpos; 372 373 /* 374 * Loop around, advancing over the mbuf data. 375 */ 376 while (offs > left) { 377 offs -= left; 378 nd->nd_md = mbuf_next(nd->nd_md); 379 if (nd->nd_md == NULL) { 380 error = EBADRPC; 381 goto out; 382 } 383 left = mbuf_len(nd->nd_md); 384 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); 385 } 386 nd->nd_dpos += offs; 387 388out: 389 NFSEXITCODE(error); 390 return (error); 391} 392 393/* 394 * Copy a string into mbuf(s). 395 * Return the number of bytes output, including XDR overheads. 396 */ 397APPLESTATIC int 398nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz) 399{ 400 mbuf_t m2; 401 int xfer, left; 402 mbuf_t m1; 403 int rem, bytesize; 404 u_int32_t *tl; 405 char *cp2; 406 407 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 408 *tl = txdr_unsigned(siz); 409 rem = NFSM_RNDUP(siz) - siz; 410 bytesize = NFSX_UNSIGNED + siz + rem; 411 m2 = nd->nd_mb; 412 cp2 = nd->nd_bpos; 413 left = M_TRAILINGSPACE(m2); 414 415 /* 416 * Loop around copying the string to mbuf(s). 417 */ 418 while (siz > 0) { 419 if (left == 0) { 420 if (siz > ncl_mbuf_mlen) 421 NFSMCLGET(m1, M_WAITOK); 422 else 423 NFSMGET(m1); 424 mbuf_setlen(m1, 0); 425 mbuf_setnext(m2, m1); 426 m2 = m1; 427 cp2 = NFSMTOD(m2, caddr_t); 428 left = M_TRAILINGSPACE(m2); 429 } 430 if (left >= siz) 431 xfer = siz; 432 else 433 xfer = left; 434 NFSBCOPY(cp, cp2, xfer); 435 cp += xfer; 436 mbuf_setlen(m2, mbuf_len(m2) + xfer); 437 siz -= xfer; 438 left -= xfer; 439 if (siz == 0 && rem) { 440 if (left < rem) 441 panic("nfsm_strtom"); 442 NFSBZERO(cp2 + xfer, rem); 443 mbuf_setlen(m2, mbuf_len(m2) + rem); 444 } 445 } 446 nd->nd_mb = m2; 447 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); 448 return (bytesize); 449} 450 451/* 452 * Called once to initialize data structures... 453 */ 454APPLESTATIC void 455newnfs_init(void) 456{ 457 static int nfs_inited = 0; 458 459 if (nfs_inited) 460 return; 461 nfs_inited = 1; 462 463 newnfs_true = txdr_unsigned(TRUE); 464 newnfs_false = txdr_unsigned(FALSE); 465 newnfs_xdrneg1 = txdr_unsigned(-1); 466 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 467 if (nfscl_ticks < 1) 468 nfscl_ticks = 1; 469 NFSSETBOOTTIME(nfsboottime); 470 471 /* 472 * Initialize reply list and start timer 473 */ 474 TAILQ_INIT(&nfsd_reqq); 475 NFS_TIMERINIT; 476} 477 478/* 479 * Put a file handle in an mbuf list. 480 * If the size argument == 0, just use the default size. 481 * set_true == 1 if there should be an newnfs_true prepended on the file handle. 482 * Return the number of bytes output, including XDR overhead. 483 */ 484APPLESTATIC int 485nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true) 486{ 487 u_int32_t *tl; 488 u_int8_t *cp; 489 int fullsiz, rem, bytesize = 0; 490 491 if (size == 0) 492 size = NFSX_MYFH; 493 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { 494 case ND_NFSV2: 495 if (size > NFSX_V2FH) 496 panic("fh size > NFSX_V2FH for NFSv2"); 497 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH); 498 NFSBCOPY(fhp, cp, size); 499 if (size < NFSX_V2FH) 500 NFSBZERO(cp + size, NFSX_V2FH - size); 501 bytesize = NFSX_V2FH; 502 break; 503 case ND_NFSV3: 504 case ND_NFSV4: 505 fullsiz = NFSM_RNDUP(size); 506 rem = fullsiz - size; 507 if (set_true) { 508 bytesize = 2 * NFSX_UNSIGNED + fullsiz; 509 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 510 *tl = newnfs_true; 511 } else { 512 bytesize = NFSX_UNSIGNED + fullsiz; 513 } 514 (void) nfsm_strtom(nd, fhp, size); 515 break; 516 }; 517 return (bytesize); 518} 519 520/* 521 * This function compares two net addresses by family and returns TRUE 522 * if they are the same host. 523 * If there is any doubt, return FALSE. 524 * The AF_INET family is handled as a special case so that address mbufs 525 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 526 */ 527APPLESTATIC int 528nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam) 529{ 530 struct sockaddr_in *inetaddr; 531 532 switch (family) { 533 case AF_INET: 534 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *); 535 if (inetaddr->sin_family == AF_INET && 536 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr) 537 return (1); 538 break; 539#ifdef INET6 540 case AF_INET6: 541 { 542 struct sockaddr_in6 *inetaddr6; 543 544 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *); 545 /* XXX - should test sin6_scope_id ? */ 546 if (inetaddr6->sin6_family == AF_INET6 && 547 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr, 548 &haddr->had_inet6)) 549 return (1); 550 } 551 break; 552#endif 553 }; 554 return (0); 555} 556 557/* 558 * Similar to the above, but takes to NFSSOCKADDR_T args. 559 */ 560APPLESTATIC int 561nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2) 562{ 563 struct sockaddr_in *addr1, *addr2; 564 struct sockaddr *inaddr; 565 566 inaddr = NFSSOCKADDR(nam1, struct sockaddr *); 567 switch (inaddr->sa_family) { 568 case AF_INET: 569 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *); 570 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *); 571 if (addr2->sin_family == AF_INET && 572 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) 573 return (1); 574 break; 575#ifdef INET6 576 case AF_INET6: 577 { 578 struct sockaddr_in6 *inet6addr1, *inet6addr2; 579 580 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *); 581 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *); 582 /* XXX - should test sin6_scope_id ? */ 583 if (inet6addr2->sin6_family == AF_INET6 && 584 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 585 &inet6addr2->sin6_addr)) 586 return (1); 587 } 588 break; 589#endif 590 }; 591 return (0); 592} 593 594 595/* 596 * Trim the stuff already dissected off the mbuf list. 597 */ 598APPLESTATIC void 599newnfs_trimleading(nd) 600 struct nfsrv_descript *nd; 601{ 602 mbuf_t m, n; 603 int offs; 604 605 /* 606 * First, free up leading mbufs. 607 */ 608 if (nd->nd_mrep != nd->nd_md) { 609 m = nd->nd_mrep; 610 while (mbuf_next(m) != nd->nd_md) { 611 if (mbuf_next(m) == NULL) 612 panic("nfsm trim leading"); 613 m = mbuf_next(m); 614 } 615 mbuf_setnext(m, NULL); 616 mbuf_freem(nd->nd_mrep); 617 } 618 m = nd->nd_md; 619 620 /* 621 * Now, adjust this mbuf, based on nd_dpos. 622 */ 623 offs = nd->nd_dpos - NFSMTOD(m, caddr_t); 624 if (offs == mbuf_len(m)) { 625 n = m; 626 m = mbuf_next(m); 627 if (m == NULL) 628 panic("nfsm trim leading2"); 629 mbuf_setnext(n, NULL); 630 mbuf_freem(n); 631 } else if (offs > 0) { 632 mbuf_setlen(m, mbuf_len(m) - offs); 633 NFSM_DATAP(m, offs); 634 } else if (offs < 0) 635 panic("nfsm trimleading offs"); 636 nd->nd_mrep = m; 637 nd->nd_md = m; 638 nd->nd_dpos = NFSMTOD(m, caddr_t); 639} 640 641/* 642 * Trim trailing data off the mbuf list being built. 643 */ 644APPLESTATIC void 645newnfs_trimtrailing(nd, mb, bpos) 646 struct nfsrv_descript *nd; 647 mbuf_t mb; 648 caddr_t bpos; 649{ 650 651 if (mbuf_next(mb)) { 652 mbuf_freem(mbuf_next(mb)); 653 mbuf_setnext(mb, NULL); 654 } 655 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t)); 656 nd->nd_mb = mb; 657 nd->nd_bpos = bpos; 658} 659 660/* 661 * Dissect a file handle on the client. 662 */ 663APPLESTATIC int 664nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp) 665{ 666 u_int32_t *tl; 667 struct nfsfh *nfhp; 668 int error, len; 669 670 *nfhpp = NULL; 671 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 672 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 673 if ((len = fxdr_unsigned(int, *tl)) <= 0 || 674 len > NFSX_FHMAX) { 675 error = EBADRPC; 676 goto nfsmout; 677 } 678 } else 679 len = NFSX_V2FH; 680 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len, 681 M_NFSFH, M_WAITOK); 682 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len); 683 if (error) { 684 FREE((caddr_t)nfhp, M_NFSFH); 685 goto nfsmout; 686 } 687 nfhp->nfh_len = len; 688 *nfhpp = nfhp; 689nfsmout: 690 NFSEXITCODE2(error, nd); 691 return (error); 692} 693 694/* 695 * Break down the nfsv4 acl. 696 * If the aclp == NULL or won't fit in an acl, just discard the acl info. 697 */ 698APPLESTATIC int 699nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp, 700 int *aclsizep, __unused NFSPROC_T *p) 701{ 702 u_int32_t *tl; 703 int i, aclsize; 704 int acecnt, error = 0, aceerr = 0, acesize; 705 706 *aclerrp = 0; 707 if (aclp) 708 aclp->acl_cnt = 0; 709 /* 710 * Parse out the ace entries and expect them to conform to 711 * what can be supported by R/W/X bits. 712 */ 713 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 714 aclsize = NFSX_UNSIGNED; 715 acecnt = fxdr_unsigned(int, *tl); 716 if (acecnt > ACL_MAX_ENTRIES) 717 aceerr = NFSERR_ATTRNOTSUPP; 718 if (nfsrv_useacl == 0) 719 aceerr = NFSERR_ATTRNOTSUPP; 720 for (i = 0; i < acecnt; i++) { 721 if (aclp && !aceerr) 722 error = nfsrv_dissectace(nd, &aclp->acl_entry[i], 723 &aceerr, &acesize, p); 724 else 725 error = nfsrv_skipace(nd, &acesize); 726 if (error) 727 goto nfsmout; 728 aclsize += acesize; 729 } 730 if (aclp && !aceerr) 731 aclp->acl_cnt = acecnt; 732 if (aceerr) 733 *aclerrp = aceerr; 734 if (aclsizep) 735 *aclsizep = aclsize; 736nfsmout: 737 NFSEXITCODE2(error, nd); 738 return (error); 739} 740 741/* 742 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it. 743 */ 744static int 745nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep) 746{ 747 u_int32_t *tl; 748 int error, len = 0; 749 750 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 751 len = fxdr_unsigned(int, *(tl + 3)); 752 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 753nfsmout: 754 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); 755 NFSEXITCODE2(error, nd); 756 return (error); 757} 758 759/* 760 * Get attribute bits from an mbuf list. 761 * Returns EBADRPC for a parsing error, 0 otherwise. 762 * If the clearinvalid flag is set, clear the bits not supported. 763 */ 764APPLESTATIC int 765nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp, 766 int *retnotsupp) 767{ 768 u_int32_t *tl; 769 int cnt, i, outcnt; 770 int error = 0; 771 772 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 773 cnt = fxdr_unsigned(int, *tl); 774 if (cnt < 0) { 775 error = NFSERR_BADXDR; 776 goto nfsmout; 777 } 778 if (cnt > NFSATTRBIT_MAXWORDS) 779 outcnt = NFSATTRBIT_MAXWORDS; 780 else 781 outcnt = cnt; 782 NFSZERO_ATTRBIT(attrbitp); 783 if (outcnt > 0) { 784 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED); 785 for (i = 0; i < outcnt; i++) 786 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++); 787 } 788 for (i = 0; i < (cnt - outcnt); i++) { 789 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 790 if (retnotsupp != NULL && *tl != 0) 791 *retnotsupp = NFSERR_ATTRNOTSUPP; 792 } 793 if (cntp) 794 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED); 795nfsmout: 796 NFSEXITCODE2(error, nd); 797 return (error); 798} 799 800/* 801 * Get the attributes for V4. 802 * If the compare flag is true, test for any attribute changes, 803 * otherwise return the attribute values. 804 * These attributes cover fields in "struct vattr", "struct statfs", 805 * "struct nfsfsinfo", the file handle and the lease duration. 806 * The value of retcmpp is set to 1 if all attributes are the same, 807 * and 0 otherwise. 808 * Returns EBADRPC if it can't be parsed, 0 otherwise. 809 */ 810APPLESTATIC int 811nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, 812 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize, 813 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp, 814 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp, 815 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred) 816{ 817 u_int32_t *tl; 818 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0; 819 int error, tfhsize, aceerr, attrsize, cnt, retnotsup; 820 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1]; 821 nfsattrbit_t attrbits, retattrbits, checkattrbits; 822 struct nfsfh *tnfhp; 823 struct nfsreferral *refp; 824 u_quad_t tquad; 825 nfsquad_t tnfsquad; 826 struct timespec temptime; 827 uid_t uid; 828 gid_t gid; 829 long fid; 830 u_int32_t freenum = 0, tuint; 831 u_int64_t uquad = 0, thyp, thyp2; 832#ifdef QUOTA 833 struct dqblk dqb; 834 uid_t savuid; 835#endif 836 static struct timeval last64fileid; 837 static size_t count64fileid; 838 static struct timeval last64mountfileid; 839 static size_t count64mountfileid; 840 static struct timeval warninterval = { 60, 0 }; 841 842 if (compare) { 843 retnotsup = 0; 844 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); 845 } else { 846 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 847 } 848 if (error) 849 goto nfsmout; 850 851 if (compare) { 852 *retcmpp = retnotsup; 853 } else { 854 /* 855 * Just set default values to some of the important ones. 856 */ 857 if (nap != NULL) { 858 nap->na_type = VREG; 859 nap->na_mode = 0; 860 nap->na_rdev = (NFSDEV_T)0; 861 nap->na_mtime.tv_sec = 0; 862 nap->na_mtime.tv_nsec = 0; 863 nap->na_gen = 0; 864 nap->na_flags = 0; 865 nap->na_blocksize = NFS_FABLKSIZE; 866 } 867 if (sbp != NULL) { 868 sbp->f_bsize = NFS_FABLKSIZE; 869 sbp->f_blocks = 0; 870 sbp->f_bfree = 0; 871 sbp->f_bavail = 0; 872 sbp->f_files = 0; 873 sbp->f_ffree = 0; 874 } 875 if (fsp != NULL) { 876 fsp->fs_rtmax = 8192; 877 fsp->fs_rtpref = 8192; 878 fsp->fs_maxname = NFS_MAXNAMLEN; 879 fsp->fs_wtmax = 8192; 880 fsp->fs_wtpref = 8192; 881 fsp->fs_wtmult = NFS_FABLKSIZE; 882 fsp->fs_dtpref = 8192; 883 fsp->fs_maxfilesize = 0xffffffffffffffffull; 884 fsp->fs_timedelta.tv_sec = 0; 885 fsp->fs_timedelta.tv_nsec = 1; 886 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK | 887 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME); 888 } 889 if (pc != NULL) { 890 pc->pc_linkmax = LINK_MAX; 891 pc->pc_namemax = NAME_MAX; 892 pc->pc_notrunc = 0; 893 pc->pc_chownrestricted = 0; 894 pc->pc_caseinsensitive = 0; 895 pc->pc_casepreserving = 1; 896 } 897 if (sfp != NULL) { 898 sfp->sf_ffiles = UINT64_MAX; 899 sfp->sf_tfiles = UINT64_MAX; 900 sfp->sf_afiles = UINT64_MAX; 901 sfp->sf_fbytes = UINT64_MAX; 902 sfp->sf_tbytes = UINT64_MAX; 903 sfp->sf_abytes = UINT64_MAX; 904 } 905 } 906 907 /* 908 * Loop around getting the attributes. 909 */ 910 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 911 attrsize = fxdr_unsigned(int, *tl); 912 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 913 if (attrsum > attrsize) { 914 error = NFSERR_BADXDR; 915 goto nfsmout; 916 } 917 if (NFSISSET_ATTRBIT(&attrbits, bitpos)) 918 switch (bitpos) { 919 case NFSATTRBIT_SUPPORTEDATTRS: 920 retnotsup = 0; 921 if (compare || nap == NULL) 922 error = nfsrv_getattrbits(nd, &retattrbits, 923 &cnt, &retnotsup); 924 else 925 error = nfsrv_getattrbits(nd, &nap->na_suppattr, 926 &cnt, &retnotsup); 927 if (error) 928 goto nfsmout; 929 if (compare && !(*retcmpp)) { 930 NFSSETSUPP_ATTRBIT(&checkattrbits, nd); 931 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 932 || retnotsup) 933 *retcmpp = NFSERR_NOTSAME; 934 } 935 attrsum += cnt; 936 break; 937 case NFSATTRBIT_TYPE: 938 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 939 if (compare) { 940 if (!(*retcmpp)) { 941 if (nap->na_type != nfsv34tov_type(*tl)) 942 *retcmpp = NFSERR_NOTSAME; 943 } 944 } else if (nap != NULL) { 945 nap->na_type = nfsv34tov_type(*tl); 946 } 947 attrsum += NFSX_UNSIGNED; 948 break; 949 case NFSATTRBIT_FHEXPIRETYPE: 950 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 951 if (compare && !(*retcmpp)) { 952 if (fxdr_unsigned(int, *tl) != 953 NFSV4FHTYPE_PERSISTENT) 954 *retcmpp = NFSERR_NOTSAME; 955 } 956 attrsum += NFSX_UNSIGNED; 957 break; 958 case NFSATTRBIT_CHANGE: 959 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 960 if (compare) { 961 if (!(*retcmpp)) { 962 if (nap->na_filerev != fxdr_hyper(tl)) 963 *retcmpp = NFSERR_NOTSAME; 964 } 965 } else if (nap != NULL) { 966 nap->na_filerev = fxdr_hyper(tl); 967 } 968 attrsum += NFSX_HYPER; 969 break; 970 case NFSATTRBIT_SIZE: 971 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 972 if (compare) { 973 if (!(*retcmpp)) { 974 if (nap->na_size != fxdr_hyper(tl)) 975 *retcmpp = NFSERR_NOTSAME; 976 } 977 } else if (nap != NULL) { 978 nap->na_size = fxdr_hyper(tl); 979 } 980 attrsum += NFSX_HYPER; 981 break; 982 case NFSATTRBIT_LINKSUPPORT: 983 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 984 if (compare) { 985 if (!(*retcmpp)) { 986 if (fsp->fs_properties & NFSV3_FSFLINK) { 987 if (*tl == newnfs_false) 988 *retcmpp = NFSERR_NOTSAME; 989 } else { 990 if (*tl == newnfs_true) 991 *retcmpp = NFSERR_NOTSAME; 992 } 993 } 994 } else if (fsp != NULL) { 995 if (*tl == newnfs_true) 996 fsp->fs_properties |= NFSV3_FSFLINK; 997 else 998 fsp->fs_properties &= ~NFSV3_FSFLINK; 999 } 1000 attrsum += NFSX_UNSIGNED; 1001 break; 1002 case NFSATTRBIT_SYMLINKSUPPORT: 1003 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1004 if (compare) { 1005 if (!(*retcmpp)) { 1006 if (fsp->fs_properties & NFSV3_FSFSYMLINK) { 1007 if (*tl == newnfs_false) 1008 *retcmpp = NFSERR_NOTSAME; 1009 } else { 1010 if (*tl == newnfs_true) 1011 *retcmpp = NFSERR_NOTSAME; 1012 } 1013 } 1014 } else if (fsp != NULL) { 1015 if (*tl == newnfs_true) 1016 fsp->fs_properties |= NFSV3_FSFSYMLINK; 1017 else 1018 fsp->fs_properties &= ~NFSV3_FSFSYMLINK; 1019 } 1020 attrsum += NFSX_UNSIGNED; 1021 break; 1022 case NFSATTRBIT_NAMEDATTR: 1023 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1024 if (compare && !(*retcmpp)) { 1025 if (*tl != newnfs_false) 1026 *retcmpp = NFSERR_NOTSAME; 1027 } 1028 attrsum += NFSX_UNSIGNED; 1029 break; 1030 case NFSATTRBIT_FSID: 1031 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1032 thyp = fxdr_hyper(tl); 1033 tl += 2; 1034 thyp2 = fxdr_hyper(tl); 1035 if (compare) { 1036 if (*retcmpp == 0) { 1037 if (thyp != (u_int64_t) 1038 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] || 1039 thyp2 != (u_int64_t) 1040 vfs_statfs(vnode_mount(vp))->f_fsid.val[1]) 1041 *retcmpp = NFSERR_NOTSAME; 1042 } 1043 } else if (nap != NULL) { 1044 nap->na_filesid[0] = thyp; 1045 nap->na_filesid[1] = thyp2; 1046 } 1047 attrsum += (4 * NFSX_UNSIGNED); 1048 break; 1049 case NFSATTRBIT_UNIQUEHANDLES: 1050 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1051 if (compare && !(*retcmpp)) { 1052 if (*tl != newnfs_true) 1053 *retcmpp = NFSERR_NOTSAME; 1054 } 1055 attrsum += NFSX_UNSIGNED; 1056 break; 1057 case NFSATTRBIT_LEASETIME: 1058 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1059 if (compare) { 1060 if (fxdr_unsigned(int, *tl) != nfsrv_lease && 1061 !(*retcmpp)) 1062 *retcmpp = NFSERR_NOTSAME; 1063 } else if (leasep != NULL) { 1064 *leasep = fxdr_unsigned(u_int32_t, *tl); 1065 } 1066 attrsum += NFSX_UNSIGNED; 1067 break; 1068 case NFSATTRBIT_RDATTRERROR: 1069 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1070 if (compare) { 1071 if (!(*retcmpp)) 1072 *retcmpp = NFSERR_INVAL; 1073 } else if (rderrp != NULL) { 1074 *rderrp = fxdr_unsigned(u_int32_t, *tl); 1075 } 1076 attrsum += NFSX_UNSIGNED; 1077 break; 1078 case NFSATTRBIT_ACL: 1079 if (compare) { 1080 if (!(*retcmpp)) { 1081 if (nfsrv_useacl) { 1082 NFSACL_T *naclp; 1083 1084 naclp = acl_alloc(M_WAITOK); 1085 error = nfsrv_dissectacl(nd, naclp, &aceerr, 1086 &cnt, p); 1087 if (error) { 1088 acl_free(naclp); 1089 goto nfsmout; 1090 } 1091 if (aceerr || aclp == NULL || 1092 nfsrv_compareacl(aclp, naclp)) 1093 *retcmpp = NFSERR_NOTSAME; 1094 acl_free(naclp); 1095 } else { 1096 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1097 &cnt, p); 1098 *retcmpp = NFSERR_ATTRNOTSUPP; 1099 } 1100 } 1101 } else { 1102 if (vp != NULL && aclp != NULL) 1103 error = nfsrv_dissectacl(nd, aclp, &aceerr, 1104 &cnt, p); 1105 else 1106 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1107 &cnt, p); 1108 if (error) 1109 goto nfsmout; 1110 } 1111 attrsum += cnt; 1112 break; 1113 case NFSATTRBIT_ACLSUPPORT: 1114 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1115 if (compare && !(*retcmpp)) { 1116 if (nfsrv_useacl) { 1117 if (fxdr_unsigned(u_int32_t, *tl) != 1118 NFSV4ACE_SUPTYPES) 1119 *retcmpp = NFSERR_NOTSAME; 1120 } else { 1121 *retcmpp = NFSERR_ATTRNOTSUPP; 1122 } 1123 } 1124 attrsum += NFSX_UNSIGNED; 1125 break; 1126 case NFSATTRBIT_ARCHIVE: 1127 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1128 if (compare && !(*retcmpp)) 1129 *retcmpp = NFSERR_ATTRNOTSUPP; 1130 attrsum += NFSX_UNSIGNED; 1131 break; 1132 case NFSATTRBIT_CANSETTIME: 1133 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1134 if (compare) { 1135 if (!(*retcmpp)) { 1136 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) { 1137 if (*tl == newnfs_false) 1138 *retcmpp = NFSERR_NOTSAME; 1139 } else { 1140 if (*tl == newnfs_true) 1141 *retcmpp = NFSERR_NOTSAME; 1142 } 1143 } 1144 } else if (fsp != NULL) { 1145 if (*tl == newnfs_true) 1146 fsp->fs_properties |= NFSV3_FSFCANSETTIME; 1147 else 1148 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME; 1149 } 1150 attrsum += NFSX_UNSIGNED; 1151 break; 1152 case NFSATTRBIT_CASEINSENSITIVE: 1153 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1154 if (compare) { 1155 if (!(*retcmpp)) { 1156 if (*tl != newnfs_false) 1157 *retcmpp = NFSERR_NOTSAME; 1158 } 1159 } else if (pc != NULL) { 1160 pc->pc_caseinsensitive = 1161 fxdr_unsigned(u_int32_t, *tl); 1162 } 1163 attrsum += NFSX_UNSIGNED; 1164 break; 1165 case NFSATTRBIT_CASEPRESERVING: 1166 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1167 if (compare) { 1168 if (!(*retcmpp)) { 1169 if (*tl != newnfs_true) 1170 *retcmpp = NFSERR_NOTSAME; 1171 } 1172 } else if (pc != NULL) { 1173 pc->pc_casepreserving = 1174 fxdr_unsigned(u_int32_t, *tl); 1175 } 1176 attrsum += NFSX_UNSIGNED; 1177 break; 1178 case NFSATTRBIT_CHOWNRESTRICTED: 1179 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1180 if (compare) { 1181 if (!(*retcmpp)) { 1182 if (*tl != newnfs_true) 1183 *retcmpp = NFSERR_NOTSAME; 1184 } 1185 } else if (pc != NULL) { 1186 pc->pc_chownrestricted = 1187 fxdr_unsigned(u_int32_t, *tl); 1188 } 1189 attrsum += NFSX_UNSIGNED; 1190 break; 1191 case NFSATTRBIT_FILEHANDLE: 1192 error = nfsm_getfh(nd, &tnfhp); 1193 if (error) 1194 goto nfsmout; 1195 tfhsize = tnfhp->nfh_len; 1196 if (compare) { 1197 if (!(*retcmpp) && 1198 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize, 1199 fhp, fhsize)) 1200 *retcmpp = NFSERR_NOTSAME; 1201 FREE((caddr_t)tnfhp, M_NFSFH); 1202 } else if (nfhpp != NULL) { 1203 *nfhpp = tnfhp; 1204 } else { 1205 FREE((caddr_t)tnfhp, M_NFSFH); 1206 } 1207 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize)); 1208 break; 1209 case NFSATTRBIT_FILEID: 1210 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1211 thyp = fxdr_hyper(tl); 1212 if (compare) { 1213 if (!(*retcmpp)) { 1214 if ((u_int64_t)nap->na_fileid != thyp) 1215 *retcmpp = NFSERR_NOTSAME; 1216 } 1217 } else if (nap != NULL) { 1218 if (*tl++) { 1219 count64fileid++; 1220 if (ratecheck(&last64fileid, &warninterval)) { 1221 printf("NFSv4 fileid > 32bits (%zu occurrences)\n", 1222 count64fileid); 1223 count64fileid = 0; 1224 } 1225 } 1226 nap->na_fileid = thyp; 1227 } 1228 attrsum += NFSX_HYPER; 1229 break; 1230 case NFSATTRBIT_FILESAVAIL: 1231 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1232 if (compare) { 1233 if (!(*retcmpp) && 1234 sfp->sf_afiles != fxdr_hyper(tl)) 1235 *retcmpp = NFSERR_NOTSAME; 1236 } else if (sfp != NULL) { 1237 sfp->sf_afiles = fxdr_hyper(tl); 1238 } 1239 attrsum += NFSX_HYPER; 1240 break; 1241 case NFSATTRBIT_FILESFREE: 1242 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1243 if (compare) { 1244 if (!(*retcmpp) && 1245 sfp->sf_ffiles != fxdr_hyper(tl)) 1246 *retcmpp = NFSERR_NOTSAME; 1247 } else if (sfp != NULL) { 1248 sfp->sf_ffiles = fxdr_hyper(tl); 1249 } 1250 attrsum += NFSX_HYPER; 1251 break; 1252 case NFSATTRBIT_FILESTOTAL: 1253 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1254 if (compare) { 1255 if (!(*retcmpp) && 1256 sfp->sf_tfiles != fxdr_hyper(tl)) 1257 *retcmpp = NFSERR_NOTSAME; 1258 } else if (sfp != NULL) { 1259 sfp->sf_tfiles = fxdr_hyper(tl); 1260 } 1261 attrsum += NFSX_HYPER; 1262 break; 1263 case NFSATTRBIT_FSLOCATIONS: 1264 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m); 1265 if (error) 1266 goto nfsmout; 1267 attrsum += l; 1268 if (compare && !(*retcmpp)) { 1269 refp = nfsv4root_getreferral(vp, NULL, 0); 1270 if (refp != NULL) { 1271 if (cp == NULL || cp2 == NULL || 1272 strcmp(cp, "/") || 1273 strcmp(cp2, refp->nfr_srvlist)) 1274 *retcmpp = NFSERR_NOTSAME; 1275 } else if (m == 0) { 1276 *retcmpp = NFSERR_NOTSAME; 1277 } 1278 } 1279 if (cp != NULL) 1280 free(cp, M_NFSSTRING); 1281 if (cp2 != NULL) 1282 free(cp2, M_NFSSTRING); 1283 break; 1284 case NFSATTRBIT_HIDDEN: 1285 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1286 if (compare && !(*retcmpp)) 1287 *retcmpp = NFSERR_ATTRNOTSUPP; 1288 attrsum += NFSX_UNSIGNED; 1289 break; 1290 case NFSATTRBIT_HOMOGENEOUS: 1291 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1292 if (compare) { 1293 if (!(*retcmpp)) { 1294 if (fsp->fs_properties & 1295 NFSV3_FSFHOMOGENEOUS) { 1296 if (*tl == newnfs_false) 1297 *retcmpp = NFSERR_NOTSAME; 1298 } else { 1299 if (*tl == newnfs_true) 1300 *retcmpp = NFSERR_NOTSAME; 1301 } 1302 } 1303 } else if (fsp != NULL) { 1304 if (*tl == newnfs_true) 1305 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS; 1306 else 1307 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS; 1308 } 1309 attrsum += NFSX_UNSIGNED; 1310 break; 1311 case NFSATTRBIT_MAXFILESIZE: 1312 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1313 tnfsquad.qval = fxdr_hyper(tl); 1314 if (compare) { 1315 if (!(*retcmpp)) { 1316 tquad = NFSRV_MAXFILESIZE; 1317 if (tquad != tnfsquad.qval) 1318 *retcmpp = NFSERR_NOTSAME; 1319 } 1320 } else if (fsp != NULL) { 1321 fsp->fs_maxfilesize = tnfsquad.qval; 1322 } 1323 attrsum += NFSX_HYPER; 1324 break; 1325 case NFSATTRBIT_MAXLINK: 1326 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1327 if (compare) { 1328 if (!(*retcmpp)) { 1329 if (fxdr_unsigned(int, *tl) != LINK_MAX) 1330 *retcmpp = NFSERR_NOTSAME; 1331 } 1332 } else if (pc != NULL) { 1333 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl); 1334 } 1335 attrsum += NFSX_UNSIGNED; 1336 break; 1337 case NFSATTRBIT_MAXNAME: 1338 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1339 if (compare) { 1340 if (!(*retcmpp)) { 1341 if (fsp->fs_maxname != 1342 fxdr_unsigned(u_int32_t, *tl)) 1343 *retcmpp = NFSERR_NOTSAME; 1344 } 1345 } else { 1346 tuint = fxdr_unsigned(u_int32_t, *tl); 1347 /* 1348 * Some Linux NFSv4 servers report this 1349 * as 0 or 4billion, so I'll set it to 1350 * NFS_MAXNAMLEN. If a server actually creates 1351 * a name longer than NFS_MAXNAMLEN, it will 1352 * get an error back. 1353 */ 1354 if (tuint == 0 || tuint > NFS_MAXNAMLEN) 1355 tuint = NFS_MAXNAMLEN; 1356 if (fsp != NULL) 1357 fsp->fs_maxname = tuint; 1358 if (pc != NULL) 1359 pc->pc_namemax = tuint; 1360 } 1361 attrsum += NFSX_UNSIGNED; 1362 break; 1363 case NFSATTRBIT_MAXREAD: 1364 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1365 if (compare) { 1366 if (!(*retcmpp)) { 1367 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t, 1368 *(tl + 1)) || *tl != 0) 1369 *retcmpp = NFSERR_NOTSAME; 1370 } 1371 } else if (fsp != NULL) { 1372 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl); 1373 fsp->fs_rtpref = fsp->fs_rtmax; 1374 fsp->fs_dtpref = fsp->fs_rtpref; 1375 } 1376 attrsum += NFSX_HYPER; 1377 break; 1378 case NFSATTRBIT_MAXWRITE: 1379 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1380 if (compare) { 1381 if (!(*retcmpp)) { 1382 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t, 1383 *(tl + 1)) || *tl != 0) 1384 *retcmpp = NFSERR_NOTSAME; 1385 } 1386 } else if (fsp != NULL) { 1387 fsp->fs_wtmax = fxdr_unsigned(int, *++tl); 1388 fsp->fs_wtpref = fsp->fs_wtmax; 1389 } 1390 attrsum += NFSX_HYPER; 1391 break; 1392 case NFSATTRBIT_MIMETYPE: 1393 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1394 i = fxdr_unsigned(int, *tl); 1395 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); 1396 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 1397 if (error) 1398 goto nfsmout; 1399 if (compare && !(*retcmpp)) 1400 *retcmpp = NFSERR_ATTRNOTSUPP; 1401 break; 1402 case NFSATTRBIT_MODE: 1403 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1404 if (compare) { 1405 if (!(*retcmpp)) { 1406 if (nap->na_mode != nfstov_mode(*tl)) 1407 *retcmpp = NFSERR_NOTSAME; 1408 } 1409 } else if (nap != NULL) { 1410 nap->na_mode = nfstov_mode(*tl); 1411 } 1412 attrsum += NFSX_UNSIGNED; 1413 break; 1414 case NFSATTRBIT_NOTRUNC: 1415 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1416 if (compare) { 1417 if (!(*retcmpp)) { 1418 if (*tl != newnfs_true) 1419 *retcmpp = NFSERR_NOTSAME; 1420 } 1421 } else if (pc != NULL) { 1422 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl); 1423 } 1424 attrsum += NFSX_UNSIGNED; 1425 break; 1426 case NFSATTRBIT_NUMLINKS: 1427 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1428 tuint = fxdr_unsigned(u_int32_t, *tl); 1429 if (compare) { 1430 if (!(*retcmpp)) { 1431 if ((u_int32_t)nap->na_nlink != tuint) 1432 *retcmpp = NFSERR_NOTSAME; 1433 } 1434 } else if (nap != NULL) { 1435 nap->na_nlink = tuint; 1436 } 1437 attrsum += NFSX_UNSIGNED; 1438 break; 1439 case NFSATTRBIT_OWNER: 1440 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1441 j = fxdr_unsigned(int, *tl); 1442 if (j < 0) { 1443 error = NFSERR_BADXDR; 1444 goto nfsmout; 1445 } 1446 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1447 if (j > NFSV4_SMALLSTR) 1448 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1449 else 1450 cp = namestr; 1451 error = nfsrv_mtostr(nd, cp, j); 1452 if (error) { 1453 if (j > NFSV4_SMALLSTR) 1454 free(cp, M_NFSSTRING); 1455 goto nfsmout; 1456 } 1457 if (compare) { 1458 if (!(*retcmpp)) { 1459 if (nfsv4_strtouid(nd, cp, j, &uid, p) || 1460 nap->na_uid != uid) 1461 *retcmpp = NFSERR_NOTSAME; 1462 } 1463 } else if (nap != NULL) { 1464 if (nfsv4_strtouid(nd, cp, j, &uid, p)) 1465 nap->na_uid = nfsrv_defaultuid; 1466 else 1467 nap->na_uid = uid; 1468 } 1469 if (j > NFSV4_SMALLSTR) 1470 free(cp, M_NFSSTRING); 1471 break; 1472 case NFSATTRBIT_OWNERGROUP: 1473 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1474 j = fxdr_unsigned(int, *tl); 1475 if (j < 0) { 1476 error = NFSERR_BADXDR; 1477 goto nfsmout; 1478 } 1479 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1480 if (j > NFSV4_SMALLSTR) 1481 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1482 else 1483 cp = namestr; 1484 error = nfsrv_mtostr(nd, cp, j); 1485 if (error) { 1486 if (j > NFSV4_SMALLSTR) 1487 free(cp, M_NFSSTRING); 1488 goto nfsmout; 1489 } 1490 if (compare) { 1491 if (!(*retcmpp)) { 1492 if (nfsv4_strtogid(nd, cp, j, &gid, p) || 1493 nap->na_gid != gid) 1494 *retcmpp = NFSERR_NOTSAME; 1495 } 1496 } else if (nap != NULL) { 1497 if (nfsv4_strtogid(nd, cp, j, &gid, p)) 1498 nap->na_gid = nfsrv_defaultgid; 1499 else 1500 nap->na_gid = gid; 1501 } 1502 if (j > NFSV4_SMALLSTR) 1503 free(cp, M_NFSSTRING); 1504 break; 1505 case NFSATTRBIT_QUOTAHARD: 1506 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1507 if (sbp != NULL) { 1508 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1509 freenum = sbp->f_bfree; 1510 else 1511 freenum = sbp->f_bavail; 1512#ifdef QUOTA 1513 /* 1514 * ufs_quotactl() insists that the uid argument 1515 * equal p_ruid for non-root quota access, so 1516 * we'll just make sure that's the case. 1517 */ 1518 savuid = p->p_cred->p_ruid; 1519 p->p_cred->p_ruid = cred->cr_uid; 1520 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1521 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1522 freenum = min(dqb.dqb_bhardlimit, freenum); 1523 p->p_cred->p_ruid = savuid; 1524#endif /* QUOTA */ 1525 uquad = (u_int64_t)freenum; 1526 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1527 } 1528 if (compare && !(*retcmpp)) { 1529 if (uquad != fxdr_hyper(tl)) 1530 *retcmpp = NFSERR_NOTSAME; 1531 } 1532 attrsum += NFSX_HYPER; 1533 break; 1534 case NFSATTRBIT_QUOTASOFT: 1535 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1536 if (sbp != NULL) { 1537 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1538 freenum = sbp->f_bfree; 1539 else 1540 freenum = sbp->f_bavail; 1541#ifdef QUOTA 1542 /* 1543 * ufs_quotactl() insists that the uid argument 1544 * equal p_ruid for non-root quota access, so 1545 * we'll just make sure that's the case. 1546 */ 1547 savuid = p->p_cred->p_ruid; 1548 p->p_cred->p_ruid = cred->cr_uid; 1549 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1550 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1551 freenum = min(dqb.dqb_bsoftlimit, freenum); 1552 p->p_cred->p_ruid = savuid; 1553#endif /* QUOTA */ 1554 uquad = (u_int64_t)freenum; 1555 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1556 } 1557 if (compare && !(*retcmpp)) { 1558 if (uquad != fxdr_hyper(tl)) 1559 *retcmpp = NFSERR_NOTSAME; 1560 } 1561 attrsum += NFSX_HYPER; 1562 break; 1563 case NFSATTRBIT_QUOTAUSED: 1564 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1565 if (sbp != NULL) { 1566 freenum = 0; 1567#ifdef QUOTA 1568 /* 1569 * ufs_quotactl() insists that the uid argument 1570 * equal p_ruid for non-root quota access, so 1571 * we'll just make sure that's the case. 1572 */ 1573 savuid = p->p_cred->p_ruid; 1574 p->p_cred->p_ruid = cred->cr_uid; 1575 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1576 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1577 freenum = dqb.dqb_curblocks; 1578 p->p_cred->p_ruid = savuid; 1579#endif /* QUOTA */ 1580 uquad = (u_int64_t)freenum; 1581 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1582 } 1583 if (compare && !(*retcmpp)) { 1584 if (uquad != fxdr_hyper(tl)) 1585 *retcmpp = NFSERR_NOTSAME; 1586 } 1587 attrsum += NFSX_HYPER; 1588 break; 1589 case NFSATTRBIT_RAWDEV: 1590 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA); 1591 j = fxdr_unsigned(int, *tl++); 1592 k = fxdr_unsigned(int, *tl); 1593 if (compare) { 1594 if (!(*retcmpp)) { 1595 if (nap->na_rdev != NFSMAKEDEV(j, k)) 1596 *retcmpp = NFSERR_NOTSAME; 1597 } 1598 } else if (nap != NULL) { 1599 nap->na_rdev = NFSMAKEDEV(j, k); 1600 } 1601 attrsum += NFSX_V4SPECDATA; 1602 break; 1603 case NFSATTRBIT_SPACEAVAIL: 1604 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1605 if (compare) { 1606 if (!(*retcmpp) && 1607 sfp->sf_abytes != fxdr_hyper(tl)) 1608 *retcmpp = NFSERR_NOTSAME; 1609 } else if (sfp != NULL) { 1610 sfp->sf_abytes = fxdr_hyper(tl); 1611 } 1612 attrsum += NFSX_HYPER; 1613 break; 1614 case NFSATTRBIT_SPACEFREE: 1615 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1616 if (compare) { 1617 if (!(*retcmpp) && 1618 sfp->sf_fbytes != fxdr_hyper(tl)) 1619 *retcmpp = NFSERR_NOTSAME; 1620 } else if (sfp != NULL) { 1621 sfp->sf_fbytes = fxdr_hyper(tl); 1622 } 1623 attrsum += NFSX_HYPER; 1624 break; 1625 case NFSATTRBIT_SPACETOTAL: 1626 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1627 if (compare) { 1628 if (!(*retcmpp) && 1629 sfp->sf_tbytes != fxdr_hyper(tl)) 1630 *retcmpp = NFSERR_NOTSAME; 1631 } else if (sfp != NULL) { 1632 sfp->sf_tbytes = fxdr_hyper(tl); 1633 } 1634 attrsum += NFSX_HYPER; 1635 break; 1636 case NFSATTRBIT_SPACEUSED: 1637 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1638 thyp = fxdr_hyper(tl); 1639 if (compare) { 1640 if (!(*retcmpp)) { 1641 if ((u_int64_t)nap->na_bytes != thyp) 1642 *retcmpp = NFSERR_NOTSAME; 1643 } 1644 } else if (nap != NULL) { 1645 nap->na_bytes = thyp; 1646 } 1647 attrsum += NFSX_HYPER; 1648 break; 1649 case NFSATTRBIT_SYSTEM: 1650 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1651 if (compare && !(*retcmpp)) 1652 *retcmpp = NFSERR_ATTRNOTSUPP; 1653 attrsum += NFSX_UNSIGNED; 1654 break; 1655 case NFSATTRBIT_TIMEACCESS: 1656 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1657 fxdr_nfsv4time(tl, &temptime); 1658 if (compare) { 1659 if (!(*retcmpp)) { 1660 if (!NFS_CMPTIME(temptime, nap->na_atime)) 1661 *retcmpp = NFSERR_NOTSAME; 1662 } 1663 } else if (nap != NULL) { 1664 nap->na_atime = temptime; 1665 } 1666 attrsum += NFSX_V4TIME; 1667 break; 1668 case NFSATTRBIT_TIMEACCESSSET: 1669 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1670 attrsum += NFSX_UNSIGNED; 1671 i = fxdr_unsigned(int, *tl); 1672 if (i == NFSV4SATTRTIME_TOCLIENT) { 1673 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1674 attrsum += NFSX_V4TIME; 1675 } 1676 if (compare && !(*retcmpp)) 1677 *retcmpp = NFSERR_INVAL; 1678 break; 1679 case NFSATTRBIT_TIMEBACKUP: 1680 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1681 if (compare && !(*retcmpp)) 1682 *retcmpp = NFSERR_ATTRNOTSUPP; 1683 attrsum += NFSX_V4TIME; 1684 break; 1685 case NFSATTRBIT_TIMECREATE: 1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1687 if (compare && !(*retcmpp)) 1688 *retcmpp = NFSERR_ATTRNOTSUPP; 1689 attrsum += NFSX_V4TIME; 1690 break; 1691 case NFSATTRBIT_TIMEDELTA: 1692 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1693 if (fsp != NULL) { 1694 if (compare) { 1695 if (!(*retcmpp)) { 1696 if ((u_int32_t)fsp->fs_timedelta.tv_sec != 1697 fxdr_unsigned(u_int32_t, *(tl + 1)) || 1698 (u_int32_t)fsp->fs_timedelta.tv_nsec != 1699 (fxdr_unsigned(u_int32_t, *(tl + 2)) % 1700 1000000000) || 1701 *tl != 0) 1702 *retcmpp = NFSERR_NOTSAME; 1703 } 1704 } else { 1705 fxdr_nfsv4time(tl, &fsp->fs_timedelta); 1706 } 1707 } 1708 attrsum += NFSX_V4TIME; 1709 break; 1710 case NFSATTRBIT_TIMEMETADATA: 1711 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1712 fxdr_nfsv4time(tl, &temptime); 1713 if (compare) { 1714 if (!(*retcmpp)) { 1715 if (!NFS_CMPTIME(temptime, nap->na_ctime)) 1716 *retcmpp = NFSERR_NOTSAME; 1717 } 1718 } else if (nap != NULL) { 1719 nap->na_ctime = temptime; 1720 } 1721 attrsum += NFSX_V4TIME; 1722 break; 1723 case NFSATTRBIT_TIMEMODIFY: 1724 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1725 fxdr_nfsv4time(tl, &temptime); 1726 if (compare) { 1727 if (!(*retcmpp)) { 1728 if (!NFS_CMPTIME(temptime, nap->na_mtime)) 1729 *retcmpp = NFSERR_NOTSAME; 1730 } 1731 } else if (nap != NULL) { 1732 nap->na_mtime = temptime; 1733 } 1734 attrsum += NFSX_V4TIME; 1735 break; 1736 case NFSATTRBIT_TIMEMODIFYSET: 1737 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1738 attrsum += NFSX_UNSIGNED; 1739 i = fxdr_unsigned(int, *tl); 1740 if (i == NFSV4SATTRTIME_TOCLIENT) { 1741 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1742 attrsum += NFSX_V4TIME; 1743 } 1744 if (compare && !(*retcmpp)) 1745 *retcmpp = NFSERR_INVAL; 1746 break; 1747 case NFSATTRBIT_MOUNTEDONFILEID: 1748 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1749 thyp = fxdr_hyper(tl); 1750 if (compare) { 1751 if (!(*retcmpp)) { 1752 if (*tl++) { 1753 *retcmpp = NFSERR_NOTSAME; 1754 } else { 1755 if (!vp || !nfsrv_atroot(vp, &fid)) 1756 fid = nap->na_fileid; 1757 if ((u_int64_t)fid != thyp) 1758 *retcmpp = NFSERR_NOTSAME; 1759 } 1760 } 1761 } else if (nap != NULL) { 1762 if (*tl++) { 1763 count64mountfileid++; 1764 if (ratecheck(&last64mountfileid, &warninterval)) { 1765 printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n", 1766 count64mountfileid); 1767 count64mountfileid = 0; 1768 } 1769 } 1770 nap->na_mntonfileno = thyp; 1771 } 1772 attrsum += NFSX_HYPER; 1773 break; 1774 case NFSATTRBIT_SUPPATTREXCLCREAT: 1775 retnotsup = 0; 1776 error = nfsrv_getattrbits(nd, &retattrbits, 1777 &cnt, &retnotsup); 1778 if (error) 1779 goto nfsmout; 1780 if (compare && !(*retcmpp)) { 1781 NFSSETSUPP_ATTRBIT(&checkattrbits, nd); 1782 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits, nd); 1783 NFSCLRBIT_ATTRBIT(&checkattrbits, 1784 NFSATTRBIT_TIMEACCESSSET); 1785 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 1786 || retnotsup) 1787 *retcmpp = NFSERR_NOTSAME; 1788 } 1789 attrsum += cnt; 1790 break; 1791 default: 1792 printf("EEK! nfsv4_loadattr unknown attr=%d\n", 1793 bitpos); 1794 if (compare && !(*retcmpp)) 1795 *retcmpp = NFSERR_ATTRNOTSUPP; 1796 /* 1797 * and get out of the loop, since we can't parse 1798 * the unknown attrbute data. 1799 */ 1800 bitpos = NFSATTRBIT_MAX; 1801 break; 1802 }; 1803 } 1804 1805 /* 1806 * some clients pad the attrlist, so we need to skip over the 1807 * padding. 1808 */ 1809 if (attrsum > attrsize) { 1810 error = NFSERR_BADXDR; 1811 } else { 1812 attrsize = NFSM_RNDUP(attrsize); 1813 if (attrsum < attrsize) 1814 error = nfsm_advance(nd, attrsize - attrsum, -1); 1815 } 1816nfsmout: 1817 NFSEXITCODE2(error, nd); 1818 return (error); 1819} 1820 1821/* 1822 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a 1823 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock. 1824 * The first argument is a pointer to an nfsv4lock structure. 1825 * The second argument is 1 iff a blocking lock is wanted. 1826 * If this argument is 0, the call waits until no thread either wants nor 1827 * holds an exclusive lock. 1828 * It returns 1 if the lock was acquired, 0 otherwise. 1829 * If several processes call this function concurrently wanting the exclusive 1830 * lock, one will get the lock and the rest will return without getting the 1831 * lock. (If the caller must have the lock, it simply calls this function in a 1832 * loop until the function returns 1 to indicate the lock was acquired.) 1833 * Any usecnt must be decremented by calling nfsv4_relref() before 1834 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could 1835 * be called in a loop. 1836 * The isleptp argument is set to indicate if the call slept, iff not NULL 1837 * and the mp argument indicates to check for a forced dismount, iff not 1838 * NULL. 1839 */ 1840APPLESTATIC int 1841nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp, 1842 void *mutex, struct mount *mp) 1843{ 1844 1845 if (isleptp) 1846 *isleptp = 0; 1847 /* 1848 * If a lock is wanted, loop around until the lock is acquired by 1849 * someone and then released. If I want the lock, try to acquire it. 1850 * For a lock to be issued, no lock must be in force and the usecnt 1851 * must be zero. 1852 */ 1853 if (iwantlock) { 1854 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1855 lp->nfslock_usecnt == 0) { 1856 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1857 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1858 return (1); 1859 } 1860 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED; 1861 } 1862 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) { 1863 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1864 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1865 return (0); 1866 } 1867 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1868 if (isleptp) 1869 *isleptp = 1; 1870 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1871 PZERO - 1, "nfsv4lck", NULL); 1872 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1873 lp->nfslock_usecnt == 0) { 1874 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1875 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1876 return (1); 1877 } 1878 } 1879 return (0); 1880} 1881 1882/* 1883 * Release the lock acquired by nfsv4_lock(). 1884 * The second argument is set to 1 to indicate the nfslock_usecnt should be 1885 * incremented, as well. 1886 */ 1887APPLESTATIC void 1888nfsv4_unlock(struct nfsv4lock *lp, int incref) 1889{ 1890 1891 lp->nfslock_lock &= ~NFSV4LOCK_LOCK; 1892 if (incref) 1893 lp->nfslock_usecnt++; 1894 nfsv4_wanted(lp); 1895} 1896 1897/* 1898 * Release a reference cnt. 1899 */ 1900APPLESTATIC void 1901nfsv4_relref(struct nfsv4lock *lp) 1902{ 1903 1904 if (lp->nfslock_usecnt <= 0) 1905 panic("nfsv4root ref cnt"); 1906 lp->nfslock_usecnt--; 1907 if (lp->nfslock_usecnt == 0) 1908 nfsv4_wanted(lp); 1909} 1910 1911/* 1912 * Get a reference cnt. 1913 * This function will wait for any exclusive lock to be released, but will 1914 * not wait for threads that want the exclusive lock. If priority needs 1915 * to be given to threads that need the exclusive lock, a call to nfsv4_lock() 1916 * with the 2nd argument == 0 should be done before calling nfsv4_getref(). 1917 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and 1918 * return without getting a refcnt for that case. 1919 */ 1920APPLESTATIC void 1921nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex, 1922 struct mount *mp) 1923{ 1924 1925 if (isleptp) 1926 *isleptp = 0; 1927 1928 /* 1929 * Wait for a lock held. 1930 */ 1931 while (lp->nfslock_lock & NFSV4LOCK_LOCK) { 1932 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1933 return; 1934 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1935 if (isleptp) 1936 *isleptp = 1; 1937 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1938 PZERO - 1, "nfsv4gr", NULL); 1939 } 1940 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1941 return; 1942 1943 lp->nfslock_usecnt++; 1944} 1945 1946/* 1947 * Get a reference as above, but return failure instead of sleeping if 1948 * an exclusive lock is held. 1949 */ 1950APPLESTATIC int 1951nfsv4_getref_nonblock(struct nfsv4lock *lp) 1952{ 1953 1954 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0) 1955 return (0); 1956 1957 lp->nfslock_usecnt++; 1958 return (1); 1959} 1960 1961/* 1962 * Test for a lock. Return 1 if locked, 0 otherwise. 1963 */ 1964APPLESTATIC int 1965nfsv4_testlock(struct nfsv4lock *lp) 1966{ 1967 1968 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 && 1969 lp->nfslock_usecnt == 0) 1970 return (0); 1971 return (1); 1972} 1973 1974/* 1975 * Wake up anyone sleeping, waiting for this lock. 1976 */ 1977static void 1978nfsv4_wanted(struct nfsv4lock *lp) 1979{ 1980 1981 if (lp->nfslock_lock & NFSV4LOCK_WANTED) { 1982 lp->nfslock_lock &= ~NFSV4LOCK_WANTED; 1983 wakeup((caddr_t)&lp->nfslock_lock); 1984 } 1985} 1986 1987/* 1988 * Copy a string from an mbuf list into a character array. 1989 * Return EBADRPC if there is an mbuf error, 1990 * 0 otherwise. 1991 */ 1992APPLESTATIC int 1993nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) 1994{ 1995 char *cp; 1996 int xfer, len; 1997 mbuf_t mp; 1998 int rem, error = 0; 1999 2000 mp = nd->nd_md; 2001 cp = nd->nd_dpos; 2002 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp; 2003 rem = NFSM_RNDUP(siz) - siz; 2004 while (siz > 0) { 2005 if (len > siz) 2006 xfer = siz; 2007 else 2008 xfer = len; 2009 NFSBCOPY(cp, str, xfer); 2010 str += xfer; 2011 siz -= xfer; 2012 if (siz > 0) { 2013 mp = mbuf_next(mp); 2014 if (mp == NULL) { 2015 error = EBADRPC; 2016 goto out; 2017 } 2018 cp = NFSMTOD(mp, caddr_t); 2019 len = mbuf_len(mp); 2020 } else { 2021 cp += xfer; 2022 len -= xfer; 2023 } 2024 } 2025 *str = '\0'; 2026 nd->nd_dpos = cp; 2027 nd->nd_md = mp; 2028 if (rem > 0) { 2029 if (len < rem) 2030 error = nfsm_advance(nd, rem, len); 2031 else 2032 nd->nd_dpos += rem; 2033 } 2034 2035out: 2036 NFSEXITCODE2(error, nd); 2037 return (error); 2038} 2039 2040/* 2041 * Fill in the attributes as marked by the bitmap (V4). 2042 */ 2043APPLESTATIC int 2044nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, 2045 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror, 2046 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram, 2047 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno) 2048{ 2049 int bitpos, retnum = 0; 2050 u_int32_t *tl; 2051 int siz, prefixnum, error; 2052 u_char *cp, namestr[NFSV4_SMALLSTR]; 2053 nfsattrbit_t attrbits, retbits; 2054 nfsattrbit_t *retbitp = &retbits; 2055 u_int32_t freenum, *retnump; 2056 u_int64_t uquad; 2057 struct statfs fs; 2058 struct nfsfsinfo fsinf; 2059 struct timespec temptime; 2060 NFSACL_T *aclp, *naclp = NULL; 2061#ifdef QUOTA 2062 struct dqblk dqb; 2063 uid_t savuid; 2064#endif 2065 2066 /* 2067 * First, set the bits that can be filled and get fsinfo. 2068 */ 2069 NFSSET_ATTRBIT(retbitp, attrbitp); 2070 /* 2071 * If both p and cred are NULL, it is a client side setattr call. 2072 * If both p and cred are not NULL, it is a server side reply call. 2073 * If p is not NULL and cred is NULL, it is a client side callback 2074 * reply call. 2075 */ 2076 if (p == NULL && cred == NULL) { 2077 NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd); 2078 aclp = saclp; 2079 } else { 2080 NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd); 2081 naclp = acl_alloc(M_WAITOK); 2082 aclp = naclp; 2083 } 2084 nfsvno_getfs(&fsinf, isdgram); 2085#ifndef APPLE 2086 /* 2087 * Get the VFS_STATFS(), since some attributes need them. 2088 */ 2089 if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 2090 error = VFS_STATFS(mp, &fs); 2091 if (error != 0) { 2092 if (reterr) { 2093 nd->nd_repstat = NFSERR_ACCES; 2094 return (0); 2095 } 2096 NFSCLRSTATFS_ATTRBIT(retbitp); 2097 } 2098 } 2099#endif 2100 2101 /* 2102 * And the NFSv4 ACL... 2103 */ 2104 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 2105 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2106 supports_nfsv4acls == 0))) { 2107 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 2108 } 2109 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 2110 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2111 supports_nfsv4acls == 0)) { 2112 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2113 } else if (naclp != NULL) { 2114 if (NFSVOPLOCK(vp, LK_SHARED) == 0) { 2115 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); 2116 if (error == 0) 2117 error = VOP_GETACL(vp, ACL_TYPE_NFS4, 2118 naclp, cred, p); 2119 NFSVOPUNLOCK(vp, 0); 2120 } else 2121 error = NFSERR_PERM; 2122 if (error != 0) { 2123 if (reterr) { 2124 nd->nd_repstat = NFSERR_ACCES; 2125 return (0); 2126 } 2127 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2128 } 2129 } 2130 } 2131 /* 2132 * Put out the attribute bitmap for the ones being filled in 2133 * and get the field for the number of attributes returned. 2134 */ 2135 prefixnum = nfsrv_putattrbit(nd, retbitp); 2136 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 2137 prefixnum += NFSX_UNSIGNED; 2138 2139 /* 2140 * Now, loop around filling in the attributes for each bit set. 2141 */ 2142 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 2143 if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 2144 switch (bitpos) { 2145 case NFSATTRBIT_SUPPORTEDATTRS: 2146 NFSSETSUPP_ATTRBIT(&attrbits, nd); 2147 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 2148 && supports_nfsv4acls == 0)) { 2149 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 2150 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 2151 } 2152 retnum += nfsrv_putattrbit(nd, &attrbits); 2153 break; 2154 case NFSATTRBIT_TYPE: 2155 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2156 *tl = vtonfsv34_type(vap->va_type); 2157 retnum += NFSX_UNSIGNED; 2158 break; 2159 case NFSATTRBIT_FHEXPIRETYPE: 2160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2161 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2162 retnum += NFSX_UNSIGNED; 2163 break; 2164 case NFSATTRBIT_CHANGE: 2165 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2166 txdr_hyper(vap->va_filerev, tl); 2167 retnum += NFSX_HYPER; 2168 break; 2169 case NFSATTRBIT_SIZE: 2170 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2171 txdr_hyper(vap->va_size, tl); 2172 retnum += NFSX_HYPER; 2173 break; 2174 case NFSATTRBIT_LINKSUPPORT: 2175 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2176 if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2177 *tl = newnfs_true; 2178 else 2179 *tl = newnfs_false; 2180 retnum += NFSX_UNSIGNED; 2181 break; 2182 case NFSATTRBIT_SYMLINKSUPPORT: 2183 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2184 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2185 *tl = newnfs_true; 2186 else 2187 *tl = newnfs_false; 2188 retnum += NFSX_UNSIGNED; 2189 break; 2190 case NFSATTRBIT_NAMEDATTR: 2191 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2192 *tl = newnfs_false; 2193 retnum += NFSX_UNSIGNED; 2194 break; 2195 case NFSATTRBIT_FSID: 2196 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2197 *tl++ = 0; 2198 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]); 2199 *tl++ = 0; 2200 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]); 2201 retnum += NFSX_V4FSID; 2202 break; 2203 case NFSATTRBIT_UNIQUEHANDLES: 2204 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2205 *tl = newnfs_true; 2206 retnum += NFSX_UNSIGNED; 2207 break; 2208 case NFSATTRBIT_LEASETIME: 2209 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2210 *tl = txdr_unsigned(nfsrv_lease); 2211 retnum += NFSX_UNSIGNED; 2212 break; 2213 case NFSATTRBIT_RDATTRERROR: 2214 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2215 *tl = txdr_unsigned(rderror); 2216 retnum += NFSX_UNSIGNED; 2217 break; 2218 /* 2219 * Recommended Attributes. (Only the supported ones.) 2220 */ 2221 case NFSATTRBIT_ACL: 2222 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2223 break; 2224 case NFSATTRBIT_ACLSUPPORT: 2225 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2226 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2227 retnum += NFSX_UNSIGNED; 2228 break; 2229 case NFSATTRBIT_CANSETTIME: 2230 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2231 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2232 *tl = newnfs_true; 2233 else 2234 *tl = newnfs_false; 2235 retnum += NFSX_UNSIGNED; 2236 break; 2237 case NFSATTRBIT_CASEINSENSITIVE: 2238 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2239 *tl = newnfs_false; 2240 retnum += NFSX_UNSIGNED; 2241 break; 2242 case NFSATTRBIT_CASEPRESERVING: 2243 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2244 *tl = newnfs_true; 2245 retnum += NFSX_UNSIGNED; 2246 break; 2247 case NFSATTRBIT_CHOWNRESTRICTED: 2248 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2249 *tl = newnfs_true; 2250 retnum += NFSX_UNSIGNED; 2251 break; 2252 case NFSATTRBIT_FILEHANDLE: 2253 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2254 break; 2255 case NFSATTRBIT_FILEID: 2256 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2257 *tl++ = 0; 2258 *tl = txdr_unsigned(vap->va_fileid); 2259 retnum += NFSX_HYPER; 2260 break; 2261 case NFSATTRBIT_FILESAVAIL: 2262 /* 2263 * Check quota and use min(quota, f_ffree). 2264 */ 2265 freenum = fs.f_ffree; 2266#ifdef QUOTA 2267 /* 2268 * ufs_quotactl() insists that the uid argument 2269 * equal p_ruid for non-root quota access, so 2270 * we'll just make sure that's the case. 2271 */ 2272 savuid = p->p_cred->p_ruid; 2273 p->p_cred->p_ruid = cred->cr_uid; 2274 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2275 cred->cr_uid, (caddr_t)&dqb)) 2276 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2277 freenum); 2278 p->p_cred->p_ruid = savuid; 2279#endif /* QUOTA */ 2280 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2281 *tl++ = 0; 2282 *tl = txdr_unsigned(freenum); 2283 retnum += NFSX_HYPER; 2284 break; 2285 case NFSATTRBIT_FILESFREE: 2286 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2287 *tl++ = 0; 2288 *tl = txdr_unsigned(fs.f_ffree); 2289 retnum += NFSX_HYPER; 2290 break; 2291 case NFSATTRBIT_FILESTOTAL: 2292 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2293 *tl++ = 0; 2294 *tl = txdr_unsigned(fs.f_files); 2295 retnum += NFSX_HYPER; 2296 break; 2297 case NFSATTRBIT_FSLOCATIONS: 2298 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2299 *tl++ = 0; 2300 *tl = 0; 2301 retnum += 2 * NFSX_UNSIGNED; 2302 break; 2303 case NFSATTRBIT_HOMOGENEOUS: 2304 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2305 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2306 *tl = newnfs_true; 2307 else 2308 *tl = newnfs_false; 2309 retnum += NFSX_UNSIGNED; 2310 break; 2311 case NFSATTRBIT_MAXFILESIZE: 2312 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2313 uquad = NFSRV_MAXFILESIZE; 2314 txdr_hyper(uquad, tl); 2315 retnum += NFSX_HYPER; 2316 break; 2317 case NFSATTRBIT_MAXLINK: 2318 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2319 *tl = txdr_unsigned(LINK_MAX); 2320 retnum += NFSX_UNSIGNED; 2321 break; 2322 case NFSATTRBIT_MAXNAME: 2323 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2324 *tl = txdr_unsigned(NFS_MAXNAMLEN); 2325 retnum += NFSX_UNSIGNED; 2326 break; 2327 case NFSATTRBIT_MAXREAD: 2328 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2329 *tl++ = 0; 2330 *tl = txdr_unsigned(fsinf.fs_rtmax); 2331 retnum += NFSX_HYPER; 2332 break; 2333 case NFSATTRBIT_MAXWRITE: 2334 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2335 *tl++ = 0; 2336 *tl = txdr_unsigned(fsinf.fs_wtmax); 2337 retnum += NFSX_HYPER; 2338 break; 2339 case NFSATTRBIT_MODE: 2340 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2341 *tl = vtonfsv34_mode(vap->va_mode); 2342 retnum += NFSX_UNSIGNED; 2343 break; 2344 case NFSATTRBIT_NOTRUNC: 2345 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2346 *tl = newnfs_true; 2347 retnum += NFSX_UNSIGNED; 2348 break; 2349 case NFSATTRBIT_NUMLINKS: 2350 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2351 *tl = txdr_unsigned(vap->va_nlink); 2352 retnum += NFSX_UNSIGNED; 2353 break; 2354 case NFSATTRBIT_OWNER: 2355 cp = namestr; 2356 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); 2357 retnum += nfsm_strtom(nd, cp, siz); 2358 if (cp != namestr) 2359 free(cp, M_NFSSTRING); 2360 break; 2361 case NFSATTRBIT_OWNERGROUP: 2362 cp = namestr; 2363 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); 2364 retnum += nfsm_strtom(nd, cp, siz); 2365 if (cp != namestr) 2366 free(cp, M_NFSSTRING); 2367 break; 2368 case NFSATTRBIT_QUOTAHARD: 2369 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2370 freenum = fs.f_bfree; 2371 else 2372 freenum = fs.f_bavail; 2373#ifdef QUOTA 2374 /* 2375 * ufs_quotactl() insists that the uid argument 2376 * equal p_ruid for non-root quota access, so 2377 * we'll just make sure that's the case. 2378 */ 2379 savuid = p->p_cred->p_ruid; 2380 p->p_cred->p_ruid = cred->cr_uid; 2381 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2382 cred->cr_uid, (caddr_t)&dqb)) 2383 freenum = min(dqb.dqb_bhardlimit, freenum); 2384 p->p_cred->p_ruid = savuid; 2385#endif /* QUOTA */ 2386 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2387 uquad = (u_int64_t)freenum; 2388 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2389 txdr_hyper(uquad, tl); 2390 retnum += NFSX_HYPER; 2391 break; 2392 case NFSATTRBIT_QUOTASOFT: 2393 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2394 freenum = fs.f_bfree; 2395 else 2396 freenum = fs.f_bavail; 2397#ifdef QUOTA 2398 /* 2399 * ufs_quotactl() insists that the uid argument 2400 * equal p_ruid for non-root quota access, so 2401 * we'll just make sure that's the case. 2402 */ 2403 savuid = p->p_cred->p_ruid; 2404 p->p_cred->p_ruid = cred->cr_uid; 2405 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2406 cred->cr_uid, (caddr_t)&dqb)) 2407 freenum = min(dqb.dqb_bsoftlimit, freenum); 2408 p->p_cred->p_ruid = savuid; 2409#endif /* QUOTA */ 2410 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2411 uquad = (u_int64_t)freenum; 2412 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2413 txdr_hyper(uquad, tl); 2414 retnum += NFSX_HYPER; 2415 break; 2416 case NFSATTRBIT_QUOTAUSED: 2417 freenum = 0; 2418#ifdef QUOTA 2419 /* 2420 * ufs_quotactl() insists that the uid argument 2421 * equal p_ruid for non-root quota access, so 2422 * we'll just make sure that's the case. 2423 */ 2424 savuid = p->p_cred->p_ruid; 2425 p->p_cred->p_ruid = cred->cr_uid; 2426 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2427 cred->cr_uid, (caddr_t)&dqb)) 2428 freenum = dqb.dqb_curblocks; 2429 p->p_cred->p_ruid = savuid; 2430#endif /* QUOTA */ 2431 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2432 uquad = (u_int64_t)freenum; 2433 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2434 txdr_hyper(uquad, tl); 2435 retnum += NFSX_HYPER; 2436 break; 2437 case NFSATTRBIT_RAWDEV: 2438 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2439 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2440 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2441 retnum += NFSX_V4SPECDATA; 2442 break; 2443 case NFSATTRBIT_SPACEAVAIL: 2444 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2445 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) 2446 uquad = (u_int64_t)fs.f_bfree; 2447 else 2448 uquad = (u_int64_t)fs.f_bavail; 2449 uquad *= fs.f_bsize; 2450 txdr_hyper(uquad, tl); 2451 retnum += NFSX_HYPER; 2452 break; 2453 case NFSATTRBIT_SPACEFREE: 2454 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2455 uquad = (u_int64_t)fs.f_bfree; 2456 uquad *= fs.f_bsize; 2457 txdr_hyper(uquad, tl); 2458 retnum += NFSX_HYPER; 2459 break; 2460 case NFSATTRBIT_SPACETOTAL: 2461 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2462 uquad = (u_int64_t)fs.f_blocks; 2463 uquad *= fs.f_bsize; 2464 txdr_hyper(uquad, tl); 2465 retnum += NFSX_HYPER; 2466 break; 2467 case NFSATTRBIT_SPACEUSED: 2468 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2469 txdr_hyper(vap->va_bytes, tl); 2470 retnum += NFSX_HYPER; 2471 break; 2472 case NFSATTRBIT_TIMEACCESS: 2473 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2474 txdr_nfsv4time(&vap->va_atime, tl); 2475 retnum += NFSX_V4TIME; 2476 break; 2477 case NFSATTRBIT_TIMEACCESSSET: 2478 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2479 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2480 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2481 txdr_nfsv4time(&vap->va_atime, tl); 2482 retnum += NFSX_V4SETTIME; 2483 } else { 2484 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2485 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2486 retnum += NFSX_UNSIGNED; 2487 } 2488 break; 2489 case NFSATTRBIT_TIMEDELTA: 2490 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2491 temptime.tv_sec = 0; 2492 temptime.tv_nsec = 1000000000 / hz; 2493 txdr_nfsv4time(&temptime, tl); 2494 retnum += NFSX_V4TIME; 2495 break; 2496 case NFSATTRBIT_TIMEMETADATA: 2497 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2498 txdr_nfsv4time(&vap->va_ctime, tl); 2499 retnum += NFSX_V4TIME; 2500 break; 2501 case NFSATTRBIT_TIMEMODIFY: 2502 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2503 txdr_nfsv4time(&vap->va_mtime, tl); 2504 retnum += NFSX_V4TIME; 2505 break; 2506 case NFSATTRBIT_TIMEMODIFYSET: 2507 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2508 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2509 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2510 txdr_nfsv4time(&vap->va_mtime, tl); 2511 retnum += NFSX_V4SETTIME; 2512 } else { 2513 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2514 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2515 retnum += NFSX_UNSIGNED; 2516 } 2517 break; 2518 case NFSATTRBIT_MOUNTEDONFILEID: 2519 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2520 if (at_root != 0) 2521 uquad = mounted_on_fileno; 2522 else 2523 uquad = (u_int64_t)vap->va_fileid; 2524 txdr_hyper(uquad, tl); 2525 retnum += NFSX_HYPER; 2526 break; 2527 case NFSATTRBIT_SUPPATTREXCLCREAT: 2528 NFSSETSUPP_ATTRBIT(&attrbits, nd); 2529 NFSCLRNOTSETABLE_ATTRBIT(&attrbits, nd); 2530 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); 2531 retnum += nfsrv_putattrbit(nd, &attrbits); 2532 break; 2533 default: 2534 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2535 }; 2536 } 2537 } 2538 if (naclp != NULL) 2539 acl_free(naclp); 2540 *retnump = txdr_unsigned(retnum); 2541 return (retnum + prefixnum); 2542} 2543 2544/* 2545 * Put the attribute bits onto an mbuf list. 2546 * Return the number of bytes of output generated. 2547 */ 2548APPLESTATIC int 2549nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 2550{ 2551 u_int32_t *tl; 2552 int cnt, i, bytesize; 2553 2554 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 2555 if (attrbitp->bits[cnt - 1]) 2556 break; 2557 bytesize = (cnt + 1) * NFSX_UNSIGNED; 2558 NFSM_BUILD(tl, u_int32_t *, bytesize); 2559 *tl++ = txdr_unsigned(cnt); 2560 for (i = 0; i < cnt; i++) 2561 *tl++ = txdr_unsigned(attrbitp->bits[i]); 2562 return (bytesize); 2563} 2564 2565/* 2566 * Convert a uid to a string. 2567 * If the lookup fails, just output the digits. 2568 * uid - the user id 2569 * cpp - points to a buffer of size NFSV4_SMALLSTR 2570 * (malloc a larger one, as required) 2571 * retlenp - pointer to length to be returned 2572 */ 2573APPLESTATIC void 2574nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2575{ 2576 int i; 2577 struct nfsusrgrp *usrp; 2578 u_char *cp = *cpp; 2579 uid_t tmp; 2580 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2581 struct nfsrv_lughash *hp; 2582 2583 cnt = 0; 2584tryagain: 2585 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) { 2586 /* 2587 * Always map nfsrv_defaultuid to "nobody". 2588 */ 2589 if (uid == nfsrv_defaultuid) { 2590 i = nfsrv_dnsnamelen + 7; 2591 if (i > len) { 2592 if (len > NFSV4_SMALLSTR) 2593 free(cp, M_NFSSTRING); 2594 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2595 *cpp = cp; 2596 len = i; 2597 goto tryagain; 2598 } 2599 *retlenp = i; 2600 NFSBCOPY("nobody@", cp, 7); 2601 cp += 7; 2602 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2603 return; 2604 } 2605 hasampersand = 0; 2606 hp = NFSUSERHASH(uid); 2607 mtx_lock(&hp->mtx); 2608 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2609 if (usrp->lug_uid == uid) { 2610 if (usrp->lug_expiry < NFSD_MONOSEC) 2611 break; 2612 /* 2613 * If the name doesn't already have an '@' 2614 * in it, append @domainname to it. 2615 */ 2616 for (i = 0; i < usrp->lug_namelen; i++) { 2617 if (usrp->lug_name[i] == '@') { 2618 hasampersand = 1; 2619 break; 2620 } 2621 } 2622 if (hasampersand) 2623 i = usrp->lug_namelen; 2624 else 2625 i = usrp->lug_namelen + 2626 nfsrv_dnsnamelen + 1; 2627 if (i > len) { 2628 mtx_unlock(&hp->mtx); 2629 if (len > NFSV4_SMALLSTR) 2630 free(cp, M_NFSSTRING); 2631 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2632 *cpp = cp; 2633 len = i; 2634 goto tryagain; 2635 } 2636 *retlenp = i; 2637 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2638 if (!hasampersand) { 2639 cp += usrp->lug_namelen; 2640 *cp++ = '@'; 2641 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2642 } 2643 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2644 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2645 lug_numhash); 2646 mtx_unlock(&hp->mtx); 2647 return; 2648 } 2649 } 2650 mtx_unlock(&hp->mtx); 2651 cnt++; 2652 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2653 NULL, p); 2654 if (ret == 0 && cnt < 2) 2655 goto tryagain; 2656 } 2657 2658 /* 2659 * No match, just return a string of digits. 2660 */ 2661 tmp = uid; 2662 i = 0; 2663 while (tmp || i == 0) { 2664 tmp /= 10; 2665 i++; 2666 } 2667 len = (i > len) ? len : i; 2668 *retlenp = len; 2669 cp += (len - 1); 2670 tmp = uid; 2671 for (i = 0; i < len; i++) { 2672 *cp-- = '0' + (tmp % 10); 2673 tmp /= 10; 2674 } 2675 return; 2676} 2677 2678/* 2679 * Get a credential for the uid with the server's group list. 2680 * If none is found, just return the credential passed in after 2681 * logging a warning message. 2682 */ 2683struct ucred * 2684nfsrv_getgrpscred(struct ucred *oldcred) 2685{ 2686 struct nfsusrgrp *usrp; 2687 struct ucred *newcred; 2688 int cnt, ret; 2689 uid_t uid; 2690 struct nfsrv_lughash *hp; 2691 2692 cnt = 0; 2693 uid = oldcred->cr_uid; 2694tryagain: 2695 if (nfsrv_dnsnamelen > 0) { 2696 hp = NFSUSERHASH(uid); 2697 mtx_lock(&hp->mtx); 2698 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2699 if (usrp->lug_uid == uid) { 2700 if (usrp->lug_expiry < NFSD_MONOSEC) 2701 break; 2702 if (usrp->lug_cred != NULL) { 2703 newcred = crhold(usrp->lug_cred); 2704 crfree(oldcred); 2705 } else 2706 newcred = oldcred; 2707 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2708 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2709 lug_numhash); 2710 mtx_unlock(&hp->mtx); 2711 return (newcred); 2712 } 2713 } 2714 mtx_unlock(&hp->mtx); 2715 cnt++; 2716 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2717 NULL, curthread); 2718 if (ret == 0 && cnt < 2) 2719 goto tryagain; 2720 } 2721 return (oldcred); 2722} 2723 2724/* 2725 * Convert a string to a uid. 2726 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2727 * return 0. 2728 * If this is called from a client side mount using AUTH_SYS and the 2729 * string is made up entirely of digits, just convert the string to 2730 * a number. 2731 */ 2732APPLESTATIC int 2733nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp, 2734 NFSPROC_T *p) 2735{ 2736 int i; 2737 char *cp, *endstr, *str0; 2738 struct nfsusrgrp *usrp; 2739 int cnt, ret; 2740 int error = 0; 2741 uid_t tuid; 2742 struct nfsrv_lughash *hp, *hp2; 2743 2744 if (len == 0) { 2745 error = NFSERR_BADOWNER; 2746 goto out; 2747 } 2748 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2749 str0 = str; 2750 tuid = (uid_t)strtoul(str0, &endstr, 10); 2751 if ((endstr - str0) == len) { 2752 /* A numeric string. */ 2753 if ((nd->nd_flag & ND_KERBV) == 0 && 2754 ((nd->nd_flag & ND_NFSCL) != 0 || 2755 nfsd_enable_stringtouid != 0)) 2756 *uidp = tuid; 2757 else 2758 error = NFSERR_BADOWNER; 2759 goto out; 2760 } 2761 /* 2762 * Look for an '@'. 2763 */ 2764 cp = strchr(str0, '@'); 2765 if (cp != NULL) 2766 i = (int)(cp++ - str0); 2767 else 2768 i = len; 2769 2770 cnt = 0; 2771tryagain: 2772 if (nfsrv_dnsnamelen > 0) { 2773 /* 2774 * If an '@' is found and the domain name matches, search for 2775 * the name with dns stripped off. 2776 * Mixed case alpahbetics will match for the domain name, but 2777 * all upper case will not. 2778 */ 2779 if (cnt == 0 && i < len && i > 0 && 2780 (len - 1 - i) == nfsrv_dnsnamelen && 2781 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2782 len -= (nfsrv_dnsnamelen + 1); 2783 *(cp - 1) = '\0'; 2784 } 2785 2786 /* 2787 * Check for the special case of "nobody". 2788 */ 2789 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 2790 *uidp = nfsrv_defaultuid; 2791 error = 0; 2792 goto out; 2793 } 2794 2795 hp = NFSUSERNAMEHASH(str, len); 2796 mtx_lock(&hp->mtx); 2797 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 2798 if (usrp->lug_namelen == len && 2799 !NFSBCMP(usrp->lug_name, str, len)) { 2800 if (usrp->lug_expiry < NFSD_MONOSEC) 2801 break; 2802 hp2 = NFSUSERHASH(usrp->lug_uid); 2803 mtx_lock(&hp2->mtx); 2804 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 2805 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 2806 lug_numhash); 2807 *uidp = usrp->lug_uid; 2808 mtx_unlock(&hp2->mtx); 2809 mtx_unlock(&hp->mtx); 2810 error = 0; 2811 goto out; 2812 } 2813 } 2814 mtx_unlock(&hp->mtx); 2815 cnt++; 2816 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 2817 str, p); 2818 if (ret == 0 && cnt < 2) 2819 goto tryagain; 2820 } 2821 error = NFSERR_BADOWNER; 2822 2823out: 2824 NFSEXITCODE(error); 2825 return (error); 2826} 2827 2828/* 2829 * Convert a gid to a string. 2830 * gid - the group id 2831 * cpp - points to a buffer of size NFSV4_SMALLSTR 2832 * (malloc a larger one, as required) 2833 * retlenp - pointer to length to be returned 2834 */ 2835APPLESTATIC void 2836nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2837{ 2838 int i; 2839 struct nfsusrgrp *usrp; 2840 u_char *cp = *cpp; 2841 gid_t tmp; 2842 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2843 struct nfsrv_lughash *hp; 2844 2845 cnt = 0; 2846tryagain: 2847 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) { 2848 /* 2849 * Always map nfsrv_defaultgid to "nogroup". 2850 */ 2851 if (gid == nfsrv_defaultgid) { 2852 i = nfsrv_dnsnamelen + 8; 2853 if (i > len) { 2854 if (len > NFSV4_SMALLSTR) 2855 free(cp, M_NFSSTRING); 2856 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2857 *cpp = cp; 2858 len = i; 2859 goto tryagain; 2860 } 2861 *retlenp = i; 2862 NFSBCOPY("nogroup@", cp, 8); 2863 cp += 8; 2864 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2865 return; 2866 } 2867 hasampersand = 0; 2868 hp = NFSGROUPHASH(gid); 2869 mtx_lock(&hp->mtx); 2870 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2871 if (usrp->lug_gid == gid) { 2872 if (usrp->lug_expiry < NFSD_MONOSEC) 2873 break; 2874 /* 2875 * If the name doesn't already have an '@' 2876 * in it, append @domainname to it. 2877 */ 2878 for (i = 0; i < usrp->lug_namelen; i++) { 2879 if (usrp->lug_name[i] == '@') { 2880 hasampersand = 1; 2881 break; 2882 } 2883 } 2884 if (hasampersand) 2885 i = usrp->lug_namelen; 2886 else 2887 i = usrp->lug_namelen + 2888 nfsrv_dnsnamelen + 1; 2889 if (i > len) { 2890 mtx_unlock(&hp->mtx); 2891 if (len > NFSV4_SMALLSTR) 2892 free(cp, M_NFSSTRING); 2893 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2894 *cpp = cp; 2895 len = i; 2896 goto tryagain; 2897 } 2898 *retlenp = i; 2899 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2900 if (!hasampersand) { 2901 cp += usrp->lug_namelen; 2902 *cp++ = '@'; 2903 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2904 } 2905 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2906 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2907 lug_numhash); 2908 mtx_unlock(&hp->mtx); 2909 return; 2910 } 2911 } 2912 mtx_unlock(&hp->mtx); 2913 cnt++; 2914 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, 2915 NULL, p); 2916 if (ret == 0 && cnt < 2) 2917 goto tryagain; 2918 } 2919 2920 /* 2921 * No match, just return a string of digits. 2922 */ 2923 tmp = gid; 2924 i = 0; 2925 while (tmp || i == 0) { 2926 tmp /= 10; 2927 i++; 2928 } 2929 len = (i > len) ? len : i; 2930 *retlenp = len; 2931 cp += (len - 1); 2932 tmp = gid; 2933 for (i = 0; i < len; i++) { 2934 *cp-- = '0' + (tmp % 10); 2935 tmp /= 10; 2936 } 2937 return; 2938} 2939 2940/* 2941 * Convert a string to a gid. 2942 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2943 * return 0. 2944 * If this is called from a client side mount using AUTH_SYS and the 2945 * string is made up entirely of digits, just convert the string to 2946 * a number. 2947 */ 2948APPLESTATIC int 2949nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp, 2950 NFSPROC_T *p) 2951{ 2952 int i; 2953 char *cp, *endstr, *str0; 2954 struct nfsusrgrp *usrp; 2955 int cnt, ret; 2956 int error = 0; 2957 gid_t tgid; 2958 struct nfsrv_lughash *hp, *hp2; 2959 2960 if (len == 0) { 2961 error = NFSERR_BADOWNER; 2962 goto out; 2963 } 2964 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2965 str0 = str; 2966 tgid = (gid_t)strtoul(str0, &endstr, 10); 2967 if ((endstr - str0) == len) { 2968 /* A numeric string. */ 2969 if ((nd->nd_flag & ND_KERBV) == 0 && 2970 ((nd->nd_flag & ND_NFSCL) != 0 || 2971 nfsd_enable_stringtouid != 0)) 2972 *gidp = tgid; 2973 else 2974 error = NFSERR_BADOWNER; 2975 goto out; 2976 } 2977 /* 2978 * Look for an '@'. 2979 */ 2980 cp = strchr(str0, '@'); 2981 if (cp != NULL) 2982 i = (int)(cp++ - str0); 2983 else 2984 i = len; 2985 2986 cnt = 0; 2987tryagain: 2988 if (nfsrv_dnsnamelen > 0) { 2989 /* 2990 * If an '@' is found and the dns name matches, search for the 2991 * name with the dns stripped off. 2992 */ 2993 if (cnt == 0 && i < len && i > 0 && 2994 (len - 1 - i) == nfsrv_dnsnamelen && 2995 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2996 len -= (nfsrv_dnsnamelen + 1); 2997 *(cp - 1) = '\0'; 2998 } 2999 3000 /* 3001 * Check for the special case of "nogroup". 3002 */ 3003 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 3004 *gidp = nfsrv_defaultgid; 3005 error = 0; 3006 goto out; 3007 } 3008 3009 hp = NFSGROUPNAMEHASH(str, len); 3010 mtx_lock(&hp->mtx); 3011 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 3012 if (usrp->lug_namelen == len && 3013 !NFSBCMP(usrp->lug_name, str, len)) { 3014 if (usrp->lug_expiry < NFSD_MONOSEC) 3015 break; 3016 hp2 = NFSGROUPHASH(usrp->lug_gid); 3017 mtx_lock(&hp2->mtx); 3018 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 3019 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 3020 lug_numhash); 3021 *gidp = usrp->lug_gid; 3022 mtx_unlock(&hp2->mtx); 3023 mtx_unlock(&hp->mtx); 3024 error = 0; 3025 goto out; 3026 } 3027 } 3028 mtx_unlock(&hp->mtx); 3029 cnt++; 3030 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 3031 str, p); 3032 if (ret == 0 && cnt < 2) 3033 goto tryagain; 3034 } 3035 error = NFSERR_BADOWNER; 3036 3037out: 3038 NFSEXITCODE(error); 3039 return (error); 3040} 3041 3042/* 3043 * Cmp len chars, allowing mixed case in the first argument to match lower 3044 * case in the second, but not if the first argument is all upper case. 3045 * Return 0 for a match, 1 otherwise. 3046 */ 3047static int 3048nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 3049{ 3050 int i; 3051 u_char tmp; 3052 int fndlower = 0; 3053 3054 for (i = 0; i < len; i++) { 3055 if (*cp >= 'A' && *cp <= 'Z') { 3056 tmp = *cp++ + ('a' - 'A'); 3057 } else { 3058 tmp = *cp++; 3059 if (tmp >= 'a' && tmp <= 'z') 3060 fndlower = 1; 3061 } 3062 if (tmp != *cp2++) 3063 return (1); 3064 } 3065 if (fndlower) 3066 return (0); 3067 else 3068 return (1); 3069} 3070 3071/* 3072 * Set the port for the nfsuserd. 3073 */ 3074APPLESTATIC int 3075nfsrv_nfsuserdport(struct nfsuserd_args *nargs, NFSPROC_T *p) 3076{ 3077 struct nfssockreq *rp; 3078#ifdef INET 3079 struct sockaddr_in *ad; 3080#endif 3081#ifdef INET6 3082 struct sockaddr_in6 *ad6; 3083 const struct in6_addr in6loopback = IN6ADDR_LOOPBACK_INIT; 3084#endif 3085 int error; 3086 3087 NFSLOCKNAMEID(); 3088 if (nfsrv_nfsuserd) { 3089 NFSUNLOCKNAMEID(); 3090 error = EPERM; 3091 goto out; 3092 } 3093 nfsrv_nfsuserd = 1; 3094 NFSUNLOCKNAMEID(); 3095 /* 3096 * Set up the socket record and connect. 3097 */ 3098 rp = &nfsrv_nfsuserdsock; 3099 rp->nr_client = NULL; 3100 rp->nr_sotype = SOCK_DGRAM; 3101 rp->nr_soproto = IPPROTO_UDP; 3102 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 3103 rp->nr_cred = NULL; 3104 rp->nr_prog = RPCPROG_NFSUSERD; 3105 error = 0; 3106 switch (nargs->nuserd_family) { 3107#ifdef INET 3108 case AF_INET: 3109 rp->nr_nam = malloc(sizeof(struct sockaddr_in), M_SONAME, 3110 M_WAITOK | M_ZERO); 3111 ad = (struct sockaddr_in *)rp->nr_nam; 3112 ad->sin_len = sizeof(struct sockaddr_in); 3113 ad->sin_family = AF_INET; 3114 ad->sin_addr.s_addr = htonl(INADDR_LOOPBACK); 3115 ad->sin_port = nargs->nuserd_port; 3116 break; 3117#endif 3118#ifdef INET6 3119 case AF_INET6: 3120 rp->nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 3121 M_WAITOK | M_ZERO); 3122 ad6 = (struct sockaddr_in6 *)rp->nr_nam; 3123 ad6->sin6_len = sizeof(struct sockaddr_in6); 3124 ad6->sin6_family = AF_INET6; 3125 ad6->sin6_addr = in6loopback; 3126 ad6->sin6_port = nargs->nuserd_port; 3127 break; 3128#endif 3129 default: 3130 error = ENXIO; 3131 } 3132 rp->nr_vers = RPCNFSUSERD_VERS; 3133 if (error == 0) 3134 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 3135 if (error) { 3136 free(rp->nr_nam, M_SONAME); 3137 nfsrv_nfsuserd = 0; 3138 } 3139out: 3140 NFSEXITCODE(error); 3141 return (error); 3142} 3143 3144/* 3145 * Delete the nfsuserd port. 3146 */ 3147APPLESTATIC void 3148nfsrv_nfsuserddelport(void) 3149{ 3150 3151 NFSLOCKNAMEID(); 3152 if (nfsrv_nfsuserd == 0) { 3153 NFSUNLOCKNAMEID(); 3154 return; 3155 } 3156 nfsrv_nfsuserd = 0; 3157 NFSUNLOCKNAMEID(); 3158 newnfs_disconnect(&nfsrv_nfsuserdsock); 3159 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); 3160} 3161 3162/* 3163 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 3164 * name<-->id cache. 3165 * Returns 0 upon success, non-zero otherwise. 3166 */ 3167static int 3168nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) 3169{ 3170 u_int32_t *tl; 3171 struct nfsrv_descript *nd; 3172 int len; 3173 struct nfsrv_descript nfsd; 3174 struct ucred *cred; 3175 int error; 3176 3177 NFSLOCKNAMEID(); 3178 if (nfsrv_nfsuserd == 0) { 3179 NFSUNLOCKNAMEID(); 3180 error = EPERM; 3181 goto out; 3182 } 3183 NFSUNLOCKNAMEID(); 3184 nd = &nfsd; 3185 cred = newnfs_getcred(); 3186 nd->nd_flag = ND_GSSINITREPLY; 3187 nfsrvd_rephead(nd); 3188 3189 nd->nd_procnum = procnum; 3190 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3191 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3192 if (procnum == RPCNFSUSERD_GETUID) 3193 *tl = txdr_unsigned(uid); 3194 else 3195 *tl = txdr_unsigned(gid); 3196 } else { 3197 len = strlen(name); 3198 (void) nfsm_strtom(nd, name, len); 3199 } 3200 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 3201 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL); 3202 NFSFREECRED(cred); 3203 if (!error) { 3204 mbuf_freem(nd->nd_mrep); 3205 error = nd->nd_repstat; 3206 } 3207out: 3208 NFSEXITCODE(error); 3209 return (error); 3210} 3211 3212/* 3213 * This function is called from the nfssvc(2) system call, to update the 3214 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3215 */ 3216APPLESTATIC int 3217nfssvc_idname(struct nfsd_idargs *nidp) 3218{ 3219 struct nfsusrgrp *nusrp, *usrp, *newusrp; 3220 struct nfsrv_lughash *hp_name, *hp_idnum, *thp; 3221 int i, group_locked, groupname_locked, user_locked, username_locked; 3222 int error = 0; 3223 u_char *cp; 3224 gid_t *grps; 3225 struct ucred *cr; 3226 static int onethread = 0; 3227 static time_t lasttime = 0; 3228 3229 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) { 3230 error = EINVAL; 3231 goto out; 3232 } 3233 if (nidp->nid_flag & NFSID_INITIALIZE) { 3234 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); 3235 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 3236 nidp->nid_namelen); 3237 if (error != 0) { 3238 free(cp, M_NFSSTRING); 3239 goto out; 3240 } 3241 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) { 3242 /* 3243 * Free up all the old stuff and reinitialize hash 3244 * lists. All mutexes for both lists must be locked, 3245 * with the user/group name ones before the uid/gid 3246 * ones, to avoid a LOR. 3247 */ 3248 for (i = 0; i < nfsrv_lughashsize; i++) 3249 mtx_lock(&nfsusernamehash[i].mtx); 3250 for (i = 0; i < nfsrv_lughashsize; i++) 3251 mtx_lock(&nfsuserhash[i].mtx); 3252 for (i = 0; i < nfsrv_lughashsize; i++) 3253 TAILQ_FOREACH_SAFE(usrp, 3254 &nfsuserhash[i].lughead, lug_numhash, nusrp) 3255 nfsrv_removeuser(usrp, 1); 3256 for (i = 0; i < nfsrv_lughashsize; i++) 3257 mtx_unlock(&nfsuserhash[i].mtx); 3258 for (i = 0; i < nfsrv_lughashsize; i++) 3259 mtx_unlock(&nfsusernamehash[i].mtx); 3260 for (i = 0; i < nfsrv_lughashsize; i++) 3261 mtx_lock(&nfsgroupnamehash[i].mtx); 3262 for (i = 0; i < nfsrv_lughashsize; i++) 3263 mtx_lock(&nfsgrouphash[i].mtx); 3264 for (i = 0; i < nfsrv_lughashsize; i++) 3265 TAILQ_FOREACH_SAFE(usrp, 3266 &nfsgrouphash[i].lughead, lug_numhash, 3267 nusrp) 3268 nfsrv_removeuser(usrp, 0); 3269 for (i = 0; i < nfsrv_lughashsize; i++) 3270 mtx_unlock(&nfsgrouphash[i].mtx); 3271 for (i = 0; i < nfsrv_lughashsize; i++) 3272 mtx_unlock(&nfsgroupnamehash[i].mtx); 3273 free(nfsrv_dnsname, M_NFSSTRING); 3274 nfsrv_dnsname = NULL; 3275 } 3276 if (nfsuserhash == NULL) { 3277 /* Allocate the hash tables. */ 3278 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) * 3279 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3280 M_ZERO); 3281 for (i = 0; i < nfsrv_lughashsize; i++) 3282 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash", 3283 NULL, MTX_DEF | MTX_DUPOK); 3284 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) * 3285 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3286 M_ZERO); 3287 for (i = 0; i < nfsrv_lughashsize; i++) 3288 mtx_init(&nfsusernamehash[i].mtx, 3289 "nfsusrhash", NULL, MTX_DEF | 3290 MTX_DUPOK); 3291 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) * 3292 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3293 M_ZERO); 3294 for (i = 0; i < nfsrv_lughashsize; i++) 3295 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash", 3296 NULL, MTX_DEF | MTX_DUPOK); 3297 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) * 3298 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3299 M_ZERO); 3300 for (i = 0; i < nfsrv_lughashsize; i++) 3301 mtx_init(&nfsgroupnamehash[i].mtx, 3302 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK); 3303 } 3304 /* (Re)initialize the list heads. */ 3305 for (i = 0; i < nfsrv_lughashsize; i++) 3306 TAILQ_INIT(&nfsuserhash[i].lughead); 3307 for (i = 0; i < nfsrv_lughashsize; i++) 3308 TAILQ_INIT(&nfsusernamehash[i].lughead); 3309 for (i = 0; i < nfsrv_lughashsize; i++) 3310 TAILQ_INIT(&nfsgrouphash[i].lughead); 3311 for (i = 0; i < nfsrv_lughashsize; i++) 3312 TAILQ_INIT(&nfsgroupnamehash[i].lughead); 3313 3314 /* 3315 * Put name in "DNS" string. 3316 */ 3317 nfsrv_dnsname = cp; 3318 nfsrv_defaultuid = nidp->nid_uid; 3319 nfsrv_defaultgid = nidp->nid_gid; 3320 nfsrv_usercnt = 0; 3321 nfsrv_usermax = nidp->nid_usermax; 3322 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen); 3323 goto out; 3324 } 3325 3326 /* 3327 * malloc the new one now, so any potential sleep occurs before 3328 * manipulation of the lists. 3329 */ 3330 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, 3331 M_NFSUSERGROUP, M_WAITOK | M_ZERO); 3332 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 3333 nidp->nid_namelen); 3334 if (error == 0 && nidp->nid_ngroup > 0 && 3335 (nidp->nid_flag & NFSID_ADDUID) != 0) { 3336 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP, 3337 M_WAITOK); 3338 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps, 3339 sizeof(gid_t) * nidp->nid_ngroup); 3340 if (error == 0) { 3341 /* 3342 * Create a credential just like svc_getcred(), 3343 * but using the group list provided. 3344 */ 3345 cr = crget(); 3346 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; 3347 crsetgroups(cr, nidp->nid_ngroup, grps); 3348 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; 3349 cr->cr_prison = &prison0; 3350 prison_hold(cr->cr_prison); 3351#ifdef MAC 3352 mac_cred_associate_nfsd(cr); 3353#endif 3354 newusrp->lug_cred = cr; 3355 } 3356 free(grps, M_TEMP); 3357 } 3358 if (error) { 3359 free(newusrp, M_NFSUSERGROUP); 3360 goto out; 3361 } 3362 newusrp->lug_namelen = nidp->nid_namelen; 3363 3364 /* 3365 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed 3366 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group. 3367 * The flags user_locked, username_locked, group_locked and 3368 * groupname_locked are set to indicate all of those hash lists are 3369 * locked. hp_name != NULL and hp_idnum != NULL indicates that 3370 * the respective one mutex is locked. 3371 */ 3372 user_locked = username_locked = group_locked = groupname_locked = 0; 3373 hp_name = hp_idnum = NULL; 3374 3375 /* 3376 * Delete old entries, as required. 3377 */ 3378 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3379 /* Must lock all username hash lists first, to avoid a LOR. */ 3380 for (i = 0; i < nfsrv_lughashsize; i++) 3381 mtx_lock(&nfsusernamehash[i].mtx); 3382 username_locked = 1; 3383 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3384 mtx_lock(&hp_idnum->mtx); 3385 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3386 nusrp) { 3387 if (usrp->lug_uid == nidp->nid_uid) 3388 nfsrv_removeuser(usrp, 1); 3389 } 3390 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3391 hp_name = NFSUSERNAMEHASH(newusrp->lug_name, 3392 newusrp->lug_namelen); 3393 mtx_lock(&hp_name->mtx); 3394 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3395 nusrp) { 3396 if (usrp->lug_namelen == newusrp->lug_namelen && 3397 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3398 usrp->lug_namelen)) { 3399 thp = NFSUSERHASH(usrp->lug_uid); 3400 mtx_lock(&thp->mtx); 3401 nfsrv_removeuser(usrp, 1); 3402 mtx_unlock(&thp->mtx); 3403 } 3404 } 3405 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3406 mtx_lock(&hp_idnum->mtx); 3407 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3408 /* Must lock all groupname hash lists first, to avoid a LOR. */ 3409 for (i = 0; i < nfsrv_lughashsize; i++) 3410 mtx_lock(&nfsgroupnamehash[i].mtx); 3411 groupname_locked = 1; 3412 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3413 mtx_lock(&hp_idnum->mtx); 3414 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3415 nusrp) { 3416 if (usrp->lug_gid == nidp->nid_gid) 3417 nfsrv_removeuser(usrp, 0); 3418 } 3419 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3420 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name, 3421 newusrp->lug_namelen); 3422 mtx_lock(&hp_name->mtx); 3423 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3424 nusrp) { 3425 if (usrp->lug_namelen == newusrp->lug_namelen && 3426 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3427 usrp->lug_namelen)) { 3428 thp = NFSGROUPHASH(usrp->lug_gid); 3429 mtx_lock(&thp->mtx); 3430 nfsrv_removeuser(usrp, 0); 3431 mtx_unlock(&thp->mtx); 3432 } 3433 } 3434 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3435 mtx_lock(&hp_idnum->mtx); 3436 } 3437 3438 /* 3439 * Now, we can add the new one. 3440 */ 3441 if (nidp->nid_usertimeout) 3442 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3443 else 3444 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3445 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3446 newusrp->lug_uid = nidp->nid_uid; 3447 thp = NFSUSERHASH(newusrp->lug_uid); 3448 mtx_assert(&thp->mtx, MA_OWNED); 3449 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3450 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3451 mtx_assert(&thp->mtx, MA_OWNED); 3452 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3453 atomic_add_int(&nfsrv_usercnt, 1); 3454 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3455 newusrp->lug_gid = nidp->nid_gid; 3456 thp = NFSGROUPHASH(newusrp->lug_gid); 3457 mtx_assert(&thp->mtx, MA_OWNED); 3458 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3459 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3460 mtx_assert(&thp->mtx, MA_OWNED); 3461 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3462 atomic_add_int(&nfsrv_usercnt, 1); 3463 } else { 3464 if (newusrp->lug_cred != NULL) 3465 crfree(newusrp->lug_cred); 3466 free(newusrp, M_NFSUSERGROUP); 3467 } 3468 3469 /* 3470 * Once per second, allow one thread to trim the cache. 3471 */ 3472 if (lasttime < NFSD_MONOSEC && 3473 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) { 3474 /* 3475 * First, unlock the single mutexes, so that all entries 3476 * can be locked and any LOR is avoided. 3477 */ 3478 if (hp_name != NULL) { 3479 mtx_unlock(&hp_name->mtx); 3480 hp_name = NULL; 3481 } 3482 if (hp_idnum != NULL) { 3483 mtx_unlock(&hp_idnum->mtx); 3484 hp_idnum = NULL; 3485 } 3486 3487 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID | 3488 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) { 3489 if (username_locked == 0) { 3490 for (i = 0; i < nfsrv_lughashsize; i++) 3491 mtx_lock(&nfsusernamehash[i].mtx); 3492 username_locked = 1; 3493 } 3494 KASSERT(user_locked == 0, 3495 ("nfssvc_idname: user_locked")); 3496 for (i = 0; i < nfsrv_lughashsize; i++) 3497 mtx_lock(&nfsuserhash[i].mtx); 3498 user_locked = 1; 3499 for (i = 0; i < nfsrv_lughashsize; i++) { 3500 TAILQ_FOREACH_SAFE(usrp, 3501 &nfsuserhash[i].lughead, lug_numhash, 3502 nusrp) 3503 if (usrp->lug_expiry < NFSD_MONOSEC) 3504 nfsrv_removeuser(usrp, 1); 3505 } 3506 for (i = 0; i < nfsrv_lughashsize; i++) { 3507 /* 3508 * Trim the cache using an approximate LRU 3509 * algorithm. This code deletes the least 3510 * recently used entry on each hash list. 3511 */ 3512 if (nfsrv_usercnt <= nfsrv_usermax) 3513 break; 3514 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead); 3515 if (usrp != NULL) 3516 nfsrv_removeuser(usrp, 1); 3517 } 3518 } else { 3519 if (groupname_locked == 0) { 3520 for (i = 0; i < nfsrv_lughashsize; i++) 3521 mtx_lock(&nfsgroupnamehash[i].mtx); 3522 groupname_locked = 1; 3523 } 3524 KASSERT(group_locked == 0, 3525 ("nfssvc_idname: group_locked")); 3526 for (i = 0; i < nfsrv_lughashsize; i++) 3527 mtx_lock(&nfsgrouphash[i].mtx); 3528 group_locked = 1; 3529 for (i = 0; i < nfsrv_lughashsize; i++) { 3530 TAILQ_FOREACH_SAFE(usrp, 3531 &nfsgrouphash[i].lughead, lug_numhash, 3532 nusrp) 3533 if (usrp->lug_expiry < NFSD_MONOSEC) 3534 nfsrv_removeuser(usrp, 0); 3535 } 3536 for (i = 0; i < nfsrv_lughashsize; i++) { 3537 /* 3538 * Trim the cache using an approximate LRU 3539 * algorithm. This code deletes the least 3540 * recently user entry on each hash list. 3541 */ 3542 if (nfsrv_usercnt <= nfsrv_usermax) 3543 break; 3544 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead); 3545 if (usrp != NULL) 3546 nfsrv_removeuser(usrp, 0); 3547 } 3548 } 3549 lasttime = NFSD_MONOSEC; 3550 atomic_store_rel_int(&onethread, 0); 3551 } 3552 3553 /* Now, unlock all locked mutexes. */ 3554 if (hp_idnum != NULL) 3555 mtx_unlock(&hp_idnum->mtx); 3556 if (hp_name != NULL) 3557 mtx_unlock(&hp_name->mtx); 3558 if (user_locked != 0) 3559 for (i = 0; i < nfsrv_lughashsize; i++) 3560 mtx_unlock(&nfsuserhash[i].mtx); 3561 if (username_locked != 0) 3562 for (i = 0; i < nfsrv_lughashsize; i++) 3563 mtx_unlock(&nfsusernamehash[i].mtx); 3564 if (group_locked != 0) 3565 for (i = 0; i < nfsrv_lughashsize; i++) 3566 mtx_unlock(&nfsgrouphash[i].mtx); 3567 if (groupname_locked != 0) 3568 for (i = 0; i < nfsrv_lughashsize; i++) 3569 mtx_unlock(&nfsgroupnamehash[i].mtx); 3570out: 3571 NFSEXITCODE(error); 3572 return (error); 3573} 3574 3575/* 3576 * Remove a user/group name element. 3577 */ 3578static void 3579nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser) 3580{ 3581 struct nfsrv_lughash *hp; 3582 3583 if (isuser != 0) { 3584 hp = NFSUSERHASH(usrp->lug_uid); 3585 mtx_assert(&hp->mtx, MA_OWNED); 3586 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3587 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3588 mtx_assert(&hp->mtx, MA_OWNED); 3589 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 3590 } else { 3591 hp = NFSGROUPHASH(usrp->lug_gid); 3592 mtx_assert(&hp->mtx, MA_OWNED); 3593 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3594 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3595 mtx_assert(&hp->mtx, MA_OWNED); 3596 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 3597 } 3598 atomic_add_int(&nfsrv_usercnt, -1); 3599 if (usrp->lug_cred != NULL) 3600 crfree(usrp->lug_cred); 3601 free(usrp, M_NFSUSERGROUP); 3602} 3603 3604/* 3605 * Free up all the allocations related to the name<-->id cache. 3606 * This function should only be called when the nfsuserd daemon isn't 3607 * running, since it doesn't do any locking. 3608 * This function is meant to be used when the nfscommon module is unloaded. 3609 */ 3610APPLESTATIC void 3611nfsrv_cleanusergroup(void) 3612{ 3613 struct nfsrv_lughash *hp, *hp2; 3614 struct nfsusrgrp *nusrp, *usrp; 3615 int i; 3616 3617 if (nfsuserhash == NULL) 3618 return; 3619 3620 for (i = 0; i < nfsrv_lughashsize; i++) { 3621 hp = &nfsuserhash[i]; 3622 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 3623 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3624 hp2 = NFSUSERNAMEHASH(usrp->lug_name, 3625 usrp->lug_namelen); 3626 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 3627 if (usrp->lug_cred != NULL) 3628 crfree(usrp->lug_cred); 3629 free(usrp, M_NFSUSERGROUP); 3630 } 3631 hp = &nfsgrouphash[i]; 3632 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 3633 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3634 hp2 = NFSGROUPNAMEHASH(usrp->lug_name, 3635 usrp->lug_namelen); 3636 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 3637 if (usrp->lug_cred != NULL) 3638 crfree(usrp->lug_cred); 3639 free(usrp, M_NFSUSERGROUP); 3640 } 3641 mtx_destroy(&nfsuserhash[i].mtx); 3642 mtx_destroy(&nfsusernamehash[i].mtx); 3643 mtx_destroy(&nfsgroupnamehash[i].mtx); 3644 mtx_destroy(&nfsgrouphash[i].mtx); 3645 } 3646 free(nfsuserhash, M_NFSUSERGROUP); 3647 free(nfsusernamehash, M_NFSUSERGROUP); 3648 free(nfsgrouphash, M_NFSUSERGROUP); 3649 free(nfsgroupnamehash, M_NFSUSERGROUP); 3650 free(nfsrv_dnsname, M_NFSSTRING); 3651} 3652 3653/* 3654 * This function scans a byte string and checks for UTF-8 compliance. 3655 * It returns 0 if it conforms and NFSERR_INVAL if not. 3656 */ 3657APPLESTATIC int 3658nfsrv_checkutf8(u_int8_t *cp, int len) 3659{ 3660 u_int32_t val = 0x0; 3661 int cnt = 0, gotd = 0, shift = 0; 3662 u_int8_t byte; 3663 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 3664 int error = 0; 3665 3666 /* 3667 * Here are what the variables are used for: 3668 * val - the calculated value of a multibyte char, used to check 3669 * that it was coded with the correct range 3670 * cnt - the number of 10xxxxxx bytes to follow 3671 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 3672 * shift - lower order bits of range (ie. "val >> shift" should 3673 * not be 0, in other words, dividing by the lower bound 3674 * of the range should get a non-zero value) 3675 * byte - used to calculate cnt 3676 */ 3677 while (len > 0) { 3678 if (cnt > 0) { 3679 /* This handles the 10xxxxxx bytes */ 3680 if ((*cp & 0xc0) != 0x80 || 3681 (gotd && (*cp & 0x20))) { 3682 error = NFSERR_INVAL; 3683 goto out; 3684 } 3685 gotd = 0; 3686 val <<= 6; 3687 val |= (*cp & 0x3f); 3688 cnt--; 3689 if (cnt == 0 && (val >> shift) == 0x0) { 3690 error = NFSERR_INVAL; 3691 goto out; 3692 } 3693 } else if (*cp & 0x80) { 3694 /* first byte of multi byte char */ 3695 byte = *cp; 3696 while ((byte & 0x40) && cnt < 6) { 3697 cnt++; 3698 byte <<= 1; 3699 } 3700 if (cnt == 0 || cnt == 6) { 3701 error = NFSERR_INVAL; 3702 goto out; 3703 } 3704 val = (*cp & (0x3f >> cnt)); 3705 shift = utf8_shift[cnt - 1]; 3706 if (cnt == 2 && val == 0xd) 3707 /* Check for the 0xd800-0xdfff case */ 3708 gotd = 1; 3709 } 3710 cp++; 3711 len--; 3712 } 3713 if (cnt > 0) 3714 error = NFSERR_INVAL; 3715 3716out: 3717 NFSEXITCODE(error); 3718 return (error); 3719} 3720 3721/* 3722 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 3723 * strings, one with the root path in it and the other with the list of 3724 * locations. The list is in the same format as is found in nfr_refs. 3725 * It is a "," separated list of entries, where each of them is of the 3726 * form <server>:<rootpath>. For example 3727 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 3728 * The nilp argument is set to 1 for the special case of a null fs_root 3729 * and an empty server list. 3730 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 3731 * number of xdr bytes parsed in sump. 3732 */ 3733static int 3734nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 3735 int *sump, int *nilp) 3736{ 3737 u_int32_t *tl; 3738 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 3739 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 3740 struct list { 3741 SLIST_ENTRY(list) next; 3742 int len; 3743 u_char host[1]; 3744 } *lsp, *nlsp; 3745 SLIST_HEAD(, list) head; 3746 3747 *fsrootp = NULL; 3748 *srvp = NULL; 3749 *nilp = 0; 3750 3751 /* 3752 * Get the fs_root path and check for the special case of null path 3753 * and 0 length server list. 3754 */ 3755 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3756 len = fxdr_unsigned(int, *tl); 3757 if (len < 0 || len > 10240) { 3758 error = NFSERR_BADXDR; 3759 goto nfsmout; 3760 } 3761 if (len == 0) { 3762 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3763 if (*tl != 0) { 3764 error = NFSERR_BADXDR; 3765 goto nfsmout; 3766 } 3767 *nilp = 1; 3768 *sump = 2 * NFSX_UNSIGNED; 3769 error = 0; 3770 goto nfsmout; 3771 } 3772 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 3773 error = nfsrv_mtostr(nd, cp, len); 3774 if (!error) { 3775 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3776 cnt = fxdr_unsigned(int, *tl); 3777 if (cnt <= 0) 3778 error = NFSERR_BADXDR; 3779 } 3780 if (error) 3781 goto nfsmout; 3782 3783 /* 3784 * Now, loop through the location list and make up the srvlist. 3785 */ 3786 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3787 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 3788 slen = 1024; 3789 siz = 0; 3790 for (i = 0; i < cnt; i++) { 3791 SLIST_INIT(&head); 3792 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3793 nsrv = fxdr_unsigned(int, *tl); 3794 if (nsrv <= 0) { 3795 error = NFSERR_BADXDR; 3796 goto nfsmout; 3797 } 3798 3799 /* 3800 * Handle the first server by putting it in the srvstr. 3801 */ 3802 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3803 len = fxdr_unsigned(int, *tl); 3804 if (len <= 0 || len > 1024) { 3805 error = NFSERR_BADXDR; 3806 goto nfsmout; 3807 } 3808 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 3809 if (cp3 != cp2) { 3810 *cp3++ = ','; 3811 siz++; 3812 } 3813 error = nfsrv_mtostr(nd, cp3, len); 3814 if (error) 3815 goto nfsmout; 3816 cp3 += len; 3817 *cp3++ = ':'; 3818 siz += (len + 1); 3819 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3820 for (j = 1; j < nsrv; j++) { 3821 /* 3822 * Yuck, put them in an slist and process them later. 3823 */ 3824 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3825 len = fxdr_unsigned(int, *tl); 3826 if (len <= 0 || len > 1024) { 3827 error = NFSERR_BADXDR; 3828 goto nfsmout; 3829 } 3830 lsp = (struct list *)malloc(sizeof (struct list) 3831 + len, M_TEMP, M_WAITOK); 3832 error = nfsrv_mtostr(nd, lsp->host, len); 3833 if (error) 3834 goto nfsmout; 3835 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3836 lsp->len = len; 3837 SLIST_INSERT_HEAD(&head, lsp, next); 3838 } 3839 3840 /* 3841 * Finally, we can get the path. 3842 */ 3843 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3844 len = fxdr_unsigned(int, *tl); 3845 if (len <= 0 || len > 1024) { 3846 error = NFSERR_BADXDR; 3847 goto nfsmout; 3848 } 3849 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 3850 error = nfsrv_mtostr(nd, cp3, len); 3851 if (error) 3852 goto nfsmout; 3853 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3854 str = cp3; 3855 stringlen = len; 3856 cp3 += len; 3857 siz += len; 3858 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 3859 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 3860 &cp2, &cp3, &slen); 3861 *cp3++ = ','; 3862 NFSBCOPY(lsp->host, cp3, lsp->len); 3863 cp3 += lsp->len; 3864 *cp3++ = ':'; 3865 NFSBCOPY(str, cp3, stringlen); 3866 cp3 += stringlen; 3867 *cp3 = '\0'; 3868 siz += (lsp->len + stringlen + 2); 3869 free((caddr_t)lsp, M_TEMP); 3870 } 3871 } 3872 *fsrootp = cp; 3873 *srvp = cp2; 3874 *sump = xdrsum; 3875 NFSEXITCODE2(0, nd); 3876 return (0); 3877nfsmout: 3878 if (cp != NULL) 3879 free(cp, M_NFSSTRING); 3880 if (cp2 != NULL) 3881 free(cp2, M_NFSSTRING); 3882 NFSEXITCODE2(error, nd); 3883 return (error); 3884} 3885 3886/* 3887 * Make the malloc'd space large enough. This is a pain, but the xdr 3888 * doesn't set an upper bound on the side, so... 3889 */ 3890static void 3891nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 3892{ 3893 u_char *cp; 3894 int i; 3895 3896 if (siz <= *slenp) 3897 return; 3898 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 3899 NFSBCOPY(*cpp, cp, *slenp); 3900 free(*cpp, M_NFSSTRING); 3901 i = *cpp2 - *cpp; 3902 *cpp = cp; 3903 *cpp2 = cp + i; 3904 *slenp = siz + 1024; 3905} 3906 3907/* 3908 * Initialize the reply header data structures. 3909 */ 3910APPLESTATIC void 3911nfsrvd_rephead(struct nfsrv_descript *nd) 3912{ 3913 mbuf_t mreq; 3914 3915 /* 3916 * If this is a big reply, use a cluster. 3917 */ 3918 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 3919 nfs_bigreply[nd->nd_procnum]) { 3920 NFSMCLGET(mreq, M_WAITOK); 3921 nd->nd_mreq = mreq; 3922 nd->nd_mb = mreq; 3923 } else { 3924 NFSMGET(mreq); 3925 nd->nd_mreq = mreq; 3926 nd->nd_mb = mreq; 3927 } 3928 nd->nd_bpos = NFSMTOD(mreq, caddr_t); 3929 mbuf_setlen(mreq, 0); 3930 3931 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 3932 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 3933} 3934 3935/* 3936 * Lock a socket against others. 3937 * Currently used to serialize connect/disconnect attempts. 3938 */ 3939int 3940newnfs_sndlock(int *flagp) 3941{ 3942 struct timespec ts; 3943 3944 NFSLOCKSOCK(); 3945 while (*flagp & NFSR_SNDLOCK) { 3946 *flagp |= NFSR_WANTSND; 3947 ts.tv_sec = 0; 3948 ts.tv_nsec = 0; 3949 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 3950 PZERO - 1, "nfsndlck", &ts); 3951 } 3952 *flagp |= NFSR_SNDLOCK; 3953 NFSUNLOCKSOCK(); 3954 return (0); 3955} 3956 3957/* 3958 * Unlock the stream socket for others. 3959 */ 3960void 3961newnfs_sndunlock(int *flagp) 3962{ 3963 3964 NFSLOCKSOCK(); 3965 if ((*flagp & NFSR_SNDLOCK) == 0) 3966 panic("nfs sndunlock"); 3967 *flagp &= ~NFSR_SNDLOCK; 3968 if (*flagp & NFSR_WANTSND) { 3969 *flagp &= ~NFSR_WANTSND; 3970 wakeup((caddr_t)flagp); 3971 } 3972 NFSUNLOCKSOCK(); 3973} 3974 3975APPLESTATIC int 3976nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa, 3977 int *isudp) 3978{ 3979 struct sockaddr_in *sad; 3980 struct sockaddr_in6 *sad6; 3981 struct in_addr saddr; 3982 uint32_t portnum, *tl; 3983 int af = 0, i, j, k; 3984 char addr[64], protocol[5], *cp; 3985 int cantparse = 0, error = 0; 3986 uint16_t portv; 3987 3988 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3989 i = fxdr_unsigned(int, *tl); 3990 if (i >= 3 && i <= 4) { 3991 error = nfsrv_mtostr(nd, protocol, i); 3992 if (error) 3993 goto nfsmout; 3994 if (strcmp(protocol, "tcp") == 0) { 3995 af = AF_INET; 3996 *isudp = 0; 3997 } else if (strcmp(protocol, "udp") == 0) { 3998 af = AF_INET; 3999 *isudp = 1; 4000 } else if (strcmp(protocol, "tcp6") == 0) { 4001 af = AF_INET6; 4002 *isudp = 0; 4003 } else if (strcmp(protocol, "udp6") == 0) { 4004 af = AF_INET6; 4005 *isudp = 1; 4006 } else 4007 cantparse = 1; 4008 } else { 4009 cantparse = 1; 4010 if (i > 0) { 4011 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4012 if (error) 4013 goto nfsmout; 4014 } 4015 } 4016 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4017 i = fxdr_unsigned(int, *tl); 4018 if (i < 0) { 4019 error = NFSERR_BADXDR; 4020 goto nfsmout; 4021 } else if (cantparse == 0 && i >= 11 && i < 64) { 4022 /* 4023 * The shortest address is 11chars and the longest is < 64. 4024 */ 4025 error = nfsrv_mtostr(nd, addr, i); 4026 if (error) 4027 goto nfsmout; 4028 4029 /* Find the port# at the end and extract that. */ 4030 i = strlen(addr); 4031 k = 0; 4032 cp = &addr[i - 1]; 4033 /* Count back two '.'s from end to get port# field. */ 4034 for (j = 0; j < i; j++) { 4035 if (*cp == '.') { 4036 k++; 4037 if (k == 2) 4038 break; 4039 } 4040 cp--; 4041 } 4042 if (k == 2) { 4043 /* 4044 * The NFSv4 port# is appended as .N.N, where N is 4045 * a decimal # in the range 0-255, just like an inet4 4046 * address. Cheat and use inet_aton(), which will 4047 * return a Class A address and then shift the high 4048 * order 8bits over to convert it to the port#. 4049 */ 4050 *cp++ = '\0'; 4051 if (inet_aton(cp, &saddr) == 1) { 4052 portnum = ntohl(saddr.s_addr); 4053 portv = (uint16_t)((portnum >> 16) | 4054 (portnum & 0xff)); 4055 } else 4056 cantparse = 1; 4057 } else 4058 cantparse = 1; 4059 if (cantparse == 0) { 4060 if (af == AF_INET) { 4061 sad = (struct sockaddr_in *)sa; 4062 if (inet_pton(af, addr, &sad->sin_addr) == 1) { 4063 sad->sin_len = sizeof(*sad); 4064 sad->sin_family = AF_INET; 4065 sad->sin_port = htons(portv); 4066 return (0); 4067 } 4068 } else { 4069 sad6 = (struct sockaddr_in6 *)sa; 4070 if (inet_pton(af, addr, &sad6->sin6_addr) 4071 == 1) { 4072 sad6->sin6_len = sizeof(*sad6); 4073 sad6->sin6_family = AF_INET6; 4074 sad6->sin6_port = htons(portv); 4075 return (0); 4076 } 4077 } 4078 } 4079 } else { 4080 if (i > 0) { 4081 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4082 if (error) 4083 goto nfsmout; 4084 } 4085 } 4086 error = EPERM; 4087nfsmout: 4088 return (error); 4089} 4090 4091/* 4092 * Handle an NFSv4.1 Sequence request for the session. 4093 * If reply != NULL, use it to return the cached reply, as required. 4094 * The client gets a cached reply via this call for callbacks, however the 4095 * server gets a cached reply via the nfsv4_seqsess_cachereply() call. 4096 */ 4097int 4098nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 4099 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 4100{ 4101 int error; 4102 4103 error = 0; 4104 if (reply != NULL) 4105 *reply = NULL; 4106 if (slotid > maxslot) 4107 return (NFSERR_BADSLOT); 4108 if (seqid == slots[slotid].nfssl_seq) { 4109 /* A retry. */ 4110 if (slots[slotid].nfssl_inprog != 0) 4111 error = NFSERR_DELAY; 4112 else if (slots[slotid].nfssl_reply != NULL) { 4113 if (reply != NULL) { 4114 *reply = slots[slotid].nfssl_reply; 4115 slots[slotid].nfssl_reply = NULL; 4116 } 4117 slots[slotid].nfssl_inprog = 1; 4118 error = NFSERR_REPLYFROMCACHE; 4119 } else 4120 /* No reply cached, so just do it. */ 4121 slots[slotid].nfssl_inprog = 1; 4122 } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 4123 if (slots[slotid].nfssl_reply != NULL) 4124 m_freem(slots[slotid].nfssl_reply); 4125 slots[slotid].nfssl_reply = NULL; 4126 slots[slotid].nfssl_inprog = 1; 4127 slots[slotid].nfssl_seq++; 4128 } else 4129 error = NFSERR_SEQMISORDERED; 4130 return (error); 4131} 4132 4133/* 4134 * Cache this reply for the slot. 4135 * Use the "rep" argument to return the cached reply if repstat is set to 4136 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value. 4137 */ 4138void 4139nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat, 4140 struct mbuf **rep) 4141{ 4142 4143 if (repstat == NFSERR_REPLYFROMCACHE) { 4144 *rep = slots[slotid].nfssl_reply; 4145 slots[slotid].nfssl_reply = NULL; 4146 } else { 4147 if (slots[slotid].nfssl_reply != NULL) 4148 m_freem(slots[slotid].nfssl_reply); 4149 slots[slotid].nfssl_reply = *rep; 4150 } 4151 slots[slotid].nfssl_inprog = 0; 4152} 4153 4154/* 4155 * Generate the xdr for an NFSv4.1 Sequence Operation. 4156 */ 4157APPLESTATIC void 4158nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, 4159 struct nfsclsession *sep, int dont_replycache) 4160{ 4161 uint32_t *tl, slotseq = 0; 4162 int error, maxslot, slotpos; 4163 uint8_t sessionid[NFSX_V4SESSIONID]; 4164 4165 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq, 4166 sessionid); 4167 4168 /* Build the Sequence arguments. */ 4169 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 4170 nd->nd_sequence = tl; 4171 bcopy(sessionid, tl, NFSX_V4SESSIONID); 4172 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4173 nd->nd_slotseq = tl; 4174 if (error == 0) { 4175 *tl++ = txdr_unsigned(slotseq); 4176 *tl++ = txdr_unsigned(slotpos); 4177 *tl++ = txdr_unsigned(maxslot); 4178 if (dont_replycache == 0) 4179 *tl = newnfs_true; 4180 else 4181 *tl = newnfs_false; 4182 } else { 4183 /* 4184 * There are two errors and the rest of the session can 4185 * just be zeros. 4186 * NFSERR_BADSESSION: This bad session should just generate 4187 * the same error again when the RPC is retried. 4188 * ESTALE: A forced dismount is in progress and will cause the 4189 * RPC to fail later. 4190 */ 4191 *tl++ = 0; 4192 *tl++ = 0; 4193 *tl++ = 0; 4194 *tl = 0; 4195 } 4196 nd->nd_flag |= ND_HASSEQUENCE; 4197} 4198 4199int 4200nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep, 4201 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid) 4202{ 4203 int i, maxslot, slotpos; 4204 uint64_t bitval; 4205 4206 /* Find an unused slot. */ 4207 slotpos = -1; 4208 maxslot = -1; 4209 mtx_lock(&sep->nfsess_mtx); 4210 do { 4211 if (nmp != NULL && sep->nfsess_defunct != 0) { 4212 /* Just return the bad session. */ 4213 bcopy(sep->nfsess_sessionid, sessionid, 4214 NFSX_V4SESSIONID); 4215 mtx_unlock(&sep->nfsess_mtx); 4216 return (NFSERR_BADSESSION); 4217 } 4218 bitval = 1; 4219 for (i = 0; i < sep->nfsess_foreslots; i++) { 4220 if ((bitval & sep->nfsess_slots) == 0) { 4221 slotpos = i; 4222 sep->nfsess_slots |= bitval; 4223 sep->nfsess_slotseq[i]++; 4224 *slotseqp = sep->nfsess_slotseq[i]; 4225 break; 4226 } 4227 bitval <<= 1; 4228 } 4229 if (slotpos == -1) { 4230 /* 4231 * If a forced dismount is in progress, just return. 4232 * This RPC attempt will fail when it calls 4233 * newnfs_request(). 4234 */ 4235 if (nmp != NULL && 4236 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) 4237 != 0) { 4238 mtx_unlock(&sep->nfsess_mtx); 4239 return (ESTALE); 4240 } 4241 /* Wake up once/sec, to check for a forced dismount. */ 4242 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 4243 PZERO, "nfsclseq", hz); 4244 } 4245 } while (slotpos == -1); 4246 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 4247 bitval = 1; 4248 for (i = 0; i < 64; i++) { 4249 if ((bitval & sep->nfsess_slots) != 0) 4250 maxslot = i; 4251 bitval <<= 1; 4252 } 4253 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 4254 mtx_unlock(&sep->nfsess_mtx); 4255 *slotposp = slotpos; 4256 *maxslotp = maxslot; 4257 return (0); 4258} 4259 4260/* 4261 * Free a session slot. 4262 */ 4263APPLESTATIC void 4264nfsv4_freeslot(struct nfsclsession *sep, int slot) 4265{ 4266 uint64_t bitval; 4267 4268 bitval = 1; 4269 if (slot > 0) 4270 bitval <<= slot; 4271 mtx_lock(&sep->nfsess_mtx); 4272 if ((bitval & sep->nfsess_slots) == 0) 4273 printf("freeing free slot!!\n"); 4274 sep->nfsess_slots &= ~bitval; 4275 wakeup(&sep->nfsess_slots); 4276 mtx_unlock(&sep->nfsess_mtx); 4277} 4278 4279