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