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