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