nfs_commonsubs.c revision 317419
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 317419 2017-04-25 19:35:13Z 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; 67gid_t nfsrv_defaultgid; 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 } 892 893 /* 894 * Loop around getting the attributes. 895 */ 896 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 897 attrsize = fxdr_unsigned(int, *tl); 898 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 899 if (attrsum > attrsize) { 900 error = NFSERR_BADXDR; 901 goto nfsmout; 902 } 903 if (NFSISSET_ATTRBIT(&attrbits, bitpos)) 904 switch (bitpos) { 905 case NFSATTRBIT_SUPPORTEDATTRS: 906 retnotsup = 0; 907 if (compare || nap == NULL) 908 error = nfsrv_getattrbits(nd, &retattrbits, 909 &cnt, &retnotsup); 910 else 911 error = nfsrv_getattrbits(nd, &nap->na_suppattr, 912 &cnt, &retnotsup); 913 if (error) 914 goto nfsmout; 915 if (compare && !(*retcmpp)) { 916 NFSSETSUPP_ATTRBIT(&checkattrbits); 917 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 918 || retnotsup) 919 *retcmpp = NFSERR_NOTSAME; 920 } 921 attrsum += cnt; 922 break; 923 case NFSATTRBIT_TYPE: 924 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 925 if (compare) { 926 if (!(*retcmpp)) { 927 if (nap->na_type != nfsv34tov_type(*tl)) 928 *retcmpp = NFSERR_NOTSAME; 929 } 930 } else if (nap != NULL) { 931 nap->na_type = nfsv34tov_type(*tl); 932 } 933 attrsum += NFSX_UNSIGNED; 934 break; 935 case NFSATTRBIT_FHEXPIRETYPE: 936 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 937 if (compare && !(*retcmpp)) { 938 if (fxdr_unsigned(int, *tl) != 939 NFSV4FHTYPE_PERSISTENT) 940 *retcmpp = NFSERR_NOTSAME; 941 } 942 attrsum += NFSX_UNSIGNED; 943 break; 944 case NFSATTRBIT_CHANGE: 945 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 946 if (compare) { 947 if (!(*retcmpp)) { 948 if (nap->na_filerev != fxdr_hyper(tl)) 949 *retcmpp = NFSERR_NOTSAME; 950 } 951 } else if (nap != NULL) { 952 nap->na_filerev = fxdr_hyper(tl); 953 } 954 attrsum += NFSX_HYPER; 955 break; 956 case NFSATTRBIT_SIZE: 957 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 958 if (compare) { 959 if (!(*retcmpp)) { 960 if (nap->na_size != fxdr_hyper(tl)) 961 *retcmpp = NFSERR_NOTSAME; 962 } 963 } else if (nap != NULL) { 964 nap->na_size = fxdr_hyper(tl); 965 } 966 attrsum += NFSX_HYPER; 967 break; 968 case NFSATTRBIT_LINKSUPPORT: 969 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 970 if (compare) { 971 if (!(*retcmpp)) { 972 if (fsp->fs_properties & NFSV3_FSFLINK) { 973 if (*tl == newnfs_false) 974 *retcmpp = NFSERR_NOTSAME; 975 } else { 976 if (*tl == newnfs_true) 977 *retcmpp = NFSERR_NOTSAME; 978 } 979 } 980 } else if (fsp != NULL) { 981 if (*tl == newnfs_true) 982 fsp->fs_properties |= NFSV3_FSFLINK; 983 else 984 fsp->fs_properties &= ~NFSV3_FSFLINK; 985 } 986 attrsum += NFSX_UNSIGNED; 987 break; 988 case NFSATTRBIT_SYMLINKSUPPORT: 989 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 990 if (compare) { 991 if (!(*retcmpp)) { 992 if (fsp->fs_properties & NFSV3_FSFSYMLINK) { 993 if (*tl == newnfs_false) 994 *retcmpp = NFSERR_NOTSAME; 995 } else { 996 if (*tl == newnfs_true) 997 *retcmpp = NFSERR_NOTSAME; 998 } 999 } 1000 } else if (fsp != NULL) { 1001 if (*tl == newnfs_true) 1002 fsp->fs_properties |= NFSV3_FSFSYMLINK; 1003 else 1004 fsp->fs_properties &= ~NFSV3_FSFSYMLINK; 1005 } 1006 attrsum += NFSX_UNSIGNED; 1007 break; 1008 case NFSATTRBIT_NAMEDATTR: 1009 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1010 if (compare && !(*retcmpp)) { 1011 if (*tl != newnfs_false) 1012 *retcmpp = NFSERR_NOTSAME; 1013 } 1014 attrsum += NFSX_UNSIGNED; 1015 break; 1016 case NFSATTRBIT_FSID: 1017 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1018 thyp = fxdr_hyper(tl); 1019 tl += 2; 1020 thyp2 = fxdr_hyper(tl); 1021 if (compare) { 1022 if (*retcmpp == 0) { 1023 if (thyp != (u_int64_t) 1024 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] || 1025 thyp2 != (u_int64_t) 1026 vfs_statfs(vnode_mount(vp))->f_fsid.val[1]) 1027 *retcmpp = NFSERR_NOTSAME; 1028 } 1029 } else if (nap != NULL) { 1030 nap->na_filesid[0] = thyp; 1031 nap->na_filesid[1] = thyp2; 1032 } 1033 attrsum += (4 * NFSX_UNSIGNED); 1034 break; 1035 case NFSATTRBIT_UNIQUEHANDLES: 1036 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1037 if (compare && !(*retcmpp)) { 1038 if (*tl != newnfs_true) 1039 *retcmpp = NFSERR_NOTSAME; 1040 } 1041 attrsum += NFSX_UNSIGNED; 1042 break; 1043 case NFSATTRBIT_LEASETIME: 1044 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1045 if (compare) { 1046 if (fxdr_unsigned(int, *tl) != nfsrv_lease && 1047 !(*retcmpp)) 1048 *retcmpp = NFSERR_NOTSAME; 1049 } else if (leasep != NULL) { 1050 *leasep = fxdr_unsigned(u_int32_t, *tl); 1051 } 1052 attrsum += NFSX_UNSIGNED; 1053 break; 1054 case NFSATTRBIT_RDATTRERROR: 1055 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1056 if (compare) { 1057 if (!(*retcmpp)) 1058 *retcmpp = NFSERR_INVAL; 1059 } else if (rderrp != NULL) { 1060 *rderrp = fxdr_unsigned(u_int32_t, *tl); 1061 } 1062 attrsum += NFSX_UNSIGNED; 1063 break; 1064 case NFSATTRBIT_ACL: 1065 if (compare) { 1066 if (!(*retcmpp)) { 1067 if (nfsrv_useacl) { 1068 NFSACL_T *naclp; 1069 1070 naclp = acl_alloc(M_WAITOK); 1071 error = nfsrv_dissectacl(nd, naclp, &aceerr, 1072 &cnt, p); 1073 if (error) { 1074 acl_free(naclp); 1075 goto nfsmout; 1076 } 1077 if (aceerr || aclp == NULL || 1078 nfsrv_compareacl(aclp, naclp)) 1079 *retcmpp = NFSERR_NOTSAME; 1080 acl_free(naclp); 1081 } else { 1082 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1083 &cnt, p); 1084 *retcmpp = NFSERR_ATTRNOTSUPP; 1085 } 1086 } 1087 } else { 1088 if (vp != NULL && aclp != NULL) 1089 error = nfsrv_dissectacl(nd, aclp, &aceerr, 1090 &cnt, p); 1091 else 1092 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1093 &cnt, p); 1094 if (error) 1095 goto nfsmout; 1096 } 1097 attrsum += cnt; 1098 break; 1099 case NFSATTRBIT_ACLSUPPORT: 1100 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1101 if (compare && !(*retcmpp)) { 1102 if (nfsrv_useacl) { 1103 if (fxdr_unsigned(u_int32_t, *tl) != 1104 NFSV4ACE_SUPTYPES) 1105 *retcmpp = NFSERR_NOTSAME; 1106 } else { 1107 *retcmpp = NFSERR_ATTRNOTSUPP; 1108 } 1109 } 1110 attrsum += NFSX_UNSIGNED; 1111 break; 1112 case NFSATTRBIT_ARCHIVE: 1113 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1114 if (compare && !(*retcmpp)) 1115 *retcmpp = NFSERR_ATTRNOTSUPP; 1116 attrsum += NFSX_UNSIGNED; 1117 break; 1118 case NFSATTRBIT_CANSETTIME: 1119 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1120 if (compare) { 1121 if (!(*retcmpp)) { 1122 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) { 1123 if (*tl == newnfs_false) 1124 *retcmpp = NFSERR_NOTSAME; 1125 } else { 1126 if (*tl == newnfs_true) 1127 *retcmpp = NFSERR_NOTSAME; 1128 } 1129 } 1130 } else if (fsp != NULL) { 1131 if (*tl == newnfs_true) 1132 fsp->fs_properties |= NFSV3_FSFCANSETTIME; 1133 else 1134 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME; 1135 } 1136 attrsum += NFSX_UNSIGNED; 1137 break; 1138 case NFSATTRBIT_CASEINSENSITIVE: 1139 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1140 if (compare) { 1141 if (!(*retcmpp)) { 1142 if (*tl != newnfs_false) 1143 *retcmpp = NFSERR_NOTSAME; 1144 } 1145 } else if (pc != NULL) { 1146 pc->pc_caseinsensitive = 1147 fxdr_unsigned(u_int32_t, *tl); 1148 } 1149 attrsum += NFSX_UNSIGNED; 1150 break; 1151 case NFSATTRBIT_CASEPRESERVING: 1152 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1153 if (compare) { 1154 if (!(*retcmpp)) { 1155 if (*tl != newnfs_true) 1156 *retcmpp = NFSERR_NOTSAME; 1157 } 1158 } else if (pc != NULL) { 1159 pc->pc_casepreserving = 1160 fxdr_unsigned(u_int32_t, *tl); 1161 } 1162 attrsum += NFSX_UNSIGNED; 1163 break; 1164 case NFSATTRBIT_CHOWNRESTRICTED: 1165 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1166 if (compare) { 1167 if (!(*retcmpp)) { 1168 if (*tl != newnfs_true) 1169 *retcmpp = NFSERR_NOTSAME; 1170 } 1171 } else if (pc != NULL) { 1172 pc->pc_chownrestricted = 1173 fxdr_unsigned(u_int32_t, *tl); 1174 } 1175 attrsum += NFSX_UNSIGNED; 1176 break; 1177 case NFSATTRBIT_FILEHANDLE: 1178 error = nfsm_getfh(nd, &tnfhp); 1179 if (error) 1180 goto nfsmout; 1181 tfhsize = tnfhp->nfh_len; 1182 if (compare) { 1183 if (!(*retcmpp) && 1184 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize, 1185 fhp, fhsize)) 1186 *retcmpp = NFSERR_NOTSAME; 1187 FREE((caddr_t)tnfhp, M_NFSFH); 1188 } else if (nfhpp != NULL) { 1189 *nfhpp = tnfhp; 1190 } else { 1191 FREE((caddr_t)tnfhp, M_NFSFH); 1192 } 1193 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize)); 1194 break; 1195 case NFSATTRBIT_FILEID: 1196 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1197 thyp = fxdr_hyper(tl); 1198 if (compare) { 1199 if (!(*retcmpp)) { 1200 if ((u_int64_t)nap->na_fileid != thyp) 1201 *retcmpp = NFSERR_NOTSAME; 1202 } 1203 } else if (nap != NULL) { 1204 if (*tl++) { 1205 count64fileid++; 1206 if (ratecheck(&last64fileid, &warninterval)) { 1207 printf("NFSv4 fileid > 32bits (%zu occurrences)\n", 1208 count64fileid); 1209 count64fileid = 0; 1210 } 1211 } 1212 nap->na_fileid = thyp; 1213 } 1214 attrsum += NFSX_HYPER; 1215 break; 1216 case NFSATTRBIT_FILESAVAIL: 1217 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1218 if (compare) { 1219 if (!(*retcmpp) && 1220 sfp->sf_afiles != fxdr_hyper(tl)) 1221 *retcmpp = NFSERR_NOTSAME; 1222 } else if (sfp != NULL) { 1223 sfp->sf_afiles = fxdr_hyper(tl); 1224 } 1225 attrsum += NFSX_HYPER; 1226 break; 1227 case NFSATTRBIT_FILESFREE: 1228 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1229 if (compare) { 1230 if (!(*retcmpp) && 1231 sfp->sf_ffiles != fxdr_hyper(tl)) 1232 *retcmpp = NFSERR_NOTSAME; 1233 } else if (sfp != NULL) { 1234 sfp->sf_ffiles = fxdr_hyper(tl); 1235 } 1236 attrsum += NFSX_HYPER; 1237 break; 1238 case NFSATTRBIT_FILESTOTAL: 1239 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1240 if (compare) { 1241 if (!(*retcmpp) && 1242 sfp->sf_tfiles != fxdr_hyper(tl)) 1243 *retcmpp = NFSERR_NOTSAME; 1244 } else if (sfp != NULL) { 1245 sfp->sf_tfiles = fxdr_hyper(tl); 1246 } 1247 attrsum += NFSX_HYPER; 1248 break; 1249 case NFSATTRBIT_FSLOCATIONS: 1250 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m); 1251 if (error) 1252 goto nfsmout; 1253 attrsum += l; 1254 if (compare && !(*retcmpp)) { 1255 refp = nfsv4root_getreferral(vp, NULL, 0); 1256 if (refp != NULL) { 1257 if (cp == NULL || cp2 == NULL || 1258 strcmp(cp, "/") || 1259 strcmp(cp2, refp->nfr_srvlist)) 1260 *retcmpp = NFSERR_NOTSAME; 1261 } else if (m == 0) { 1262 *retcmpp = NFSERR_NOTSAME; 1263 } 1264 } 1265 if (cp != NULL) 1266 free(cp, M_NFSSTRING); 1267 if (cp2 != NULL) 1268 free(cp2, M_NFSSTRING); 1269 break; 1270 case NFSATTRBIT_HIDDEN: 1271 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1272 if (compare && !(*retcmpp)) 1273 *retcmpp = NFSERR_ATTRNOTSUPP; 1274 attrsum += NFSX_UNSIGNED; 1275 break; 1276 case NFSATTRBIT_HOMOGENEOUS: 1277 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1278 if (compare) { 1279 if (!(*retcmpp)) { 1280 if (fsp->fs_properties & 1281 NFSV3_FSFHOMOGENEOUS) { 1282 if (*tl == newnfs_false) 1283 *retcmpp = NFSERR_NOTSAME; 1284 } else { 1285 if (*tl == newnfs_true) 1286 *retcmpp = NFSERR_NOTSAME; 1287 } 1288 } 1289 } else if (fsp != NULL) { 1290 if (*tl == newnfs_true) 1291 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS; 1292 else 1293 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS; 1294 } 1295 attrsum += NFSX_UNSIGNED; 1296 break; 1297 case NFSATTRBIT_MAXFILESIZE: 1298 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1299 tnfsquad.qval = fxdr_hyper(tl); 1300 if (compare) { 1301 if (!(*retcmpp)) { 1302 tquad = NFSRV_MAXFILESIZE; 1303 if (tquad != tnfsquad.qval) 1304 *retcmpp = NFSERR_NOTSAME; 1305 } 1306 } else if (fsp != NULL) { 1307 fsp->fs_maxfilesize = tnfsquad.qval; 1308 } 1309 attrsum += NFSX_HYPER; 1310 break; 1311 case NFSATTRBIT_MAXLINK: 1312 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1313 if (compare) { 1314 if (!(*retcmpp)) { 1315 if (fxdr_unsigned(int, *tl) != LINK_MAX) 1316 *retcmpp = NFSERR_NOTSAME; 1317 } 1318 } else if (pc != NULL) { 1319 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl); 1320 } 1321 attrsum += NFSX_UNSIGNED; 1322 break; 1323 case NFSATTRBIT_MAXNAME: 1324 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1325 if (compare) { 1326 if (!(*retcmpp)) { 1327 if (fsp->fs_maxname != 1328 fxdr_unsigned(u_int32_t, *tl)) 1329 *retcmpp = NFSERR_NOTSAME; 1330 } 1331 } else { 1332 tuint = fxdr_unsigned(u_int32_t, *tl); 1333 /* 1334 * Some Linux NFSv4 servers report this 1335 * as 0 or 4billion, so I'll set it to 1336 * NFS_MAXNAMLEN. If a server actually creates 1337 * a name longer than NFS_MAXNAMLEN, it will 1338 * get an error back. 1339 */ 1340 if (tuint == 0 || tuint > NFS_MAXNAMLEN) 1341 tuint = NFS_MAXNAMLEN; 1342 if (fsp != NULL) 1343 fsp->fs_maxname = tuint; 1344 if (pc != NULL) 1345 pc->pc_namemax = tuint; 1346 } 1347 attrsum += NFSX_UNSIGNED; 1348 break; 1349 case NFSATTRBIT_MAXREAD: 1350 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1351 if (compare) { 1352 if (!(*retcmpp)) { 1353 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t, 1354 *(tl + 1)) || *tl != 0) 1355 *retcmpp = NFSERR_NOTSAME; 1356 } 1357 } else if (fsp != NULL) { 1358 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl); 1359 fsp->fs_rtpref = fsp->fs_rtmax; 1360 fsp->fs_dtpref = fsp->fs_rtpref; 1361 } 1362 attrsum += NFSX_HYPER; 1363 break; 1364 case NFSATTRBIT_MAXWRITE: 1365 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1366 if (compare) { 1367 if (!(*retcmpp)) { 1368 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t, 1369 *(tl + 1)) || *tl != 0) 1370 *retcmpp = NFSERR_NOTSAME; 1371 } 1372 } else if (fsp != NULL) { 1373 fsp->fs_wtmax = fxdr_unsigned(int, *++tl); 1374 fsp->fs_wtpref = fsp->fs_wtmax; 1375 } 1376 attrsum += NFSX_HYPER; 1377 break; 1378 case NFSATTRBIT_MIMETYPE: 1379 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1380 i = fxdr_unsigned(int, *tl); 1381 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); 1382 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 1383 if (error) 1384 goto nfsmout; 1385 if (compare && !(*retcmpp)) 1386 *retcmpp = NFSERR_ATTRNOTSUPP; 1387 break; 1388 case NFSATTRBIT_MODE: 1389 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1390 if (compare) { 1391 if (!(*retcmpp)) { 1392 if (nap->na_mode != nfstov_mode(*tl)) 1393 *retcmpp = NFSERR_NOTSAME; 1394 } 1395 } else if (nap != NULL) { 1396 nap->na_mode = nfstov_mode(*tl); 1397 } 1398 attrsum += NFSX_UNSIGNED; 1399 break; 1400 case NFSATTRBIT_NOTRUNC: 1401 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1402 if (compare) { 1403 if (!(*retcmpp)) { 1404 if (*tl != newnfs_true) 1405 *retcmpp = NFSERR_NOTSAME; 1406 } 1407 } else if (pc != NULL) { 1408 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl); 1409 } 1410 attrsum += NFSX_UNSIGNED; 1411 break; 1412 case NFSATTRBIT_NUMLINKS: 1413 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1414 tuint = fxdr_unsigned(u_int32_t, *tl); 1415 if (compare) { 1416 if (!(*retcmpp)) { 1417 if ((u_int32_t)nap->na_nlink != tuint) 1418 *retcmpp = NFSERR_NOTSAME; 1419 } 1420 } else if (nap != NULL) { 1421 nap->na_nlink = tuint; 1422 } 1423 attrsum += NFSX_UNSIGNED; 1424 break; 1425 case NFSATTRBIT_OWNER: 1426 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1427 j = fxdr_unsigned(int, *tl); 1428 if (j < 0) { 1429 error = NFSERR_BADXDR; 1430 goto nfsmout; 1431 } 1432 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1433 if (j > NFSV4_SMALLSTR) 1434 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1435 else 1436 cp = namestr; 1437 error = nfsrv_mtostr(nd, cp, j); 1438 if (error) { 1439 if (j > NFSV4_SMALLSTR) 1440 free(cp, M_NFSSTRING); 1441 goto nfsmout; 1442 } 1443 if (compare) { 1444 if (!(*retcmpp)) { 1445 if (nfsv4_strtouid(nd, cp, j, &uid, p) || 1446 nap->na_uid != uid) 1447 *retcmpp = NFSERR_NOTSAME; 1448 } 1449 } else if (nap != NULL) { 1450 if (nfsv4_strtouid(nd, cp, j, &uid, p)) 1451 nap->na_uid = nfsrv_defaultuid; 1452 else 1453 nap->na_uid = uid; 1454 } 1455 if (j > NFSV4_SMALLSTR) 1456 free(cp, M_NFSSTRING); 1457 break; 1458 case NFSATTRBIT_OWNERGROUP: 1459 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1460 j = fxdr_unsigned(int, *tl); 1461 if (j < 0) { 1462 error = NFSERR_BADXDR; 1463 goto nfsmout; 1464 } 1465 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1466 if (j > NFSV4_SMALLSTR) 1467 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1468 else 1469 cp = namestr; 1470 error = nfsrv_mtostr(nd, cp, j); 1471 if (error) { 1472 if (j > NFSV4_SMALLSTR) 1473 free(cp, M_NFSSTRING); 1474 goto nfsmout; 1475 } 1476 if (compare) { 1477 if (!(*retcmpp)) { 1478 if (nfsv4_strtogid(nd, cp, j, &gid, p) || 1479 nap->na_gid != gid) 1480 *retcmpp = NFSERR_NOTSAME; 1481 } 1482 } else if (nap != NULL) { 1483 if (nfsv4_strtogid(nd, cp, j, &gid, p)) 1484 nap->na_gid = nfsrv_defaultgid; 1485 else 1486 nap->na_gid = gid; 1487 } 1488 if (j > NFSV4_SMALLSTR) 1489 free(cp, M_NFSSTRING); 1490 break; 1491 case NFSATTRBIT_QUOTAHARD: 1492 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1493 if (sbp != NULL) { 1494 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1495 freenum = sbp->f_bfree; 1496 else 1497 freenum = sbp->f_bavail; 1498#ifdef QUOTA 1499 /* 1500 * ufs_quotactl() insists that the uid argument 1501 * equal p_ruid for non-root quota access, so 1502 * we'll just make sure that's the case. 1503 */ 1504 savuid = p->p_cred->p_ruid; 1505 p->p_cred->p_ruid = cred->cr_uid; 1506 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1507 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1508 freenum = min(dqb.dqb_bhardlimit, freenum); 1509 p->p_cred->p_ruid = savuid; 1510#endif /* QUOTA */ 1511 uquad = (u_int64_t)freenum; 1512 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1513 } 1514 if (compare && !(*retcmpp)) { 1515 if (uquad != fxdr_hyper(tl)) 1516 *retcmpp = NFSERR_NOTSAME; 1517 } 1518 attrsum += NFSX_HYPER; 1519 break; 1520 case NFSATTRBIT_QUOTASOFT: 1521 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1522 if (sbp != NULL) { 1523 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1524 freenum = sbp->f_bfree; 1525 else 1526 freenum = sbp->f_bavail; 1527#ifdef QUOTA 1528 /* 1529 * ufs_quotactl() insists that the uid argument 1530 * equal p_ruid for non-root quota access, so 1531 * we'll just make sure that's the case. 1532 */ 1533 savuid = p->p_cred->p_ruid; 1534 p->p_cred->p_ruid = cred->cr_uid; 1535 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1536 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1537 freenum = min(dqb.dqb_bsoftlimit, freenum); 1538 p->p_cred->p_ruid = savuid; 1539#endif /* QUOTA */ 1540 uquad = (u_int64_t)freenum; 1541 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1542 } 1543 if (compare && !(*retcmpp)) { 1544 if (uquad != fxdr_hyper(tl)) 1545 *retcmpp = NFSERR_NOTSAME; 1546 } 1547 attrsum += NFSX_HYPER; 1548 break; 1549 case NFSATTRBIT_QUOTAUSED: 1550 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1551 if (sbp != NULL) { 1552 freenum = 0; 1553#ifdef QUOTA 1554 /* 1555 * ufs_quotactl() insists that the uid argument 1556 * equal p_ruid for non-root quota access, so 1557 * we'll just make sure that's the case. 1558 */ 1559 savuid = p->p_cred->p_ruid; 1560 p->p_cred->p_ruid = cred->cr_uid; 1561 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1562 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1563 freenum = dqb.dqb_curblocks; 1564 p->p_cred->p_ruid = savuid; 1565#endif /* QUOTA */ 1566 uquad = (u_int64_t)freenum; 1567 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1568 } 1569 if (compare && !(*retcmpp)) { 1570 if (uquad != fxdr_hyper(tl)) 1571 *retcmpp = NFSERR_NOTSAME; 1572 } 1573 attrsum += NFSX_HYPER; 1574 break; 1575 case NFSATTRBIT_RAWDEV: 1576 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA); 1577 j = fxdr_unsigned(int, *tl++); 1578 k = fxdr_unsigned(int, *tl); 1579 if (compare) { 1580 if (!(*retcmpp)) { 1581 if (nap->na_rdev != NFSMAKEDEV(j, k)) 1582 *retcmpp = NFSERR_NOTSAME; 1583 } 1584 } else if (nap != NULL) { 1585 nap->na_rdev = NFSMAKEDEV(j, k); 1586 } 1587 attrsum += NFSX_V4SPECDATA; 1588 break; 1589 case NFSATTRBIT_SPACEAVAIL: 1590 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1591 if (compare) { 1592 if (!(*retcmpp) && 1593 sfp->sf_abytes != fxdr_hyper(tl)) 1594 *retcmpp = NFSERR_NOTSAME; 1595 } else if (sfp != NULL) { 1596 sfp->sf_abytes = fxdr_hyper(tl); 1597 } 1598 attrsum += NFSX_HYPER; 1599 break; 1600 case NFSATTRBIT_SPACEFREE: 1601 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1602 if (compare) { 1603 if (!(*retcmpp) && 1604 sfp->sf_fbytes != fxdr_hyper(tl)) 1605 *retcmpp = NFSERR_NOTSAME; 1606 } else if (sfp != NULL) { 1607 sfp->sf_fbytes = fxdr_hyper(tl); 1608 } 1609 attrsum += NFSX_HYPER; 1610 break; 1611 case NFSATTRBIT_SPACETOTAL: 1612 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1613 if (compare) { 1614 if (!(*retcmpp) && 1615 sfp->sf_tbytes != fxdr_hyper(tl)) 1616 *retcmpp = NFSERR_NOTSAME; 1617 } else if (sfp != NULL) { 1618 sfp->sf_tbytes = fxdr_hyper(tl); 1619 } 1620 attrsum += NFSX_HYPER; 1621 break; 1622 case NFSATTRBIT_SPACEUSED: 1623 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1624 thyp = fxdr_hyper(tl); 1625 if (compare) { 1626 if (!(*retcmpp)) { 1627 if ((u_int64_t)nap->na_bytes != thyp) 1628 *retcmpp = NFSERR_NOTSAME; 1629 } 1630 } else if (nap != NULL) { 1631 nap->na_bytes = thyp; 1632 } 1633 attrsum += NFSX_HYPER; 1634 break; 1635 case NFSATTRBIT_SYSTEM: 1636 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1637 if (compare && !(*retcmpp)) 1638 *retcmpp = NFSERR_ATTRNOTSUPP; 1639 attrsum += NFSX_UNSIGNED; 1640 break; 1641 case NFSATTRBIT_TIMEACCESS: 1642 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1643 fxdr_nfsv4time(tl, &temptime); 1644 if (compare) { 1645 if (!(*retcmpp)) { 1646 if (!NFS_CMPTIME(temptime, nap->na_atime)) 1647 *retcmpp = NFSERR_NOTSAME; 1648 } 1649 } else if (nap != NULL) { 1650 nap->na_atime = temptime; 1651 } 1652 attrsum += NFSX_V4TIME; 1653 break; 1654 case NFSATTRBIT_TIMEACCESSSET: 1655 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1656 attrsum += NFSX_UNSIGNED; 1657 i = fxdr_unsigned(int, *tl); 1658 if (i == NFSV4SATTRTIME_TOCLIENT) { 1659 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1660 attrsum += NFSX_V4TIME; 1661 } 1662 if (compare && !(*retcmpp)) 1663 *retcmpp = NFSERR_INVAL; 1664 break; 1665 case NFSATTRBIT_TIMEBACKUP: 1666 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1667 if (compare && !(*retcmpp)) 1668 *retcmpp = NFSERR_ATTRNOTSUPP; 1669 attrsum += NFSX_V4TIME; 1670 break; 1671 case NFSATTRBIT_TIMECREATE: 1672 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1673 if (compare && !(*retcmpp)) 1674 *retcmpp = NFSERR_ATTRNOTSUPP; 1675 attrsum += NFSX_V4TIME; 1676 break; 1677 case NFSATTRBIT_TIMEDELTA: 1678 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1679 if (fsp != NULL) { 1680 if (compare) { 1681 if (!(*retcmpp)) { 1682 if ((u_int32_t)fsp->fs_timedelta.tv_sec != 1683 fxdr_unsigned(u_int32_t, *(tl + 1)) || 1684 (u_int32_t)fsp->fs_timedelta.tv_nsec != 1685 (fxdr_unsigned(u_int32_t, *(tl + 2)) % 1686 1000000000) || 1687 *tl != 0) 1688 *retcmpp = NFSERR_NOTSAME; 1689 } 1690 } else { 1691 fxdr_nfsv4time(tl, &fsp->fs_timedelta); 1692 } 1693 } 1694 attrsum += NFSX_V4TIME; 1695 break; 1696 case NFSATTRBIT_TIMEMETADATA: 1697 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1698 fxdr_nfsv4time(tl, &temptime); 1699 if (compare) { 1700 if (!(*retcmpp)) { 1701 if (!NFS_CMPTIME(temptime, nap->na_ctime)) 1702 *retcmpp = NFSERR_NOTSAME; 1703 } 1704 } else if (nap != NULL) { 1705 nap->na_ctime = temptime; 1706 } 1707 attrsum += NFSX_V4TIME; 1708 break; 1709 case NFSATTRBIT_TIMEMODIFY: 1710 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1711 fxdr_nfsv4time(tl, &temptime); 1712 if (compare) { 1713 if (!(*retcmpp)) { 1714 if (!NFS_CMPTIME(temptime, nap->na_mtime)) 1715 *retcmpp = NFSERR_NOTSAME; 1716 } 1717 } else if (nap != NULL) { 1718 nap->na_mtime = temptime; 1719 } 1720 attrsum += NFSX_V4TIME; 1721 break; 1722 case NFSATTRBIT_TIMEMODIFYSET: 1723 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1724 attrsum += NFSX_UNSIGNED; 1725 i = fxdr_unsigned(int, *tl); 1726 if (i == NFSV4SATTRTIME_TOCLIENT) { 1727 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1728 attrsum += NFSX_V4TIME; 1729 } 1730 if (compare && !(*retcmpp)) 1731 *retcmpp = NFSERR_INVAL; 1732 break; 1733 case NFSATTRBIT_MOUNTEDONFILEID: 1734 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1735 thyp = fxdr_hyper(tl); 1736 if (compare) { 1737 if (!(*retcmpp)) { 1738 if (*tl++) { 1739 *retcmpp = NFSERR_NOTSAME; 1740 } else { 1741 if (!vp || !nfsrv_atroot(vp, &fid)) 1742 fid = nap->na_fileid; 1743 if ((u_int64_t)fid != thyp) 1744 *retcmpp = NFSERR_NOTSAME; 1745 } 1746 } 1747 } else if (nap != NULL) { 1748 if (*tl++) { 1749 count64mountfileid++; 1750 if (ratecheck(&last64mountfileid, &warninterval)) { 1751 printf("NFSv4 mounted on fileid > 32bits (%zu occurrences)\n", 1752 count64mountfileid); 1753 count64mountfileid = 0; 1754 } 1755 } 1756 nap->na_mntonfileno = thyp; 1757 } 1758 attrsum += NFSX_HYPER; 1759 break; 1760 case NFSATTRBIT_SUPPATTREXCLCREAT: 1761 retnotsup = 0; 1762 error = nfsrv_getattrbits(nd, &retattrbits, 1763 &cnt, &retnotsup); 1764 if (error) 1765 goto nfsmout; 1766 if (compare && !(*retcmpp)) { 1767 NFSSETSUPP_ATTRBIT(&checkattrbits); 1768 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits); 1769 NFSCLRBIT_ATTRBIT(&checkattrbits, 1770 NFSATTRBIT_TIMEACCESSSET); 1771 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 1772 || retnotsup) 1773 *retcmpp = NFSERR_NOTSAME; 1774 } 1775 attrsum += cnt; 1776 break; 1777 default: 1778 printf("EEK! nfsv4_loadattr unknown attr=%d\n", 1779 bitpos); 1780 if (compare && !(*retcmpp)) 1781 *retcmpp = NFSERR_ATTRNOTSUPP; 1782 /* 1783 * and get out of the loop, since we can't parse 1784 * the unknown attrbute data. 1785 */ 1786 bitpos = NFSATTRBIT_MAX; 1787 break; 1788 }; 1789 } 1790 1791 /* 1792 * some clients pad the attrlist, so we need to skip over the 1793 * padding. 1794 */ 1795 if (attrsum > attrsize) { 1796 error = NFSERR_BADXDR; 1797 } else { 1798 attrsize = NFSM_RNDUP(attrsize); 1799 if (attrsum < attrsize) 1800 error = nfsm_advance(nd, attrsize - attrsum, -1); 1801 } 1802nfsmout: 1803 NFSEXITCODE2(error, nd); 1804 return (error); 1805} 1806 1807/* 1808 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a 1809 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock. 1810 * The first argument is a pointer to an nfsv4lock structure. 1811 * The second argument is 1 iff a blocking lock is wanted. 1812 * If this argument is 0, the call waits until no thread either wants nor 1813 * holds an exclusive lock. 1814 * It returns 1 if the lock was acquired, 0 otherwise. 1815 * If several processes call this function concurrently wanting the exclusive 1816 * lock, one will get the lock and the rest will return without getting the 1817 * lock. (If the caller must have the lock, it simply calls this function in a 1818 * loop until the function returns 1 to indicate the lock was acquired.) 1819 * Any usecnt must be decremented by calling nfsv4_relref() before 1820 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could 1821 * be called in a loop. 1822 * The isleptp argument is set to indicate if the call slept, iff not NULL 1823 * and the mp argument indicates to check for a forced dismount, iff not 1824 * NULL. 1825 */ 1826APPLESTATIC int 1827nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp, 1828 void *mutex, struct mount *mp) 1829{ 1830 1831 if (isleptp) 1832 *isleptp = 0; 1833 /* 1834 * If a lock is wanted, loop around until the lock is acquired by 1835 * someone and then released. If I want the lock, try to acquire it. 1836 * For a lock to be issued, no lock must be in force and the usecnt 1837 * must be zero. 1838 */ 1839 if (iwantlock) { 1840 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1841 lp->nfslock_usecnt == 0) { 1842 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1843 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1844 return (1); 1845 } 1846 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED; 1847 } 1848 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) { 1849 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1850 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1851 return (0); 1852 } 1853 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1854 if (isleptp) 1855 *isleptp = 1; 1856 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1857 PZERO - 1, "nfsv4lck", NULL); 1858 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1859 lp->nfslock_usecnt == 0) { 1860 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1861 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1862 return (1); 1863 } 1864 } 1865 return (0); 1866} 1867 1868/* 1869 * Release the lock acquired by nfsv4_lock(). 1870 * The second argument is set to 1 to indicate the nfslock_usecnt should be 1871 * incremented, as well. 1872 */ 1873APPLESTATIC void 1874nfsv4_unlock(struct nfsv4lock *lp, int incref) 1875{ 1876 1877 lp->nfslock_lock &= ~NFSV4LOCK_LOCK; 1878 if (incref) 1879 lp->nfslock_usecnt++; 1880 nfsv4_wanted(lp); 1881} 1882 1883/* 1884 * Release a reference cnt. 1885 */ 1886APPLESTATIC void 1887nfsv4_relref(struct nfsv4lock *lp) 1888{ 1889 1890 if (lp->nfslock_usecnt <= 0) 1891 panic("nfsv4root ref cnt"); 1892 lp->nfslock_usecnt--; 1893 if (lp->nfslock_usecnt == 0) 1894 nfsv4_wanted(lp); 1895} 1896 1897/* 1898 * Get a reference cnt. 1899 * This function will wait for any exclusive lock to be released, but will 1900 * not wait for threads that want the exclusive lock. If priority needs 1901 * to be given to threads that need the exclusive lock, a call to nfsv4_lock() 1902 * with the 2nd argument == 0 should be done before calling nfsv4_getref(). 1903 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and 1904 * return without getting a refcnt for that case. 1905 */ 1906APPLESTATIC void 1907nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex, 1908 struct mount *mp) 1909{ 1910 1911 if (isleptp) 1912 *isleptp = 0; 1913 1914 /* 1915 * Wait for a lock held. 1916 */ 1917 while (lp->nfslock_lock & NFSV4LOCK_LOCK) { 1918 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1919 return; 1920 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1921 if (isleptp) 1922 *isleptp = 1; 1923 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1924 PZERO - 1, "nfsv4gr", NULL); 1925 } 1926 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1927 return; 1928 1929 lp->nfslock_usecnt++; 1930} 1931 1932/* 1933 * Get a reference as above, but return failure instead of sleeping if 1934 * an exclusive lock is held. 1935 */ 1936APPLESTATIC int 1937nfsv4_getref_nonblock(struct nfsv4lock *lp) 1938{ 1939 1940 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0) 1941 return (0); 1942 1943 lp->nfslock_usecnt++; 1944 return (1); 1945} 1946 1947/* 1948 * Test for a lock. Return 1 if locked, 0 otherwise. 1949 */ 1950APPLESTATIC int 1951nfsv4_testlock(struct nfsv4lock *lp) 1952{ 1953 1954 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 && 1955 lp->nfslock_usecnt == 0) 1956 return (0); 1957 return (1); 1958} 1959 1960/* 1961 * Wake up anyone sleeping, waiting for this lock. 1962 */ 1963static void 1964nfsv4_wanted(struct nfsv4lock *lp) 1965{ 1966 1967 if (lp->nfslock_lock & NFSV4LOCK_WANTED) { 1968 lp->nfslock_lock &= ~NFSV4LOCK_WANTED; 1969 wakeup((caddr_t)&lp->nfslock_lock); 1970 } 1971} 1972 1973/* 1974 * Copy a string from an mbuf list into a character array. 1975 * Return EBADRPC if there is an mbuf error, 1976 * 0 otherwise. 1977 */ 1978APPLESTATIC int 1979nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) 1980{ 1981 char *cp; 1982 int xfer, len; 1983 mbuf_t mp; 1984 int rem, error = 0; 1985 1986 mp = nd->nd_md; 1987 cp = nd->nd_dpos; 1988 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp; 1989 rem = NFSM_RNDUP(siz) - siz; 1990 while (siz > 0) { 1991 if (len > siz) 1992 xfer = siz; 1993 else 1994 xfer = len; 1995 NFSBCOPY(cp, str, xfer); 1996 str += xfer; 1997 siz -= xfer; 1998 if (siz > 0) { 1999 mp = mbuf_next(mp); 2000 if (mp == NULL) { 2001 error = EBADRPC; 2002 goto out; 2003 } 2004 cp = NFSMTOD(mp, caddr_t); 2005 len = mbuf_len(mp); 2006 } else { 2007 cp += xfer; 2008 len -= xfer; 2009 } 2010 } 2011 *str = '\0'; 2012 nd->nd_dpos = cp; 2013 nd->nd_md = mp; 2014 if (rem > 0) { 2015 if (len < rem) 2016 error = nfsm_advance(nd, rem, len); 2017 else 2018 nd->nd_dpos += rem; 2019 } 2020 2021out: 2022 NFSEXITCODE2(error, nd); 2023 return (error); 2024} 2025 2026/* 2027 * Fill in the attributes as marked by the bitmap (V4). 2028 */ 2029APPLESTATIC int 2030nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, 2031 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror, 2032 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram, 2033 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno) 2034{ 2035 int bitpos, retnum = 0; 2036 u_int32_t *tl; 2037 int siz, prefixnum, error; 2038 u_char *cp, namestr[NFSV4_SMALLSTR]; 2039 nfsattrbit_t attrbits, retbits; 2040 nfsattrbit_t *retbitp = &retbits; 2041 u_int32_t freenum, *retnump; 2042 u_int64_t uquad; 2043 struct statfs fs; 2044 struct nfsfsinfo fsinf; 2045 struct timespec temptime; 2046 NFSACL_T *aclp, *naclp = NULL; 2047#ifdef QUOTA 2048 struct dqblk dqb; 2049 uid_t savuid; 2050#endif 2051 2052 /* 2053 * First, set the bits that can be filled and get fsinfo. 2054 */ 2055 NFSSET_ATTRBIT(retbitp, attrbitp); 2056 /* 2057 * If both p and cred are NULL, it is a client side setattr call. 2058 * If both p and cred are not NULL, it is a server side reply call. 2059 * If p is not NULL and cred is NULL, it is a client side callback 2060 * reply call. 2061 */ 2062 if (p == NULL && cred == NULL) { 2063 NFSCLRNOTSETABLE_ATTRBIT(retbitp); 2064 aclp = saclp; 2065 } else { 2066 NFSCLRNOTFILLABLE_ATTRBIT(retbitp); 2067 naclp = acl_alloc(M_WAITOK); 2068 aclp = naclp; 2069 } 2070 nfsvno_getfs(&fsinf, isdgram); 2071#ifndef APPLE 2072 /* 2073 * Get the VFS_STATFS(), since some attributes need them. 2074 */ 2075 if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 2076 error = VFS_STATFS(mp, &fs); 2077 if (error != 0) { 2078 if (reterr) { 2079 nd->nd_repstat = NFSERR_ACCES; 2080 return (0); 2081 } 2082 NFSCLRSTATFS_ATTRBIT(retbitp); 2083 } 2084 } 2085#endif 2086 2087 /* 2088 * And the NFSv4 ACL... 2089 */ 2090 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 2091 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2092 supports_nfsv4acls == 0))) { 2093 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 2094 } 2095 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 2096 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2097 supports_nfsv4acls == 0)) { 2098 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2099 } else if (naclp != NULL) { 2100 if (NFSVOPLOCK(vp, LK_SHARED) == 0) { 2101 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); 2102 if (error == 0) 2103 error = VOP_GETACL(vp, ACL_TYPE_NFS4, 2104 naclp, cred, p); 2105 NFSVOPUNLOCK(vp, 0); 2106 } else 2107 error = NFSERR_PERM; 2108 if (error != 0) { 2109 if (reterr) { 2110 nd->nd_repstat = NFSERR_ACCES; 2111 return (0); 2112 } 2113 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2114 } 2115 } 2116 } 2117 /* 2118 * Put out the attribute bitmap for the ones being filled in 2119 * and get the field for the number of attributes returned. 2120 */ 2121 prefixnum = nfsrv_putattrbit(nd, retbitp); 2122 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 2123 prefixnum += NFSX_UNSIGNED; 2124 2125 /* 2126 * Now, loop around filling in the attributes for each bit set. 2127 */ 2128 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 2129 if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 2130 switch (bitpos) { 2131 case NFSATTRBIT_SUPPORTEDATTRS: 2132 NFSSETSUPP_ATTRBIT(&attrbits); 2133 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 2134 && supports_nfsv4acls == 0)) { 2135 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 2136 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 2137 } 2138 retnum += nfsrv_putattrbit(nd, &attrbits); 2139 break; 2140 case NFSATTRBIT_TYPE: 2141 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2142 *tl = vtonfsv34_type(vap->va_type); 2143 retnum += NFSX_UNSIGNED; 2144 break; 2145 case NFSATTRBIT_FHEXPIRETYPE: 2146 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2147 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2148 retnum += NFSX_UNSIGNED; 2149 break; 2150 case NFSATTRBIT_CHANGE: 2151 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2152 txdr_hyper(vap->va_filerev, tl); 2153 retnum += NFSX_HYPER; 2154 break; 2155 case NFSATTRBIT_SIZE: 2156 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2157 txdr_hyper(vap->va_size, tl); 2158 retnum += NFSX_HYPER; 2159 break; 2160 case NFSATTRBIT_LINKSUPPORT: 2161 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2162 if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2163 *tl = newnfs_true; 2164 else 2165 *tl = newnfs_false; 2166 retnum += NFSX_UNSIGNED; 2167 break; 2168 case NFSATTRBIT_SYMLINKSUPPORT: 2169 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2170 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2171 *tl = newnfs_true; 2172 else 2173 *tl = newnfs_false; 2174 retnum += NFSX_UNSIGNED; 2175 break; 2176 case NFSATTRBIT_NAMEDATTR: 2177 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2178 *tl = newnfs_false; 2179 retnum += NFSX_UNSIGNED; 2180 break; 2181 case NFSATTRBIT_FSID: 2182 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2183 *tl++ = 0; 2184 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]); 2185 *tl++ = 0; 2186 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]); 2187 retnum += NFSX_V4FSID; 2188 break; 2189 case NFSATTRBIT_UNIQUEHANDLES: 2190 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2191 *tl = newnfs_true; 2192 retnum += NFSX_UNSIGNED; 2193 break; 2194 case NFSATTRBIT_LEASETIME: 2195 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2196 *tl = txdr_unsigned(nfsrv_lease); 2197 retnum += NFSX_UNSIGNED; 2198 break; 2199 case NFSATTRBIT_RDATTRERROR: 2200 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2201 *tl = txdr_unsigned(rderror); 2202 retnum += NFSX_UNSIGNED; 2203 break; 2204 /* 2205 * Recommended Attributes. (Only the supported ones.) 2206 */ 2207 case NFSATTRBIT_ACL: 2208 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2209 break; 2210 case NFSATTRBIT_ACLSUPPORT: 2211 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2212 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2213 retnum += NFSX_UNSIGNED; 2214 break; 2215 case NFSATTRBIT_CANSETTIME: 2216 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2217 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2218 *tl = newnfs_true; 2219 else 2220 *tl = newnfs_false; 2221 retnum += NFSX_UNSIGNED; 2222 break; 2223 case NFSATTRBIT_CASEINSENSITIVE: 2224 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2225 *tl = newnfs_false; 2226 retnum += NFSX_UNSIGNED; 2227 break; 2228 case NFSATTRBIT_CASEPRESERVING: 2229 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2230 *tl = newnfs_true; 2231 retnum += NFSX_UNSIGNED; 2232 break; 2233 case NFSATTRBIT_CHOWNRESTRICTED: 2234 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2235 *tl = newnfs_true; 2236 retnum += NFSX_UNSIGNED; 2237 break; 2238 case NFSATTRBIT_FILEHANDLE: 2239 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2240 break; 2241 case NFSATTRBIT_FILEID: 2242 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2243 *tl++ = 0; 2244 *tl = txdr_unsigned(vap->va_fileid); 2245 retnum += NFSX_HYPER; 2246 break; 2247 case NFSATTRBIT_FILESAVAIL: 2248 /* 2249 * Check quota and use min(quota, f_ffree). 2250 */ 2251 freenum = fs.f_ffree; 2252#ifdef QUOTA 2253 /* 2254 * ufs_quotactl() insists that the uid argument 2255 * equal p_ruid for non-root quota access, so 2256 * we'll just make sure that's the case. 2257 */ 2258 savuid = p->p_cred->p_ruid; 2259 p->p_cred->p_ruid = cred->cr_uid; 2260 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2261 cred->cr_uid, (caddr_t)&dqb)) 2262 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2263 freenum); 2264 p->p_cred->p_ruid = savuid; 2265#endif /* QUOTA */ 2266 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2267 *tl++ = 0; 2268 *tl = txdr_unsigned(freenum); 2269 retnum += NFSX_HYPER; 2270 break; 2271 case NFSATTRBIT_FILESFREE: 2272 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2273 *tl++ = 0; 2274 *tl = txdr_unsigned(fs.f_ffree); 2275 retnum += NFSX_HYPER; 2276 break; 2277 case NFSATTRBIT_FILESTOTAL: 2278 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2279 *tl++ = 0; 2280 *tl = txdr_unsigned(fs.f_files); 2281 retnum += NFSX_HYPER; 2282 break; 2283 case NFSATTRBIT_FSLOCATIONS: 2284 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2285 *tl++ = 0; 2286 *tl = 0; 2287 retnum += 2 * NFSX_UNSIGNED; 2288 break; 2289 case NFSATTRBIT_HOMOGENEOUS: 2290 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2291 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2292 *tl = newnfs_true; 2293 else 2294 *tl = newnfs_false; 2295 retnum += NFSX_UNSIGNED; 2296 break; 2297 case NFSATTRBIT_MAXFILESIZE: 2298 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2299 uquad = NFSRV_MAXFILESIZE; 2300 txdr_hyper(uquad, tl); 2301 retnum += NFSX_HYPER; 2302 break; 2303 case NFSATTRBIT_MAXLINK: 2304 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2305 *tl = txdr_unsigned(LINK_MAX); 2306 retnum += NFSX_UNSIGNED; 2307 break; 2308 case NFSATTRBIT_MAXNAME: 2309 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2310 *tl = txdr_unsigned(NFS_MAXNAMLEN); 2311 retnum += NFSX_UNSIGNED; 2312 break; 2313 case NFSATTRBIT_MAXREAD: 2314 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2315 *tl++ = 0; 2316 *tl = txdr_unsigned(fsinf.fs_rtmax); 2317 retnum += NFSX_HYPER; 2318 break; 2319 case NFSATTRBIT_MAXWRITE: 2320 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2321 *tl++ = 0; 2322 *tl = txdr_unsigned(fsinf.fs_wtmax); 2323 retnum += NFSX_HYPER; 2324 break; 2325 case NFSATTRBIT_MODE: 2326 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2327 *tl = vtonfsv34_mode(vap->va_mode); 2328 retnum += NFSX_UNSIGNED; 2329 break; 2330 case NFSATTRBIT_NOTRUNC: 2331 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2332 *tl = newnfs_true; 2333 retnum += NFSX_UNSIGNED; 2334 break; 2335 case NFSATTRBIT_NUMLINKS: 2336 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2337 *tl = txdr_unsigned(vap->va_nlink); 2338 retnum += NFSX_UNSIGNED; 2339 break; 2340 case NFSATTRBIT_OWNER: 2341 cp = namestr; 2342 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); 2343 retnum += nfsm_strtom(nd, cp, siz); 2344 if (cp != namestr) 2345 free(cp, M_NFSSTRING); 2346 break; 2347 case NFSATTRBIT_OWNERGROUP: 2348 cp = namestr; 2349 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); 2350 retnum += nfsm_strtom(nd, cp, siz); 2351 if (cp != namestr) 2352 free(cp, M_NFSSTRING); 2353 break; 2354 case NFSATTRBIT_QUOTAHARD: 2355 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2356 freenum = fs.f_bfree; 2357 else 2358 freenum = fs.f_bavail; 2359#ifdef QUOTA 2360 /* 2361 * ufs_quotactl() insists that the uid argument 2362 * equal p_ruid for non-root quota access, so 2363 * we'll just make sure that's the case. 2364 */ 2365 savuid = p->p_cred->p_ruid; 2366 p->p_cred->p_ruid = cred->cr_uid; 2367 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2368 cred->cr_uid, (caddr_t)&dqb)) 2369 freenum = min(dqb.dqb_bhardlimit, freenum); 2370 p->p_cred->p_ruid = savuid; 2371#endif /* QUOTA */ 2372 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2373 uquad = (u_int64_t)freenum; 2374 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2375 txdr_hyper(uquad, tl); 2376 retnum += NFSX_HYPER; 2377 break; 2378 case NFSATTRBIT_QUOTASOFT: 2379 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2380 freenum = fs.f_bfree; 2381 else 2382 freenum = fs.f_bavail; 2383#ifdef QUOTA 2384 /* 2385 * ufs_quotactl() insists that the uid argument 2386 * equal p_ruid for non-root quota access, so 2387 * we'll just make sure that's the case. 2388 */ 2389 savuid = p->p_cred->p_ruid; 2390 p->p_cred->p_ruid = cred->cr_uid; 2391 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2392 cred->cr_uid, (caddr_t)&dqb)) 2393 freenum = min(dqb.dqb_bsoftlimit, freenum); 2394 p->p_cred->p_ruid = savuid; 2395#endif /* QUOTA */ 2396 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2397 uquad = (u_int64_t)freenum; 2398 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2399 txdr_hyper(uquad, tl); 2400 retnum += NFSX_HYPER; 2401 break; 2402 case NFSATTRBIT_QUOTAUSED: 2403 freenum = 0; 2404#ifdef QUOTA 2405 /* 2406 * ufs_quotactl() insists that the uid argument 2407 * equal p_ruid for non-root quota access, so 2408 * we'll just make sure that's the case. 2409 */ 2410 savuid = p->p_cred->p_ruid; 2411 p->p_cred->p_ruid = cred->cr_uid; 2412 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2413 cred->cr_uid, (caddr_t)&dqb)) 2414 freenum = dqb.dqb_curblocks; 2415 p->p_cred->p_ruid = savuid; 2416#endif /* QUOTA */ 2417 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2418 uquad = (u_int64_t)freenum; 2419 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2420 txdr_hyper(uquad, tl); 2421 retnum += NFSX_HYPER; 2422 break; 2423 case NFSATTRBIT_RAWDEV: 2424 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2425 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2426 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2427 retnum += NFSX_V4SPECDATA; 2428 break; 2429 case NFSATTRBIT_SPACEAVAIL: 2430 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2431 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) 2432 uquad = (u_int64_t)fs.f_bfree; 2433 else 2434 uquad = (u_int64_t)fs.f_bavail; 2435 uquad *= fs.f_bsize; 2436 txdr_hyper(uquad, tl); 2437 retnum += NFSX_HYPER; 2438 break; 2439 case NFSATTRBIT_SPACEFREE: 2440 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2441 uquad = (u_int64_t)fs.f_bfree; 2442 uquad *= fs.f_bsize; 2443 txdr_hyper(uquad, tl); 2444 retnum += NFSX_HYPER; 2445 break; 2446 case NFSATTRBIT_SPACETOTAL: 2447 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2448 uquad = (u_int64_t)fs.f_blocks; 2449 uquad *= fs.f_bsize; 2450 txdr_hyper(uquad, tl); 2451 retnum += NFSX_HYPER; 2452 break; 2453 case NFSATTRBIT_SPACEUSED: 2454 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2455 txdr_hyper(vap->va_bytes, tl); 2456 retnum += NFSX_HYPER; 2457 break; 2458 case NFSATTRBIT_TIMEACCESS: 2459 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2460 txdr_nfsv4time(&vap->va_atime, tl); 2461 retnum += NFSX_V4TIME; 2462 break; 2463 case NFSATTRBIT_TIMEACCESSSET: 2464 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2465 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2466 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2467 txdr_nfsv4time(&vap->va_atime, tl); 2468 retnum += NFSX_V4SETTIME; 2469 } else { 2470 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2471 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2472 retnum += NFSX_UNSIGNED; 2473 } 2474 break; 2475 case NFSATTRBIT_TIMEDELTA: 2476 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2477 temptime.tv_sec = 0; 2478 temptime.tv_nsec = 1000000000 / hz; 2479 txdr_nfsv4time(&temptime, tl); 2480 retnum += NFSX_V4TIME; 2481 break; 2482 case NFSATTRBIT_TIMEMETADATA: 2483 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2484 txdr_nfsv4time(&vap->va_ctime, tl); 2485 retnum += NFSX_V4TIME; 2486 break; 2487 case NFSATTRBIT_TIMEMODIFY: 2488 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2489 txdr_nfsv4time(&vap->va_mtime, tl); 2490 retnum += NFSX_V4TIME; 2491 break; 2492 case NFSATTRBIT_TIMEMODIFYSET: 2493 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2494 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2495 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2496 txdr_nfsv4time(&vap->va_mtime, tl); 2497 retnum += NFSX_V4SETTIME; 2498 } else { 2499 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2500 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2501 retnum += NFSX_UNSIGNED; 2502 } 2503 break; 2504 case NFSATTRBIT_MOUNTEDONFILEID: 2505 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2506 if (at_root != 0) 2507 uquad = mounted_on_fileno; 2508 else 2509 uquad = (u_int64_t)vap->va_fileid; 2510 txdr_hyper(uquad, tl); 2511 retnum += NFSX_HYPER; 2512 break; 2513 case NFSATTRBIT_SUPPATTREXCLCREAT: 2514 NFSSETSUPP_ATTRBIT(&attrbits); 2515 NFSCLRNOTSETABLE_ATTRBIT(&attrbits); 2516 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); 2517 retnum += nfsrv_putattrbit(nd, &attrbits); 2518 break; 2519 default: 2520 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2521 }; 2522 } 2523 } 2524 if (naclp != NULL) 2525 acl_free(naclp); 2526 *retnump = txdr_unsigned(retnum); 2527 return (retnum + prefixnum); 2528} 2529 2530/* 2531 * Put the attribute bits onto an mbuf list. 2532 * Return the number of bytes of output generated. 2533 */ 2534APPLESTATIC int 2535nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 2536{ 2537 u_int32_t *tl; 2538 int cnt, i, bytesize; 2539 2540 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 2541 if (attrbitp->bits[cnt - 1]) 2542 break; 2543 bytesize = (cnt + 1) * NFSX_UNSIGNED; 2544 NFSM_BUILD(tl, u_int32_t *, bytesize); 2545 *tl++ = txdr_unsigned(cnt); 2546 for (i = 0; i < cnt; i++) 2547 *tl++ = txdr_unsigned(attrbitp->bits[i]); 2548 return (bytesize); 2549} 2550 2551/* 2552 * Convert a uid to a string. 2553 * If the lookup fails, just output the digits. 2554 * uid - the user id 2555 * cpp - points to a buffer of size NFSV4_SMALLSTR 2556 * (malloc a larger one, as required) 2557 * retlenp - pointer to length to be returned 2558 */ 2559APPLESTATIC void 2560nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2561{ 2562 int i; 2563 struct nfsusrgrp *usrp; 2564 u_char *cp = *cpp; 2565 uid_t tmp; 2566 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2567 struct nfsrv_lughash *hp; 2568 2569 cnt = 0; 2570tryagain: 2571 if (nfsrv_dnsnamelen > 0) { 2572 /* 2573 * Always map nfsrv_defaultuid to "nobody". 2574 */ 2575 if (uid == nfsrv_defaultuid) { 2576 i = nfsrv_dnsnamelen + 7; 2577 if (i > len) { 2578 if (len > NFSV4_SMALLSTR) 2579 free(cp, M_NFSSTRING); 2580 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2581 *cpp = cp; 2582 len = i; 2583 goto tryagain; 2584 } 2585 *retlenp = i; 2586 NFSBCOPY("nobody@", cp, 7); 2587 cp += 7; 2588 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2589 return; 2590 } 2591 hasampersand = 0; 2592 hp = NFSUSERHASH(uid); 2593 mtx_lock(&hp->mtx); 2594 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2595 if (usrp->lug_uid == uid) { 2596 if (usrp->lug_expiry < NFSD_MONOSEC) 2597 break; 2598 /* 2599 * If the name doesn't already have an '@' 2600 * in it, append @domainname to it. 2601 */ 2602 for (i = 0; i < usrp->lug_namelen; i++) { 2603 if (usrp->lug_name[i] == '@') { 2604 hasampersand = 1; 2605 break; 2606 } 2607 } 2608 if (hasampersand) 2609 i = usrp->lug_namelen; 2610 else 2611 i = usrp->lug_namelen + 2612 nfsrv_dnsnamelen + 1; 2613 if (i > len) { 2614 mtx_unlock(&hp->mtx); 2615 if (len > NFSV4_SMALLSTR) 2616 free(cp, M_NFSSTRING); 2617 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2618 *cpp = cp; 2619 len = i; 2620 goto tryagain; 2621 } 2622 *retlenp = i; 2623 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2624 if (!hasampersand) { 2625 cp += usrp->lug_namelen; 2626 *cp++ = '@'; 2627 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2628 } 2629 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2630 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2631 lug_numhash); 2632 mtx_unlock(&hp->mtx); 2633 return; 2634 } 2635 } 2636 mtx_unlock(&hp->mtx); 2637 cnt++; 2638 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2639 NULL, p); 2640 if (ret == 0 && cnt < 2) 2641 goto tryagain; 2642 } 2643 2644 /* 2645 * No match, just return a string of digits. 2646 */ 2647 tmp = uid; 2648 i = 0; 2649 while (tmp || i == 0) { 2650 tmp /= 10; 2651 i++; 2652 } 2653 len = (i > len) ? len : i; 2654 *retlenp = len; 2655 cp += (len - 1); 2656 tmp = uid; 2657 for (i = 0; i < len; i++) { 2658 *cp-- = '0' + (tmp % 10); 2659 tmp /= 10; 2660 } 2661 return; 2662} 2663 2664/* 2665 * Get a credential for the uid with the server's group list. 2666 * If none is found, just return the credential passed in after 2667 * logging a warning message. 2668 */ 2669struct ucred * 2670nfsrv_getgrpscred(struct ucred *oldcred) 2671{ 2672 struct nfsusrgrp *usrp; 2673 struct ucred *newcred; 2674 int cnt, ret; 2675 uid_t uid; 2676 struct nfsrv_lughash *hp; 2677 2678 cnt = 0; 2679 uid = oldcred->cr_uid; 2680tryagain: 2681 if (nfsrv_dnsnamelen > 0) { 2682 hp = NFSUSERHASH(uid); 2683 mtx_lock(&hp->mtx); 2684 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2685 if (usrp->lug_uid == uid) { 2686 if (usrp->lug_expiry < NFSD_MONOSEC) 2687 break; 2688 if (usrp->lug_cred != NULL) { 2689 newcred = crhold(usrp->lug_cred); 2690 crfree(oldcred); 2691 } else 2692 newcred = oldcred; 2693 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2694 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2695 lug_numhash); 2696 mtx_unlock(&hp->mtx); 2697 return (newcred); 2698 } 2699 } 2700 mtx_unlock(&hp->mtx); 2701 cnt++; 2702 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2703 NULL, curthread); 2704 if (ret == 0 && cnt < 2) 2705 goto tryagain; 2706 } 2707 return (oldcred); 2708} 2709 2710/* 2711 * Convert a string to a uid. 2712 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2713 * return 0. 2714 * If this is called from a client side mount using AUTH_SYS and the 2715 * string is made up entirely of digits, just convert the string to 2716 * a number. 2717 */ 2718APPLESTATIC int 2719nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp, 2720 NFSPROC_T *p) 2721{ 2722 int i; 2723 char *cp, *endstr, *str0; 2724 struct nfsusrgrp *usrp; 2725 int cnt, ret; 2726 int error = 0; 2727 uid_t tuid; 2728 struct nfsrv_lughash *hp, *hp2; 2729 2730 if (len == 0) { 2731 error = NFSERR_BADOWNER; 2732 goto out; 2733 } 2734 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2735 str0 = str; 2736 tuid = (uid_t)strtoul(str0, &endstr, 10); 2737 if ((endstr - str0) == len) { 2738 /* A numeric string. */ 2739 if ((nd->nd_flag & ND_KERBV) == 0 && 2740 ((nd->nd_flag & ND_NFSCL) != 0 || 2741 nfsd_enable_stringtouid != 0)) 2742 *uidp = tuid; 2743 else 2744 error = NFSERR_BADOWNER; 2745 goto out; 2746 } 2747 /* 2748 * Look for an '@'. 2749 */ 2750 cp = strchr(str0, '@'); 2751 if (cp != NULL) 2752 i = (int)(cp++ - str0); 2753 else 2754 i = len; 2755 2756 cnt = 0; 2757tryagain: 2758 if (nfsrv_dnsnamelen > 0) { 2759 /* 2760 * If an '@' is found and the domain name matches, search for 2761 * the name with dns stripped off. 2762 * Mixed case alpahbetics will match for the domain name, but 2763 * all upper case will not. 2764 */ 2765 if (cnt == 0 && i < len && i > 0 && 2766 (len - 1 - i) == nfsrv_dnsnamelen && 2767 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2768 len -= (nfsrv_dnsnamelen + 1); 2769 *(cp - 1) = '\0'; 2770 } 2771 2772 /* 2773 * Check for the special case of "nobody". 2774 */ 2775 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 2776 *uidp = nfsrv_defaultuid; 2777 error = 0; 2778 goto out; 2779 } 2780 2781 hp = NFSUSERNAMEHASH(str, len); 2782 mtx_lock(&hp->mtx); 2783 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 2784 if (usrp->lug_namelen == len && 2785 !NFSBCMP(usrp->lug_name, str, len)) { 2786 if (usrp->lug_expiry < NFSD_MONOSEC) 2787 break; 2788 hp2 = NFSUSERHASH(usrp->lug_uid); 2789 mtx_lock(&hp2->mtx); 2790 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 2791 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 2792 lug_numhash); 2793 *uidp = usrp->lug_uid; 2794 mtx_unlock(&hp2->mtx); 2795 mtx_unlock(&hp->mtx); 2796 error = 0; 2797 goto out; 2798 } 2799 } 2800 mtx_unlock(&hp->mtx); 2801 cnt++; 2802 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 2803 str, p); 2804 if (ret == 0 && cnt < 2) 2805 goto tryagain; 2806 } 2807 error = NFSERR_BADOWNER; 2808 2809out: 2810 NFSEXITCODE(error); 2811 return (error); 2812} 2813 2814/* 2815 * Convert a gid to a string. 2816 * gid - the group id 2817 * cpp - points to a buffer of size NFSV4_SMALLSTR 2818 * (malloc a larger one, as required) 2819 * retlenp - pointer to length to be returned 2820 */ 2821APPLESTATIC void 2822nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2823{ 2824 int i; 2825 struct nfsusrgrp *usrp; 2826 u_char *cp = *cpp; 2827 gid_t tmp; 2828 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2829 struct nfsrv_lughash *hp; 2830 2831 cnt = 0; 2832tryagain: 2833 if (nfsrv_dnsnamelen > 0) { 2834 /* 2835 * Always map nfsrv_defaultgid to "nogroup". 2836 */ 2837 if (gid == nfsrv_defaultgid) { 2838 i = nfsrv_dnsnamelen + 8; 2839 if (i > len) { 2840 if (len > NFSV4_SMALLSTR) 2841 free(cp, M_NFSSTRING); 2842 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2843 *cpp = cp; 2844 len = i; 2845 goto tryagain; 2846 } 2847 *retlenp = i; 2848 NFSBCOPY("nogroup@", cp, 8); 2849 cp += 8; 2850 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2851 return; 2852 } 2853 hasampersand = 0; 2854 hp = NFSGROUPHASH(gid); 2855 mtx_lock(&hp->mtx); 2856 TAILQ_FOREACH(usrp, &hp->lughead, lug_numhash) { 2857 if (usrp->lug_gid == gid) { 2858 if (usrp->lug_expiry < NFSD_MONOSEC) 2859 break; 2860 /* 2861 * If the name doesn't already have an '@' 2862 * in it, append @domainname to it. 2863 */ 2864 for (i = 0; i < usrp->lug_namelen; i++) { 2865 if (usrp->lug_name[i] == '@') { 2866 hasampersand = 1; 2867 break; 2868 } 2869 } 2870 if (hasampersand) 2871 i = usrp->lug_namelen; 2872 else 2873 i = usrp->lug_namelen + 2874 nfsrv_dnsnamelen + 1; 2875 if (i > len) { 2876 mtx_unlock(&hp->mtx); 2877 if (len > NFSV4_SMALLSTR) 2878 free(cp, M_NFSSTRING); 2879 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2880 *cpp = cp; 2881 len = i; 2882 goto tryagain; 2883 } 2884 *retlenp = i; 2885 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2886 if (!hasampersand) { 2887 cp += usrp->lug_namelen; 2888 *cp++ = '@'; 2889 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2890 } 2891 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 2892 TAILQ_INSERT_TAIL(&hp->lughead, usrp, 2893 lug_numhash); 2894 mtx_unlock(&hp->mtx); 2895 return; 2896 } 2897 } 2898 mtx_unlock(&hp->mtx); 2899 cnt++; 2900 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, 2901 NULL, p); 2902 if (ret == 0 && cnt < 2) 2903 goto tryagain; 2904 } 2905 2906 /* 2907 * No match, just return a string of digits. 2908 */ 2909 tmp = gid; 2910 i = 0; 2911 while (tmp || i == 0) { 2912 tmp /= 10; 2913 i++; 2914 } 2915 len = (i > len) ? len : i; 2916 *retlenp = len; 2917 cp += (len - 1); 2918 tmp = gid; 2919 for (i = 0; i < len; i++) { 2920 *cp-- = '0' + (tmp % 10); 2921 tmp /= 10; 2922 } 2923 return; 2924} 2925 2926/* 2927 * Convert a string to a gid. 2928 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2929 * return 0. 2930 * If this is called from a client side mount using AUTH_SYS and the 2931 * string is made up entirely of digits, just convert the string to 2932 * a number. 2933 */ 2934APPLESTATIC int 2935nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp, 2936 NFSPROC_T *p) 2937{ 2938 int i; 2939 char *cp, *endstr, *str0; 2940 struct nfsusrgrp *usrp; 2941 int cnt, ret; 2942 int error = 0; 2943 gid_t tgid; 2944 struct nfsrv_lughash *hp, *hp2; 2945 2946 if (len == 0) { 2947 error = NFSERR_BADOWNER; 2948 goto out; 2949 } 2950 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2951 str0 = str; 2952 tgid = (gid_t)strtoul(str0, &endstr, 10); 2953 if ((endstr - str0) == len) { 2954 /* A numeric string. */ 2955 if ((nd->nd_flag & ND_KERBV) == 0 && 2956 ((nd->nd_flag & ND_NFSCL) != 0 || 2957 nfsd_enable_stringtouid != 0)) 2958 *gidp = tgid; 2959 else 2960 error = NFSERR_BADOWNER; 2961 goto out; 2962 } 2963 /* 2964 * Look for an '@'. 2965 */ 2966 cp = strchr(str0, '@'); 2967 if (cp != NULL) 2968 i = (int)(cp++ - str0); 2969 else 2970 i = len; 2971 2972 cnt = 0; 2973tryagain: 2974 if (nfsrv_dnsnamelen > 0) { 2975 /* 2976 * If an '@' is found and the dns name matches, search for the 2977 * name with the dns stripped off. 2978 */ 2979 if (cnt == 0 && i < len && i > 0 && 2980 (len - 1 - i) == nfsrv_dnsnamelen && 2981 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2982 len -= (nfsrv_dnsnamelen + 1); 2983 *(cp - 1) = '\0'; 2984 } 2985 2986 /* 2987 * Check for the special case of "nogroup". 2988 */ 2989 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 2990 *gidp = nfsrv_defaultgid; 2991 error = 0; 2992 goto out; 2993 } 2994 2995 hp = NFSGROUPNAMEHASH(str, len); 2996 mtx_lock(&hp->mtx); 2997 TAILQ_FOREACH(usrp, &hp->lughead, lug_namehash) { 2998 if (usrp->lug_namelen == len && 2999 !NFSBCMP(usrp->lug_name, str, len)) { 3000 if (usrp->lug_expiry < NFSD_MONOSEC) 3001 break; 3002 hp2 = NFSGROUPHASH(usrp->lug_gid); 3003 mtx_lock(&hp2->mtx); 3004 TAILQ_REMOVE(&hp2->lughead, usrp, lug_numhash); 3005 TAILQ_INSERT_TAIL(&hp2->lughead, usrp, 3006 lug_numhash); 3007 *gidp = usrp->lug_gid; 3008 mtx_unlock(&hp2->mtx); 3009 mtx_unlock(&hp->mtx); 3010 error = 0; 3011 goto out; 3012 } 3013 } 3014 mtx_unlock(&hp->mtx); 3015 cnt++; 3016 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 3017 str, p); 3018 if (ret == 0 && cnt < 2) 3019 goto tryagain; 3020 } 3021 error = NFSERR_BADOWNER; 3022 3023out: 3024 NFSEXITCODE(error); 3025 return (error); 3026} 3027 3028/* 3029 * Cmp len chars, allowing mixed case in the first argument to match lower 3030 * case in the second, but not if the first argument is all upper case. 3031 * Return 0 for a match, 1 otherwise. 3032 */ 3033static int 3034nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 3035{ 3036 int i; 3037 u_char tmp; 3038 int fndlower = 0; 3039 3040 for (i = 0; i < len; i++) { 3041 if (*cp >= 'A' && *cp <= 'Z') { 3042 tmp = *cp++ + ('a' - 'A'); 3043 } else { 3044 tmp = *cp++; 3045 if (tmp >= 'a' && tmp <= 'z') 3046 fndlower = 1; 3047 } 3048 if (tmp != *cp2++) 3049 return (1); 3050 } 3051 if (fndlower) 3052 return (0); 3053 else 3054 return (1); 3055} 3056 3057/* 3058 * Set the port for the nfsuserd. 3059 */ 3060APPLESTATIC int 3061nfsrv_nfsuserdport(u_short port, NFSPROC_T *p) 3062{ 3063 struct nfssockreq *rp; 3064 struct sockaddr_in *ad; 3065 int error; 3066 3067 NFSLOCKNAMEID(); 3068 if (nfsrv_nfsuserd) { 3069 NFSUNLOCKNAMEID(); 3070 error = EPERM; 3071 goto out; 3072 } 3073 nfsrv_nfsuserd = 1; 3074 NFSUNLOCKNAMEID(); 3075 /* 3076 * Set up the socket record and connect. 3077 */ 3078 rp = &nfsrv_nfsuserdsock; 3079 rp->nr_client = NULL; 3080 rp->nr_sotype = SOCK_DGRAM; 3081 rp->nr_soproto = IPPROTO_UDP; 3082 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 3083 rp->nr_cred = NULL; 3084 NFSSOCKADDRALLOC(rp->nr_nam); 3085 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in)); 3086 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *); 3087 ad->sin_family = AF_INET; 3088 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */ 3089 ad->sin_port = port; 3090 rp->nr_prog = RPCPROG_NFSUSERD; 3091 rp->nr_vers = RPCNFSUSERD_VERS; 3092 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 3093 if (error) { 3094 NFSSOCKADDRFREE(rp->nr_nam); 3095 nfsrv_nfsuserd = 0; 3096 } 3097out: 3098 NFSEXITCODE(error); 3099 return (error); 3100} 3101 3102/* 3103 * Delete the nfsuserd port. 3104 */ 3105APPLESTATIC void 3106nfsrv_nfsuserddelport(void) 3107{ 3108 3109 NFSLOCKNAMEID(); 3110 if (nfsrv_nfsuserd == 0) { 3111 NFSUNLOCKNAMEID(); 3112 return; 3113 } 3114 nfsrv_nfsuserd = 0; 3115 NFSUNLOCKNAMEID(); 3116 newnfs_disconnect(&nfsrv_nfsuserdsock); 3117 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); 3118} 3119 3120/* 3121 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 3122 * name<-->id cache. 3123 * Returns 0 upon success, non-zero otherwise. 3124 */ 3125static int 3126nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) 3127{ 3128 u_int32_t *tl; 3129 struct nfsrv_descript *nd; 3130 int len; 3131 struct nfsrv_descript nfsd; 3132 struct ucred *cred; 3133 int error; 3134 3135 NFSLOCKNAMEID(); 3136 if (nfsrv_nfsuserd == 0) { 3137 NFSUNLOCKNAMEID(); 3138 error = EPERM; 3139 goto out; 3140 } 3141 NFSUNLOCKNAMEID(); 3142 nd = &nfsd; 3143 cred = newnfs_getcred(); 3144 nd->nd_flag = ND_GSSINITREPLY; 3145 nfsrvd_rephead(nd); 3146 3147 nd->nd_procnum = procnum; 3148 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3149 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3150 if (procnum == RPCNFSUSERD_GETUID) 3151 *tl = txdr_unsigned(uid); 3152 else 3153 *tl = txdr_unsigned(gid); 3154 } else { 3155 len = strlen(name); 3156 (void) nfsm_strtom(nd, name, len); 3157 } 3158 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 3159 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL); 3160 NFSFREECRED(cred); 3161 if (!error) { 3162 mbuf_freem(nd->nd_mrep); 3163 error = nd->nd_repstat; 3164 } 3165out: 3166 NFSEXITCODE(error); 3167 return (error); 3168} 3169 3170/* 3171 * This function is called from the nfssvc(2) system call, to update the 3172 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3173 */ 3174APPLESTATIC int 3175nfssvc_idname(struct nfsd_idargs *nidp) 3176{ 3177 struct nfsusrgrp *nusrp, *usrp, *newusrp; 3178 struct nfsrv_lughash *hp_name, *hp_idnum, *thp; 3179 int i, group_locked, groupname_locked, user_locked, username_locked; 3180 int error = 0; 3181 u_char *cp; 3182 gid_t *grps; 3183 struct ucred *cr; 3184 static int onethread = 0; 3185 static time_t lasttime = 0; 3186 3187 if (nidp->nid_namelen <= 0 || nidp->nid_namelen > MAXHOSTNAMELEN) { 3188 error = EINVAL; 3189 goto out; 3190 } 3191 if (nidp->nid_flag & NFSID_INITIALIZE) { 3192 cp = malloc(nidp->nid_namelen + 1, M_NFSSTRING, M_WAITOK); 3193 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 3194 nidp->nid_namelen); 3195 if (error != 0) { 3196 free(cp, M_NFSSTRING); 3197 goto out; 3198 } 3199 if (atomic_cmpset_acq_int(&nfsrv_dnsnamelen, 0, 0) == 0) { 3200 /* 3201 * Free up all the old stuff and reinitialize hash 3202 * lists. All mutexes for both lists must be locked, 3203 * with the user/group name ones before the uid/gid 3204 * ones, to avoid a LOR. 3205 */ 3206 for (i = 0; i < nfsrv_lughashsize; i++) 3207 mtx_lock(&nfsusernamehash[i].mtx); 3208 for (i = 0; i < nfsrv_lughashsize; i++) 3209 mtx_lock(&nfsuserhash[i].mtx); 3210 for (i = 0; i < nfsrv_lughashsize; i++) 3211 TAILQ_FOREACH_SAFE(usrp, 3212 &nfsuserhash[i].lughead, lug_numhash, nusrp) 3213 nfsrv_removeuser(usrp, 1); 3214 for (i = 0; i < nfsrv_lughashsize; i++) 3215 mtx_unlock(&nfsuserhash[i].mtx); 3216 for (i = 0; i < nfsrv_lughashsize; i++) 3217 mtx_unlock(&nfsusernamehash[i].mtx); 3218 for (i = 0; i < nfsrv_lughashsize; i++) 3219 mtx_lock(&nfsgroupnamehash[i].mtx); 3220 for (i = 0; i < nfsrv_lughashsize; i++) 3221 mtx_lock(&nfsgrouphash[i].mtx); 3222 for (i = 0; i < nfsrv_lughashsize; i++) 3223 TAILQ_FOREACH_SAFE(usrp, 3224 &nfsgrouphash[i].lughead, lug_numhash, 3225 nusrp) 3226 nfsrv_removeuser(usrp, 0); 3227 for (i = 0; i < nfsrv_lughashsize; i++) 3228 mtx_unlock(&nfsgrouphash[i].mtx); 3229 for (i = 0; i < nfsrv_lughashsize; i++) 3230 mtx_unlock(&nfsgroupnamehash[i].mtx); 3231 free(nfsrv_dnsname, M_NFSSTRING); 3232 nfsrv_dnsname = NULL; 3233 } 3234 if (nfsuserhash == NULL) { 3235 /* Allocate the hash tables. */ 3236 nfsuserhash = malloc(sizeof(struct nfsrv_lughash) * 3237 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3238 M_ZERO); 3239 for (i = 0; i < nfsrv_lughashsize; i++) 3240 mtx_init(&nfsuserhash[i].mtx, "nfsuidhash", 3241 NULL, MTX_DEF | MTX_DUPOK); 3242 nfsusernamehash = malloc(sizeof(struct nfsrv_lughash) * 3243 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3244 M_ZERO); 3245 for (i = 0; i < nfsrv_lughashsize; i++) 3246 mtx_init(&nfsusernamehash[i].mtx, 3247 "nfsusrhash", NULL, MTX_DEF | 3248 MTX_DUPOK); 3249 nfsgrouphash = malloc(sizeof(struct nfsrv_lughash) * 3250 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3251 M_ZERO); 3252 for (i = 0; i < nfsrv_lughashsize; i++) 3253 mtx_init(&nfsgrouphash[i].mtx, "nfsgidhash", 3254 NULL, MTX_DEF | MTX_DUPOK); 3255 nfsgroupnamehash = malloc(sizeof(struct nfsrv_lughash) * 3256 nfsrv_lughashsize, M_NFSUSERGROUP, M_WAITOK | 3257 M_ZERO); 3258 for (i = 0; i < nfsrv_lughashsize; i++) 3259 mtx_init(&nfsgroupnamehash[i].mtx, 3260 "nfsgrphash", NULL, MTX_DEF | MTX_DUPOK); 3261 } 3262 /* (Re)initialize the list heads. */ 3263 for (i = 0; i < nfsrv_lughashsize; i++) 3264 TAILQ_INIT(&nfsuserhash[i].lughead); 3265 for (i = 0; i < nfsrv_lughashsize; i++) 3266 TAILQ_INIT(&nfsusernamehash[i].lughead); 3267 for (i = 0; i < nfsrv_lughashsize; i++) 3268 TAILQ_INIT(&nfsgrouphash[i].lughead); 3269 for (i = 0; i < nfsrv_lughashsize; i++) 3270 TAILQ_INIT(&nfsgroupnamehash[i].lughead); 3271 3272 /* 3273 * Put name in "DNS" string. 3274 */ 3275 nfsrv_dnsname = cp; 3276 nfsrv_defaultuid = nidp->nid_uid; 3277 nfsrv_defaultgid = nidp->nid_gid; 3278 nfsrv_usercnt = 0; 3279 nfsrv_usermax = nidp->nid_usermax; 3280 atomic_store_rel_int(&nfsrv_dnsnamelen, nidp->nid_namelen); 3281 goto out; 3282 } 3283 3284 /* 3285 * malloc the new one now, so any potential sleep occurs before 3286 * manipulation of the lists. 3287 */ 3288 newusrp = malloc(sizeof(struct nfsusrgrp) + nidp->nid_namelen, 3289 M_NFSUSERGROUP, M_WAITOK | M_ZERO); 3290 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 3291 nidp->nid_namelen); 3292 if (error == 0 && nidp->nid_ngroup > 0 && 3293 (nidp->nid_flag & NFSID_ADDUID) != 0) { 3294 grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP, 3295 M_WAITOK); 3296 error = copyin(CAST_USER_ADDR_T(nidp->nid_grps), grps, 3297 sizeof(gid_t) * nidp->nid_ngroup); 3298 if (error == 0) { 3299 /* 3300 * Create a credential just like svc_getcred(), 3301 * but using the group list provided. 3302 */ 3303 cr = crget(); 3304 cr->cr_uid = cr->cr_ruid = cr->cr_svuid = nidp->nid_uid; 3305 crsetgroups(cr, nidp->nid_ngroup, grps); 3306 cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0]; 3307 cr->cr_prison = &prison0; 3308 prison_hold(cr->cr_prison); 3309#ifdef MAC 3310 mac_cred_associate_nfsd(cr); 3311#endif 3312 newusrp->lug_cred = cr; 3313 } 3314 free(grps, M_TEMP); 3315 } 3316 if (error) { 3317 free(newusrp, M_NFSUSERGROUP); 3318 goto out; 3319 } 3320 newusrp->lug_namelen = nidp->nid_namelen; 3321 3322 /* 3323 * The lock order is username[0]->[nfsrv_lughashsize - 1] followed 3324 * by uid[0]->[nfsrv_lughashsize - 1], with the same for group. 3325 * The flags user_locked, username_locked, group_locked and 3326 * groupname_locked are set to indicate all of those hash lists are 3327 * locked. hp_name != NULL and hp_idnum != NULL indicates that 3328 * the respective one mutex is locked. 3329 */ 3330 user_locked = username_locked = group_locked = groupname_locked = 0; 3331 hp_name = hp_idnum = NULL; 3332 3333 /* 3334 * Delete old entries, as required. 3335 */ 3336 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3337 /* Must lock all username hash lists first, to avoid a LOR. */ 3338 for (i = 0; i < nfsrv_lughashsize; i++) 3339 mtx_lock(&nfsusernamehash[i].mtx); 3340 username_locked = 1; 3341 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3342 mtx_lock(&hp_idnum->mtx); 3343 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3344 nusrp) { 3345 if (usrp->lug_uid == nidp->nid_uid) 3346 nfsrv_removeuser(usrp, 1); 3347 } 3348 } else if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3349 hp_name = NFSUSERNAMEHASH(newusrp->lug_name, 3350 newusrp->lug_namelen); 3351 mtx_lock(&hp_name->mtx); 3352 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3353 nusrp) { 3354 if (usrp->lug_namelen == newusrp->lug_namelen && 3355 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3356 usrp->lug_namelen)) { 3357 thp = NFSUSERHASH(usrp->lug_uid); 3358 mtx_lock(&thp->mtx); 3359 nfsrv_removeuser(usrp, 1); 3360 mtx_unlock(&thp->mtx); 3361 } 3362 } 3363 hp_idnum = NFSUSERHASH(nidp->nid_uid); 3364 mtx_lock(&hp_idnum->mtx); 3365 } else if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3366 /* Must lock all groupname hash lists first, to avoid a LOR. */ 3367 for (i = 0; i < nfsrv_lughashsize; i++) 3368 mtx_lock(&nfsgroupnamehash[i].mtx); 3369 groupname_locked = 1; 3370 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3371 mtx_lock(&hp_idnum->mtx); 3372 TAILQ_FOREACH_SAFE(usrp, &hp_idnum->lughead, lug_numhash, 3373 nusrp) { 3374 if (usrp->lug_gid == nidp->nid_gid) 3375 nfsrv_removeuser(usrp, 0); 3376 } 3377 } else if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3378 hp_name = NFSGROUPNAMEHASH(newusrp->lug_name, 3379 newusrp->lug_namelen); 3380 mtx_lock(&hp_name->mtx); 3381 TAILQ_FOREACH_SAFE(usrp, &hp_name->lughead, lug_namehash, 3382 nusrp) { 3383 if (usrp->lug_namelen == newusrp->lug_namelen && 3384 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3385 usrp->lug_namelen)) { 3386 thp = NFSGROUPHASH(usrp->lug_gid); 3387 mtx_lock(&thp->mtx); 3388 nfsrv_removeuser(usrp, 0); 3389 mtx_unlock(&thp->mtx); 3390 } 3391 } 3392 hp_idnum = NFSGROUPHASH(nidp->nid_gid); 3393 mtx_lock(&hp_idnum->mtx); 3394 } 3395 3396 /* 3397 * Now, we can add the new one. 3398 */ 3399 if (nidp->nid_usertimeout) 3400 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3401 else 3402 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3403 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3404 newusrp->lug_uid = nidp->nid_uid; 3405 thp = NFSUSERHASH(newusrp->lug_uid); 3406 mtx_assert(&thp->mtx, MA_OWNED); 3407 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3408 thp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3409 mtx_assert(&thp->mtx, MA_OWNED); 3410 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3411 atomic_add_int(&nfsrv_usercnt, 1); 3412 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3413 newusrp->lug_gid = nidp->nid_gid; 3414 thp = NFSGROUPHASH(newusrp->lug_gid); 3415 mtx_assert(&thp->mtx, MA_OWNED); 3416 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_numhash); 3417 thp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3418 mtx_assert(&thp->mtx, MA_OWNED); 3419 TAILQ_INSERT_TAIL(&thp->lughead, newusrp, lug_namehash); 3420 atomic_add_int(&nfsrv_usercnt, 1); 3421 } else { 3422 if (newusrp->lug_cred != NULL) 3423 crfree(newusrp->lug_cred); 3424 free(newusrp, M_NFSUSERGROUP); 3425 } 3426 3427 /* 3428 * Once per second, allow one thread to trim the cache. 3429 */ 3430 if (lasttime < NFSD_MONOSEC && 3431 atomic_cmpset_acq_int(&onethread, 0, 1) != 0) { 3432 /* 3433 * First, unlock the single mutexes, so that all entries 3434 * can be locked and any LOR is avoided. 3435 */ 3436 if (hp_name != NULL) { 3437 mtx_unlock(&hp_name->mtx); 3438 hp_name = NULL; 3439 } 3440 if (hp_idnum != NULL) { 3441 mtx_unlock(&hp_idnum->mtx); 3442 hp_idnum = NULL; 3443 } 3444 3445 if ((nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID | 3446 NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) != 0) { 3447 if (username_locked == 0) { 3448 for (i = 0; i < nfsrv_lughashsize; i++) 3449 mtx_lock(&nfsusernamehash[i].mtx); 3450 username_locked = 1; 3451 } 3452 KASSERT(user_locked == 0, 3453 ("nfssvc_idname: user_locked")); 3454 for (i = 0; i < nfsrv_lughashsize; i++) 3455 mtx_lock(&nfsuserhash[i].mtx); 3456 user_locked = 1; 3457 for (i = 0; i < nfsrv_lughashsize; i++) { 3458 TAILQ_FOREACH_SAFE(usrp, 3459 &nfsuserhash[i].lughead, lug_numhash, 3460 nusrp) 3461 if (usrp->lug_expiry < NFSD_MONOSEC) 3462 nfsrv_removeuser(usrp, 1); 3463 } 3464 for (i = 0; i < nfsrv_lughashsize; i++) { 3465 /* 3466 * Trim the cache using an approximate LRU 3467 * algorithm. This code deletes the least 3468 * recently used entry on each hash list. 3469 */ 3470 if (nfsrv_usercnt <= nfsrv_usermax) 3471 break; 3472 usrp = TAILQ_FIRST(&nfsuserhash[i].lughead); 3473 if (usrp != NULL) 3474 nfsrv_removeuser(usrp, 1); 3475 } 3476 } else { 3477 if (groupname_locked == 0) { 3478 for (i = 0; i < nfsrv_lughashsize; i++) 3479 mtx_lock(&nfsgroupnamehash[i].mtx); 3480 groupname_locked = 1; 3481 } 3482 KASSERT(group_locked == 0, 3483 ("nfssvc_idname: group_locked")); 3484 for (i = 0; i < nfsrv_lughashsize; i++) 3485 mtx_lock(&nfsgrouphash[i].mtx); 3486 group_locked = 1; 3487 for (i = 0; i < nfsrv_lughashsize; i++) { 3488 TAILQ_FOREACH_SAFE(usrp, 3489 &nfsgrouphash[i].lughead, lug_numhash, 3490 nusrp) 3491 if (usrp->lug_expiry < NFSD_MONOSEC) 3492 nfsrv_removeuser(usrp, 0); 3493 } 3494 for (i = 0; i < nfsrv_lughashsize; i++) { 3495 /* 3496 * Trim the cache using an approximate LRU 3497 * algorithm. This code deletes the least 3498 * recently user entry on each hash list. 3499 */ 3500 if (nfsrv_usercnt <= nfsrv_usermax) 3501 break; 3502 usrp = TAILQ_FIRST(&nfsgrouphash[i].lughead); 3503 if (usrp != NULL) 3504 nfsrv_removeuser(usrp, 0); 3505 } 3506 } 3507 lasttime = NFSD_MONOSEC; 3508 atomic_store_rel_int(&onethread, 0); 3509 } 3510 3511 /* Now, unlock all locked mutexes. */ 3512 if (hp_idnum != NULL) 3513 mtx_unlock(&hp_idnum->mtx); 3514 if (hp_name != NULL) 3515 mtx_unlock(&hp_name->mtx); 3516 if (user_locked != 0) 3517 for (i = 0; i < nfsrv_lughashsize; i++) 3518 mtx_unlock(&nfsuserhash[i].mtx); 3519 if (username_locked != 0) 3520 for (i = 0; i < nfsrv_lughashsize; i++) 3521 mtx_unlock(&nfsusernamehash[i].mtx); 3522 if (group_locked != 0) 3523 for (i = 0; i < nfsrv_lughashsize; i++) 3524 mtx_unlock(&nfsgrouphash[i].mtx); 3525 if (groupname_locked != 0) 3526 for (i = 0; i < nfsrv_lughashsize; i++) 3527 mtx_unlock(&nfsgroupnamehash[i].mtx); 3528out: 3529 NFSEXITCODE(error); 3530 return (error); 3531} 3532 3533/* 3534 * Remove a user/group name element. 3535 */ 3536static void 3537nfsrv_removeuser(struct nfsusrgrp *usrp, int isuser) 3538{ 3539 struct nfsrv_lughash *hp; 3540 3541 if (isuser != 0) { 3542 hp = NFSUSERHASH(usrp->lug_uid); 3543 mtx_assert(&hp->mtx, MA_OWNED); 3544 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3545 hp = NFSUSERNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3546 mtx_assert(&hp->mtx, MA_OWNED); 3547 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 3548 } else { 3549 hp = NFSGROUPHASH(usrp->lug_gid); 3550 mtx_assert(&hp->mtx, MA_OWNED); 3551 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3552 hp = NFSGROUPNAMEHASH(usrp->lug_name, usrp->lug_namelen); 3553 mtx_assert(&hp->mtx, MA_OWNED); 3554 TAILQ_REMOVE(&hp->lughead, usrp, lug_namehash); 3555 } 3556 atomic_add_int(&nfsrv_usercnt, -1); 3557 if (usrp->lug_cred != NULL) 3558 crfree(usrp->lug_cred); 3559 free(usrp, M_NFSUSERGROUP); 3560} 3561 3562/* 3563 * Free up all the allocations related to the name<-->id cache. 3564 * This function should only be called when the nfsuserd daemon isn't 3565 * running, since it doesn't do any locking. 3566 * This function is meant to be used when the nfscommon module is unloaded. 3567 */ 3568APPLESTATIC void 3569nfsrv_cleanusergroup(void) 3570{ 3571 struct nfsrv_lughash *hp, *hp2; 3572 struct nfsusrgrp *nusrp, *usrp; 3573 int i; 3574 3575 if (nfsuserhash == NULL) 3576 return; 3577 3578 for (i = 0; i < nfsrv_lughashsize; i++) { 3579 hp = &nfsuserhash[i]; 3580 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 3581 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3582 hp2 = NFSUSERNAMEHASH(usrp->lug_name, 3583 usrp->lug_namelen); 3584 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 3585 if (usrp->lug_cred != NULL) 3586 crfree(usrp->lug_cred); 3587 free(usrp, M_NFSUSERGROUP); 3588 } 3589 hp = &nfsgrouphash[i]; 3590 TAILQ_FOREACH_SAFE(usrp, &hp->lughead, lug_numhash, nusrp) { 3591 TAILQ_REMOVE(&hp->lughead, usrp, lug_numhash); 3592 hp2 = NFSGROUPNAMEHASH(usrp->lug_name, 3593 usrp->lug_namelen); 3594 TAILQ_REMOVE(&hp2->lughead, usrp, lug_namehash); 3595 if (usrp->lug_cred != NULL) 3596 crfree(usrp->lug_cred); 3597 free(usrp, M_NFSUSERGROUP); 3598 } 3599 mtx_destroy(&nfsuserhash[i].mtx); 3600 mtx_destroy(&nfsusernamehash[i].mtx); 3601 mtx_destroy(&nfsgroupnamehash[i].mtx); 3602 mtx_destroy(&nfsgrouphash[i].mtx); 3603 } 3604 free(nfsuserhash, M_NFSUSERGROUP); 3605 free(nfsusernamehash, M_NFSUSERGROUP); 3606 free(nfsgrouphash, M_NFSUSERGROUP); 3607 free(nfsgroupnamehash, M_NFSUSERGROUP); 3608 free(nfsrv_dnsname, M_NFSSTRING); 3609} 3610 3611/* 3612 * This function scans a byte string and checks for UTF-8 compliance. 3613 * It returns 0 if it conforms and NFSERR_INVAL if not. 3614 */ 3615APPLESTATIC int 3616nfsrv_checkutf8(u_int8_t *cp, int len) 3617{ 3618 u_int32_t val = 0x0; 3619 int cnt = 0, gotd = 0, shift = 0; 3620 u_int8_t byte; 3621 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 3622 int error = 0; 3623 3624 /* 3625 * Here are what the variables are used for: 3626 * val - the calculated value of a multibyte char, used to check 3627 * that it was coded with the correct range 3628 * cnt - the number of 10xxxxxx bytes to follow 3629 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 3630 * shift - lower order bits of range (ie. "val >> shift" should 3631 * not be 0, in other words, dividing by the lower bound 3632 * of the range should get a non-zero value) 3633 * byte - used to calculate cnt 3634 */ 3635 while (len > 0) { 3636 if (cnt > 0) { 3637 /* This handles the 10xxxxxx bytes */ 3638 if ((*cp & 0xc0) != 0x80 || 3639 (gotd && (*cp & 0x20))) { 3640 error = NFSERR_INVAL; 3641 goto out; 3642 } 3643 gotd = 0; 3644 val <<= 6; 3645 val |= (*cp & 0x3f); 3646 cnt--; 3647 if (cnt == 0 && (val >> shift) == 0x0) { 3648 error = NFSERR_INVAL; 3649 goto out; 3650 } 3651 } else if (*cp & 0x80) { 3652 /* first byte of multi byte char */ 3653 byte = *cp; 3654 while ((byte & 0x40) && cnt < 6) { 3655 cnt++; 3656 byte <<= 1; 3657 } 3658 if (cnt == 0 || cnt == 6) { 3659 error = NFSERR_INVAL; 3660 goto out; 3661 } 3662 val = (*cp & (0x3f >> cnt)); 3663 shift = utf8_shift[cnt - 1]; 3664 if (cnt == 2 && val == 0xd) 3665 /* Check for the 0xd800-0xdfff case */ 3666 gotd = 1; 3667 } 3668 cp++; 3669 len--; 3670 } 3671 if (cnt > 0) 3672 error = NFSERR_INVAL; 3673 3674out: 3675 NFSEXITCODE(error); 3676 return (error); 3677} 3678 3679/* 3680 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 3681 * strings, one with the root path in it and the other with the list of 3682 * locations. The list is in the same format as is found in nfr_refs. 3683 * It is a "," separated list of entries, where each of them is of the 3684 * form <server>:<rootpath>. For example 3685 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 3686 * The nilp argument is set to 1 for the special case of a null fs_root 3687 * and an empty server list. 3688 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 3689 * number of xdr bytes parsed in sump. 3690 */ 3691static int 3692nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 3693 int *sump, int *nilp) 3694{ 3695 u_int32_t *tl; 3696 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 3697 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 3698 struct list { 3699 SLIST_ENTRY(list) next; 3700 int len; 3701 u_char host[1]; 3702 } *lsp, *nlsp; 3703 SLIST_HEAD(, list) head; 3704 3705 *fsrootp = NULL; 3706 *srvp = NULL; 3707 *nilp = 0; 3708 3709 /* 3710 * Get the fs_root path and check for the special case of null path 3711 * and 0 length server list. 3712 */ 3713 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3714 len = fxdr_unsigned(int, *tl); 3715 if (len < 0 || len > 10240) { 3716 error = NFSERR_BADXDR; 3717 goto nfsmout; 3718 } 3719 if (len == 0) { 3720 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3721 if (*tl != 0) { 3722 error = NFSERR_BADXDR; 3723 goto nfsmout; 3724 } 3725 *nilp = 1; 3726 *sump = 2 * NFSX_UNSIGNED; 3727 error = 0; 3728 goto nfsmout; 3729 } 3730 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 3731 error = nfsrv_mtostr(nd, cp, len); 3732 if (!error) { 3733 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3734 cnt = fxdr_unsigned(int, *tl); 3735 if (cnt <= 0) 3736 error = NFSERR_BADXDR; 3737 } 3738 if (error) 3739 goto nfsmout; 3740 3741 /* 3742 * Now, loop through the location list and make up the srvlist. 3743 */ 3744 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3745 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 3746 slen = 1024; 3747 siz = 0; 3748 for (i = 0; i < cnt; i++) { 3749 SLIST_INIT(&head); 3750 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3751 nsrv = fxdr_unsigned(int, *tl); 3752 if (nsrv <= 0) { 3753 error = NFSERR_BADXDR; 3754 goto nfsmout; 3755 } 3756 3757 /* 3758 * Handle the first server by putting it in the srvstr. 3759 */ 3760 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3761 len = fxdr_unsigned(int, *tl); 3762 if (len <= 0 || len > 1024) { 3763 error = NFSERR_BADXDR; 3764 goto nfsmout; 3765 } 3766 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 3767 if (cp3 != cp2) { 3768 *cp3++ = ','; 3769 siz++; 3770 } 3771 error = nfsrv_mtostr(nd, cp3, len); 3772 if (error) 3773 goto nfsmout; 3774 cp3 += len; 3775 *cp3++ = ':'; 3776 siz += (len + 1); 3777 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3778 for (j = 1; j < nsrv; j++) { 3779 /* 3780 * Yuck, put them in an slist and process them later. 3781 */ 3782 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3783 len = fxdr_unsigned(int, *tl); 3784 if (len <= 0 || len > 1024) { 3785 error = NFSERR_BADXDR; 3786 goto nfsmout; 3787 } 3788 lsp = (struct list *)malloc(sizeof (struct list) 3789 + len, M_TEMP, M_WAITOK); 3790 error = nfsrv_mtostr(nd, lsp->host, len); 3791 if (error) 3792 goto nfsmout; 3793 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3794 lsp->len = len; 3795 SLIST_INSERT_HEAD(&head, lsp, next); 3796 } 3797 3798 /* 3799 * Finally, we can get the path. 3800 */ 3801 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3802 len = fxdr_unsigned(int, *tl); 3803 if (len <= 0 || len > 1024) { 3804 error = NFSERR_BADXDR; 3805 goto nfsmout; 3806 } 3807 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 3808 error = nfsrv_mtostr(nd, cp3, len); 3809 if (error) 3810 goto nfsmout; 3811 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3812 str = cp3; 3813 stringlen = len; 3814 cp3 += len; 3815 siz += len; 3816 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 3817 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 3818 &cp2, &cp3, &slen); 3819 *cp3++ = ','; 3820 NFSBCOPY(lsp->host, cp3, lsp->len); 3821 cp3 += lsp->len; 3822 *cp3++ = ':'; 3823 NFSBCOPY(str, cp3, stringlen); 3824 cp3 += stringlen; 3825 *cp3 = '\0'; 3826 siz += (lsp->len + stringlen + 2); 3827 free((caddr_t)lsp, M_TEMP); 3828 } 3829 } 3830 *fsrootp = cp; 3831 *srvp = cp2; 3832 *sump = xdrsum; 3833 NFSEXITCODE2(0, nd); 3834 return (0); 3835nfsmout: 3836 if (cp != NULL) 3837 free(cp, M_NFSSTRING); 3838 if (cp2 != NULL) 3839 free(cp2, M_NFSSTRING); 3840 NFSEXITCODE2(error, nd); 3841 return (error); 3842} 3843 3844/* 3845 * Make the malloc'd space large enough. This is a pain, but the xdr 3846 * doesn't set an upper bound on the side, so... 3847 */ 3848static void 3849nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 3850{ 3851 u_char *cp; 3852 int i; 3853 3854 if (siz <= *slenp) 3855 return; 3856 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 3857 NFSBCOPY(*cpp, cp, *slenp); 3858 free(*cpp, M_NFSSTRING); 3859 i = *cpp2 - *cpp; 3860 *cpp = cp; 3861 *cpp2 = cp + i; 3862 *slenp = siz + 1024; 3863} 3864 3865/* 3866 * Initialize the reply header data structures. 3867 */ 3868APPLESTATIC void 3869nfsrvd_rephead(struct nfsrv_descript *nd) 3870{ 3871 mbuf_t mreq; 3872 3873 /* 3874 * If this is a big reply, use a cluster. 3875 */ 3876 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 3877 nfs_bigreply[nd->nd_procnum]) { 3878 NFSMCLGET(mreq, M_WAITOK); 3879 nd->nd_mreq = mreq; 3880 nd->nd_mb = mreq; 3881 } else { 3882 NFSMGET(mreq); 3883 nd->nd_mreq = mreq; 3884 nd->nd_mb = mreq; 3885 } 3886 nd->nd_bpos = NFSMTOD(mreq, caddr_t); 3887 mbuf_setlen(mreq, 0); 3888 3889 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 3890 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 3891} 3892 3893/* 3894 * Lock a socket against others. 3895 * Currently used to serialize connect/disconnect attempts. 3896 */ 3897int 3898newnfs_sndlock(int *flagp) 3899{ 3900 struct timespec ts; 3901 3902 NFSLOCKSOCK(); 3903 while (*flagp & NFSR_SNDLOCK) { 3904 *flagp |= NFSR_WANTSND; 3905 ts.tv_sec = 0; 3906 ts.tv_nsec = 0; 3907 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 3908 PZERO - 1, "nfsndlck", &ts); 3909 } 3910 *flagp |= NFSR_SNDLOCK; 3911 NFSUNLOCKSOCK(); 3912 return (0); 3913} 3914 3915/* 3916 * Unlock the stream socket for others. 3917 */ 3918void 3919newnfs_sndunlock(int *flagp) 3920{ 3921 3922 NFSLOCKSOCK(); 3923 if ((*flagp & NFSR_SNDLOCK) == 0) 3924 panic("nfs sndunlock"); 3925 *flagp &= ~NFSR_SNDLOCK; 3926 if (*flagp & NFSR_WANTSND) { 3927 *flagp &= ~NFSR_WANTSND; 3928 wakeup((caddr_t)flagp); 3929 } 3930 NFSUNLOCKSOCK(); 3931} 3932 3933APPLESTATIC int 3934nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa, 3935 int *isudp) 3936{ 3937 struct sockaddr_in *sad; 3938 struct sockaddr_in6 *sad6; 3939 struct in_addr saddr; 3940 uint32_t portnum, *tl; 3941 int af = 0, i, j, k; 3942 char addr[64], protocol[5], *cp; 3943 int cantparse = 0, error = 0; 3944 uint16_t portv; 3945 3946 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3947 i = fxdr_unsigned(int, *tl); 3948 if (i >= 3 && i <= 4) { 3949 error = nfsrv_mtostr(nd, protocol, i); 3950 if (error) 3951 goto nfsmout; 3952 if (strcmp(protocol, "tcp") == 0) { 3953 af = AF_INET; 3954 *isudp = 0; 3955 } else if (strcmp(protocol, "udp") == 0) { 3956 af = AF_INET; 3957 *isudp = 1; 3958 } else if (strcmp(protocol, "tcp6") == 0) { 3959 af = AF_INET6; 3960 *isudp = 0; 3961 } else if (strcmp(protocol, "udp6") == 0) { 3962 af = AF_INET6; 3963 *isudp = 1; 3964 } else 3965 cantparse = 1; 3966 } else { 3967 cantparse = 1; 3968 if (i > 0) { 3969 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3970 if (error) 3971 goto nfsmout; 3972 } 3973 } 3974 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3975 i = fxdr_unsigned(int, *tl); 3976 if (i < 0) { 3977 error = NFSERR_BADXDR; 3978 goto nfsmout; 3979 } else if (cantparse == 0 && i >= 11 && i < 64) { 3980 /* 3981 * The shortest address is 11chars and the longest is < 64. 3982 */ 3983 error = nfsrv_mtostr(nd, addr, i); 3984 if (error) 3985 goto nfsmout; 3986 3987 /* Find the port# at the end and extract that. */ 3988 i = strlen(addr); 3989 k = 0; 3990 cp = &addr[i - 1]; 3991 /* Count back two '.'s from end to get port# field. */ 3992 for (j = 0; j < i; j++) { 3993 if (*cp == '.') { 3994 k++; 3995 if (k == 2) 3996 break; 3997 } 3998 cp--; 3999 } 4000 if (k == 2) { 4001 /* 4002 * The NFSv4 port# is appended as .N.N, where N is 4003 * a decimal # in the range 0-255, just like an inet4 4004 * address. Cheat and use inet_aton(), which will 4005 * return a Class A address and then shift the high 4006 * order 8bits over to convert it to the port#. 4007 */ 4008 *cp++ = '\0'; 4009 if (inet_aton(cp, &saddr) == 1) { 4010 portnum = ntohl(saddr.s_addr); 4011 portv = (uint16_t)((portnum >> 16) | 4012 (portnum & 0xff)); 4013 } else 4014 cantparse = 1; 4015 } else 4016 cantparse = 1; 4017 if (cantparse == 0) { 4018 if (af == AF_INET) { 4019 sad = (struct sockaddr_in *)sa; 4020 if (inet_pton(af, addr, &sad->sin_addr) == 1) { 4021 sad->sin_len = sizeof(*sad); 4022 sad->sin_family = AF_INET; 4023 sad->sin_port = htons(portv); 4024 return (0); 4025 } 4026 } else { 4027 sad6 = (struct sockaddr_in6 *)sa; 4028 if (inet_pton(af, addr, &sad6->sin6_addr) 4029 == 1) { 4030 sad6->sin6_len = sizeof(*sad6); 4031 sad6->sin6_family = AF_INET6; 4032 sad6->sin6_port = htons(portv); 4033 return (0); 4034 } 4035 } 4036 } 4037 } else { 4038 if (i > 0) { 4039 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 4040 if (error) 4041 goto nfsmout; 4042 } 4043 } 4044 error = EPERM; 4045nfsmout: 4046 return (error); 4047} 4048 4049/* 4050 * Handle an NFSv4.1 Sequence request for the session. 4051 * If reply != NULL, use it to return the cached reply, as required. 4052 * The client gets a cached reply via this call for callbacks, however the 4053 * server gets a cached reply via the nfsv4_seqsess_cachereply() call. 4054 */ 4055int 4056nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 4057 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 4058{ 4059 int error; 4060 4061 error = 0; 4062 if (reply != NULL) 4063 *reply = NULL; 4064 if (slotid > maxslot) 4065 return (NFSERR_BADSLOT); 4066 if (seqid == slots[slotid].nfssl_seq) { 4067 /* A retry. */ 4068 if (slots[slotid].nfssl_inprog != 0) 4069 error = NFSERR_DELAY; 4070 else if (slots[slotid].nfssl_reply != NULL) { 4071 if (reply != NULL) { 4072 *reply = slots[slotid].nfssl_reply; 4073 slots[slotid].nfssl_reply = NULL; 4074 } 4075 slots[slotid].nfssl_inprog = 1; 4076 error = NFSERR_REPLYFROMCACHE; 4077 } else 4078 /* No reply cached, so just do it. */ 4079 slots[slotid].nfssl_inprog = 1; 4080 } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 4081 if (slots[slotid].nfssl_reply != NULL) 4082 m_freem(slots[slotid].nfssl_reply); 4083 slots[slotid].nfssl_reply = NULL; 4084 slots[slotid].nfssl_inprog = 1; 4085 slots[slotid].nfssl_seq++; 4086 } else 4087 error = NFSERR_SEQMISORDERED; 4088 return (error); 4089} 4090 4091/* 4092 * Cache this reply for the slot. 4093 * Use the "rep" argument to return the cached reply if repstat is set to 4094 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value. 4095 */ 4096void 4097nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat, 4098 struct mbuf **rep) 4099{ 4100 4101 if (repstat == NFSERR_REPLYFROMCACHE) { 4102 *rep = slots[slotid].nfssl_reply; 4103 slots[slotid].nfssl_reply = NULL; 4104 } else { 4105 if (slots[slotid].nfssl_reply != NULL) 4106 m_freem(slots[slotid].nfssl_reply); 4107 slots[slotid].nfssl_reply = *rep; 4108 } 4109 slots[slotid].nfssl_inprog = 0; 4110} 4111 4112/* 4113 * Generate the xdr for an NFSv4.1 Sequence Operation. 4114 */ 4115APPLESTATIC void 4116nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, 4117 struct nfsclsession *sep, int dont_replycache) 4118{ 4119 uint32_t *tl, slotseq = 0; 4120 int error, maxslot, slotpos; 4121 uint8_t sessionid[NFSX_V4SESSIONID]; 4122 4123 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq, 4124 sessionid); 4125 4126 /* Build the Sequence arguments. */ 4127 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 4128 nd->nd_sequence = tl; 4129 bcopy(sessionid, tl, NFSX_V4SESSIONID); 4130 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4131 nd->nd_slotseq = tl; 4132 if (error == 0) { 4133 *tl++ = txdr_unsigned(slotseq); 4134 *tl++ = txdr_unsigned(slotpos); 4135 *tl++ = txdr_unsigned(maxslot); 4136 if (dont_replycache == 0) 4137 *tl = newnfs_true; 4138 else 4139 *tl = newnfs_false; 4140 } else { 4141 /* 4142 * There are two errors and the rest of the session can 4143 * just be zeros. 4144 * NFSERR_BADSESSION: This bad session should just generate 4145 * the same error again when the RPC is retried. 4146 * ESTALE: A forced dismount is in progress and will cause the 4147 * RPC to fail later. 4148 */ 4149 *tl++ = 0; 4150 *tl++ = 0; 4151 *tl++ = 0; 4152 *tl = 0; 4153 } 4154 nd->nd_flag |= ND_HASSEQUENCE; 4155} 4156 4157int 4158nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep, 4159 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid) 4160{ 4161 int i, maxslot, slotpos; 4162 uint64_t bitval; 4163 4164 /* Find an unused slot. */ 4165 slotpos = -1; 4166 maxslot = -1; 4167 mtx_lock(&sep->nfsess_mtx); 4168 do { 4169 if (nmp != NULL && sep->nfsess_defunct != 0) { 4170 /* Just return the bad session. */ 4171 bcopy(sep->nfsess_sessionid, sessionid, 4172 NFSX_V4SESSIONID); 4173 mtx_unlock(&sep->nfsess_mtx); 4174 return (NFSERR_BADSESSION); 4175 } 4176 bitval = 1; 4177 for (i = 0; i < sep->nfsess_foreslots; i++) { 4178 if ((bitval & sep->nfsess_slots) == 0) { 4179 slotpos = i; 4180 sep->nfsess_slots |= bitval; 4181 sep->nfsess_slotseq[i]++; 4182 *slotseqp = sep->nfsess_slotseq[i]; 4183 break; 4184 } 4185 bitval <<= 1; 4186 } 4187 if (slotpos == -1) { 4188 /* 4189 * If a forced dismount is in progress, just return. 4190 * This RPC attempt will fail when it calls 4191 * newnfs_request(). 4192 */ 4193 if (nmp != NULL && 4194 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) 4195 != 0) { 4196 mtx_unlock(&sep->nfsess_mtx); 4197 return (ESTALE); 4198 } 4199 /* Wake up once/sec, to check for a forced dismount. */ 4200 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 4201 PZERO, "nfsclseq", hz); 4202 } 4203 } while (slotpos == -1); 4204 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 4205 bitval = 1; 4206 for (i = 0; i < 64; i++) { 4207 if ((bitval & sep->nfsess_slots) != 0) 4208 maxslot = i; 4209 bitval <<= 1; 4210 } 4211 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 4212 mtx_unlock(&sep->nfsess_mtx); 4213 *slotposp = slotpos; 4214 *maxslotp = maxslot; 4215 return (0); 4216} 4217 4218/* 4219 * Free a session slot. 4220 */ 4221APPLESTATIC void 4222nfsv4_freeslot(struct nfsclsession *sep, int slot) 4223{ 4224 uint64_t bitval; 4225 4226 bitval = 1; 4227 if (slot > 0) 4228 bitval <<= slot; 4229 mtx_lock(&sep->nfsess_mtx); 4230 if ((bitval & sep->nfsess_slots) == 0) 4231 printf("freeing free slot!!\n"); 4232 sep->nfsess_slots &= ~bitval; 4233 wakeup(&sep->nfsess_slots); 4234 mtx_unlock(&sep->nfsess_mtx); 4235} 4236 4237