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