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, rem, 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 rem = fullsiz - size; 508 if (set_true) { 509 bytesize = 2 * NFSX_UNSIGNED + fullsiz; 510 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 511 *tl = newnfs_true; 512 } else { 513 bytesize = NFSX_UNSIGNED + fullsiz; 514 } 515 (void) nfsm_strtom(nd, fhp, size); 516 break; 517 } 518 return (bytesize); 519 } 520 521 /* 522 * This function compares two net addresses by family and returns TRUE 523 * if they are the same host. 524 * If there is any doubt, return FALSE. 525 * The AF_INET family is handled as a special case so that address mbufs 526 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 527 */ 528 APPLESTATIC int 529 nfsaddr_match(int family, union nethostaddr *haddr, NFSSOCKADDR_T nam) 530 { 531 struct sockaddr_in *inetaddr; 532 533 switch (family) { 534 case AF_INET: 535 inetaddr = NFSSOCKADDR(nam, struct sockaddr_in *); 536 if (inetaddr->sin_family == AF_INET && 537 inetaddr->sin_addr.s_addr == haddr->had_inet.s_addr) 538 return (1); 539 break; 540 #ifdef INET6 541 case AF_INET6: 542 { 543 struct sockaddr_in6 *inetaddr6; 544 545 inetaddr6 = NFSSOCKADDR(nam, struct sockaddr_in6 *); 546 /* XXX - should test sin6_scope_id ? */ 547 if (inetaddr6->sin6_family == AF_INET6 && 548 IN6_ARE_ADDR_EQUAL(&inetaddr6->sin6_addr, 549 &haddr->had_inet6)) 550 return (1); 551 } 552 break; 553 #endif 554 } 555 return (0); 556 } 557 558 /* 559 * Similar to the above, but takes to NFSSOCKADDR_T args. 560 */ 561 APPLESTATIC int 562 nfsaddr2_match(NFSSOCKADDR_T nam1, NFSSOCKADDR_T nam2) 563 { 564 struct sockaddr_in *addr1, *addr2; 565 struct sockaddr *inaddr; 566 567 inaddr = NFSSOCKADDR(nam1, struct sockaddr *); 568 switch (inaddr->sa_family) { 569 case AF_INET: 570 addr1 = NFSSOCKADDR(nam1, struct sockaddr_in *); 571 addr2 = NFSSOCKADDR(nam2, struct sockaddr_in *); 572 if (addr2->sin_family == AF_INET && 573 addr1->sin_addr.s_addr == addr2->sin_addr.s_addr) 574 return (1); 575 break; 576 #ifdef INET6 577 case AF_INET6: 578 { 579 struct sockaddr_in6 *inet6addr1, *inet6addr2; 580 581 inet6addr1 = NFSSOCKADDR(nam1, struct sockaddr_in6 *); 582 inet6addr2 = NFSSOCKADDR(nam2, struct sockaddr_in6 *); 583 /* XXX - should test sin6_scope_id ? */ 584 if (inet6addr2->sin6_family == AF_INET6 && 585 IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 586 &inet6addr2->sin6_addr)) 587 return (1); 588 } 589 break; 590 #endif 591 } 592 return (0); 593 } 594 595 596 /* 597 * Trim the stuff already dissected off the mbuf list. 598 */ 599 APPLESTATIC void 600 newnfs_trimleading(nd) 601 struct nfsrv_descript *nd; 602 { 603 mbuf_t m, n; 604 int offs; 605 606 /* 607 * First, free up leading mbufs. 608 */ 609 if (nd->nd_mrep != nd->nd_md) { 610 m = nd->nd_mrep; 611 while (mbuf_next(m) != nd->nd_md) { 612 if (mbuf_next(m) == NULL) 613 panic("nfsm trim leading"); 614 m = mbuf_next(m); 615 } 616 mbuf_setnext(m, NULL); 617 mbuf_freem(nd->nd_mrep); 618 } 619 m = nd->nd_md; 620 621 /* 622 * Now, adjust this mbuf, based on nd_dpos. 623 */ 624 offs = nd->nd_dpos - NFSMTOD(m, caddr_t); 625 if (offs == mbuf_len(m)) { 626 n = m; 627 m = mbuf_next(m); 628 if (m == NULL) 629 panic("nfsm trim leading2"); 630 mbuf_setnext(n, NULL); 631 mbuf_freem(n); 632 } else if (offs > 0) { 633 mbuf_setlen(m, mbuf_len(m) - offs); 634 NFSM_DATAP(m, offs); 635 } else if (offs < 0) 636 panic("nfsm trimleading offs"); 637 nd->nd_mrep = m; 638 nd->nd_md = m; 639 nd->nd_dpos = NFSMTOD(m, caddr_t); 640 } 641 642 /* 643 * Trim trailing data off the mbuf list being built. 644 */ 645 APPLESTATIC void 646 newnfs_trimtrailing(nd, mb, bpos) 647 struct nfsrv_descript *nd; 648 mbuf_t mb; 649 caddr_t bpos; 650 { 651 652 if (mbuf_next(mb)) { 653 mbuf_freem(mbuf_next(mb)); 654 mbuf_setnext(mb, NULL); 655 } 656 mbuf_setlen(mb, bpos - NFSMTOD(mb, caddr_t)); 657 nd->nd_mb = mb; 658 nd->nd_bpos = bpos; 659 } 660 661 /* 662 * Dissect a file handle on the client. 663 */ 664 APPLESTATIC int 665 nfsm_getfh(struct nfsrv_descript *nd, struct nfsfh **nfhpp) 666 { 667 u_int32_t *tl; 668 struct nfsfh *nfhp; 669 int error, len; 670 671 *nfhpp = NULL; 672 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 673 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 674 if ((len = fxdr_unsigned(int, *tl)) <= 0 || 675 len > NFSX_FHMAX) { 676 error = EBADRPC; 677 goto nfsmout; 678 } 679 } else 680 len = NFSX_V2FH; 681 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + len, 682 M_NFSFH, M_WAITOK); 683 error = nfsrv_mtostr(nd, nfhp->nfh_fh, len); 684 if (error) { 685 FREE((caddr_t)nfhp, M_NFSFH); 686 goto nfsmout; 687 } 688 nfhp->nfh_len = len; 689 *nfhpp = nfhp; 690 nfsmout: 691 NFSEXITCODE2(error, nd); 692 return (error); 693 } 694 695 /* 696 * Break down the nfsv4 acl. 697 * If the aclp == NULL or won't fit in an acl, just discard the acl info. 698 */ 699 APPLESTATIC int 700 nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, int *aclerrp, 701 int *aclsizep, __unused NFSPROC_T *p) 702 { 703 u_int32_t *tl; 704 int i, aclsize; 705 int acecnt, error = 0, aceerr = 0, acesize; 706 707 *aclerrp = 0; 708 if (aclp) 709 aclp->acl_cnt = 0; 710 /* 711 * Parse out the ace entries and expect them to conform to 712 * what can be supported by R/W/X bits. 713 */ 714 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 715 aclsize = NFSX_UNSIGNED; 716 acecnt = fxdr_unsigned(int, *tl); 717 if (acecnt > ACL_MAX_ENTRIES) 718 aceerr = NFSERR_ATTRNOTSUPP; 719 if (nfsrv_useacl == 0) 720 aceerr = NFSERR_ATTRNOTSUPP; 721 for (i = 0; i < acecnt; i++) { 722 if (aclp && !aceerr) 723 error = nfsrv_dissectace(nd, &aclp->acl_entry[i], 724 &aceerr, &acesize, p); 725 else 726 error = nfsrv_skipace(nd, &acesize); 727 if (error) 728 goto nfsmout; 729 aclsize += acesize; 730 } 731 if (aclp && !aceerr) 732 aclp->acl_cnt = acecnt; 733 if (aceerr) 734 *aclerrp = aceerr; 735 if (aclsizep) 736 *aclsizep = aclsize; 737 nfsmout: 738 NFSEXITCODE2(error, nd); 739 return (error); 740 } 741 742 /* 743 * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it. 744 */ 745 static int 746 nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep) 747 { 748 u_int32_t *tl; 749 int error, len = 0; 750 751 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 752 len = fxdr_unsigned(int, *(tl + 3)); 753 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 754 nfsmout: 755 *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); 756 NFSEXITCODE2(error, nd); 757 return (error); 758 } 759 760 /* 761 * Get attribute bits from an mbuf list. 762 * Returns EBADRPC for a parsing error, 0 otherwise. 763 * If the clearinvalid flag is set, clear the bits not supported. 764 */ 765 APPLESTATIC int 766 nfsrv_getattrbits(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp, int *cntp, 767 int *retnotsupp) 768 { 769 u_int32_t *tl; 770 int cnt, i, outcnt; 771 int error = 0; 772 773 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 774 cnt = fxdr_unsigned(int, *tl); 775 if (cnt < 0) { 776 error = NFSERR_BADXDR; 777 goto nfsmout; 778 } 779 if (cnt > NFSATTRBIT_MAXWORDS) 780 outcnt = NFSATTRBIT_MAXWORDS; 781 else 782 outcnt = cnt; 783 NFSZERO_ATTRBIT(attrbitp); 784 if (outcnt > 0) { 785 NFSM_DISSECT(tl, u_int32_t *, outcnt * NFSX_UNSIGNED); 786 for (i = 0; i < outcnt; i++) 787 attrbitp->bits[i] = fxdr_unsigned(u_int32_t, *tl++); 788 } 789 for (i = 0; i < (cnt - outcnt); i++) { 790 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 791 if (retnotsupp != NULL && *tl != 0) 792 *retnotsupp = NFSERR_ATTRNOTSUPP; 793 } 794 if (cntp) 795 *cntp = NFSX_UNSIGNED + (cnt * NFSX_UNSIGNED); 796 nfsmout: 797 NFSEXITCODE2(error, nd); 798 return (error); 799 } 800 801 /* 802 * Get the attributes for V4. 803 * If the compare flag is true, test for any attribute changes, 804 * otherwise return the attribute values. 805 * These attributes cover fields in "struct vattr", "struct statfs", 806 * "struct nfsfsinfo", the file handle and the lease duration. 807 * The value of retcmpp is set to 1 if all attributes are the same, 808 * and 0 otherwise. 809 * Returns EBADRPC if it can't be parsed, 0 otherwise. 810 */ 811 APPLESTATIC int 812 nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, 813 struct nfsvattr *nap, struct nfsfh **nfhpp, fhandle_t *fhp, int fhsize, 814 struct nfsv3_pathconf *pc, struct statfs *sbp, struct nfsstatfs *sfp, 815 struct nfsfsinfo *fsp, NFSACL_T *aclp, int compare, int *retcmpp, 816 u_int32_t *leasep, u_int32_t *rderrp, NFSPROC_T *p, struct ucred *cred) 817 { 818 u_int32_t *tl; 819 int i = 0, j, k, l = 0, m, bitpos, attrsum = 0; 820 int error, tfhsize, aceerr, attrsize, cnt, retnotsup; 821 u_char *cp, *cp2, namestr[NFSV4_SMALLSTR + 1]; 822 nfsattrbit_t attrbits, retattrbits, checkattrbits; 823 struct nfsfh *tnfhp; 824 struct nfsreferral *refp; 825 u_quad_t tquad; 826 nfsquad_t tnfsquad; 827 struct timespec temptime; 828 uid_t uid; 829 gid_t gid; 830 u_int32_t freenum = 0, tuint; 831 u_int64_t uquad = 0, thyp, thyp2; 832 #ifdef QUOTA 833 struct dqblk dqb; 834 uid_t savuid; 835 #endif 836 837 CTASSERT(sizeof(ino_t) == sizeof(uint64_t)); 838 if (compare) { 839 retnotsup = 0; 840 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); 841 } else { 842 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 843 } 844 if (error) 845 goto nfsmout; 846 847 if (compare) { 848 *retcmpp = retnotsup; 849 } else { 850 /* 851 * Just set default values to some of the important ones. 852 */ 853 if (nap != NULL) { 854 nap->na_type = VREG; 855 nap->na_mode = 0; 856 nap->na_rdev = (NFSDEV_T)0; 857 nap->na_mtime.tv_sec = 0; 858 nap->na_mtime.tv_nsec = 0; 859 nap->na_gen = 0; 860 nap->na_flags = 0; 861 nap->na_blocksize = NFS_FABLKSIZE; 862 } 863 if (sbp != NULL) { 864 sbp->f_bsize = NFS_FABLKSIZE; 865 sbp->f_blocks = 0; 866 sbp->f_bfree = 0; 867 sbp->f_bavail = 0; 868 sbp->f_files = 0; 869 sbp->f_ffree = 0; 870 } 871 if (fsp != NULL) { 872 fsp->fs_rtmax = 8192; 873 fsp->fs_rtpref = 8192; 874 fsp->fs_maxname = NFS_MAXNAMLEN; 875 fsp->fs_wtmax = 8192; 876 fsp->fs_wtpref = 8192; 877 fsp->fs_wtmult = NFS_FABLKSIZE; 878 fsp->fs_dtpref = 8192; 879 fsp->fs_maxfilesize = 0xffffffffffffffffull; 880 fsp->fs_timedelta.tv_sec = 0; 881 fsp->fs_timedelta.tv_nsec = 1; 882 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK | 883 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME); 884 } 885 if (pc != NULL) { 886 pc->pc_linkmax = LINK_MAX; 887 pc->pc_namemax = NAME_MAX; 888 pc->pc_notrunc = 0; 889 pc->pc_chownrestricted = 0; 890 pc->pc_caseinsensitive = 0; 891 pc->pc_casepreserving = 1; 892 } 893 if (sfp != NULL) { 894 sfp->sf_ffiles = UINT64_MAX; 895 sfp->sf_tfiles = UINT64_MAX; 896 sfp->sf_afiles = UINT64_MAX; 897 sfp->sf_fbytes = UINT64_MAX; 898 sfp->sf_tbytes = UINT64_MAX; 899 sfp->sf_abytes = UINT64_MAX; 900 } 901 } 902 903 /* 904 * Loop around getting the attributes. 905 */ 906 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 907 attrsize = fxdr_unsigned(int, *tl); 908 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 909 if (attrsum > attrsize) { 910 error = NFSERR_BADXDR; 911 goto nfsmout; 912 } 913 if (NFSISSET_ATTRBIT(&attrbits, bitpos)) 914 switch (bitpos) { 915 case NFSATTRBIT_SUPPORTEDATTRS: 916 retnotsup = 0; 917 if (compare || nap == NULL) 918 error = nfsrv_getattrbits(nd, &retattrbits, 919 &cnt, &retnotsup); 920 else 921 error = nfsrv_getattrbits(nd, &nap->na_suppattr, 922 &cnt, &retnotsup); 923 if (error) 924 goto nfsmout; 925 if (compare && !(*retcmpp)) { 926 NFSSETSUPP_ATTRBIT(&checkattrbits); 927 928 /* Some filesystem do not support NFSv4ACL */ 929 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) { 930 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL); 931 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT); 932 } 933 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 934 || retnotsup) 935 *retcmpp = NFSERR_NOTSAME; 936 } 937 attrsum += cnt; 938 break; 939 case NFSATTRBIT_TYPE: 940 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 941 if (compare) { 942 if (!(*retcmpp)) { 943 if (nap->na_type != nfsv34tov_type(*tl)) 944 *retcmpp = NFSERR_NOTSAME; 945 } 946 } else if (nap != NULL) { 947 nap->na_type = nfsv34tov_type(*tl); 948 } 949 attrsum += NFSX_UNSIGNED; 950 break; 951 case NFSATTRBIT_FHEXPIRETYPE: 952 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 953 if (compare && !(*retcmpp)) { 954 if (fxdr_unsigned(int, *tl) != 955 NFSV4FHTYPE_PERSISTENT) 956 *retcmpp = NFSERR_NOTSAME; 957 } 958 attrsum += NFSX_UNSIGNED; 959 break; 960 case NFSATTRBIT_CHANGE: 961 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 962 if (compare) { 963 if (!(*retcmpp)) { 964 if (nap->na_filerev != fxdr_hyper(tl)) 965 *retcmpp = NFSERR_NOTSAME; 966 } 967 } else if (nap != NULL) { 968 nap->na_filerev = fxdr_hyper(tl); 969 } 970 attrsum += NFSX_HYPER; 971 break; 972 case NFSATTRBIT_SIZE: 973 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 974 if (compare) { 975 if (!(*retcmpp)) { 976 if (nap->na_size != fxdr_hyper(tl)) 977 *retcmpp = NFSERR_NOTSAME; 978 } 979 } else if (nap != NULL) { 980 nap->na_size = fxdr_hyper(tl); 981 } 982 attrsum += NFSX_HYPER; 983 break; 984 case NFSATTRBIT_LINKSUPPORT: 985 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 986 if (compare) { 987 if (!(*retcmpp)) { 988 if (fsp->fs_properties & NFSV3_FSFLINK) { 989 if (*tl == newnfs_false) 990 *retcmpp = NFSERR_NOTSAME; 991 } else { 992 if (*tl == newnfs_true) 993 *retcmpp = NFSERR_NOTSAME; 994 } 995 } 996 } else if (fsp != NULL) { 997 if (*tl == newnfs_true) 998 fsp->fs_properties |= NFSV3_FSFLINK; 999 else 1000 fsp->fs_properties &= ~NFSV3_FSFLINK; 1001 } 1002 attrsum += NFSX_UNSIGNED; 1003 break; 1004 case NFSATTRBIT_SYMLINKSUPPORT: 1005 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1006 if (compare) { 1007 if (!(*retcmpp)) { 1008 if (fsp->fs_properties & NFSV3_FSFSYMLINK) { 1009 if (*tl == newnfs_false) 1010 *retcmpp = NFSERR_NOTSAME; 1011 } else { 1012 if (*tl == newnfs_true) 1013 *retcmpp = NFSERR_NOTSAME; 1014 } 1015 } 1016 } else if (fsp != NULL) { 1017 if (*tl == newnfs_true) 1018 fsp->fs_properties |= NFSV3_FSFSYMLINK; 1019 else 1020 fsp->fs_properties &= ~NFSV3_FSFSYMLINK; 1021 } 1022 attrsum += NFSX_UNSIGNED; 1023 break; 1024 case NFSATTRBIT_NAMEDATTR: 1025 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1026 if (compare && !(*retcmpp)) { 1027 if (*tl != newnfs_false) 1028 *retcmpp = NFSERR_NOTSAME; 1029 } 1030 attrsum += NFSX_UNSIGNED; 1031 break; 1032 case NFSATTRBIT_FSID: 1033 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1034 thyp = fxdr_hyper(tl); 1035 tl += 2; 1036 thyp2 = fxdr_hyper(tl); 1037 if (compare) { 1038 if (*retcmpp == 0) { 1039 if (thyp != (u_int64_t) 1040 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] || 1041 thyp2 != (u_int64_t) 1042 vfs_statfs(vnode_mount(vp))->f_fsid.val[1]) 1043 *retcmpp = NFSERR_NOTSAME; 1044 } 1045 } else if (nap != NULL) { 1046 nap->na_filesid[0] = thyp; 1047 nap->na_filesid[1] = thyp2; 1048 } 1049 attrsum += (4 * NFSX_UNSIGNED); 1050 break; 1051 case NFSATTRBIT_UNIQUEHANDLES: 1052 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1053 if (compare && !(*retcmpp)) { 1054 if (*tl != newnfs_true) 1055 *retcmpp = NFSERR_NOTSAME; 1056 } 1057 attrsum += NFSX_UNSIGNED; 1058 break; 1059 case NFSATTRBIT_LEASETIME: 1060 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1061 if (compare) { 1062 if (fxdr_unsigned(int, *tl) != nfsrv_lease && 1063 !(*retcmpp)) 1064 *retcmpp = NFSERR_NOTSAME; 1065 } else if (leasep != NULL) { 1066 *leasep = fxdr_unsigned(u_int32_t, *tl); 1067 } 1068 attrsum += NFSX_UNSIGNED; 1069 break; 1070 case NFSATTRBIT_RDATTRERROR: 1071 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1072 if (compare) { 1073 if (!(*retcmpp)) 1074 *retcmpp = NFSERR_INVAL; 1075 } else if (rderrp != NULL) { 1076 *rderrp = fxdr_unsigned(u_int32_t, *tl); 1077 } 1078 attrsum += NFSX_UNSIGNED; 1079 break; 1080 case NFSATTRBIT_ACL: 1081 if (compare) { 1082 if (!(*retcmpp)) { 1083 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) { 1084 NFSACL_T *naclp; 1085 1086 naclp = acl_alloc(M_WAITOK); 1087 error = nfsrv_dissectacl(nd, naclp, &aceerr, 1088 &cnt, p); 1089 if (error) { 1090 acl_free(naclp); 1091 goto nfsmout; 1092 } 1093 if (aceerr || aclp == NULL || 1094 nfsrv_compareacl(aclp, naclp)) 1095 *retcmpp = NFSERR_NOTSAME; 1096 acl_free(naclp); 1097 } else { 1098 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1099 &cnt, p); 1100 *retcmpp = NFSERR_ATTRNOTSUPP; 1101 } 1102 } 1103 } else { 1104 if (vp != NULL && aclp != NULL) 1105 error = nfsrv_dissectacl(nd, aclp, &aceerr, 1106 &cnt, p); 1107 else 1108 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1109 &cnt, p); 1110 if (error) 1111 goto nfsmout; 1112 } 1113 1114 attrsum += cnt; 1115 break; 1116 case NFSATTRBIT_ACLSUPPORT: 1117 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1118 if (compare && !(*retcmpp)) { 1119 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) { 1120 if (fxdr_unsigned(u_int32_t, *tl) != 1121 NFSV4ACE_SUPTYPES) 1122 *retcmpp = NFSERR_NOTSAME; 1123 } else { 1124 *retcmpp = NFSERR_ATTRNOTSUPP; 1125 } 1126 } 1127 attrsum += NFSX_UNSIGNED; 1128 break; 1129 case NFSATTRBIT_ARCHIVE: 1130 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1131 if (compare && !(*retcmpp)) 1132 *retcmpp = NFSERR_ATTRNOTSUPP; 1133 attrsum += NFSX_UNSIGNED; 1134 break; 1135 case NFSATTRBIT_CANSETTIME: 1136 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1137 if (compare) { 1138 if (!(*retcmpp)) { 1139 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) { 1140 if (*tl == newnfs_false) 1141 *retcmpp = NFSERR_NOTSAME; 1142 } else { 1143 if (*tl == newnfs_true) 1144 *retcmpp = NFSERR_NOTSAME; 1145 } 1146 } 1147 } else if (fsp != NULL) { 1148 if (*tl == newnfs_true) 1149 fsp->fs_properties |= NFSV3_FSFCANSETTIME; 1150 else 1151 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME; 1152 } 1153 attrsum += NFSX_UNSIGNED; 1154 break; 1155 case NFSATTRBIT_CASEINSENSITIVE: 1156 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1157 if (compare) { 1158 if (!(*retcmpp)) { 1159 if (*tl != newnfs_false) 1160 *retcmpp = NFSERR_NOTSAME; 1161 } 1162 } else if (pc != NULL) { 1163 pc->pc_caseinsensitive = 1164 fxdr_unsigned(u_int32_t, *tl); 1165 } 1166 attrsum += NFSX_UNSIGNED; 1167 break; 1168 case NFSATTRBIT_CASEPRESERVING: 1169 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1170 if (compare) { 1171 if (!(*retcmpp)) { 1172 if (*tl != newnfs_true) 1173 *retcmpp = NFSERR_NOTSAME; 1174 } 1175 } else if (pc != NULL) { 1176 pc->pc_casepreserving = 1177 fxdr_unsigned(u_int32_t, *tl); 1178 } 1179 attrsum += NFSX_UNSIGNED; 1180 break; 1181 case NFSATTRBIT_CHOWNRESTRICTED: 1182 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1183 if (compare) { 1184 if (!(*retcmpp)) { 1185 if (*tl != newnfs_true) 1186 *retcmpp = NFSERR_NOTSAME; 1187 } 1188 } else if (pc != NULL) { 1189 pc->pc_chownrestricted = 1190 fxdr_unsigned(u_int32_t, *tl); 1191 } 1192 attrsum += NFSX_UNSIGNED; 1193 break; 1194 case NFSATTRBIT_FILEHANDLE: 1195 error = nfsm_getfh(nd, &tnfhp); 1196 if (error) 1197 goto nfsmout; 1198 tfhsize = tnfhp->nfh_len; 1199 if (compare) { 1200 if (!(*retcmpp) && 1201 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize, 1202 fhp, fhsize)) 1203 *retcmpp = NFSERR_NOTSAME; 1204 FREE((caddr_t)tnfhp, M_NFSFH); 1205 } else if (nfhpp != NULL) { 1206 *nfhpp = tnfhp; 1207 } else { 1208 FREE((caddr_t)tnfhp, M_NFSFH); 1209 } 1210 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize)); 1211 break; 1212 case NFSATTRBIT_FILEID: 1213 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1214 thyp = fxdr_hyper(tl); 1215 if (compare) { 1216 if (!(*retcmpp)) { 1217 if (nap->na_fileid != thyp) 1218 *retcmpp = NFSERR_NOTSAME; 1219 } 1220 } else if (nap != NULL) 1221 nap->na_fileid = thyp; 1222 attrsum += NFSX_HYPER; 1223 break; 1224 case NFSATTRBIT_FILESAVAIL: 1225 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1226 if (compare) { 1227 if (!(*retcmpp) && 1228 sfp->sf_afiles != fxdr_hyper(tl)) 1229 *retcmpp = NFSERR_NOTSAME; 1230 } else if (sfp != NULL) { 1231 sfp->sf_afiles = fxdr_hyper(tl); 1232 } 1233 attrsum += NFSX_HYPER; 1234 break; 1235 case NFSATTRBIT_FILESFREE: 1236 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1237 if (compare) { 1238 if (!(*retcmpp) && 1239 sfp->sf_ffiles != fxdr_hyper(tl)) 1240 *retcmpp = NFSERR_NOTSAME; 1241 } else if (sfp != NULL) { 1242 sfp->sf_ffiles = fxdr_hyper(tl); 1243 } 1244 attrsum += NFSX_HYPER; 1245 break; 1246 case NFSATTRBIT_FILESTOTAL: 1247 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1248 if (compare) { 1249 if (!(*retcmpp) && 1250 sfp->sf_tfiles != fxdr_hyper(tl)) 1251 *retcmpp = NFSERR_NOTSAME; 1252 } else if (sfp != NULL) { 1253 sfp->sf_tfiles = fxdr_hyper(tl); 1254 } 1255 attrsum += NFSX_HYPER; 1256 break; 1257 case NFSATTRBIT_FSLOCATIONS: 1258 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m); 1259 if (error) 1260 goto nfsmout; 1261 attrsum += l; 1262 if (compare && !(*retcmpp)) { 1263 refp = nfsv4root_getreferral(vp, NULL, 0); 1264 if (refp != NULL) { 1265 if (cp == NULL || cp2 == NULL || 1266 strcmp(cp, "/") || 1267 strcmp(cp2, refp->nfr_srvlist)) 1268 *retcmpp = NFSERR_NOTSAME; 1269 } else if (m == 0) { 1270 *retcmpp = NFSERR_NOTSAME; 1271 } 1272 } 1273 if (cp != NULL) 1274 free(cp, M_NFSSTRING); 1275 if (cp2 != NULL) 1276 free(cp2, M_NFSSTRING); 1277 break; 1278 case NFSATTRBIT_HIDDEN: 1279 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1280 if (compare && !(*retcmpp)) 1281 *retcmpp = NFSERR_ATTRNOTSUPP; 1282 attrsum += NFSX_UNSIGNED; 1283 break; 1284 case NFSATTRBIT_HOMOGENEOUS: 1285 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1286 if (compare) { 1287 if (!(*retcmpp)) { 1288 if (fsp->fs_properties & 1289 NFSV3_FSFHOMOGENEOUS) { 1290 if (*tl == newnfs_false) 1291 *retcmpp = NFSERR_NOTSAME; 1292 } else { 1293 if (*tl == newnfs_true) 1294 *retcmpp = NFSERR_NOTSAME; 1295 } 1296 } 1297 } else if (fsp != NULL) { 1298 if (*tl == newnfs_true) 1299 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS; 1300 else 1301 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS; 1302 } 1303 attrsum += NFSX_UNSIGNED; 1304 break; 1305 case NFSATTRBIT_MAXFILESIZE: 1306 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1307 tnfsquad.qval = fxdr_hyper(tl); 1308 if (compare) { 1309 if (!(*retcmpp)) { 1310 tquad = NFSRV_MAXFILESIZE; 1311 if (tquad != tnfsquad.qval) 1312 *retcmpp = NFSERR_NOTSAME; 1313 } 1314 } else if (fsp != NULL) { 1315 fsp->fs_maxfilesize = tnfsquad.qval; 1316 } 1317 attrsum += NFSX_HYPER; 1318 break; 1319 case NFSATTRBIT_MAXLINK: 1320 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1321 if (compare) { 1322 if (!(*retcmpp)) { 1323 if (fxdr_unsigned(int, *tl) != LINK_MAX) 1324 *retcmpp = NFSERR_NOTSAME; 1325 } 1326 } else if (pc != NULL) { 1327 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl); 1328 } 1329 attrsum += NFSX_UNSIGNED; 1330 break; 1331 case NFSATTRBIT_MAXNAME: 1332 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1333 if (compare) { 1334 if (!(*retcmpp)) { 1335 if (fsp->fs_maxname != 1336 fxdr_unsigned(u_int32_t, *tl)) 1337 *retcmpp = NFSERR_NOTSAME; 1338 } 1339 } else { 1340 tuint = fxdr_unsigned(u_int32_t, *tl); 1341 /* 1342 * Some Linux NFSv4 servers report this 1343 * as 0 or 4billion, so I'll set it to 1344 * NFS_MAXNAMLEN. If a server actually creates 1345 * a name longer than NFS_MAXNAMLEN, it will 1346 * get an error back. 1347 */ 1348 if (tuint == 0 || tuint > NFS_MAXNAMLEN) 1349 tuint = NFS_MAXNAMLEN; 1350 if (fsp != NULL) 1351 fsp->fs_maxname = tuint; 1352 if (pc != NULL) 1353 pc->pc_namemax = tuint; 1354 } 1355 attrsum += NFSX_UNSIGNED; 1356 break; 1357 case NFSATTRBIT_MAXREAD: 1358 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1359 if (compare) { 1360 if (!(*retcmpp)) { 1361 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t, 1362 *(tl + 1)) || *tl != 0) 1363 *retcmpp = NFSERR_NOTSAME; 1364 } 1365 } else if (fsp != NULL) { 1366 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl); 1367 fsp->fs_rtpref = fsp->fs_rtmax; 1368 fsp->fs_dtpref = fsp->fs_rtpref; 1369 } 1370 attrsum += NFSX_HYPER; 1371 break; 1372 case NFSATTRBIT_MAXWRITE: 1373 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1374 if (compare) { 1375 if (!(*retcmpp)) { 1376 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t, 1377 *(tl + 1)) || *tl != 0) 1378 *retcmpp = NFSERR_NOTSAME; 1379 } 1380 } else if (fsp != NULL) { 1381 fsp->fs_wtmax = fxdr_unsigned(int, *++tl); 1382 fsp->fs_wtpref = fsp->fs_wtmax; 1383 } 1384 attrsum += NFSX_HYPER; 1385 break; 1386 case NFSATTRBIT_MIMETYPE: 1387 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1388 i = fxdr_unsigned(int, *tl); 1389 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); 1390 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 1391 if (error) 1392 goto nfsmout; 1393 if (compare && !(*retcmpp)) 1394 *retcmpp = NFSERR_ATTRNOTSUPP; 1395 break; 1396 case NFSATTRBIT_MODE: 1397 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1398 if (compare) { 1399 if (!(*retcmpp)) { 1400 if (nap->na_mode != nfstov_mode(*tl)) 1401 *retcmpp = NFSERR_NOTSAME; 1402 } 1403 } else if (nap != NULL) { 1404 nap->na_mode = nfstov_mode(*tl); 1405 } 1406 attrsum += NFSX_UNSIGNED; 1407 break; 1408 case NFSATTRBIT_NOTRUNC: 1409 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1410 if (compare) { 1411 if (!(*retcmpp)) { 1412 if (*tl != newnfs_true) 1413 *retcmpp = NFSERR_NOTSAME; 1414 } 1415 } else if (pc != NULL) { 1416 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl); 1417 } 1418 attrsum += NFSX_UNSIGNED; 1419 break; 1420 case NFSATTRBIT_NUMLINKS: 1421 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1422 tuint = fxdr_unsigned(u_int32_t, *tl); 1423 if (compare) { 1424 if (!(*retcmpp)) { 1425 if ((u_int32_t)nap->na_nlink != tuint) 1426 *retcmpp = NFSERR_NOTSAME; 1427 } 1428 } else if (nap != NULL) { 1429 nap->na_nlink = tuint; 1430 } 1431 attrsum += NFSX_UNSIGNED; 1432 break; 1433 case NFSATTRBIT_OWNER: 1434 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1435 j = fxdr_unsigned(int, *tl); 1436 if (j < 0) { 1437 error = NFSERR_BADXDR; 1438 goto nfsmout; 1439 } 1440 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1441 if (j > NFSV4_SMALLSTR) 1442 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1443 else 1444 cp = namestr; 1445 error = nfsrv_mtostr(nd, cp, j); 1446 if (error) { 1447 if (j > NFSV4_SMALLSTR) 1448 free(cp, M_NFSSTRING); 1449 goto nfsmout; 1450 } 1451 if (compare) { 1452 if (!(*retcmpp)) { 1453 if (nfsv4_strtouid(nd, cp, j, &uid, p) || 1454 nap->na_uid != uid) 1455 *retcmpp = NFSERR_NOTSAME; 1456 } 1457 } else if (nap != NULL) { 1458 if (nfsv4_strtouid(nd, cp, j, &uid, p)) 1459 nap->na_uid = nfsrv_defaultuid; 1460 else 1461 nap->na_uid = uid; 1462 } 1463 if (j > NFSV4_SMALLSTR) 1464 free(cp, M_NFSSTRING); 1465 break; 1466 case NFSATTRBIT_OWNERGROUP: 1467 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1468 j = fxdr_unsigned(int, *tl); 1469 if (j < 0) { 1470 error = NFSERR_BADXDR; 1471 goto nfsmout; 1472 } 1473 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1474 if (j > NFSV4_SMALLSTR) 1475 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1476 else 1477 cp = namestr; 1478 error = nfsrv_mtostr(nd, cp, j); 1479 if (error) { 1480 if (j > NFSV4_SMALLSTR) 1481 free(cp, M_NFSSTRING); 1482 goto nfsmout; 1483 } 1484 if (compare) { 1485 if (!(*retcmpp)) { 1486 if (nfsv4_strtogid(nd, cp, j, &gid, p) || 1487 nap->na_gid != gid) 1488 *retcmpp = NFSERR_NOTSAME; 1489 } 1490 } else if (nap != NULL) { 1491 if (nfsv4_strtogid(nd, cp, j, &gid, p)) 1492 nap->na_gid = nfsrv_defaultgid; 1493 else 1494 nap->na_gid = gid; 1495 } 1496 if (j > NFSV4_SMALLSTR) 1497 free(cp, M_NFSSTRING); 1498 break; 1499 case NFSATTRBIT_QUOTAHARD: 1500 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1501 if (sbp != NULL) { 1502 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1503 freenum = sbp->f_bfree; 1504 else 1505 freenum = sbp->f_bavail; 1506 #ifdef QUOTA 1507 /* 1508 * ufs_quotactl() insists that the uid argument 1509 * equal p_ruid for non-root quota access, so 1510 * we'll just make sure that's the case. 1511 */ 1512 savuid = p->p_cred->p_ruid; 1513 p->p_cred->p_ruid = cred->cr_uid; 1514 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1515 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1516 freenum = min(dqb.dqb_bhardlimit, freenum); 1517 p->p_cred->p_ruid = savuid; 1518 #endif /* QUOTA */ 1519 uquad = (u_int64_t)freenum; 1520 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1521 } 1522 if (compare && !(*retcmpp)) { 1523 if (uquad != fxdr_hyper(tl)) 1524 *retcmpp = NFSERR_NOTSAME; 1525 } 1526 attrsum += NFSX_HYPER; 1527 break; 1528 case NFSATTRBIT_QUOTASOFT: 1529 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1530 if (sbp != NULL) { 1531 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1532 freenum = sbp->f_bfree; 1533 else 1534 freenum = sbp->f_bavail; 1535 #ifdef QUOTA 1536 /* 1537 * ufs_quotactl() insists that the uid argument 1538 * equal p_ruid for non-root quota access, so 1539 * we'll just make sure that's the case. 1540 */ 1541 savuid = p->p_cred->p_ruid; 1542 p->p_cred->p_ruid = cred->cr_uid; 1543 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1544 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1545 freenum = min(dqb.dqb_bsoftlimit, freenum); 1546 p->p_cred->p_ruid = savuid; 1547 #endif /* QUOTA */ 1548 uquad = (u_int64_t)freenum; 1549 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1550 } 1551 if (compare && !(*retcmpp)) { 1552 if (uquad != fxdr_hyper(tl)) 1553 *retcmpp = NFSERR_NOTSAME; 1554 } 1555 attrsum += NFSX_HYPER; 1556 break; 1557 case NFSATTRBIT_QUOTAUSED: 1558 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1559 if (sbp != NULL) { 1560 freenum = 0; 1561 #ifdef QUOTA 1562 /* 1563 * ufs_quotactl() insists that the uid argument 1564 * equal p_ruid for non-root quota access, so 1565 * we'll just make sure that's the case. 1566 */ 1567 savuid = p->p_cred->p_ruid; 1568 p->p_cred->p_ruid = cred->cr_uid; 1569 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1570 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1571 freenum = dqb.dqb_curblocks; 1572 p->p_cred->p_ruid = savuid; 1573 #endif /* QUOTA */ 1574 uquad = (u_int64_t)freenum; 1575 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1576 } 1577 if (compare && !(*retcmpp)) { 1578 if (uquad != fxdr_hyper(tl)) 1579 *retcmpp = NFSERR_NOTSAME; 1580 } 1581 attrsum += NFSX_HYPER; 1582 break; 1583 case NFSATTRBIT_RAWDEV: 1584 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA); 1585 j = fxdr_unsigned(int, *tl++); 1586 k = fxdr_unsigned(int, *tl); 1587 if (compare) { 1588 if (!(*retcmpp)) { 1589 if (nap->na_rdev != NFSMAKEDEV(j, k)) 1590 *retcmpp = NFSERR_NOTSAME; 1591 } 1592 } else if (nap != NULL) { 1593 nap->na_rdev = NFSMAKEDEV(j, k); 1594 } 1595 attrsum += NFSX_V4SPECDATA; 1596 break; 1597 case NFSATTRBIT_SPACEAVAIL: 1598 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1599 if (compare) { 1600 if (!(*retcmpp) && 1601 sfp->sf_abytes != fxdr_hyper(tl)) 1602 *retcmpp = NFSERR_NOTSAME; 1603 } else if (sfp != NULL) { 1604 sfp->sf_abytes = fxdr_hyper(tl); 1605 } 1606 attrsum += NFSX_HYPER; 1607 break; 1608 case NFSATTRBIT_SPACEFREE: 1609 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1610 if (compare) { 1611 if (!(*retcmpp) && 1612 sfp->sf_fbytes != fxdr_hyper(tl)) 1613 *retcmpp = NFSERR_NOTSAME; 1614 } else if (sfp != NULL) { 1615 sfp->sf_fbytes = fxdr_hyper(tl); 1616 } 1617 attrsum += NFSX_HYPER; 1618 break; 1619 case NFSATTRBIT_SPACETOTAL: 1620 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1621 if (compare) { 1622 if (!(*retcmpp) && 1623 sfp->sf_tbytes != fxdr_hyper(tl)) 1624 *retcmpp = NFSERR_NOTSAME; 1625 } else if (sfp != NULL) { 1626 sfp->sf_tbytes = fxdr_hyper(tl); 1627 } 1628 attrsum += NFSX_HYPER; 1629 break; 1630 case NFSATTRBIT_SPACEUSED: 1631 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1632 thyp = fxdr_hyper(tl); 1633 if (compare) { 1634 if (!(*retcmpp)) { 1635 if ((u_int64_t)nap->na_bytes != thyp) 1636 *retcmpp = NFSERR_NOTSAME; 1637 } 1638 } else if (nap != NULL) { 1639 nap->na_bytes = thyp; 1640 } 1641 attrsum += NFSX_HYPER; 1642 break; 1643 case NFSATTRBIT_SYSTEM: 1644 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1645 if (compare && !(*retcmpp)) 1646 *retcmpp = NFSERR_ATTRNOTSUPP; 1647 attrsum += NFSX_UNSIGNED; 1648 break; 1649 case NFSATTRBIT_TIMEACCESS: 1650 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1651 fxdr_nfsv4time(tl, &temptime); 1652 if (compare) { 1653 if (!(*retcmpp)) { 1654 if (!NFS_CMPTIME(temptime, nap->na_atime)) 1655 *retcmpp = NFSERR_NOTSAME; 1656 } 1657 } else if (nap != NULL) { 1658 nap->na_atime = temptime; 1659 } 1660 attrsum += NFSX_V4TIME; 1661 break; 1662 case NFSATTRBIT_TIMEACCESSSET: 1663 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1664 attrsum += NFSX_UNSIGNED; 1665 i = fxdr_unsigned(int, *tl); 1666 if (i == NFSV4SATTRTIME_TOCLIENT) { 1667 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1668 attrsum += NFSX_V4TIME; 1669 } 1670 if (compare && !(*retcmpp)) 1671 *retcmpp = NFSERR_INVAL; 1672 break; 1673 case NFSATTRBIT_TIMEBACKUP: 1674 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1675 if (compare && !(*retcmpp)) 1676 *retcmpp = NFSERR_ATTRNOTSUPP; 1677 attrsum += NFSX_V4TIME; 1678 break; 1679 case NFSATTRBIT_TIMECREATE: 1680 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1681 if (compare && !(*retcmpp)) 1682 *retcmpp = NFSERR_ATTRNOTSUPP; 1683 attrsum += NFSX_V4TIME; 1684 break; 1685 case NFSATTRBIT_TIMEDELTA: 1686 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1687 if (fsp != NULL) { 1688 if (compare) { 1689 if (!(*retcmpp)) { 1690 if ((u_int32_t)fsp->fs_timedelta.tv_sec != 1691 fxdr_unsigned(u_int32_t, *(tl + 1)) || 1692 (u_int32_t)fsp->fs_timedelta.tv_nsec != 1693 (fxdr_unsigned(u_int32_t, *(tl + 2)) % 1694 1000000000) || 1695 *tl != 0) 1696 *retcmpp = NFSERR_NOTSAME; 1697 } 1698 } else { 1699 fxdr_nfsv4time(tl, &fsp->fs_timedelta); 1700 } 1701 } 1702 attrsum += NFSX_V4TIME; 1703 break; 1704 case NFSATTRBIT_TIMEMETADATA: 1705 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1706 fxdr_nfsv4time(tl, &temptime); 1707 if (compare) { 1708 if (!(*retcmpp)) { 1709 if (!NFS_CMPTIME(temptime, nap->na_ctime)) 1710 *retcmpp = NFSERR_NOTSAME; 1711 } 1712 } else if (nap != NULL) { 1713 nap->na_ctime = temptime; 1714 } 1715 attrsum += NFSX_V4TIME; 1716 break; 1717 case NFSATTRBIT_TIMEMODIFY: 1718 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1719 fxdr_nfsv4time(tl, &temptime); 1720 if (compare) { 1721 if (!(*retcmpp)) { 1722 if (!NFS_CMPTIME(temptime, nap->na_mtime)) 1723 *retcmpp = NFSERR_NOTSAME; 1724 } 1725 } else if (nap != NULL) { 1726 nap->na_mtime = temptime; 1727 } 1728 attrsum += NFSX_V4TIME; 1729 break; 1730 case NFSATTRBIT_TIMEMODIFYSET: 1731 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1732 attrsum += NFSX_UNSIGNED; 1733 i = fxdr_unsigned(int, *tl); 1734 if (i == NFSV4SATTRTIME_TOCLIENT) { 1735 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1736 attrsum += NFSX_V4TIME; 1737 } 1738 if (compare && !(*retcmpp)) 1739 *retcmpp = NFSERR_INVAL; 1740 break; 1741 case NFSATTRBIT_MOUNTEDONFILEID: 1742 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1743 thyp = fxdr_hyper(tl); 1744 if (compare) { 1745 if (!(*retcmpp)) { 1746 if (!vp || !nfsrv_atroot(vp, &thyp2)) 1747 thyp2 = nap->na_fileid; 1748 if (thyp2 != thyp) 1749 *retcmpp = NFSERR_NOTSAME; 1750 } 1751 } else if (nap != NULL) 1752 nap->na_mntonfileno = thyp; 1753 attrsum += NFSX_HYPER; 1754 break; 1755 case NFSATTRBIT_SUPPATTREXCLCREAT: 1756 retnotsup = 0; 1757 error = nfsrv_getattrbits(nd, &retattrbits, 1758 &cnt, &retnotsup); 1759 if (error) 1760 goto nfsmout; 1761 if (compare && !(*retcmpp)) { 1762 NFSSETSUPP_ATTRBIT(&checkattrbits); 1763 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits); 1764 NFSCLRBIT_ATTRBIT(&checkattrbits, 1765 NFSATTRBIT_TIMEACCESSSET); 1766 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 1767 || retnotsup) 1768 *retcmpp = NFSERR_NOTSAME; 1769 } 1770 attrsum += cnt; 1771 break; 1772 default: 1773 printf("EEK! nfsv4_loadattr unknown attr=%d\n", 1774 bitpos); 1775 if (compare && !(*retcmpp)) 1776 *retcmpp = NFSERR_ATTRNOTSUPP; 1777 /* 1778 * and get out of the loop, since we can't parse 1779 * the unknown attrbute data. 1780 */ 1781 bitpos = NFSATTRBIT_MAX; 1782 break; 1783 } 1784 } 1785 1786 /* 1787 * some clients pad the attrlist, so we need to skip over the 1788 * padding. 1789 */ 1790 if (attrsum > attrsize) { 1791 error = NFSERR_BADXDR; 1792 } else { 1793 attrsize = NFSM_RNDUP(attrsize); 1794 if (attrsum < attrsize) 1795 error = nfsm_advance(nd, attrsize - attrsum, -1); 1796 } 1797 nfsmout: 1798 NFSEXITCODE2(error, nd); 1799 return (error); 1800 } 1801 1802 /* 1803 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a 1804 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock. 1805 * The first argument is a pointer to an nfsv4lock structure. 1806 * The second argument is 1 iff a blocking lock is wanted. 1807 * If this argument is 0, the call waits until no thread either wants nor 1808 * holds an exclusive lock. 1809 * It returns 1 if the lock was acquired, 0 otherwise. 1810 * If several processes call this function concurrently wanting the exclusive 1811 * lock, one will get the lock and the rest will return without getting the 1812 * lock. (If the caller must have the lock, it simply calls this function in a 1813 * loop until the function returns 1 to indicate the lock was acquired.) 1814 * Any usecnt must be decremented by calling nfsv4_relref() before 1815 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could 1816 * be called in a loop. 1817 * The isleptp argument is set to indicate if the call slept, iff not NULL 1818 * and the mp argument indicates to check for a forced dismount, iff not 1819 * NULL. 1820 */ 1821 APPLESTATIC int 1822 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp, 1823 void *mutex, struct mount *mp) 1824 { 1825 1826 if (isleptp) 1827 *isleptp = 0; 1828 /* 1829 * If a lock is wanted, loop around until the lock is acquired by 1830 * someone and then released. If I want the lock, try to acquire it. 1831 * For a lock to be issued, no lock must be in force and the usecnt 1832 * must be zero. 1833 */ 1834 if (iwantlock) { 1835 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1836 lp->nfslock_usecnt == 0) { 1837 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1838 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1839 return (1); 1840 } 1841 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED; 1842 } 1843 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) { 1844 if (mp != NULL && NFSCL_FORCEDISM(mp)) { 1845 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1846 return (0); 1847 } 1848 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1849 if (isleptp) 1850 *isleptp = 1; 1851 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1852 PZERO - 1, "nfsv4lck", NULL); 1853 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1854 lp->nfslock_usecnt == 0) { 1855 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1856 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1857 return (1); 1858 } 1859 } 1860 return (0); 1861 } 1862 1863 /* 1864 * Release the lock acquired by nfsv4_lock(). 1865 * The second argument is set to 1 to indicate the nfslock_usecnt should be 1866 * incremented, as well. 1867 */ 1868 APPLESTATIC void 1869 nfsv4_unlock(struct nfsv4lock *lp, int incref) 1870 { 1871 1872 lp->nfslock_lock &= ~NFSV4LOCK_LOCK; 1873 if (incref) 1874 lp->nfslock_usecnt++; 1875 nfsv4_wanted(lp); 1876 } 1877 1878 /* 1879 * Release a reference cnt. 1880 */ 1881 APPLESTATIC void 1882 nfsv4_relref(struct nfsv4lock *lp) 1883 { 1884 1885 if (lp->nfslock_usecnt <= 0) 1886 panic("nfsv4root ref cnt"); 1887 lp->nfslock_usecnt--; 1888 if (lp->nfslock_usecnt == 0) 1889 nfsv4_wanted(lp); 1890 } 1891 1892 /* 1893 * Get a reference cnt. 1894 * This function will wait for any exclusive lock to be released, but will 1895 * not wait for threads that want the exclusive lock. If priority needs 1896 * to be given to threads that need the exclusive lock, a call to nfsv4_lock() 1897 * with the 2nd argument == 0 should be done before calling nfsv4_getref(). 1898 * If the mp argument is not NULL, check for NFSCL_FORCEDISM() being set and 1899 * return without getting a refcnt for that case. 1900 */ 1901 APPLESTATIC void 1902 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex, 1903 struct mount *mp) 1904 { 1905 1906 if (isleptp) 1907 *isleptp = 0; 1908 1909 /* 1910 * Wait for a lock held. 1911 */ 1912 while (lp->nfslock_lock & NFSV4LOCK_LOCK) { 1913 if (mp != NULL && NFSCL_FORCEDISM(mp)) 1914 return; 1915 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1916 if (isleptp) 1917 *isleptp = 1; 1918 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1919 PZERO - 1, "nfsv4gr", NULL); 1920 } 1921 if (mp != NULL && NFSCL_FORCEDISM(mp)) 1922 return; 1923 1924 lp->nfslock_usecnt++; 1925 } 1926 1927 /* 1928 * Get a reference as above, but return failure instead of sleeping if 1929 * an exclusive lock is held. 1930 */ 1931 APPLESTATIC int 1932 nfsv4_getref_nonblock(struct nfsv4lock *lp) 1933 { 1934 1935 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0) 1936 return (0); 1937 1938 lp->nfslock_usecnt++; 1939 return (1); 1940 } 1941 1942 /* 1943 * Test for a lock. Return 1 if locked, 0 otherwise. 1944 */ 1945 APPLESTATIC int 1946 nfsv4_testlock(struct nfsv4lock *lp) 1947 { 1948 1949 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 && 1950 lp->nfslock_usecnt == 0) 1951 return (0); 1952 return (1); 1953 } 1954 1955 /* 1956 * Wake up anyone sleeping, waiting for this lock. 1957 */ 1958 static void 1959 nfsv4_wanted(struct nfsv4lock *lp) 1960 { 1961 1962 if (lp->nfslock_lock & NFSV4LOCK_WANTED) { 1963 lp->nfslock_lock &= ~NFSV4LOCK_WANTED; 1964 wakeup((caddr_t)&lp->nfslock_lock); 1965 } 1966 } 1967 1968 /* 1969 * Copy a string from an mbuf list into a character array. 1970 * Return EBADRPC if there is an mbuf error, 1971 * 0 otherwise. 1972 */ 1973 APPLESTATIC int 1974 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) 1975 { 1976 char *cp; 1977 int xfer, len; 1978 mbuf_t mp; 1979 int rem, error = 0; 1980 1981 mp = nd->nd_md; 1982 cp = nd->nd_dpos; 1983 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp; 1984 rem = NFSM_RNDUP(siz) - siz; 1985 while (siz > 0) { 1986 if (len > siz) 1987 xfer = siz; 1988 else 1989 xfer = len; 1990 NFSBCOPY(cp, str, xfer); 1991 str += xfer; 1992 siz -= xfer; 1993 if (siz > 0) { 1994 mp = mbuf_next(mp); 1995 if (mp == NULL) { 1996 error = EBADRPC; 1997 goto out; 1998 } 1999 cp = NFSMTOD(mp, caddr_t); 2000 len = mbuf_len(mp); 2001 } else { 2002 cp += xfer; 2003 len -= xfer; 2004 } 2005 } 2006 *str = '\0'; 2007 nd->nd_dpos = cp; 2008 nd->nd_md = mp; 2009 if (rem > 0) { 2010 if (len < rem) 2011 error = nfsm_advance(nd, rem, len); 2012 else 2013 nd->nd_dpos += rem; 2014 } 2015 2016 out: 2017 NFSEXITCODE2(error, nd); 2018 return (error); 2019 } 2020 2021 /* 2022 * Fill in the attributes as marked by the bitmap (V4). 2023 */ 2024 APPLESTATIC int 2025 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, 2026 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror, 2027 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram, 2028 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno) 2029 { 2030 int bitpos, retnum = 0; 2031 u_int32_t *tl; 2032 int siz, prefixnum, error; 2033 u_char *cp, namestr[NFSV4_SMALLSTR]; 2034 nfsattrbit_t attrbits, retbits; 2035 nfsattrbit_t *retbitp = &retbits; 2036 u_int32_t freenum, *retnump; 2037 u_int64_t uquad; 2038 struct statfs *fs; 2039 struct nfsfsinfo fsinf; 2040 struct timespec temptime; 2041 NFSACL_T *aclp, *naclp = NULL; 2042 #ifdef QUOTA 2043 struct dqblk dqb; 2044 uid_t savuid; 2045 #endif 2046 2047 /* 2048 * First, set the bits that can be filled and get fsinfo. 2049 */ 2050 NFSSET_ATTRBIT(retbitp, attrbitp); 2051 /* 2052 * If both p and cred are NULL, it is a client side setattr call. 2053 * If both p and cred are not NULL, it is a server side reply call. 2054 * If p is not NULL and cred is NULL, it is a client side callback 2055 * reply call. 2056 */ 2057 if (p == NULL && cred == NULL) { 2058 NFSCLRNOTSETABLE_ATTRBIT(retbitp); 2059 aclp = saclp; 2060 } else { 2061 NFSCLRNOTFILLABLE_ATTRBIT(retbitp); 2062 naclp = acl_alloc(M_WAITOK); 2063 aclp = naclp; 2064 } 2065 nfsvno_getfs(&fsinf, isdgram); 2066 #ifndef APPLE 2067 /* 2068 * Get the VFS_STATFS(), since some attributes need them. 2069 */ 2070 fs = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 2071 if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 2072 error = VFS_STATFS(mp, fs); 2073 if (error != 0) { 2074 if (reterr) { 2075 nd->nd_repstat = NFSERR_ACCES; 2076 free(fs, M_STATFS); 2077 return (0); 2078 } 2079 NFSCLRSTATFS_ATTRBIT(retbitp); 2080 } 2081 } 2082 #endif 2083 2084 /* 2085 * And the NFSv4 ACL... 2086 */ 2087 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 2088 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2089 supports_nfsv4acls == 0))) { 2090 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 2091 } 2092 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 2093 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2094 supports_nfsv4acls == 0)) { 2095 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2096 } else if (naclp != NULL) { 2097 if (NFSVOPLOCK(vp, LK_SHARED) == 0) { 2098 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); 2099 if (error == 0) 2100 error = VOP_GETACL(vp, ACL_TYPE_NFS4, 2101 naclp, cred, p); 2102 NFSVOPUNLOCK(vp, 0); 2103 } else 2104 error = NFSERR_PERM; 2105 if (error != 0) { 2106 if (reterr) { 2107 nd->nd_repstat = NFSERR_ACCES; 2108 free(fs, M_STATFS); 2109 return (0); 2110 } 2111 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2112 } 2113 } 2114 } 2115 2116 /* 2117 * Put out the attribute bitmap for the ones being filled in 2118 * and get the field for the number of attributes returned. 2119 */ 2120 prefixnum = nfsrv_putattrbit(nd, retbitp); 2121 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 2122 prefixnum += NFSX_UNSIGNED; 2123 2124 /* 2125 * Now, loop around filling in the attributes for each bit set. 2126 */ 2127 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 2128 if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 2129 switch (bitpos) { 2130 case NFSATTRBIT_SUPPORTEDATTRS: 2131 NFSSETSUPP_ATTRBIT(&attrbits); 2132 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 2133 && supports_nfsv4acls == 0)) { 2134 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 2135 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 2136 } 2137 retnum += nfsrv_putattrbit(nd, &attrbits); 2138 break; 2139 case NFSATTRBIT_TYPE: 2140 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2141 *tl = vtonfsv34_type(vap->va_type); 2142 retnum += NFSX_UNSIGNED; 2143 break; 2144 case NFSATTRBIT_FHEXPIRETYPE: 2145 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2146 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2147 retnum += NFSX_UNSIGNED; 2148 break; 2149 case NFSATTRBIT_CHANGE: 2150 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2151 txdr_hyper(vap->va_filerev, tl); 2152 retnum += NFSX_HYPER; 2153 break; 2154 case NFSATTRBIT_SIZE: 2155 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2156 txdr_hyper(vap->va_size, tl); 2157 retnum += NFSX_HYPER; 2158 break; 2159 case NFSATTRBIT_LINKSUPPORT: 2160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2161 if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2162 *tl = newnfs_true; 2163 else 2164 *tl = newnfs_false; 2165 retnum += NFSX_UNSIGNED; 2166 break; 2167 case NFSATTRBIT_SYMLINKSUPPORT: 2168 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2169 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2170 *tl = newnfs_true; 2171 else 2172 *tl = newnfs_false; 2173 retnum += NFSX_UNSIGNED; 2174 break; 2175 case NFSATTRBIT_NAMEDATTR: 2176 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2177 *tl = newnfs_false; 2178 retnum += NFSX_UNSIGNED; 2179 break; 2180 case NFSATTRBIT_FSID: 2181 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2182 *tl++ = 0; 2183 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]); 2184 *tl++ = 0; 2185 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]); 2186 retnum += NFSX_V4FSID; 2187 break; 2188 case NFSATTRBIT_UNIQUEHANDLES: 2189 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2190 *tl = newnfs_true; 2191 retnum += NFSX_UNSIGNED; 2192 break; 2193 case NFSATTRBIT_LEASETIME: 2194 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2195 *tl = txdr_unsigned(nfsrv_lease); 2196 retnum += NFSX_UNSIGNED; 2197 break; 2198 case NFSATTRBIT_RDATTRERROR: 2199 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2200 *tl = txdr_unsigned(rderror); 2201 retnum += NFSX_UNSIGNED; 2202 break; 2203 /* 2204 * Recommended Attributes. (Only the supported ones.) 2205 */ 2206 case NFSATTRBIT_ACL: 2207 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2208 break; 2209 case NFSATTRBIT_ACLSUPPORT: 2210 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2211 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2212 retnum += NFSX_UNSIGNED; 2213 break; 2214 case NFSATTRBIT_CANSETTIME: 2215 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2216 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2217 *tl = newnfs_true; 2218 else 2219 *tl = newnfs_false; 2220 retnum += NFSX_UNSIGNED; 2221 break; 2222 case NFSATTRBIT_CASEINSENSITIVE: 2223 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2224 *tl = newnfs_false; 2225 retnum += NFSX_UNSIGNED; 2226 break; 2227 case NFSATTRBIT_CASEPRESERVING: 2228 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2229 *tl = newnfs_true; 2230 retnum += NFSX_UNSIGNED; 2231 break; 2232 case NFSATTRBIT_CHOWNRESTRICTED: 2233 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2234 *tl = newnfs_true; 2235 retnum += NFSX_UNSIGNED; 2236 break; 2237 case NFSATTRBIT_FILEHANDLE: 2238 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2239 break; 2240 case NFSATTRBIT_FILEID: 2241 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2242 uquad = vap->va_fileid; 2243 txdr_hyper(uquad, tl); 2244 retnum += NFSX_HYPER; 2245 break; 2246 case NFSATTRBIT_FILESAVAIL: 2247 /* 2248 * Check quota and use min(quota, f_ffree). 2249 */ 2250 freenum = fs->f_ffree; 2251 #ifdef QUOTA 2252 /* 2253 * ufs_quotactl() insists that the uid argument 2254 * equal p_ruid for non-root quota access, so 2255 * we'll just make sure that's the case. 2256 */ 2257 savuid = p->p_cred->p_ruid; 2258 p->p_cred->p_ruid = cred->cr_uid; 2259 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2260 cred->cr_uid, (caddr_t)&dqb)) 2261 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2262 freenum); 2263 p->p_cred->p_ruid = savuid; 2264 #endif /* QUOTA */ 2265 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2266 *tl++ = 0; 2267 *tl = txdr_unsigned(freenum); 2268 retnum += NFSX_HYPER; 2269 break; 2270 case NFSATTRBIT_FILESFREE: 2271 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2272 *tl++ = 0; 2273 *tl = txdr_unsigned(fs->f_ffree); 2274 retnum += NFSX_HYPER; 2275 break; 2276 case NFSATTRBIT_FILESTOTAL: 2277 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2278 *tl++ = 0; 2279 *tl = txdr_unsigned(fs->f_files); 2280 retnum += NFSX_HYPER; 2281 break; 2282 case NFSATTRBIT_FSLOCATIONS: 2283 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2284 *tl++ = 0; 2285 *tl = 0; 2286 retnum += 2 * NFSX_UNSIGNED; 2287 break; 2288 case NFSATTRBIT_HOMOGENEOUS: 2289 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2290 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2291 *tl = newnfs_true; 2292 else 2293 *tl = newnfs_false; 2294 retnum += NFSX_UNSIGNED; 2295 break; 2296 case NFSATTRBIT_MAXFILESIZE: 2297 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2298 uquad = NFSRV_MAXFILESIZE; 2299 txdr_hyper(uquad, tl); 2300 retnum += NFSX_HYPER; 2301 break; 2302 case NFSATTRBIT_MAXLINK: 2303 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2304 *tl = txdr_unsigned(LINK_MAX); 2305 retnum += NFSX_UNSIGNED; 2306 break; 2307 case NFSATTRBIT_MAXNAME: 2308 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2309 *tl = txdr_unsigned(NFS_MAXNAMLEN); 2310 retnum += NFSX_UNSIGNED; 2311 break; 2312 case NFSATTRBIT_MAXREAD: 2313 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2314 *tl++ = 0; 2315 *tl = txdr_unsigned(fsinf.fs_rtmax); 2316 retnum += NFSX_HYPER; 2317 break; 2318 case NFSATTRBIT_MAXWRITE: 2319 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2320 *tl++ = 0; 2321 *tl = txdr_unsigned(fsinf.fs_wtmax); 2322 retnum += NFSX_HYPER; 2323 break; 2324 case NFSATTRBIT_MODE: 2325 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2326 *tl = vtonfsv34_mode(vap->va_mode); 2327 retnum += NFSX_UNSIGNED; 2328 break; 2329 case NFSATTRBIT_NOTRUNC: 2330 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2331 *tl = newnfs_true; 2332 retnum += NFSX_UNSIGNED; 2333 break; 2334 case NFSATTRBIT_NUMLINKS: 2335 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2336 *tl = txdr_unsigned(vap->va_nlink); 2337 retnum += NFSX_UNSIGNED; 2338 break; 2339 case NFSATTRBIT_OWNER: 2340 cp = namestr; 2341 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); 2342 retnum += nfsm_strtom(nd, cp, siz); 2343 if (cp != namestr) 2344 free(cp, M_NFSSTRING); 2345 break; 2346 case NFSATTRBIT_OWNERGROUP: 2347 cp = namestr; 2348 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); 2349 retnum += nfsm_strtom(nd, cp, siz); 2350 if (cp != namestr) 2351 free(cp, M_NFSSTRING); 2352 break; 2353 case NFSATTRBIT_QUOTAHARD: 2354 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2355 freenum = fs->f_bfree; 2356 else 2357 freenum = fs->f_bavail; 2358 #ifdef QUOTA 2359 /* 2360 * ufs_quotactl() insists that the uid argument 2361 * equal p_ruid for non-root quota access, so 2362 * we'll just make sure that's the case. 2363 */ 2364 savuid = p->p_cred->p_ruid; 2365 p->p_cred->p_ruid = cred->cr_uid; 2366 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2367 cred->cr_uid, (caddr_t)&dqb)) 2368 freenum = min(dqb.dqb_bhardlimit, freenum); 2369 p->p_cred->p_ruid = savuid; 2370 #endif /* QUOTA */ 2371 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2372 uquad = (u_int64_t)freenum; 2373 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize); 2374 txdr_hyper(uquad, tl); 2375 retnum += NFSX_HYPER; 2376 break; 2377 case NFSATTRBIT_QUOTASOFT: 2378 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2379 freenum = fs->f_bfree; 2380 else 2381 freenum = fs->f_bavail; 2382 #ifdef QUOTA 2383 /* 2384 * ufs_quotactl() insists that the uid argument 2385 * equal p_ruid for non-root quota access, so 2386 * we'll just make sure that's the case. 2387 */ 2388 savuid = p->p_cred->p_ruid; 2389 p->p_cred->p_ruid = cred->cr_uid; 2390 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2391 cred->cr_uid, (caddr_t)&dqb)) 2392 freenum = min(dqb.dqb_bsoftlimit, freenum); 2393 p->p_cred->p_ruid = savuid; 2394 #endif /* QUOTA */ 2395 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2396 uquad = (u_int64_t)freenum; 2397 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize); 2398 txdr_hyper(uquad, tl); 2399 retnum += NFSX_HYPER; 2400 break; 2401 case NFSATTRBIT_QUOTAUSED: 2402 freenum = 0; 2403 #ifdef QUOTA 2404 /* 2405 * ufs_quotactl() insists that the uid argument 2406 * equal p_ruid for non-root quota access, so 2407 * we'll just make sure that's the case. 2408 */ 2409 savuid = p->p_cred->p_ruid; 2410 p->p_cred->p_ruid = cred->cr_uid; 2411 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2412 cred->cr_uid, (caddr_t)&dqb)) 2413 freenum = dqb.dqb_curblocks; 2414 p->p_cred->p_ruid = savuid; 2415 #endif /* QUOTA */ 2416 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2417 uquad = (u_int64_t)freenum; 2418 NFSQUOTABLKTOBYTE(uquad, fs->f_bsize); 2419 txdr_hyper(uquad, tl); 2420 retnum += NFSX_HYPER; 2421 break; 2422 case NFSATTRBIT_RAWDEV: 2423 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2424 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2425 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2426 retnum += NFSX_V4SPECDATA; 2427 break; 2428 case NFSATTRBIT_SPACEAVAIL: 2429 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2430 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) 2431 uquad = (u_int64_t)fs->f_bfree; 2432 else 2433 uquad = (u_int64_t)fs->f_bavail; 2434 uquad *= fs->f_bsize; 2435 txdr_hyper(uquad, tl); 2436 retnum += NFSX_HYPER; 2437 break; 2438 case NFSATTRBIT_SPACEFREE: 2439 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2440 uquad = (u_int64_t)fs->f_bfree; 2441 uquad *= fs->f_bsize; 2442 txdr_hyper(uquad, tl); 2443 retnum += NFSX_HYPER; 2444 break; 2445 case NFSATTRBIT_SPACETOTAL: 2446 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2447 uquad = (u_int64_t)fs->f_blocks; 2448 uquad *= fs->f_bsize; 2449 txdr_hyper(uquad, tl); 2450 retnum += NFSX_HYPER; 2451 break; 2452 case NFSATTRBIT_SPACEUSED: 2453 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2454 txdr_hyper(vap->va_bytes, tl); 2455 retnum += NFSX_HYPER; 2456 break; 2457 case NFSATTRBIT_TIMEACCESS: 2458 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2459 txdr_nfsv4time(&vap->va_atime, tl); 2460 retnum += NFSX_V4TIME; 2461 break; 2462 case NFSATTRBIT_TIMEACCESSSET: 2463 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2464 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2465 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2466 txdr_nfsv4time(&vap->va_atime, tl); 2467 retnum += NFSX_V4SETTIME; 2468 } else { 2469 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2470 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2471 retnum += NFSX_UNSIGNED; 2472 } 2473 break; 2474 case NFSATTRBIT_TIMEDELTA: 2475 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2476 temptime.tv_sec = 0; 2477 temptime.tv_nsec = 1000000000 / hz; 2478 txdr_nfsv4time(&temptime, tl); 2479 retnum += NFSX_V4TIME; 2480 break; 2481 case NFSATTRBIT_TIMEMETADATA: 2482 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2483 txdr_nfsv4time(&vap->va_ctime, tl); 2484 retnum += NFSX_V4TIME; 2485 break; 2486 case NFSATTRBIT_TIMEMODIFY: 2487 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2488 txdr_nfsv4time(&vap->va_mtime, tl); 2489 retnum += NFSX_V4TIME; 2490 break; 2491 case NFSATTRBIT_TIMEMODIFYSET: 2492 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2493 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2494 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2495 txdr_nfsv4time(&vap->va_mtime, tl); 2496 retnum += NFSX_V4SETTIME; 2497 } else { 2498 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2499 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2500 retnum += NFSX_UNSIGNED; 2501 } 2502 break; 2503 case NFSATTRBIT_MOUNTEDONFILEID: 2504 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2505 if (at_root != 0) 2506 uquad = mounted_on_fileno; 2507 else 2508 uquad = vap->va_fileid; 2509 txdr_hyper(uquad, tl); 2510 retnum += NFSX_HYPER; 2511 break; 2512 case NFSATTRBIT_SUPPATTREXCLCREAT: 2513 NFSSETSUPP_ATTRBIT(&attrbits); 2514 NFSCLRNOTSETABLE_ATTRBIT(&attrbits); 2515 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); 2516 retnum += nfsrv_putattrbit(nd, &attrbits); 2517 break; 2518 default: 2519 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2520 } 2521 } 2522 } 2523 if (naclp != NULL) 2524 acl_free(naclp); 2525 free(fs, M_STATFS); 2526 *retnump = txdr_unsigned(retnum); 2527 return (retnum + prefixnum); 2528 } 2529 2530 /* 2531 * Put the attribute bits onto an mbuf list. 2532 * Return the number of bytes of output generated. 2533 */ 2534 APPLESTATIC int 2535 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 2536 { 2537 u_int32_t *tl; 2538 int cnt, i, bytesize; 2539 2540 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 2541 if (attrbitp->bits[cnt - 1]) 2542 break; 2543 bytesize = (cnt + 1) * NFSX_UNSIGNED; 2544 NFSM_BUILD(tl, u_int32_t *, bytesize); 2545 *tl++ = txdr_unsigned(cnt); 2546 for (i = 0; i < cnt; i++) 2547 *tl++ = txdr_unsigned(attrbitp->bits[i]); 2548 return (bytesize); 2549 } 2550 2551 /* 2552 * Convert a uid to a string. 2553 * If the lookup fails, just output the digits. 2554 * uid - the user id 2555 * cpp - points to a buffer of size NFSV4_SMALLSTR 2556 * (malloc a larger one, as required) 2557 * retlenp - pointer to length to be returned 2558 */ 2559 APPLESTATIC void 2560 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2561 { 2562 int i; 2563 struct nfsusrgrp *usrp; 2564 u_char *cp = *cpp; 2565 uid_t tmp; 2566 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2567 struct nfsrv_lughash *hp; 2568 2569 cnt = 0; 2570 tryagain: 2571 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) { 2572 /* 2573 * Always map nfsrv_defaultuid to "nobody". 2574 */ 2575 if (uid == nfsrv_defaultuid) { 2576 i = nfsrv_dnsnamelen + 7; 2577 if (i > len) { 2578 if (len > NFSV4_SMALLSTR) 2579 free(cp, M_NFSSTRING); 2580 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2581 *cpp = cp; 2582 len = i; 2583 goto tryagain; 2584 } 2585 *retlenp = i; 2586 NFSBCOPY("nobody@", cp, 7); 2587 cp += 7; 2588 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2589 return; 2590 } 2591 hasampersand = 0; 2592 hp = NFSUSERHASH(uid); 2593 mtx_lock(&hp->mtx); 2594 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2595 if (usrp->lug_uid == uid) { 2596 if (usrp->lug_expiry < NFSD_MONOSEC) 2597 break; 2598 /* 2599 * If the name doesn't already have an '@' 2600 * in it, append @domainname to it. 2601 */ 2602 for (i = 0; i < usrp->lug_namelen; i++) { 2603 if (usrp->lug_name[i] == '@') { 2604 hasampersand = 1; 2605 break; 2606 } 2607 } 2608 if (hasampersand) 2609 i = usrp->lug_namelen; 2610 else 2611 i = usrp->lug_namelen + 2612 nfsrv_dnsnamelen + 1; 2613 if (i > len) { 2614 mtx_unlock(&hp->mtx); 2615 if (len > NFSV4_SMALLSTR) 2616 free(cp, M_NFSSTRING); 2617 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2618 *cpp = cp; 2619 len = i; 2620 goto tryagain; 2621 } 2622 *retlenp = i; 2623 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2624 if (!hasampersand) { 2625 cp += usrp->lug_namelen; 2626 *cp++ = '@'; 2627 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2628 } 2629 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2630 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2631 lug_numhash); 2632 mtx_unlock(&hp->mtx); 2633 return; 2634 } 2635 } 2636 mtx_unlock(&hp->mtx); 2637 cnt++; 2638 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2639 NULL, p); 2640 if (ret == 0 && cnt < 2) 2641 goto tryagain; 2642 } 2643 2644 /* 2645 * No match, just return a string of digits. 2646 */ 2647 tmp = uid; 2648 i = 0; 2649 while (tmp || i == 0) { 2650 tmp /= 10; 2651 i++; 2652 } 2653 len = (i > len) ? len : i; 2654 *retlenp = len; 2655 cp += (len - 1); 2656 tmp = uid; 2657 for (i = 0; i < len; i++) { 2658 *cp-- = '0' + (tmp % 10); 2659 tmp /= 10; 2660 } 2661 return; 2662 } 2663 2664 /* 2665 * Get a credential for the uid with the server's group list. 2666 * If none is found, just return the credential passed in after 2667 * logging a warning message. 2668 */ 2669 struct ucred * 2670 nfsrv_getgrpscred(struct ucred *oldcred) 2671 { 2672 struct nfsusrgrp *usrp; 2673 struct ucred *newcred; 2674 int cnt, ret; 2675 uid_t uid; 2676 struct nfsrv_lughash *hp; 2677 2678 cnt = 0; 2679 uid = oldcred->cr_uid; 2680 tryagain: 2681 if (nfsrv_dnsnamelen > 0) { 2682 hp = NFSUSERHASH(uid); 2683 mtx_lock(&hp->mtx); 2684 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2685 if (usrp->lug_uid == uid) { 2686 if (usrp->lug_expiry < NFSD_MONOSEC) 2687 break; 2688 if (usrp->lug_cred != NULL) { 2689 newcred = crhold(usrp->lug_cred); 2690 crfree(oldcred); 2691 } else 2692 newcred = oldcred; 2693 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2694 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2695 lug_numhash); 2696 mtx_unlock(&hp->mtx); 2697 return (newcred); 2698 } 2699 } 2700 mtx_unlock(&hp->mtx); 2701 cnt++; 2702 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2703 NULL, curthread); 2704 if (ret == 0 && cnt < 2) 2705 goto tryagain; 2706 } 2707 return (oldcred); 2708 } 2709 2710 /* 2711 * Convert a string to a uid. 2712 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2713 * return 0. 2714 * If this is called from a client side mount using AUTH_SYS and the 2715 * string is made up entirely of digits, just convert the string to 2716 * a number. 2717 */ 2718 APPLESTATIC int 2719 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp, 2720 NFSPROC_T *p) 2721 { 2722 int i; 2723 char *cp, *endstr, *str0; 2724 struct nfsusrgrp *usrp; 2725 int cnt, ret; 2726 int error = 0; 2727 uid_t tuid; 2728 struct nfsrv_lughash *hp, *hp2; 2729 2730 if (len == 0) { 2731 error = NFSERR_BADOWNER; 2732 goto out; 2733 } 2734 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2735 str0 = str; 2736 tuid = (uid_t)strtoul(str0, &endstr, 10); 2737 if ((endstr - str0) == len) { 2738 /* A numeric string. */ 2739 if ((nd->nd_flag & ND_KERBV) == 0 && 2740 ((nd->nd_flag & ND_NFSCL) != 0 || 2741 nfsd_enable_stringtouid != 0)) 2742 *uidp = tuid; 2743 else 2744 error = NFSERR_BADOWNER; 2745 goto out; 2746 } 2747 /* 2748 * Look for an '@'. 2749 */ 2750 cp = strchr(str0, '@'); 2751 if (cp != NULL) 2752 i = (int)(cp++ - str0); 2753 else 2754 i = len; 2755 2756 cnt = 0; 2757 tryagain: 2758 if (nfsrv_dnsnamelen > 0) { 2759 /* 2760 * If an '@' is found and the domain name matches, search for 2761 * the name with dns stripped off. 2762 * Mixed case alpahbetics will match for the domain name, but 2763 * all upper case will not. 2764 */ 2765 if (cnt == 0 && i < len && i > 0 && 2766 (len - 1 - i) == nfsrv_dnsnamelen && 2767 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2768 len -= (nfsrv_dnsnamelen + 1); 2769 *(cp - 1) = '\0'; 2770 } 2771 2772 /* 2773 * Check for the special case of "nobody". 2774 */ 2775 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 2776 *uidp = nfsrv_defaultuid; 2777 error = 0; 2778 goto out; 2779 } 2780 2781 hp = NFSUSERNAMEHASH(str, len); 2782 mtx_lock(&hp->mtx); 2783 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 2784 if (usrp->lug_namelen == len && 2785 !NFSBCMP(usrp->lug_name, str, len)) { 2786 if (usrp->lug_expiry < NFSD_MONOSEC) 2787 break; 2788 hp2 = NFSUSERHASH(usrp->lug_uid); 2789 mtx_lock(&hp2->mtx); 2790 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 2791 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 2792 lug_numhash); 2793 *uidp = usrp->lug_uid; 2794 mtx_unlock(&hp2->mtx); 2795 mtx_unlock(&hp->mtx); 2796 error = 0; 2797 goto out; 2798 } 2799 } 2800 mtx_unlock(&hp->mtx); 2801 cnt++; 2802 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 2803 str, p); 2804 if (ret == 0 && cnt < 2) 2805 goto tryagain; 2806 } 2807 error = NFSERR_BADOWNER; 2808 2809 out: 2810 NFSEXITCODE(error); 2811 return (error); 2812 } 2813 2814 /* 2815 * Convert a gid to a string. 2816 * gid - the group id 2817 * cpp - points to a buffer of size NFSV4_SMALLSTR 2818 * (malloc a larger one, as required) 2819 * retlenp - pointer to length to be returned 2820 */ 2821 APPLESTATIC void 2822 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2823 { 2824 int i; 2825 struct nfsusrgrp *usrp; 2826 u_char *cp = *cpp; 2827 gid_t tmp; 2828 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2829 struct nfsrv_lughash *hp; 2830 2831 cnt = 0; 2832 tryagain: 2833 if (nfsrv_dnsnamelen > 0 && !nfs_enable_uidtostring) { 2834 /* 2835 * Always map nfsrv_defaultgid to "nogroup". 2836 */ 2837 if (gid == nfsrv_defaultgid) { 2838 i = nfsrv_dnsnamelen + 8; 2839 if (i > len) { 2840 if (len > NFSV4_SMALLSTR) 2841 free(cp, M_NFSSTRING); 2842 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2843 *cpp = cp; 2844 len = i; 2845 goto tryagain; 2846 } 2847 *retlenp = i; 2848 NFSBCOPY("nogroup@", cp, 8); 2849 cp += 8; 2850 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2851 return; 2852 } 2853 hasampersand = 0; 2854 hp = NFSGROUPHASH(gid); 2855 mtx_lock(&hp->mtx); 2856 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2857 if (usrp->lug_gid == gid) { 2858 if (usrp->lug_expiry < NFSD_MONOSEC) 2859 break; 2860 /* 2861 * If the name doesn't already have an '@' 2862 * in it, append @domainname to it. 2863 */ 2864 for (i = 0; i < usrp->lug_namelen; i++) { 2865 if (usrp->lug_name[i] == '@') { 2866 hasampersand = 1; 2867 break; 2868 } 2869 } 2870 if (hasampersand) 2871 i = usrp->lug_namelen; 2872 else 2873 i = usrp->lug_namelen + 2874 nfsrv_dnsnamelen + 1; 2875 if (i > len) { 2876 mtx_unlock(&hp->mtx); 2877 if (len > NFSV4_SMALLSTR) 2878 free(cp, M_NFSSTRING); 2879 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2880 *cpp = cp; 2881 len = i; 2882 goto tryagain; 2883 } 2884 *retlenp = i; 2885 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2886 if (!hasampersand) { 2887 cp += usrp->lug_namelen; 2888 *cp++ = '@'; 2889 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2890 } 2891 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2892 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2893 lug_numhash); 2894 mtx_unlock(&hp->mtx); 2895 return; 2896 } 2897 } 2898 mtx_unlock(&hp->mtx); 2899 cnt++; 2900 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, 2901 NULL, p); 2902 if (ret == 0 && cnt < 2) 2903 goto tryagain; 2904 } 2905 2906 /* 2907 * No match, just return a string of digits. 2908 */ 2909 tmp = gid; 2910 i = 0; 2911 while (tmp || i == 0) { 2912 tmp /= 10; 2913 i++; 2914 } 2915 len = (i > len) ? len : i; 2916 *retlenp = len; 2917 cp += (len - 1); 2918 tmp = gid; 2919 for (i = 0; i < len; i++) { 2920 *cp-- = '0' + (tmp % 10); 2921 tmp /= 10; 2922 } 2923 return; 2924 } 2925 2926 /* 2927 * Convert a string to a gid. 2928 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2929 * return 0. 2930 * If this is called from a client side mount using AUTH_SYS and the 2931 * string is made up entirely of digits, just convert the string to 2932 * a number. 2933 */ 2934 APPLESTATIC int 2935 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp, 2936 NFSPROC_T *p) 2937 { 2938 int i; 2939 char *cp, *endstr, *str0; 2940 struct nfsusrgrp *usrp; 2941 int cnt, ret; 2942 int error = 0; 2943 gid_t tgid; 2944 struct nfsrv_lughash *hp, *hp2; 2945 2946 if (len == 0) { 2947 error = NFSERR_BADOWNER; 2948 goto out; 2949 } 2950 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2951 str0 = str; 2952 tgid = (gid_t)strtoul(str0, &endstr, 10); 2953 if ((endstr - str0) == len) { 2954 /* A numeric string. */ 2955 if ((nd->nd_flag & ND_KERBV) == 0 && 2956 ((nd->nd_flag & ND_NFSCL) != 0 || 2957 nfsd_enable_stringtouid != 0)) 2958 *gidp = tgid; 2959 else 2960 error = NFSERR_BADOWNER; 2961 goto out; 2962 } 2963 /* 2964 * Look for an '@'. 2965 */ 2966 cp = strchr(str0, '@'); 2967 if (cp != NULL) 2968 i = (int)(cp++ - str0); 2969 else 2970 i = len; 2971 2972 cnt = 0; 2973 tryagain: 2974 if (nfsrv_dnsnamelen > 0) { 2975 /* 2976 * If an '@' is found and the dns name matches, search for the 2977 * name with the dns stripped off. 2978 */ 2979 if (cnt == 0 && i < len && i > 0 && 2980 (len - 1 - i) == nfsrv_dnsnamelen && 2981 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2982 len -= (nfsrv_dnsnamelen + 1); 2983 *(cp - 1) = '\0'; 2984 } 2985 2986 /* 2987 * Check for the special case of "nogroup". 2988 */ 2989 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 2990 *gidp = nfsrv_defaultgid; 2991 error = 0; 2992 goto out; 2993 } 2994 2995 hp = NFSGROUPNAMEHASH(str, len); 2996 mtx_lock(&hp->mtx); 2997 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 2998 if (usrp->lug_namelen == len && 2999 !NFSBCMP(usrp->lug_name, str, len)) { 3000 if (usrp->lug_expiry < NFSD_MONOSEC) 3001 break; 3002 hp2 = NFSGROUPHASH(usrp->lug_gid); 3003 mtx_lock(&hp2->mtx); 3004 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 3005 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 3006 lug_numhash); 3007 *gidp = usrp->lug_gid; 3008 mtx_unlock(&hp2->mtx); 3009 mtx_unlock(&hp->mtx); 3010 error = 0; 3011 goto out; 3012 } 3013 } 3014 mtx_unlock(&hp->mtx); 3015 cnt++; 3016 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 3017 str, p); 3018 if (ret == 0 && cnt < 2) 3019 goto tryagain; 3020 } 3021 error = NFSERR_BADOWNER; 3022 3023 out: 3024 NFSEXITCODE(error); 3025 return (error); 3026 } 3027 3028 /* 3029 * Cmp len chars, allowing mixed case in the first argument to match lower 3030 * case in the second, but not if the first argument is all upper case. 3031 * Return 0 for a match, 1 otherwise. 3032 */ 3033 static int 3034 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 3035 { 3036 int i; 3037 u_char tmp; 3038 int fndlower = 0; 3039 3040 for (i = 0; i < len; i++) { 3041 if (*cp >= 'A' && *cp <= 'Z') { 3042 tmp = *cp++ + ('a' - 'A'); 3043 } else { 3044 tmp = *cp++; 3045 if (tmp >= 'a' && tmp <= 'z') 3046 fndlower = 1; 3047 } 3048 if (tmp != *cp2++) 3049 return (1); 3050 } 3051 if (fndlower) 3052 return (0); 3053 else 3054 return (1); 3055 } 3056 3057 /* 3058 * Set the port for the nfsuserd. 3059 */ 3060 APPLESTATIC int 3061 nfsrv_nfsuserdport(struct sockaddr *sad, u_short port, NFSPROC_T *p) 3062 { 3063 struct nfssockreq *rp; 3064 struct sockaddr_in *ad; 3065 int error; 3066 3067 NFSLOCKNAMEID(); 3068 if (nfsrv_nfsuserd) { 3069 NFSUNLOCKNAMEID(); 3070 error = EPERM; 3071 NFSSOCKADDRFREE(sad); 3072 goto out; 3073 } 3074 nfsrv_nfsuserd = 1; 3075 NFSUNLOCKNAMEID(); 3076 /* 3077 * Set up the socket record and connect. 3078 */ 3079 rp = &nfsrv_nfsuserdsock; 3080 rp->nr_client = NULL; 3081 rp->nr_cred = NULL; 3082 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 3083 if (sad != NULL) { 3084 /* Use the AF_LOCAL socket address passed in. */ 3085 rp->nr_sotype = SOCK_STREAM; 3086 rp->nr_soproto = 0; 3087 rp->nr_nam = sad; 3088 } else { 3089 /* Use the port# for a UDP socket (old nfsuserd). */ 3090 rp->nr_sotype = SOCK_DGRAM; 3091 rp->nr_soproto = IPPROTO_UDP; 3092 NFSSOCKADDRALLOC(rp->nr_nam); 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 NFSSOCKADDRFREE(rp->nr_nam); 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 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); 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((caddr_t)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