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