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