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