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