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