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