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 last argument is set to indicate if the call slept, iff not NULL. 1730 */ 1731 APPLESTATIC int 1732 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp, 1733 void *mutex) 1734 { 1735 1736 if (isleptp) 1737 *isleptp = 0; 1738 /* 1739 * If a lock is wanted, loop around until the lock is acquired by 1740 * someone and then released. If I want the lock, try to acquire it. 1741 * For a lock to be issued, no lock must be in force and the usecnt 1742 * must be zero. 1743 */ 1744 if (iwantlock) { 1745 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1746 lp->nfslock_usecnt == 0) { 1747 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1748 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1749 return (1); 1750 } 1751 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED; 1752 } 1753 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) { 1754 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1755 if (isleptp) 1756 *isleptp = 1; 1757 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1758 PZERO - 1, "nfsv4lck", NULL); 1759 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1760 lp->nfslock_usecnt == 0) { 1761 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1762 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1763 return (1); 1764 } 1765 } 1766 return (0); 1767 } 1768 1769 /* 1770 * Release the lock acquired by nfsv4_lock(). 1771 * The second argument is set to 1 to indicate the nfslock_usecnt should be 1772 * incremented, as well. 1773 */ 1774 APPLESTATIC void 1775 nfsv4_unlock(struct nfsv4lock *lp, int incref) 1776 { 1777 1778 lp->nfslock_lock &= ~NFSV4LOCK_LOCK; 1779 if (incref) 1780 lp->nfslock_usecnt++; 1781 nfsv4_wanted(lp); 1782 } 1783 1784 /* 1785 * Release a reference cnt. 1786 */ 1787 APPLESTATIC void 1788 nfsv4_relref(struct nfsv4lock *lp) 1789 { 1790 1791 if (lp->nfslock_usecnt <= 0) 1792 panic("nfsv4root ref cnt"); 1793 lp->nfslock_usecnt--; 1794 if (lp->nfslock_usecnt == 0) 1795 nfsv4_wanted(lp); 1796 } 1797 1798 /* 1799 * Get a reference cnt. 1800 * This function will wait for any exclusive lock to be released, but will 1801 * not wait for threads that want the exclusive lock. If priority needs 1802 * to be given to threads that need the exclusive lock, a call to nfsv4_lock() 1803 * with the 2nd argument == 0 should be done before calling nfsv4_getref(). 1804 */ 1805 APPLESTATIC void 1806 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex) 1807 { 1808 1809 if (isleptp) 1810 *isleptp = 0; 1811 1812 /* 1813 * Wait for a lock held. 1814 */ 1815 while (lp->nfslock_lock & NFSV4LOCK_LOCK) { 1816 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1817 if (isleptp) 1818 *isleptp = 1; 1819 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1820 PZERO - 1, "nfsv4lck", NULL); 1821 } 1822 1823 lp->nfslock_usecnt++; 1824 } 1825 1826 /* 1827 * Get a reference as above, but return failure instead of sleeping if 1828 * an exclusive lock is held. 1829 */ 1830 APPLESTATIC int 1831 nfsv4_getref_nonblock(struct nfsv4lock *lp) 1832 { 1833 1834 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0) 1835 return (0); 1836 1837 lp->nfslock_usecnt++; 1838 return (1); 1839 } 1840 1841 /* 1842 * Test for a lock. Return 1 if locked, 0 otherwise. 1843 */ 1844 APPLESTATIC int 1845 nfsv4_testlock(struct nfsv4lock *lp) 1846 { 1847 1848 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 && 1849 lp->nfslock_usecnt == 0) 1850 return (0); 1851 return (1); 1852 } 1853 1854 /* 1855 * Wake up anyone sleeping, waiting for this lock. 1856 */ 1857 static void 1858 nfsv4_wanted(struct nfsv4lock *lp) 1859 { 1860 1861 if (lp->nfslock_lock & NFSV4LOCK_WANTED) { 1862 lp->nfslock_lock &= ~NFSV4LOCK_WANTED; 1863 wakeup((caddr_t)&lp->nfslock_lock); 1864 } 1865 } 1866 1867 /* 1868 * Copy a string from an mbuf list into a character array. 1869 * Return EBADRPC if there is an mbuf error, 1870 * 0 otherwise. 1871 */ 1872 APPLESTATIC int 1873 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) 1874 { 1875 char *cp; 1876 int xfer, len; 1877 mbuf_t mp; 1878 int rem, error = 0; 1879 1880 mp = nd->nd_md; 1881 cp = nd->nd_dpos; 1882 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp; 1883 rem = NFSM_RNDUP(siz) - siz; 1884 while (siz > 0) { 1885 if (len > siz) 1886 xfer = siz; 1887 else 1888 xfer = len; 1889 NFSBCOPY(cp, str, xfer); 1890 str += xfer; 1891 siz -= xfer; 1892 if (siz > 0) { 1893 mp = mbuf_next(mp); 1894 if (mp == NULL) 1895 return (EBADRPC); 1896 cp = NFSMTOD(mp, caddr_t); 1897 len = mbuf_len(mp); 1898 } else { 1899 cp += xfer; 1900 len -= xfer; 1901 } 1902 } 1903 *str = '\0'; 1904 nd->nd_dpos = cp; 1905 nd->nd_md = mp; 1906 if (rem > 0) { 1907 if (len < rem) 1908 error = nfsm_advance(nd, rem, len); 1909 else 1910 nd->nd_dpos += rem; 1911 } 1912 return (error); 1913 } 1914 1915 /* 1916 * Fill in the attributes as marked by the bitmap (V4). 1917 */ 1918 APPLESTATIC int 1919 nfsv4_fillattr(struct nfsrv_descript *nd, vnode_t vp, NFSACL_T *saclp, 1920 struct vattr *vap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp, 1921 struct ucred *cred, NFSPROC_T *p, int isdgram, int reterr) 1922 { 1923 int bitpos, retnum = 0; 1924 u_int32_t *tl; 1925 int siz, prefixnum, error; 1926 u_char *cp, namestr[NFSV4_SMALLSTR]; 1927 nfsattrbit_t attrbits, retbits; 1928 nfsattrbit_t *retbitp = &retbits; 1929 u_int32_t freenum, *retnump; 1930 u_int64_t uquad; 1931 long fid; 1932 struct statfs fs; 1933 struct nfsfsinfo fsinf; 1934 struct timespec temptime; 1935 struct timeval curtime; 1936 NFSACL_T *aclp, *naclp = NULL; 1937 #ifdef QUOTA 1938 struct dqblk dqb; 1939 uid_t savuid; 1940 #endif 1941 1942 /* 1943 * First, set the bits that can be filled and get fsinfo. 1944 */ 1945 NFSSET_ATTRBIT(retbitp, attrbitp); 1946 /* If p and cred are NULL, it is a client side call */ 1947 if (p == NULL && cred == NULL) { 1948 NFSCLRNOTSETABLE_ATTRBIT(retbitp); 1949 aclp = saclp; 1950 } else { 1951 NFSCLRNOTFILLABLE_ATTRBIT(retbitp); 1952 naclp = acl_alloc(M_WAITOK); 1953 aclp = naclp; 1954 } 1955 nfsvno_getfs(&fsinf, isdgram); 1956 #ifndef APPLE 1957 /* 1958 * Get the VFS_STATFS(), since some attributes need them. 1959 */ 1960 if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 1961 error = VFS_STATFS(vnode_mount(vp), &fs); 1962 if (error != 0) { 1963 if (reterr) { 1964 nd->nd_repstat = NFSERR_ACCES; 1965 return (0); 1966 } 1967 NFSCLRSTATFS_ATTRBIT(retbitp); 1968 } 1969 } 1970 #endif 1971 1972 /* 1973 * And the NFSv4 ACL... 1974 */ 1975 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 1976 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 1977 !NFSHASNFS4ACL(vnode_mount(vp))))) { 1978 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 1979 } 1980 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 1981 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 1982 !NFSHASNFS4ACL(vnode_mount(vp)))) { 1983 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 1984 } else if (naclp != NULL) { 1985 if (vn_lock(vp, LK_SHARED) == 0) { 1986 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); 1987 if (error == 0) 1988 error = VOP_GETACL(vp, ACL_TYPE_NFS4, 1989 naclp, cred, p); 1990 VOP_UNLOCK(vp, 0); 1991 } else 1992 error = NFSERR_PERM; 1993 if (error != 0) { 1994 if (reterr) { 1995 nd->nd_repstat = NFSERR_ACCES; 1996 return (0); 1997 } 1998 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 1999 } 2000 } 2001 } 2002 /* 2003 * Put out the attribute bitmap for the ones being filled in 2004 * and get the field for the number of attributes returned. 2005 */ 2006 prefixnum = nfsrv_putattrbit(nd, retbitp); 2007 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 2008 prefixnum += NFSX_UNSIGNED; 2009 2010 /* 2011 * Now, loop around filling in the attributes for each bit set. 2012 */ 2013 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 2014 if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 2015 switch (bitpos) { 2016 case NFSATTRBIT_SUPPORTEDATTRS: 2017 NFSSETSUPP_ATTRBIT(&attrbits); 2018 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 2019 && !NFSHASNFS4ACL(vnode_mount(vp)))) { 2020 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 2021 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 2022 } 2023 retnum += nfsrv_putattrbit(nd, &attrbits); 2024 break; 2025 case NFSATTRBIT_TYPE: 2026 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2027 *tl = vtonfsv34_type(vap->va_type); 2028 retnum += NFSX_UNSIGNED; 2029 break; 2030 case NFSATTRBIT_FHEXPIRETYPE: 2031 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2032 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2033 retnum += NFSX_UNSIGNED; 2034 break; 2035 case NFSATTRBIT_CHANGE: 2036 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2037 txdr_hyper(vap->va_filerev, tl); 2038 retnum += NFSX_HYPER; 2039 break; 2040 case NFSATTRBIT_SIZE: 2041 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2042 txdr_hyper(vap->va_size, tl); 2043 retnum += NFSX_HYPER; 2044 break; 2045 case NFSATTRBIT_LINKSUPPORT: 2046 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2047 if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2048 *tl = newnfs_true; 2049 else 2050 *tl = newnfs_false; 2051 retnum += NFSX_UNSIGNED; 2052 break; 2053 case NFSATTRBIT_SYMLINKSUPPORT: 2054 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2055 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2056 *tl = newnfs_true; 2057 else 2058 *tl = newnfs_false; 2059 retnum += NFSX_UNSIGNED; 2060 break; 2061 case NFSATTRBIT_NAMEDATTR: 2062 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2063 *tl = newnfs_false; 2064 retnum += NFSX_UNSIGNED; 2065 break; 2066 case NFSATTRBIT_FSID: 2067 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2068 *tl++ = 0; 2069 *tl++=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[0]); 2070 *tl++ = 0; 2071 *tl=txdr_unsigned(vfs_statfs(vnode_mount(vp))->f_fsid.val[1]); 2072 retnum += NFSX_V4FSID; 2073 break; 2074 case NFSATTRBIT_UNIQUEHANDLES: 2075 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2076 *tl = newnfs_true; 2077 retnum += NFSX_UNSIGNED; 2078 break; 2079 case NFSATTRBIT_LEASETIME: 2080 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2081 *tl = txdr_unsigned(nfsrv_lease); 2082 retnum += NFSX_UNSIGNED; 2083 break; 2084 case NFSATTRBIT_RDATTRERROR: 2085 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2086 *tl = txdr_unsigned(rderror); 2087 retnum += NFSX_UNSIGNED; 2088 break; 2089 /* 2090 * Recommended Attributes. (Only the supported ones.) 2091 */ 2092 case NFSATTRBIT_ACL: 2093 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2094 break; 2095 case NFSATTRBIT_ACLSUPPORT: 2096 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2097 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2098 retnum += NFSX_UNSIGNED; 2099 break; 2100 case NFSATTRBIT_CANSETTIME: 2101 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2102 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2103 *tl = newnfs_true; 2104 else 2105 *tl = newnfs_false; 2106 retnum += NFSX_UNSIGNED; 2107 break; 2108 case NFSATTRBIT_CASEINSENSITIVE: 2109 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2110 *tl = newnfs_false; 2111 retnum += NFSX_UNSIGNED; 2112 break; 2113 case NFSATTRBIT_CASEPRESERVING: 2114 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2115 *tl = newnfs_true; 2116 retnum += NFSX_UNSIGNED; 2117 break; 2118 case NFSATTRBIT_CHOWNRESTRICTED: 2119 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2120 *tl = newnfs_true; 2121 retnum += NFSX_UNSIGNED; 2122 break; 2123 case NFSATTRBIT_FILEHANDLE: 2124 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2125 break; 2126 case NFSATTRBIT_FILEID: 2127 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2128 *tl++ = 0; 2129 *tl = txdr_unsigned(vap->va_fileid); 2130 retnum += NFSX_HYPER; 2131 break; 2132 case NFSATTRBIT_FILESAVAIL: 2133 /* 2134 * Check quota and use min(quota, f_ffree). 2135 */ 2136 freenum = fs.f_ffree; 2137 #ifdef QUOTA 2138 /* 2139 * ufs_quotactl() insists that the uid argument 2140 * equal p_ruid for non-root quota access, so 2141 * we'll just make sure that's the case. 2142 */ 2143 savuid = p->p_cred->p_ruid; 2144 p->p_cred->p_ruid = cred->cr_uid; 2145 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), 2146 cred->cr_uid, (caddr_t)&dqb)) 2147 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2148 freenum); 2149 p->p_cred->p_ruid = savuid; 2150 #endif /* QUOTA */ 2151 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2152 *tl++ = 0; 2153 *tl = txdr_unsigned(freenum); 2154 retnum += NFSX_HYPER; 2155 break; 2156 case NFSATTRBIT_FILESFREE: 2157 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2158 *tl++ = 0; 2159 *tl = txdr_unsigned(fs.f_ffree); 2160 retnum += NFSX_HYPER; 2161 break; 2162 case NFSATTRBIT_FILESTOTAL: 2163 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2164 *tl++ = 0; 2165 *tl = txdr_unsigned(fs.f_files); 2166 retnum += NFSX_HYPER; 2167 break; 2168 case NFSATTRBIT_FSLOCATIONS: 2169 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2170 *tl++ = 0; 2171 *tl = 0; 2172 retnum += 2 * NFSX_UNSIGNED; 2173 break; 2174 case NFSATTRBIT_HOMOGENEOUS: 2175 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2176 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2177 *tl = newnfs_true; 2178 else 2179 *tl = newnfs_false; 2180 retnum += NFSX_UNSIGNED; 2181 break; 2182 case NFSATTRBIT_MAXFILESIZE: 2183 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2184 uquad = NFSRV_MAXFILESIZE; 2185 txdr_hyper(uquad, tl); 2186 retnum += NFSX_HYPER; 2187 break; 2188 case NFSATTRBIT_MAXLINK: 2189 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2190 *tl = txdr_unsigned(LINK_MAX); 2191 retnum += NFSX_UNSIGNED; 2192 break; 2193 case NFSATTRBIT_MAXNAME: 2194 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2195 *tl = txdr_unsigned(NFS_MAXNAMLEN); 2196 retnum += NFSX_UNSIGNED; 2197 break; 2198 case NFSATTRBIT_MAXREAD: 2199 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2200 *tl++ = 0; 2201 *tl = txdr_unsigned(fsinf.fs_rtmax); 2202 retnum += NFSX_HYPER; 2203 break; 2204 case NFSATTRBIT_MAXWRITE: 2205 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2206 *tl++ = 0; 2207 *tl = txdr_unsigned(fsinf.fs_wtmax); 2208 retnum += NFSX_HYPER; 2209 break; 2210 case NFSATTRBIT_MODE: 2211 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2212 *tl = vtonfsv34_mode(vap->va_mode); 2213 retnum += NFSX_UNSIGNED; 2214 break; 2215 case NFSATTRBIT_NOTRUNC: 2216 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2217 *tl = newnfs_true; 2218 retnum += NFSX_UNSIGNED; 2219 break; 2220 case NFSATTRBIT_NUMLINKS: 2221 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2222 *tl = txdr_unsigned(vap->va_nlink); 2223 retnum += NFSX_UNSIGNED; 2224 break; 2225 case NFSATTRBIT_OWNER: 2226 cp = namestr; 2227 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); 2228 retnum += nfsm_strtom(nd, cp, siz); 2229 if (cp != namestr) 2230 free(cp, M_NFSSTRING); 2231 break; 2232 case NFSATTRBIT_OWNERGROUP: 2233 cp = namestr; 2234 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); 2235 retnum += nfsm_strtom(nd, cp, siz); 2236 if (cp != namestr) 2237 free(cp, M_NFSSTRING); 2238 break; 2239 case NFSATTRBIT_QUOTAHARD: 2240 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2241 freenum = fs.f_bfree; 2242 else 2243 freenum = fs.f_bavail; 2244 #ifdef QUOTA 2245 /* 2246 * ufs_quotactl() insists that the uid argument 2247 * equal p_ruid for non-root quota access, so 2248 * we'll just make sure that's the case. 2249 */ 2250 savuid = p->p_cred->p_ruid; 2251 p->p_cred->p_ruid = cred->cr_uid; 2252 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), 2253 cred->cr_uid, (caddr_t)&dqb)) 2254 freenum = min(dqb.dqb_bhardlimit, freenum); 2255 p->p_cred->p_ruid = savuid; 2256 #endif /* QUOTA */ 2257 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2258 uquad = (u_int64_t)freenum; 2259 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2260 txdr_hyper(uquad, tl); 2261 retnum += NFSX_HYPER; 2262 break; 2263 case NFSATTRBIT_QUOTASOFT: 2264 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2265 freenum = fs.f_bfree; 2266 else 2267 freenum = fs.f_bavail; 2268 #ifdef QUOTA 2269 /* 2270 * ufs_quotactl() insists that the uid argument 2271 * equal p_ruid for non-root quota access, so 2272 * we'll just make sure that's the case. 2273 */ 2274 savuid = p->p_cred->p_ruid; 2275 p->p_cred->p_ruid = cred->cr_uid; 2276 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), 2277 cred->cr_uid, (caddr_t)&dqb)) 2278 freenum = min(dqb.dqb_bsoftlimit, freenum); 2279 p->p_cred->p_ruid = savuid; 2280 #endif /* QUOTA */ 2281 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2282 uquad = (u_int64_t)freenum; 2283 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2284 txdr_hyper(uquad, tl); 2285 retnum += NFSX_HYPER; 2286 break; 2287 case NFSATTRBIT_QUOTAUSED: 2288 freenum = 0; 2289 #ifdef QUOTA 2290 /* 2291 * ufs_quotactl() insists that the uid argument 2292 * equal p_ruid for non-root quota access, so 2293 * we'll just make sure that's the case. 2294 */ 2295 savuid = p->p_cred->p_ruid; 2296 p->p_cred->p_ruid = cred->cr_uid; 2297 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA,USRQUOTA), 2298 cred->cr_uid, (caddr_t)&dqb)) 2299 freenum = dqb.dqb_curblocks; 2300 p->p_cred->p_ruid = savuid; 2301 #endif /* QUOTA */ 2302 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2303 uquad = (u_int64_t)freenum; 2304 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2305 txdr_hyper(uquad, tl); 2306 retnum += NFSX_HYPER; 2307 break; 2308 case NFSATTRBIT_RAWDEV: 2309 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2310 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2311 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2312 retnum += NFSX_V4SPECDATA; 2313 break; 2314 case NFSATTRBIT_SPACEAVAIL: 2315 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2316 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) 2317 uquad = (u_int64_t)fs.f_bfree; 2318 else 2319 uquad = (u_int64_t)fs.f_bavail; 2320 uquad *= fs.f_bsize; 2321 txdr_hyper(uquad, tl); 2322 retnum += NFSX_HYPER; 2323 break; 2324 case NFSATTRBIT_SPACEFREE: 2325 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2326 uquad = (u_int64_t)fs.f_bfree; 2327 uquad *= fs.f_bsize; 2328 txdr_hyper(uquad, tl); 2329 retnum += NFSX_HYPER; 2330 break; 2331 case NFSATTRBIT_SPACETOTAL: 2332 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2333 uquad = (u_int64_t)fs.f_blocks; 2334 uquad *= fs.f_bsize; 2335 txdr_hyper(uquad, tl); 2336 retnum += NFSX_HYPER; 2337 break; 2338 case NFSATTRBIT_SPACEUSED: 2339 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2340 txdr_hyper(vap->va_bytes, tl); 2341 retnum += NFSX_HYPER; 2342 break; 2343 case NFSATTRBIT_TIMEACCESS: 2344 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2345 txdr_nfsv4time(&vap->va_atime, tl); 2346 retnum += NFSX_V4TIME; 2347 break; 2348 case NFSATTRBIT_TIMEACCESSSET: 2349 NFSGETTIME(&curtime); 2350 if (vap->va_atime.tv_sec != curtime.tv_sec) { 2351 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2352 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2353 txdr_nfsv4time(&vap->va_atime, tl); 2354 retnum += NFSX_V4SETTIME; 2355 } else { 2356 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2357 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2358 retnum += NFSX_UNSIGNED; 2359 } 2360 break; 2361 case NFSATTRBIT_TIMEDELTA: 2362 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2363 temptime.tv_sec = 0; 2364 temptime.tv_nsec = 1000000000 / hz; 2365 txdr_nfsv4time(&temptime, tl); 2366 retnum += NFSX_V4TIME; 2367 break; 2368 case NFSATTRBIT_TIMEMETADATA: 2369 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2370 txdr_nfsv4time(&vap->va_ctime, tl); 2371 retnum += NFSX_V4TIME; 2372 break; 2373 case NFSATTRBIT_TIMEMODIFY: 2374 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2375 txdr_nfsv4time(&vap->va_mtime, tl); 2376 retnum += NFSX_V4TIME; 2377 break; 2378 case NFSATTRBIT_TIMEMODIFYSET: 2379 NFSGETTIME(&curtime); 2380 if (vap->va_mtime.tv_sec != curtime.tv_sec) { 2381 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2382 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2383 txdr_nfsv4time(&vap->va_mtime, tl); 2384 retnum += NFSX_V4SETTIME; 2385 } else { 2386 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2387 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2388 retnum += NFSX_UNSIGNED; 2389 } 2390 break; 2391 case NFSATTRBIT_MOUNTEDONFILEID: 2392 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2393 *tl++ = 0; 2394 if (nfsrv_atroot(vp, &fid)) 2395 *tl = txdr_unsigned(fid); 2396 else 2397 *tl = txdr_unsigned(vap->va_fileid); 2398 retnum += NFSX_HYPER; 2399 break; 2400 default: 2401 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2402 }; 2403 } 2404 } 2405 if (naclp != NULL) 2406 acl_free(naclp); 2407 *retnump = txdr_unsigned(retnum); 2408 return (retnum + prefixnum); 2409 } 2410 2411 /* 2412 * Put the attribute bits onto an mbuf list. 2413 * Return the number of bytes of output generated. 2414 */ 2415 APPLESTATIC int 2416 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 2417 { 2418 u_int32_t *tl; 2419 int cnt, i, bytesize; 2420 2421 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 2422 if (attrbitp->bits[cnt - 1]) 2423 break; 2424 bytesize = (cnt + 1) * NFSX_UNSIGNED; 2425 NFSM_BUILD(tl, u_int32_t *, bytesize); 2426 *tl++ = txdr_unsigned(cnt); 2427 for (i = 0; i < cnt; i++) 2428 *tl++ = txdr_unsigned(attrbitp->bits[i]); 2429 return (bytesize); 2430 } 2431 2432 /* 2433 * Convert a uid to a string. 2434 * If the lookup fails, just output the digits. 2435 * uid - the user id 2436 * cpp - points to a buffer of size NFSV4_SMALLSTR 2437 * (malloc a larger one, as required) 2438 * retlenp - pointer to length to be returned 2439 */ 2440 APPLESTATIC void 2441 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2442 { 2443 int i; 2444 struct nfsusrgrp *usrp; 2445 u_char *cp = *cpp; 2446 uid_t tmp; 2447 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2448 2449 cnt = 0; 2450 tryagain: 2451 NFSLOCKNAMEID(); 2452 if (nfsrv_dnsname) { 2453 /* 2454 * Always map nfsrv_defaultuid to "nobody". 2455 */ 2456 if (uid == nfsrv_defaultuid) { 2457 i = nfsrv_dnsnamelen + 7; 2458 if (i > len) { 2459 NFSUNLOCKNAMEID(); 2460 if (len > NFSV4_SMALLSTR) 2461 free(cp, M_NFSSTRING); 2462 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2463 *cpp = cp; 2464 len = i; 2465 goto tryagain; 2466 } 2467 *retlenp = i; 2468 NFSBCOPY("nobody@", cp, 7); 2469 cp += 7; 2470 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2471 NFSUNLOCKNAMEID(); 2472 return; 2473 } 2474 hasampersand = 0; 2475 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) { 2476 if (usrp->lug_uid == uid) { 2477 if (usrp->lug_expiry < NFSD_MONOSEC) 2478 break; 2479 /* 2480 * If the name doesn't already have an '@' 2481 * in it, append @domainname to it. 2482 */ 2483 for (i = 0; i < usrp->lug_namelen; i++) { 2484 if (usrp->lug_name[i] == '@') { 2485 hasampersand = 1; 2486 break; 2487 } 2488 } 2489 if (hasampersand) 2490 i = usrp->lug_namelen; 2491 else 2492 i = usrp->lug_namelen + 2493 nfsrv_dnsnamelen + 1; 2494 if (i > len) { 2495 NFSUNLOCKNAMEID(); 2496 if (len > NFSV4_SMALLSTR) 2497 free(cp, M_NFSSTRING); 2498 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2499 *cpp = cp; 2500 len = i; 2501 goto tryagain; 2502 } 2503 *retlenp = i; 2504 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2505 if (!hasampersand) { 2506 cp += usrp->lug_namelen; 2507 *cp++ = '@'; 2508 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2509 } 2510 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2511 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2512 NFSUNLOCKNAMEID(); 2513 return; 2514 } 2515 } 2516 NFSUNLOCKNAMEID(); 2517 cnt++; 2518 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2519 NULL, p); 2520 if (ret == 0 && cnt < 2) 2521 goto tryagain; 2522 } else { 2523 NFSUNLOCKNAMEID(); 2524 } 2525 2526 /* 2527 * No match, just return a string of digits. 2528 */ 2529 tmp = uid; 2530 i = 0; 2531 while (tmp || i == 0) { 2532 tmp /= 10; 2533 i++; 2534 } 2535 len = (i > len) ? len : i; 2536 *retlenp = len; 2537 cp += (len - 1); 2538 tmp = uid; 2539 for (i = 0; i < len; i++) { 2540 *cp-- = '0' + (tmp % 10); 2541 tmp /= 10; 2542 } 2543 return; 2544 } 2545 2546 /* 2547 * Convert a string to a uid. 2548 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2549 * return 0. 2550 */ 2551 APPLESTATIC int 2552 nfsv4_strtouid(u_char *str, int len, uid_t *uidp, NFSPROC_T *p) 2553 { 2554 int i; 2555 u_char *cp; 2556 struct nfsusrgrp *usrp; 2557 int cnt, ret; 2558 2559 if (len == 0) 2560 return (NFSERR_BADOWNER); 2561 /* 2562 * Look for an '@'. 2563 */ 2564 cp = str; 2565 for (i = 0; i < len; i++) 2566 if (*cp++ == '@') 2567 break; 2568 2569 cnt = 0; 2570 tryagain: 2571 NFSLOCKNAMEID(); 2572 /* 2573 * If an '@' is found and the domain name matches, search for the name 2574 * with dns stripped off. 2575 * Mixed case alpahbetics will match for the domain name, but all 2576 * upper case will not. 2577 */ 2578 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2579 (len - 1 - i) == nfsrv_dnsnamelen && 2580 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2581 len -= (nfsrv_dnsnamelen + 1); 2582 *(cp - 1) = '\0'; 2583 } 2584 2585 /* 2586 * Check for the special case of "nobody". 2587 */ 2588 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 2589 *uidp = nfsrv_defaultuid; 2590 NFSUNLOCKNAMEID(); 2591 return (0); 2592 } 2593 2594 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) { 2595 if (usrp->lug_namelen == len && 2596 !NFSBCMP(usrp->lug_name, str, len)) { 2597 if (usrp->lug_expiry < NFSD_MONOSEC) 2598 break; 2599 *uidp = usrp->lug_uid; 2600 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2601 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2602 NFSUNLOCKNAMEID(); 2603 return (0); 2604 } 2605 } 2606 NFSUNLOCKNAMEID(); 2607 cnt++; 2608 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 2609 str, p); 2610 if (ret == 0 && cnt < 2) 2611 goto tryagain; 2612 return (NFSERR_BADOWNER); 2613 } 2614 2615 /* 2616 * Convert a gid to a string. 2617 * gid - the group id 2618 * cpp - points to a buffer of size NFSV4_SMALLSTR 2619 * (malloc a larger one, as required) 2620 * retlenp - pointer to length to be returned 2621 */ 2622 APPLESTATIC void 2623 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2624 { 2625 int i; 2626 struct nfsusrgrp *usrp; 2627 u_char *cp = *cpp; 2628 gid_t tmp; 2629 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2630 2631 cnt = 0; 2632 tryagain: 2633 NFSLOCKNAMEID(); 2634 if (nfsrv_dnsname) { 2635 /* 2636 * Always map nfsrv_defaultgid to "nogroup". 2637 */ 2638 if (gid == nfsrv_defaultgid) { 2639 i = nfsrv_dnsnamelen + 8; 2640 if (i > len) { 2641 NFSUNLOCKNAMEID(); 2642 if (len > NFSV4_SMALLSTR) 2643 free(cp, M_NFSSTRING); 2644 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2645 *cpp = cp; 2646 len = i; 2647 goto tryagain; 2648 } 2649 *retlenp = i; 2650 NFSBCOPY("nogroup@", cp, 8); 2651 cp += 8; 2652 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2653 NFSUNLOCKNAMEID(); 2654 return; 2655 } 2656 hasampersand = 0; 2657 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) { 2658 if (usrp->lug_gid == gid) { 2659 if (usrp->lug_expiry < NFSD_MONOSEC) 2660 break; 2661 /* 2662 * If the name doesn't already have an '@' 2663 * in it, append @domainname to it. 2664 */ 2665 for (i = 0; i < usrp->lug_namelen; i++) { 2666 if (usrp->lug_name[i] == '@') { 2667 hasampersand = 1; 2668 break; 2669 } 2670 } 2671 if (hasampersand) 2672 i = usrp->lug_namelen; 2673 else 2674 i = usrp->lug_namelen + 2675 nfsrv_dnsnamelen + 1; 2676 if (i > len) { 2677 NFSUNLOCKNAMEID(); 2678 if (len > NFSV4_SMALLSTR) 2679 free(cp, M_NFSSTRING); 2680 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2681 *cpp = cp; 2682 len = i; 2683 goto tryagain; 2684 } 2685 *retlenp = i; 2686 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2687 if (!hasampersand) { 2688 cp += usrp->lug_namelen; 2689 *cp++ = '@'; 2690 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2691 } 2692 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2693 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2694 NFSUNLOCKNAMEID(); 2695 return; 2696 } 2697 } 2698 NFSUNLOCKNAMEID(); 2699 cnt++; 2700 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, 2701 NULL, p); 2702 if (ret == 0 && cnt < 2) 2703 goto tryagain; 2704 } else { 2705 NFSUNLOCKNAMEID(); 2706 } 2707 2708 /* 2709 * No match, just return a string of digits. 2710 */ 2711 tmp = gid; 2712 i = 0; 2713 while (tmp || i == 0) { 2714 tmp /= 10; 2715 i++; 2716 } 2717 len = (i > len) ? len : i; 2718 *retlenp = len; 2719 cp += (len - 1); 2720 tmp = gid; 2721 for (i = 0; i < len; i++) { 2722 *cp-- = '0' + (tmp % 10); 2723 tmp /= 10; 2724 } 2725 return; 2726 } 2727 2728 /* 2729 * Convert a string to a gid. 2730 */ 2731 APPLESTATIC int 2732 nfsv4_strtogid(u_char *str, int len, gid_t *gidp, NFSPROC_T *p) 2733 { 2734 int i; 2735 u_char *cp; 2736 struct nfsusrgrp *usrp; 2737 int cnt, ret; 2738 2739 if (len == 0) 2740 return (NFSERR_BADOWNER); 2741 /* 2742 * Look for an '@'. 2743 */ 2744 cp = str; 2745 for (i = 0; i < len; i++) 2746 if (*cp++ == '@') 2747 break; 2748 2749 cnt = 0; 2750 tryagain: 2751 NFSLOCKNAMEID(); 2752 /* 2753 * If an '@' is found and the dns name matches, search for the name 2754 * with the dns stripped off. 2755 */ 2756 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2757 (len - 1 - i) == nfsrv_dnsnamelen && 2758 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2759 len -= (nfsrv_dnsnamelen + 1); 2760 *(cp - 1) = '\0'; 2761 } 2762 2763 /* 2764 * Check for the special case of "nogroup". 2765 */ 2766 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 2767 *gidp = nfsrv_defaultgid; 2768 NFSUNLOCKNAMEID(); 2769 return (0); 2770 } 2771 2772 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) { 2773 if (usrp->lug_namelen == len && 2774 !NFSBCMP(usrp->lug_name, str, len)) { 2775 if (usrp->lug_expiry < NFSD_MONOSEC) 2776 break; 2777 *gidp = usrp->lug_gid; 2778 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2779 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2780 NFSUNLOCKNAMEID(); 2781 return (0); 2782 } 2783 } 2784 NFSUNLOCKNAMEID(); 2785 cnt++; 2786 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 2787 str, p); 2788 if (ret == 0 && cnt < 2) 2789 goto tryagain; 2790 return (NFSERR_BADOWNER); 2791 } 2792 2793 /* 2794 * Cmp len chars, allowing mixed case in the first argument to match lower 2795 * case in the second, but not if the first argument is all upper case. 2796 * Return 0 for a match, 1 otherwise. 2797 */ 2798 static int 2799 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 2800 { 2801 int i; 2802 u_char tmp; 2803 int fndlower = 0; 2804 2805 for (i = 0; i < len; i++) { 2806 if (*cp >= 'A' && *cp <= 'Z') { 2807 tmp = *cp++ + ('a' - 'A'); 2808 } else { 2809 tmp = *cp++; 2810 if (tmp >= 'a' && tmp <= 'z') 2811 fndlower = 1; 2812 } 2813 if (tmp != *cp2++) 2814 return (1); 2815 } 2816 if (fndlower) 2817 return (0); 2818 else 2819 return (1); 2820 } 2821 2822 /* 2823 * Set the port for the nfsuserd. 2824 */ 2825 APPLESTATIC int 2826 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p) 2827 { 2828 struct nfssockreq *rp; 2829 struct sockaddr_in *ad; 2830 int error; 2831 2832 NFSLOCKNAMEID(); 2833 if (nfsrv_nfsuserd) { 2834 NFSUNLOCKNAMEID(); 2835 return (EPERM); 2836 } 2837 nfsrv_nfsuserd = 1; 2838 NFSUNLOCKNAMEID(); 2839 /* 2840 * Set up the socket record and connect. 2841 */ 2842 rp = &nfsrv_nfsuserdsock; 2843 rp->nr_client = NULL; 2844 rp->nr_sotype = SOCK_DGRAM; 2845 rp->nr_soproto = IPPROTO_UDP; 2846 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 2847 rp->nr_cred = NULL; 2848 NFSSOCKADDRALLOC(rp->nr_nam); 2849 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in)); 2850 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *); 2851 ad->sin_family = AF_INET; 2852 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */ 2853 ad->sin_port = port; 2854 rp->nr_prog = RPCPROG_NFSUSERD; 2855 rp->nr_vers = RPCNFSUSERD_VERS; 2856 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 2857 if (error) { 2858 NFSSOCKADDRFREE(rp->nr_nam); 2859 nfsrv_nfsuserd = 0; 2860 } 2861 return (error); 2862 } 2863 2864 /* 2865 * Delete the nfsuserd port. 2866 */ 2867 APPLESTATIC void 2868 nfsrv_nfsuserddelport(void) 2869 { 2870 2871 NFSLOCKNAMEID(); 2872 if (nfsrv_nfsuserd == 0) { 2873 NFSUNLOCKNAMEID(); 2874 return; 2875 } 2876 nfsrv_nfsuserd = 0; 2877 NFSUNLOCKNAMEID(); 2878 newnfs_disconnect(&nfsrv_nfsuserdsock); 2879 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); 2880 } 2881 2882 /* 2883 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 2884 * name<-->id cache. 2885 * Returns 0 upon success, non-zero otherwise. 2886 */ 2887 static int 2888 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) 2889 { 2890 u_int32_t *tl; 2891 struct nfsrv_descript *nd; 2892 int len; 2893 struct nfsrv_descript nfsd; 2894 struct ucred *cred; 2895 int error; 2896 2897 NFSLOCKNAMEID(); 2898 if (nfsrv_nfsuserd == 0) { 2899 NFSUNLOCKNAMEID(); 2900 return (EPERM); 2901 } 2902 NFSUNLOCKNAMEID(); 2903 nd = &nfsd; 2904 cred = newnfs_getcred(); 2905 nd->nd_flag = ND_GSSINITREPLY; 2906 nfsrvd_rephead(nd); 2907 2908 nd->nd_procnum = procnum; 2909 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 2910 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2911 if (procnum == RPCNFSUSERD_GETUID) 2912 *tl = txdr_unsigned(uid); 2913 else 2914 *tl = txdr_unsigned(gid); 2915 } else { 2916 len = strlen(name); 2917 (void) nfsm_strtom(nd, name, len); 2918 } 2919 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 2920 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL); 2921 NFSFREECRED(cred); 2922 if (!error) { 2923 mbuf_freem(nd->nd_mrep); 2924 error = nd->nd_repstat; 2925 } 2926 return (error); 2927 } 2928 2929 /* 2930 * This function is called from the nfssvc(2) system call, to update the 2931 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 2932 */ 2933 APPLESTATIC int 2934 nfssvc_idname(struct nfsd_idargs *nidp) 2935 { 2936 struct nfsusrgrp *nusrp, *usrp, *newusrp; 2937 struct nfsuserhashhead *hp; 2938 int i; 2939 int error = 0; 2940 u_char *cp; 2941 2942 if (nidp->nid_flag & NFSID_INITIALIZE) { 2943 cp = (u_char *)malloc(nidp->nid_namelen + 1, 2944 M_NFSSTRING, M_WAITOK); 2945 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 2946 nidp->nid_namelen); 2947 NFSLOCKNAMEID(); 2948 if (nfsrv_dnsname) { 2949 /* 2950 * Free up all the old stuff and reinitialize hash lists. 2951 */ 2952 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 2953 nfsrv_removeuser(usrp); 2954 } 2955 free(nfsrv_dnsname, M_NFSSTRING); 2956 nfsrv_dnsname = NULL; 2957 } 2958 TAILQ_INIT(&nfsuserlruhead); 2959 for (i = 0; i < NFSUSERHASHSIZE; i++) 2960 LIST_INIT(&nfsuserhash[i]); 2961 for (i = 0; i < NFSGROUPHASHSIZE; i++) 2962 LIST_INIT(&nfsgrouphash[i]); 2963 for (i = 0; i < NFSUSERHASHSIZE; i++) 2964 LIST_INIT(&nfsusernamehash[i]); 2965 for (i = 0; i < NFSGROUPHASHSIZE; i++) 2966 LIST_INIT(&nfsgroupnamehash[i]); 2967 2968 /* 2969 * Put name in "DNS" string. 2970 */ 2971 if (!error) { 2972 nfsrv_dnsname = cp; 2973 nfsrv_dnsnamelen = nidp->nid_namelen; 2974 nfsrv_defaultuid = nidp->nid_uid; 2975 nfsrv_defaultgid = nidp->nid_gid; 2976 nfsrv_usercnt = 0; 2977 nfsrv_usermax = nidp->nid_usermax; 2978 } 2979 NFSUNLOCKNAMEID(); 2980 if (error) 2981 free(cp, M_NFSSTRING); 2982 return (error); 2983 } 2984 2985 /* 2986 * malloc the new one now, so any potential sleep occurs before 2987 * manipulation of the lists. 2988 */ 2989 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) + 2990 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK); 2991 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 2992 nidp->nid_namelen); 2993 if (error) { 2994 free((caddr_t)newusrp, M_NFSUSERGROUP); 2995 return (error); 2996 } 2997 newusrp->lug_namelen = nidp->nid_namelen; 2998 2999 NFSLOCKNAMEID(); 3000 /* 3001 * Delete old entries, as required. 3002 */ 3003 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3004 hp = NFSUSERHASH(nidp->nid_uid); 3005 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 3006 if (usrp->lug_uid == nidp->nid_uid) 3007 nfsrv_removeuser(usrp); 3008 } 3009 } 3010 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3011 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3012 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 3013 if (usrp->lug_namelen == newusrp->lug_namelen && 3014 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3015 usrp->lug_namelen)) 3016 nfsrv_removeuser(usrp); 3017 } 3018 } 3019 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3020 hp = NFSGROUPHASH(nidp->nid_gid); 3021 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 3022 if (usrp->lug_gid == nidp->nid_gid) 3023 nfsrv_removeuser(usrp); 3024 } 3025 } 3026 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3027 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3028 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 3029 if (usrp->lug_namelen == newusrp->lug_namelen && 3030 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3031 usrp->lug_namelen)) 3032 nfsrv_removeuser(usrp); 3033 } 3034 } 3035 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 3036 if (usrp->lug_expiry < NFSD_MONOSEC) 3037 nfsrv_removeuser(usrp); 3038 } 3039 while (nfsrv_usercnt >= nfsrv_usermax) { 3040 usrp = TAILQ_FIRST(&nfsuserlruhead); 3041 nfsrv_removeuser(usrp); 3042 } 3043 3044 /* 3045 * Now, we can add the new one. 3046 */ 3047 if (nidp->nid_usertimeout) 3048 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3049 else 3050 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3051 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3052 newusrp->lug_uid = nidp->nid_uid; 3053 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp, 3054 lug_numhash); 3055 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name, 3056 newusrp->lug_namelen), newusrp, lug_namehash); 3057 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3058 nfsrv_usercnt++; 3059 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3060 newusrp->lug_gid = nidp->nid_gid; 3061 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp, 3062 lug_numhash); 3063 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name, 3064 newusrp->lug_namelen), newusrp, lug_namehash); 3065 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3066 nfsrv_usercnt++; 3067 } else 3068 FREE((caddr_t)newusrp, M_NFSUSERGROUP); 3069 NFSUNLOCKNAMEID(); 3070 return (error); 3071 } 3072 3073 /* 3074 * Remove a user/group name element. 3075 */ 3076 static void 3077 nfsrv_removeuser(struct nfsusrgrp *usrp) 3078 { 3079 3080 NFSNAMEIDREQUIRED(); 3081 LIST_REMOVE(usrp, lug_numhash); 3082 LIST_REMOVE(usrp, lug_namehash); 3083 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 3084 nfsrv_usercnt--; 3085 FREE((caddr_t)usrp, M_NFSUSERGROUP); 3086 } 3087 3088 /* 3089 * This function scans a byte string and checks for UTF-8 compliance. 3090 * It returns 0 if it conforms and NFSERR_INVAL if not. 3091 */ 3092 APPLESTATIC int 3093 nfsrv_checkutf8(u_int8_t *cp, int len) 3094 { 3095 u_int32_t val = 0x0; 3096 int cnt = 0, gotd = 0, shift = 0; 3097 u_int8_t byte; 3098 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 3099 3100 /* 3101 * Here are what the variables are used for: 3102 * val - the calculated value of a multibyte char, used to check 3103 * that it was coded with the correct range 3104 * cnt - the number of 10xxxxxx bytes to follow 3105 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 3106 * shift - lower order bits of range (ie. "val >> shift" should 3107 * not be 0, in other words, dividing by the lower bound 3108 * of the range should get a non-zero value) 3109 * byte - used to calculate cnt 3110 */ 3111 while (len > 0) { 3112 if (cnt > 0) { 3113 /* This handles the 10xxxxxx bytes */ 3114 if ((*cp & 0xc0) != 0x80 || 3115 (gotd && (*cp & 0x20))) 3116 return (NFSERR_INVAL); 3117 gotd = 0; 3118 val <<= 6; 3119 val |= (*cp & 0x3f); 3120 cnt--; 3121 if (cnt == 0 && (val >> shift) == 0x0) 3122 return (NFSERR_INVAL); 3123 } else if (*cp & 0x80) { 3124 /* first byte of multi byte char */ 3125 byte = *cp; 3126 while ((byte & 0x40) && cnt < 6) { 3127 cnt++; 3128 byte <<= 1; 3129 } 3130 if (cnt == 0 || cnt == 6) 3131 return (NFSERR_INVAL); 3132 val = (*cp & (0x3f >> cnt)); 3133 shift = utf8_shift[cnt - 1]; 3134 if (cnt == 2 && val == 0xd) 3135 /* Check for the 0xd800-0xdfff case */ 3136 gotd = 1; 3137 } 3138 cp++; 3139 len--; 3140 } 3141 if (cnt > 0) 3142 return (NFSERR_INVAL); 3143 return (0); 3144 } 3145 3146 /* 3147 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 3148 * strings, one with the root path in it and the other with the list of 3149 * locations. The list is in the same format as is found in nfr_refs. 3150 * It is a "," separated list of entries, where each of them is of the 3151 * form <server>:<rootpath>. For example 3152 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 3153 * The nilp argument is set to 1 for the special case of a null fs_root 3154 * and an empty server list. 3155 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 3156 * number of xdr bytes parsed in sump. 3157 */ 3158 static int 3159 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 3160 int *sump, int *nilp) 3161 { 3162 u_int32_t *tl; 3163 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 3164 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error, nsrv; 3165 struct list { 3166 SLIST_ENTRY(list) next; 3167 int len; 3168 u_char host[1]; 3169 } *lsp, *nlsp; 3170 SLIST_HEAD(, list) head; 3171 3172 *fsrootp = NULL; 3173 *srvp = NULL; 3174 *nilp = 0; 3175 3176 /* 3177 * Get the fs_root path and check for the special case of null path 3178 * and 0 length server list. 3179 */ 3180 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3181 len = fxdr_unsigned(int, *tl); 3182 if (len < 0 || len > 10240) 3183 return (NFSERR_BADXDR); 3184 if (len == 0) { 3185 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3186 if (*tl != 0) 3187 return (NFSERR_BADXDR); 3188 *nilp = 1; 3189 *sump = 2 * NFSX_UNSIGNED; 3190 return (0); 3191 } 3192 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 3193 error = nfsrv_mtostr(nd, cp, len); 3194 if (!error) { 3195 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3196 cnt = fxdr_unsigned(int, *tl); 3197 if (cnt <= 0) 3198 error = NFSERR_BADXDR; 3199 } 3200 if (error) { 3201 free(cp, M_NFSSTRING); 3202 return (error); 3203 } 3204 3205 /* 3206 * Now, loop through the location list and make up the srvlist. 3207 */ 3208 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3209 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 3210 slen = 1024; 3211 siz = 0; 3212 for (i = 0; i < cnt; i++) { 3213 SLIST_INIT(&head); 3214 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3215 nsrv = fxdr_unsigned(int, *tl); 3216 if (nsrv <= 0) { 3217 free(cp, M_NFSSTRING); 3218 free(cp2, M_NFSSTRING); 3219 return (NFSERR_BADXDR); 3220 } 3221 3222 /* 3223 * Handle the first server by putting it in the srvstr. 3224 */ 3225 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3226 len = fxdr_unsigned(int, *tl); 3227 if (len <= 0 || len > 1024) { 3228 free(cp, M_NFSSTRING); 3229 free(cp2, M_NFSSTRING); 3230 return (NFSERR_BADXDR); 3231 } 3232 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 3233 if (cp3 != cp2) { 3234 *cp3++ = ','; 3235 siz++; 3236 } 3237 error = nfsrv_mtostr(nd, cp3, len); 3238 if (error) { 3239 free(cp, M_NFSSTRING); 3240 free(cp2, M_NFSSTRING); 3241 return (error); 3242 } 3243 cp3 += len; 3244 *cp3++ = ':'; 3245 siz += (len + 1); 3246 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3247 for (j = 1; j < nsrv; j++) { 3248 /* 3249 * Yuck, put them in an slist and process them later. 3250 */ 3251 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3252 len = fxdr_unsigned(int, *tl); 3253 if (len <= 0 || len > 1024) { 3254 free(cp, M_NFSSTRING); 3255 free(cp2, M_NFSSTRING); 3256 return (NFSERR_BADXDR); 3257 } 3258 lsp = (struct list *)malloc(sizeof (struct list) 3259 + len, M_TEMP, M_WAITOK); 3260 error = nfsrv_mtostr(nd, lsp->host, len); 3261 if (error) { 3262 free(cp, M_NFSSTRING); 3263 free(cp2, M_NFSSTRING); 3264 return (error); 3265 } 3266 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3267 lsp->len = len; 3268 SLIST_INSERT_HEAD(&head, lsp, next); 3269 } 3270 3271 /* 3272 * Finally, we can get the path. 3273 */ 3274 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3275 len = fxdr_unsigned(int, *tl); 3276 if (len <= 0 || len > 1024) { 3277 free(cp, M_NFSSTRING); 3278 free(cp2, M_NFSSTRING); 3279 return (NFSERR_BADXDR); 3280 } 3281 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 3282 error = nfsrv_mtostr(nd, cp3, len); 3283 if (error) { 3284 free(cp, M_NFSSTRING); 3285 free(cp2, M_NFSSTRING); 3286 return (error); 3287 } 3288 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3289 str = cp3; 3290 stringlen = len; 3291 cp3 += len; 3292 siz += len; 3293 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 3294 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 3295 &cp2, &cp3, &slen); 3296 *cp3++ = ','; 3297 NFSBCOPY(lsp->host, cp3, lsp->len); 3298 cp3 += lsp->len; 3299 *cp3++ = ':'; 3300 NFSBCOPY(str, cp3, stringlen); 3301 cp3 += stringlen; 3302 *cp3 = '\0'; 3303 siz += (lsp->len + stringlen + 2); 3304 free((caddr_t)lsp, M_TEMP); 3305 } 3306 } 3307 *fsrootp = cp; 3308 *srvp = cp2; 3309 *sump = xdrsum; 3310 return (0); 3311 nfsmout: 3312 if (cp != NULL) 3313 free(cp, M_NFSSTRING); 3314 if (cp2 != NULL) 3315 free(cp2, M_NFSSTRING); 3316 return (error); 3317 } 3318 3319 /* 3320 * Make the malloc'd space large enough. This is a pain, but the xdr 3321 * doesn't set an upper bound on the side, so... 3322 */ 3323 static void 3324 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 3325 { 3326 u_char *cp; 3327 int i; 3328 3329 if (siz <= *slenp) 3330 return; 3331 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 3332 NFSBCOPY(*cpp, cp, *slenp); 3333 free(*cpp, M_NFSSTRING); 3334 i = *cpp2 - *cpp; 3335 *cpp = cp; 3336 *cpp2 = cp + i; 3337 *slenp = siz + 1024; 3338 } 3339 3340 /* 3341 * Initialize the reply header data structures. 3342 */ 3343 APPLESTATIC void 3344 nfsrvd_rephead(struct nfsrv_descript *nd) 3345 { 3346 mbuf_t mreq; 3347 3348 /* 3349 * If this is a big reply, use a cluster. 3350 */ 3351 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 3352 nfs_bigreply[nd->nd_procnum]) { 3353 NFSMCLGET(mreq, M_WAIT); 3354 nd->nd_mreq = mreq; 3355 nd->nd_mb = mreq; 3356 } else { 3357 NFSMGET(mreq); 3358 nd->nd_mreq = mreq; 3359 nd->nd_mb = mreq; 3360 } 3361 nd->nd_bpos = NFSMTOD(mreq, caddr_t); 3362 mbuf_setlen(mreq, 0); 3363 3364 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 3365 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 3366 } 3367 3368 /* 3369 * Lock a socket against others. 3370 * Currently used to serialize connect/disconnect attempts. 3371 */ 3372 int 3373 newnfs_sndlock(int *flagp) 3374 { 3375 struct timespec ts; 3376 3377 NFSLOCKSOCK(); 3378 while (*flagp & NFSR_SNDLOCK) { 3379 *flagp |= NFSR_WANTSND; 3380 ts.tv_sec = 0; 3381 ts.tv_nsec = 0; 3382 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 3383 PZERO - 1, "nfsndlck", &ts); 3384 } 3385 *flagp |= NFSR_SNDLOCK; 3386 NFSUNLOCKSOCK(); 3387 return (0); 3388 } 3389 3390 /* 3391 * Unlock the stream socket for others. 3392 */ 3393 void 3394 newnfs_sndunlock(int *flagp) 3395 { 3396 3397 NFSLOCKSOCK(); 3398 if ((*flagp & NFSR_SNDLOCK) == 0) 3399 panic("nfs sndunlock"); 3400 *flagp &= ~NFSR_SNDLOCK; 3401 if (*flagp & NFSR_WANTSND) { 3402 *flagp &= ~NFSR_WANTSND; 3403 wakeup((caddr_t)flagp); 3404 } 3405 NFSUNLOCKSOCK(); 3406 } 3407 3408