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_flag & NFSID_INITIALIZE) { 3178 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); 3179 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 3180 nidp->nid_namelen); 3181 if (error != 0) { 3182 free(cp, M_NFSSTRING); 3183 goto out; 3184 } 3185 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) { 3186 /* 3187 * Free up all the old stuff and reinitialize hash 3188 * lists. All mutexes for both lists must be locked, 3189 * with the user/group name ones before the uid/gid 3190 * ones, to avoid a LOR. 3191 */ 3192 for (i = 0; i < nfsrv_lughashsize; i++) 3193 mtx_lock(&nfsusernamehash[i].mtx); 3194 for (i = 0; i < nfsrv_lughashsize; i++) 3195 mtx_lock(&nfsuserhash[i].mtx); 3196 for (i = 0; i < nfsrv_lughashsize; i++) 3197 TAILQ_FOREACH_SAFE(usrp, 3198 &nfsuserhash[i].lughead, lug_numhash, nusrp) 3199 nfsrv_removeuser(usrp, 1); 3200 for (i = 0; i < nfsrv_lughashsize; i++) 3201 mtx_unlock(&nfsuserhash[i].mtx); 3202 for (i = 0; i < nfsrv_lughashsize; i++) 3203 mtx_unlock(&nfsusernamehash[i].mtx); 3204 for (i = 0; i < nfsrv_lughashsize; i++) 3205 mtx_lock(&nfsgroupnamehash[i].mtx); 3206 for (i = 0; i < nfsrv_lughashsize; i++) 3207 mtx_lock(&nfsgrouphash[i].mtx); 3208 for (i = 0; i < nfsrv_lughashsize; i++) 3209 TAILQ_FOREACH_SAFE(usrp, 3210 &nfsgrouphash[i].lughead, lug_numhash, 3211 nusrp) 3212 nfsrv_removeuser(usrp, 0); 3213 for (i = 0; i < nfsrv_lughashsize; i++) 3214 mtx_unlock(&nfsgrouphash[i].mtx); 3215 for (i = 0; i < nfsrv_lughashsize; i++) 3216 mtx_unlock(&nfsgroupnamehash[i].mtx); 3217 free(nfsrv_dnsname, M_NFSSTRING); 3218 nfsrv_dnsname = NULL; 3219 } 3220 if (nfsuserhash == NULL) { 3221 /* Allocate the hash tables. */ 3222 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) * 3223 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3224 M_ZERO); 3225 for (i = 0; i < nfsrv_lughashsize; i++) 3226 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash", 3227 NULL, MTX_DEF | MTX_DUPOK); 3228 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) * 3229 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3230 M_ZERO); 3231 for (i = 0; i < nfsrv_lughashsize; i++) 3232 mtx_init(&nfsusernamehash[i].mtx, 3233 "nfsusrhash", NULL, MTX_DEF | 3234 MTX_DUPOK); 3235 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) * 3236 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3237 M_ZERO); 3238 for (i = 0; i < nfsrv_lughashsize; i++) 3239 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash", 3240 NULL, MTX_DEF | MTX_DUPOK); 3241 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) * 3242 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3243 M_ZERO); 3244 for (i = 0; i < nfsrv_lughashsize; i++) 3245 mtx_init(&nfsgroupnamehash[i].mtx, 3246 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK); 3247 } 3248 /* (Re)initialize the list heads. */ 3249 for (i = 0; i < nfsrv_lughashsize; i++) 3250 TAILQ_INIT(&nfsuserhash[i].lughead); 3251 for (i = 0; i < nfsrv_lughashsize; i++) 3252 TAILQ_INIT(&nfsusernamehash[i].lughead); 3253 for (i = 0; i < nfsrv_lughashsize; i++) 3254 TAILQ_INIT(&nfsgrouphash[i].lughead); 3255 for (i = 0; i < nfsrv_lughashsize; i++) 3256 TAILQ_INIT(&nfsgroupnamehash[i].lughead); 3257 3258 /* 3259 * Put name in "DNS" string. 3260 */ 3261 nfsrv_dnsname = cp; 3262 nfsrv_defaultuid = nidp->nid_uid; 3263 nfsrv_defaultgid = nidp->nid_gid; 3264 nfsrv_usercnt = 0; 3265 nfsrv_usermax = nidp->nid_usermax; 3266 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen); 3267 goto out; 3268 } 3269 3270 /* 3271 * malloc the new one now, so any potential sleep occurs before 3272 * manipulation of the lists. 3273 */ 3274 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, 3275 M_NFSUSERGROUP, M_WAITOK | M_ZERO); 3276 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 3277 nidp->nid_namelen); 3278 if (error == 0 && nidp->nid_ngroup > 0 && 3279 (nidp->nid_flag & NFSID_ADDUID) != 0) { 3280 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP, 3281 M_WAITOK); 3282 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps, 3283 sizeof(gid_t) * nidp->nid_ngroup); 3284 if (error == 0) { 3285 /* 3286 * Create a credential just like svc_getcred(), 3287 * but using the group list provided. 3288 */ 3289 cr = crget(); 3290 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; 3291 crsetgroups(cr, nidp->nid_ngroup, grps); 3292 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; 3293 cr->cr_prison = &prison0; 3294 prison_hold(cr->cr_prison); 3295 #ifdef MAC 3296 mac_cred_associate_nfsd(cr); 3297 #endif 3298 newusrp->lug_cred = cr; 3299 } 3300 free(grps, M_TEMP); 3301 } 3302 if (error) { 3303 free(newusrp, M_NFSUSERGROUP); 3304 goto out; 3305 } 3306 newusrp->lug_namelen = nidp->nid_namelen; 3307 3308 /* 3309 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed 3310 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group. 3311 * The flags user_locked, username_locked, group_locked and 3312 * groupname_locked are set to indicate all of those hash lists are 3313 * locked. hp_name != NULL and hp_idnum != NULL indicates that 3314 * the respective one mutex is locked. 3315 */ 3316 user_locked = username_locked = group_locked = groupname_locked = 0; 3317 hp_name = hp_idnum = NULL; 3318 3319 /* 3320 * Delete old entries, as required. 3321 */ 3322 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3323 /* Must lock all username hash lists first, to avoid a LOR. */ 3324 for (i = 0; i < nfsrv_lughashsize; i++) 3325 mtx_lock(&nfsusernamehash[i].mtx); 3326 username_locked = 1; 3327 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3328 mtx_lock(&hp_idnum->mtx); 3329 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3330 nusrp) { 3331 if (usrp->lug_uid == nidp->nid_uid) 3332 nfsrv_removeuser(usrp, 1); 3333 } 3334 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3335 hp_name = NFSUSERNAMEHASH(newusrp->lug_name, 3336 newusrp->lug_namelen); 3337 mtx_lock(&hp_name->mtx); 3338 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3339 nusrp) { 3340 if (usrp->lug_namelen == newusrp->lug_namelen && 3341 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3342 usrp->lug_namelen)) { 3343 thp = NFSUSERHASH(usrp->lug_uid); 3344 mtx_lock(&thp->mtx); 3345 nfsrv_removeuser(usrp, 1); 3346 mtx_unlock(&thp->mtx); 3347 } 3348 } 3349 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3350 mtx_lock(&hp_idnum->mtx); 3351 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3352 /* Must lock all groupname hash lists first, to avoid a LOR. */ 3353 for (i = 0; i < nfsrv_lughashsize; i++) 3354 mtx_lock(&nfsgroupnamehash[i].mtx); 3355 groupname_locked = 1; 3356 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3357 mtx_lock(&hp_idnum->mtx); 3358 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3359 nusrp) { 3360 if (usrp->lug_gid == nidp->nid_gid) 3361 nfsrv_removeuser(usrp, 0); 3362 } 3363 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3364 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name, 3365 newusrp->lug_namelen); 3366 mtx_lock(&hp_name->mtx); 3367 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3368 nusrp) { 3369 if (usrp->lug_namelen == newusrp->lug_namelen && 3370 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3371 usrp->lug_namelen)) { 3372 thp = NFSGROUPHASH(usrp->lug_gid); 3373 mtx_lock(&thp->mtx); 3374 nfsrv_removeuser(usrp, 0); 3375 mtx_unlock(&thp->mtx); 3376 } 3377 } 3378 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3379 mtx_lock(&hp_idnum->mtx); 3380 } 3381 3382 /* 3383 * Now, we can add the new one. 3384 */ 3385 if (nidp->nid_usertimeout) 3386 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3387 else 3388 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3389 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3390 newusrp->lug_uid = nidp->nid_uid; 3391 thp = NFSUSERHASH(newusrp->lug_uid); 3392 mtx_assert(&thp->mtx, MA_OWNED); 3393 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3394 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3395 mtx_assert(&thp->mtx, MA_OWNED); 3396 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3397 atomic_add_int(&nfsrv_usercnt, 1); 3398 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3399 newusrp->lug_gid = nidp->nid_gid; 3400 thp = NFSGROUPHASH(newusrp->lug_gid); 3401 mtx_assert(&thp->mtx, MA_OWNED); 3402 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3403 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3404 mtx_assert(&thp->mtx, MA_OWNED); 3405 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3406 atomic_add_int(&nfsrv_usercnt, 1); 3407 } else { 3408 if (newusrp->lug_cred != NULL) 3409 crfree(newusrp->lug_cred); 3410 free(newusrp, M_NFSUSERGROUP); 3411 } 3412 3413 /* 3414 * Once per second, allow one thread to trim the cache. 3415 */ 3416 if (lasttime < NFSD_MONOSEC && 3417 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) { 3418 /* 3419 * First, unlock the single mutexes, so that all entries 3420 * can be locked and any LOR is avoided. 3421 */ 3422 if (hp_name != NULL) { 3423 mtx_unlock(&hp_name->mtx); 3424 hp_name = NULL; 3425 } 3426 if (hp_idnum != NULL) { 3427 mtx_unlock(&hp_idnum->mtx); 3428 hp_idnum = NULL; 3429 } 3430 3431 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID | 3432 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) { 3433 if (username_locked == 0) { 3434 for (i = 0; i < nfsrv_lughashsize; i++) 3435 mtx_lock(&nfsusernamehash[i].mtx); 3436 username_locked = 1; 3437 } 3438 KASSERT(user_locked == 0, 3439 ("nfssvc_idname: user_locked")); 3440 for (i = 0; i < nfsrv_lughashsize; i++) 3441 mtx_lock(&nfsuserhash[i].mtx); 3442 user_locked = 1; 3443 for (i = 0; i < nfsrv_lughashsize; i++) { 3444 TAILQ_FOREACH_SAFE(usrp, 3445 &nfsuserhash[i].lughead, lug_numhash, 3446 nusrp) 3447 if (usrp->lug_expiry < NFSD_MONOSEC) 3448 nfsrv_removeuser(usrp, 1); 3449 } 3450 for (i = 0; i < nfsrv_lughashsize; i++) { 3451 /* 3452 * Trim the cache using an approximate LRU 3453 * algorithm. This code deletes the least 3454 * recently used entry on each hash list. 3455 */ 3456 if (nfsrv_usercnt <= nfsrv_usermax) 3457 break; 3458 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead); 3459 if (usrp != NULL) 3460 nfsrv_removeuser(usrp, 1); 3461 } 3462 } else { 3463 if (groupname_locked == 0) { 3464 for (i = 0; i < nfsrv_lughashsize; i++) 3465 mtx_lock(&nfsgroupnamehash[i].mtx); 3466 groupname_locked = 1; 3467 } 3468 KASSERT(group_locked == 0, 3469 ("nfssvc_idname: group_locked")); 3470 for (i = 0; i < nfsrv_lughashsize; i++) 3471 mtx_lock(&nfsgrouphash[i].mtx); 3472 group_locked = 1; 3473 for (i = 0; i < nfsrv_lughashsize; i++) { 3474 TAILQ_FOREACH_SAFE(usrp, 3475 &nfsgrouphash[i].lughead, lug_numhash, 3476 nusrp) 3477 if (usrp->lug_expiry < NFSD_MONOSEC) 3478 nfsrv_removeuser(usrp, 0); 3479 } 3480 for (i = 0; i < nfsrv_lughashsize; i++) { 3481 /* 3482 * Trim the cache using an approximate LRU 3483 * algorithm. This code deletes the least 3484 * recently user entry on each hash list. 3485 */ 3486 if (nfsrv_usercnt <= nfsrv_usermax) 3487 break; 3488 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead); 3489 if (usrp != NULL) 3490 nfsrv_removeuser(usrp, 0); 3491 } 3492 } 3493 lasttime = NFSD_MONOSEC; 3494 atomic_store_rel_int(&onethread, 0); 3495 } 3496 3497 /* Now, unlock all locked mutexes. */ 3498 if (hp_idnum != NULL) 3499 mtx_unlock(&hp_idnum->mtx); 3500 if (hp_name != NULL) 3501 mtx_unlock(&hp_name->mtx); 3502 if (user_locked != 0) 3503 for (i = 0; i < nfsrv_lughashsize; i++) 3504 mtx_unlock(&nfsuserhash[i].mtx); 3505 if (username_locked != 0) 3506 for (i = 0; i < nfsrv_lughashsize; i++) 3507 mtx_unlock(&nfsusernamehash[i].mtx); 3508 if (group_locked != 0) 3509 for (i = 0; i < nfsrv_lughashsize; i++) 3510 mtx_unlock(&nfsgrouphash[i].mtx); 3511 if (groupname_locked != 0) 3512 for (i = 0; i < nfsrv_lughashsize; i++) 3513 mtx_unlock(&nfsgroupnamehash[i].mtx); 3514 out: 3515 NFSEXITCODE(error); 3516 return (error); 3517 } 3518 3519 /* 3520 * Remove a user/group name element. 3521 */ 3522 static void 3523 nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser) 3524 { 3525 struct nfsrv_lughash *hp; 3526 3527 if (isuser != 0) { 3528 hp = NFSUSERHASH(usrp->lug_uid); 3529 mtx_assert(&hp->mtx, MA_OWNED); 3530 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3531 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3532 mtx_assert(&hp->mtx, MA_OWNED); 3533 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 3534 } else { 3535 hp = NFSGROUPHASH(usrp->lug_gid); 3536 mtx_assert(&hp->mtx, MA_OWNED); 3537 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3538 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3539 mtx_assert(&hp->mtx, MA_OWNED); 3540 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 3541 } 3542 atomic_add_int(&nfsrv_usercnt, -1); 3543 if (usrp->lug_cred != NULL) 3544 crfree(usrp->lug_cred); 3545 free(usrp, M_NFSUSERGROUP); 3546 } 3547 3548 /* 3549 * Free up all the allocations related to the name<-->id cache. 3550 * This function should only be called when the nfsuserd daemon isn't 3551 * running, since it doesn't do any locking. 3552 * This function is meant to be used when the nfscommon module is unloaded. 3553 */ 3554 APPLESTATIC void 3555 nfsrv_cleanusergroup(void) 3556 { 3557 struct nfsrv_lughash *hp, *hp2; 3558 struct nfsusrgrp *nusrp, *usrp; 3559 int i; 3560 3561 if (nfsuserhash == NULL) 3562 return; 3563 3564 for (i = 0; i < nfsrv_lughashsize; i++) { 3565 hp = &nfsuserhash[i]; 3566 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 3567 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3568 hp2 = NFSUSERNAMEHASH(usrp->lug_name, 3569 usrp->lug_namelen); 3570 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 3571 if (usrp->lug_cred != NULL) 3572 crfree(usrp->lug_cred); 3573 free(usrp, M_NFSUSERGROUP); 3574 } 3575 hp = &nfsgrouphash[i]; 3576 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 3577 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3578 hp2 = NFSGROUPNAMEHASH(usrp->lug_name, 3579 usrp->lug_namelen); 3580 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 3581 if (usrp->lug_cred != NULL) 3582 crfree(usrp->lug_cred); 3583 free(usrp, M_NFSUSERGROUP); 3584 } 3585 mtx_destroy(&nfsuserhash[i].mtx); 3586 mtx_destroy(&nfsusernamehash[i].mtx); 3587 mtx_destroy(&nfsgroupnamehash[i].mtx); 3588 mtx_destroy(&nfsgrouphash[i].mtx); 3589 } 3590 free(nfsuserhash, M_NFSUSERGROUP); 3591 free(nfsusernamehash, M_NFSUSERGROUP); 3592 free(nfsgrouphash, M_NFSUSERGROUP); 3593 free(nfsgroupnamehash, M_NFSUSERGROUP); 3594 free(nfsrv_dnsname, M_NFSSTRING); 3595 } 3596 3597 /* 3598 * This function scans a byte string and checks for UTF-8 compliance. 3599 * It returns 0 if it conforms and NFSERR_INVAL if not. 3600 */ 3601 APPLESTATIC int 3602 nfsrv_checkutf8(u_int8_t *cp, int len) 3603 { 3604 u_int32_t val = 0x0; 3605 int cnt = 0, gotd = 0, shift = 0; 3606 u_int8_t byte; 3607 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 3608 int error = 0; 3609 3610 /* 3611 * Here are what the variables are used for: 3612 * val - the calculated value of a multibyte char, used to check 3613 * that it was coded with the correct range 3614 * cnt - the number of 10xxxxxx bytes to follow 3615 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 3616 * shift - lower order bits of range (ie. "val >> shift" should 3617 * not be 0, in other words, dividing by the lower bound 3618 * of the range should get a non-zero value) 3619 * byte - used to calculate cnt 3620 */ 3621 while (len > 0) { 3622 if (cnt > 0) { 3623 /* This handles the 10xxxxxx bytes */ 3624 if ((*cp & 0xc0) != 0x80 || 3625 (gotd && (*cp & 0x20))) { 3626 error = NFSERR_INVAL; 3627 goto out; 3628 } 3629 gotd = 0; 3630 val <<= 6; 3631 val |= (*cp & 0x3f); 3632 cnt--; 3633 if (cnt == 0 && (val >> shift) == 0x0) { 3634 error = NFSERR_INVAL; 3635 goto out; 3636 } 3637 } else if (*cp & 0x80) { 3638 /* first byte of multi byte char */ 3639 byte = *cp; 3640 while ((byte & 0x40) && cnt < 6) { 3641 cnt++; 3642 byte <<= 1; 3643 } 3644 if (cnt == 0 || cnt == 6) { 3645 error = NFSERR_INVAL; 3646 goto out; 3647 } 3648 val = (*cp & (0x3f >> cnt)); 3649 shift = utf8_shift[cnt - 1]; 3650 if (cnt == 2 && val == 0xd) 3651 /* Check for the 0xd800-0xdfff case */ 3652 gotd = 1; 3653 } 3654 cp++; 3655 len--; 3656 } 3657 if (cnt > 0) 3658 error = NFSERR_INVAL; 3659 3660 out: 3661 NFSEXITCODE(error); 3662 return (error); 3663 } 3664 3665 /* 3666 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 3667 * strings, one with the root path in it and the other with the list of 3668 * locations. The list is in the same format as is found in nfr_refs. 3669 * It is a "," separated list of entries, where each of them is of the 3670 * form <server>:<rootpath>. For example 3671 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 3672 * The nilp argument is set to 1 for the special case of a null fs_root 3673 * and an empty server list. 3674 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 3675 * number of xdr bytes parsed in sump. 3676 */ 3677 static int 3678 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 3679 int *sump, int *nilp) 3680 { 3681 u_int32_t *tl; 3682 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 3683 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 3684 struct list { 3685 SLIST_ENTRY(list) next; 3686 int len; 3687 u_char host[1]; 3688 } *lsp, *nlsp; 3689 SLIST_HEAD(, list) head; 3690 3691 *fsrootp = NULL; 3692 *srvp = NULL; 3693 *nilp = 0; 3694 3695 /* 3696 * Get the fs_root path and check for the special case of null path 3697 * and 0 length server list. 3698 */ 3699 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3700 len = fxdr_unsigned(int, *tl); 3701 if (len < 0 || len > 10240) { 3702 error = NFSERR_BADXDR; 3703 goto nfsmout; 3704 } 3705 if (len == 0) { 3706 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3707 if (*tl != 0) { 3708 error = NFSERR_BADXDR; 3709 goto nfsmout; 3710 } 3711 *nilp = 1; 3712 *sump = 2 * NFSX_UNSIGNED; 3713 error = 0; 3714 goto nfsmout; 3715 } 3716 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 3717 error = nfsrv_mtostr(nd, cp, len); 3718 if (!error) { 3719 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3720 cnt = fxdr_unsigned(int, *tl); 3721 if (cnt <= 0) 3722 error = NFSERR_BADXDR; 3723 } 3724 if (error) 3725 goto nfsmout; 3726 3727 /* 3728 * Now, loop through the location list and make up the srvlist. 3729 */ 3730 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3731 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 3732 slen = 1024; 3733 siz = 0; 3734 for (i = 0; i < cnt; i++) { 3735 SLIST_INIT(&head); 3736 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3737 nsrv = fxdr_unsigned(int, *tl); 3738 if (nsrv <= 0) { 3739 error = NFSERR_BADXDR; 3740 goto nfsmout; 3741 } 3742 3743 /* 3744 * Handle the first server by putting it in the srvstr. 3745 */ 3746 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3747 len = fxdr_unsigned(int, *tl); 3748 if (len <= 0 || len > 1024) { 3749 error = NFSERR_BADXDR; 3750 goto nfsmout; 3751 } 3752 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 3753 if (cp3 != cp2) { 3754 *cp3++ = ','; 3755 siz++; 3756 } 3757 error = nfsrv_mtostr(nd, cp3, len); 3758 if (error) 3759 goto nfsmout; 3760 cp3 += len; 3761 *cp3++ = ':'; 3762 siz += (len + 1); 3763 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3764 for (j = 1; j < nsrv; j++) { 3765 /* 3766 * Yuck, put them in an slist and process them later. 3767 */ 3768 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3769 len = fxdr_unsigned(int, *tl); 3770 if (len <= 0 || len > 1024) { 3771 error = NFSERR_BADXDR; 3772 goto nfsmout; 3773 } 3774 lsp = (struct list *)malloc(sizeof (struct list) 3775 + len, M_TEMP, M_WAITOK); 3776 error = nfsrv_mtostr(nd, lsp->host, len); 3777 if (error) 3778 goto nfsmout; 3779 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3780 lsp->len = len; 3781 SLIST_INSERT_HEAD(&head, lsp, next); 3782 } 3783 3784 /* 3785 * Finally, we can get the path. 3786 */ 3787 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3788 len = fxdr_unsigned(int, *tl); 3789 if (len <= 0 || len > 1024) { 3790 error = NFSERR_BADXDR; 3791 goto nfsmout; 3792 } 3793 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 3794 error = nfsrv_mtostr(nd, cp3, len); 3795 if (error) 3796 goto nfsmout; 3797 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3798 str = cp3; 3799 stringlen = len; 3800 cp3 += len; 3801 siz += len; 3802 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 3803 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 3804 &cp2, &cp3, &slen); 3805 *cp3++ = ','; 3806 NFSBCOPY(lsp->host, cp3, lsp->len); 3807 cp3 += lsp->len; 3808 *cp3++ = ':'; 3809 NFSBCOPY(str, cp3, stringlen); 3810 cp3 += stringlen; 3811 *cp3 = '\0'; 3812 siz += (lsp->len + stringlen + 2); 3813 free((caddr_t)lsp, M_TEMP); 3814 } 3815 } 3816 *fsrootp = cp; 3817 *srvp = cp2; 3818 *sump = xdrsum; 3819 NFSEXITCODE2(0, nd); 3820 return (0); 3821 nfsmout: 3822 if (cp != NULL) 3823 free(cp, M_NFSSTRING); 3824 if (cp2 != NULL) 3825 free(cp2, M_NFSSTRING); 3826 NFSEXITCODE2(error, nd); 3827 return (error); 3828 } 3829 3830 /* 3831 * Make the malloc'd space large enough. This is a pain, but the xdr 3832 * doesn't set an upper bound on the side, so... 3833 */ 3834 static void 3835 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 3836 { 3837 u_char *cp; 3838 int i; 3839 3840 if (siz <= *slenp) 3841 return; 3842 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 3843 NFSBCOPY(*cpp, cp, *slenp); 3844 free(*cpp, M_NFSSTRING); 3845 i = *cpp2 - *cpp; 3846 *cpp = cp; 3847 *cpp2 = cp + i; 3848 *slenp = siz + 1024; 3849 } 3850 3851 /* 3852 * Initialize the reply header data structures. 3853 */ 3854 APPLESTATIC void 3855 nfsrvd_rephead(struct nfsrv_descript *nd) 3856 { 3857 mbuf_t mreq; 3858 3859 /* 3860 * If this is a big reply, use a cluster. 3861 */ 3862 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 3863 nfs_bigreply[nd->nd_procnum]) { 3864 NFSMCLGET(mreq, M_WAITOK); 3865 nd->nd_mreq = mreq; 3866 nd->nd_mb = mreq; 3867 } else { 3868 NFSMGET(mreq); 3869 nd->nd_mreq = mreq; 3870 nd->nd_mb = mreq; 3871 } 3872 nd->nd_bpos = NFSMTOD(mreq, caddr_t); 3873 mbuf_setlen(mreq, 0); 3874 3875 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 3876 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 3877 } 3878 3879 /* 3880 * Lock a socket against others. 3881 * Currently used to serialize connect/disconnect attempts. 3882 */ 3883 int 3884 newnfs_sndlock(int *flagp) 3885 { 3886 struct timespec ts; 3887 3888 NFSLOCKSOCK(); 3889 while (*flagp & NFSR_SNDLOCK) { 3890 *flagp |= NFSR_WANTSND; 3891 ts.tv_sec = 0; 3892 ts.tv_nsec = 0; 3893 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 3894 PZERO - 1, "nfsndlck", &ts); 3895 } 3896 *flagp |= NFSR_SNDLOCK; 3897 NFSUNLOCKSOCK(); 3898 return (0); 3899 } 3900 3901 /* 3902 * Unlock the stream socket for others. 3903 */ 3904 void 3905 newnfs_sndunlock(int *flagp) 3906 { 3907 3908 NFSLOCKSOCK(); 3909 if ((*flagp & NFSR_SNDLOCK) == 0) 3910 panic("nfs sndunlock"); 3911 *flagp &= ~NFSR_SNDLOCK; 3912 if (*flagp & NFSR_WANTSND) { 3913 *flagp &= ~NFSR_WANTSND; 3914 wakeup((caddr_t)flagp); 3915 } 3916 NFSUNLOCKSOCK(); 3917 } 3918 3919 APPLESTATIC int 3920 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa, 3921 int *isudp) 3922 { 3923 struct sockaddr_in *sad; 3924 struct sockaddr_in6 *sad6; 3925 struct in_addr saddr; 3926 uint32_t portnum, *tl; 3927 int af = 0, i, j, k; 3928 char addr[64], protocol[5], *cp; 3929 int cantparse = 0, error = 0; 3930 uint16_t portv; 3931 3932 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3933 i = fxdr_unsigned(int, *tl); 3934 if (i >= 3 && i <= 4) { 3935 error = nfsrv_mtostr(nd, protocol, i); 3936 if (error) 3937 goto nfsmout; 3938 if (strcmp(protocol, "tcp") == 0) { 3939 af = AF_INET; 3940 *isudp = 0; 3941 } else if (strcmp(protocol, "udp") == 0) { 3942 af = AF_INET; 3943 *isudp = 1; 3944 } else if (strcmp(protocol, "tcp6") == 0) { 3945 af = AF_INET6; 3946 *isudp = 0; 3947 } else if (strcmp(protocol, "udp6") == 0) { 3948 af = AF_INET6; 3949 *isudp = 1; 3950 } else 3951 cantparse = 1; 3952 } else { 3953 cantparse = 1; 3954 if (i > 0) { 3955 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3956 if (error) 3957 goto nfsmout; 3958 } 3959 } 3960 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3961 i = fxdr_unsigned(int, *tl); 3962 if (i < 0) { 3963 error = NFSERR_BADXDR; 3964 goto nfsmout; 3965 } else if (cantparse == 0 && i >= 11 && i < 64) { 3966 /* 3967 * The shortest address is 11chars and the longest is < 64. 3968 */ 3969 error = nfsrv_mtostr(nd, addr, i); 3970 if (error) 3971 goto nfsmout; 3972 3973 /* Find the port# at the end and extract that. */ 3974 i = strlen(addr); 3975 k = 0; 3976 cp = &addr[i - 1]; 3977 /* Count back two '.'s from end to get port# field. */ 3978 for (j = 0; j < i; j++) { 3979 if (*cp == '.') { 3980 k++; 3981 if (k == 2) 3982 break; 3983 } 3984 cp--; 3985 } 3986 if (k == 2) { 3987 /* 3988 * The NFSv4 port# is appended as .N.N, where N is 3989 * a decimal # in the range 0-255, just like an inet4 3990 * address. Cheat and use inet_aton(), which will 3991 * return a Class A address and then shift the high 3992 * order 8bits over to convert it to the port#. 3993 */ 3994 *cp++ = '\0'; 3995 if (inet_aton(cp, &saddr) == 1) { 3996 portnum = ntohl(saddr.s_addr); 3997 portv = (uint16_t)((portnum >> 16) | 3998 (portnum & 0xff)); 3999 } else 4000 cantparse = 1; 4001 } else 4002 cantparse = 1; 4003 if (cantparse == 0) { 4004 if (af == AF_INET) { 4005 sad = (struct sockaddr_in *)sa; 4006 if (inet_pton(af, addr, &sad->sin_addr) == 1) { 4007 sad->sin_len = sizeof(*sad); 4008 sad->sin_family = AF_INET; 4009 sad->sin_port = htons(portv); 4010 return (0); 4011 } 4012 } else { 4013 sad6 = (struct sockaddr_in6 *)sa; 4014 if (inet_pton(af, addr, &sad6->sin6_addr) 4015 == 1) { 4016 sad6->sin6_len = sizeof(*sad6); 4017 sad6->sin6_family = AF_INET6; 4018 sad6->sin6_port = htons(portv); 4019 return (0); 4020 } 4021 } 4022 } 4023 } else { 4024 if (i > 0) { 4025 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4026 if (error) 4027 goto nfsmout; 4028 } 4029 } 4030 error = EPERM; 4031 nfsmout: 4032 return (error); 4033 } 4034 4035 /* 4036 * Handle an NFSv4.1 Sequence request for the session. 4037 * If reply != NULL, use it to return the cached reply, as required. 4038 * The client gets a cached reply via this call for callbacks, however the 4039 * server gets a cached reply via the nfsv4_seqsess_cachereply() call. 4040 */ 4041 int 4042 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 4043 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 4044 { 4045 int error; 4046 4047 error = 0; 4048 if (reply != NULL) 4049 *reply = NULL; 4050 if (slotid > maxslot) 4051 return (NFSERR_BADSLOT); 4052 if (seqid == slots[slotid].nfssl_seq) { 4053 /* A retry. */ 4054 if (slots[slotid].nfssl_inprog != 0) 4055 error = NFSERR_DELAY; 4056 else if (slots[slotid].nfssl_reply != NULL) { 4057 if (reply != NULL) { 4058 *reply = slots[slotid].nfssl_reply; 4059 slots[slotid].nfssl_reply = NULL; 4060 } 4061 slots[slotid].nfssl_inprog = 1; 4062 error = NFSERR_REPLYFROMCACHE; 4063 } else 4064 /* No reply cached, so just do it. */ 4065 slots[slotid].nfssl_inprog = 1; 4066 } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 4067 if (slots[slotid].nfssl_reply != NULL) 4068 m_freem(slots[slotid].nfssl_reply); 4069 slots[slotid].nfssl_reply = NULL; 4070 slots[slotid].nfssl_inprog = 1; 4071 slots[slotid].nfssl_seq++; 4072 } else 4073 error = NFSERR_SEQMISORDERED; 4074 return (error); 4075 } 4076 4077 /* 4078 * Cache this reply for the slot. 4079 * Use the "rep" argument to return the cached reply if repstat is set to 4080 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value. 4081 */ 4082 void 4083 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat, 4084 struct mbuf **rep) 4085 { 4086 4087 if (repstat == NFSERR_REPLYFROMCACHE) { 4088 *rep = slots[slotid].nfssl_reply; 4089 slots[slotid].nfssl_reply = NULL; 4090 } else { 4091 if (slots[slotid].nfssl_reply != NULL) 4092 m_freem(slots[slotid].nfssl_reply); 4093 slots[slotid].nfssl_reply = *rep; 4094 } 4095 slots[slotid].nfssl_inprog = 0; 4096 } 4097 4098 /* 4099 * Generate the xdr for an NFSv4.1 Sequence Operation. 4100 */ 4101 APPLESTATIC void 4102 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, 4103 struct nfsclsession *sep, int dont_replycache) 4104 { 4105 uint32_t *tl, slotseq = 0; 4106 int error, maxslot, slotpos; 4107 uint8_t sessionid[NFSX_V4SESSIONID]; 4108 4109 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq, 4110 sessionid); 4111 if (error != 0) 4112 return; 4113 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot")); 4114 4115 /* Build the Sequence arguments. */ 4116 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 4117 bcopy(sessionid, tl, NFSX_V4SESSIONID); 4118 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4119 nd->nd_slotseq = tl; 4120 *tl++ = txdr_unsigned(slotseq); 4121 *tl++ = txdr_unsigned(slotpos); 4122 *tl++ = txdr_unsigned(maxslot); 4123 if (dont_replycache == 0) 4124 *tl = newnfs_true; 4125 else 4126 *tl = newnfs_false; 4127 nd->nd_flag |= ND_HASSEQUENCE; 4128 } 4129 4130 int 4131 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep, 4132 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid) 4133 { 4134 int i, maxslot, slotpos; 4135 uint64_t bitval; 4136 4137 /* Find an unused slot. */ 4138 slotpos = -1; 4139 maxslot = -1; 4140 mtx_lock(&sep->nfsess_mtx); 4141 do { 4142 bitval = 1; 4143 for (i = 0; i < sep->nfsess_foreslots; i++) { 4144 if ((bitval & sep->nfsess_slots) == 0) { 4145 slotpos = i; 4146 sep->nfsess_slots |= bitval; 4147 sep->nfsess_slotseq[i]++; 4148 *slotseqp = sep->nfsess_slotseq[i]; 4149 break; 4150 } 4151 bitval <<= 1; 4152 } 4153 if (slotpos == -1) { 4154 /* 4155 * If a forced dismount is in progress, just return. 4156 * This RPC attempt will fail when it calls 4157 * newnfs_request(). 4158 */ 4159 if (nmp != NULL && 4160 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) 4161 != 0) { 4162 mtx_unlock(&sep->nfsess_mtx); 4163 return (ESTALE); 4164 } 4165 /* Wake up once/sec, to check for a forced dismount. */ 4166 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 4167 PZERO, "nfsclseq", hz); 4168 } 4169 } while (slotpos == -1); 4170 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 4171 bitval = 1; 4172 for (i = 0; i < 64; i++) { 4173 if ((bitval & sep->nfsess_slots) != 0) 4174 maxslot = i; 4175 bitval <<= 1; 4176 } 4177 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 4178 mtx_unlock(&sep->nfsess_mtx); 4179 *slotposp = slotpos; 4180 *maxslotp = maxslot; 4181 return (0); 4182 } 4183 4184 /* 4185 * Free a session slot. 4186 */ 4187 APPLESTATIC void 4188 nfsv4_freeslot(struct nfsclsession *sep, int slot) 4189 { 4190 uint64_t bitval; 4191 4192 bitval = 1; 4193 if (slot > 0) 4194 bitval <<= slot; 4195 mtx_lock(&sep->nfsess_mtx); 4196 if ((bitval & sep->nfsess_slots) == 0) 4197 printf("freeing free slot!!\n"); 4198 sep->nfsess_slots &= ~bitval; 4199 wakeup(&sep->nfsess_slots); 4200 mtx_unlock(&sep->nfsess_mtx); 4201 } 4202 4203