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