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