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