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