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