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$"); 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 <fs/nfs/nfsport.h> 44 45 /* 46 * Data items converted to xdr at startup, since they are constant 47 * This is kinda hokey, but may save a little time doing byte swaps 48 */ 49 u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1; 50 51 /* And other global data */ 52 nfstype nfsv34_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, 53 NFFIFO, NFNON }; 54 enum vtype newnv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; 55 enum vtype nv34tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 56 struct timeval nfsboottime; /* Copy boottime once, so it never changes */ 57 int nfscl_ticks; 58 int nfsrv_useacl = 1; 59 struct nfssockreq nfsrv_nfsuserdsock; 60 int nfsrv_nfsuserd = 0; 61 struct nfsreqhead nfsd_reqq; 62 uid_t nfsrv_defaultuid; 63 gid_t nfsrv_defaultgid; 64 int nfsrv_lease = NFSRV_LEASE; 65 int ncl_mbuf_mlen = MLEN; 66 NFSNAMEIDMUTEX; 67 NFSSOCKMUTEX; 68 69 /* 70 * This array of structures indicates, for V4: 71 * retfh - which of 3 types of calling args are used 72 * 0 - doesn't change cfh or use a sfh 73 * 1 - replaces cfh with a new one (unless it returns an error status) 74 * 2 - uses cfh and sfh 75 * needscfh - if the op wants a cfh and premtime 76 * 0 - doesn't use a cfh 77 * 1 - uses a cfh, but doesn't want pre-op attributes 78 * 2 - uses a cfh and wants pre-op attributes 79 * savereply - indicates a non-idempotent Op 80 * 0 - not non-idempotent 81 * 1 - non-idempotent 82 * Ops that are ordered via seqid# are handled separately from these 83 * non-idempotent Ops. 84 * Define it here, since it is used by both the client and server. 85 */ 86 struct nfsv4_opflag nfsv4_opflag[NFSV4OP_NOPS] = { 87 { 0, 0, 0, 0 }, /* undef */ 88 { 0, 0, 0, 0 }, /* undef */ 89 { 0, 0, 0, 0 }, /* undef */ 90 { 0, 1, 0, 0 }, /* Access */ 91 { 0, 1, 0, 0 }, /* Close */ 92 { 0, 2, 0, 1 }, /* Commit */ 93 { 1, 2, 1, 1 }, /* Create */ 94 { 0, 0, 0, 0 }, /* Delegpurge */ 95 { 0, 1, 0, 0 }, /* Delegreturn */ 96 { 0, 1, 0, 0 }, /* Getattr */ 97 { 0, 1, 0, 0 }, /* GetFH */ 98 { 2, 1, 1, 1 }, /* Link */ 99 { 0, 1, 0, 0 }, /* Lock */ 100 { 0, 1, 0, 0 }, /* LockT */ 101 { 0, 1, 0, 0 }, /* LockU */ 102 { 1, 1, 0, 0 }, /* Lookup */ 103 { 1, 1, 0, 0 }, /* Lookupp */ 104 { 0, 1, 0, 0 }, /* NVerify */ 105 { 1, 1, 0, 1 }, /* Open */ 106 { 1, 1, 0, 0 }, /* OpenAttr */ 107 { 0, 1, 0, 0 }, /* OpenConfirm */ 108 { 0, 1, 0, 0 }, /* OpenDowngrade */ 109 { 1, 0, 0, 0 }, /* PutFH */ 110 { 1, 0, 0, 0 }, /* PutPubFH */ 111 { 1, 0, 0, 0 }, /* PutRootFH */ 112 { 0, 1, 0, 0 }, /* Read */ 113 { 0, 1, 0, 0 }, /* Readdir */ 114 { 0, 1, 0, 0 }, /* ReadLink */ 115 { 0, 2, 1, 1 }, /* Remove */ 116 { 2, 1, 1, 1 }, /* Rename */ 117 { 0, 0, 0, 0 }, /* Renew */ 118 { 0, 0, 0, 0 }, /* RestoreFH */ 119 { 0, 1, 0, 0 }, /* SaveFH */ 120 { 0, 1, 0, 0 }, /* SecInfo */ 121 { 0, 2, 1, 1 }, /* Setattr */ 122 { 0, 0, 0, 0 }, /* SetClientID */ 123 { 0, 0, 0, 0 }, /* SetClientIDConfirm */ 124 { 0, 1, 0, 0 }, /* Verify */ 125 { 0, 2, 1, 1 }, /* Write */ 126 { 0, 0, 0, 0 }, /* ReleaseLockOwner */ 127 }; 128 #endif /* !APPLEKEXT */ 129 130 static int ncl_mbuf_mhlen = MHLEN; 131 static int nfsrv_usercnt = 0; 132 static int nfsrv_dnsnamelen; 133 static u_char *nfsrv_dnsname = NULL; 134 static int nfsrv_usermax = 999999999; 135 static struct nfsuserhashhead nfsuserhash[NFSUSERHASHSIZE]; 136 static struct nfsuserhashhead nfsusernamehash[NFSUSERHASHSIZE]; 137 static struct nfsuserhashhead nfsgrouphash[NFSGROUPHASHSIZE]; 138 static struct nfsuserhashhead nfsgroupnamehash[NFSGROUPHASHSIZE]; 139 static struct nfsuserlruhead nfsuserlruhead; 140 141 /* 142 * This static array indicates whether or not the RPC generates a large 143 * reply. This is used by nfs_reply() to decide whether or not an mbuf 144 * cluster should be allocated. (If a cluster is required by an RPC 145 * marked 0 in this array, the code will still work, just not quite as 146 * efficiently.) 147 */ 148 static int nfs_bigreply[NFS_NPROCS] = { 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 149 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, 150 0, 0, 0, 0, 0 }; 151 152 /* local functions */ 153 static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); 154 static void nfsv4_wanted(struct nfsv4lock *lp); 155 static int nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len); 156 static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, 157 NFSPROC_T *p); 158 static void nfsrv_removeuser(struct nfsusrgrp *usrp); 159 static int nfsrv_getrefstr(struct nfsrv_descript *, u_char **, u_char **, 160 int *, int *); 161 static void nfsrv_refstrbigenough(int, u_char **, u_char **, int *); 162 163 164 #ifndef APPLE 165 /* 166 * copies mbuf chain to the uio scatter/gather list 167 */ 168 int 169 nfsm_mbufuio(struct nfsrv_descript *nd, struct uio *uiop, int siz) 170 { 171 char *mbufcp, *uiocp; 172 int xfer, left, len; 173 mbuf_t mp; 174 long uiosiz, rem; 175 int error = 0; 176 177 mp = nd->nd_md; 178 mbufcp = nd->nd_dpos; 179 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - mbufcp; 180 rem = NFSM_RNDUP(siz) - siz; 181 while (siz > 0) { 182 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 183 return (EBADRPC); 184 left = uiop->uio_iov->iov_len; 185 uiocp = uiop->uio_iov->iov_base; 186 if (left > siz) 187 left = siz; 188 uiosiz = left; 189 while (left > 0) { 190 while (len == 0) { 191 mp = mbuf_next(mp); 192 if (mp == NULL) 193 return (EBADRPC); 194 mbufcp = NFSMTOD(mp, caddr_t); 195 len = mbuf_len(mp); 196 } 197 xfer = (left > len) ? len : left; 198 #ifdef notdef 199 /* Not Yet.. */ 200 if (uiop->uio_iov->iov_op != NULL) 201 (*(uiop->uio_iov->iov_op)) 202 (mbufcp, uiocp, xfer); 203 else 204 #endif 205 if (uiop->uio_segflg == UIO_SYSSPACE) 206 NFSBCOPY(mbufcp, uiocp, xfer); 207 else 208 copyout(mbufcp, CAST_USER_ADDR_T(uiocp), xfer); 209 left -= xfer; 210 len -= xfer; 211 mbufcp += xfer; 212 uiocp += xfer; 213 uiop->uio_offset += xfer; 214 uiop->uio_resid -= xfer; 215 } 216 if (uiop->uio_iov->iov_len <= siz) { 217 uiop->uio_iovcnt--; 218 uiop->uio_iov++; 219 } else { 220 uiop->uio_iov->iov_base = (void *) 221 ((char *)uiop->uio_iov->iov_base + uiosiz); 222 uiop->uio_iov->iov_len -= uiosiz; 223 } 224 siz -= uiosiz; 225 } 226 nd->nd_dpos = mbufcp; 227 nd->nd_md = mp; 228 if (rem > 0) { 229 if (len < rem) 230 error = nfsm_advance(nd, rem, len); 231 else 232 nd->nd_dpos += rem; 233 } 234 return (error); 235 } 236 #endif /* !APPLE */ 237 238 /* 239 * Help break down an mbuf chain by setting the first siz bytes contiguous 240 * pointed to by returned val. 241 * This is used by the macro NFSM_DISSECT for tough 242 * cases. 243 */ 244 APPLESTATIC void * 245 nfsm_dissct(struct nfsrv_descript *nd, int siz) 246 { 247 mbuf_t mp2; 248 int siz2, xfer; 249 caddr_t p; 250 int left; 251 caddr_t retp; 252 253 retp = NULL; 254 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - nd->nd_dpos; 255 while (left == 0) { 256 nd->nd_md = mbuf_next(nd->nd_md); 257 if (nd->nd_md == NULL) 258 return (retp); 259 left = mbuf_len(nd->nd_md); 260 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); 261 } 262 if (left >= siz) { 263 retp = nd->nd_dpos; 264 nd->nd_dpos += siz; 265 } else if (mbuf_next(nd->nd_md) == NULL) { 266 return (retp); 267 } else if (siz > ncl_mbuf_mhlen) { 268 panic("nfs S too big"); 269 } else { 270 NFSMGET(mp2); 271 mbuf_setnext(mp2, mbuf_next(nd->nd_md)); 272 mbuf_setnext(nd->nd_md, mp2); 273 mbuf_setlen(nd->nd_md, mbuf_len(nd->nd_md) - left); 274 nd->nd_md = mp2; 275 retp = p = NFSMTOD(mp2, caddr_t); 276 NFSBCOPY(nd->nd_dpos, p, left); /* Copy what was left */ 277 siz2 = siz - left; 278 p += left; 279 mp2 = mbuf_next(mp2); 280 /* Loop around copying up the siz2 bytes */ 281 while (siz2 > 0) { 282 if (mp2 == NULL) 283 return (NULL); 284 xfer = (siz2 > mbuf_len(mp2)) ? mbuf_len(mp2) : siz2; 285 if (xfer > 0) { 286 NFSBCOPY(NFSMTOD(mp2, caddr_t), p, xfer); 287 NFSM_DATAP(mp2, xfer); 288 mbuf_setlen(mp2, mbuf_len(mp2) - xfer); 289 p += xfer; 290 siz2 -= xfer; 291 } 292 if (siz2 > 0) 293 mp2 = mbuf_next(mp2); 294 } 295 mbuf_setlen(nd->nd_md, siz); 296 nd->nd_md = mp2; 297 nd->nd_dpos = NFSMTOD(mp2, caddr_t); 298 } 299 return (retp); 300 } 301 302 /* 303 * Advance the position in the mbuf chain. 304 * If offs == 0, this is a no-op, but it is simpler to just return from 305 * here than check for offs > 0 for all calls to nfsm_advance. 306 * If left == -1, it should be calculated here. 307 */ 308 APPLESTATIC int 309 nfsm_advance(struct nfsrv_descript *nd, int offs, int left) 310 { 311 312 if (offs == 0) 313 return (0); 314 /* 315 * A negative offs should be considered a serious problem. 316 */ 317 if (offs < 0) 318 panic("nfsrv_advance"); 319 320 /* 321 * If left == -1, calculate it here. 322 */ 323 if (left == -1) 324 left = NFSMTOD(nd->nd_md, caddr_t) + mbuf_len(nd->nd_md) - 325 nd->nd_dpos; 326 327 /* 328 * Loop around, advancing over the mbuf data. 329 */ 330 while (offs > left) { 331 offs -= left; 332 nd->nd_md = mbuf_next(nd->nd_md); 333 if (nd->nd_md == NULL) 334 return (EBADRPC); 335 left = mbuf_len(nd->nd_md); 336 nd->nd_dpos = NFSMTOD(nd->nd_md, caddr_t); 337 } 338 nd->nd_dpos += offs; 339 return (0); 340 } 341 342 /* 343 * Copy a string into mbuf(s). 344 * Return the number of bytes output, including XDR overheads. 345 */ 346 APPLESTATIC int 347 nfsm_strtom(struct nfsrv_descript *nd, const char *cp, int siz) 348 { 349 mbuf_t m2; 350 int xfer, left; 351 mbuf_t m1; 352 int rem, bytesize; 353 u_int32_t *tl; 354 char *cp2; 355 356 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 357 *tl = txdr_unsigned(siz); 358 rem = NFSM_RNDUP(siz) - siz; 359 bytesize = NFSX_UNSIGNED + siz + rem; 360 m2 = nd->nd_mb; 361 cp2 = nd->nd_bpos; 362 left = M_TRAILINGSPACE(m2); 363 364 /* 365 * Loop around copying the string to mbuf(s). 366 */ 367 while (siz > 0) { 368 if (left == 0) { 369 if (siz > ncl_mbuf_mlen) 370 NFSMCLGET(m1, M_WAIT); 371 else 372 NFSMGET(m1); 373 mbuf_setlen(m1, 0); 374 mbuf_setnext(m2, m1); 375 m2 = m1; 376 cp2 = NFSMTOD(m2, caddr_t); 377 left = M_TRAILINGSPACE(m2); 378 } 379 if (left >= siz) 380 xfer = siz; 381 else 382 xfer = left; 383 NFSBCOPY(cp, cp2, xfer); 384 cp += xfer; 385 mbuf_setlen(m2, mbuf_len(m2) + xfer); 386 siz -= xfer; 387 left -= xfer; 388 if (siz == 0 && rem) { 389 if (left < rem) 390 panic("nfsm_strtom"); 391 NFSBZERO(cp2 + xfer, rem); 392 mbuf_setlen(m2, mbuf_len(m2) + rem); 393 } 394 } 395 nd->nd_mb = m2; 396 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); 397 return (bytesize); 398 } 399 400 /* 401 * Called once to initialize data structures... 402 */ 403 APPLESTATIC void 404 newnfs_init(void) 405 { 406 static int nfs_inited = 0; 407 408 if (nfs_inited) 409 return; 410 nfs_inited = 1; 411 412 newnfs_true = txdr_unsigned(TRUE); 413 newnfs_false = txdr_unsigned(FALSE); 414 newnfs_xdrneg1 = txdr_unsigned(-1); 415 nfscl_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 416 if (nfscl_ticks < 1) 417 nfscl_ticks = 1; 418 NFSSETBOOTTIME(nfsboottime); 419 420 /* 421 * Initialize reply list and start timer 422 */ 423 TAILQ_INIT(&nfsd_reqq); 424 NFS_TIMERINIT; 425 } 426 427 /* 428 * Put a file handle in an mbuf list. 429 * If the size argument == 0, just use the default size. 430 * set_true == 1 if there should be an newnfs_true prepended on the file handle. 431 * Return the number of bytes output, including XDR overhead. 432 */ 433 APPLESTATIC int 434 nfsm_fhtom(struct nfsrv_descript *nd, u_int8_t *fhp, int size, int set_true) 435 { 436 u_int32_t *tl; 437 u_int8_t *cp; 438 int fullsiz, rem, bytesize = 0; 439 440 if (size == 0) 441 size = NFSX_MYFH; 442 switch (nd->nd_flag & (ND_NFSV2 | ND_NFSV3 | ND_NFSV4)) { 443 case ND_NFSV2: 444 if (size > NFSX_V2FH) 445 panic("fh size > NFSX_V2FH for NFSv2"); 446 NFSM_BUILD(cp, u_int8_t *, NFSX_V2FH); 447 NFSBCOPY(fhp, cp, size); 448 if (size < NFSX_V2FH) 449 NFSBZERO(cp + size, NFSX_V2FH - size); 450 bytesize = NFSX_V2FH; 451 break; 452 case ND_NFSV3: 453 case ND_NFSV4: 454 fullsiz = NFSM_RNDUP(size); 455 rem = fullsiz - size; 456 if (set_true) { 457 bytesize = 2 * NFSX_UNSIGNED + fullsiz; 458 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 459 *tl = newnfs_true; 460 } else { 461 bytesize = NFSX_UNSIGNED + fullsiz; 462 } 463 (void) nfsm_strtom(nd, fhp, size); 464 break; 465 }; 466 return (bytesize); 467 } 468 469 /* 470 * This function compares two net addresses by family and returns TRUE 471 * if they are the same host. 472 * If there is any doubt, return FALSE. 473 * The AF_INET family is handled as a special case so that address mbufs 474 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 475 */ 476 APPLESTATIC int 477 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam) 478 { 479 struct sockaddr_in *inetaddr; 480 481 switch (family) { 482 case AF_INET: 483 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *); 484 if (inetaddr->sin_family == AF_INET && 485 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr) 486 return (1); 487 break; 488 #ifdef INET6 489 case AF_INET6: 490 { 491 struct sockaddr_in6 *inetaddr6; 492 493 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *); 494 /* XXX - should test sin6_scope_id ? */ 495 if (inetaddr6->sin6_family == AF_INET6 && 496 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr, 497 &haddr->had_inet6)) 498 return (1); 499 } 500 break; 501 #endif 502 }; 503 return (0); 504 } 505 506 /* 507 * Similar to the above, but takes to NFSSOCKADDR_T args. 508 */ 509 APPLESTATIC int 510 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2) 511 { 512 struct sockaddr_in *addr1, *addr2; 513 struct sockaddr *inaddr; 514 515 inaddr = NFSSOCKADDR(nam1, struct sockaddr *); 516 switch (inaddr->sa_family) { 517 case AF_INET: 518 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *); 519 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *); 520 if (addr2->sin_family == AF_INET && 521 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) 522 return (1); 523 break; 524 #ifdef INET6 525 case AF_INET6: 526 { 527 struct sockaddr_in6 *inet6addr1, *inet6addr2; 528 529 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *); 530 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *); 531 /* XXX - should test sin6_scope_id ? */ 532 if (inet6addr2->sin6_family == AF_INET6 && 533 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 534 &inet6addr2->sin6_addr)) 535 return (1); 536 } 537 break; 538 #endif 539 }; 540 return (0); 541 } 542 543 544 /* 545 * Trim the stuff already dissected off the mbuf list. 546 */ 547 APPLESTATIC void 548 newnfs_trimleading(nd) 549 struct nfsrv_descript *nd; 550 { 551 mbuf_t m, n; 552 int offs; 553 554 /* 555 * First, free up leading mbufs. 556 */ 557 if (nd->nd_mrep != nd->nd_md) { 558 m = nd->nd_mrep; 559 while (mbuf_next(m) != nd->nd_md) { 560 if (mbuf_next(m) == NULL) 561 panic("nfsm trim leading"); 562 m = mbuf_next(m); 563 } 564 mbuf_setnext(m, NULL); 565 mbuf_freem(nd->nd_mrep); 566 } 567 m = nd->nd_md; 568 569 /* 570 * Now, adjust this mbuf, based on nd_dpos. 571 */ 572 offs = nd->nd_dpos - NFSMTOD(m, caddr_t); 573 if (offs == mbuf_len(m)) { 574 n = m; 575 m = mbuf_next(m); 576 if (m == NULL) 577 panic("nfsm trim leading2"); 578 mbuf_setnext(n, NULL); 579 mbuf_freem(n); 580 } else if (offs > 0) { 581 mbuf_setlen(m, mbuf_len(m) - offs); 582 NFSM_DATAP(m, offs); 583 } else if (offs < 0) 584 panic("nfsm trimleading offs"); 585 nd->nd_mrep = m; 586 nd->nd_md = m; 587 nd->nd_dpos = NFSMTOD(m, caddr_t); 588 } 589 590 /* 591 * Trim trailing data off the mbuf list being built. 592 */ 593 APPLESTATIC void 594 newnfs_trimtrailing(nd, mb, bpos) 595 struct nfsrv_descript *nd; 596 mbuf_t mb; 597 caddr_t bpos; 598 { 599 600 if (mbuf_next(mb)) { 601 mbuf_freem(mbuf_next(mb)); 602 mbuf_setnext(mb, NULL); 603 } 604 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t)); 605 nd->nd_mb = mb; 606 nd->nd_bpos = bpos; 607 } 608 609 /* 610 * Dissect a file handle on the client. 611 */ 612 APPLESTATIC int 613 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp) 614 { 615 u_int32_t *tl; 616 struct nfsfh *nfhp; 617 int error, len; 618 619 *nfhpp = NULL; 620 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 621 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 622 if ((len = fxdr_unsigned(int, *tl)) <= 0 || 623 len > NFSX_FHMAX) 624 return (EBADRPC); 625 } else 626 len = NFSX_V2FH; 627 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len, 628 M_NFSFH, M_WAITOK); 629 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len); 630 if (error) { 631 FREE((caddr_t)nfhp, M_NFSFH); 632 return (error); 633 } 634 nfhp->nfh_len = len; 635 *nfhpp = nfhp; 636 nfsmout: 637 return (error); 638 } 639 640 /* 641 * Break down the nfsv4 acl. 642 * If the aclp == NULL or won't fit in an acl, just discard the acl info. 643 */ 644 APPLESTATIC int 645 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp, 646 int *aclsizep, __unused NFSPROC_T *p) 647 { 648 u_int32_t *tl; 649 int i, aclsize; 650 int acecnt, error = 0, aceerr = 0, acesize; 651 652 *aclerrp = 0; 653 if (aclp) 654 aclp->acl_cnt = 0; 655 /* 656 * Parse out the ace entries and expect them to conform to 657 * what can be supported by R/W/X bits. 658 */ 659 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 660 aclsize = NFSX_UNSIGNED; 661 acecnt = fxdr_unsigned(int, *tl); 662 if (acecnt > ACL_MAX_ENTRIES) 663 aceerr = 1; 664 if (nfsrv_useacl == 0) 665 aceerr = 1; 666 for (i = 0; i < acecnt; i++) { 667 if (aclp && !aceerr) 668 error = nfsrv_dissectace(nd, &aclp->acl_entry[i], 669 &aceerr, &acesize, p); 670 else 671 error = nfsrv_skipace(nd, &acesize); 672 if (error) 673 return (error); 674 aclsize += acesize; 675 } 676 if (aclp && !aceerr) 677 aclp->acl_cnt = acecnt; 678 if (aceerr) 679 *aclerrp = aceerr; 680 if (aclsizep) 681 *aclsizep = aclsize; 682 nfsmout: 683 return (error); 684 } 685 686 /* 687 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it. 688 */ 689 static int 690 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep) 691 { 692 u_int32_t *tl; 693 int error, len = 0; 694 695 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 696 len = fxdr_unsigned(int, *(tl + 3)); 697 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 698 nfsmout: 699 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); 700 return (error); 701 } 702 703 /* 704 * Get attribute bits from an mbuf list. 705 * Returns EBADRPC for a parsing error, 0 otherwise. 706 * If the clearinvalid flag is set, clear the bits not supported. 707 */ 708 APPLESTATIC int 709 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp, 710 int *retnotsupp) 711 { 712 u_int32_t *tl; 713 int cnt, i, outcnt; 714 int error = 0; 715 716 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 717 cnt = fxdr_unsigned(int, *tl); 718 if (cnt < 0) 719 return (NFSERR_BADXDR); 720 if (cnt > NFSATTRBIT_MAXWORDS) { 721 outcnt = NFSATTRBIT_MAXWORDS; 722 if (retnotsupp) 723 *retnotsupp = NFSERR_ATTRNOTSUPP; 724 } else { 725 outcnt = cnt; 726 } 727 NFSZERO_ATTRBIT(attrbitp); 728 if (outcnt > 0) { 729 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED); 730 for (i = 0; i < outcnt; i++) 731 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++); 732 } 733 if (cnt > outcnt) 734 error = nfsm_advance(nd, (cnt - outcnt) * NFSX_UNSIGNED, -1); 735 if (cntp) 736 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED); 737 nfsmout: 738 return (error); 739 } 740 741 /* 742 * Get the attributes for V4. 743 * If the compare flag is true, test for any attribute changes, 744 * otherwise return the attribute values. 745 * These attributes cover fields in "struct vattr", "struct statfs", 746 * "struct nfsfsinfo", the file handle and the lease duration. 747 * The value of retcmpp is set to 1 if all attributes are the same, 748 * and 0 otherwise. 749 * Returns EBADRPC if it can't be parsed, 0 otherwise. 750 */ 751 APPLESTATIC int 752 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, 753 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize, 754 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp, 755 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp, 756 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred) 757 { 758 u_int32_t *tl; 759 int i = 0, j, k, l, m, bitpos, attrsum = 0; 760 int error, tfhsize, aceerr, attrsize, cnt, retnotsup; 761 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1]; 762 nfsattrbit_t attrbits, retattrbits, checkattrbits; 763 struct nfsfh *tnfhp; 764 struct nfsreferral *refp; 765 u_quad_t tquad; 766 nfsquad_t tnfsquad; 767 struct timespec temptime; 768 uid_t uid; 769 gid_t gid; 770 long fid; 771 u_int32_t freenum = 0, tuint; 772 u_int64_t uquad = 0, thyp, thyp2; 773 #ifdef QUOTA 774 struct dqblk dqb; 775 uid_t savuid; 776 #endif 777 778 if (compare) { 779 retnotsup = 0; 780 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); 781 } else { 782 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 783 } 784 if (error) 785 return (error); 786 787 if (compare) { 788 *retcmpp = retnotsup; 789 } else { 790 /* 791 * Just set default values to some of the important ones. 792 */ 793 if (nap != NULL) { 794 nap->na_type = VREG; 795 nap->na_mode = 0; 796 nap->na_rdev = (NFSDEV_T)0; 797 nap->na_mtime.tv_sec = 0; 798 nap->na_mtime.tv_nsec = 0; 799 nap->na_gen = 0; 800 nap->na_flags = 0; 801 nap->na_blocksize = NFS_FABLKSIZE; 802 } 803 if (sbp != NULL) { 804 sbp->f_bsize = NFS_FABLKSIZE; 805 sbp->f_blocks = 0; 806 sbp->f_bfree = 0; 807 sbp->f_bavail = 0; 808 sbp->f_files = 0; 809 sbp->f_ffree = 0; 810 } 811 if (fsp != NULL) { 812 fsp->fs_rtmax = 8192; 813 fsp->fs_rtpref = 8192; 814 fsp->fs_maxname = NFS_MAXNAMLEN; 815 fsp->fs_wtmax = 8192; 816 fsp->fs_wtpref = 8192; 817 fsp->fs_wtmult = NFS_FABLKSIZE; 818 fsp->fs_dtpref = 8192; 819 fsp->fs_maxfilesize = 0xffffffffffffffffull; 820 fsp->fs_timedelta.tv_sec = 0; 821 fsp->fs_timedelta.tv_nsec = 1; 822 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK | 823 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME); 824 } 825 if (pc != NULL) { 826 pc->pc_linkmax = LINK_MAX; 827 pc->pc_namemax = NAME_MAX; 828 pc->pc_notrunc = 0; 829 pc->pc_chownrestricted = 0; 830 pc->pc_caseinsensitive = 0; 831 pc->pc_casepreserving = 1; 832 } 833 } 834 835 /* 836 * Loop around getting the attributes. 837 */ 838 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 839 attrsize = fxdr_unsigned(int, *tl); 840 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 841 if (attrsum > attrsize) { 842 error = NFSERR_BADXDR; 843 goto nfsmout; 844 } 845 if (NFSISSET_ATTRBIT(&attrbits, bitpos)) 846 switch (bitpos) { 847 case NFSATTRBIT_SUPPORTEDATTRS: 848 retnotsup = 0; 849 if (compare || nap == NULL) 850 error = nfsrv_getattrbits(nd, &retattrbits, 851 &cnt, &retnotsup); 852 else 853 error = nfsrv_getattrbits(nd, &nap->na_suppattr, 854 &cnt, &retnotsup); 855 if (error) 856 return (error); 857 if (compare && !(*retcmpp)) { 858 NFSSETSUPP_ATTRBIT(&checkattrbits); 859 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 860 || retnotsup) 861 *retcmpp = NFSERR_NOTSAME; 862 } 863 attrsum += cnt; 864 break; 865 case NFSATTRBIT_TYPE: 866 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 867 if (compare) { 868 if (!(*retcmpp)) { 869 if (nap->na_type != nfsv34tov_type(*tl)) 870 *retcmpp = NFSERR_NOTSAME; 871 } 872 } else if (nap != NULL) { 873 nap->na_type = nfsv34tov_type(*tl); 874 } 875 attrsum += NFSX_UNSIGNED; 876 break; 877 case NFSATTRBIT_FHEXPIRETYPE: 878 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 879 if (compare && !(*retcmpp)) { 880 if (fxdr_unsigned(int, *tl) != 881 NFSV4FHTYPE_PERSISTENT) 882 *retcmpp = NFSERR_NOTSAME; 883 } 884 attrsum += NFSX_UNSIGNED; 885 break; 886 case NFSATTRBIT_CHANGE: 887 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 888 if (compare) { 889 if (!(*retcmpp)) { 890 if (nap->na_filerev != fxdr_hyper(tl)) 891 *retcmpp = NFSERR_NOTSAME; 892 } 893 } else if (nap != NULL) { 894 nap->na_filerev = fxdr_hyper(tl); 895 } 896 attrsum += NFSX_HYPER; 897 break; 898 case NFSATTRBIT_SIZE: 899 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 900 if (compare) { 901 if (!(*retcmpp)) { 902 if (nap->na_size != fxdr_hyper(tl)) 903 *retcmpp = NFSERR_NOTSAME; 904 } 905 } else if (nap != NULL) { 906 nap->na_size = fxdr_hyper(tl); 907 } 908 attrsum += NFSX_HYPER; 909 break; 910 case NFSATTRBIT_LINKSUPPORT: 911 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 912 if (compare) { 913 if (!(*retcmpp)) { 914 if (fsp->fs_properties & NFSV3_FSFLINK) { 915 if (*tl == newnfs_false) 916 *retcmpp = NFSERR_NOTSAME; 917 } else { 918 if (*tl == newnfs_true) 919 *retcmpp = NFSERR_NOTSAME; 920 } 921 } 922 } else if (fsp != NULL) { 923 if (*tl == newnfs_true) 924 fsp->fs_properties |= NFSV3_FSFLINK; 925 else 926 fsp->fs_properties &= ~NFSV3_FSFLINK; 927 } 928 attrsum += NFSX_UNSIGNED; 929 break; 930 case NFSATTRBIT_SYMLINKSUPPORT: 931 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 932 if (compare) { 933 if (!(*retcmpp)) { 934 if (fsp->fs_properties & NFSV3_FSFSYMLINK) { 935 if (*tl == newnfs_false) 936 *retcmpp = NFSERR_NOTSAME; 937 } else { 938 if (*tl == newnfs_true) 939 *retcmpp = NFSERR_NOTSAME; 940 } 941 } 942 } else if (fsp != NULL) { 943 if (*tl == newnfs_true) 944 fsp->fs_properties |= NFSV3_FSFSYMLINK; 945 else 946 fsp->fs_properties &= ~NFSV3_FSFSYMLINK; 947 } 948 attrsum += NFSX_UNSIGNED; 949 break; 950 case NFSATTRBIT_NAMEDATTR: 951 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 952 if (compare && !(*retcmpp)) { 953 if (*tl != newnfs_false) 954 *retcmpp = NFSERR_NOTSAME; 955 } 956 attrsum += NFSX_UNSIGNED; 957 break; 958 case NFSATTRBIT_FSID: 959 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 960 thyp = fxdr_hyper(tl); 961 tl += 2; 962 thyp2 = fxdr_hyper(tl); 963 if (compare) { 964 if (*retcmpp == 0) { 965 if (thyp != (u_int64_t) 966 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] || 967 thyp2 != (u_int64_t) 968 vfs_statfs(vnode_mount(vp))->f_fsid.val[1]) 969 *retcmpp = NFSERR_NOTSAME; 970 } 971 } else if (nap != NULL) { 972 nap->na_filesid[0] = thyp; 973 nap->na_filesid[1] = thyp2; 974 } 975 attrsum += (4 * NFSX_UNSIGNED); 976 break; 977 case NFSATTRBIT_UNIQUEHANDLES: 978 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 979 if (compare && !(*retcmpp)) { 980 if (*tl != newnfs_true) 981 *retcmpp = NFSERR_NOTSAME; 982 } 983 attrsum += NFSX_UNSIGNED; 984 break; 985 case NFSATTRBIT_LEASETIME: 986 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 987 if (compare) { 988 if (fxdr_unsigned(int, *tl) != nfsrv_lease && 989 !(*retcmpp)) 990 *retcmpp = NFSERR_NOTSAME; 991 } else if (leasep != NULL) { 992 *leasep = fxdr_unsigned(u_int32_t, *tl); 993 } 994 attrsum += NFSX_UNSIGNED; 995 break; 996 case NFSATTRBIT_RDATTRERROR: 997 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 998 if (compare) { 999 if (!(*retcmpp)) 1000 *retcmpp = NFSERR_INVAL; 1001 } else if (rderrp != NULL) { 1002 *rderrp = fxdr_unsigned(u_int32_t, *tl); 1003 } 1004 attrsum += NFSX_UNSIGNED; 1005 break; 1006 case NFSATTRBIT_ACL: 1007 if (compare) { 1008 if (!(*retcmpp)) { 1009 if (nfsrv_useacl) { 1010 NFSACL_T *naclp; 1011 1012 naclp = acl_alloc(M_WAITOK); 1013 error = nfsrv_dissectacl(nd, naclp, &aceerr, 1014 &cnt, p); 1015 if (error) { 1016 acl_free(naclp); 1017 return (error); 1018 } 1019 if (aceerr || nfsrv_compareacl(aclp, naclp)) 1020 *retcmpp = NFSERR_NOTSAME; 1021 acl_free(naclp); 1022 } else { 1023 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1024 &cnt, p); 1025 *retcmpp = NFSERR_ATTRNOTSUPP; 1026 } 1027 } 1028 } else { 1029 if (vp != NULL && aclp != NULL) 1030 error = nfsrv_dissectacl(nd, aclp, &aceerr, 1031 &cnt, p); 1032 else 1033 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1034 &cnt, p); 1035 if (error) 1036 return (error); 1037 } 1038 attrsum += cnt; 1039 break; 1040 case NFSATTRBIT_ACLSUPPORT: 1041 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1042 if (compare && !(*retcmpp)) { 1043 if (nfsrv_useacl) { 1044 if (fxdr_unsigned(u_int32_t, *tl) != 1045 NFSV4ACE_SUPTYPES) 1046 *retcmpp = NFSERR_NOTSAME; 1047 } else { 1048 *retcmpp = NFSERR_ATTRNOTSUPP; 1049 } 1050 } 1051 attrsum += NFSX_UNSIGNED; 1052 break; 1053 case NFSATTRBIT_ARCHIVE: 1054 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1055 if (compare && !(*retcmpp)) 1056 *retcmpp = NFSERR_ATTRNOTSUPP; 1057 attrsum += NFSX_UNSIGNED; 1058 break; 1059 case NFSATTRBIT_CANSETTIME: 1060 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1061 if (compare) { 1062 if (!(*retcmpp)) { 1063 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) { 1064 if (*tl == newnfs_false) 1065 *retcmpp = NFSERR_NOTSAME; 1066 } else { 1067 if (*tl == newnfs_true) 1068 *retcmpp = NFSERR_NOTSAME; 1069 } 1070 } 1071 } else if (fsp != NULL) { 1072 if (*tl == newnfs_true) 1073 fsp->fs_properties |= NFSV3_FSFCANSETTIME; 1074 else 1075 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME; 1076 } 1077 attrsum += NFSX_UNSIGNED; 1078 break; 1079 case NFSATTRBIT_CASEINSENSITIVE: 1080 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1081 if (compare) { 1082 if (!(*retcmpp)) { 1083 if (*tl != newnfs_false) 1084 *retcmpp = NFSERR_NOTSAME; 1085 } 1086 } else if (pc != NULL) { 1087 pc->pc_caseinsensitive = 1088 fxdr_unsigned(u_int32_t, *tl); 1089 } 1090 attrsum += NFSX_UNSIGNED; 1091 break; 1092 case NFSATTRBIT_CASEPRESERVING: 1093 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1094 if (compare) { 1095 if (!(*retcmpp)) { 1096 if (*tl != newnfs_true) 1097 *retcmpp = NFSERR_NOTSAME; 1098 } 1099 } else if (pc != NULL) { 1100 pc->pc_casepreserving = 1101 fxdr_unsigned(u_int32_t, *tl); 1102 } 1103 attrsum += NFSX_UNSIGNED; 1104 break; 1105 case NFSATTRBIT_CHOWNRESTRICTED: 1106 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1107 if (compare) { 1108 if (!(*retcmpp)) { 1109 if (*tl != newnfs_true) 1110 *retcmpp = NFSERR_NOTSAME; 1111 } 1112 } else if (pc != NULL) { 1113 pc->pc_chownrestricted = 1114 fxdr_unsigned(u_int32_t, *tl); 1115 } 1116 attrsum += NFSX_UNSIGNED; 1117 break; 1118 case NFSATTRBIT_FILEHANDLE: 1119 error = nfsm_getfh(nd, &tnfhp); 1120 if (error) 1121 return (error); 1122 tfhsize = tnfhp->nfh_len; 1123 if (compare) { 1124 if (!(*retcmpp) && 1125 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize, 1126 fhp, fhsize)) 1127 *retcmpp = NFSERR_NOTSAME; 1128 FREE((caddr_t)tnfhp, M_NFSFH); 1129 } else if (nfhpp != NULL) { 1130 *nfhpp = tnfhp; 1131 } else { 1132 FREE((caddr_t)tnfhp, M_NFSFH); 1133 } 1134 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize)); 1135 break; 1136 case NFSATTRBIT_FILEID: 1137 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1138 thyp = fxdr_hyper(tl); 1139 if (compare) { 1140 if (!(*retcmpp)) { 1141 if ((u_int64_t)nap->na_fileid != thyp) 1142 *retcmpp = NFSERR_NOTSAME; 1143 } 1144 } else if (nap != NULL) { 1145 if (*tl++) 1146 printf("NFSv4 fileid > 32bits\n"); 1147 nap->na_fileid = thyp; 1148 } 1149 attrsum += NFSX_HYPER; 1150 break; 1151 case NFSATTRBIT_FILESAVAIL: 1152 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1153 if (compare) { 1154 if (!(*retcmpp) && 1155 sfp->sf_afiles != fxdr_hyper(tl)) 1156 *retcmpp = NFSERR_NOTSAME; 1157 } else if (sfp != NULL) { 1158 sfp->sf_afiles = fxdr_hyper(tl); 1159 } 1160 attrsum += NFSX_HYPER; 1161 break; 1162 case NFSATTRBIT_FILESFREE: 1163 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1164 if (compare) { 1165 if (!(*retcmpp) && 1166 sfp->sf_ffiles != fxdr_hyper(tl)) 1167 *retcmpp = NFSERR_NOTSAME; 1168 } else if (sfp != NULL) { 1169 sfp->sf_ffiles = fxdr_hyper(tl); 1170 } 1171 attrsum += NFSX_HYPER; 1172 break; 1173 case NFSATTRBIT_FILESTOTAL: 1174 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1175 if (compare) { 1176 if (!(*retcmpp) && 1177 sfp->sf_tfiles != fxdr_hyper(tl)) 1178 *retcmpp = NFSERR_NOTSAME; 1179 } else if (sfp != NULL) { 1180 sfp->sf_tfiles = fxdr_hyper(tl); 1181 } 1182 attrsum += NFSX_HYPER; 1183 break; 1184 case NFSATTRBIT_FSLOCATIONS: 1185 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m); 1186 if (error) 1187 return (error); 1188 attrsum += l; 1189 if (compare && !(*retcmpp)) { 1190 refp = nfsv4root_getreferral(vp, NULL, 0); 1191 if (refp != NULL) { 1192 if (cp == NULL || cp2 == NULL || 1193 strcmp(cp, "/") || 1194 strcmp(cp2, refp->nfr_srvlist)) 1195 *retcmpp = NFSERR_NOTSAME; 1196 } else if (m == 0) { 1197 *retcmpp = NFSERR_NOTSAME; 1198 } 1199 } 1200 if (cp != NULL) 1201 free(cp, M_NFSSTRING); 1202 if (cp2 != NULL) 1203 free(cp2, M_NFSSTRING); 1204 break; 1205 case NFSATTRBIT_HIDDEN: 1206 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1207 if (compare && !(*retcmpp)) 1208 *retcmpp = NFSERR_ATTRNOTSUPP; 1209 attrsum += NFSX_UNSIGNED; 1210 break; 1211 case NFSATTRBIT_HOMOGENEOUS: 1212 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1213 if (compare) { 1214 if (!(*retcmpp)) { 1215 if (fsp->fs_properties & 1216 NFSV3_FSFHOMOGENEOUS) { 1217 if (*tl == newnfs_false) 1218 *retcmpp = NFSERR_NOTSAME; 1219 } else { 1220 if (*tl == newnfs_true) 1221 *retcmpp = NFSERR_NOTSAME; 1222 } 1223 } 1224 } else if (fsp != NULL) { 1225 if (*tl == newnfs_true) 1226 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS; 1227 else 1228 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS; 1229 } 1230 attrsum += NFSX_UNSIGNED; 1231 break; 1232 case NFSATTRBIT_MAXFILESIZE: 1233 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1234 tnfsquad.qval = fxdr_hyper(tl); 1235 if (compare) { 1236 if (!(*retcmpp)) { 1237 tquad = NFSRV_MAXFILESIZE; 1238 if (tquad != tnfsquad.qval) 1239 *retcmpp = NFSERR_NOTSAME; 1240 } 1241 } else if (fsp != NULL) { 1242 fsp->fs_maxfilesize = tnfsquad.qval; 1243 } 1244 attrsum += NFSX_HYPER; 1245 break; 1246 case NFSATTRBIT_MAXLINK: 1247 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1248 if (compare) { 1249 if (!(*retcmpp)) { 1250 if (fxdr_unsigned(int, *tl) != LINK_MAX) 1251 *retcmpp = NFSERR_NOTSAME; 1252 } 1253 } else if (pc != NULL) { 1254 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl); 1255 } 1256 attrsum += NFSX_UNSIGNED; 1257 break; 1258 case NFSATTRBIT_MAXNAME: 1259 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1260 if (compare) { 1261 if (!(*retcmpp)) { 1262 if (fsp->fs_maxname != 1263 fxdr_unsigned(u_int32_t, *tl)) 1264 *retcmpp = NFSERR_NOTSAME; 1265 } 1266 } else { 1267 tuint = fxdr_unsigned(u_int32_t, *tl); 1268 /* 1269 * Some Linux NFSv4 servers report this 1270 * as 0 or 4billion, so I'll set it to 1271 * NFS_MAXNAMLEN. If a server actually creates 1272 * a name longer than NFS_MAXNAMLEN, it will 1273 * get an error back. 1274 */ 1275 if (tuint == 0 || tuint > NFS_MAXNAMLEN) 1276 tuint = NFS_MAXNAMLEN; 1277 if (fsp != NULL) 1278 fsp->fs_maxname = tuint; 1279 if (pc != NULL) 1280 pc->pc_namemax = tuint; 1281 } 1282 attrsum += NFSX_UNSIGNED; 1283 break; 1284 case NFSATTRBIT_MAXREAD: 1285 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1286 if (compare) { 1287 if (!(*retcmpp)) { 1288 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t, 1289 *(tl + 1)) || *tl != 0) 1290 *retcmpp = NFSERR_NOTSAME; 1291 } 1292 } else if (fsp != NULL) { 1293 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl); 1294 fsp->fs_rtpref = fsp->fs_rtmax; 1295 fsp->fs_dtpref = fsp->fs_rtpref; 1296 } 1297 attrsum += NFSX_HYPER; 1298 break; 1299 case NFSATTRBIT_MAXWRITE: 1300 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1301 if (compare) { 1302 if (!(*retcmpp)) { 1303 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t, 1304 *(tl + 1)) || *tl != 0) 1305 *retcmpp = NFSERR_NOTSAME; 1306 } 1307 } else if (fsp != NULL) { 1308 fsp->fs_wtmax = fxdr_unsigned(int, *++tl); 1309 fsp->fs_wtpref = fsp->fs_wtmax; 1310 } 1311 attrsum += NFSX_HYPER; 1312 break; 1313 case NFSATTRBIT_MIMETYPE: 1314 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1315 i = fxdr_unsigned(int, *tl); 1316 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); 1317 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 1318 if (error) 1319 goto nfsmout; 1320 if (compare && !(*retcmpp)) 1321 *retcmpp = NFSERR_ATTRNOTSUPP; 1322 break; 1323 case NFSATTRBIT_MODE: 1324 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1325 if (compare) { 1326 if (!(*retcmpp)) { 1327 if (nap->na_mode != nfstov_mode(*tl)) 1328 *retcmpp = NFSERR_NOTSAME; 1329 } 1330 } else if (nap != NULL) { 1331 nap->na_mode = nfstov_mode(*tl); 1332 } 1333 attrsum += NFSX_UNSIGNED; 1334 break; 1335 case NFSATTRBIT_NOTRUNC: 1336 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1337 if (compare) { 1338 if (!(*retcmpp)) { 1339 if (*tl != newnfs_true) 1340 *retcmpp = NFSERR_NOTSAME; 1341 } 1342 } else if (pc != NULL) { 1343 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl); 1344 } 1345 attrsum += NFSX_UNSIGNED; 1346 break; 1347 case NFSATTRBIT_NUMLINKS: 1348 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1349 tuint = fxdr_unsigned(u_int32_t, *tl); 1350 if (compare) { 1351 if (!(*retcmpp)) { 1352 if ((u_int32_t)nap->na_nlink != tuint) 1353 *retcmpp = NFSERR_NOTSAME; 1354 } 1355 } else if (nap != NULL) { 1356 nap->na_nlink = tuint; 1357 } 1358 attrsum += NFSX_UNSIGNED; 1359 break; 1360 case NFSATTRBIT_OWNER: 1361 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1362 j = fxdr_unsigned(int, *tl); 1363 if (j < 0) 1364 return (NFSERR_BADXDR); 1365 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1366 if (j > NFSV4_SMALLSTR) 1367 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1368 else 1369 cp = namestr; 1370 error = nfsrv_mtostr(nd, cp, j); 1371 if (error) { 1372 if (j > NFSV4_SMALLSTR) 1373 free(cp, M_NFSSTRING); 1374 return (error); 1375 } 1376 if (compare) { 1377 if (!(*retcmpp)) { 1378 if (nfsv4_strtouid(cp, j, &uid, p) || 1379 nap->na_uid != uid) 1380 *retcmpp = NFSERR_NOTSAME; 1381 } 1382 } else if (nap != NULL) { 1383 if (nfsv4_strtouid(cp, j, &uid, p)) 1384 nap->na_uid = nfsrv_defaultuid; 1385 else 1386 nap->na_uid = uid; 1387 } 1388 if (j > NFSV4_SMALLSTR) 1389 free(cp, M_NFSSTRING); 1390 break; 1391 case NFSATTRBIT_OWNERGROUP: 1392 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1393 j = fxdr_unsigned(int, *tl); 1394 if (j < 0) 1395 return (NFSERR_BADXDR); 1396 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1397 if (j > NFSV4_SMALLSTR) 1398 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1399 else 1400 cp = namestr; 1401 error = nfsrv_mtostr(nd, cp, j); 1402 if (error) { 1403 if (j > NFSV4_SMALLSTR) 1404 free(cp, M_NFSSTRING); 1405 return (error); 1406 } 1407 if (compare) { 1408 if (!(*retcmpp)) { 1409 if (nfsv4_strtogid(cp, j, &gid, p) || 1410 nap->na_gid != gid) 1411 *retcmpp = NFSERR_NOTSAME; 1412 } 1413 } else if (nap != NULL) { 1414 if (nfsv4_strtogid(cp, j, &gid, p)) 1415 nap->na_gid = nfsrv_defaultgid; 1416 else 1417 nap->na_gid = gid; 1418 } 1419 if (j > NFSV4_SMALLSTR) 1420 free(cp, M_NFSSTRING); 1421 break; 1422 case NFSATTRBIT_QUOTAHARD: 1423 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1424 if (sbp != NULL) { 1425 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1426 freenum = sbp->f_bfree; 1427 else 1428 freenum = sbp->f_bavail; 1429 #ifdef QUOTA 1430 /* 1431 * ufs_quotactl() insists that the uid argument 1432 * equal p_ruid for non-root quota access, so 1433 * we'll just make sure that's the case. 1434 */ 1435 savuid = p->p_cred->p_ruid; 1436 p->p_cred->p_ruid = cred->cr_uid; 1437 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1438 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1439 freenum = min(dqb.dqb_bhardlimit, freenum); 1440 p->p_cred->p_ruid = savuid; 1441 #endif /* QUOTA */ 1442 uquad = (u_int64_t)freenum; 1443 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1444 } 1445 if (compare && !(*retcmpp)) { 1446 if (uquad != fxdr_hyper(tl)) 1447 *retcmpp = NFSERR_NOTSAME; 1448 } 1449 attrsum += NFSX_HYPER; 1450 break; 1451 case NFSATTRBIT_QUOTASOFT: 1452 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1453 if (sbp != NULL) { 1454 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1455 freenum = sbp->f_bfree; 1456 else 1457 freenum = sbp->f_bavail; 1458 #ifdef QUOTA 1459 /* 1460 * ufs_quotactl() insists that the uid argument 1461 * equal p_ruid for non-root quota access, so 1462 * we'll just make sure that's the case. 1463 */ 1464 savuid = p->p_cred->p_ruid; 1465 p->p_cred->p_ruid = cred->cr_uid; 1466 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1467 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1468 freenum = min(dqb.dqb_bsoftlimit, freenum); 1469 p->p_cred->p_ruid = savuid; 1470 #endif /* QUOTA */ 1471 uquad = (u_int64_t)freenum; 1472 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1473 } 1474 if (compare && !(*retcmpp)) { 1475 if (uquad != fxdr_hyper(tl)) 1476 *retcmpp = NFSERR_NOTSAME; 1477 } 1478 attrsum += NFSX_HYPER; 1479 break; 1480 case NFSATTRBIT_QUOTAUSED: 1481 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1482 if (sbp != NULL) { 1483 freenum = 0; 1484 #ifdef QUOTA 1485 /* 1486 * ufs_quotactl() insists that the uid argument 1487 * equal p_ruid for non-root quota access, so 1488 * we'll just make sure that's the case. 1489 */ 1490 savuid = p->p_cred->p_ruid; 1491 p->p_cred->p_ruid = cred->cr_uid; 1492 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1493 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1494 freenum = dqb.dqb_curblocks; 1495 p->p_cred->p_ruid = savuid; 1496 #endif /* QUOTA */ 1497 uquad = (u_int64_t)freenum; 1498 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1499 } 1500 if (compare && !(*retcmpp)) { 1501 if (uquad != fxdr_hyper(tl)) 1502 *retcmpp = NFSERR_NOTSAME; 1503 } 1504 attrsum += NFSX_HYPER; 1505 break; 1506 case NFSATTRBIT_RAWDEV: 1507 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA); 1508 j = fxdr_unsigned(int, *tl++); 1509 k = fxdr_unsigned(int, *tl); 1510 if (compare) { 1511 if (!(*retcmpp)) { 1512 if (nap->na_rdev != NFSMAKEDEV(j, k)) 1513 *retcmpp = NFSERR_NOTSAME; 1514 } 1515 } else if (nap != NULL) { 1516 nap->na_rdev = NFSMAKEDEV(j, k); 1517 } 1518 attrsum += NFSX_V4SPECDATA; 1519 break; 1520 case NFSATTRBIT_SPACEAVAIL: 1521 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1522 if (compare) { 1523 if (!(*retcmpp) && 1524 sfp->sf_abytes != fxdr_hyper(tl)) 1525 *retcmpp = NFSERR_NOTSAME; 1526 } else if (sfp != NULL) { 1527 sfp->sf_abytes = fxdr_hyper(tl); 1528 } 1529 attrsum += NFSX_HYPER; 1530 break; 1531 case NFSATTRBIT_SPACEFREE: 1532 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1533 if (compare) { 1534 if (!(*retcmpp) && 1535 sfp->sf_fbytes != fxdr_hyper(tl)) 1536 *retcmpp = NFSERR_NOTSAME; 1537 } else if (sfp != NULL) { 1538 sfp->sf_fbytes = fxdr_hyper(tl); 1539 } 1540 attrsum += NFSX_HYPER; 1541 break; 1542 case NFSATTRBIT_SPACETOTAL: 1543 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1544 if (compare) { 1545 if (!(*retcmpp) && 1546 sfp->sf_tbytes != fxdr_hyper(tl)) 1547 *retcmpp = NFSERR_NOTSAME; 1548 } else if (sfp != NULL) { 1549 sfp->sf_tbytes = fxdr_hyper(tl); 1550 } 1551 attrsum += NFSX_HYPER; 1552 break; 1553 case NFSATTRBIT_SPACEUSED: 1554 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1555 thyp = fxdr_hyper(tl); 1556 if (compare) { 1557 if (!(*retcmpp)) { 1558 if ((u_int64_t)nap->na_bytes != thyp) 1559 *retcmpp = NFSERR_NOTSAME; 1560 } 1561 } else if (nap != NULL) { 1562 nap->na_bytes = thyp; 1563 } 1564 attrsum += NFSX_HYPER; 1565 break; 1566 case NFSATTRBIT_SYSTEM: 1567 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1568 if (compare && !(*retcmpp)) 1569 *retcmpp = NFSERR_ATTRNOTSUPP; 1570 attrsum += NFSX_UNSIGNED; 1571 break; 1572 case NFSATTRBIT_TIMEACCESS: 1573 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1574 fxdr_nfsv4time(tl, &temptime); 1575 if (compare) { 1576 if (!(*retcmpp)) { 1577 if (!NFS_CMPTIME(temptime, nap->na_atime)) 1578 *retcmpp = NFSERR_NOTSAME; 1579 } 1580 } else if (nap != NULL) { 1581 nap->na_atime = temptime; 1582 } 1583 attrsum += NFSX_V4TIME; 1584 break; 1585 case NFSATTRBIT_TIMEACCESSSET: 1586 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1587 attrsum += NFSX_UNSIGNED; 1588 i = fxdr_unsigned(int, *tl); 1589 if (i == NFSV4SATTRTIME_TOCLIENT) { 1590 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1591 attrsum += NFSX_V4TIME; 1592 } 1593 if (compare && !(*retcmpp)) 1594 *retcmpp = NFSERR_INVAL; 1595 break; 1596 case NFSATTRBIT_TIMEBACKUP: 1597 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1598 if (compare && !(*retcmpp)) 1599 *retcmpp = NFSERR_ATTRNOTSUPP; 1600 attrsum += NFSX_V4TIME; 1601 break; 1602 case NFSATTRBIT_TIMECREATE: 1603 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1604 if (compare && !(*retcmpp)) 1605 *retcmpp = NFSERR_ATTRNOTSUPP; 1606 attrsum += NFSX_V4TIME; 1607 break; 1608 case NFSATTRBIT_TIMEDELTA: 1609 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1610 if (fsp != NULL) { 1611 if (compare) { 1612 if (!(*retcmpp)) { 1613 if ((u_int32_t)fsp->fs_timedelta.tv_sec != 1614 fxdr_unsigned(u_int32_t, *(tl + 1)) || 1615 (u_int32_t)fsp->fs_timedelta.tv_nsec != 1616 (fxdr_unsigned(u_int32_t, *(tl + 2)) % 1617 1000000000) || 1618 *tl != 0) 1619 *retcmpp = NFSERR_NOTSAME; 1620 } 1621 } else { 1622 fxdr_nfsv4time(tl, &fsp->fs_timedelta); 1623 } 1624 } 1625 attrsum += NFSX_V4TIME; 1626 break; 1627 case NFSATTRBIT_TIMEMETADATA: 1628 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1629 fxdr_nfsv4time(tl, &temptime); 1630 if (compare) { 1631 if (!(*retcmpp)) { 1632 if (!NFS_CMPTIME(temptime, nap->na_ctime)) 1633 *retcmpp = NFSERR_NOTSAME; 1634 } 1635 } else if (nap != NULL) { 1636 nap->na_ctime = temptime; 1637 } 1638 attrsum += NFSX_V4TIME; 1639 break; 1640 case NFSATTRBIT_TIMEMODIFY: 1641 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1642 fxdr_nfsv4time(tl, &temptime); 1643 if (compare) { 1644 if (!(*retcmpp)) { 1645 if (!NFS_CMPTIME(temptime, nap->na_mtime)) 1646 *retcmpp = NFSERR_NOTSAME; 1647 } 1648 } else if (nap != NULL) { 1649 nap->na_mtime = temptime; 1650 } 1651 attrsum += NFSX_V4TIME; 1652 break; 1653 case NFSATTRBIT_TIMEMODIFYSET: 1654 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1655 attrsum += NFSX_UNSIGNED; 1656 i = fxdr_unsigned(int, *tl); 1657 if (i == NFSV4SATTRTIME_TOCLIENT) { 1658 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1659 attrsum += NFSX_V4TIME; 1660 } 1661 if (compare && !(*retcmpp)) 1662 *retcmpp = NFSERR_INVAL; 1663 break; 1664 case NFSATTRBIT_MOUNTEDONFILEID: 1665 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1666 thyp = fxdr_hyper(tl); 1667 if (compare) { 1668 if (!(*retcmpp)) { 1669 if (*tl++) { 1670 *retcmpp = NFSERR_NOTSAME; 1671 } else { 1672 if (!vp || !nfsrv_atroot(vp, &fid)) 1673 fid = nap->na_fileid; 1674 if ((u_int64_t)fid != thyp) 1675 *retcmpp = NFSERR_NOTSAME; 1676 } 1677 } 1678 } else if (nap != NULL) { 1679 if (*tl++) 1680 printf("NFSv4 mounted on fileid > 32bits\n"); 1681 nap->na_mntonfileno = thyp; 1682 } 1683 attrsum += NFSX_HYPER; 1684 break; 1685 default: 1686 printf("EEK! nfsv4_loadattr unknown attr=%d\n", 1687 bitpos); 1688 if (compare && !(*retcmpp)) 1689 *retcmpp = NFSERR_ATTRNOTSUPP; 1690 /* 1691 * and get out of the loop, since we can't parse 1692 * the unknown attrbute data. 1693 */ 1694 bitpos = NFSATTRBIT_MAX; 1695 break; 1696 }; 1697 } 1698 1699 /* 1700 * some clients pad the attrlist, so we need to skip over the 1701 * padding. 1702 */ 1703 if (attrsum > attrsize) { 1704 error = NFSERR_BADXDR; 1705 } else { 1706 attrsize = NFSM_RNDUP(attrsize); 1707 if (attrsum < attrsize) 1708 error = nfsm_advance(nd, attrsize - attrsum, -1); 1709 } 1710 nfsmout: 1711 return (error); 1712 } 1713 1714 /* 1715 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a 1716 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock. 1717 * The first argument is a pointer to an nfsv4lock structure. 1718 * The second argument is 1 iff a blocking lock is wanted. 1719 * If this argument is 0, the call waits until no thread either wants nor 1720 * holds an exclusive lock. 1721 * It returns 1 if the lock was acquired, 0 otherwise. 1722 * If several processes call this function concurrently wanting the exclusive 1723 * lock, one will get the lock and the rest will return without getting the 1724 * lock. (If the caller must have the lock, it simply calls this function in a 1725 * loop until the function returns 1 to indicate the lock was acquired.) 1726 * Any usecnt must be decremented by calling nfsv4_relref() before 1727 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could 1728 * be called in a loop. 1729 * The last argument is set to indicate if the call slept, iff not NULL. 1730 */ 1731 APPLESTATIC int 1732 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp, 1733 void *mutex) 1734 { 1735 1736 if (isleptp) 1737 *isleptp = 0; 1738 /* 1739 * If a lock is wanted, loop around until the lock is acquired by 1740 * someone and then released. If I want the lock, try to acquire it. 1741 * For a lock to be issued, no lock must be in force and the usecnt 1742 * must be zero. 1743 */ 1744 if (iwantlock) { 1745 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1746 lp->nfslock_usecnt == 0) { 1747 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1748 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1749 return (1); 1750 } 1751 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED; 1752 } 1753 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) { 1754 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1755 if (isleptp) 1756 *isleptp = 1; 1757 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1758 PZERO - 1, "nfsv4lck", NULL); 1759 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1760 lp->nfslock_usecnt == 0) { 1761 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1762 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1763 return (1); 1764 } 1765 } 1766 return (0); 1767 } 1768 1769 /* 1770 * Release the lock acquired by nfsv4_lock(). 1771 * The second argument is set to 1 to indicate the nfslock_usecnt should be 1772 * incremented, as well. 1773 */ 1774 APPLESTATIC void 1775 nfsv4_unlock(struct nfsv4lock *lp, int incref) 1776 { 1777 1778 lp->nfslock_lock &= ~NFSV4LOCK_LOCK; 1779 if (incref) 1780 lp->nfslock_usecnt++; 1781 nfsv4_wanted(lp); 1782 } 1783 1784 /* 1785 * Release a reference cnt. 1786 */ 1787 APPLESTATIC void 1788 nfsv4_relref(struct nfsv4lock *lp) 1789 { 1790 1791 if (lp->nfslock_usecnt <= 0) 1792 panic("nfsv4root ref cnt"); 1793 lp->nfslock_usecnt--; 1794 if (lp->nfslock_usecnt == 0) 1795 nfsv4_wanted(lp); 1796 } 1797 1798 /* 1799 * Get a reference cnt. 1800 * This function will wait for any exclusive lock to be released, but will 1801 * not wait for threads that want the exclusive lock. If priority needs 1802 * to be given to threads that need the exclusive lock, a call to nfsv4_lock() 1803 * with the 2nd argument == 0 should be done before calling nfsv4_getref(). 1804 */ 1805 APPLESTATIC void 1806 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex) 1807 { 1808 1809 if (isleptp) 1810 *isleptp = 0; 1811 1812 /* 1813 * Wait for a lock held. 1814 */ 1815 while (lp->nfslock_lock & NFSV4LOCK_LOCK) { 1816 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1817 if (isleptp) 1818 *isleptp = 1; 1819 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1820 PZERO - 1, "nfsv4lck", NULL); 1821 } 1822 1823 lp->nfslock_usecnt++; 1824 } 1825 1826 /* 1827 * Wake up anyone sleeping, waiting for this lock. 1828 */ 1829 static void 1830 nfsv4_wanted(struct nfsv4lock *lp) 1831 { 1832 1833 if (lp->nfslock_lock & NFSV4LOCK_WANTED) { 1834 lp->nfslock_lock &= ~NFSV4LOCK_WANTED; 1835 wakeup((caddr_t)&lp->nfslock_lock); 1836 } 1837 } 1838 1839 /* 1840 * Copy a string from an mbuf list into a character array. 1841 * Return EBADRPC if there is an mbuf error, 1842 * 0 otherwise. 1843 */ 1844 APPLESTATIC int 1845 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) 1846 { 1847 char *cp; 1848 int xfer, len; 1849 mbuf_t mp; 1850 int rem, error = 0; 1851 1852 mp = nd->nd_md; 1853 cp = nd->nd_dpos; 1854 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp; 1855 rem = NFSM_RNDUP(siz) - siz; 1856 while (siz > 0) { 1857 if (len > siz) 1858 xfer = siz; 1859 else 1860 xfer = len; 1861 NFSBCOPY(cp, str, xfer); 1862 str += xfer; 1863 siz -= xfer; 1864 if (siz > 0) { 1865 mp = mbuf_next(mp); 1866 if (mp == NULL) 1867 return (EBADRPC); 1868 cp = NFSMTOD(mp, caddr_t); 1869 len = mbuf_len(mp); 1870 } else { 1871 cp += xfer; 1872 len -= xfer; 1873 } 1874 } 1875 *str = '\0'; 1876 nd->nd_dpos = cp; 1877 nd->nd_md = mp; 1878 if (rem > 0) { 1879 if (len < rem) 1880 error = nfsm_advance(nd, rem, len); 1881 else 1882 nd->nd_dpos += rem; 1883 } 1884 return (error); 1885 } 1886 1887 /* 1888 * Fill in the attributes as marked by the bitmap (V4). 1889 */ 1890 APPLESTATIC int 1891 nfsv4_fillattr(struct nfsrv_descript *nd, vnode_t vp, NFSACL_T *saclp, 1892 struct vattr *vap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp, 1893 struct ucred *cred, NFSPROC_T *p, int isdgram, int reterr) 1894 { 1895 int bitpos, retnum = 0; 1896 u_int32_t *tl; 1897 int siz, prefixnum, error; 1898 u_char *cp, namestr[NFSV4_SMALLSTR]; 1899 nfsattrbit_t attrbits, retbits; 1900 nfsattrbit_t *retbitp = &retbits; 1901 u_int32_t freenum, *retnump; 1902 u_int64_t uquad; 1903 long fid; 1904 struct statfs fs; 1905 struct nfsfsinfo fsinf; 1906 struct timespec temptime; 1907 struct timeval curtime; 1908 NFSACL_T *aclp, *naclp = NULL; 1909 #ifdef QUOTA 1910 struct dqblk dqb; 1911 uid_t savuid; 1912 #endif 1913 1914 /* 1915 * First, set the bits that can be filled and get fsinfo. 1916 */ 1917 NFSSET_ATTRBIT(retbitp, attrbitp); 1918 /* If p and cred are NULL, it is a client side call */ 1919 if (p == NULL && cred == NULL) { 1920 NFSCLRNOTSETABLE_ATTRBIT(retbitp); 1921 aclp = saclp; 1922 } else { 1923 NFSCLRNOTFILLABLE_ATTRBIT(retbitp); 1924 naclp = acl_alloc(M_WAITOK); 1925 aclp = naclp; 1926 } 1927 nfsvno_getfs(&fsinf, isdgram); 1928 #ifndef APPLE 1929 /* 1930 * Get the VFS_STATFS(), since some attributes need them. 1931 */ 1932 if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 1933 error = VFS_STATFS(vnode_mount(vp), &fs); 1934 if (error != 0) { 1935 if (reterr) { 1936 nd->nd_repstat = NFSERR_ACCES; 1937 return (0); 1938 } 1939 NFSCLRSTATFS_ATTRBIT(retbitp); 1940 } 1941 } 1942 #endif 1943 1944 /* 1945 * And the NFSv4 ACL... 1946 */ 1947 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 1948 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 1949 !NFSHASNFS4ACL(vnode_mount(vp))))) { 1950 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 1951 } 1952 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 1953 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 1954 !NFSHASNFS4ACL(vnode_mount(vp)))) { 1955 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 1956 } else if (naclp != NULL) { 1957 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p); 1958 error = VOP_ACCESS(vp, VREAD_ACL, cred, p); 1959 if (error == 0) 1960 error = VOP_GETACL(vp, ACL_TYPE_NFS4, naclp, 1961 cred, p); 1962 NFSVOPUNLOCK(vp, 0, p); 1963 if (error != 0) { 1964 if (reterr) { 1965 nd->nd_repstat = NFSERR_ACCES; 1966 return (0); 1967 } 1968 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 1969 } 1970 } 1971 } 1972 /* 1973 * Put out the attribute bitmap for the ones being filled in 1974 * and get the field for the number of attributes returned. 1975 */ 1976 prefixnum = nfsrv_putattrbit(nd, retbitp); 1977 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 1978 prefixnum += NFSX_UNSIGNED; 1979 1980 /* 1981 * Now, loop around filling in the attributes for each bit set. 1982 */ 1983 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 1984 if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 1985 switch (bitpos) { 1986 case NFSATTRBIT_SUPPORTEDATTRS: 1987 NFSSETSUPP_ATTRBIT(&attrbits); 1988 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 1989 && !NFSHASNFS4ACL(vnode_mount(vp)))) { 1990 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 1991 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 1992 } 1993 retnum += nfsrv_putattrbit(nd, &attrbits); 1994 break; 1995 case NFSATTRBIT_TYPE: 1996 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1997 *tl = vtonfsv34_type(vap->va_type); 1998 retnum += NFSX_UNSIGNED; 1999 break; 2000 case NFSATTRBIT_FHEXPIRETYPE: 2001 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2002 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2003 retnum += NFSX_UNSIGNED; 2004 break; 2005 case NFSATTRBIT_CHANGE: 2006 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2007 txdr_hyper(vap->va_filerev, tl); 2008 retnum += NFSX_HYPER; 2009 break; 2010 case NFSATTRBIT_SIZE: 2011 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2012 txdr_hyper(vap->va_size, tl); 2013 retnum += NFSX_HYPER; 2014 break; 2015 case NFSATTRBIT_LINKSUPPORT: 2016 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2017 if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2018 *tl = newnfs_true; 2019 else 2020 *tl = newnfs_false; 2021 retnum += NFSX_UNSIGNED; 2022 break; 2023 case NFSATTRBIT_SYMLINKSUPPORT: 2024 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2025 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2026 *tl = newnfs_true; 2027 else 2028 *tl = newnfs_false; 2029 retnum += NFSX_UNSIGNED; 2030 break; 2031 case NFSATTRBIT_NAMEDATTR: 2032 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2033 *tl = newnfs_false; 2034 retnum += NFSX_UNSIGNED; 2035 break; 2036 case NFSATTRBIT_FSID: 2037 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2038 *tl++ = 0; 2039 *tl++=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[0]); 2040 *tl++ = 0; 2041 *tl=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[1]); 2042 retnum += NFSX_V4FSID; 2043 break; 2044 case NFSATTRBIT_UNIQUEHANDLES: 2045 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2046 *tl = newnfs_true; 2047 retnum += NFSX_UNSIGNED; 2048 break; 2049 case NFSATTRBIT_LEASETIME: 2050 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2051 *tl = txdr_unsigned(nfsrv_lease); 2052 retnum += NFSX_UNSIGNED; 2053 break; 2054 case NFSATTRBIT_RDATTRERROR: 2055 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2056 *tl = txdr_unsigned(rderror); 2057 retnum += NFSX_UNSIGNED; 2058 break; 2059 /* 2060 * Recommended Attributes. (Only the supported ones.) 2061 */ 2062 case NFSATTRBIT_ACL: 2063 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2064 break; 2065 case NFSATTRBIT_ACLSUPPORT: 2066 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2067 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2068 retnum += NFSX_UNSIGNED; 2069 break; 2070 case NFSATTRBIT_CANSETTIME: 2071 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2072 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2073 *tl = newnfs_true; 2074 else 2075 *tl = newnfs_false; 2076 retnum += NFSX_UNSIGNED; 2077 break; 2078 case NFSATTRBIT_CASEINSENSITIVE: 2079 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2080 *tl = newnfs_false; 2081 retnum += NFSX_UNSIGNED; 2082 break; 2083 case NFSATTRBIT_CASEPRESERVING: 2084 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2085 *tl = newnfs_true; 2086 retnum += NFSX_UNSIGNED; 2087 break; 2088 case NFSATTRBIT_CHOWNRESTRICTED: 2089 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2090 *tl = newnfs_true; 2091 retnum += NFSX_UNSIGNED; 2092 break; 2093 case NFSATTRBIT_FILEHANDLE: 2094 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2095 break; 2096 case NFSATTRBIT_FILEID: 2097 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2098 *tl++ = 0; 2099 *tl = txdr_unsigned(vap->va_fileid); 2100 retnum += NFSX_HYPER; 2101 break; 2102 case NFSATTRBIT_FILESAVAIL: 2103 /* 2104 * Check quota and use min(quota, f_ffree). 2105 */ 2106 freenum = fs.f_ffree; 2107 #ifdef QUOTA 2108 /* 2109 * ufs_quotactl() insists that the uid argument 2110 * equal p_ruid for non-root quota access, so 2111 * we'll just make sure that's the case. 2112 */ 2113 savuid = p->p_cred->p_ruid; 2114 p->p_cred->p_ruid = cred->cr_uid; 2115 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), 2116 cred->cr_uid, (caddr_t)&dqb)) 2117 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2118 freenum); 2119 p->p_cred->p_ruid = savuid; 2120 #endif /* QUOTA */ 2121 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2122 *tl++ = 0; 2123 *tl = txdr_unsigned(freenum); 2124 retnum += NFSX_HYPER; 2125 break; 2126 case NFSATTRBIT_FILESFREE: 2127 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2128 *tl++ = 0; 2129 *tl = txdr_unsigned(fs.f_ffree); 2130 retnum += NFSX_HYPER; 2131 break; 2132 case NFSATTRBIT_FILESTOTAL: 2133 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2134 *tl++ = 0; 2135 *tl = txdr_unsigned(fs.f_files); 2136 retnum += NFSX_HYPER; 2137 break; 2138 case NFSATTRBIT_FSLOCATIONS: 2139 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2140 *tl++ = 0; 2141 *tl = 0; 2142 retnum += 2 * NFSX_UNSIGNED; 2143 break; 2144 case NFSATTRBIT_HOMOGENEOUS: 2145 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2146 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2147 *tl = newnfs_true; 2148 else 2149 *tl = newnfs_false; 2150 retnum += NFSX_UNSIGNED; 2151 break; 2152 case NFSATTRBIT_MAXFILESIZE: 2153 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2154 uquad = NFSRV_MAXFILESIZE; 2155 txdr_hyper(uquad, tl); 2156 retnum += NFSX_HYPER; 2157 break; 2158 case NFSATTRBIT_MAXLINK: 2159 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2160 *tl = txdr_unsigned(LINK_MAX); 2161 retnum += NFSX_UNSIGNED; 2162 break; 2163 case NFSATTRBIT_MAXNAME: 2164 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2165 *tl = txdr_unsigned(NFS_MAXNAMLEN); 2166 retnum += NFSX_UNSIGNED; 2167 break; 2168 case NFSATTRBIT_MAXREAD: 2169 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2170 *tl++ = 0; 2171 *tl = txdr_unsigned(fsinf.fs_rtmax); 2172 retnum += NFSX_HYPER; 2173 break; 2174 case NFSATTRBIT_MAXWRITE: 2175 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2176 *tl++ = 0; 2177 *tl = txdr_unsigned(fsinf.fs_wtmax); 2178 retnum += NFSX_HYPER; 2179 break; 2180 case NFSATTRBIT_MODE: 2181 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2182 *tl = vtonfsv34_mode(vap->va_mode); 2183 retnum += NFSX_UNSIGNED; 2184 break; 2185 case NFSATTRBIT_NOTRUNC: 2186 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2187 *tl = newnfs_true; 2188 retnum += NFSX_UNSIGNED; 2189 break; 2190 case NFSATTRBIT_NUMLINKS: 2191 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2192 *tl = txdr_unsigned(vap->va_nlink); 2193 retnum += NFSX_UNSIGNED; 2194 break; 2195 case NFSATTRBIT_OWNER: 2196 cp = namestr; 2197 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); 2198 retnum += nfsm_strtom(nd, cp, siz); 2199 if (cp != namestr) 2200 free(cp, M_NFSSTRING); 2201 break; 2202 case NFSATTRBIT_OWNERGROUP: 2203 cp = namestr; 2204 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); 2205 retnum += nfsm_strtom(nd, cp, siz); 2206 if (cp != namestr) 2207 free(cp, M_NFSSTRING); 2208 break; 2209 case NFSATTRBIT_QUOTAHARD: 2210 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2211 freenum = fs.f_bfree; 2212 else 2213 freenum = fs.f_bavail; 2214 #ifdef QUOTA 2215 /* 2216 * ufs_quotactl() insists that the uid argument 2217 * equal p_ruid for non-root quota access, so 2218 * we'll just make sure that's the case. 2219 */ 2220 savuid = p->p_cred->p_ruid; 2221 p->p_cred->p_ruid = cred->cr_uid; 2222 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), 2223 cred->cr_uid, (caddr_t)&dqb)) 2224 freenum = min(dqb.dqb_bhardlimit, freenum); 2225 p->p_cred->p_ruid = savuid; 2226 #endif /* QUOTA */ 2227 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2228 uquad = (u_int64_t)freenum; 2229 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2230 txdr_hyper(uquad, tl); 2231 retnum += NFSX_HYPER; 2232 break; 2233 case NFSATTRBIT_QUOTASOFT: 2234 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2235 freenum = fs.f_bfree; 2236 else 2237 freenum = fs.f_bavail; 2238 #ifdef QUOTA 2239 /* 2240 * ufs_quotactl() insists that the uid argument 2241 * equal p_ruid for non-root quota access, so 2242 * we'll just make sure that's the case. 2243 */ 2244 savuid = p->p_cred->p_ruid; 2245 p->p_cred->p_ruid = cred->cr_uid; 2246 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), 2247 cred->cr_uid, (caddr_t)&dqb)) 2248 freenum = min(dqb.dqb_bsoftlimit, freenum); 2249 p->p_cred->p_ruid = savuid; 2250 #endif /* QUOTA */ 2251 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2252 uquad = (u_int64_t)freenum; 2253 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2254 txdr_hyper(uquad, tl); 2255 retnum += NFSX_HYPER; 2256 break; 2257 case NFSATTRBIT_QUOTAUSED: 2258 freenum = 0; 2259 #ifdef QUOTA 2260 /* 2261 * ufs_quotactl() insists that the uid argument 2262 * equal p_ruid for non-root quota access, so 2263 * we'll just make sure that's the case. 2264 */ 2265 savuid = p->p_cred->p_ruid; 2266 p->p_cred->p_ruid = cred->cr_uid; 2267 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), 2268 cred->cr_uid, (caddr_t)&dqb)) 2269 freenum = dqb.dqb_curblocks; 2270 p->p_cred->p_ruid = savuid; 2271 #endif /* QUOTA */ 2272 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2273 uquad = (u_int64_t)freenum; 2274 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2275 txdr_hyper(uquad, tl); 2276 retnum += NFSX_HYPER; 2277 break; 2278 case NFSATTRBIT_RAWDEV: 2279 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2280 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2281 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2282 retnum += NFSX_V4SPECDATA; 2283 break; 2284 case NFSATTRBIT_SPACEAVAIL: 2285 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2286 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) 2287 uquad = (u_int64_t)fs.f_bfree; 2288 else 2289 uquad = (u_int64_t)fs.f_bavail; 2290 uquad *= fs.f_bsize; 2291 txdr_hyper(uquad, tl); 2292 retnum += NFSX_HYPER; 2293 break; 2294 case NFSATTRBIT_SPACEFREE: 2295 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2296 uquad = (u_int64_t)fs.f_bfree; 2297 uquad *= fs.f_bsize; 2298 txdr_hyper(uquad, tl); 2299 retnum += NFSX_HYPER; 2300 break; 2301 case NFSATTRBIT_SPACETOTAL: 2302 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2303 uquad = (u_int64_t)fs.f_blocks; 2304 uquad *= fs.f_bsize; 2305 txdr_hyper(uquad, tl); 2306 retnum += NFSX_HYPER; 2307 break; 2308 case NFSATTRBIT_SPACEUSED: 2309 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2310 txdr_hyper(vap->va_bytes, tl); 2311 retnum += NFSX_HYPER; 2312 break; 2313 case NFSATTRBIT_TIMEACCESS: 2314 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2315 txdr_nfsv4time(&vap->va_atime, tl); 2316 retnum += NFSX_V4TIME; 2317 break; 2318 case NFSATTRBIT_TIMEACCESSSET: 2319 NFSGETTIME(&curtime); 2320 if (vap->va_atime.tv_sec != curtime.tv_sec) { 2321 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2322 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2323 txdr_nfsv4time(&vap->va_atime, tl); 2324 retnum += NFSX_V4SETTIME; 2325 } else { 2326 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2327 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2328 retnum += NFSX_UNSIGNED; 2329 } 2330 break; 2331 case NFSATTRBIT_TIMEDELTA: 2332 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2333 temptime.tv_sec = 0; 2334 temptime.tv_nsec = 1000000000 / hz; 2335 txdr_nfsv4time(&temptime, tl); 2336 retnum += NFSX_V4TIME; 2337 break; 2338 case NFSATTRBIT_TIMEMETADATA: 2339 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2340 txdr_nfsv4time(&vap->va_ctime, tl); 2341 retnum += NFSX_V4TIME; 2342 break; 2343 case NFSATTRBIT_TIMEMODIFY: 2344 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2345 txdr_nfsv4time(&vap->va_mtime, tl); 2346 retnum += NFSX_V4TIME; 2347 break; 2348 case NFSATTRBIT_TIMEMODIFYSET: 2349 NFSGETTIME(&curtime); 2350 if (vap->va_mtime.tv_sec != curtime.tv_sec) { 2351 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2352 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2353 txdr_nfsv4time(&vap->va_mtime, tl); 2354 retnum += NFSX_V4SETTIME; 2355 } else { 2356 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2357 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2358 retnum += NFSX_UNSIGNED; 2359 } 2360 break; 2361 case NFSATTRBIT_MOUNTEDONFILEID: 2362 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2363 *tl++ = 0; 2364 if (nfsrv_atroot(vp, &fid)) 2365 *tl = txdr_unsigned(fid); 2366 else 2367 *tl = txdr_unsigned(vap->va_fileid); 2368 retnum += NFSX_HYPER; 2369 break; 2370 default: 2371 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2372 }; 2373 } 2374 } 2375 if (naclp != NULL) 2376 acl_free(naclp); 2377 *retnump = txdr_unsigned(retnum); 2378 return (retnum + prefixnum); 2379 } 2380 2381 /* 2382 * Put the attribute bits onto an mbuf list. 2383 * Return the number of bytes of output generated. 2384 */ 2385 APPLESTATIC int 2386 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 2387 { 2388 u_int32_t *tl; 2389 int cnt, i, bytesize; 2390 2391 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 2392 if (attrbitp->bits[cnt - 1]) 2393 break; 2394 bytesize = (cnt + 1) * NFSX_UNSIGNED; 2395 NFSM_BUILD(tl, u_int32_t *, bytesize); 2396 *tl++ = txdr_unsigned(cnt); 2397 for (i = 0; i < cnt; i++) 2398 *tl++ = txdr_unsigned(attrbitp->bits[i]); 2399 return (bytesize); 2400 } 2401 2402 /* 2403 * Convert a uid to a string. 2404 * If the lookup fails, just output the digits. 2405 * uid - the user id 2406 * cpp - points to a buffer of size NFSV4_SMALLSTR 2407 * (malloc a larger one, as required) 2408 * retlenp - pointer to length to be returned 2409 */ 2410 APPLESTATIC void 2411 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2412 { 2413 int i; 2414 struct nfsusrgrp *usrp; 2415 u_char *cp = *cpp; 2416 uid_t tmp; 2417 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2418 2419 cnt = 0; 2420 tryagain: 2421 NFSLOCKNAMEID(); 2422 if (nfsrv_dnsname) { 2423 /* 2424 * Always map nfsrv_defaultuid to "nobody". 2425 */ 2426 if (uid == nfsrv_defaultuid) { 2427 i = nfsrv_dnsnamelen + 7; 2428 if (i > len) { 2429 NFSUNLOCKNAMEID(); 2430 if (len > NFSV4_SMALLSTR) 2431 free(cp, M_NFSSTRING); 2432 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2433 *cpp = cp; 2434 len = i; 2435 goto tryagain; 2436 } 2437 *retlenp = i; 2438 NFSBCOPY("nobody@", cp, 7); 2439 cp += 7; 2440 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2441 NFSUNLOCKNAMEID(); 2442 return; 2443 } 2444 hasampersand = 0; 2445 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) { 2446 if (usrp->lug_uid == uid) { 2447 if (usrp->lug_expiry < NFSD_MONOSEC) 2448 break; 2449 /* 2450 * If the name doesn't already have an '@' 2451 * in it, append @domainname to it. 2452 */ 2453 for (i = 0; i < usrp->lug_namelen; i++) { 2454 if (usrp->lug_name[i] == '@') { 2455 hasampersand = 1; 2456 break; 2457 } 2458 } 2459 if (hasampersand) 2460 i = usrp->lug_namelen; 2461 else 2462 i = usrp->lug_namelen + 2463 nfsrv_dnsnamelen + 1; 2464 if (i > len) { 2465 NFSUNLOCKNAMEID(); 2466 if (len > NFSV4_SMALLSTR) 2467 free(cp, M_NFSSTRING); 2468 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2469 *cpp = cp; 2470 len = i; 2471 goto tryagain; 2472 } 2473 *retlenp = i; 2474 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2475 if (!hasampersand) { 2476 cp += usrp->lug_namelen; 2477 *cp++ = '@'; 2478 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2479 } 2480 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2481 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2482 NFSUNLOCKNAMEID(); 2483 return; 2484 } 2485 } 2486 NFSUNLOCKNAMEID(); 2487 cnt++; 2488 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2489 NULL, p); 2490 if (ret == 0 && cnt < 2) 2491 goto tryagain; 2492 } else { 2493 NFSUNLOCKNAMEID(); 2494 } 2495 2496 /* 2497 * No match, just return a string of digits. 2498 */ 2499 tmp = uid; 2500 i = 0; 2501 while (tmp || i == 0) { 2502 tmp /= 10; 2503 i++; 2504 } 2505 len = (i > len) ? len : i; 2506 *retlenp = len; 2507 cp += (len - 1); 2508 tmp = uid; 2509 for (i = 0; i < len; i++) { 2510 *cp-- = '0' + (tmp % 10); 2511 tmp /= 10; 2512 } 2513 return; 2514 } 2515 2516 /* 2517 * Convert a string to a uid. 2518 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2519 * return 0. 2520 */ 2521 APPLESTATIC int 2522 nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p) 2523 { 2524 int i; 2525 u_char *cp; 2526 struct nfsusrgrp *usrp; 2527 int cnt, ret; 2528 2529 if (len == 0) 2530 return (NFSERR_BADOWNER); 2531 /* 2532 * Look for an '@'. 2533 */ 2534 cp = str; 2535 for (i = 0; i < len; i++) 2536 if (*cp++ == '@') 2537 break; 2538 2539 cnt = 0; 2540 tryagain: 2541 NFSLOCKNAMEID(); 2542 /* 2543 * If an '@' is found and the domain name matches, search for the name 2544 * with dns stripped off. 2545 * Mixed case alpahbetics will match for the domain name, but all 2546 * upper case will not. 2547 */ 2548 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2549 (len - 1 - i) == nfsrv_dnsnamelen && 2550 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2551 len -= (nfsrv_dnsnamelen + 1); 2552 *(cp - 1) = '\0'; 2553 } 2554 2555 /* 2556 * Check for the special case of "nobody". 2557 */ 2558 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 2559 *uidp = nfsrv_defaultuid; 2560 NFSUNLOCKNAMEID(); 2561 return (0); 2562 } 2563 2564 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) { 2565 if (usrp->lug_namelen == len && 2566 !NFSBCMP(usrp->lug_name, str, len)) { 2567 if (usrp->lug_expiry < NFSD_MONOSEC) 2568 break; 2569 *uidp = usrp->lug_uid; 2570 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2571 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2572 NFSUNLOCKNAMEID(); 2573 return (0); 2574 } 2575 } 2576 NFSUNLOCKNAMEID(); 2577 cnt++; 2578 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 2579 str, p); 2580 if (ret == 0 && cnt < 2) 2581 goto tryagain; 2582 return (NFSERR_BADOWNER); 2583 } 2584 2585 /* 2586 * Convert a gid to a string. 2587 * gid - the group id 2588 * cpp - points to a buffer of size NFSV4_SMALLSTR 2589 * (malloc a larger one, as required) 2590 * retlenp - pointer to length to be returned 2591 */ 2592 APPLESTATIC void 2593 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2594 { 2595 int i; 2596 struct nfsusrgrp *usrp; 2597 u_char *cp = *cpp; 2598 gid_t tmp; 2599 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2600 2601 cnt = 0; 2602 tryagain: 2603 NFSLOCKNAMEID(); 2604 if (nfsrv_dnsname) { 2605 /* 2606 * Always map nfsrv_defaultgid to "nogroup". 2607 */ 2608 if (gid == nfsrv_defaultgid) { 2609 i = nfsrv_dnsnamelen + 8; 2610 if (i > len) { 2611 NFSUNLOCKNAMEID(); 2612 if (len > NFSV4_SMALLSTR) 2613 free(cp, M_NFSSTRING); 2614 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2615 *cpp = cp; 2616 len = i; 2617 goto tryagain; 2618 } 2619 *retlenp = i; 2620 NFSBCOPY("nogroup@", cp, 8); 2621 cp += 8; 2622 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2623 NFSUNLOCKNAMEID(); 2624 return; 2625 } 2626 hasampersand = 0; 2627 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) { 2628 if (usrp->lug_gid == gid) { 2629 if (usrp->lug_expiry < NFSD_MONOSEC) 2630 break; 2631 /* 2632 * If the name doesn't already have an '@' 2633 * in it, append @domainname to it. 2634 */ 2635 for (i = 0; i < usrp->lug_namelen; i++) { 2636 if (usrp->lug_name[i] == '@') { 2637 hasampersand = 1; 2638 break; 2639 } 2640 } 2641 if (hasampersand) 2642 i = usrp->lug_namelen; 2643 else 2644 i = usrp->lug_namelen + 2645 nfsrv_dnsnamelen + 1; 2646 if (i > len) { 2647 NFSUNLOCKNAMEID(); 2648 if (len > NFSV4_SMALLSTR) 2649 free(cp, M_NFSSTRING); 2650 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2651 *cpp = cp; 2652 len = i; 2653 goto tryagain; 2654 } 2655 *retlenp = i; 2656 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2657 if (!hasampersand) { 2658 cp += usrp->lug_namelen; 2659 *cp++ = '@'; 2660 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2661 } 2662 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2663 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2664 NFSUNLOCKNAMEID(); 2665 return; 2666 } 2667 } 2668 NFSUNLOCKNAMEID(); 2669 cnt++; 2670 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, 2671 NULL, p); 2672 if (ret == 0 && cnt < 2) 2673 goto tryagain; 2674 } else { 2675 NFSUNLOCKNAMEID(); 2676 } 2677 2678 /* 2679 * No match, just return a string of digits. 2680 */ 2681 tmp = gid; 2682 i = 0; 2683 while (tmp || i == 0) { 2684 tmp /= 10; 2685 i++; 2686 } 2687 len = (i > len) ? len : i; 2688 *retlenp = len; 2689 cp += (len - 1); 2690 tmp = gid; 2691 for (i = 0; i < len; i++) { 2692 *cp-- = '0' + (tmp % 10); 2693 tmp /= 10; 2694 } 2695 return; 2696 } 2697 2698 /* 2699 * Convert a string to a gid. 2700 */ 2701 APPLESTATIC int 2702 nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p) 2703 { 2704 int i; 2705 u_char *cp; 2706 struct nfsusrgrp *usrp; 2707 int cnt, ret; 2708 2709 if (len == 0) 2710 return (NFSERR_BADOWNER); 2711 /* 2712 * Look for an '@'. 2713 */ 2714 cp = str; 2715 for (i = 0; i < len; i++) 2716 if (*cp++ == '@') 2717 break; 2718 2719 cnt = 0; 2720 tryagain: 2721 NFSLOCKNAMEID(); 2722 /* 2723 * If an '@' is found and the dns name matches, search for the name 2724 * with the dns stripped off. 2725 */ 2726 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2727 (len - 1 - i) == nfsrv_dnsnamelen && 2728 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2729 len -= (nfsrv_dnsnamelen + 1); 2730 *(cp - 1) = '\0'; 2731 } 2732 2733 /* 2734 * Check for the special case of "nogroup". 2735 */ 2736 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 2737 *gidp = nfsrv_defaultgid; 2738 NFSUNLOCKNAMEID(); 2739 return (0); 2740 } 2741 2742 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) { 2743 if (usrp->lug_namelen == len && 2744 !NFSBCMP(usrp->lug_name, str, len)) { 2745 if (usrp->lug_expiry < NFSD_MONOSEC) 2746 break; 2747 *gidp = usrp->lug_gid; 2748 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2749 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2750 NFSUNLOCKNAMEID(); 2751 return (0); 2752 } 2753 } 2754 NFSUNLOCKNAMEID(); 2755 cnt++; 2756 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 2757 str, p); 2758 if (ret == 0 && cnt < 2) 2759 goto tryagain; 2760 return (NFSERR_BADOWNER); 2761 } 2762 2763 /* 2764 * Cmp len chars, allowing mixed case in the first argument to match lower 2765 * case in the second, but not if the first argument is all upper case. 2766 * Return 0 for a match, 1 otherwise. 2767 */ 2768 static int 2769 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 2770 { 2771 int i; 2772 u_char tmp; 2773 int fndlower = 0; 2774 2775 for (i = 0; i < len; i++) { 2776 if (*cp >= 'A' && *cp <= 'Z') { 2777 tmp = *cp++ + ('a' - 'A'); 2778 } else { 2779 tmp = *cp++; 2780 if (tmp >= 'a' && tmp <= 'z') 2781 fndlower = 1; 2782 } 2783 if (tmp != *cp2++) 2784 return (1); 2785 } 2786 if (fndlower) 2787 return (0); 2788 else 2789 return (1); 2790 } 2791 2792 /* 2793 * Set the port for the nfsuserd. 2794 */ 2795 APPLESTATIC int 2796 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p) 2797 { 2798 struct nfssockreq *rp; 2799 struct sockaddr_in *ad; 2800 int error; 2801 2802 NFSLOCKNAMEID(); 2803 if (nfsrv_nfsuserd) { 2804 NFSUNLOCKNAMEID(); 2805 return (EPERM); 2806 } 2807 nfsrv_nfsuserd = 1; 2808 NFSUNLOCKNAMEID(); 2809 /* 2810 * Set up the socket record and connect. 2811 */ 2812 rp = &nfsrv_nfsuserdsock; 2813 rp->nr_client = NULL; 2814 rp->nr_sotype = SOCK_DGRAM; 2815 rp->nr_soproto = IPPROTO_UDP; 2816 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 2817 rp->nr_cred = NULL; 2818 NFSSOCKADDRALLOC(rp->nr_nam); 2819 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in)); 2820 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *); 2821 ad->sin_family = AF_INET; 2822 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */ 2823 ad->sin_port = port; 2824 rp->nr_prog = RPCPROG_NFSUSERD; 2825 rp->nr_vers = RPCNFSUSERD_VERS; 2826 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 2827 if (error) { 2828 NFSSOCKADDRFREE(rp->nr_nam); 2829 nfsrv_nfsuserd = 0; 2830 } 2831 return (error); 2832 } 2833 2834 /* 2835 * Delete the nfsuserd port. 2836 */ 2837 APPLESTATIC void 2838 nfsrv_nfsuserddelport(void) 2839 { 2840 2841 NFSLOCKNAMEID(); 2842 if (nfsrv_nfsuserd == 0) { 2843 NFSUNLOCKNAMEID(); 2844 return; 2845 } 2846 nfsrv_nfsuserd = 0; 2847 NFSUNLOCKNAMEID(); 2848 newnfs_disconnect(&nfsrv_nfsuserdsock); 2849 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); 2850 } 2851 2852 /* 2853 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 2854 * name<-->id cache. 2855 * Returns 0 upon success, non-zero otherwise. 2856 */ 2857 static int 2858 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) 2859 { 2860 u_int32_t *tl; 2861 struct nfsrv_descript *nd; 2862 int len; 2863 struct nfsrv_descript nfsd; 2864 struct ucred *cred; 2865 int error; 2866 2867 NFSLOCKNAMEID(); 2868 if (nfsrv_nfsuserd == 0) { 2869 NFSUNLOCKNAMEID(); 2870 return (EPERM); 2871 } 2872 NFSUNLOCKNAMEID(); 2873 nd = &nfsd; 2874 cred = newnfs_getcred(); 2875 nd->nd_flag = ND_GSSINITREPLY; 2876 nfsrvd_rephead(nd); 2877 2878 nd->nd_procnum = procnum; 2879 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 2880 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2881 if (procnum == RPCNFSUSERD_GETUID) 2882 *tl = txdr_unsigned(uid); 2883 else 2884 *tl = txdr_unsigned(gid); 2885 } else { 2886 len = strlen(name); 2887 (void) nfsm_strtom(nd, name, len); 2888 } 2889 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 2890 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL); 2891 NFSFREECRED(cred); 2892 if (!error) { 2893 mbuf_freem(nd->nd_mrep); 2894 error = nd->nd_repstat; 2895 } 2896 return (error); 2897 } 2898 2899 /* 2900 * This function is called from the nfssvc(2) system call, to update the 2901 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 2902 */ 2903 APPLESTATIC int 2904 nfssvc_idname(struct nfsd_idargs *nidp) 2905 { 2906 struct nfsusrgrp *nusrp, *usrp, *newusrp; 2907 struct nfsuserhashhead *hp; 2908 int i; 2909 int error = 0; 2910 u_char *cp; 2911 2912 if (nidp->nid_flag & NFSID_INITIALIZE) { 2913 cp = (u_char *)malloc(nidp->nid_namelen + 1, 2914 M_NFSSTRING, M_WAITOK); 2915 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 2916 nidp->nid_namelen); 2917 NFSLOCKNAMEID(); 2918 if (nfsrv_dnsname) { 2919 /* 2920 * Free up all the old stuff and reinitialize hash lists. 2921 */ 2922 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 2923 nfsrv_removeuser(usrp); 2924 } 2925 free(nfsrv_dnsname, M_NFSSTRING); 2926 nfsrv_dnsname = NULL; 2927 } 2928 TAILQ_INIT(&nfsuserlruhead); 2929 for (i = 0; i < NFSUSERHASHSIZE; i++) 2930 LIST_INIT(&nfsuserhash[i]); 2931 for (i = 0; i < NFSGROUPHASHSIZE; i++) 2932 LIST_INIT(&nfsgrouphash[i]); 2933 for (i = 0; i < NFSUSERHASHSIZE; i++) 2934 LIST_INIT(&nfsusernamehash[i]); 2935 for (i = 0; i < NFSGROUPHASHSIZE; i++) 2936 LIST_INIT(&nfsgroupnamehash[i]); 2937 2938 /* 2939 * Put name in "DNS" string. 2940 */ 2941 if (!error) { 2942 nfsrv_dnsname = cp; 2943 nfsrv_dnsnamelen = nidp->nid_namelen; 2944 nfsrv_defaultuid = nidp->nid_uid; 2945 nfsrv_defaultgid = nidp->nid_gid; 2946 nfsrv_usercnt = 0; 2947 nfsrv_usermax = nidp->nid_usermax; 2948 } 2949 NFSUNLOCKNAMEID(); 2950 if (error) 2951 free(cp, M_NFSSTRING); 2952 return (error); 2953 } 2954 2955 /* 2956 * malloc the new one now, so any potential sleep occurs before 2957 * manipulation of the lists. 2958 */ 2959 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) + 2960 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK); 2961 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 2962 nidp->nid_namelen); 2963 if (error) { 2964 free((caddr_t)newusrp, M_NFSUSERGROUP); 2965 return (error); 2966 } 2967 newusrp->lug_namelen = nidp->nid_namelen; 2968 2969 NFSLOCKNAMEID(); 2970 /* 2971 * Delete old entries, as required. 2972 */ 2973 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 2974 hp = NFSUSERHASH(nidp->nid_uid); 2975 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 2976 if (usrp->lug_uid == nidp->nid_uid) 2977 nfsrv_removeuser(usrp); 2978 } 2979 } 2980 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 2981 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 2982 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 2983 if (usrp->lug_namelen == newusrp->lug_namelen && 2984 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 2985 usrp->lug_namelen)) 2986 nfsrv_removeuser(usrp); 2987 } 2988 } 2989 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 2990 hp = NFSGROUPHASH(nidp->nid_gid); 2991 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 2992 if (usrp->lug_gid == nidp->nid_gid) 2993 nfsrv_removeuser(usrp); 2994 } 2995 } 2996 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 2997 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 2998 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 2999 if (usrp->lug_namelen == newusrp->lug_namelen && 3000 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3001 usrp->lug_namelen)) 3002 nfsrv_removeuser(usrp); 3003 } 3004 } 3005 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 3006 if (usrp->lug_expiry < NFSD_MONOSEC) 3007 nfsrv_removeuser(usrp); 3008 } 3009 while (nfsrv_usercnt >= nfsrv_usermax) { 3010 usrp = TAILQ_FIRST(&nfsuserlruhead); 3011 nfsrv_removeuser(usrp); 3012 } 3013 3014 /* 3015 * Now, we can add the new one. 3016 */ 3017 if (nidp->nid_usertimeout) 3018 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3019 else 3020 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3021 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3022 newusrp->lug_uid = nidp->nid_uid; 3023 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp, 3024 lug_numhash); 3025 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name, 3026 newusrp->lug_namelen), newusrp, lug_namehash); 3027 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3028 nfsrv_usercnt++; 3029 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3030 newusrp->lug_gid = nidp->nid_gid; 3031 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp, 3032 lug_numhash); 3033 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name, 3034 newusrp->lug_namelen), newusrp, lug_namehash); 3035 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3036 nfsrv_usercnt++; 3037 } else 3038 FREE((caddr_t)newusrp, M_NFSUSERGROUP); 3039 NFSUNLOCKNAMEID(); 3040 return (error); 3041 } 3042 3043 /* 3044 * Remove a user/group name element. 3045 */ 3046 static void 3047 nfsrv_removeuser(struct nfsusrgrp *usrp) 3048 { 3049 3050 NFSNAMEIDREQUIRED(); 3051 LIST_REMOVE(usrp, lug_numhash); 3052 LIST_REMOVE(usrp, lug_namehash); 3053 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 3054 nfsrv_usercnt--; 3055 FREE((caddr_t)usrp, M_NFSUSERGROUP); 3056 } 3057 3058 /* 3059 * This function scans a byte string and checks for UTF-8 compliance. 3060 * It returns 0 if it conforms and NFSERR_INVAL if not. 3061 */ 3062 APPLESTATIC int 3063 nfsrv_checkutf8(u_int8_t *cp, int len) 3064 { 3065 u_int32_t val = 0x0; 3066 int cnt = 0, gotd = 0, shift = 0; 3067 u_int8_t byte; 3068 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 3069 3070 /* 3071 * Here are what the variables are used for: 3072 * val - the calculated value of a multibyte char, used to check 3073 * that it was coded with the correct range 3074 * cnt - the number of 10xxxxxx bytes to follow 3075 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 3076 * shift - lower order bits of range (ie. "val >> shift" should 3077 * not be 0, in other words, dividing by the lower bound 3078 * of the range should get a non-zero value) 3079 * byte - used to calculate cnt 3080 */ 3081 while (len > 0) { 3082 if (cnt > 0) { 3083 /* This handles the 10xxxxxx bytes */ 3084 if ((*cp & 0xc0) != 0x80 || 3085 (gotd && (*cp & 0x20))) 3086 return (NFSERR_INVAL); 3087 gotd = 0; 3088 val <<= 6; 3089 val |= (*cp & 0x3f); 3090 cnt--; 3091 if (cnt == 0 && (val >> shift) == 0x0) 3092 return (NFSERR_INVAL); 3093 } else if (*cp & 0x80) { 3094 /* first byte of multi byte char */ 3095 byte = *cp; 3096 while ((byte & 0x40) && cnt < 6) { 3097 cnt++; 3098 byte <<= 1; 3099 } 3100 if (cnt == 0 || cnt == 6) 3101 return (NFSERR_INVAL); 3102 val = (*cp & (0x3f >> cnt)); 3103 shift = utf8_shift[cnt - 1]; 3104 if (cnt == 2 && val == 0xd) 3105 /* Check for the 0xd800-0xdfff case */ 3106 gotd = 1; 3107 } 3108 cp++; 3109 len--; 3110 } 3111 if (cnt > 0) 3112 return (NFSERR_INVAL); 3113 return (0); 3114 } 3115 3116 /* 3117 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 3118 * strings, one with the root path in it and the other with the list of 3119 * locations. The list is in the same format as is found in nfr_refs. 3120 * It is a "," separated list of entries, where each of them is of the 3121 * form <server>:<rootpath>. For example 3122 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 3123 * The nilp argument is set to 1 for the special case of a null fs_root 3124 * and an empty server list. 3125 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 3126 * number of xdr bytes parsed in sump. 3127 */ 3128 static int 3129 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 3130 int *sump, int *nilp) 3131 { 3132 u_int32_t *tl; 3133 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 3134 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error, nsrv; 3135 struct list { 3136 SLIST_ENTRY(list) next; 3137 int len; 3138 u_char host[1]; 3139 } *lsp, *nlsp; 3140 SLIST_HEAD(, list) head; 3141 3142 *fsrootp = NULL; 3143 *srvp = NULL; 3144 *nilp = 0; 3145 3146 /* 3147 * Get the fs_root path and check for the special case of null path 3148 * and 0 length server list. 3149 */ 3150 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3151 len = fxdr_unsigned(int, *tl); 3152 if (len < 0 || len > 10240) 3153 return (NFSERR_BADXDR); 3154 if (len == 0) { 3155 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3156 if (*tl != 0) 3157 return (NFSERR_BADXDR); 3158 *nilp = 1; 3159 *sump = 2 * NFSX_UNSIGNED; 3160 return (0); 3161 } 3162 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 3163 error = nfsrv_mtostr(nd, cp, len); 3164 if (!error) { 3165 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3166 cnt = fxdr_unsigned(int, *tl); 3167 if (cnt <= 0) 3168 error = NFSERR_BADXDR; 3169 } 3170 if (error) { 3171 free(cp, M_NFSSTRING); 3172 return (error); 3173 } 3174 3175 /* 3176 * Now, loop through the location list and make up the srvlist. 3177 */ 3178 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3179 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 3180 slen = 1024; 3181 siz = 0; 3182 for (i = 0; i < cnt; i++) { 3183 SLIST_INIT(&head); 3184 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3185 nsrv = fxdr_unsigned(int, *tl); 3186 if (nsrv <= 0) { 3187 free(cp, M_NFSSTRING); 3188 free(cp2, M_NFSSTRING); 3189 return (NFSERR_BADXDR); 3190 } 3191 3192 /* 3193 * Handle the first server by putting it in the srvstr. 3194 */ 3195 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3196 len = fxdr_unsigned(int, *tl); 3197 if (len <= 0 || len > 1024) { 3198 free(cp, M_NFSSTRING); 3199 free(cp2, M_NFSSTRING); 3200 return (NFSERR_BADXDR); 3201 } 3202 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 3203 if (cp3 != cp2) { 3204 *cp3++ = ','; 3205 siz++; 3206 } 3207 error = nfsrv_mtostr(nd, cp3, len); 3208 if (error) { 3209 free(cp, M_NFSSTRING); 3210 free(cp2, M_NFSSTRING); 3211 return (error); 3212 } 3213 cp3 += len; 3214 *cp3++ = ':'; 3215 siz += (len + 1); 3216 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3217 for (j = 1; j < nsrv; j++) { 3218 /* 3219 * Yuck, put them in an slist and process them later. 3220 */ 3221 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3222 len = fxdr_unsigned(int, *tl); 3223 if (len <= 0 || len > 1024) { 3224 free(cp, M_NFSSTRING); 3225 free(cp2, M_NFSSTRING); 3226 return (NFSERR_BADXDR); 3227 } 3228 lsp = (struct list *)malloc(sizeof (struct list) 3229 + len, M_TEMP, M_WAITOK); 3230 error = nfsrv_mtostr(nd, lsp->host, len); 3231 if (error) { 3232 free(cp, M_NFSSTRING); 3233 free(cp2, M_NFSSTRING); 3234 return (error); 3235 } 3236 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3237 lsp->len = len; 3238 SLIST_INSERT_HEAD(&head, lsp, next); 3239 } 3240 3241 /* 3242 * Finally, we can get the path. 3243 */ 3244 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3245 len = fxdr_unsigned(int, *tl); 3246 if (len <= 0 || len > 1024) { 3247 free(cp, M_NFSSTRING); 3248 free(cp2, M_NFSSTRING); 3249 return (NFSERR_BADXDR); 3250 } 3251 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 3252 error = nfsrv_mtostr(nd, cp3, len); 3253 if (error) { 3254 free(cp, M_NFSSTRING); 3255 free(cp2, M_NFSSTRING); 3256 return (error); 3257 } 3258 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3259 str = cp3; 3260 stringlen = len; 3261 cp3 += len; 3262 siz += len; 3263 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 3264 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 3265 &cp2, &cp3, &slen); 3266 *cp3++ = ','; 3267 NFSBCOPY(lsp->host, cp3, lsp->len); 3268 cp3 += lsp->len; 3269 *cp3++ = ':'; 3270 NFSBCOPY(str, cp3, stringlen); 3271 cp3 += stringlen; 3272 *cp3 = '\0'; 3273 siz += (lsp->len + stringlen + 2); 3274 free((caddr_t)lsp, M_TEMP); 3275 } 3276 } 3277 *fsrootp = cp; 3278 *srvp = cp2; 3279 *sump = xdrsum; 3280 return (0); 3281 nfsmout: 3282 if (cp != NULL) 3283 free(cp, M_NFSSTRING); 3284 if (cp2 != NULL) 3285 free(cp2, M_NFSSTRING); 3286 return (error); 3287 } 3288 3289 /* 3290 * Make the malloc'd space large enough. This is a pain, but the xdr 3291 * doesn't set an upper bound on the side, so... 3292 */ 3293 static void 3294 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 3295 { 3296 u_char *cp; 3297 int i; 3298 3299 if (siz <= *slenp) 3300 return; 3301 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 3302 NFSBCOPY(*cpp, cp, *slenp); 3303 free(*cpp, M_NFSSTRING); 3304 i = *cpp2 - *cpp; 3305 *cpp = cp; 3306 *cpp2 = cp + i; 3307 *slenp = siz + 1024; 3308 } 3309 3310 /* 3311 * Initialize the reply header data structures. 3312 */ 3313 APPLESTATIC void 3314 nfsrvd_rephead(struct nfsrv_descript *nd) 3315 { 3316 mbuf_t mreq; 3317 3318 /* 3319 * If this is a big reply, use a cluster. 3320 */ 3321 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 3322 nfs_bigreply[nd->nd_procnum]) { 3323 NFSMCLGET(mreq, M_WAIT); 3324 nd->nd_mreq = mreq; 3325 nd->nd_mb = mreq; 3326 } else { 3327 NFSMGET(mreq); 3328 nd->nd_mreq = mreq; 3329 nd->nd_mb = mreq; 3330 } 3331 nd->nd_bpos = NFSMTOD(mreq, caddr_t); 3332 mbuf_setlen(mreq, 0); 3333 3334 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 3335 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 3336 } 3337 3338 /* 3339 * Lock a socket against others. 3340 * Currently used to serialize connect/disconnect attempts. 3341 */ 3342 int 3343 newnfs_sndlock(int *flagp) 3344 { 3345 struct timespec ts; 3346 3347 NFSLOCKSOCK(); 3348 while (*flagp & NFSR_SNDLOCK) { 3349 *flagp |= NFSR_WANTSND; 3350 ts.tv_sec = 0; 3351 ts.tv_nsec = 0; 3352 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 3353 PZERO - 1, "nfsndlck", &ts); 3354 } 3355 *flagp |= NFSR_SNDLOCK; 3356 NFSUNLOCKSOCK(); 3357 return (0); 3358 } 3359 3360 /* 3361 * Unlock the stream socket for others. 3362 */ 3363 void 3364 newnfs_sndunlock(int *flagp) 3365 { 3366 3367 NFSLOCKSOCK(); 3368 if ((*flagp & NFSR_SNDLOCK) == 0) 3369 panic("nfs sndunlock"); 3370 *flagp &= ~NFSR_SNDLOCK; 3371 if (*flagp & NFSR_WANTSND) { 3372 *flagp &= ~NFSR_WANTSND; 3373 wakeup((caddr_t)flagp); 3374 } 3375 NFSUNLOCKSOCK(); 3376 } 3377 3378