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