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 if (compare) { 831 retnotsup = 0; 832 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); 833 } else { 834 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 835 } 836 if (error) 837 goto nfsmout; 838 839 if (compare) { 840 *retcmpp = retnotsup; 841 } else { 842 /* 843 * Just set default values to some of the important ones. 844 */ 845 if (nap != NULL) { 846 nap->na_type = VREG; 847 nap->na_mode = 0; 848 nap->na_rdev = (NFSDEV_T)0; 849 nap->na_mtime.tv_sec = 0; 850 nap->na_mtime.tv_nsec = 0; 851 nap->na_gen = 0; 852 nap->na_flags = 0; 853 nap->na_blocksize = NFS_FABLKSIZE; 854 } 855 if (sbp != NULL) { 856 sbp->f_bsize = NFS_FABLKSIZE; 857 sbp->f_blocks = 0; 858 sbp->f_bfree = 0; 859 sbp->f_bavail = 0; 860 sbp->f_files = 0; 861 sbp->f_ffree = 0; 862 } 863 if (fsp != NULL) { 864 fsp->fs_rtmax = 8192; 865 fsp->fs_rtpref = 8192; 866 fsp->fs_maxname = NFS_MAXNAMLEN; 867 fsp->fs_wtmax = 8192; 868 fsp->fs_wtpref = 8192; 869 fsp->fs_wtmult = NFS_FABLKSIZE; 870 fsp->fs_dtpref = 8192; 871 fsp->fs_maxfilesize = 0xffffffffffffffffull; 872 fsp->fs_timedelta.tv_sec = 0; 873 fsp->fs_timedelta.tv_nsec = 1; 874 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK | 875 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME); 876 } 877 if (pc != NULL) { 878 pc->pc_linkmax = LINK_MAX; 879 pc->pc_namemax = NAME_MAX; 880 pc->pc_notrunc = 0; 881 pc->pc_chownrestricted = 0; 882 pc->pc_caseinsensitive = 0; 883 pc->pc_casepreserving = 1; 884 } 885 } 886 887 /* 888 * Loop around getting the attributes. 889 */ 890 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 891 attrsize = fxdr_unsigned(int, *tl); 892 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 893 if (attrsum > attrsize) { 894 error = NFSERR_BADXDR; 895 goto nfsmout; 896 } 897 if (NFSISSET_ATTRBIT(&attrbits, bitpos)) 898 switch (bitpos) { 899 case NFSATTRBIT_SUPPORTEDATTRS: 900 retnotsup = 0; 901 if (compare || nap == NULL) 902 error = nfsrv_getattrbits(nd, &retattrbits, 903 &cnt, &retnotsup); 904 else 905 error = nfsrv_getattrbits(nd, &nap->na_suppattr, 906 &cnt, &retnotsup); 907 if (error) 908 goto nfsmout; 909 if (compare && !(*retcmpp)) { 910 NFSSETSUPP_ATTRBIT(&checkattrbits); 911 912 /* Some filesystem do not support NFSv4ACL */ 913 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) { 914 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL); 915 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT); 916 } 917 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 918 || retnotsup) 919 *retcmpp = NFSERR_NOTSAME; 920 } 921 attrsum += cnt; 922 break; 923 case NFSATTRBIT_TYPE: 924 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 925 if (compare) { 926 if (!(*retcmpp)) { 927 if (nap->na_type != nfsv34tov_type(*tl)) 928 *retcmpp = NFSERR_NOTSAME; 929 } 930 } else if (nap != NULL) { 931 nap->na_type = nfsv34tov_type(*tl); 932 } 933 attrsum += NFSX_UNSIGNED; 934 break; 935 case NFSATTRBIT_FHEXPIRETYPE: 936 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 937 if (compare && !(*retcmpp)) { 938 if (fxdr_unsigned(int, *tl) != 939 NFSV4FHTYPE_PERSISTENT) 940 *retcmpp = NFSERR_NOTSAME; 941 } 942 attrsum += NFSX_UNSIGNED; 943 break; 944 case NFSATTRBIT_CHANGE: 945 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 946 if (compare) { 947 if (!(*retcmpp)) { 948 if (nap->na_filerev != fxdr_hyper(tl)) 949 *retcmpp = NFSERR_NOTSAME; 950 } 951 } else if (nap != NULL) { 952 nap->na_filerev = fxdr_hyper(tl); 953 } 954 attrsum += NFSX_HYPER; 955 break; 956 case NFSATTRBIT_SIZE: 957 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 958 if (compare) { 959 if (!(*retcmpp)) { 960 if (nap->na_size != fxdr_hyper(tl)) 961 *retcmpp = NFSERR_NOTSAME; 962 } 963 } else if (nap != NULL) { 964 nap->na_size = fxdr_hyper(tl); 965 } 966 attrsum += NFSX_HYPER; 967 break; 968 case NFSATTRBIT_LINKSUPPORT: 969 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 970 if (compare) { 971 if (!(*retcmpp)) { 972 if (fsp->fs_properties & NFSV3_FSFLINK) { 973 if (*tl == newnfs_false) 974 *retcmpp = NFSERR_NOTSAME; 975 } else { 976 if (*tl == newnfs_true) 977 *retcmpp = NFSERR_NOTSAME; 978 } 979 } 980 } else if (fsp != NULL) { 981 if (*tl == newnfs_true) 982 fsp->fs_properties |= NFSV3_FSFLINK; 983 else 984 fsp->fs_properties &= ~NFSV3_FSFLINK; 985 } 986 attrsum += NFSX_UNSIGNED; 987 break; 988 case NFSATTRBIT_SYMLINKSUPPORT: 989 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 990 if (compare) { 991 if (!(*retcmpp)) { 992 if (fsp->fs_properties & NFSV3_FSFSYMLINK) { 993 if (*tl == newnfs_false) 994 *retcmpp = NFSERR_NOTSAME; 995 } else { 996 if (*tl == newnfs_true) 997 *retcmpp = NFSERR_NOTSAME; 998 } 999 } 1000 } else if (fsp != NULL) { 1001 if (*tl == newnfs_true) 1002 fsp->fs_properties |= NFSV3_FSFSYMLINK; 1003 else 1004 fsp->fs_properties &= ~NFSV3_FSFSYMLINK; 1005 } 1006 attrsum += NFSX_UNSIGNED; 1007 break; 1008 case NFSATTRBIT_NAMEDATTR: 1009 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1010 if (compare && !(*retcmpp)) { 1011 if (*tl != newnfs_false) 1012 *retcmpp = NFSERR_NOTSAME; 1013 } 1014 attrsum += NFSX_UNSIGNED; 1015 break; 1016 case NFSATTRBIT_FSID: 1017 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1018 thyp = fxdr_hyper(tl); 1019 tl += 2; 1020 thyp2 = fxdr_hyper(tl); 1021 if (compare) { 1022 if (*retcmpp == 0) { 1023 if (thyp != (u_int64_t) 1024 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] || 1025 thyp2 != (u_int64_t) 1026 vfs_statfs(vnode_mount(vp))->f_fsid.val[1]) 1027 *retcmpp = NFSERR_NOTSAME; 1028 } 1029 } else if (nap != NULL) { 1030 nap->na_filesid[0] = thyp; 1031 nap->na_filesid[1] = thyp2; 1032 } 1033 attrsum += (4 * NFSX_UNSIGNED); 1034 break; 1035 case NFSATTRBIT_UNIQUEHANDLES: 1036 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1037 if (compare && !(*retcmpp)) { 1038 if (*tl != newnfs_true) 1039 *retcmpp = NFSERR_NOTSAME; 1040 } 1041 attrsum += NFSX_UNSIGNED; 1042 break; 1043 case NFSATTRBIT_LEASETIME: 1044 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1045 if (compare) { 1046 if (fxdr_unsigned(int, *tl) != nfsrv_lease && 1047 !(*retcmpp)) 1048 *retcmpp = NFSERR_NOTSAME; 1049 } else if (leasep != NULL) { 1050 *leasep = fxdr_unsigned(u_int32_t, *tl); 1051 } 1052 attrsum += NFSX_UNSIGNED; 1053 break; 1054 case NFSATTRBIT_RDATTRERROR: 1055 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1056 if (compare) { 1057 if (!(*retcmpp)) 1058 *retcmpp = NFSERR_INVAL; 1059 } else if (rderrp != NULL) { 1060 *rderrp = fxdr_unsigned(u_int32_t, *tl); 1061 } 1062 attrsum += NFSX_UNSIGNED; 1063 break; 1064 case NFSATTRBIT_ACL: 1065 if (compare) { 1066 if (!(*retcmpp)) { 1067 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) { 1068 NFSACL_T *naclp; 1069 1070 naclp = acl_alloc(M_WAITOK); 1071 error = nfsrv_dissectacl(nd, naclp, &aceerr, 1072 &cnt, p); 1073 if (error) { 1074 acl_free(naclp); 1075 goto nfsmout; 1076 } 1077 if (aceerr || aclp == NULL || 1078 nfsrv_compareacl(aclp, naclp)) 1079 *retcmpp = NFSERR_NOTSAME; 1080 acl_free(naclp); 1081 } else { 1082 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1083 &cnt, p); 1084 *retcmpp = NFSERR_ATTRNOTSUPP; 1085 } 1086 } 1087 } else { 1088 if (vp != NULL && aclp != NULL) 1089 error = nfsrv_dissectacl(nd, aclp, &aceerr, 1090 &cnt, p); 1091 else 1092 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1093 &cnt, p); 1094 if (error) 1095 goto nfsmout; 1096 } 1097 1098 attrsum += cnt; 1099 break; 1100 case NFSATTRBIT_ACLSUPPORT: 1101 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1102 if (compare && !(*retcmpp)) { 1103 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) { 1104 if (fxdr_unsigned(u_int32_t, *tl) != 1105 NFSV4ACE_SUPTYPES) 1106 *retcmpp = NFSERR_NOTSAME; 1107 } else { 1108 *retcmpp = NFSERR_ATTRNOTSUPP; 1109 } 1110 } 1111 attrsum += NFSX_UNSIGNED; 1112 break; 1113 case NFSATTRBIT_ARCHIVE: 1114 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1115 if (compare && !(*retcmpp)) 1116 *retcmpp = NFSERR_ATTRNOTSUPP; 1117 attrsum += NFSX_UNSIGNED; 1118 break; 1119 case NFSATTRBIT_CANSETTIME: 1120 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1121 if (compare) { 1122 if (!(*retcmpp)) { 1123 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) { 1124 if (*tl == newnfs_false) 1125 *retcmpp = NFSERR_NOTSAME; 1126 } else { 1127 if (*tl == newnfs_true) 1128 *retcmpp = NFSERR_NOTSAME; 1129 } 1130 } 1131 } else if (fsp != NULL) { 1132 if (*tl == newnfs_true) 1133 fsp->fs_properties |= NFSV3_FSFCANSETTIME; 1134 else 1135 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME; 1136 } 1137 attrsum += NFSX_UNSIGNED; 1138 break; 1139 case NFSATTRBIT_CASEINSENSITIVE: 1140 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1141 if (compare) { 1142 if (!(*retcmpp)) { 1143 if (*tl != newnfs_false) 1144 *retcmpp = NFSERR_NOTSAME; 1145 } 1146 } else if (pc != NULL) { 1147 pc->pc_caseinsensitive = 1148 fxdr_unsigned(u_int32_t, *tl); 1149 } 1150 attrsum += NFSX_UNSIGNED; 1151 break; 1152 case NFSATTRBIT_CASEPRESERVING: 1153 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1154 if (compare) { 1155 if (!(*retcmpp)) { 1156 if (*tl != newnfs_true) 1157 *retcmpp = NFSERR_NOTSAME; 1158 } 1159 } else if (pc != NULL) { 1160 pc->pc_casepreserving = 1161 fxdr_unsigned(u_int32_t, *tl); 1162 } 1163 attrsum += NFSX_UNSIGNED; 1164 break; 1165 case NFSATTRBIT_CHOWNRESTRICTED: 1166 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1167 if (compare) { 1168 if (!(*retcmpp)) { 1169 if (*tl != newnfs_true) 1170 *retcmpp = NFSERR_NOTSAME; 1171 } 1172 } else if (pc != NULL) { 1173 pc->pc_chownrestricted = 1174 fxdr_unsigned(u_int32_t, *tl); 1175 } 1176 attrsum += NFSX_UNSIGNED; 1177 break; 1178 case NFSATTRBIT_FILEHANDLE: 1179 error = nfsm_getfh(nd, &tnfhp); 1180 if (error) 1181 goto nfsmout; 1182 tfhsize = tnfhp->nfh_len; 1183 if (compare) { 1184 if (!(*retcmpp) && 1185 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize, 1186 fhp, fhsize)) 1187 *retcmpp = NFSERR_NOTSAME; 1188 FREE((caddr_t)tnfhp, M_NFSFH); 1189 } else if (nfhpp != NULL) { 1190 *nfhpp = tnfhp; 1191 } else { 1192 FREE((caddr_t)tnfhp, M_NFSFH); 1193 } 1194 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize)); 1195 break; 1196 case NFSATTRBIT_FILEID: 1197 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1198 thyp = fxdr_hyper(tl); 1199 if (compare) { 1200 if (!(*retcmpp)) { 1201 if ((u_int64_t)nap->na_fileid != thyp) 1202 *retcmpp = NFSERR_NOTSAME; 1203 } 1204 } else if (nap != NULL) { 1205 if (*tl++) 1206 printf("NFSv4 fileid > 32bits\n"); 1207 nap->na_fileid = thyp; 1208 } 1209 attrsum += NFSX_HYPER; 1210 break; 1211 case NFSATTRBIT_FILESAVAIL: 1212 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1213 if (compare) { 1214 if (!(*retcmpp) && 1215 sfp->sf_afiles != fxdr_hyper(tl)) 1216 *retcmpp = NFSERR_NOTSAME; 1217 } else if (sfp != NULL) { 1218 sfp->sf_afiles = fxdr_hyper(tl); 1219 } 1220 attrsum += NFSX_HYPER; 1221 break; 1222 case NFSATTRBIT_FILESFREE: 1223 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1224 if (compare) { 1225 if (!(*retcmpp) && 1226 sfp->sf_ffiles != fxdr_hyper(tl)) 1227 *retcmpp = NFSERR_NOTSAME; 1228 } else if (sfp != NULL) { 1229 sfp->sf_ffiles = fxdr_hyper(tl); 1230 } 1231 attrsum += NFSX_HYPER; 1232 break; 1233 case NFSATTRBIT_FILESTOTAL: 1234 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1235 if (compare) { 1236 if (!(*retcmpp) && 1237 sfp->sf_tfiles != fxdr_hyper(tl)) 1238 *retcmpp = NFSERR_NOTSAME; 1239 } else if (sfp != NULL) { 1240 sfp->sf_tfiles = fxdr_hyper(tl); 1241 } 1242 attrsum += NFSX_HYPER; 1243 break; 1244 case NFSATTRBIT_FSLOCATIONS: 1245 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m); 1246 if (error) 1247 goto nfsmout; 1248 attrsum += l; 1249 if (compare && !(*retcmpp)) { 1250 refp = nfsv4root_getreferral(vp, NULL, 0); 1251 if (refp != NULL) { 1252 if (cp == NULL || cp2 == NULL || 1253 strcmp(cp, "/") || 1254 strcmp(cp2, refp->nfr_srvlist)) 1255 *retcmpp = NFSERR_NOTSAME; 1256 } else if (m == 0) { 1257 *retcmpp = NFSERR_NOTSAME; 1258 } 1259 } 1260 if (cp != NULL) 1261 free(cp, M_NFSSTRING); 1262 if (cp2 != NULL) 1263 free(cp2, M_NFSSTRING); 1264 break; 1265 case NFSATTRBIT_HIDDEN: 1266 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1267 if (compare && !(*retcmpp)) 1268 *retcmpp = NFSERR_ATTRNOTSUPP; 1269 attrsum += NFSX_UNSIGNED; 1270 break; 1271 case NFSATTRBIT_HOMOGENEOUS: 1272 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1273 if (compare) { 1274 if (!(*retcmpp)) { 1275 if (fsp->fs_properties & 1276 NFSV3_FSFHOMOGENEOUS) { 1277 if (*tl == newnfs_false) 1278 *retcmpp = NFSERR_NOTSAME; 1279 } else { 1280 if (*tl == newnfs_true) 1281 *retcmpp = NFSERR_NOTSAME; 1282 } 1283 } 1284 } else if (fsp != NULL) { 1285 if (*tl == newnfs_true) 1286 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS; 1287 else 1288 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS; 1289 } 1290 attrsum += NFSX_UNSIGNED; 1291 break; 1292 case NFSATTRBIT_MAXFILESIZE: 1293 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1294 tnfsquad.qval = fxdr_hyper(tl); 1295 if (compare) { 1296 if (!(*retcmpp)) { 1297 tquad = NFSRV_MAXFILESIZE; 1298 if (tquad != tnfsquad.qval) 1299 *retcmpp = NFSERR_NOTSAME; 1300 } 1301 } else if (fsp != NULL) { 1302 fsp->fs_maxfilesize = tnfsquad.qval; 1303 } 1304 attrsum += NFSX_HYPER; 1305 break; 1306 case NFSATTRBIT_MAXLINK: 1307 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1308 if (compare) { 1309 if (!(*retcmpp)) { 1310 if (fxdr_unsigned(int, *tl) != LINK_MAX) 1311 *retcmpp = NFSERR_NOTSAME; 1312 } 1313 } else if (pc != NULL) { 1314 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl); 1315 } 1316 attrsum += NFSX_UNSIGNED; 1317 break; 1318 case NFSATTRBIT_MAXNAME: 1319 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1320 if (compare) { 1321 if (!(*retcmpp)) { 1322 if (fsp->fs_maxname != 1323 fxdr_unsigned(u_int32_t, *tl)) 1324 *retcmpp = NFSERR_NOTSAME; 1325 } 1326 } else { 1327 tuint = fxdr_unsigned(u_int32_t, *tl); 1328 /* 1329 * Some Linux NFSv4 servers report this 1330 * as 0 or 4billion, so I'll set it to 1331 * NFS_MAXNAMLEN. If a server actually creates 1332 * a name longer than NFS_MAXNAMLEN, it will 1333 * get an error back. 1334 */ 1335 if (tuint == 0 || tuint > NFS_MAXNAMLEN) 1336 tuint = NFS_MAXNAMLEN; 1337 if (fsp != NULL) 1338 fsp->fs_maxname = tuint; 1339 if (pc != NULL) 1340 pc->pc_namemax = tuint; 1341 } 1342 attrsum += NFSX_UNSIGNED; 1343 break; 1344 case NFSATTRBIT_MAXREAD: 1345 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1346 if (compare) { 1347 if (!(*retcmpp)) { 1348 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t, 1349 *(tl + 1)) || *tl != 0) 1350 *retcmpp = NFSERR_NOTSAME; 1351 } 1352 } else if (fsp != NULL) { 1353 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl); 1354 fsp->fs_rtpref = fsp->fs_rtmax; 1355 fsp->fs_dtpref = fsp->fs_rtpref; 1356 } 1357 attrsum += NFSX_HYPER; 1358 break; 1359 case NFSATTRBIT_MAXWRITE: 1360 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1361 if (compare) { 1362 if (!(*retcmpp)) { 1363 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t, 1364 *(tl + 1)) || *tl != 0) 1365 *retcmpp = NFSERR_NOTSAME; 1366 } 1367 } else if (fsp != NULL) { 1368 fsp->fs_wtmax = fxdr_unsigned(int, *++tl); 1369 fsp->fs_wtpref = fsp->fs_wtmax; 1370 } 1371 attrsum += NFSX_HYPER; 1372 break; 1373 case NFSATTRBIT_MIMETYPE: 1374 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1375 i = fxdr_unsigned(int, *tl); 1376 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); 1377 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 1378 if (error) 1379 goto nfsmout; 1380 if (compare && !(*retcmpp)) 1381 *retcmpp = NFSERR_ATTRNOTSUPP; 1382 break; 1383 case NFSATTRBIT_MODE: 1384 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1385 if (compare) { 1386 if (!(*retcmpp)) { 1387 if (nap->na_mode != nfstov_mode(*tl)) 1388 *retcmpp = NFSERR_NOTSAME; 1389 } 1390 } else if (nap != NULL) { 1391 nap->na_mode = nfstov_mode(*tl); 1392 } 1393 attrsum += NFSX_UNSIGNED; 1394 break; 1395 case NFSATTRBIT_NOTRUNC: 1396 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1397 if (compare) { 1398 if (!(*retcmpp)) { 1399 if (*tl != newnfs_true) 1400 *retcmpp = NFSERR_NOTSAME; 1401 } 1402 } else if (pc != NULL) { 1403 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl); 1404 } 1405 attrsum += NFSX_UNSIGNED; 1406 break; 1407 case NFSATTRBIT_NUMLINKS: 1408 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1409 tuint = fxdr_unsigned(u_int32_t, *tl); 1410 if (compare) { 1411 if (!(*retcmpp)) { 1412 if ((u_int32_t)nap->na_nlink != tuint) 1413 *retcmpp = NFSERR_NOTSAME; 1414 } 1415 } else if (nap != NULL) { 1416 nap->na_nlink = tuint; 1417 } 1418 attrsum += NFSX_UNSIGNED; 1419 break; 1420 case NFSATTRBIT_OWNER: 1421 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1422 j = fxdr_unsigned(int, *tl); 1423 if (j < 0) { 1424 error = NFSERR_BADXDR; 1425 goto nfsmout; 1426 } 1427 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1428 if (j > NFSV4_SMALLSTR) 1429 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1430 else 1431 cp = namestr; 1432 error = nfsrv_mtostr(nd, cp, j); 1433 if (error) { 1434 if (j > NFSV4_SMALLSTR) 1435 free(cp, M_NFSSTRING); 1436 goto nfsmout; 1437 } 1438 if (compare) { 1439 if (!(*retcmpp)) { 1440 if (nfsv4_strtouid(nd, cp, j, &uid, p) || 1441 nap->na_uid != uid) 1442 *retcmpp = NFSERR_NOTSAME; 1443 } 1444 } else if (nap != NULL) { 1445 if (nfsv4_strtouid(nd, cp, j, &uid, p)) 1446 nap->na_uid = nfsrv_defaultuid; 1447 else 1448 nap->na_uid = uid; 1449 } 1450 if (j > NFSV4_SMALLSTR) 1451 free(cp, M_NFSSTRING); 1452 break; 1453 case NFSATTRBIT_OWNERGROUP: 1454 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1455 j = fxdr_unsigned(int, *tl); 1456 if (j < 0) { 1457 error = NFSERR_BADXDR; 1458 goto nfsmout; 1459 } 1460 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1461 if (j > NFSV4_SMALLSTR) 1462 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1463 else 1464 cp = namestr; 1465 error = nfsrv_mtostr(nd, cp, j); 1466 if (error) { 1467 if (j > NFSV4_SMALLSTR) 1468 free(cp, M_NFSSTRING); 1469 goto nfsmout; 1470 } 1471 if (compare) { 1472 if (!(*retcmpp)) { 1473 if (nfsv4_strtogid(nd, cp, j, &gid, p) || 1474 nap->na_gid != gid) 1475 *retcmpp = NFSERR_NOTSAME; 1476 } 1477 } else if (nap != NULL) { 1478 if (nfsv4_strtogid(nd, cp, j, &gid, p)) 1479 nap->na_gid = nfsrv_defaultgid; 1480 else 1481 nap->na_gid = gid; 1482 } 1483 if (j > NFSV4_SMALLSTR) 1484 free(cp, M_NFSSTRING); 1485 break; 1486 case NFSATTRBIT_QUOTAHARD: 1487 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1488 if (sbp != NULL) { 1489 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1490 freenum = sbp->f_bfree; 1491 else 1492 freenum = sbp->f_bavail; 1493 #ifdef QUOTA 1494 /* 1495 * ufs_quotactl() insists that the uid argument 1496 * equal p_ruid for non-root quota access, so 1497 * we'll just make sure that's the case. 1498 */ 1499 savuid = p->p_cred->p_ruid; 1500 p->p_cred->p_ruid = cred->cr_uid; 1501 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1502 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1503 freenum = min(dqb.dqb_bhardlimit, freenum); 1504 p->p_cred->p_ruid = savuid; 1505 #endif /* QUOTA */ 1506 uquad = (u_int64_t)freenum; 1507 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1508 } 1509 if (compare && !(*retcmpp)) { 1510 if (uquad != fxdr_hyper(tl)) 1511 *retcmpp = NFSERR_NOTSAME; 1512 } 1513 attrsum += NFSX_HYPER; 1514 break; 1515 case NFSATTRBIT_QUOTASOFT: 1516 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1517 if (sbp != NULL) { 1518 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1519 freenum = sbp->f_bfree; 1520 else 1521 freenum = sbp->f_bavail; 1522 #ifdef QUOTA 1523 /* 1524 * ufs_quotactl() insists that the uid argument 1525 * equal p_ruid for non-root quota access, so 1526 * we'll just make sure that's the case. 1527 */ 1528 savuid = p->p_cred->p_ruid; 1529 p->p_cred->p_ruid = cred->cr_uid; 1530 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1531 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1532 freenum = min(dqb.dqb_bsoftlimit, freenum); 1533 p->p_cred->p_ruid = savuid; 1534 #endif /* QUOTA */ 1535 uquad = (u_int64_t)freenum; 1536 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1537 } 1538 if (compare && !(*retcmpp)) { 1539 if (uquad != fxdr_hyper(tl)) 1540 *retcmpp = NFSERR_NOTSAME; 1541 } 1542 attrsum += NFSX_HYPER; 1543 break; 1544 case NFSATTRBIT_QUOTAUSED: 1545 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1546 if (sbp != NULL) { 1547 freenum = 0; 1548 #ifdef QUOTA 1549 /* 1550 * ufs_quotactl() insists that the uid argument 1551 * equal p_ruid for non-root quota access, so 1552 * we'll just make sure that's the case. 1553 */ 1554 savuid = p->p_cred->p_ruid; 1555 p->p_cred->p_ruid = cred->cr_uid; 1556 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1557 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1558 freenum = dqb.dqb_curblocks; 1559 p->p_cred->p_ruid = savuid; 1560 #endif /* QUOTA */ 1561 uquad = (u_int64_t)freenum; 1562 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1563 } 1564 if (compare && !(*retcmpp)) { 1565 if (uquad != fxdr_hyper(tl)) 1566 *retcmpp = NFSERR_NOTSAME; 1567 } 1568 attrsum += NFSX_HYPER; 1569 break; 1570 case NFSATTRBIT_RAWDEV: 1571 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA); 1572 j = fxdr_unsigned(int, *tl++); 1573 k = fxdr_unsigned(int, *tl); 1574 if (compare) { 1575 if (!(*retcmpp)) { 1576 if (nap->na_rdev != NFSMAKEDEV(j, k)) 1577 *retcmpp = NFSERR_NOTSAME; 1578 } 1579 } else if (nap != NULL) { 1580 nap->na_rdev = NFSMAKEDEV(j, k); 1581 } 1582 attrsum += NFSX_V4SPECDATA; 1583 break; 1584 case NFSATTRBIT_SPACEAVAIL: 1585 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1586 if (compare) { 1587 if (!(*retcmpp) && 1588 sfp->sf_abytes != fxdr_hyper(tl)) 1589 *retcmpp = NFSERR_NOTSAME; 1590 } else if (sfp != NULL) { 1591 sfp->sf_abytes = fxdr_hyper(tl); 1592 } 1593 attrsum += NFSX_HYPER; 1594 break; 1595 case NFSATTRBIT_SPACEFREE: 1596 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1597 if (compare) { 1598 if (!(*retcmpp) && 1599 sfp->sf_fbytes != fxdr_hyper(tl)) 1600 *retcmpp = NFSERR_NOTSAME; 1601 } else if (sfp != NULL) { 1602 sfp->sf_fbytes = fxdr_hyper(tl); 1603 } 1604 attrsum += NFSX_HYPER; 1605 break; 1606 case NFSATTRBIT_SPACETOTAL: 1607 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1608 if (compare) { 1609 if (!(*retcmpp) && 1610 sfp->sf_tbytes != fxdr_hyper(tl)) 1611 *retcmpp = NFSERR_NOTSAME; 1612 } else if (sfp != NULL) { 1613 sfp->sf_tbytes = fxdr_hyper(tl); 1614 } 1615 attrsum += NFSX_HYPER; 1616 break; 1617 case NFSATTRBIT_SPACEUSED: 1618 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1619 thyp = fxdr_hyper(tl); 1620 if (compare) { 1621 if (!(*retcmpp)) { 1622 if ((u_int64_t)nap->na_bytes != thyp) 1623 *retcmpp = NFSERR_NOTSAME; 1624 } 1625 } else if (nap != NULL) { 1626 nap->na_bytes = thyp; 1627 } 1628 attrsum += NFSX_HYPER; 1629 break; 1630 case NFSATTRBIT_SYSTEM: 1631 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1632 if (compare && !(*retcmpp)) 1633 *retcmpp = NFSERR_ATTRNOTSUPP; 1634 attrsum += NFSX_UNSIGNED; 1635 break; 1636 case NFSATTRBIT_TIMEACCESS: 1637 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1638 fxdr_nfsv4time(tl, &temptime); 1639 if (compare) { 1640 if (!(*retcmpp)) { 1641 if (!NFS_CMPTIME(temptime, nap->na_atime)) 1642 *retcmpp = NFSERR_NOTSAME; 1643 } 1644 } else if (nap != NULL) { 1645 nap->na_atime = temptime; 1646 } 1647 attrsum += NFSX_V4TIME; 1648 break; 1649 case NFSATTRBIT_TIMEACCESSSET: 1650 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1651 attrsum += NFSX_UNSIGNED; 1652 i = fxdr_unsigned(int, *tl); 1653 if (i == NFSV4SATTRTIME_TOCLIENT) { 1654 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1655 attrsum += NFSX_V4TIME; 1656 } 1657 if (compare && !(*retcmpp)) 1658 *retcmpp = NFSERR_INVAL; 1659 break; 1660 case NFSATTRBIT_TIMEBACKUP: 1661 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1662 if (compare && !(*retcmpp)) 1663 *retcmpp = NFSERR_ATTRNOTSUPP; 1664 attrsum += NFSX_V4TIME; 1665 break; 1666 case NFSATTRBIT_TIMECREATE: 1667 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1668 if (compare && !(*retcmpp)) 1669 *retcmpp = NFSERR_ATTRNOTSUPP; 1670 attrsum += NFSX_V4TIME; 1671 break; 1672 case NFSATTRBIT_TIMEDELTA: 1673 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1674 if (fsp != NULL) { 1675 if (compare) { 1676 if (!(*retcmpp)) { 1677 if ((u_int32_t)fsp->fs_timedelta.tv_sec != 1678 fxdr_unsigned(u_int32_t, *(tl + 1)) || 1679 (u_int32_t)fsp->fs_timedelta.tv_nsec != 1680 (fxdr_unsigned(u_int32_t, *(tl + 2)) % 1681 1000000000) || 1682 *tl != 0) 1683 *retcmpp = NFSERR_NOTSAME; 1684 } 1685 } else { 1686 fxdr_nfsv4time(tl, &fsp->fs_timedelta); 1687 } 1688 } 1689 attrsum += NFSX_V4TIME; 1690 break; 1691 case NFSATTRBIT_TIMEMETADATA: 1692 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1693 fxdr_nfsv4time(tl, &temptime); 1694 if (compare) { 1695 if (!(*retcmpp)) { 1696 if (!NFS_CMPTIME(temptime, nap->na_ctime)) 1697 *retcmpp = NFSERR_NOTSAME; 1698 } 1699 } else if (nap != NULL) { 1700 nap->na_ctime = temptime; 1701 } 1702 attrsum += NFSX_V4TIME; 1703 break; 1704 case NFSATTRBIT_TIMEMODIFY: 1705 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1706 fxdr_nfsv4time(tl, &temptime); 1707 if (compare) { 1708 if (!(*retcmpp)) { 1709 if (!NFS_CMPTIME(temptime, nap->na_mtime)) 1710 *retcmpp = NFSERR_NOTSAME; 1711 } 1712 } else if (nap != NULL) { 1713 nap->na_mtime = temptime; 1714 } 1715 attrsum += NFSX_V4TIME; 1716 break; 1717 case NFSATTRBIT_TIMEMODIFYSET: 1718 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1719 attrsum += NFSX_UNSIGNED; 1720 i = fxdr_unsigned(int, *tl); 1721 if (i == NFSV4SATTRTIME_TOCLIENT) { 1722 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1723 attrsum += NFSX_V4TIME; 1724 } 1725 if (compare && !(*retcmpp)) 1726 *retcmpp = NFSERR_INVAL; 1727 break; 1728 case NFSATTRBIT_MOUNTEDONFILEID: 1729 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1730 thyp = fxdr_hyper(tl); 1731 if (compare) { 1732 if (!(*retcmpp)) { 1733 if (*tl++) { 1734 *retcmpp = NFSERR_NOTSAME; 1735 } else { 1736 if (!vp || !nfsrv_atroot(vp, &fid)) 1737 fid = nap->na_fileid; 1738 if ((u_int64_t)fid != thyp) 1739 *retcmpp = NFSERR_NOTSAME; 1740 } 1741 } 1742 } else if (nap != NULL) { 1743 if (*tl++) 1744 printf("NFSv4 mounted on fileid > 32bits\n"); 1745 nap->na_mntonfileno = thyp; 1746 } 1747 attrsum += NFSX_HYPER; 1748 break; 1749 case NFSATTRBIT_SUPPATTREXCLCREAT: 1750 retnotsup = 0; 1751 error = nfsrv_getattrbits(nd, &retattrbits, 1752 &cnt, &retnotsup); 1753 if (error) 1754 goto nfsmout; 1755 if (compare && !(*retcmpp)) { 1756 NFSSETSUPP_ATTRBIT(&checkattrbits); 1757 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits); 1758 NFSCLRBIT_ATTRBIT(&checkattrbits, 1759 NFSATTRBIT_TIMEACCESSSET); 1760 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 1761 || retnotsup) 1762 *retcmpp = NFSERR_NOTSAME; 1763 } 1764 attrsum += cnt; 1765 break; 1766 default: 1767 printf("EEK! nfsv4_loadattr unknown attr=%d\n", 1768 bitpos); 1769 if (compare && !(*retcmpp)) 1770 *retcmpp = NFSERR_ATTRNOTSUPP; 1771 /* 1772 * and get out of the loop, since we can't parse 1773 * the unknown attrbute data. 1774 */ 1775 bitpos = NFSATTRBIT_MAX; 1776 break; 1777 } 1778 } 1779 1780 /* 1781 * some clients pad the attrlist, so we need to skip over the 1782 * padding. 1783 */ 1784 if (attrsum > attrsize) { 1785 error = NFSERR_BADXDR; 1786 } else { 1787 attrsize = NFSM_RNDUP(attrsize); 1788 if (attrsum < attrsize) 1789 error = nfsm_advance(nd, attrsize - attrsum, -1); 1790 } 1791 nfsmout: 1792 NFSEXITCODE2(error, nd); 1793 return (error); 1794 } 1795 1796 /* 1797 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a 1798 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock. 1799 * The first argument is a pointer to an nfsv4lock structure. 1800 * The second argument is 1 iff a blocking lock is wanted. 1801 * If this argument is 0, the call waits until no thread either wants nor 1802 * holds an exclusive lock. 1803 * It returns 1 if the lock was acquired, 0 otherwise. 1804 * If several processes call this function concurrently wanting the exclusive 1805 * lock, one will get the lock and the rest will return without getting the 1806 * lock. (If the caller must have the lock, it simply calls this function in a 1807 * loop until the function returns 1 to indicate the lock was acquired.) 1808 * Any usecnt must be decremented by calling nfsv4_relref() before 1809 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could 1810 * be called in a loop. 1811 * The isleptp argument is set to indicate if the call slept, iff not NULL 1812 * and the mp argument indicates to check for a forced dismount, iff not 1813 * NULL. 1814 */ 1815 APPLESTATIC int 1816 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp, 1817 void *mutex, struct mount *mp) 1818 { 1819 1820 if (isleptp) 1821 *isleptp = 0; 1822 /* 1823 * If a lock is wanted, loop around until the lock is acquired by 1824 * someone and then released. If I want the lock, try to acquire it. 1825 * For a lock to be issued, no lock must be in force and the usecnt 1826 * must be zero. 1827 */ 1828 if (iwantlock) { 1829 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1830 lp->nfslock_usecnt == 0) { 1831 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1832 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1833 return (1); 1834 } 1835 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED; 1836 } 1837 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) { 1838 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1839 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1840 return (0); 1841 } 1842 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1843 if (isleptp) 1844 *isleptp = 1; 1845 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1846 PZERO - 1, "nfsv4lck", NULL); 1847 if (iwantlock && !(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 } 1854 return (0); 1855 } 1856 1857 /* 1858 * Release the lock acquired by nfsv4_lock(). 1859 * The second argument is set to 1 to indicate the nfslock_usecnt should be 1860 * incremented, as well. 1861 */ 1862 APPLESTATIC void 1863 nfsv4_unlock(struct nfsv4lock *lp, int incref) 1864 { 1865 1866 lp->nfslock_lock &= ~NFSV4LOCK_LOCK; 1867 if (incref) 1868 lp->nfslock_usecnt++; 1869 nfsv4_wanted(lp); 1870 } 1871 1872 /* 1873 * Release a reference cnt. 1874 */ 1875 APPLESTATIC void 1876 nfsv4_relref(struct nfsv4lock *lp) 1877 { 1878 1879 if (lp->nfslock_usecnt <= 0) 1880 panic("nfsv4root ref cnt"); 1881 lp->nfslock_usecnt--; 1882 if (lp->nfslock_usecnt == 0) 1883 nfsv4_wanted(lp); 1884 } 1885 1886 /* 1887 * Get a reference cnt. 1888 * This function will wait for any exclusive lock to be released, but will 1889 * not wait for threads that want the exclusive lock. If priority needs 1890 * to be given to threads that need the exclusive lock, a call to nfsv4_lock() 1891 * with the 2nd argument == 0 should be done before calling nfsv4_getref(). 1892 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and 1893 * return without getting a refcnt for that case. 1894 */ 1895 APPLESTATIC void 1896 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex, 1897 struct mount *mp) 1898 { 1899 1900 if (isleptp) 1901 *isleptp = 0; 1902 1903 /* 1904 * Wait for a lock held. 1905 */ 1906 while (lp->nfslock_lock & NFSV4LOCK_LOCK) { 1907 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1908 return; 1909 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1910 if (isleptp) 1911 *isleptp = 1; 1912 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1913 PZERO - 1, "nfsv4gr", NULL); 1914 } 1915 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1916 return; 1917 1918 lp->nfslock_usecnt++; 1919 } 1920 1921 /* 1922 * Get a reference as above, but return failure instead of sleeping if 1923 * an exclusive lock is held. 1924 */ 1925 APPLESTATIC int 1926 nfsv4_getref_nonblock(struct nfsv4lock *lp) 1927 { 1928 1929 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0) 1930 return (0); 1931 1932 lp->nfslock_usecnt++; 1933 return (1); 1934 } 1935 1936 /* 1937 * Test for a lock. Return 1 if locked, 0 otherwise. 1938 */ 1939 APPLESTATIC int 1940 nfsv4_testlock(struct nfsv4lock *lp) 1941 { 1942 1943 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 && 1944 lp->nfslock_usecnt == 0) 1945 return (0); 1946 return (1); 1947 } 1948 1949 /* 1950 * Wake up anyone sleeping, waiting for this lock. 1951 */ 1952 static void 1953 nfsv4_wanted(struct nfsv4lock *lp) 1954 { 1955 1956 if (lp->nfslock_lock & NFSV4LOCK_WANTED) { 1957 lp->nfslock_lock &= ~NFSV4LOCK_WANTED; 1958 wakeup((caddr_t)&lp->nfslock_lock); 1959 } 1960 } 1961 1962 /* 1963 * Copy a string from an mbuf list into a character array. 1964 * Return EBADRPC if there is an mbuf error, 1965 * 0 otherwise. 1966 */ 1967 APPLESTATIC int 1968 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) 1969 { 1970 char *cp; 1971 int xfer, len; 1972 mbuf_t mp; 1973 int rem, error = 0; 1974 1975 mp = nd->nd_md; 1976 cp = nd->nd_dpos; 1977 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp; 1978 rem = NFSM_RNDUP(siz) - siz; 1979 while (siz > 0) { 1980 if (len > siz) 1981 xfer = siz; 1982 else 1983 xfer = len; 1984 NFSBCOPY(cp, str, xfer); 1985 str += xfer; 1986 siz -= xfer; 1987 if (siz > 0) { 1988 mp = mbuf_next(mp); 1989 if (mp == NULL) { 1990 error = EBADRPC; 1991 goto out; 1992 } 1993 cp = NFSMTOD(mp, caddr_t); 1994 len = mbuf_len(mp); 1995 } else { 1996 cp += xfer; 1997 len -= xfer; 1998 } 1999 } 2000 *str = '\0'; 2001 nd->nd_dpos = cp; 2002 nd->nd_md = mp; 2003 if (rem > 0) { 2004 if (len < rem) 2005 error = nfsm_advance(nd, rem, len); 2006 else 2007 nd->nd_dpos += rem; 2008 } 2009 2010 out: 2011 NFSEXITCODE2(error, nd); 2012 return (error); 2013 } 2014 2015 /* 2016 * Fill in the attributes as marked by the bitmap (V4). 2017 */ 2018 APPLESTATIC int 2019 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, 2020 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror, 2021 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram, 2022 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno) 2023 { 2024 int bitpos, retnum = 0; 2025 u_int32_t *tl; 2026 int siz, prefixnum, error; 2027 u_char *cp, namestr[NFSV4_SMALLSTR]; 2028 nfsattrbit_t attrbits, retbits; 2029 nfsattrbit_t *retbitp = &retbits; 2030 u_int32_t freenum, *retnump; 2031 u_int64_t uquad; 2032 struct statfs fs; 2033 struct nfsfsinfo fsinf; 2034 struct timespec temptime; 2035 NFSACL_T *aclp, *naclp = NULL; 2036 #ifdef QUOTA 2037 struct dqblk dqb; 2038 uid_t savuid; 2039 #endif 2040 2041 /* 2042 * First, set the bits that can be filled and get fsinfo. 2043 */ 2044 NFSSET_ATTRBIT(retbitp, attrbitp); 2045 /* 2046 * If both p and cred are NULL, it is a client side setattr call. 2047 * If both p and cred are not NULL, it is a server side reply call. 2048 * If p is not NULL and cred is NULL, it is a client side callback 2049 * reply call. 2050 */ 2051 if (p == NULL && cred == NULL) { 2052 NFSCLRNOTSETABLE_ATTRBIT(retbitp); 2053 aclp = saclp; 2054 } else { 2055 NFSCLRNOTFILLABLE_ATTRBIT(retbitp); 2056 naclp = acl_alloc(M_WAITOK); 2057 aclp = naclp; 2058 } 2059 nfsvno_getfs(&fsinf, isdgram); 2060 #ifndef APPLE 2061 /* 2062 * Get the VFS_STATFS(), since some attributes need them. 2063 */ 2064 if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 2065 error = VFS_STATFS(mp, &fs); 2066 if (error != 0) { 2067 if (reterr) { 2068 nd->nd_repstat = NFSERR_ACCES; 2069 return (0); 2070 } 2071 NFSCLRSTATFS_ATTRBIT(retbitp); 2072 } 2073 } 2074 #endif 2075 2076 /* 2077 * And the NFSv4 ACL... 2078 */ 2079 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 2080 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2081 supports_nfsv4acls == 0))) { 2082 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 2083 } 2084 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 2085 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2086 supports_nfsv4acls == 0)) { 2087 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2088 } else if (naclp != NULL) { 2089 if (NFSVOPLOCK(vp, LK_SHARED) == 0) { 2090 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); 2091 if (error == 0) 2092 error = VOP_GETACL(vp, ACL_TYPE_NFS4, 2093 naclp, cred, p); 2094 NFSVOPUNLOCK(vp, 0); 2095 } else 2096 error = NFSERR_PERM; 2097 if (error != 0) { 2098 if (reterr) { 2099 nd->nd_repstat = NFSERR_ACCES; 2100 return (0); 2101 } 2102 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2103 } 2104 } 2105 } 2106 2107 /* 2108 * Put out the attribute bitmap for the ones being filled in 2109 * and get the field for the number of attributes returned. 2110 */ 2111 prefixnum = nfsrv_putattrbit(nd, retbitp); 2112 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 2113 prefixnum += NFSX_UNSIGNED; 2114 2115 /* 2116 * Now, loop around filling in the attributes for each bit set. 2117 */ 2118 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 2119 if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 2120 switch (bitpos) { 2121 case NFSATTRBIT_SUPPORTEDATTRS: 2122 NFSSETSUPP_ATTRBIT(&attrbits); 2123 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 2124 && supports_nfsv4acls == 0)) { 2125 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 2126 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 2127 } 2128 retnum += nfsrv_putattrbit(nd, &attrbits); 2129 break; 2130 case NFSATTRBIT_TYPE: 2131 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2132 *tl = vtonfsv34_type(vap->va_type); 2133 retnum += NFSX_UNSIGNED; 2134 break; 2135 case NFSATTRBIT_FHEXPIRETYPE: 2136 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2137 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2138 retnum += NFSX_UNSIGNED; 2139 break; 2140 case NFSATTRBIT_CHANGE: 2141 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2142 txdr_hyper(vap->va_filerev, tl); 2143 retnum += NFSX_HYPER; 2144 break; 2145 case NFSATTRBIT_SIZE: 2146 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2147 txdr_hyper(vap->va_size, tl); 2148 retnum += NFSX_HYPER; 2149 break; 2150 case NFSATTRBIT_LINKSUPPORT: 2151 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2152 if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2153 *tl = newnfs_true; 2154 else 2155 *tl = newnfs_false; 2156 retnum += NFSX_UNSIGNED; 2157 break; 2158 case NFSATTRBIT_SYMLINKSUPPORT: 2159 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2160 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2161 *tl = newnfs_true; 2162 else 2163 *tl = newnfs_false; 2164 retnum += NFSX_UNSIGNED; 2165 break; 2166 case NFSATTRBIT_NAMEDATTR: 2167 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2168 *tl = newnfs_false; 2169 retnum += NFSX_UNSIGNED; 2170 break; 2171 case NFSATTRBIT_FSID: 2172 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2173 *tl++ = 0; 2174 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]); 2175 *tl++ = 0; 2176 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]); 2177 retnum += NFSX_V4FSID; 2178 break; 2179 case NFSATTRBIT_UNIQUEHANDLES: 2180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2181 *tl = newnfs_true; 2182 retnum += NFSX_UNSIGNED; 2183 break; 2184 case NFSATTRBIT_LEASETIME: 2185 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2186 *tl = txdr_unsigned(nfsrv_lease); 2187 retnum += NFSX_UNSIGNED; 2188 break; 2189 case NFSATTRBIT_RDATTRERROR: 2190 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2191 *tl = txdr_unsigned(rderror); 2192 retnum += NFSX_UNSIGNED; 2193 break; 2194 /* 2195 * Recommended Attributes. (Only the supported ones.) 2196 */ 2197 case NFSATTRBIT_ACL: 2198 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2199 break; 2200 case NFSATTRBIT_ACLSUPPORT: 2201 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2202 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2203 retnum += NFSX_UNSIGNED; 2204 break; 2205 case NFSATTRBIT_CANSETTIME: 2206 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2207 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2208 *tl = newnfs_true; 2209 else 2210 *tl = newnfs_false; 2211 retnum += NFSX_UNSIGNED; 2212 break; 2213 case NFSATTRBIT_CASEINSENSITIVE: 2214 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2215 *tl = newnfs_false; 2216 retnum += NFSX_UNSIGNED; 2217 break; 2218 case NFSATTRBIT_CASEPRESERVING: 2219 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2220 *tl = newnfs_true; 2221 retnum += NFSX_UNSIGNED; 2222 break; 2223 case NFSATTRBIT_CHOWNRESTRICTED: 2224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2225 *tl = newnfs_true; 2226 retnum += NFSX_UNSIGNED; 2227 break; 2228 case NFSATTRBIT_FILEHANDLE: 2229 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2230 break; 2231 case NFSATTRBIT_FILEID: 2232 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2233 *tl++ = 0; 2234 *tl = txdr_unsigned(vap->va_fileid); 2235 retnum += NFSX_HYPER; 2236 break; 2237 case NFSATTRBIT_FILESAVAIL: 2238 /* 2239 * Check quota and use min(quota, f_ffree). 2240 */ 2241 freenum = fs.f_ffree; 2242 #ifdef QUOTA 2243 /* 2244 * ufs_quotactl() insists that the uid argument 2245 * equal p_ruid for non-root quota access, so 2246 * we'll just make sure that's the case. 2247 */ 2248 savuid = p->p_cred->p_ruid; 2249 p->p_cred->p_ruid = cred->cr_uid; 2250 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2251 cred->cr_uid, (caddr_t)&dqb)) 2252 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2253 freenum); 2254 p->p_cred->p_ruid = savuid; 2255 #endif /* QUOTA */ 2256 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2257 *tl++ = 0; 2258 *tl = txdr_unsigned(freenum); 2259 retnum += NFSX_HYPER; 2260 break; 2261 case NFSATTRBIT_FILESFREE: 2262 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2263 *tl++ = 0; 2264 *tl = txdr_unsigned(fs.f_ffree); 2265 retnum += NFSX_HYPER; 2266 break; 2267 case NFSATTRBIT_FILESTOTAL: 2268 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2269 *tl++ = 0; 2270 *tl = txdr_unsigned(fs.f_files); 2271 retnum += NFSX_HYPER; 2272 break; 2273 case NFSATTRBIT_FSLOCATIONS: 2274 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2275 *tl++ = 0; 2276 *tl = 0; 2277 retnum += 2 * NFSX_UNSIGNED; 2278 break; 2279 case NFSATTRBIT_HOMOGENEOUS: 2280 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2281 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2282 *tl = newnfs_true; 2283 else 2284 *tl = newnfs_false; 2285 retnum += NFSX_UNSIGNED; 2286 break; 2287 case NFSATTRBIT_MAXFILESIZE: 2288 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2289 uquad = NFSRV_MAXFILESIZE; 2290 txdr_hyper(uquad, tl); 2291 retnum += NFSX_HYPER; 2292 break; 2293 case NFSATTRBIT_MAXLINK: 2294 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2295 *tl = txdr_unsigned(LINK_MAX); 2296 retnum += NFSX_UNSIGNED; 2297 break; 2298 case NFSATTRBIT_MAXNAME: 2299 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2300 *tl = txdr_unsigned(NFS_MAXNAMLEN); 2301 retnum += NFSX_UNSIGNED; 2302 break; 2303 case NFSATTRBIT_MAXREAD: 2304 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2305 *tl++ = 0; 2306 *tl = txdr_unsigned(fsinf.fs_rtmax); 2307 retnum += NFSX_HYPER; 2308 break; 2309 case NFSATTRBIT_MAXWRITE: 2310 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2311 *tl++ = 0; 2312 *tl = txdr_unsigned(fsinf.fs_wtmax); 2313 retnum += NFSX_HYPER; 2314 break; 2315 case NFSATTRBIT_MODE: 2316 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2317 *tl = vtonfsv34_mode(vap->va_mode); 2318 retnum += NFSX_UNSIGNED; 2319 break; 2320 case NFSATTRBIT_NOTRUNC: 2321 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2322 *tl = newnfs_true; 2323 retnum += NFSX_UNSIGNED; 2324 break; 2325 case NFSATTRBIT_NUMLINKS: 2326 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2327 *tl = txdr_unsigned(vap->va_nlink); 2328 retnum += NFSX_UNSIGNED; 2329 break; 2330 case NFSATTRBIT_OWNER: 2331 cp = namestr; 2332 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); 2333 retnum += nfsm_strtom(nd, cp, siz); 2334 if (cp != namestr) 2335 free(cp, M_NFSSTRING); 2336 break; 2337 case NFSATTRBIT_OWNERGROUP: 2338 cp = namestr; 2339 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); 2340 retnum += nfsm_strtom(nd, cp, siz); 2341 if (cp != namestr) 2342 free(cp, M_NFSSTRING); 2343 break; 2344 case NFSATTRBIT_QUOTAHARD: 2345 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2346 freenum = fs.f_bfree; 2347 else 2348 freenum = fs.f_bavail; 2349 #ifdef QUOTA 2350 /* 2351 * ufs_quotactl() insists that the uid argument 2352 * equal p_ruid for non-root quota access, so 2353 * we'll just make sure that's the case. 2354 */ 2355 savuid = p->p_cred->p_ruid; 2356 p->p_cred->p_ruid = cred->cr_uid; 2357 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2358 cred->cr_uid, (caddr_t)&dqb)) 2359 freenum = min(dqb.dqb_bhardlimit, freenum); 2360 p->p_cred->p_ruid = savuid; 2361 #endif /* QUOTA */ 2362 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2363 uquad = (u_int64_t)freenum; 2364 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2365 txdr_hyper(uquad, tl); 2366 retnum += NFSX_HYPER; 2367 break; 2368 case NFSATTRBIT_QUOTASOFT: 2369 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2370 freenum = fs.f_bfree; 2371 else 2372 freenum = fs.f_bavail; 2373 #ifdef QUOTA 2374 /* 2375 * ufs_quotactl() insists that the uid argument 2376 * equal p_ruid for non-root quota access, so 2377 * we'll just make sure that's the case. 2378 */ 2379 savuid = p->p_cred->p_ruid; 2380 p->p_cred->p_ruid = cred->cr_uid; 2381 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2382 cred->cr_uid, (caddr_t)&dqb)) 2383 freenum = min(dqb.dqb_bsoftlimit, freenum); 2384 p->p_cred->p_ruid = savuid; 2385 #endif /* QUOTA */ 2386 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2387 uquad = (u_int64_t)freenum; 2388 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2389 txdr_hyper(uquad, tl); 2390 retnum += NFSX_HYPER; 2391 break; 2392 case NFSATTRBIT_QUOTAUSED: 2393 freenum = 0; 2394 #ifdef QUOTA 2395 /* 2396 * ufs_quotactl() insists that the uid argument 2397 * equal p_ruid for non-root quota access, so 2398 * we'll just make sure that's the case. 2399 */ 2400 savuid = p->p_cred->p_ruid; 2401 p->p_cred->p_ruid = cred->cr_uid; 2402 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2403 cred->cr_uid, (caddr_t)&dqb)) 2404 freenum = dqb.dqb_curblocks; 2405 p->p_cred->p_ruid = savuid; 2406 #endif /* QUOTA */ 2407 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2408 uquad = (u_int64_t)freenum; 2409 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2410 txdr_hyper(uquad, tl); 2411 retnum += NFSX_HYPER; 2412 break; 2413 case NFSATTRBIT_RAWDEV: 2414 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2415 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2416 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2417 retnum += NFSX_V4SPECDATA; 2418 break; 2419 case NFSATTRBIT_SPACEAVAIL: 2420 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2421 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) 2422 uquad = (u_int64_t)fs.f_bfree; 2423 else 2424 uquad = (u_int64_t)fs.f_bavail; 2425 uquad *= fs.f_bsize; 2426 txdr_hyper(uquad, tl); 2427 retnum += NFSX_HYPER; 2428 break; 2429 case NFSATTRBIT_SPACEFREE: 2430 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2431 uquad = (u_int64_t)fs.f_bfree; 2432 uquad *= fs.f_bsize; 2433 txdr_hyper(uquad, tl); 2434 retnum += NFSX_HYPER; 2435 break; 2436 case NFSATTRBIT_SPACETOTAL: 2437 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2438 uquad = (u_int64_t)fs.f_blocks; 2439 uquad *= fs.f_bsize; 2440 txdr_hyper(uquad, tl); 2441 retnum += NFSX_HYPER; 2442 break; 2443 case NFSATTRBIT_SPACEUSED: 2444 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2445 txdr_hyper(vap->va_bytes, tl); 2446 retnum += NFSX_HYPER; 2447 break; 2448 case NFSATTRBIT_TIMEACCESS: 2449 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2450 txdr_nfsv4time(&vap->va_atime, tl); 2451 retnum += NFSX_V4TIME; 2452 break; 2453 case NFSATTRBIT_TIMEACCESSSET: 2454 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2455 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2456 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2457 txdr_nfsv4time(&vap->va_atime, tl); 2458 retnum += NFSX_V4SETTIME; 2459 } else { 2460 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2461 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2462 retnum += NFSX_UNSIGNED; 2463 } 2464 break; 2465 case NFSATTRBIT_TIMEDELTA: 2466 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2467 temptime.tv_sec = 0; 2468 temptime.tv_nsec = 1000000000 / hz; 2469 txdr_nfsv4time(&temptime, tl); 2470 retnum += NFSX_V4TIME; 2471 break; 2472 case NFSATTRBIT_TIMEMETADATA: 2473 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2474 txdr_nfsv4time(&vap->va_ctime, tl); 2475 retnum += NFSX_V4TIME; 2476 break; 2477 case NFSATTRBIT_TIMEMODIFY: 2478 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2479 txdr_nfsv4time(&vap->va_mtime, tl); 2480 retnum += NFSX_V4TIME; 2481 break; 2482 case NFSATTRBIT_TIMEMODIFYSET: 2483 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2484 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2485 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2486 txdr_nfsv4time(&vap->va_mtime, tl); 2487 retnum += NFSX_V4SETTIME; 2488 } else { 2489 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2490 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2491 retnum += NFSX_UNSIGNED; 2492 } 2493 break; 2494 case NFSATTRBIT_MOUNTEDONFILEID: 2495 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2496 if (at_root != 0) 2497 uquad = mounted_on_fileno; 2498 else 2499 uquad = (u_int64_t)vap->va_fileid; 2500 txdr_hyper(uquad, tl); 2501 retnum += NFSX_HYPER; 2502 break; 2503 case NFSATTRBIT_SUPPATTREXCLCREAT: 2504 NFSSETSUPP_ATTRBIT(&attrbits); 2505 NFSCLRNOTSETABLE_ATTRBIT(&attrbits); 2506 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); 2507 retnum += nfsrv_putattrbit(nd, &attrbits); 2508 break; 2509 default: 2510 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2511 } 2512 } 2513 } 2514 if (naclp != NULL) 2515 acl_free(naclp); 2516 *retnump = txdr_unsigned(retnum); 2517 return (retnum + prefixnum); 2518 } 2519 2520 /* 2521 * Put the attribute bits onto an mbuf list. 2522 * Return the number of bytes of output generated. 2523 */ 2524 APPLESTATIC int 2525 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 2526 { 2527 u_int32_t *tl; 2528 int cnt, i, bytesize; 2529 2530 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 2531 if (attrbitp->bits[cnt - 1]) 2532 break; 2533 bytesize = (cnt + 1) * NFSX_UNSIGNED; 2534 NFSM_BUILD(tl, u_int32_t *, bytesize); 2535 *tl++ = txdr_unsigned(cnt); 2536 for (i = 0; i < cnt; i++) 2537 *tl++ = txdr_unsigned(attrbitp->bits[i]); 2538 return (bytesize); 2539 } 2540 2541 /* 2542 * Convert a uid to a string. 2543 * If the lookup fails, just output the digits. 2544 * uid - the user id 2545 * cpp - points to a buffer of size NFSV4_SMALLSTR 2546 * (malloc a larger one, as required) 2547 * retlenp - pointer to length to be returned 2548 */ 2549 APPLESTATIC void 2550 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2551 { 2552 int i; 2553 struct nfsusrgrp *usrp; 2554 u_char *cp = *cpp; 2555 uid_t tmp; 2556 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2557 struct nfsrv_lughash *hp; 2558 2559 cnt = 0; 2560 tryagain: 2561 if (nfsrv_dnsnamelen > 0) { 2562 /* 2563 * Always map nfsrv_defaultuid to "nobody". 2564 */ 2565 if (uid == nfsrv_defaultuid) { 2566 i = nfsrv_dnsnamelen + 7; 2567 if (i > len) { 2568 if (len > NFSV4_SMALLSTR) 2569 free(cp, M_NFSSTRING); 2570 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2571 *cpp = cp; 2572 len = i; 2573 goto tryagain; 2574 } 2575 *retlenp = i; 2576 NFSBCOPY("nobody@", cp, 7); 2577 cp += 7; 2578 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2579 return; 2580 } 2581 hasampersand = 0; 2582 hp = NFSUSERHASH(uid); 2583 mtx_lock(&hp->mtx); 2584 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2585 if (usrp->lug_uid == uid) { 2586 if (usrp->lug_expiry < NFSD_MONOSEC) 2587 break; 2588 /* 2589 * If the name doesn't already have an '@' 2590 * in it, append @domainname to it. 2591 */ 2592 for (i = 0; i < usrp->lug_namelen; i++) { 2593 if (usrp->lug_name[i] == '@') { 2594 hasampersand = 1; 2595 break; 2596 } 2597 } 2598 if (hasampersand) 2599 i = usrp->lug_namelen; 2600 else 2601 i = usrp->lug_namelen + 2602 nfsrv_dnsnamelen + 1; 2603 if (i > len) { 2604 mtx_unlock(&hp->mtx); 2605 if (len > NFSV4_SMALLSTR) 2606 free(cp, M_NFSSTRING); 2607 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2608 *cpp = cp; 2609 len = i; 2610 goto tryagain; 2611 } 2612 *retlenp = i; 2613 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2614 if (!hasampersand) { 2615 cp += usrp->lug_namelen; 2616 *cp++ = '@'; 2617 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2618 } 2619 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2620 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2621 lug_numhash); 2622 mtx_unlock(&hp->mtx); 2623 return; 2624 } 2625 } 2626 mtx_unlock(&hp->mtx); 2627 cnt++; 2628 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2629 NULL, p); 2630 if (ret == 0 && cnt < 2) 2631 goto tryagain; 2632 } 2633 2634 /* 2635 * No match, just return a string of digits. 2636 */ 2637 tmp = uid; 2638 i = 0; 2639 while (tmp || i == 0) { 2640 tmp /= 10; 2641 i++; 2642 } 2643 len = (i > len) ? len : i; 2644 *retlenp = len; 2645 cp += (len - 1); 2646 tmp = uid; 2647 for (i = 0; i < len; i++) { 2648 *cp-- = '0' + (tmp % 10); 2649 tmp /= 10; 2650 } 2651 return; 2652 } 2653 2654 /* 2655 * Get a credential for the uid with the server's group list. 2656 * If none is found, just return the credential passed in after 2657 * logging a warning message. 2658 */ 2659 struct ucred * 2660 nfsrv_getgrpscred(struct ucred *oldcred) 2661 { 2662 struct nfsusrgrp *usrp; 2663 struct ucred *newcred; 2664 int cnt, ret; 2665 uid_t uid; 2666 struct nfsrv_lughash *hp; 2667 2668 cnt = 0; 2669 uid = oldcred->cr_uid; 2670 tryagain: 2671 if (nfsrv_dnsnamelen > 0) { 2672 hp = NFSUSERHASH(uid); 2673 mtx_lock(&hp->mtx); 2674 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2675 if (usrp->lug_uid == uid) { 2676 if (usrp->lug_expiry < NFSD_MONOSEC) 2677 break; 2678 if (usrp->lug_cred != NULL) { 2679 newcred = crhold(usrp->lug_cred); 2680 crfree(oldcred); 2681 } else 2682 newcred = oldcred; 2683 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2684 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2685 lug_numhash); 2686 mtx_unlock(&hp->mtx); 2687 return (newcred); 2688 } 2689 } 2690 mtx_unlock(&hp->mtx); 2691 cnt++; 2692 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2693 NULL, curthread); 2694 if (ret == 0 && cnt < 2) 2695 goto tryagain; 2696 } 2697 return (oldcred); 2698 } 2699 2700 /* 2701 * Convert a string to a uid. 2702 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2703 * return 0. 2704 * If this is called from a client side mount using AUTH_SYS and the 2705 * string is made up entirely of digits, just convert the string to 2706 * a number. 2707 */ 2708 APPLESTATIC int 2709 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp, 2710 NFSPROC_T *p) 2711 { 2712 int i; 2713 char *cp, *endstr, *str0; 2714 struct nfsusrgrp *usrp; 2715 int cnt, ret; 2716 int error = 0; 2717 uid_t tuid; 2718 struct nfsrv_lughash *hp, *hp2; 2719 2720 if (len == 0) { 2721 error = NFSERR_BADOWNER; 2722 goto out; 2723 } 2724 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2725 str0 = str; 2726 tuid = (uid_t)strtoul(str0, &endstr, 10); 2727 if ((endstr - str0) == len) { 2728 /* A numeric string. */ 2729 if ((nd->nd_flag & ND_KERBV) == 0 && 2730 ((nd->nd_flag & ND_NFSCL) != 0 || 2731 nfsd_enable_stringtouid != 0)) 2732 *uidp = tuid; 2733 else 2734 error = NFSERR_BADOWNER; 2735 goto out; 2736 } 2737 /* 2738 * Look for an '@'. 2739 */ 2740 cp = strchr(str0, '@'); 2741 if (cp != NULL) 2742 i = (int)(cp++ - str0); 2743 else 2744 i = len; 2745 2746 cnt = 0; 2747 tryagain: 2748 if (nfsrv_dnsnamelen > 0) { 2749 /* 2750 * If an '@' is found and the domain name matches, search for 2751 * the name with dns stripped off. 2752 * Mixed case alpahbetics will match for the domain name, but 2753 * all upper case will not. 2754 */ 2755 if (cnt == 0 && i < len && i > 0 && 2756 (len - 1 - i) == nfsrv_dnsnamelen && 2757 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2758 len -= (nfsrv_dnsnamelen + 1); 2759 *(cp - 1) = '\0'; 2760 } 2761 2762 /* 2763 * Check for the special case of "nobody". 2764 */ 2765 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 2766 *uidp = nfsrv_defaultuid; 2767 error = 0; 2768 goto out; 2769 } 2770 2771 hp = NFSUSERNAMEHASH(str, len); 2772 mtx_lock(&hp->mtx); 2773 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 2774 if (usrp->lug_namelen == len && 2775 !NFSBCMP(usrp->lug_name, str, len)) { 2776 if (usrp->lug_expiry < NFSD_MONOSEC) 2777 break; 2778 hp2 = NFSUSERHASH(usrp->lug_uid); 2779 mtx_lock(&hp2->mtx); 2780 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 2781 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 2782 lug_numhash); 2783 *uidp = usrp->lug_uid; 2784 mtx_unlock(&hp2->mtx); 2785 mtx_unlock(&hp->mtx); 2786 error = 0; 2787 goto out; 2788 } 2789 } 2790 mtx_unlock(&hp->mtx); 2791 cnt++; 2792 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 2793 str, p); 2794 if (ret == 0 && cnt < 2) 2795 goto tryagain; 2796 } 2797 error = NFSERR_BADOWNER; 2798 2799 out: 2800 NFSEXITCODE(error); 2801 return (error); 2802 } 2803 2804 /* 2805 * Convert a gid to a string. 2806 * gid - the group id 2807 * cpp - points to a buffer of size NFSV4_SMALLSTR 2808 * (malloc a larger one, as required) 2809 * retlenp - pointer to length to be returned 2810 */ 2811 APPLESTATIC void 2812 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2813 { 2814 int i; 2815 struct nfsusrgrp *usrp; 2816 u_char *cp = *cpp; 2817 gid_t tmp; 2818 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2819 struct nfsrv_lughash *hp; 2820 2821 cnt = 0; 2822 tryagain: 2823 if (nfsrv_dnsnamelen > 0) { 2824 /* 2825 * Always map nfsrv_defaultgid to "nogroup". 2826 */ 2827 if (gid == nfsrv_defaultgid) { 2828 i = nfsrv_dnsnamelen + 8; 2829 if (i > len) { 2830 if (len > NFSV4_SMALLSTR) 2831 free(cp, M_NFSSTRING); 2832 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2833 *cpp = cp; 2834 len = i; 2835 goto tryagain; 2836 } 2837 *retlenp = i; 2838 NFSBCOPY("nogroup@", cp, 8); 2839 cp += 8; 2840 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2841 return; 2842 } 2843 hasampersand = 0; 2844 hp = NFSGROUPHASH(gid); 2845 mtx_lock(&hp->mtx); 2846 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2847 if (usrp->lug_gid == gid) { 2848 if (usrp->lug_expiry < NFSD_MONOSEC) 2849 break; 2850 /* 2851 * If the name doesn't already have an '@' 2852 * in it, append @domainname to it. 2853 */ 2854 for (i = 0; i < usrp->lug_namelen; i++) { 2855 if (usrp->lug_name[i] == '@') { 2856 hasampersand = 1; 2857 break; 2858 } 2859 } 2860 if (hasampersand) 2861 i = usrp->lug_namelen; 2862 else 2863 i = usrp->lug_namelen + 2864 nfsrv_dnsnamelen + 1; 2865 if (i > len) { 2866 mtx_unlock(&hp->mtx); 2867 if (len > NFSV4_SMALLSTR) 2868 free(cp, M_NFSSTRING); 2869 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2870 *cpp = cp; 2871 len = i; 2872 goto tryagain; 2873 } 2874 *retlenp = i; 2875 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2876 if (!hasampersand) { 2877 cp += usrp->lug_namelen; 2878 *cp++ = '@'; 2879 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2880 } 2881 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2882 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2883 lug_numhash); 2884 mtx_unlock(&hp->mtx); 2885 return; 2886 } 2887 } 2888 mtx_unlock(&hp->mtx); 2889 cnt++; 2890 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, 2891 NULL, p); 2892 if (ret == 0 && cnt < 2) 2893 goto tryagain; 2894 } 2895 2896 /* 2897 * No match, just return a string of digits. 2898 */ 2899 tmp = gid; 2900 i = 0; 2901 while (tmp || i == 0) { 2902 tmp /= 10; 2903 i++; 2904 } 2905 len = (i > len) ? len : i; 2906 *retlenp = len; 2907 cp += (len - 1); 2908 tmp = gid; 2909 for (i = 0; i < len; i++) { 2910 *cp-- = '0' + (tmp % 10); 2911 tmp /= 10; 2912 } 2913 return; 2914 } 2915 2916 /* 2917 * Convert a string to a gid. 2918 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2919 * return 0. 2920 * If this is called from a client side mount using AUTH_SYS and the 2921 * string is made up entirely of digits, just convert the string to 2922 * a number. 2923 */ 2924 APPLESTATIC int 2925 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp, 2926 NFSPROC_T *p) 2927 { 2928 int i; 2929 char *cp, *endstr, *str0; 2930 struct nfsusrgrp *usrp; 2931 int cnt, ret; 2932 int error = 0; 2933 gid_t tgid; 2934 struct nfsrv_lughash *hp, *hp2; 2935 2936 if (len == 0) { 2937 error = NFSERR_BADOWNER; 2938 goto out; 2939 } 2940 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2941 str0 = str; 2942 tgid = (gid_t)strtoul(str0, &endstr, 10); 2943 if ((endstr - str0) == len) { 2944 /* A numeric string. */ 2945 if ((nd->nd_flag & ND_KERBV) == 0 && 2946 ((nd->nd_flag & ND_NFSCL) != 0 || 2947 nfsd_enable_stringtouid != 0)) 2948 *gidp = tgid; 2949 else 2950 error = NFSERR_BADOWNER; 2951 goto out; 2952 } 2953 /* 2954 * Look for an '@'. 2955 */ 2956 cp = strchr(str0, '@'); 2957 if (cp != NULL) 2958 i = (int)(cp++ - str0); 2959 else 2960 i = len; 2961 2962 cnt = 0; 2963 tryagain: 2964 if (nfsrv_dnsnamelen > 0) { 2965 /* 2966 * If an '@' is found and the dns name matches, search for the 2967 * name with the dns stripped off. 2968 */ 2969 if (cnt == 0 && i < len && i > 0 && 2970 (len - 1 - i) == nfsrv_dnsnamelen && 2971 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2972 len -= (nfsrv_dnsnamelen + 1); 2973 *(cp - 1) = '\0'; 2974 } 2975 2976 /* 2977 * Check for the special case of "nogroup". 2978 */ 2979 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 2980 *gidp = nfsrv_defaultgid; 2981 error = 0; 2982 goto out; 2983 } 2984 2985 hp = NFSGROUPNAMEHASH(str, len); 2986 mtx_lock(&hp->mtx); 2987 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 2988 if (usrp->lug_namelen == len && 2989 !NFSBCMP(usrp->lug_name, str, len)) { 2990 if (usrp->lug_expiry < NFSD_MONOSEC) 2991 break; 2992 hp2 = NFSGROUPHASH(usrp->lug_gid); 2993 mtx_lock(&hp2->mtx); 2994 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 2995 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 2996 lug_numhash); 2997 *gidp = usrp->lug_gid; 2998 mtx_unlock(&hp2->mtx); 2999 mtx_unlock(&hp->mtx); 3000 error = 0; 3001 goto out; 3002 } 3003 } 3004 mtx_unlock(&hp->mtx); 3005 cnt++; 3006 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 3007 str, p); 3008 if (ret == 0 && cnt < 2) 3009 goto tryagain; 3010 } 3011 error = NFSERR_BADOWNER; 3012 3013 out: 3014 NFSEXITCODE(error); 3015 return (error); 3016 } 3017 3018 /* 3019 * Cmp len chars, allowing mixed case in the first argument to match lower 3020 * case in the second, but not if the first argument is all upper case. 3021 * Return 0 for a match, 1 otherwise. 3022 */ 3023 static int 3024 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 3025 { 3026 int i; 3027 u_char tmp; 3028 int fndlower = 0; 3029 3030 for (i = 0; i < len; i++) { 3031 if (*cp >= 'A' && *cp <= 'Z') { 3032 tmp = *cp++ + ('a' - 'A'); 3033 } else { 3034 tmp = *cp++; 3035 if (tmp >= 'a' && tmp <= 'z') 3036 fndlower = 1; 3037 } 3038 if (tmp != *cp2++) 3039 return (1); 3040 } 3041 if (fndlower) 3042 return (0); 3043 else 3044 return (1); 3045 } 3046 3047 /* 3048 * Set the port for the nfsuserd. 3049 */ 3050 APPLESTATIC int 3051 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p) 3052 { 3053 struct nfssockreq *rp; 3054 struct sockaddr_in *ad; 3055 int error; 3056 3057 NFSLOCKNAMEID(); 3058 if (nfsrv_nfsuserd) { 3059 NFSUNLOCKNAMEID(); 3060 error = EPERM; 3061 goto out; 3062 } 3063 nfsrv_nfsuserd = 1; 3064 NFSUNLOCKNAMEID(); 3065 /* 3066 * Set up the socket record and connect. 3067 */ 3068 rp = &nfsrv_nfsuserdsock; 3069 rp->nr_client = NULL; 3070 rp->nr_sotype = SOCK_DGRAM; 3071 rp->nr_soproto = IPPROTO_UDP; 3072 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 3073 rp->nr_cred = NULL; 3074 NFSSOCKADDRALLOC(rp->nr_nam); 3075 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in)); 3076 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *); 3077 ad->sin_family = AF_INET; 3078 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */ 3079 ad->sin_port = port; 3080 rp->nr_prog = RPCPROG_NFSUSERD; 3081 rp->nr_vers = RPCNFSUSERD_VERS; 3082 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 3083 if (error) { 3084 NFSSOCKADDRFREE(rp->nr_nam); 3085 nfsrv_nfsuserd = 0; 3086 } 3087 out: 3088 NFSEXITCODE(error); 3089 return (error); 3090 } 3091 3092 /* 3093 * Delete the nfsuserd port. 3094 */ 3095 APPLESTATIC void 3096 nfsrv_nfsuserddelport(void) 3097 { 3098 3099 NFSLOCKNAMEID(); 3100 if (nfsrv_nfsuserd == 0) { 3101 NFSUNLOCKNAMEID(); 3102 return; 3103 } 3104 nfsrv_nfsuserd = 0; 3105 NFSUNLOCKNAMEID(); 3106 newnfs_disconnect(&nfsrv_nfsuserdsock); 3107 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); 3108 } 3109 3110 /* 3111 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 3112 * name<-->id cache. 3113 * Returns 0 upon success, non-zero otherwise. 3114 */ 3115 static int 3116 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) 3117 { 3118 u_int32_t *tl; 3119 struct nfsrv_descript *nd; 3120 int len; 3121 struct nfsrv_descript nfsd; 3122 struct ucred *cred; 3123 int error; 3124 3125 NFSLOCKNAMEID(); 3126 if (nfsrv_nfsuserd == 0) { 3127 NFSUNLOCKNAMEID(); 3128 error = EPERM; 3129 goto out; 3130 } 3131 NFSUNLOCKNAMEID(); 3132 nd = &nfsd; 3133 cred = newnfs_getcred(); 3134 nd->nd_flag = ND_GSSINITREPLY; 3135 nfsrvd_rephead(nd); 3136 3137 nd->nd_procnum = procnum; 3138 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3139 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3140 if (procnum == RPCNFSUSERD_GETUID) 3141 *tl = txdr_unsigned(uid); 3142 else 3143 *tl = txdr_unsigned(gid); 3144 } else { 3145 len = strlen(name); 3146 (void) nfsm_strtom(nd, name, len); 3147 } 3148 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 3149 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL); 3150 NFSFREECRED(cred); 3151 if (!error) { 3152 mbuf_freem(nd->nd_mrep); 3153 error = nd->nd_repstat; 3154 } 3155 out: 3156 NFSEXITCODE(error); 3157 return (error); 3158 } 3159 3160 /* 3161 * This function is called from the nfssvc(2) system call, to update the 3162 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3163 */ 3164 APPLESTATIC int 3165 nfssvc_idname(struct nfsd_idargs *nidp) 3166 { 3167 struct nfsusrgrp *nusrp, *usrp, *newusrp; 3168 struct nfsrv_lughash *hp_name, *hp_idnum, *thp; 3169 int i, group_locked, groupname_locked, user_locked, username_locked; 3170 int error = 0; 3171 u_char *cp; 3172 gid_t *grps; 3173 struct ucred *cr; 3174 static int onethread = 0; 3175 static time_t lasttime = 0; 3176 3177 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) { 3178 error = EINVAL; 3179 goto out; 3180 } 3181 if (nidp->nid_flag & NFSID_INITIALIZE) { 3182 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); 3183 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 3184 nidp->nid_namelen); 3185 if (error != 0) { 3186 free(cp, M_NFSSTRING); 3187 goto out; 3188 } 3189 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) { 3190 /* 3191 * Free up all the old stuff and reinitialize hash 3192 * lists. All mutexes for both lists must be locked, 3193 * with the user/group name ones before the uid/gid 3194 * ones, to avoid a LOR. 3195 */ 3196 for (i = 0; i < nfsrv_lughashsize; i++) 3197 mtx_lock(&nfsusernamehash[i].mtx); 3198 for (i = 0; i < nfsrv_lughashsize; i++) 3199 mtx_lock(&nfsuserhash[i].mtx); 3200 for (i = 0; i < nfsrv_lughashsize; i++) 3201 TAILQ_FOREACH_SAFE(usrp, 3202 &nfsuserhash[i].lughead, lug_numhash, nusrp) 3203 nfsrv_removeuser(usrp, 1); 3204 for (i = 0; i < nfsrv_lughashsize; i++) 3205 mtx_unlock(&nfsuserhash[i].mtx); 3206 for (i = 0; i < nfsrv_lughashsize; i++) 3207 mtx_unlock(&nfsusernamehash[i].mtx); 3208 for (i = 0; i < nfsrv_lughashsize; i++) 3209 mtx_lock(&nfsgroupnamehash[i].mtx); 3210 for (i = 0; i < nfsrv_lughashsize; i++) 3211 mtx_lock(&nfsgrouphash[i].mtx); 3212 for (i = 0; i < nfsrv_lughashsize; i++) 3213 TAILQ_FOREACH_SAFE(usrp, 3214 &nfsgrouphash[i].lughead, lug_numhash, 3215 nusrp) 3216 nfsrv_removeuser(usrp, 0); 3217 for (i = 0; i < nfsrv_lughashsize; i++) 3218 mtx_unlock(&nfsgrouphash[i].mtx); 3219 for (i = 0; i < nfsrv_lughashsize; i++) 3220 mtx_unlock(&nfsgroupnamehash[i].mtx); 3221 free(nfsrv_dnsname, M_NFSSTRING); 3222 nfsrv_dnsname = NULL; 3223 } 3224 if (nfsuserhash == NULL) { 3225 /* Allocate the hash tables. */ 3226 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) * 3227 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3228 M_ZERO); 3229 for (i = 0; i < nfsrv_lughashsize; i++) 3230 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash", 3231 NULL, MTX_DEF | MTX_DUPOK); 3232 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) * 3233 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3234 M_ZERO); 3235 for (i = 0; i < nfsrv_lughashsize; i++) 3236 mtx_init(&nfsusernamehash[i].mtx, 3237 "nfsusrhash", NULL, MTX_DEF | 3238 MTX_DUPOK); 3239 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) * 3240 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3241 M_ZERO); 3242 for (i = 0; i < nfsrv_lughashsize; i++) 3243 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash", 3244 NULL, MTX_DEF | MTX_DUPOK); 3245 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) * 3246 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3247 M_ZERO); 3248 for (i = 0; i < nfsrv_lughashsize; i++) 3249 mtx_init(&nfsgroupnamehash[i].mtx, 3250 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK); 3251 } 3252 /* (Re)initialize the list heads. */ 3253 for (i = 0; i < nfsrv_lughashsize; i++) 3254 TAILQ_INIT(&nfsuserhash[i].lughead); 3255 for (i = 0; i < nfsrv_lughashsize; i++) 3256 TAILQ_INIT(&nfsusernamehash[i].lughead); 3257 for (i = 0; i < nfsrv_lughashsize; i++) 3258 TAILQ_INIT(&nfsgrouphash[i].lughead); 3259 for (i = 0; i < nfsrv_lughashsize; i++) 3260 TAILQ_INIT(&nfsgroupnamehash[i].lughead); 3261 3262 /* 3263 * Put name in "DNS" string. 3264 */ 3265 nfsrv_dnsname = cp; 3266 nfsrv_defaultuid = nidp->nid_uid; 3267 nfsrv_defaultgid = nidp->nid_gid; 3268 nfsrv_usercnt = 0; 3269 nfsrv_usermax = nidp->nid_usermax; 3270 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen); 3271 goto out; 3272 } 3273 3274 /* 3275 * malloc the new one now, so any potential sleep occurs before 3276 * manipulation of the lists. 3277 */ 3278 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, 3279 M_NFSUSERGROUP, M_WAITOK | M_ZERO); 3280 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 3281 nidp->nid_namelen); 3282 if (error == 0 && nidp->nid_ngroup > 0 && 3283 (nidp->nid_flag & NFSID_ADDUID) != 0) { 3284 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP, 3285 M_WAITOK); 3286 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps, 3287 sizeof(gid_t) * nidp->nid_ngroup); 3288 if (error == 0) { 3289 /* 3290 * Create a credential just like svc_getcred(), 3291 * but using the group list provided. 3292 */ 3293 cr = crget(); 3294 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; 3295 crsetgroups(cr, nidp->nid_ngroup, grps); 3296 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; 3297 cr->cr_prison = &prison0; 3298 prison_hold(cr->cr_prison); 3299 #ifdef MAC 3300 mac_cred_associate_nfsd(cr); 3301 #endif 3302 newusrp->lug_cred = cr; 3303 } 3304 free(grps, M_TEMP); 3305 } 3306 if (error) { 3307 free(newusrp, M_NFSUSERGROUP); 3308 goto out; 3309 } 3310 newusrp->lug_namelen = nidp->nid_namelen; 3311 3312 /* 3313 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed 3314 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group. 3315 * The flags user_locked, username_locked, group_locked and 3316 * groupname_locked are set to indicate all of those hash lists are 3317 * locked. hp_name != NULL and hp_idnum != NULL indicates that 3318 * the respective one mutex is locked. 3319 */ 3320 user_locked = username_locked = group_locked = groupname_locked = 0; 3321 hp_name = hp_idnum = NULL; 3322 3323 /* 3324 * Delete old entries, as required. 3325 */ 3326 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3327 /* Must lock all username hash lists first, to avoid a LOR. */ 3328 for (i = 0; i < nfsrv_lughashsize; i++) 3329 mtx_lock(&nfsusernamehash[i].mtx); 3330 username_locked = 1; 3331 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3332 mtx_lock(&hp_idnum->mtx); 3333 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3334 nusrp) { 3335 if (usrp->lug_uid == nidp->nid_uid) 3336 nfsrv_removeuser(usrp, 1); 3337 } 3338 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3339 hp_name = NFSUSERNAMEHASH(newusrp->lug_name, 3340 newusrp->lug_namelen); 3341 mtx_lock(&hp_name->mtx); 3342 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3343 nusrp) { 3344 if (usrp->lug_namelen == newusrp->lug_namelen && 3345 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3346 usrp->lug_namelen)) { 3347 thp = NFSUSERHASH(usrp->lug_uid); 3348 mtx_lock(&thp->mtx); 3349 nfsrv_removeuser(usrp, 1); 3350 mtx_unlock(&thp->mtx); 3351 } 3352 } 3353 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3354 mtx_lock(&hp_idnum->mtx); 3355 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3356 /* Must lock all groupname hash lists first, to avoid a LOR. */ 3357 for (i = 0; i < nfsrv_lughashsize; i++) 3358 mtx_lock(&nfsgroupnamehash[i].mtx); 3359 groupname_locked = 1; 3360 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3361 mtx_lock(&hp_idnum->mtx); 3362 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3363 nusrp) { 3364 if (usrp->lug_gid == nidp->nid_gid) 3365 nfsrv_removeuser(usrp, 0); 3366 } 3367 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3368 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name, 3369 newusrp->lug_namelen); 3370 mtx_lock(&hp_name->mtx); 3371 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3372 nusrp) { 3373 if (usrp->lug_namelen == newusrp->lug_namelen && 3374 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3375 usrp->lug_namelen)) { 3376 thp = NFSGROUPHASH(usrp->lug_gid); 3377 mtx_lock(&thp->mtx); 3378 nfsrv_removeuser(usrp, 0); 3379 mtx_unlock(&thp->mtx); 3380 } 3381 } 3382 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3383 mtx_lock(&hp_idnum->mtx); 3384 } 3385 3386 /* 3387 * Now, we can add the new one. 3388 */ 3389 if (nidp->nid_usertimeout) 3390 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3391 else 3392 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3393 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3394 newusrp->lug_uid = nidp->nid_uid; 3395 thp = NFSUSERHASH(newusrp->lug_uid); 3396 mtx_assert(&thp->mtx, MA_OWNED); 3397 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3398 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3399 mtx_assert(&thp->mtx, MA_OWNED); 3400 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3401 atomic_add_int(&nfsrv_usercnt, 1); 3402 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3403 newusrp->lug_gid = nidp->nid_gid; 3404 thp = NFSGROUPHASH(newusrp->lug_gid); 3405 mtx_assert(&thp->mtx, MA_OWNED); 3406 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3407 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3408 mtx_assert(&thp->mtx, MA_OWNED); 3409 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3410 atomic_add_int(&nfsrv_usercnt, 1); 3411 } else { 3412 if (newusrp->lug_cred != NULL) 3413 crfree(newusrp->lug_cred); 3414 free(newusrp, M_NFSUSERGROUP); 3415 } 3416 3417 /* 3418 * Once per second, allow one thread to trim the cache. 3419 */ 3420 if (lasttime < NFSD_MONOSEC && 3421 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) { 3422 /* 3423 * First, unlock the single mutexes, so that all entries 3424 * can be locked and any LOR is avoided. 3425 */ 3426 if (hp_name != NULL) { 3427 mtx_unlock(&hp_name->mtx); 3428 hp_name = NULL; 3429 } 3430 if (hp_idnum != NULL) { 3431 mtx_unlock(&hp_idnum->mtx); 3432 hp_idnum = NULL; 3433 } 3434 3435 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID | 3436 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) { 3437 if (username_locked == 0) { 3438 for (i = 0; i < nfsrv_lughashsize; i++) 3439 mtx_lock(&nfsusernamehash[i].mtx); 3440 username_locked = 1; 3441 } 3442 KASSERT(user_locked == 0, 3443 ("nfssvc_idname: user_locked")); 3444 for (i = 0; i < nfsrv_lughashsize; i++) 3445 mtx_lock(&nfsuserhash[i].mtx); 3446 user_locked = 1; 3447 for (i = 0; i < nfsrv_lughashsize; i++) { 3448 TAILQ_FOREACH_SAFE(usrp, 3449 &nfsuserhash[i].lughead, lug_numhash, 3450 nusrp) 3451 if (usrp->lug_expiry < NFSD_MONOSEC) 3452 nfsrv_removeuser(usrp, 1); 3453 } 3454 for (i = 0; i < nfsrv_lughashsize; i++) { 3455 /* 3456 * Trim the cache using an approximate LRU 3457 * algorithm. This code deletes the least 3458 * recently used entry on each hash list. 3459 */ 3460 if (nfsrv_usercnt <= nfsrv_usermax) 3461 break; 3462 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead); 3463 if (usrp != NULL) 3464 nfsrv_removeuser(usrp, 1); 3465 } 3466 } else { 3467 if (groupname_locked == 0) { 3468 for (i = 0; i < nfsrv_lughashsize; i++) 3469 mtx_lock(&nfsgroupnamehash[i].mtx); 3470 groupname_locked = 1; 3471 } 3472 KASSERT(group_locked == 0, 3473 ("nfssvc_idname: group_locked")); 3474 for (i = 0; i < nfsrv_lughashsize; i++) 3475 mtx_lock(&nfsgrouphash[i].mtx); 3476 group_locked = 1; 3477 for (i = 0; i < nfsrv_lughashsize; i++) { 3478 TAILQ_FOREACH_SAFE(usrp, 3479 &nfsgrouphash[i].lughead, lug_numhash, 3480 nusrp) 3481 if (usrp->lug_expiry < NFSD_MONOSEC) 3482 nfsrv_removeuser(usrp, 0); 3483 } 3484 for (i = 0; i < nfsrv_lughashsize; i++) { 3485 /* 3486 * Trim the cache using an approximate LRU 3487 * algorithm. This code deletes the least 3488 * recently user entry on each hash list. 3489 */ 3490 if (nfsrv_usercnt <= nfsrv_usermax) 3491 break; 3492 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead); 3493 if (usrp != NULL) 3494 nfsrv_removeuser(usrp, 0); 3495 } 3496 } 3497 lasttime = NFSD_MONOSEC; 3498 atomic_store_rel_int(&onethread, 0); 3499 } 3500 3501 /* Now, unlock all locked mutexes. */ 3502 if (hp_idnum != NULL) 3503 mtx_unlock(&hp_idnum->mtx); 3504 if (hp_name != NULL) 3505 mtx_unlock(&hp_name->mtx); 3506 if (user_locked != 0) 3507 for (i = 0; i < nfsrv_lughashsize; i++) 3508 mtx_unlock(&nfsuserhash[i].mtx); 3509 if (username_locked != 0) 3510 for (i = 0; i < nfsrv_lughashsize; i++) 3511 mtx_unlock(&nfsusernamehash[i].mtx); 3512 if (group_locked != 0) 3513 for (i = 0; i < nfsrv_lughashsize; i++) 3514 mtx_unlock(&nfsgrouphash[i].mtx); 3515 if (groupname_locked != 0) 3516 for (i = 0; i < nfsrv_lughashsize; i++) 3517 mtx_unlock(&nfsgroupnamehash[i].mtx); 3518 out: 3519 NFSEXITCODE(error); 3520 return (error); 3521 } 3522 3523 /* 3524 * Remove a user/group name element. 3525 */ 3526 static void 3527 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser) 3528 { 3529 struct nfsrv_lughash *hp; 3530 3531 if (isuser != 0) { 3532 hp = NFSUSERHASH(usrp->lug_uid); 3533 mtx_assert(&hp->mtx, MA_OWNED); 3534 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3535 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3536 mtx_assert(&hp->mtx, MA_OWNED); 3537 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 3538 } else { 3539 hp = NFSGROUPHASH(usrp->lug_gid); 3540 mtx_assert(&hp->mtx, MA_OWNED); 3541 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3542 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3543 mtx_assert(&hp->mtx, MA_OWNED); 3544 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 3545 } 3546 atomic_add_int(&nfsrv_usercnt, -1); 3547 if (usrp->lug_cred != NULL) 3548 crfree(usrp->lug_cred); 3549 free(usrp, M_NFSUSERGROUP); 3550 } 3551 3552 /* 3553 * Free up all the allocations related to the name<-->id cache. 3554 * This function should only be called when the nfsuserd daemon isn't 3555 * running, since it doesn't do any locking. 3556 * This function is meant to be used when the nfscommon module is unloaded. 3557 */ 3558 APPLESTATIC void 3559 nfsrv_cleanusergroup(void) 3560 { 3561 struct nfsrv_lughash *hp, *hp2; 3562 struct nfsusrgrp *nusrp, *usrp; 3563 int i; 3564 3565 if (nfsuserhash == NULL) 3566 return; 3567 3568 for (i = 0; i < nfsrv_lughashsize; i++) { 3569 hp = &nfsuserhash[i]; 3570 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 3571 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3572 hp2 = NFSUSERNAMEHASH(usrp->lug_name, 3573 usrp->lug_namelen); 3574 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 3575 if (usrp->lug_cred != NULL) 3576 crfree(usrp->lug_cred); 3577 free(usrp, M_NFSUSERGROUP); 3578 } 3579 hp = &nfsgrouphash[i]; 3580 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 3581 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3582 hp2 = NFSGROUPNAMEHASH(usrp->lug_name, 3583 usrp->lug_namelen); 3584 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 3585 if (usrp->lug_cred != NULL) 3586 crfree(usrp->lug_cred); 3587 free(usrp, M_NFSUSERGROUP); 3588 } 3589 mtx_destroy(&nfsuserhash[i].mtx); 3590 mtx_destroy(&nfsusernamehash[i].mtx); 3591 mtx_destroy(&nfsgroupnamehash[i].mtx); 3592 mtx_destroy(&nfsgrouphash[i].mtx); 3593 } 3594 free(nfsuserhash, M_NFSUSERGROUP); 3595 free(nfsusernamehash, M_NFSUSERGROUP); 3596 free(nfsgrouphash, M_NFSUSERGROUP); 3597 free(nfsgroupnamehash, M_NFSUSERGROUP); 3598 free(nfsrv_dnsname, M_NFSSTRING); 3599 } 3600 3601 /* 3602 * This function scans a byte string and checks for UTF-8 compliance. 3603 * It returns 0 if it conforms and NFSERR_INVAL if not. 3604 */ 3605 APPLESTATIC int 3606 nfsrv_checkutf8(u_int8_t *cp, int len) 3607 { 3608 u_int32_t val = 0x0; 3609 int cnt = 0, gotd = 0, shift = 0; 3610 u_int8_t byte; 3611 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 3612 int error = 0; 3613 3614 /* 3615 * Here are what the variables are used for: 3616 * val - the calculated value of a multibyte char, used to check 3617 * that it was coded with the correct range 3618 * cnt - the number of 10xxxxxx bytes to follow 3619 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 3620 * shift - lower order bits of range (ie. "val >> shift" should 3621 * not be 0, in other words, dividing by the lower bound 3622 * of the range should get a non-zero value) 3623 * byte - used to calculate cnt 3624 */ 3625 while (len > 0) { 3626 if (cnt > 0) { 3627 /* This handles the 10xxxxxx bytes */ 3628 if ((*cp & 0xc0) != 0x80 || 3629 (gotd && (*cp & 0x20))) { 3630 error = NFSERR_INVAL; 3631 goto out; 3632 } 3633 gotd = 0; 3634 val <<= 6; 3635 val |= (*cp & 0x3f); 3636 cnt--; 3637 if (cnt == 0 && (val >> shift) == 0x0) { 3638 error = NFSERR_INVAL; 3639 goto out; 3640 } 3641 } else if (*cp & 0x80) { 3642 /* first byte of multi byte char */ 3643 byte = *cp; 3644 while ((byte & 0x40) && cnt < 6) { 3645 cnt++; 3646 byte <<= 1; 3647 } 3648 if (cnt == 0 || cnt == 6) { 3649 error = NFSERR_INVAL; 3650 goto out; 3651 } 3652 val = (*cp & (0x3f >> cnt)); 3653 shift = utf8_shift[cnt - 1]; 3654 if (cnt == 2 && val == 0xd) 3655 /* Check for the 0xd800-0xdfff case */ 3656 gotd = 1; 3657 } 3658 cp++; 3659 len--; 3660 } 3661 if (cnt > 0) 3662 error = NFSERR_INVAL; 3663 3664 out: 3665 NFSEXITCODE(error); 3666 return (error); 3667 } 3668 3669 /* 3670 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 3671 * strings, one with the root path in it and the other with the list of 3672 * locations. The list is in the same format as is found in nfr_refs. 3673 * It is a "," separated list of entries, where each of them is of the 3674 * form <server>:<rootpath>. For example 3675 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 3676 * The nilp argument is set to 1 for the special case of a null fs_root 3677 * and an empty server list. 3678 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 3679 * number of xdr bytes parsed in sump. 3680 */ 3681 static int 3682 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 3683 int *sump, int *nilp) 3684 { 3685 u_int32_t *tl; 3686 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 3687 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 3688 struct list { 3689 SLIST_ENTRY(list) next; 3690 int len; 3691 u_char host[1]; 3692 } *lsp, *nlsp; 3693 SLIST_HEAD(, list) head; 3694 3695 *fsrootp = NULL; 3696 *srvp = NULL; 3697 *nilp = 0; 3698 3699 /* 3700 * Get the fs_root path and check for the special case of null path 3701 * and 0 length server list. 3702 */ 3703 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3704 len = fxdr_unsigned(int, *tl); 3705 if (len < 0 || len > 10240) { 3706 error = NFSERR_BADXDR; 3707 goto nfsmout; 3708 } 3709 if (len == 0) { 3710 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3711 if (*tl != 0) { 3712 error = NFSERR_BADXDR; 3713 goto nfsmout; 3714 } 3715 *nilp = 1; 3716 *sump = 2 * NFSX_UNSIGNED; 3717 error = 0; 3718 goto nfsmout; 3719 } 3720 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 3721 error = nfsrv_mtostr(nd, cp, len); 3722 if (!error) { 3723 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3724 cnt = fxdr_unsigned(int, *tl); 3725 if (cnt <= 0) 3726 error = NFSERR_BADXDR; 3727 } 3728 if (error) 3729 goto nfsmout; 3730 3731 /* 3732 * Now, loop through the location list and make up the srvlist. 3733 */ 3734 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3735 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 3736 slen = 1024; 3737 siz = 0; 3738 for (i = 0; i < cnt; i++) { 3739 SLIST_INIT(&head); 3740 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3741 nsrv = fxdr_unsigned(int, *tl); 3742 if (nsrv <= 0) { 3743 error = NFSERR_BADXDR; 3744 goto nfsmout; 3745 } 3746 3747 /* 3748 * Handle the first server by putting it in the srvstr. 3749 */ 3750 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3751 len = fxdr_unsigned(int, *tl); 3752 if (len <= 0 || len > 1024) { 3753 error = NFSERR_BADXDR; 3754 goto nfsmout; 3755 } 3756 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 3757 if (cp3 != cp2) { 3758 *cp3++ = ','; 3759 siz++; 3760 } 3761 error = nfsrv_mtostr(nd, cp3, len); 3762 if (error) 3763 goto nfsmout; 3764 cp3 += len; 3765 *cp3++ = ':'; 3766 siz += (len + 1); 3767 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3768 for (j = 1; j < nsrv; j++) { 3769 /* 3770 * Yuck, put them in an slist and process them later. 3771 */ 3772 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3773 len = fxdr_unsigned(int, *tl); 3774 if (len <= 0 || len > 1024) { 3775 error = NFSERR_BADXDR; 3776 goto nfsmout; 3777 } 3778 lsp = (struct list *)malloc(sizeof (struct list) 3779 + len, M_TEMP, M_WAITOK); 3780 error = nfsrv_mtostr(nd, lsp->host, len); 3781 if (error) 3782 goto nfsmout; 3783 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3784 lsp->len = len; 3785 SLIST_INSERT_HEAD(&head, lsp, next); 3786 } 3787 3788 /* 3789 * Finally, we can get the path. 3790 */ 3791 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3792 len = fxdr_unsigned(int, *tl); 3793 if (len <= 0 || len > 1024) { 3794 error = NFSERR_BADXDR; 3795 goto nfsmout; 3796 } 3797 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 3798 error = nfsrv_mtostr(nd, cp3, len); 3799 if (error) 3800 goto nfsmout; 3801 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3802 str = cp3; 3803 stringlen = len; 3804 cp3 += len; 3805 siz += len; 3806 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 3807 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 3808 &cp2, &cp3, &slen); 3809 *cp3++ = ','; 3810 NFSBCOPY(lsp->host, cp3, lsp->len); 3811 cp3 += lsp->len; 3812 *cp3++ = ':'; 3813 NFSBCOPY(str, cp3, stringlen); 3814 cp3 += stringlen; 3815 *cp3 = '\0'; 3816 siz += (lsp->len + stringlen + 2); 3817 free((caddr_t)lsp, M_TEMP); 3818 } 3819 } 3820 *fsrootp = cp; 3821 *srvp = cp2; 3822 *sump = xdrsum; 3823 NFSEXITCODE2(0, nd); 3824 return (0); 3825 nfsmout: 3826 if (cp != NULL) 3827 free(cp, M_NFSSTRING); 3828 if (cp2 != NULL) 3829 free(cp2, M_NFSSTRING); 3830 NFSEXITCODE2(error, nd); 3831 return (error); 3832 } 3833 3834 /* 3835 * Make the malloc'd space large enough. This is a pain, but the xdr 3836 * doesn't set an upper bound on the side, so... 3837 */ 3838 static void 3839 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 3840 { 3841 u_char *cp; 3842 int i; 3843 3844 if (siz <= *slenp) 3845 return; 3846 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 3847 NFSBCOPY(*cpp, cp, *slenp); 3848 free(*cpp, M_NFSSTRING); 3849 i = *cpp2 - *cpp; 3850 *cpp = cp; 3851 *cpp2 = cp + i; 3852 *slenp = siz + 1024; 3853 } 3854 3855 /* 3856 * Initialize the reply header data structures. 3857 */ 3858 APPLESTATIC void 3859 nfsrvd_rephead(struct nfsrv_descript *nd) 3860 { 3861 mbuf_t mreq; 3862 3863 /* 3864 * If this is a big reply, use a cluster. 3865 */ 3866 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 3867 nfs_bigreply[nd->nd_procnum]) { 3868 NFSMCLGET(mreq, M_WAITOK); 3869 nd->nd_mreq = mreq; 3870 nd->nd_mb = mreq; 3871 } else { 3872 NFSMGET(mreq); 3873 nd->nd_mreq = mreq; 3874 nd->nd_mb = mreq; 3875 } 3876 nd->nd_bpos = NFSMTOD(mreq, caddr_t); 3877 mbuf_setlen(mreq, 0); 3878 3879 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 3880 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 3881 } 3882 3883 /* 3884 * Lock a socket against others. 3885 * Currently used to serialize connect/disconnect attempts. 3886 */ 3887 int 3888 newnfs_sndlock(int *flagp) 3889 { 3890 struct timespec ts; 3891 3892 NFSLOCKSOCK(); 3893 while (*flagp & NFSR_SNDLOCK) { 3894 *flagp |= NFSR_WANTSND; 3895 ts.tv_sec = 0; 3896 ts.tv_nsec = 0; 3897 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 3898 PZERO - 1, "nfsndlck", &ts); 3899 } 3900 *flagp |= NFSR_SNDLOCK; 3901 NFSUNLOCKSOCK(); 3902 return (0); 3903 } 3904 3905 /* 3906 * Unlock the stream socket for others. 3907 */ 3908 void 3909 newnfs_sndunlock(int *flagp) 3910 { 3911 3912 NFSLOCKSOCK(); 3913 if ((*flagp & NFSR_SNDLOCK) == 0) 3914 panic("nfs sndunlock"); 3915 *flagp &= ~NFSR_SNDLOCK; 3916 if (*flagp & NFSR_WANTSND) { 3917 *flagp &= ~NFSR_WANTSND; 3918 wakeup((caddr_t)flagp); 3919 } 3920 NFSUNLOCKSOCK(); 3921 } 3922 3923 APPLESTATIC int 3924 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa, 3925 int *isudp) 3926 { 3927 struct sockaddr_in *sad; 3928 struct sockaddr_in6 *sad6; 3929 struct in_addr saddr; 3930 uint32_t portnum, *tl; 3931 int af = 0, i, j, k; 3932 char addr[64], protocol[5], *cp; 3933 int cantparse = 0, error = 0; 3934 uint16_t portv; 3935 3936 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3937 i = fxdr_unsigned(int, *tl); 3938 if (i >= 3 && i <= 4) { 3939 error = nfsrv_mtostr(nd, protocol, i); 3940 if (error) 3941 goto nfsmout; 3942 if (strcmp(protocol, "tcp") == 0) { 3943 af = AF_INET; 3944 *isudp = 0; 3945 } else if (strcmp(protocol, "udp") == 0) { 3946 af = AF_INET; 3947 *isudp = 1; 3948 } else if (strcmp(protocol, "tcp6") == 0) { 3949 af = AF_INET6; 3950 *isudp = 0; 3951 } else if (strcmp(protocol, "udp6") == 0) { 3952 af = AF_INET6; 3953 *isudp = 1; 3954 } else 3955 cantparse = 1; 3956 } else { 3957 cantparse = 1; 3958 if (i > 0) { 3959 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3960 if (error) 3961 goto nfsmout; 3962 } 3963 } 3964 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3965 i = fxdr_unsigned(int, *tl); 3966 if (i < 0) { 3967 error = NFSERR_BADXDR; 3968 goto nfsmout; 3969 } else if (cantparse == 0 && i >= 11 && i < 64) { 3970 /* 3971 * The shortest address is 11chars and the longest is < 64. 3972 */ 3973 error = nfsrv_mtostr(nd, addr, i); 3974 if (error) 3975 goto nfsmout; 3976 3977 /* Find the port# at the end and extract that. */ 3978 i = strlen(addr); 3979 k = 0; 3980 cp = &addr[i - 1]; 3981 /* Count back two '.'s from end to get port# field. */ 3982 for (j = 0; j < i; j++) { 3983 if (*cp == '.') { 3984 k++; 3985 if (k == 2) 3986 break; 3987 } 3988 cp--; 3989 } 3990 if (k == 2) { 3991 /* 3992 * The NFSv4 port# is appended as .N.N, where N is 3993 * a decimal # in the range 0-255, just like an inet4 3994 * address. Cheat and use inet_aton(), which will 3995 * return a Class A address and then shift the high 3996 * order 8bits over to convert it to the port#. 3997 */ 3998 *cp++ = '\0'; 3999 if (inet_aton(cp, &saddr) == 1) { 4000 portnum = ntohl(saddr.s_addr); 4001 portv = (uint16_t)((portnum >> 16) | 4002 (portnum & 0xff)); 4003 } else 4004 cantparse = 1; 4005 } else 4006 cantparse = 1; 4007 if (cantparse == 0) { 4008 if (af == AF_INET) { 4009 sad = (struct sockaddr_in *)sa; 4010 if (inet_pton(af, addr, &sad->sin_addr) == 1) { 4011 sad->sin_len = sizeof(*sad); 4012 sad->sin_family = AF_INET; 4013 sad->sin_port = htons(portv); 4014 return (0); 4015 } 4016 } else { 4017 sad6 = (struct sockaddr_in6 *)sa; 4018 if (inet_pton(af, addr, &sad6->sin6_addr) 4019 == 1) { 4020 sad6->sin6_len = sizeof(*sad6); 4021 sad6->sin6_family = AF_INET6; 4022 sad6->sin6_port = htons(portv); 4023 return (0); 4024 } 4025 } 4026 } 4027 } else { 4028 if (i > 0) { 4029 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4030 if (error) 4031 goto nfsmout; 4032 } 4033 } 4034 error = EPERM; 4035 nfsmout: 4036 return (error); 4037 } 4038 4039 /* 4040 * Handle an NFSv4.1 Sequence request for the session. 4041 * If reply != NULL, use it to return the cached reply, as required. 4042 * The client gets a cached reply via this call for callbacks, however the 4043 * server gets a cached reply via the nfsv4_seqsess_cachereply() call. 4044 */ 4045 int 4046 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 4047 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 4048 { 4049 int error; 4050 4051 error = 0; 4052 if (reply != NULL) 4053 *reply = NULL; 4054 if (slotid > maxslot) 4055 return (NFSERR_BADSLOT); 4056 if (seqid == slots[slotid].nfssl_seq) { 4057 /* A retry. */ 4058 if (slots[slotid].nfssl_inprog != 0) 4059 error = NFSERR_DELAY; 4060 else if (slots[slotid].nfssl_reply != NULL) { 4061 if (reply != NULL) { 4062 *reply = slots[slotid].nfssl_reply; 4063 slots[slotid].nfssl_reply = NULL; 4064 } 4065 slots[slotid].nfssl_inprog = 1; 4066 error = NFSERR_REPLYFROMCACHE; 4067 } else 4068 /* No reply cached, so just do it. */ 4069 slots[slotid].nfssl_inprog = 1; 4070 } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 4071 if (slots[slotid].nfssl_reply != NULL) 4072 m_freem(slots[slotid].nfssl_reply); 4073 slots[slotid].nfssl_reply = NULL; 4074 slots[slotid].nfssl_inprog = 1; 4075 slots[slotid].nfssl_seq++; 4076 } else 4077 error = NFSERR_SEQMISORDERED; 4078 return (error); 4079 } 4080 4081 /* 4082 * Cache this reply for the slot. 4083 * Use the "rep" argument to return the cached reply if repstat is set to 4084 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value. 4085 */ 4086 void 4087 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat, 4088 struct mbuf **rep) 4089 { 4090 4091 if (repstat == NFSERR_REPLYFROMCACHE) { 4092 *rep = slots[slotid].nfssl_reply; 4093 slots[slotid].nfssl_reply = NULL; 4094 } else { 4095 if (slots[slotid].nfssl_reply != NULL) 4096 m_freem(slots[slotid].nfssl_reply); 4097 slots[slotid].nfssl_reply = *rep; 4098 } 4099 slots[slotid].nfssl_inprog = 0; 4100 } 4101 4102 /* 4103 * Generate the xdr for an NFSv4.1 Sequence Operation. 4104 */ 4105 APPLESTATIC void 4106 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, 4107 struct nfsclsession *sep, int dont_replycache) 4108 { 4109 uint32_t *tl, slotseq = 0; 4110 int error, maxslot, slotpos; 4111 uint8_t sessionid[NFSX_V4SESSIONID]; 4112 4113 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq, 4114 sessionid); 4115 if (error != 0) 4116 return; 4117 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot")); 4118 4119 /* Build the Sequence arguments. */ 4120 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 4121 bcopy(sessionid, tl, NFSX_V4SESSIONID); 4122 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4123 nd->nd_slotseq = tl; 4124 *tl++ = txdr_unsigned(slotseq); 4125 *tl++ = txdr_unsigned(slotpos); 4126 *tl++ = txdr_unsigned(maxslot); 4127 if (dont_replycache == 0) 4128 *tl = newnfs_true; 4129 else 4130 *tl = newnfs_false; 4131 nd->nd_flag |= ND_HASSEQUENCE; 4132 } 4133 4134 int 4135 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep, 4136 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid) 4137 { 4138 int i, maxslot, slotpos; 4139 uint64_t bitval; 4140 4141 /* Find an unused slot. */ 4142 slotpos = -1; 4143 maxslot = -1; 4144 mtx_lock(&sep->nfsess_mtx); 4145 do { 4146 bitval = 1; 4147 for (i = 0; i < sep->nfsess_foreslots; i++) { 4148 if ((bitval & sep->nfsess_slots) == 0) { 4149 slotpos = i; 4150 sep->nfsess_slots |= bitval; 4151 sep->nfsess_slotseq[i]++; 4152 *slotseqp = sep->nfsess_slotseq[i]; 4153 break; 4154 } 4155 bitval <<= 1; 4156 } 4157 if (slotpos == -1) { 4158 /* 4159 * If a forced dismount is in progress, just return. 4160 * This RPC attempt will fail when it calls 4161 * newnfs_request(). 4162 */ 4163 if (nmp != NULL && 4164 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) 4165 != 0) { 4166 mtx_unlock(&sep->nfsess_mtx); 4167 return (ESTALE); 4168 } 4169 /* Wake up once/sec, to check for a forced dismount. */ 4170 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 4171 PZERO, "nfsclseq", hz); 4172 } 4173 } while (slotpos == -1); 4174 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 4175 bitval = 1; 4176 for (i = 0; i < 64; i++) { 4177 if ((bitval & sep->nfsess_slots) != 0) 4178 maxslot = i; 4179 bitval <<= 1; 4180 } 4181 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 4182 mtx_unlock(&sep->nfsess_mtx); 4183 *slotposp = slotpos; 4184 *maxslotp = maxslot; 4185 return (0); 4186 } 4187 4188 /* 4189 * Free a session slot. 4190 */ 4191 APPLESTATIC void 4192 nfsv4_freeslot(struct nfsclsession *sep, int slot) 4193 { 4194 uint64_t bitval; 4195 4196 bitval = 1; 4197 if (slot > 0) 4198 bitval <<= slot; 4199 mtx_lock(&sep->nfsess_mtx); 4200 if ((bitval & sep->nfsess_slots) == 0) 4201 printf("freeing free slot!!\n"); 4202 sep->nfsess_slots &= ~bitval; 4203 wakeup(&sep->nfsess_slots); 4204 mtx_unlock(&sep->nfsess_mtx); 4205 } 4206 4207