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