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