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