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