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