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 if (compare) { 824 retnotsup = 0; 825 error = nfsrv_getattrbits(nd, &attrbits, NULL, &retnotsup); 826 } else { 827 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 828 } 829 if (error) 830 goto nfsmout; 831 832 if (compare) { 833 *retcmpp = retnotsup; 834 } else { 835 /* 836 * Just set default values to some of the important ones. 837 */ 838 if (nap != NULL) { 839 nap->na_type = VREG; 840 nap->na_mode = 0; 841 nap->na_rdev = (NFSDEV_T)0; 842 nap->na_mtime.tv_sec = 0; 843 nap->na_mtime.tv_nsec = 0; 844 nap->na_gen = 0; 845 nap->na_flags = 0; 846 nap->na_blocksize = NFS_FABLKSIZE; 847 } 848 if (sbp != NULL) { 849 sbp->f_bsize = NFS_FABLKSIZE; 850 sbp->f_blocks = 0; 851 sbp->f_bfree = 0; 852 sbp->f_bavail = 0; 853 sbp->f_files = 0; 854 sbp->f_ffree = 0; 855 } 856 if (fsp != NULL) { 857 fsp->fs_rtmax = 8192; 858 fsp->fs_rtpref = 8192; 859 fsp->fs_maxname = NFS_MAXNAMLEN; 860 fsp->fs_wtmax = 8192; 861 fsp->fs_wtpref = 8192; 862 fsp->fs_wtmult = NFS_FABLKSIZE; 863 fsp->fs_dtpref = 8192; 864 fsp->fs_maxfilesize = 0xffffffffffffffffull; 865 fsp->fs_timedelta.tv_sec = 0; 866 fsp->fs_timedelta.tv_nsec = 1; 867 fsp->fs_properties = (NFSV3_FSFLINK | NFSV3_FSFSYMLINK | 868 NFSV3_FSFHOMOGENEOUS | NFSV3_FSFCANSETTIME); 869 } 870 if (pc != NULL) { 871 pc->pc_linkmax = LINK_MAX; 872 pc->pc_namemax = NAME_MAX; 873 pc->pc_notrunc = 0; 874 pc->pc_chownrestricted = 0; 875 pc->pc_caseinsensitive = 0; 876 pc->pc_casepreserving = 1; 877 } 878 } 879 880 /* 881 * Loop around getting the attributes. 882 */ 883 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 884 attrsize = fxdr_unsigned(int, *tl); 885 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 886 if (attrsum > attrsize) { 887 error = NFSERR_BADXDR; 888 goto nfsmout; 889 } 890 if (NFSISSET_ATTRBIT(&attrbits, bitpos)) 891 switch (bitpos) { 892 case NFSATTRBIT_SUPPORTEDATTRS: 893 retnotsup = 0; 894 if (compare || nap == NULL) 895 error = nfsrv_getattrbits(nd, &retattrbits, 896 &cnt, &retnotsup); 897 else 898 error = nfsrv_getattrbits(nd, &nap->na_suppattr, 899 &cnt, &retnotsup); 900 if (error) 901 goto nfsmout; 902 if (compare && !(*retcmpp)) { 903 NFSSETSUPP_ATTRBIT(&checkattrbits); 904 905 /* Some filesystem do not support NFSv4ACL */ 906 if (nfsrv_useacl == 0 || nfs_supportsnfsv4acls(vp) == 0) { 907 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL); 908 NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT); 909 } 910 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 911 || retnotsup) 912 *retcmpp = NFSERR_NOTSAME; 913 } 914 attrsum += cnt; 915 break; 916 case NFSATTRBIT_TYPE: 917 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 918 if (compare) { 919 if (!(*retcmpp)) { 920 if (nap->na_type != nfsv34tov_type(*tl)) 921 *retcmpp = NFSERR_NOTSAME; 922 } 923 } else if (nap != NULL) { 924 nap->na_type = nfsv34tov_type(*tl); 925 } 926 attrsum += NFSX_UNSIGNED; 927 break; 928 case NFSATTRBIT_FHEXPIRETYPE: 929 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 930 if (compare && !(*retcmpp)) { 931 if (fxdr_unsigned(int, *tl) != 932 NFSV4FHTYPE_PERSISTENT) 933 *retcmpp = NFSERR_NOTSAME; 934 } 935 attrsum += NFSX_UNSIGNED; 936 break; 937 case NFSATTRBIT_CHANGE: 938 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 939 if (compare) { 940 if (!(*retcmpp)) { 941 if (nap->na_filerev != fxdr_hyper(tl)) 942 *retcmpp = NFSERR_NOTSAME; 943 } 944 } else if (nap != NULL) { 945 nap->na_filerev = fxdr_hyper(tl); 946 } 947 attrsum += NFSX_HYPER; 948 break; 949 case NFSATTRBIT_SIZE: 950 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 951 if (compare) { 952 if (!(*retcmpp)) { 953 if (nap->na_size != fxdr_hyper(tl)) 954 *retcmpp = NFSERR_NOTSAME; 955 } 956 } else if (nap != NULL) { 957 nap->na_size = fxdr_hyper(tl); 958 } 959 attrsum += NFSX_HYPER; 960 break; 961 case NFSATTRBIT_LINKSUPPORT: 962 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 963 if (compare) { 964 if (!(*retcmpp)) { 965 if (fsp->fs_properties & NFSV3_FSFLINK) { 966 if (*tl == newnfs_false) 967 *retcmpp = NFSERR_NOTSAME; 968 } else { 969 if (*tl == newnfs_true) 970 *retcmpp = NFSERR_NOTSAME; 971 } 972 } 973 } else if (fsp != NULL) { 974 if (*tl == newnfs_true) 975 fsp->fs_properties |= NFSV3_FSFLINK; 976 else 977 fsp->fs_properties &= ~NFSV3_FSFLINK; 978 } 979 attrsum += NFSX_UNSIGNED; 980 break; 981 case NFSATTRBIT_SYMLINKSUPPORT: 982 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 983 if (compare) { 984 if (!(*retcmpp)) { 985 if (fsp->fs_properties & NFSV3_FSFSYMLINK) { 986 if (*tl == newnfs_false) 987 *retcmpp = NFSERR_NOTSAME; 988 } else { 989 if (*tl == newnfs_true) 990 *retcmpp = NFSERR_NOTSAME; 991 } 992 } 993 } else if (fsp != NULL) { 994 if (*tl == newnfs_true) 995 fsp->fs_properties |= NFSV3_FSFSYMLINK; 996 else 997 fsp->fs_properties &= ~NFSV3_FSFSYMLINK; 998 } 999 attrsum += NFSX_UNSIGNED; 1000 break; 1001 case NFSATTRBIT_NAMEDATTR: 1002 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1003 if (compare && !(*retcmpp)) { 1004 if (*tl != newnfs_false) 1005 *retcmpp = NFSERR_NOTSAME; 1006 } 1007 attrsum += NFSX_UNSIGNED; 1008 break; 1009 case NFSATTRBIT_FSID: 1010 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1011 thyp = fxdr_hyper(tl); 1012 tl += 2; 1013 thyp2 = fxdr_hyper(tl); 1014 if (compare) { 1015 if (*retcmpp == 0) { 1016 if (thyp != (u_int64_t) 1017 vfs_statfs(vnode_mount(vp))->f_fsid.val[0] || 1018 thyp2 != (u_int64_t) 1019 vfs_statfs(vnode_mount(vp))->f_fsid.val[1]) 1020 *retcmpp = NFSERR_NOTSAME; 1021 } 1022 } else if (nap != NULL) { 1023 nap->na_filesid[0] = thyp; 1024 nap->na_filesid[1] = thyp2; 1025 } 1026 attrsum += (4 * NFSX_UNSIGNED); 1027 break; 1028 case NFSATTRBIT_UNIQUEHANDLES: 1029 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1030 if (compare && !(*retcmpp)) { 1031 if (*tl != newnfs_true) 1032 *retcmpp = NFSERR_NOTSAME; 1033 } 1034 attrsum += NFSX_UNSIGNED; 1035 break; 1036 case NFSATTRBIT_LEASETIME: 1037 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1038 if (compare) { 1039 if (fxdr_unsigned(int, *tl) != nfsrv_lease && 1040 !(*retcmpp)) 1041 *retcmpp = NFSERR_NOTSAME; 1042 } else if (leasep != NULL) { 1043 *leasep = fxdr_unsigned(u_int32_t, *tl); 1044 } 1045 attrsum += NFSX_UNSIGNED; 1046 break; 1047 case NFSATTRBIT_RDATTRERROR: 1048 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1049 if (compare) { 1050 if (!(*retcmpp)) 1051 *retcmpp = NFSERR_INVAL; 1052 } else if (rderrp != NULL) { 1053 *rderrp = fxdr_unsigned(u_int32_t, *tl); 1054 } 1055 attrsum += NFSX_UNSIGNED; 1056 break; 1057 case NFSATTRBIT_ACL: 1058 if (compare) { 1059 if (!(*retcmpp)) { 1060 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) { 1061 NFSACL_T *naclp; 1062 1063 naclp = acl_alloc(M_WAITOK); 1064 error = nfsrv_dissectacl(nd, naclp, &aceerr, 1065 &cnt, p); 1066 if (error) { 1067 acl_free(naclp); 1068 goto nfsmout; 1069 } 1070 if (aceerr || aclp == NULL || 1071 nfsrv_compareacl(aclp, naclp)) 1072 *retcmpp = NFSERR_NOTSAME; 1073 acl_free(naclp); 1074 } else { 1075 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1076 &cnt, p); 1077 *retcmpp = NFSERR_ATTRNOTSUPP; 1078 } 1079 } 1080 } else { 1081 if (vp != NULL && aclp != NULL) 1082 error = nfsrv_dissectacl(nd, aclp, &aceerr, 1083 &cnt, p); 1084 else 1085 error = nfsrv_dissectacl(nd, NULL, &aceerr, 1086 &cnt, p); 1087 if (error) 1088 goto nfsmout; 1089 } 1090 1091 attrsum += cnt; 1092 break; 1093 case NFSATTRBIT_ACLSUPPORT: 1094 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1095 if (compare && !(*retcmpp)) { 1096 if (nfsrv_useacl && nfs_supportsnfsv4acls(vp)) { 1097 if (fxdr_unsigned(u_int32_t, *tl) != 1098 NFSV4ACE_SUPTYPES) 1099 *retcmpp = NFSERR_NOTSAME; 1100 } else { 1101 *retcmpp = NFSERR_ATTRNOTSUPP; 1102 } 1103 } 1104 attrsum += NFSX_UNSIGNED; 1105 break; 1106 case NFSATTRBIT_ARCHIVE: 1107 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1108 if (compare && !(*retcmpp)) 1109 *retcmpp = NFSERR_ATTRNOTSUPP; 1110 attrsum += NFSX_UNSIGNED; 1111 break; 1112 case NFSATTRBIT_CANSETTIME: 1113 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1114 if (compare) { 1115 if (!(*retcmpp)) { 1116 if (fsp->fs_properties & NFSV3_FSFCANSETTIME) { 1117 if (*tl == newnfs_false) 1118 *retcmpp = NFSERR_NOTSAME; 1119 } else { 1120 if (*tl == newnfs_true) 1121 *retcmpp = NFSERR_NOTSAME; 1122 } 1123 } 1124 } else if (fsp != NULL) { 1125 if (*tl == newnfs_true) 1126 fsp->fs_properties |= NFSV3_FSFCANSETTIME; 1127 else 1128 fsp->fs_properties &= ~NFSV3_FSFCANSETTIME; 1129 } 1130 attrsum += NFSX_UNSIGNED; 1131 break; 1132 case NFSATTRBIT_CASEINSENSITIVE: 1133 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1134 if (compare) { 1135 if (!(*retcmpp)) { 1136 if (*tl != newnfs_false) 1137 *retcmpp = NFSERR_NOTSAME; 1138 } 1139 } else if (pc != NULL) { 1140 pc->pc_caseinsensitive = 1141 fxdr_unsigned(u_int32_t, *tl); 1142 } 1143 attrsum += NFSX_UNSIGNED; 1144 break; 1145 case NFSATTRBIT_CASEPRESERVING: 1146 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1147 if (compare) { 1148 if (!(*retcmpp)) { 1149 if (*tl != newnfs_true) 1150 *retcmpp = NFSERR_NOTSAME; 1151 } 1152 } else if (pc != NULL) { 1153 pc->pc_casepreserving = 1154 fxdr_unsigned(u_int32_t, *tl); 1155 } 1156 attrsum += NFSX_UNSIGNED; 1157 break; 1158 case NFSATTRBIT_CHOWNRESTRICTED: 1159 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1160 if (compare) { 1161 if (!(*retcmpp)) { 1162 if (*tl != newnfs_true) 1163 *retcmpp = NFSERR_NOTSAME; 1164 } 1165 } else if (pc != NULL) { 1166 pc->pc_chownrestricted = 1167 fxdr_unsigned(u_int32_t, *tl); 1168 } 1169 attrsum += NFSX_UNSIGNED; 1170 break; 1171 case NFSATTRBIT_FILEHANDLE: 1172 error = nfsm_getfh(nd, &tnfhp); 1173 if (error) 1174 goto nfsmout; 1175 tfhsize = tnfhp->nfh_len; 1176 if (compare) { 1177 if (!(*retcmpp) && 1178 !NFSRV_CMPFH(tnfhp->nfh_fh, tfhsize, 1179 fhp, fhsize)) 1180 *retcmpp = NFSERR_NOTSAME; 1181 FREE((caddr_t)tnfhp, M_NFSFH); 1182 } else if (nfhpp != NULL) { 1183 *nfhpp = tnfhp; 1184 } else { 1185 FREE((caddr_t)tnfhp, M_NFSFH); 1186 } 1187 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(tfhsize)); 1188 break; 1189 case NFSATTRBIT_FILEID: 1190 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1191 thyp = fxdr_hyper(tl); 1192 if (compare) { 1193 if (!(*retcmpp)) { 1194 if ((u_int64_t)nap->na_fileid != thyp) 1195 *retcmpp = NFSERR_NOTSAME; 1196 } 1197 } else if (nap != NULL) { 1198 if (*tl++) 1199 printf("NFSv4 fileid > 32bits\n"); 1200 nap->na_fileid = thyp; 1201 } 1202 attrsum += NFSX_HYPER; 1203 break; 1204 case NFSATTRBIT_FILESAVAIL: 1205 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1206 if (compare) { 1207 if (!(*retcmpp) && 1208 sfp->sf_afiles != fxdr_hyper(tl)) 1209 *retcmpp = NFSERR_NOTSAME; 1210 } else if (sfp != NULL) { 1211 sfp->sf_afiles = fxdr_hyper(tl); 1212 } 1213 attrsum += NFSX_HYPER; 1214 break; 1215 case NFSATTRBIT_FILESFREE: 1216 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1217 if (compare) { 1218 if (!(*retcmpp) && 1219 sfp->sf_ffiles != fxdr_hyper(tl)) 1220 *retcmpp = NFSERR_NOTSAME; 1221 } else if (sfp != NULL) { 1222 sfp->sf_ffiles = fxdr_hyper(tl); 1223 } 1224 attrsum += NFSX_HYPER; 1225 break; 1226 case NFSATTRBIT_FILESTOTAL: 1227 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1228 if (compare) { 1229 if (!(*retcmpp) && 1230 sfp->sf_tfiles != fxdr_hyper(tl)) 1231 *retcmpp = NFSERR_NOTSAME; 1232 } else if (sfp != NULL) { 1233 sfp->sf_tfiles = fxdr_hyper(tl); 1234 } 1235 attrsum += NFSX_HYPER; 1236 break; 1237 case NFSATTRBIT_FSLOCATIONS: 1238 error = nfsrv_getrefstr(nd, &cp, &cp2, &l, &m); 1239 if (error) 1240 goto nfsmout; 1241 attrsum += l; 1242 if (compare && !(*retcmpp)) { 1243 refp = nfsv4root_getreferral(vp, NULL, 0); 1244 if (refp != NULL) { 1245 if (cp == NULL || cp2 == NULL || 1246 strcmp(cp, "/") || 1247 strcmp(cp2, refp->nfr_srvlist)) 1248 *retcmpp = NFSERR_NOTSAME; 1249 } else if (m == 0) { 1250 *retcmpp = NFSERR_NOTSAME; 1251 } 1252 } 1253 if (cp != NULL) 1254 free(cp, M_NFSSTRING); 1255 if (cp2 != NULL) 1256 free(cp2, M_NFSSTRING); 1257 break; 1258 case NFSATTRBIT_HIDDEN: 1259 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1260 if (compare && !(*retcmpp)) 1261 *retcmpp = NFSERR_ATTRNOTSUPP; 1262 attrsum += NFSX_UNSIGNED; 1263 break; 1264 case NFSATTRBIT_HOMOGENEOUS: 1265 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1266 if (compare) { 1267 if (!(*retcmpp)) { 1268 if (fsp->fs_properties & 1269 NFSV3_FSFHOMOGENEOUS) { 1270 if (*tl == newnfs_false) 1271 *retcmpp = NFSERR_NOTSAME; 1272 } else { 1273 if (*tl == newnfs_true) 1274 *retcmpp = NFSERR_NOTSAME; 1275 } 1276 } 1277 } else if (fsp != NULL) { 1278 if (*tl == newnfs_true) 1279 fsp->fs_properties |= NFSV3_FSFHOMOGENEOUS; 1280 else 1281 fsp->fs_properties &= ~NFSV3_FSFHOMOGENEOUS; 1282 } 1283 attrsum += NFSX_UNSIGNED; 1284 break; 1285 case NFSATTRBIT_MAXFILESIZE: 1286 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1287 tnfsquad.qval = fxdr_hyper(tl); 1288 if (compare) { 1289 if (!(*retcmpp)) { 1290 tquad = NFSRV_MAXFILESIZE; 1291 if (tquad != tnfsquad.qval) 1292 *retcmpp = NFSERR_NOTSAME; 1293 } 1294 } else if (fsp != NULL) { 1295 fsp->fs_maxfilesize = tnfsquad.qval; 1296 } 1297 attrsum += NFSX_HYPER; 1298 break; 1299 case NFSATTRBIT_MAXLINK: 1300 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1301 if (compare) { 1302 if (!(*retcmpp)) { 1303 if (fxdr_unsigned(int, *tl) != LINK_MAX) 1304 *retcmpp = NFSERR_NOTSAME; 1305 } 1306 } else if (pc != NULL) { 1307 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl); 1308 } 1309 attrsum += NFSX_UNSIGNED; 1310 break; 1311 case NFSATTRBIT_MAXNAME: 1312 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1313 if (compare) { 1314 if (!(*retcmpp)) { 1315 if (fsp->fs_maxname != 1316 fxdr_unsigned(u_int32_t, *tl)) 1317 *retcmpp = NFSERR_NOTSAME; 1318 } 1319 } else { 1320 tuint = fxdr_unsigned(u_int32_t, *tl); 1321 /* 1322 * Some Linux NFSv4 servers report this 1323 * as 0 or 4billion, so I'll set it to 1324 * NFS_MAXNAMLEN. If a server actually creates 1325 * a name longer than NFS_MAXNAMLEN, it will 1326 * get an error back. 1327 */ 1328 if (tuint == 0 || tuint > NFS_MAXNAMLEN) 1329 tuint = NFS_MAXNAMLEN; 1330 if (fsp != NULL) 1331 fsp->fs_maxname = tuint; 1332 if (pc != NULL) 1333 pc->pc_namemax = tuint; 1334 } 1335 attrsum += NFSX_UNSIGNED; 1336 break; 1337 case NFSATTRBIT_MAXREAD: 1338 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1339 if (compare) { 1340 if (!(*retcmpp)) { 1341 if (fsp->fs_rtmax != fxdr_unsigned(u_int32_t, 1342 *(tl + 1)) || *tl != 0) 1343 *retcmpp = NFSERR_NOTSAME; 1344 } 1345 } else if (fsp != NULL) { 1346 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *++tl); 1347 fsp->fs_rtpref = fsp->fs_rtmax; 1348 fsp->fs_dtpref = fsp->fs_rtpref; 1349 } 1350 attrsum += NFSX_HYPER; 1351 break; 1352 case NFSATTRBIT_MAXWRITE: 1353 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1354 if (compare) { 1355 if (!(*retcmpp)) { 1356 if (fsp->fs_wtmax != fxdr_unsigned(u_int32_t, 1357 *(tl + 1)) || *tl != 0) 1358 *retcmpp = NFSERR_NOTSAME; 1359 } 1360 } else if (fsp != NULL) { 1361 fsp->fs_wtmax = fxdr_unsigned(int, *++tl); 1362 fsp->fs_wtpref = fsp->fs_wtmax; 1363 } 1364 attrsum += NFSX_HYPER; 1365 break; 1366 case NFSATTRBIT_MIMETYPE: 1367 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1368 i = fxdr_unsigned(int, *tl); 1369 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(i)); 1370 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 1371 if (error) 1372 goto nfsmout; 1373 if (compare && !(*retcmpp)) 1374 *retcmpp = NFSERR_ATTRNOTSUPP; 1375 break; 1376 case NFSATTRBIT_MODE: 1377 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1378 if (compare) { 1379 if (!(*retcmpp)) { 1380 if (nap->na_mode != nfstov_mode(*tl)) 1381 *retcmpp = NFSERR_NOTSAME; 1382 } 1383 } else if (nap != NULL) { 1384 nap->na_mode = nfstov_mode(*tl); 1385 } 1386 attrsum += NFSX_UNSIGNED; 1387 break; 1388 case NFSATTRBIT_NOTRUNC: 1389 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1390 if (compare) { 1391 if (!(*retcmpp)) { 1392 if (*tl != newnfs_true) 1393 *retcmpp = NFSERR_NOTSAME; 1394 } 1395 } else if (pc != NULL) { 1396 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl); 1397 } 1398 attrsum += NFSX_UNSIGNED; 1399 break; 1400 case NFSATTRBIT_NUMLINKS: 1401 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1402 tuint = fxdr_unsigned(u_int32_t, *tl); 1403 if (compare) { 1404 if (!(*retcmpp)) { 1405 if ((u_int32_t)nap->na_nlink != tuint) 1406 *retcmpp = NFSERR_NOTSAME; 1407 } 1408 } else if (nap != NULL) { 1409 nap->na_nlink = tuint; 1410 } 1411 attrsum += NFSX_UNSIGNED; 1412 break; 1413 case NFSATTRBIT_OWNER: 1414 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1415 j = fxdr_unsigned(int, *tl); 1416 if (j < 0) { 1417 error = NFSERR_BADXDR; 1418 goto nfsmout; 1419 } 1420 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1421 if (j > NFSV4_SMALLSTR) 1422 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1423 else 1424 cp = namestr; 1425 error = nfsrv_mtostr(nd, cp, j); 1426 if (error) { 1427 if (j > NFSV4_SMALLSTR) 1428 free(cp, M_NFSSTRING); 1429 goto nfsmout; 1430 } 1431 if (compare) { 1432 if (!(*retcmpp)) { 1433 if (nfsv4_strtouid(nd, cp, j, &uid, p) || 1434 nap->na_uid != uid) 1435 *retcmpp = NFSERR_NOTSAME; 1436 } 1437 } else if (nap != NULL) { 1438 if (nfsv4_strtouid(nd, cp, j, &uid, p)) 1439 nap->na_uid = nfsrv_defaultuid; 1440 else 1441 nap->na_uid = uid; 1442 } 1443 if (j > NFSV4_SMALLSTR) 1444 free(cp, M_NFSSTRING); 1445 break; 1446 case NFSATTRBIT_OWNERGROUP: 1447 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1448 j = fxdr_unsigned(int, *tl); 1449 if (j < 0) { 1450 error = NFSERR_BADXDR; 1451 goto nfsmout; 1452 } 1453 attrsum += (NFSX_UNSIGNED + NFSM_RNDUP(j)); 1454 if (j > NFSV4_SMALLSTR) 1455 cp = malloc(j + 1, M_NFSSTRING, M_WAITOK); 1456 else 1457 cp = namestr; 1458 error = nfsrv_mtostr(nd, cp, j); 1459 if (error) { 1460 if (j > NFSV4_SMALLSTR) 1461 free(cp, M_NFSSTRING); 1462 goto nfsmout; 1463 } 1464 if (compare) { 1465 if (!(*retcmpp)) { 1466 if (nfsv4_strtogid(nd, cp, j, &gid, p) || 1467 nap->na_gid != gid) 1468 *retcmpp = NFSERR_NOTSAME; 1469 } 1470 } else if (nap != NULL) { 1471 if (nfsv4_strtogid(nd, cp, j, &gid, p)) 1472 nap->na_gid = nfsrv_defaultgid; 1473 else 1474 nap->na_gid = gid; 1475 } 1476 if (j > NFSV4_SMALLSTR) 1477 free(cp, M_NFSSTRING); 1478 break; 1479 case NFSATTRBIT_QUOTAHARD: 1480 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1481 if (sbp != NULL) { 1482 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1483 freenum = sbp->f_bfree; 1484 else 1485 freenum = sbp->f_bavail; 1486 #ifdef QUOTA 1487 /* 1488 * ufs_quotactl() insists that the uid argument 1489 * equal p_ruid for non-root quota access, so 1490 * we'll just make sure that's the case. 1491 */ 1492 savuid = p->p_cred->p_ruid; 1493 p->p_cred->p_ruid = cred->cr_uid; 1494 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1495 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1496 freenum = min(dqb.dqb_bhardlimit, freenum); 1497 p->p_cred->p_ruid = savuid; 1498 #endif /* QUOTA */ 1499 uquad = (u_int64_t)freenum; 1500 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1501 } 1502 if (compare && !(*retcmpp)) { 1503 if (uquad != fxdr_hyper(tl)) 1504 *retcmpp = NFSERR_NOTSAME; 1505 } 1506 attrsum += NFSX_HYPER; 1507 break; 1508 case NFSATTRBIT_QUOTASOFT: 1509 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1510 if (sbp != NULL) { 1511 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 1512 freenum = sbp->f_bfree; 1513 else 1514 freenum = sbp->f_bavail; 1515 #ifdef QUOTA 1516 /* 1517 * ufs_quotactl() insists that the uid argument 1518 * equal p_ruid for non-root quota access, so 1519 * we'll just make sure that's the case. 1520 */ 1521 savuid = p->p_cred->p_ruid; 1522 p->p_cred->p_ruid = cred->cr_uid; 1523 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1524 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1525 freenum = min(dqb.dqb_bsoftlimit, freenum); 1526 p->p_cred->p_ruid = savuid; 1527 #endif /* QUOTA */ 1528 uquad = (u_int64_t)freenum; 1529 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1530 } 1531 if (compare && !(*retcmpp)) { 1532 if (uquad != fxdr_hyper(tl)) 1533 *retcmpp = NFSERR_NOTSAME; 1534 } 1535 attrsum += NFSX_HYPER; 1536 break; 1537 case NFSATTRBIT_QUOTAUSED: 1538 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1539 if (sbp != NULL) { 1540 freenum = 0; 1541 #ifdef QUOTA 1542 /* 1543 * ufs_quotactl() insists that the uid argument 1544 * equal p_ruid for non-root quota access, so 1545 * we'll just make sure that's the case. 1546 */ 1547 savuid = p->p_cred->p_ruid; 1548 p->p_cred->p_ruid = cred->cr_uid; 1549 if (!VFS_QUOTACTL(vnode_mount(vp),QCMD(Q_GETQUOTA, 1550 USRQUOTA), cred->cr_uid, (caddr_t)&dqb)) 1551 freenum = dqb.dqb_curblocks; 1552 p->p_cred->p_ruid = savuid; 1553 #endif /* QUOTA */ 1554 uquad = (u_int64_t)freenum; 1555 NFSQUOTABLKTOBYTE(uquad, sbp->f_bsize); 1556 } 1557 if (compare && !(*retcmpp)) { 1558 if (uquad != fxdr_hyper(tl)) 1559 *retcmpp = NFSERR_NOTSAME; 1560 } 1561 attrsum += NFSX_HYPER; 1562 break; 1563 case NFSATTRBIT_RAWDEV: 1564 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4SPECDATA); 1565 j = fxdr_unsigned(int, *tl++); 1566 k = fxdr_unsigned(int, *tl); 1567 if (compare) { 1568 if (!(*retcmpp)) { 1569 if (nap->na_rdev != NFSMAKEDEV(j, k)) 1570 *retcmpp = NFSERR_NOTSAME; 1571 } 1572 } else if (nap != NULL) { 1573 nap->na_rdev = NFSMAKEDEV(j, k); 1574 } 1575 attrsum += NFSX_V4SPECDATA; 1576 break; 1577 case NFSATTRBIT_SPACEAVAIL: 1578 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1579 if (compare) { 1580 if (!(*retcmpp) && 1581 sfp->sf_abytes != fxdr_hyper(tl)) 1582 *retcmpp = NFSERR_NOTSAME; 1583 } else if (sfp != NULL) { 1584 sfp->sf_abytes = fxdr_hyper(tl); 1585 } 1586 attrsum += NFSX_HYPER; 1587 break; 1588 case NFSATTRBIT_SPACEFREE: 1589 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1590 if (compare) { 1591 if (!(*retcmpp) && 1592 sfp->sf_fbytes != fxdr_hyper(tl)) 1593 *retcmpp = NFSERR_NOTSAME; 1594 } else if (sfp != NULL) { 1595 sfp->sf_fbytes = fxdr_hyper(tl); 1596 } 1597 attrsum += NFSX_HYPER; 1598 break; 1599 case NFSATTRBIT_SPACETOTAL: 1600 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1601 if (compare) { 1602 if (!(*retcmpp) && 1603 sfp->sf_tbytes != fxdr_hyper(tl)) 1604 *retcmpp = NFSERR_NOTSAME; 1605 } else if (sfp != NULL) { 1606 sfp->sf_tbytes = fxdr_hyper(tl); 1607 } 1608 attrsum += NFSX_HYPER; 1609 break; 1610 case NFSATTRBIT_SPACEUSED: 1611 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1612 thyp = fxdr_hyper(tl); 1613 if (compare) { 1614 if (!(*retcmpp)) { 1615 if ((u_int64_t)nap->na_bytes != thyp) 1616 *retcmpp = NFSERR_NOTSAME; 1617 } 1618 } else if (nap != NULL) { 1619 nap->na_bytes = thyp; 1620 } 1621 attrsum += NFSX_HYPER; 1622 break; 1623 case NFSATTRBIT_SYSTEM: 1624 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1625 if (compare && !(*retcmpp)) 1626 *retcmpp = NFSERR_ATTRNOTSUPP; 1627 attrsum += NFSX_UNSIGNED; 1628 break; 1629 case NFSATTRBIT_TIMEACCESS: 1630 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1631 fxdr_nfsv4time(tl, &temptime); 1632 if (compare) { 1633 if (!(*retcmpp)) { 1634 if (!NFS_CMPTIME(temptime, nap->na_atime)) 1635 *retcmpp = NFSERR_NOTSAME; 1636 } 1637 } else if (nap != NULL) { 1638 nap->na_atime = temptime; 1639 } 1640 attrsum += NFSX_V4TIME; 1641 break; 1642 case NFSATTRBIT_TIMEACCESSSET: 1643 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1644 attrsum += NFSX_UNSIGNED; 1645 i = fxdr_unsigned(int, *tl); 1646 if (i == NFSV4SATTRTIME_TOCLIENT) { 1647 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1648 attrsum += NFSX_V4TIME; 1649 } 1650 if (compare && !(*retcmpp)) 1651 *retcmpp = NFSERR_INVAL; 1652 break; 1653 case NFSATTRBIT_TIMEBACKUP: 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_TIMECREATE: 1660 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1661 if (compare && !(*retcmpp)) 1662 *retcmpp = NFSERR_ATTRNOTSUPP; 1663 attrsum += NFSX_V4TIME; 1664 break; 1665 case NFSATTRBIT_TIMEDELTA: 1666 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1667 if (fsp != NULL) { 1668 if (compare) { 1669 if (!(*retcmpp)) { 1670 if ((u_int32_t)fsp->fs_timedelta.tv_sec != 1671 fxdr_unsigned(u_int32_t, *(tl + 1)) || 1672 (u_int32_t)fsp->fs_timedelta.tv_nsec != 1673 (fxdr_unsigned(u_int32_t, *(tl + 2)) % 1674 1000000000) || 1675 *tl != 0) 1676 *retcmpp = NFSERR_NOTSAME; 1677 } 1678 } else { 1679 fxdr_nfsv4time(tl, &fsp->fs_timedelta); 1680 } 1681 } 1682 attrsum += NFSX_V4TIME; 1683 break; 1684 case NFSATTRBIT_TIMEMETADATA: 1685 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1686 fxdr_nfsv4time(tl, &temptime); 1687 if (compare) { 1688 if (!(*retcmpp)) { 1689 if (!NFS_CMPTIME(temptime, nap->na_ctime)) 1690 *retcmpp = NFSERR_NOTSAME; 1691 } 1692 } else if (nap != NULL) { 1693 nap->na_ctime = temptime; 1694 } 1695 attrsum += NFSX_V4TIME; 1696 break; 1697 case NFSATTRBIT_TIMEMODIFY: 1698 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1699 fxdr_nfsv4time(tl, &temptime); 1700 if (compare) { 1701 if (!(*retcmpp)) { 1702 if (!NFS_CMPTIME(temptime, nap->na_mtime)) 1703 *retcmpp = NFSERR_NOTSAME; 1704 } 1705 } else if (nap != NULL) { 1706 nap->na_mtime = temptime; 1707 } 1708 attrsum += NFSX_V4TIME; 1709 break; 1710 case NFSATTRBIT_TIMEMODIFYSET: 1711 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1712 attrsum += NFSX_UNSIGNED; 1713 i = fxdr_unsigned(int, *tl); 1714 if (i == NFSV4SATTRTIME_TOCLIENT) { 1715 NFSM_DISSECT(tl, u_int32_t *, NFSX_V4TIME); 1716 attrsum += NFSX_V4TIME; 1717 } 1718 if (compare && !(*retcmpp)) 1719 *retcmpp = NFSERR_INVAL; 1720 break; 1721 case NFSATTRBIT_MOUNTEDONFILEID: 1722 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 1723 thyp = fxdr_hyper(tl); 1724 if (compare) { 1725 if (!(*retcmpp)) { 1726 if (*tl++) { 1727 *retcmpp = NFSERR_NOTSAME; 1728 } else { 1729 if (!vp || !nfsrv_atroot(vp, &fid)) 1730 fid = nap->na_fileid; 1731 if ((u_int64_t)fid != thyp) 1732 *retcmpp = NFSERR_NOTSAME; 1733 } 1734 } 1735 } else if (nap != NULL) { 1736 if (*tl++) 1737 printf("NFSv4 mounted on fileid > 32bits\n"); 1738 nap->na_mntonfileno = thyp; 1739 } 1740 attrsum += NFSX_HYPER; 1741 break; 1742 case NFSATTRBIT_SUPPATTREXCLCREAT: 1743 retnotsup = 0; 1744 error = nfsrv_getattrbits(nd, &retattrbits, 1745 &cnt, &retnotsup); 1746 if (error) 1747 goto nfsmout; 1748 if (compare && !(*retcmpp)) { 1749 NFSSETSUPP_ATTRBIT(&checkattrbits); 1750 NFSCLRNOTSETABLE_ATTRBIT(&checkattrbits); 1751 NFSCLRBIT_ATTRBIT(&checkattrbits, 1752 NFSATTRBIT_TIMEACCESSSET); 1753 if (!NFSEQUAL_ATTRBIT(&retattrbits, &checkattrbits) 1754 || retnotsup) 1755 *retcmpp = NFSERR_NOTSAME; 1756 } 1757 attrsum += cnt; 1758 break; 1759 default: 1760 printf("EEK! nfsv4_loadattr unknown attr=%d\n", 1761 bitpos); 1762 if (compare && !(*retcmpp)) 1763 *retcmpp = NFSERR_ATTRNOTSUPP; 1764 /* 1765 * and get out of the loop, since we can't parse 1766 * the unknown attrbute data. 1767 */ 1768 bitpos = NFSATTRBIT_MAX; 1769 break; 1770 }; 1771 } 1772 1773 /* 1774 * some clients pad the attrlist, so we need to skip over the 1775 * padding. 1776 */ 1777 if (attrsum > attrsize) { 1778 error = NFSERR_BADXDR; 1779 } else { 1780 attrsize = NFSM_RNDUP(attrsize); 1781 if (attrsum < attrsize) 1782 error = nfsm_advance(nd, attrsize - attrsum, -1); 1783 } 1784 nfsmout: 1785 NFSEXITCODE2(error, nd); 1786 return (error); 1787 } 1788 1789 /* 1790 * Implement sleep locks for newnfs. The nfslock_usecnt allows for a 1791 * shared lock and the NFSXXX_LOCK flag permits an exclusive lock. 1792 * The first argument is a pointer to an nfsv4lock structure. 1793 * The second argument is 1 iff a blocking lock is wanted. 1794 * If this argument is 0, the call waits until no thread either wants nor 1795 * holds an exclusive lock. 1796 * It returns 1 if the lock was acquired, 0 otherwise. 1797 * If several processes call this function concurrently wanting the exclusive 1798 * lock, one will get the lock and the rest will return without getting the 1799 * lock. (If the caller must have the lock, it simply calls this function in a 1800 * loop until the function returns 1 to indicate the lock was acquired.) 1801 * Any usecnt must be decremented by calling nfsv4_relref() before 1802 * calling nfsv4_lock(). It was done this way, so nfsv4_lock() could 1803 * be called in a loop. 1804 * The isleptp argument is set to indicate if the call slept, iff not NULL 1805 * and the mp argument indicates to check for a forced dismount, iff not 1806 * NULL. 1807 */ 1808 APPLESTATIC int 1809 nfsv4_lock(struct nfsv4lock *lp, int iwantlock, int *isleptp, 1810 void *mutex, struct mount *mp) 1811 { 1812 1813 if (isleptp) 1814 *isleptp = 0; 1815 /* 1816 * If a lock is wanted, loop around until the lock is acquired by 1817 * someone and then released. If I want the lock, try to acquire it. 1818 * For a lock to be issued, no lock must be in force and the usecnt 1819 * must be zero. 1820 */ 1821 if (iwantlock) { 1822 if (!(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1823 lp->nfslock_usecnt == 0) { 1824 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1825 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1826 return (1); 1827 } 1828 lp->nfslock_lock |= NFSV4LOCK_LOCKWANTED; 1829 } 1830 while (lp->nfslock_lock & (NFSV4LOCK_LOCK | NFSV4LOCK_LOCKWANTED)) { 1831 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) { 1832 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1833 return (0); 1834 } 1835 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1836 if (isleptp) 1837 *isleptp = 1; 1838 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1839 PZERO - 1, "nfsv4lck", NULL); 1840 if (iwantlock && !(lp->nfslock_lock & NFSV4LOCK_LOCK) && 1841 lp->nfslock_usecnt == 0) { 1842 lp->nfslock_lock &= ~NFSV4LOCK_LOCKWANTED; 1843 lp->nfslock_lock |= NFSV4LOCK_LOCK; 1844 return (1); 1845 } 1846 } 1847 return (0); 1848 } 1849 1850 /* 1851 * Release the lock acquired by nfsv4_lock(). 1852 * The second argument is set to 1 to indicate the nfslock_usecnt should be 1853 * incremented, as well. 1854 */ 1855 APPLESTATIC void 1856 nfsv4_unlock(struct nfsv4lock *lp, int incref) 1857 { 1858 1859 lp->nfslock_lock &= ~NFSV4LOCK_LOCK; 1860 if (incref) 1861 lp->nfslock_usecnt++; 1862 nfsv4_wanted(lp); 1863 } 1864 1865 /* 1866 * Release a reference cnt. 1867 */ 1868 APPLESTATIC void 1869 nfsv4_relref(struct nfsv4lock *lp) 1870 { 1871 1872 if (lp->nfslock_usecnt <= 0) 1873 panic("nfsv4root ref cnt"); 1874 lp->nfslock_usecnt--; 1875 if (lp->nfslock_usecnt == 0) 1876 nfsv4_wanted(lp); 1877 } 1878 1879 /* 1880 * Get a reference cnt. 1881 * This function will wait for any exclusive lock to be released, but will 1882 * not wait for threads that want the exclusive lock. If priority needs 1883 * to be given to threads that need the exclusive lock, a call to nfsv4_lock() 1884 * with the 2nd argument == 0 should be done before calling nfsv4_getref(). 1885 * If the mp argument is not NULL, check for MNTK_UNMOUNTF being set and 1886 * return without getting a refcnt for that case. 1887 */ 1888 APPLESTATIC void 1889 nfsv4_getref(struct nfsv4lock *lp, int *isleptp, void *mutex, 1890 struct mount *mp) 1891 { 1892 1893 if (isleptp) 1894 *isleptp = 0; 1895 1896 /* 1897 * Wait for a lock held. 1898 */ 1899 while (lp->nfslock_lock & NFSV4LOCK_LOCK) { 1900 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1901 return; 1902 lp->nfslock_lock |= NFSV4LOCK_WANTED; 1903 if (isleptp) 1904 *isleptp = 1; 1905 (void) nfsmsleep(&lp->nfslock_lock, mutex, 1906 PZERO - 1, "nfsv4gr", NULL); 1907 } 1908 if (mp != NULL && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) 1909 return; 1910 1911 lp->nfslock_usecnt++; 1912 } 1913 1914 /* 1915 * Get a reference as above, but return failure instead of sleeping if 1916 * an exclusive lock is held. 1917 */ 1918 APPLESTATIC int 1919 nfsv4_getref_nonblock(struct nfsv4lock *lp) 1920 { 1921 1922 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) != 0) 1923 return (0); 1924 1925 lp->nfslock_usecnt++; 1926 return (1); 1927 } 1928 1929 /* 1930 * Test for a lock. Return 1 if locked, 0 otherwise. 1931 */ 1932 APPLESTATIC int 1933 nfsv4_testlock(struct nfsv4lock *lp) 1934 { 1935 1936 if ((lp->nfslock_lock & NFSV4LOCK_LOCK) == 0 && 1937 lp->nfslock_usecnt == 0) 1938 return (0); 1939 return (1); 1940 } 1941 1942 /* 1943 * Wake up anyone sleeping, waiting for this lock. 1944 */ 1945 static void 1946 nfsv4_wanted(struct nfsv4lock *lp) 1947 { 1948 1949 if (lp->nfslock_lock & NFSV4LOCK_WANTED) { 1950 lp->nfslock_lock &= ~NFSV4LOCK_WANTED; 1951 wakeup((caddr_t)&lp->nfslock_lock); 1952 } 1953 } 1954 1955 /* 1956 * Copy a string from an mbuf list into a character array. 1957 * Return EBADRPC if there is an mbuf error, 1958 * 0 otherwise. 1959 */ 1960 APPLESTATIC int 1961 nfsrv_mtostr(struct nfsrv_descript *nd, char *str, int siz) 1962 { 1963 char *cp; 1964 int xfer, len; 1965 mbuf_t mp; 1966 int rem, error = 0; 1967 1968 mp = nd->nd_md; 1969 cp = nd->nd_dpos; 1970 len = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - cp; 1971 rem = NFSM_RNDUP(siz) - siz; 1972 while (siz > 0) { 1973 if (len > siz) 1974 xfer = siz; 1975 else 1976 xfer = len; 1977 NFSBCOPY(cp, str, xfer); 1978 str += xfer; 1979 siz -= xfer; 1980 if (siz > 0) { 1981 mp = mbuf_next(mp); 1982 if (mp == NULL) { 1983 error = EBADRPC; 1984 goto out; 1985 } 1986 cp = NFSMTOD(mp, caddr_t); 1987 len = mbuf_len(mp); 1988 } else { 1989 cp += xfer; 1990 len -= xfer; 1991 } 1992 } 1993 *str = '\0'; 1994 nd->nd_dpos = cp; 1995 nd->nd_md = mp; 1996 if (rem > 0) { 1997 if (len < rem) 1998 error = nfsm_advance(nd, rem, len); 1999 else 2000 nd->nd_dpos += rem; 2001 } 2002 2003 out: 2004 NFSEXITCODE2(error, nd); 2005 return (error); 2006 } 2007 2008 /* 2009 * Fill in the attributes as marked by the bitmap (V4). 2010 */ 2011 APPLESTATIC int 2012 nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, 2013 NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror, 2014 nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram, 2015 int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno) 2016 { 2017 int bitpos, retnum = 0; 2018 u_int32_t *tl; 2019 int siz, prefixnum, error; 2020 u_char *cp, namestr[NFSV4_SMALLSTR]; 2021 nfsattrbit_t attrbits, retbits; 2022 nfsattrbit_t *retbitp = &retbits; 2023 u_int32_t freenum, *retnump; 2024 u_int64_t uquad; 2025 struct statfs fs; 2026 struct nfsfsinfo fsinf; 2027 struct timespec temptime; 2028 NFSACL_T *aclp, *naclp = NULL; 2029 #ifdef QUOTA 2030 struct dqblk dqb; 2031 uid_t savuid; 2032 #endif 2033 2034 /* 2035 * First, set the bits that can be filled and get fsinfo. 2036 */ 2037 NFSSET_ATTRBIT(retbitp, attrbitp); 2038 /* 2039 * If both p and cred are NULL, it is a client side setattr call. 2040 * If both p and cred are not NULL, it is a server side reply call. 2041 * If p is not NULL and cred is NULL, it is a client side callback 2042 * reply call. 2043 */ 2044 if (p == NULL && cred == NULL) { 2045 NFSCLRNOTSETABLE_ATTRBIT(retbitp); 2046 aclp = saclp; 2047 } else { 2048 NFSCLRNOTFILLABLE_ATTRBIT(retbitp); 2049 naclp = acl_alloc(M_WAITOK); 2050 aclp = naclp; 2051 } 2052 nfsvno_getfs(&fsinf, isdgram); 2053 #ifndef APPLE 2054 /* 2055 * Get the VFS_STATFS(), since some attributes need them. 2056 */ 2057 if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 2058 error = VFS_STATFS(mp, &fs); 2059 if (error != 0) { 2060 if (reterr) { 2061 nd->nd_repstat = NFSERR_ACCES; 2062 return (0); 2063 } 2064 NFSCLRSTATFS_ATTRBIT(retbitp); 2065 } 2066 } 2067 #endif 2068 2069 /* 2070 * And the NFSv4 ACL... 2071 */ 2072 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 2073 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2074 supports_nfsv4acls == 0))) { 2075 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 2076 } 2077 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 2078 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2079 supports_nfsv4acls == 0)) { 2080 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2081 } else if (naclp != NULL) { 2082 if (NFSVOPLOCK(vp, LK_SHARED) == 0) { 2083 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); 2084 if (error == 0) 2085 error = VOP_GETACL(vp, ACL_TYPE_NFS4, 2086 naclp, cred, p); 2087 NFSVOPUNLOCK(vp, 0); 2088 } else 2089 error = NFSERR_PERM; 2090 if (error != 0) { 2091 if (reterr) { 2092 nd->nd_repstat = NFSERR_ACCES; 2093 return (0); 2094 } 2095 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2096 } 2097 } 2098 } 2099 2100 /* 2101 * Put out the attribute bitmap for the ones being filled in 2102 * and get the field for the number of attributes returned. 2103 */ 2104 prefixnum = nfsrv_putattrbit(nd, retbitp); 2105 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 2106 prefixnum += NFSX_UNSIGNED; 2107 2108 /* 2109 * Now, loop around filling in the attributes for each bit set. 2110 */ 2111 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 2112 if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 2113 switch (bitpos) { 2114 case NFSATTRBIT_SUPPORTEDATTRS: 2115 NFSSETSUPP_ATTRBIT(&attrbits); 2116 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 2117 && supports_nfsv4acls == 0)) { 2118 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 2119 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 2120 } 2121 retnum += nfsrv_putattrbit(nd, &attrbits); 2122 break; 2123 case NFSATTRBIT_TYPE: 2124 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2125 *tl = vtonfsv34_type(vap->va_type); 2126 retnum += NFSX_UNSIGNED; 2127 break; 2128 case NFSATTRBIT_FHEXPIRETYPE: 2129 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2130 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2131 retnum += NFSX_UNSIGNED; 2132 break; 2133 case NFSATTRBIT_CHANGE: 2134 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2135 txdr_hyper(vap->va_filerev, tl); 2136 retnum += NFSX_HYPER; 2137 break; 2138 case NFSATTRBIT_SIZE: 2139 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2140 txdr_hyper(vap->va_size, tl); 2141 retnum += NFSX_HYPER; 2142 break; 2143 case NFSATTRBIT_LINKSUPPORT: 2144 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2145 if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2146 *tl = newnfs_true; 2147 else 2148 *tl = newnfs_false; 2149 retnum += NFSX_UNSIGNED; 2150 break; 2151 case NFSATTRBIT_SYMLINKSUPPORT: 2152 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2153 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2154 *tl = newnfs_true; 2155 else 2156 *tl = newnfs_false; 2157 retnum += NFSX_UNSIGNED; 2158 break; 2159 case NFSATTRBIT_NAMEDATTR: 2160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2161 *tl = newnfs_false; 2162 retnum += NFSX_UNSIGNED; 2163 break; 2164 case NFSATTRBIT_FSID: 2165 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2166 *tl++ = 0; 2167 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]); 2168 *tl++ = 0; 2169 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]); 2170 retnum += NFSX_V4FSID; 2171 break; 2172 case NFSATTRBIT_UNIQUEHANDLES: 2173 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2174 *tl = newnfs_true; 2175 retnum += NFSX_UNSIGNED; 2176 break; 2177 case NFSATTRBIT_LEASETIME: 2178 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2179 *tl = txdr_unsigned(nfsrv_lease); 2180 retnum += NFSX_UNSIGNED; 2181 break; 2182 case NFSATTRBIT_RDATTRERROR: 2183 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2184 *tl = txdr_unsigned(rderror); 2185 retnum += NFSX_UNSIGNED; 2186 break; 2187 /* 2188 * Recommended Attributes. (Only the supported ones.) 2189 */ 2190 case NFSATTRBIT_ACL: 2191 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2192 break; 2193 case NFSATTRBIT_ACLSUPPORT: 2194 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2195 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2196 retnum += NFSX_UNSIGNED; 2197 break; 2198 case NFSATTRBIT_CANSETTIME: 2199 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2200 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2201 *tl = newnfs_true; 2202 else 2203 *tl = newnfs_false; 2204 retnum += NFSX_UNSIGNED; 2205 break; 2206 case NFSATTRBIT_CASEINSENSITIVE: 2207 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2208 *tl = newnfs_false; 2209 retnum += NFSX_UNSIGNED; 2210 break; 2211 case NFSATTRBIT_CASEPRESERVING: 2212 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2213 *tl = newnfs_true; 2214 retnum += NFSX_UNSIGNED; 2215 break; 2216 case NFSATTRBIT_CHOWNRESTRICTED: 2217 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2218 *tl = newnfs_true; 2219 retnum += NFSX_UNSIGNED; 2220 break; 2221 case NFSATTRBIT_FILEHANDLE: 2222 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2223 break; 2224 case NFSATTRBIT_FILEID: 2225 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2226 *tl++ = 0; 2227 *tl = txdr_unsigned(vap->va_fileid); 2228 retnum += NFSX_HYPER; 2229 break; 2230 case NFSATTRBIT_FILESAVAIL: 2231 /* 2232 * Check quota and use min(quota, f_ffree). 2233 */ 2234 freenum = fs.f_ffree; 2235 #ifdef QUOTA 2236 /* 2237 * ufs_quotactl() insists that the uid argument 2238 * equal p_ruid for non-root quota access, so 2239 * we'll just make sure that's the case. 2240 */ 2241 savuid = p->p_cred->p_ruid; 2242 p->p_cred->p_ruid = cred->cr_uid; 2243 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2244 cred->cr_uid, (caddr_t)&dqb)) 2245 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2246 freenum); 2247 p->p_cred->p_ruid = savuid; 2248 #endif /* QUOTA */ 2249 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2250 *tl++ = 0; 2251 *tl = txdr_unsigned(freenum); 2252 retnum += NFSX_HYPER; 2253 break; 2254 case NFSATTRBIT_FILESFREE: 2255 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2256 *tl++ = 0; 2257 *tl = txdr_unsigned(fs.f_ffree); 2258 retnum += NFSX_HYPER; 2259 break; 2260 case NFSATTRBIT_FILESTOTAL: 2261 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2262 *tl++ = 0; 2263 *tl = txdr_unsigned(fs.f_files); 2264 retnum += NFSX_HYPER; 2265 break; 2266 case NFSATTRBIT_FSLOCATIONS: 2267 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2268 *tl++ = 0; 2269 *tl = 0; 2270 retnum += 2 * NFSX_UNSIGNED; 2271 break; 2272 case NFSATTRBIT_HOMOGENEOUS: 2273 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2274 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2275 *tl = newnfs_true; 2276 else 2277 *tl = newnfs_false; 2278 retnum += NFSX_UNSIGNED; 2279 break; 2280 case NFSATTRBIT_MAXFILESIZE: 2281 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2282 uquad = NFSRV_MAXFILESIZE; 2283 txdr_hyper(uquad, tl); 2284 retnum += NFSX_HYPER; 2285 break; 2286 case NFSATTRBIT_MAXLINK: 2287 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2288 *tl = txdr_unsigned(LINK_MAX); 2289 retnum += NFSX_UNSIGNED; 2290 break; 2291 case NFSATTRBIT_MAXNAME: 2292 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2293 *tl = txdr_unsigned(NFS_MAXNAMLEN); 2294 retnum += NFSX_UNSIGNED; 2295 break; 2296 case NFSATTRBIT_MAXREAD: 2297 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2298 *tl++ = 0; 2299 *tl = txdr_unsigned(fsinf.fs_rtmax); 2300 retnum += NFSX_HYPER; 2301 break; 2302 case NFSATTRBIT_MAXWRITE: 2303 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2304 *tl++ = 0; 2305 *tl = txdr_unsigned(fsinf.fs_wtmax); 2306 retnum += NFSX_HYPER; 2307 break; 2308 case NFSATTRBIT_MODE: 2309 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2310 *tl = vtonfsv34_mode(vap->va_mode); 2311 retnum += NFSX_UNSIGNED; 2312 break; 2313 case NFSATTRBIT_NOTRUNC: 2314 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2315 *tl = newnfs_true; 2316 retnum += NFSX_UNSIGNED; 2317 break; 2318 case NFSATTRBIT_NUMLINKS: 2319 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2320 *tl = txdr_unsigned(vap->va_nlink); 2321 retnum += NFSX_UNSIGNED; 2322 break; 2323 case NFSATTRBIT_OWNER: 2324 cp = namestr; 2325 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); 2326 retnum += nfsm_strtom(nd, cp, siz); 2327 if (cp != namestr) 2328 free(cp, M_NFSSTRING); 2329 break; 2330 case NFSATTRBIT_OWNERGROUP: 2331 cp = namestr; 2332 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); 2333 retnum += nfsm_strtom(nd, cp, siz); 2334 if (cp != namestr) 2335 free(cp, M_NFSSTRING); 2336 break; 2337 case NFSATTRBIT_QUOTAHARD: 2338 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2339 freenum = fs.f_bfree; 2340 else 2341 freenum = fs.f_bavail; 2342 #ifdef QUOTA 2343 /* 2344 * ufs_quotactl() insists that the uid argument 2345 * equal p_ruid for non-root quota access, so 2346 * we'll just make sure that's the case. 2347 */ 2348 savuid = p->p_cred->p_ruid; 2349 p->p_cred->p_ruid = cred->cr_uid; 2350 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2351 cred->cr_uid, (caddr_t)&dqb)) 2352 freenum = min(dqb.dqb_bhardlimit, freenum); 2353 p->p_cred->p_ruid = savuid; 2354 #endif /* QUOTA */ 2355 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2356 uquad = (u_int64_t)freenum; 2357 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2358 txdr_hyper(uquad, tl); 2359 retnum += NFSX_HYPER; 2360 break; 2361 case NFSATTRBIT_QUOTASOFT: 2362 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2363 freenum = fs.f_bfree; 2364 else 2365 freenum = fs.f_bavail; 2366 #ifdef QUOTA 2367 /* 2368 * ufs_quotactl() insists that the uid argument 2369 * equal p_ruid for non-root quota access, so 2370 * we'll just make sure that's the case. 2371 */ 2372 savuid = p->p_cred->p_ruid; 2373 p->p_cred->p_ruid = cred->cr_uid; 2374 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2375 cred->cr_uid, (caddr_t)&dqb)) 2376 freenum = min(dqb.dqb_bsoftlimit, freenum); 2377 p->p_cred->p_ruid = savuid; 2378 #endif /* QUOTA */ 2379 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2380 uquad = (u_int64_t)freenum; 2381 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2382 txdr_hyper(uquad, tl); 2383 retnum += NFSX_HYPER; 2384 break; 2385 case NFSATTRBIT_QUOTAUSED: 2386 freenum = 0; 2387 #ifdef QUOTA 2388 /* 2389 * ufs_quotactl() insists that the uid argument 2390 * equal p_ruid for non-root quota access, so 2391 * we'll just make sure that's the case. 2392 */ 2393 savuid = p->p_cred->p_ruid; 2394 p->p_cred->p_ruid = cred->cr_uid; 2395 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2396 cred->cr_uid, (caddr_t)&dqb)) 2397 freenum = dqb.dqb_curblocks; 2398 p->p_cred->p_ruid = savuid; 2399 #endif /* QUOTA */ 2400 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2401 uquad = (u_int64_t)freenum; 2402 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2403 txdr_hyper(uquad, tl); 2404 retnum += NFSX_HYPER; 2405 break; 2406 case NFSATTRBIT_RAWDEV: 2407 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2408 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2409 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2410 retnum += NFSX_V4SPECDATA; 2411 break; 2412 case NFSATTRBIT_SPACEAVAIL: 2413 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2414 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) 2415 uquad = (u_int64_t)fs.f_bfree; 2416 else 2417 uquad = (u_int64_t)fs.f_bavail; 2418 uquad *= fs.f_bsize; 2419 txdr_hyper(uquad, tl); 2420 retnum += NFSX_HYPER; 2421 break; 2422 case NFSATTRBIT_SPACEFREE: 2423 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2424 uquad = (u_int64_t)fs.f_bfree; 2425 uquad *= fs.f_bsize; 2426 txdr_hyper(uquad, tl); 2427 retnum += NFSX_HYPER; 2428 break; 2429 case NFSATTRBIT_SPACETOTAL: 2430 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2431 uquad = (u_int64_t)fs.f_blocks; 2432 uquad *= fs.f_bsize; 2433 txdr_hyper(uquad, tl); 2434 retnum += NFSX_HYPER; 2435 break; 2436 case NFSATTRBIT_SPACEUSED: 2437 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2438 txdr_hyper(vap->va_bytes, tl); 2439 retnum += NFSX_HYPER; 2440 break; 2441 case NFSATTRBIT_TIMEACCESS: 2442 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2443 txdr_nfsv4time(&vap->va_atime, tl); 2444 retnum += NFSX_V4TIME; 2445 break; 2446 case NFSATTRBIT_TIMEACCESSSET: 2447 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2448 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2449 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2450 txdr_nfsv4time(&vap->va_atime, tl); 2451 retnum += NFSX_V4SETTIME; 2452 } else { 2453 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2454 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2455 retnum += NFSX_UNSIGNED; 2456 } 2457 break; 2458 case NFSATTRBIT_TIMEDELTA: 2459 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2460 temptime.tv_sec = 0; 2461 temptime.tv_nsec = 1000000000 / hz; 2462 txdr_nfsv4time(&temptime, tl); 2463 retnum += NFSX_V4TIME; 2464 break; 2465 case NFSATTRBIT_TIMEMETADATA: 2466 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2467 txdr_nfsv4time(&vap->va_ctime, tl); 2468 retnum += NFSX_V4TIME; 2469 break; 2470 case NFSATTRBIT_TIMEMODIFY: 2471 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2472 txdr_nfsv4time(&vap->va_mtime, tl); 2473 retnum += NFSX_V4TIME; 2474 break; 2475 case NFSATTRBIT_TIMEMODIFYSET: 2476 if ((vap->va_vaflags & VA_UTIMES_NULL) == 0) { 2477 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2478 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2479 txdr_nfsv4time(&vap->va_mtime, tl); 2480 retnum += NFSX_V4SETTIME; 2481 } else { 2482 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2483 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2484 retnum += NFSX_UNSIGNED; 2485 } 2486 break; 2487 case NFSATTRBIT_MOUNTEDONFILEID: 2488 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2489 if (at_root != 0) 2490 uquad = mounted_on_fileno; 2491 else 2492 uquad = (u_int64_t)vap->va_fileid; 2493 txdr_hyper(uquad, tl); 2494 retnum += NFSX_HYPER; 2495 break; 2496 case NFSATTRBIT_SUPPATTREXCLCREAT: 2497 NFSSETSUPP_ATTRBIT(&attrbits); 2498 NFSCLRNOTSETABLE_ATTRBIT(&attrbits); 2499 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET); 2500 retnum += nfsrv_putattrbit(nd, &attrbits); 2501 break; 2502 default: 2503 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2504 }; 2505 } 2506 } 2507 if (naclp != NULL) 2508 acl_free(naclp); 2509 *retnump = txdr_unsigned(retnum); 2510 return (retnum + prefixnum); 2511 } 2512 2513 /* 2514 * Put the attribute bits onto an mbuf list. 2515 * Return the number of bytes of output generated. 2516 */ 2517 APPLESTATIC int 2518 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 2519 { 2520 u_int32_t *tl; 2521 int cnt, i, bytesize; 2522 2523 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 2524 if (attrbitp->bits[cnt - 1]) 2525 break; 2526 bytesize = (cnt + 1) * NFSX_UNSIGNED; 2527 NFSM_BUILD(tl, u_int32_t *, bytesize); 2528 *tl++ = txdr_unsigned(cnt); 2529 for (i = 0; i < cnt; i++) 2530 *tl++ = txdr_unsigned(attrbitp->bits[i]); 2531 return (bytesize); 2532 } 2533 2534 /* 2535 * Convert a uid to a string. 2536 * If the lookup fails, just output the digits. 2537 * uid - the user id 2538 * cpp - points to a buffer of size NFSV4_SMALLSTR 2539 * (malloc a larger one, as required) 2540 * retlenp - pointer to length to be returned 2541 */ 2542 APPLESTATIC void 2543 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2544 { 2545 int i; 2546 struct nfsusrgrp *usrp; 2547 u_char *cp = *cpp; 2548 uid_t tmp; 2549 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2550 2551 cnt = 0; 2552 tryagain: 2553 NFSLOCKNAMEID(); 2554 if (nfsrv_dnsname) { 2555 /* 2556 * Always map nfsrv_defaultuid to "nobody". 2557 */ 2558 if (uid == nfsrv_defaultuid) { 2559 i = nfsrv_dnsnamelen + 7; 2560 if (i > len) { 2561 NFSUNLOCKNAMEID(); 2562 if (len > NFSV4_SMALLSTR) 2563 free(cp, M_NFSSTRING); 2564 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2565 *cpp = cp; 2566 len = i; 2567 goto tryagain; 2568 } 2569 *retlenp = i; 2570 NFSBCOPY("nobody@", cp, 7); 2571 cp += 7; 2572 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2573 NFSUNLOCKNAMEID(); 2574 return; 2575 } 2576 hasampersand = 0; 2577 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) { 2578 if (usrp->lug_uid == uid) { 2579 if (usrp->lug_expiry < NFSD_MONOSEC) 2580 break; 2581 /* 2582 * If the name doesn't already have an '@' 2583 * in it, append @domainname to it. 2584 */ 2585 for (i = 0; i < usrp->lug_namelen; i++) { 2586 if (usrp->lug_name[i] == '@') { 2587 hasampersand = 1; 2588 break; 2589 } 2590 } 2591 if (hasampersand) 2592 i = usrp->lug_namelen; 2593 else 2594 i = usrp->lug_namelen + 2595 nfsrv_dnsnamelen + 1; 2596 if (i > len) { 2597 NFSUNLOCKNAMEID(); 2598 if (len > NFSV4_SMALLSTR) 2599 free(cp, M_NFSSTRING); 2600 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2601 *cpp = cp; 2602 len = i; 2603 goto tryagain; 2604 } 2605 *retlenp = i; 2606 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2607 if (!hasampersand) { 2608 cp += usrp->lug_namelen; 2609 *cp++ = '@'; 2610 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2611 } 2612 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2613 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2614 NFSUNLOCKNAMEID(); 2615 return; 2616 } 2617 } 2618 NFSUNLOCKNAMEID(); 2619 cnt++; 2620 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2621 NULL, p); 2622 if (ret == 0 && cnt < 2) 2623 goto tryagain; 2624 } else { 2625 NFSUNLOCKNAMEID(); 2626 } 2627 2628 /* 2629 * No match, just return a string of digits. 2630 */ 2631 tmp = uid; 2632 i = 0; 2633 while (tmp || i == 0) { 2634 tmp /= 10; 2635 i++; 2636 } 2637 len = (i > len) ? len : i; 2638 *retlenp = len; 2639 cp += (len - 1); 2640 tmp = uid; 2641 for (i = 0; i < len; i++) { 2642 *cp-- = '0' + (tmp % 10); 2643 tmp /= 10; 2644 } 2645 return; 2646 } 2647 2648 /* 2649 * Convert a string to a uid. 2650 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2651 * return 0. 2652 * If this is called from a client side mount using AUTH_SYS and the 2653 * string is made up entirely of digits, just convert the string to 2654 * a number. 2655 */ 2656 APPLESTATIC int 2657 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp, 2658 NFSPROC_T *p) 2659 { 2660 int i; 2661 char *cp, *endstr, *str0; 2662 struct nfsusrgrp *usrp; 2663 int cnt, ret; 2664 int error = 0; 2665 uid_t tuid; 2666 2667 if (len == 0) { 2668 error = NFSERR_BADOWNER; 2669 goto out; 2670 } 2671 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2672 str0 = str; 2673 tuid = (uid_t)strtoul(str0, &endstr, 10); 2674 if ((endstr - str0) == len) { 2675 /* A numeric string. */ 2676 if ((nd->nd_flag & ND_KERBV) == 0 && 2677 ((nd->nd_flag & ND_NFSCL) != 0 || 2678 nfsd_enable_stringtouid != 0)) 2679 *uidp = tuid; 2680 else 2681 error = NFSERR_BADOWNER; 2682 goto out; 2683 } 2684 /* 2685 * Look for an '@'. 2686 */ 2687 cp = strchr(str0, '@'); 2688 if (cp != NULL) 2689 i = (int)(cp++ - str0); 2690 else 2691 i = len; 2692 2693 cnt = 0; 2694 tryagain: 2695 NFSLOCKNAMEID(); 2696 /* 2697 * If an '@' is found and the domain name matches, search for the name 2698 * with dns stripped off. 2699 * Mixed case alpahbetics will match for the domain name, but all 2700 * upper case will not. 2701 */ 2702 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2703 (len - 1 - i) == nfsrv_dnsnamelen && 2704 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2705 len -= (nfsrv_dnsnamelen + 1); 2706 *(cp - 1) = '\0'; 2707 } 2708 2709 /* 2710 * Check for the special case of "nobody". 2711 */ 2712 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 2713 *uidp = nfsrv_defaultuid; 2714 NFSUNLOCKNAMEID(); 2715 error = 0; 2716 goto out; 2717 } 2718 2719 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) { 2720 if (usrp->lug_namelen == len && 2721 !NFSBCMP(usrp->lug_name, str, len)) { 2722 if (usrp->lug_expiry < NFSD_MONOSEC) 2723 break; 2724 *uidp = usrp->lug_uid; 2725 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2726 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2727 NFSUNLOCKNAMEID(); 2728 error = 0; 2729 goto out; 2730 } 2731 } 2732 NFSUNLOCKNAMEID(); 2733 cnt++; 2734 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 2735 str, p); 2736 if (ret == 0 && cnt < 2) 2737 goto tryagain; 2738 error = NFSERR_BADOWNER; 2739 2740 out: 2741 NFSEXITCODE(error); 2742 return (error); 2743 } 2744 2745 /* 2746 * Convert a gid to a string. 2747 * gid - the group id 2748 * cpp - points to a buffer of size NFSV4_SMALLSTR 2749 * (malloc a larger one, as required) 2750 * retlenp - pointer to length to be returned 2751 */ 2752 APPLESTATIC void 2753 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2754 { 2755 int i; 2756 struct nfsusrgrp *usrp; 2757 u_char *cp = *cpp; 2758 gid_t tmp; 2759 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2760 2761 cnt = 0; 2762 tryagain: 2763 NFSLOCKNAMEID(); 2764 if (nfsrv_dnsname) { 2765 /* 2766 * Always map nfsrv_defaultgid to "nogroup". 2767 */ 2768 if (gid == nfsrv_defaultgid) { 2769 i = nfsrv_dnsnamelen + 8; 2770 if (i > len) { 2771 NFSUNLOCKNAMEID(); 2772 if (len > NFSV4_SMALLSTR) 2773 free(cp, M_NFSSTRING); 2774 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2775 *cpp = cp; 2776 len = i; 2777 goto tryagain; 2778 } 2779 *retlenp = i; 2780 NFSBCOPY("nogroup@", cp, 8); 2781 cp += 8; 2782 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2783 NFSUNLOCKNAMEID(); 2784 return; 2785 } 2786 hasampersand = 0; 2787 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) { 2788 if (usrp->lug_gid == gid) { 2789 if (usrp->lug_expiry < NFSD_MONOSEC) 2790 break; 2791 /* 2792 * If the name doesn't already have an '@' 2793 * in it, append @domainname to it. 2794 */ 2795 for (i = 0; i < usrp->lug_namelen; i++) { 2796 if (usrp->lug_name[i] == '@') { 2797 hasampersand = 1; 2798 break; 2799 } 2800 } 2801 if (hasampersand) 2802 i = usrp->lug_namelen; 2803 else 2804 i = usrp->lug_namelen + 2805 nfsrv_dnsnamelen + 1; 2806 if (i > len) { 2807 NFSUNLOCKNAMEID(); 2808 if (len > NFSV4_SMALLSTR) 2809 free(cp, M_NFSSTRING); 2810 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2811 *cpp = cp; 2812 len = i; 2813 goto tryagain; 2814 } 2815 *retlenp = i; 2816 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2817 if (!hasampersand) { 2818 cp += usrp->lug_namelen; 2819 *cp++ = '@'; 2820 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2821 } 2822 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2823 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2824 NFSUNLOCKNAMEID(); 2825 return; 2826 } 2827 } 2828 NFSUNLOCKNAMEID(); 2829 cnt++; 2830 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, 2831 NULL, p); 2832 if (ret == 0 && cnt < 2) 2833 goto tryagain; 2834 } else { 2835 NFSUNLOCKNAMEID(); 2836 } 2837 2838 /* 2839 * No match, just return a string of digits. 2840 */ 2841 tmp = gid; 2842 i = 0; 2843 while (tmp || i == 0) { 2844 tmp /= 10; 2845 i++; 2846 } 2847 len = (i > len) ? len : i; 2848 *retlenp = len; 2849 cp += (len - 1); 2850 tmp = gid; 2851 for (i = 0; i < len; i++) { 2852 *cp-- = '0' + (tmp % 10); 2853 tmp /= 10; 2854 } 2855 return; 2856 } 2857 2858 /* 2859 * Convert a string to a gid. 2860 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2861 * return 0. 2862 * If this is called from a client side mount using AUTH_SYS and the 2863 * string is made up entirely of digits, just convert the string to 2864 * a number. 2865 */ 2866 APPLESTATIC int 2867 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp, 2868 NFSPROC_T *p) 2869 { 2870 int i; 2871 char *cp, *endstr, *str0; 2872 struct nfsusrgrp *usrp; 2873 int cnt, ret; 2874 int error = 0; 2875 gid_t tgid; 2876 2877 if (len == 0) { 2878 error = NFSERR_BADOWNER; 2879 goto out; 2880 } 2881 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2882 str0 = str; 2883 tgid = (gid_t)strtoul(str0, &endstr, 10); 2884 if ((endstr - str0) == len) { 2885 /* A numeric string. */ 2886 if ((nd->nd_flag & ND_KERBV) == 0 && 2887 ((nd->nd_flag & ND_NFSCL) != 0 || 2888 nfsd_enable_stringtouid != 0)) 2889 *gidp = tgid; 2890 else 2891 error = NFSERR_BADOWNER; 2892 goto out; 2893 } 2894 /* 2895 * Look for an '@'. 2896 */ 2897 cp = strchr(str0, '@'); 2898 if (cp != NULL) 2899 i = (int)(cp++ - str0); 2900 else 2901 i = len; 2902 2903 cnt = 0; 2904 tryagain: 2905 NFSLOCKNAMEID(); 2906 /* 2907 * If an '@' is found and the dns name matches, search for the name 2908 * with the dns stripped off. 2909 */ 2910 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2911 (len - 1 - i) == nfsrv_dnsnamelen && 2912 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2913 len -= (nfsrv_dnsnamelen + 1); 2914 *(cp - 1) = '\0'; 2915 } 2916 2917 /* 2918 * Check for the special case of "nogroup". 2919 */ 2920 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 2921 *gidp = nfsrv_defaultgid; 2922 NFSUNLOCKNAMEID(); 2923 error = 0; 2924 goto out; 2925 } 2926 2927 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) { 2928 if (usrp->lug_namelen == len && 2929 !NFSBCMP(usrp->lug_name, str, len)) { 2930 if (usrp->lug_expiry < NFSD_MONOSEC) 2931 break; 2932 *gidp = usrp->lug_gid; 2933 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2934 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2935 NFSUNLOCKNAMEID(); 2936 error = 0; 2937 goto out; 2938 } 2939 } 2940 NFSUNLOCKNAMEID(); 2941 cnt++; 2942 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 2943 str, p); 2944 if (ret == 0 && cnt < 2) 2945 goto tryagain; 2946 error = NFSERR_BADOWNER; 2947 2948 out: 2949 NFSEXITCODE(error); 2950 return (error); 2951 } 2952 2953 /* 2954 * Cmp len chars, allowing mixed case in the first argument to match lower 2955 * case in the second, but not if the first argument is all upper case. 2956 * Return 0 for a match, 1 otherwise. 2957 */ 2958 static int 2959 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 2960 { 2961 int i; 2962 u_char tmp; 2963 int fndlower = 0; 2964 2965 for (i = 0; i < len; i++) { 2966 if (*cp >= 'A' && *cp <= 'Z') { 2967 tmp = *cp++ + ('a' - 'A'); 2968 } else { 2969 tmp = *cp++; 2970 if (tmp >= 'a' && tmp <= 'z') 2971 fndlower = 1; 2972 } 2973 if (tmp != *cp2++) 2974 return (1); 2975 } 2976 if (fndlower) 2977 return (0); 2978 else 2979 return (1); 2980 } 2981 2982 /* 2983 * Set the port for the nfsuserd. 2984 */ 2985 APPLESTATIC int 2986 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p) 2987 { 2988 struct nfssockreq *rp; 2989 struct sockaddr_in *ad; 2990 int error; 2991 2992 NFSLOCKNAMEID(); 2993 if (nfsrv_nfsuserd) { 2994 NFSUNLOCKNAMEID(); 2995 error = EPERM; 2996 goto out; 2997 } 2998 nfsrv_nfsuserd = 1; 2999 NFSUNLOCKNAMEID(); 3000 /* 3001 * Set up the socket record and connect. 3002 */ 3003 rp = &nfsrv_nfsuserdsock; 3004 rp->nr_client = NULL; 3005 rp->nr_sotype = SOCK_DGRAM; 3006 rp->nr_soproto = IPPROTO_UDP; 3007 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 3008 rp->nr_cred = NULL; 3009 NFSSOCKADDRALLOC(rp->nr_nam); 3010 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in)); 3011 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *); 3012 ad->sin_family = AF_INET; 3013 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */ 3014 ad->sin_port = port; 3015 rp->nr_prog = RPCPROG_NFSUSERD; 3016 rp->nr_vers = RPCNFSUSERD_VERS; 3017 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 3018 if (error) { 3019 NFSSOCKADDRFREE(rp->nr_nam); 3020 nfsrv_nfsuserd = 0; 3021 } 3022 out: 3023 NFSEXITCODE(error); 3024 return (error); 3025 } 3026 3027 /* 3028 * Delete the nfsuserd port. 3029 */ 3030 APPLESTATIC void 3031 nfsrv_nfsuserddelport(void) 3032 { 3033 3034 NFSLOCKNAMEID(); 3035 if (nfsrv_nfsuserd == 0) { 3036 NFSUNLOCKNAMEID(); 3037 return; 3038 } 3039 nfsrv_nfsuserd = 0; 3040 NFSUNLOCKNAMEID(); 3041 newnfs_disconnect(&nfsrv_nfsuserdsock); 3042 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); 3043 } 3044 3045 /* 3046 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 3047 * name<-->id cache. 3048 * Returns 0 upon success, non-zero otherwise. 3049 */ 3050 static int 3051 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) 3052 { 3053 u_int32_t *tl; 3054 struct nfsrv_descript *nd; 3055 int len; 3056 struct nfsrv_descript nfsd; 3057 struct ucred *cred; 3058 int error; 3059 3060 NFSLOCKNAMEID(); 3061 if (nfsrv_nfsuserd == 0) { 3062 NFSUNLOCKNAMEID(); 3063 error = EPERM; 3064 goto out; 3065 } 3066 NFSUNLOCKNAMEID(); 3067 nd = &nfsd; 3068 cred = newnfs_getcred(); 3069 nd->nd_flag = ND_GSSINITREPLY; 3070 nfsrvd_rephead(nd); 3071 3072 nd->nd_procnum = procnum; 3073 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3074 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3075 if (procnum == RPCNFSUSERD_GETUID) 3076 *tl = txdr_unsigned(uid); 3077 else 3078 *tl = txdr_unsigned(gid); 3079 } else { 3080 len = strlen(name); 3081 (void) nfsm_strtom(nd, name, len); 3082 } 3083 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 3084 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL); 3085 NFSFREECRED(cred); 3086 if (!error) { 3087 mbuf_freem(nd->nd_mrep); 3088 error = nd->nd_repstat; 3089 } 3090 out: 3091 NFSEXITCODE(error); 3092 return (error); 3093 } 3094 3095 /* 3096 * This function is called from the nfssvc(2) system call, to update the 3097 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3098 */ 3099 APPLESTATIC int 3100 nfssvc_idname(struct nfsd_idargs *nidp) 3101 { 3102 struct nfsusrgrp *nusrp, *usrp, *newusrp; 3103 struct nfsuserhashhead *hp; 3104 int i; 3105 int error = 0; 3106 u_char *cp; 3107 3108 if (nidp->nid_flag & NFSID_INITIALIZE) { 3109 cp = (u_char *)malloc(nidp->nid_namelen + 1, 3110 M_NFSSTRING, M_WAITOK); 3111 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 3112 nidp->nid_namelen); 3113 NFSLOCKNAMEID(); 3114 if (nfsrv_dnsname) { 3115 /* 3116 * Free up all the old stuff and reinitialize hash lists. 3117 */ 3118 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 3119 nfsrv_removeuser(usrp); 3120 } 3121 free(nfsrv_dnsname, M_NFSSTRING); 3122 nfsrv_dnsname = NULL; 3123 } 3124 TAILQ_INIT(&nfsuserlruhead); 3125 for (i = 0; i < NFSUSERHASHSIZE; i++) 3126 LIST_INIT(&nfsuserhash[i]); 3127 for (i = 0; i < NFSGROUPHASHSIZE; i++) 3128 LIST_INIT(&nfsgrouphash[i]); 3129 for (i = 0; i < NFSUSERHASHSIZE; i++) 3130 LIST_INIT(&nfsusernamehash[i]); 3131 for (i = 0; i < NFSGROUPHASHSIZE; i++) 3132 LIST_INIT(&nfsgroupnamehash[i]); 3133 3134 /* 3135 * Put name in "DNS" string. 3136 */ 3137 if (!error) { 3138 nfsrv_dnsname = cp; 3139 nfsrv_dnsnamelen = nidp->nid_namelen; 3140 nfsrv_defaultuid = nidp->nid_uid; 3141 nfsrv_defaultgid = nidp->nid_gid; 3142 nfsrv_usercnt = 0; 3143 nfsrv_usermax = nidp->nid_usermax; 3144 } 3145 NFSUNLOCKNAMEID(); 3146 if (error) 3147 free(cp, M_NFSSTRING); 3148 goto out; 3149 } 3150 3151 /* 3152 * malloc the new one now, so any potential sleep occurs before 3153 * manipulation of the lists. 3154 */ 3155 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) + 3156 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK); 3157 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 3158 nidp->nid_namelen); 3159 if (error) { 3160 free((caddr_t)newusrp, M_NFSUSERGROUP); 3161 goto out; 3162 } 3163 newusrp->lug_namelen = nidp->nid_namelen; 3164 3165 NFSLOCKNAMEID(); 3166 /* 3167 * Delete old entries, as required. 3168 */ 3169 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3170 hp = NFSUSERHASH(nidp->nid_uid); 3171 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 3172 if (usrp->lug_uid == nidp->nid_uid) 3173 nfsrv_removeuser(usrp); 3174 } 3175 } 3176 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3177 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3178 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 3179 if (usrp->lug_namelen == newusrp->lug_namelen && 3180 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3181 usrp->lug_namelen)) 3182 nfsrv_removeuser(usrp); 3183 } 3184 } 3185 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3186 hp = NFSGROUPHASH(nidp->nid_gid); 3187 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 3188 if (usrp->lug_gid == nidp->nid_gid) 3189 nfsrv_removeuser(usrp); 3190 } 3191 } 3192 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3193 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3194 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 3195 if (usrp->lug_namelen == newusrp->lug_namelen && 3196 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3197 usrp->lug_namelen)) 3198 nfsrv_removeuser(usrp); 3199 } 3200 } 3201 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 3202 if (usrp->lug_expiry < NFSD_MONOSEC) 3203 nfsrv_removeuser(usrp); 3204 } 3205 while (nfsrv_usercnt >= nfsrv_usermax) { 3206 usrp = TAILQ_FIRST(&nfsuserlruhead); 3207 nfsrv_removeuser(usrp); 3208 } 3209 3210 /* 3211 * Now, we can add the new one. 3212 */ 3213 if (nidp->nid_usertimeout) 3214 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3215 else 3216 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3217 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3218 newusrp->lug_uid = nidp->nid_uid; 3219 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp, 3220 lug_numhash); 3221 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name, 3222 newusrp->lug_namelen), newusrp, lug_namehash); 3223 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3224 nfsrv_usercnt++; 3225 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3226 newusrp->lug_gid = nidp->nid_gid; 3227 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp, 3228 lug_numhash); 3229 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name, 3230 newusrp->lug_namelen), newusrp, lug_namehash); 3231 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3232 nfsrv_usercnt++; 3233 } else 3234 FREE((caddr_t)newusrp, M_NFSUSERGROUP); 3235 NFSUNLOCKNAMEID(); 3236 out: 3237 NFSEXITCODE(error); 3238 return (error); 3239 } 3240 3241 /* 3242 * Remove a user/group name element. 3243 */ 3244 static void 3245 nfsrv_removeuser(struct nfsusrgrp *usrp) 3246 { 3247 3248 NFSNAMEIDREQUIRED(); 3249 LIST_REMOVE(usrp, lug_numhash); 3250 LIST_REMOVE(usrp, lug_namehash); 3251 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 3252 nfsrv_usercnt--; 3253 FREE((caddr_t)usrp, M_NFSUSERGROUP); 3254 } 3255 3256 /* 3257 * This function scans a byte string and checks for UTF-8 compliance. 3258 * It returns 0 if it conforms and NFSERR_INVAL if not. 3259 */ 3260 APPLESTATIC int 3261 nfsrv_checkutf8(u_int8_t *cp, int len) 3262 { 3263 u_int32_t val = 0x0; 3264 int cnt = 0, gotd = 0, shift = 0; 3265 u_int8_t byte; 3266 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 3267 int error = 0; 3268 3269 /* 3270 * Here are what the variables are used for: 3271 * val - the calculated value of a multibyte char, used to check 3272 * that it was coded with the correct range 3273 * cnt - the number of 10xxxxxx bytes to follow 3274 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 3275 * shift - lower order bits of range (ie. "val >> shift" should 3276 * not be 0, in other words, dividing by the lower bound 3277 * of the range should get a non-zero value) 3278 * byte - used to calculate cnt 3279 */ 3280 while (len > 0) { 3281 if (cnt > 0) { 3282 /* This handles the 10xxxxxx bytes */ 3283 if ((*cp & 0xc0) != 0x80 || 3284 (gotd && (*cp & 0x20))) { 3285 error = NFSERR_INVAL; 3286 goto out; 3287 } 3288 gotd = 0; 3289 val <<= 6; 3290 val |= (*cp & 0x3f); 3291 cnt--; 3292 if (cnt == 0 && (val >> shift) == 0x0) { 3293 error = NFSERR_INVAL; 3294 goto out; 3295 } 3296 } else if (*cp & 0x80) { 3297 /* first byte of multi byte char */ 3298 byte = *cp; 3299 while ((byte & 0x40) && cnt < 6) { 3300 cnt++; 3301 byte <<= 1; 3302 } 3303 if (cnt == 0 || cnt == 6) { 3304 error = NFSERR_INVAL; 3305 goto out; 3306 } 3307 val = (*cp & (0x3f >> cnt)); 3308 shift = utf8_shift[cnt - 1]; 3309 if (cnt == 2 && val == 0xd) 3310 /* Check for the 0xd800-0xdfff case */ 3311 gotd = 1; 3312 } 3313 cp++; 3314 len--; 3315 } 3316 if (cnt > 0) 3317 error = NFSERR_INVAL; 3318 3319 out: 3320 NFSEXITCODE(error); 3321 return (error); 3322 } 3323 3324 /* 3325 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 3326 * strings, one with the root path in it and the other with the list of 3327 * locations. The list is in the same format as is found in nfr_refs. 3328 * It is a "," separated list of entries, where each of them is of the 3329 * form <server>:<rootpath>. For example 3330 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 3331 * The nilp argument is set to 1 for the special case of a null fs_root 3332 * and an empty server list. 3333 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 3334 * number of xdr bytes parsed in sump. 3335 */ 3336 static int 3337 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 3338 int *sump, int *nilp) 3339 { 3340 u_int32_t *tl; 3341 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 3342 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 3343 struct list { 3344 SLIST_ENTRY(list) next; 3345 int len; 3346 u_char host[1]; 3347 } *lsp, *nlsp; 3348 SLIST_HEAD(, list) head; 3349 3350 *fsrootp = NULL; 3351 *srvp = NULL; 3352 *nilp = 0; 3353 3354 /* 3355 * Get the fs_root path and check for the special case of null path 3356 * and 0 length server list. 3357 */ 3358 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3359 len = fxdr_unsigned(int, *tl); 3360 if (len < 0 || len > 10240) { 3361 error = NFSERR_BADXDR; 3362 goto nfsmout; 3363 } 3364 if (len == 0) { 3365 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3366 if (*tl != 0) { 3367 error = NFSERR_BADXDR; 3368 goto nfsmout; 3369 } 3370 *nilp = 1; 3371 *sump = 2 * NFSX_UNSIGNED; 3372 error = 0; 3373 goto nfsmout; 3374 } 3375 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 3376 error = nfsrv_mtostr(nd, cp, len); 3377 if (!error) { 3378 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3379 cnt = fxdr_unsigned(int, *tl); 3380 if (cnt <= 0) 3381 error = NFSERR_BADXDR; 3382 } 3383 if (error) 3384 goto nfsmout; 3385 3386 /* 3387 * Now, loop through the location list and make up the srvlist. 3388 */ 3389 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3390 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 3391 slen = 1024; 3392 siz = 0; 3393 for (i = 0; i < cnt; i++) { 3394 SLIST_INIT(&head); 3395 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3396 nsrv = fxdr_unsigned(int, *tl); 3397 if (nsrv <= 0) { 3398 error = NFSERR_BADXDR; 3399 goto nfsmout; 3400 } 3401 3402 /* 3403 * Handle the first server by putting it in the srvstr. 3404 */ 3405 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3406 len = fxdr_unsigned(int, *tl); 3407 if (len <= 0 || len > 1024) { 3408 error = NFSERR_BADXDR; 3409 goto nfsmout; 3410 } 3411 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 3412 if (cp3 != cp2) { 3413 *cp3++ = ','; 3414 siz++; 3415 } 3416 error = nfsrv_mtostr(nd, cp3, len); 3417 if (error) 3418 goto nfsmout; 3419 cp3 += len; 3420 *cp3++ = ':'; 3421 siz += (len + 1); 3422 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3423 for (j = 1; j < nsrv; j++) { 3424 /* 3425 * Yuck, put them in an slist and process them later. 3426 */ 3427 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3428 len = fxdr_unsigned(int, *tl); 3429 if (len <= 0 || len > 1024) { 3430 error = NFSERR_BADXDR; 3431 goto nfsmout; 3432 } 3433 lsp = (struct list *)malloc(sizeof (struct list) 3434 + len, M_TEMP, M_WAITOK); 3435 error = nfsrv_mtostr(nd, lsp->host, len); 3436 if (error) 3437 goto nfsmout; 3438 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3439 lsp->len = len; 3440 SLIST_INSERT_HEAD(&head, lsp, next); 3441 } 3442 3443 /* 3444 * Finally, we can get the path. 3445 */ 3446 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3447 len = fxdr_unsigned(int, *tl); 3448 if (len <= 0 || len > 1024) { 3449 error = NFSERR_BADXDR; 3450 goto nfsmout; 3451 } 3452 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 3453 error = nfsrv_mtostr(nd, cp3, len); 3454 if (error) 3455 goto nfsmout; 3456 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3457 str = cp3; 3458 stringlen = len; 3459 cp3 += len; 3460 siz += len; 3461 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 3462 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 3463 &cp2, &cp3, &slen); 3464 *cp3++ = ','; 3465 NFSBCOPY(lsp->host, cp3, lsp->len); 3466 cp3 += lsp->len; 3467 *cp3++ = ':'; 3468 NFSBCOPY(str, cp3, stringlen); 3469 cp3 += stringlen; 3470 *cp3 = '\0'; 3471 siz += (lsp->len + stringlen + 2); 3472 free((caddr_t)lsp, M_TEMP); 3473 } 3474 } 3475 *fsrootp = cp; 3476 *srvp = cp2; 3477 *sump = xdrsum; 3478 NFSEXITCODE2(0, nd); 3479 return (0); 3480 nfsmout: 3481 if (cp != NULL) 3482 free(cp, M_NFSSTRING); 3483 if (cp2 != NULL) 3484 free(cp2, M_NFSSTRING); 3485 NFSEXITCODE2(error, nd); 3486 return (error); 3487 } 3488 3489 /* 3490 * Make the malloc'd space large enough. This is a pain, but the xdr 3491 * doesn't set an upper bound on the side, so... 3492 */ 3493 static void 3494 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 3495 { 3496 u_char *cp; 3497 int i; 3498 3499 if (siz <= *slenp) 3500 return; 3501 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 3502 NFSBCOPY(*cpp, cp, *slenp); 3503 free(*cpp, M_NFSSTRING); 3504 i = *cpp2 - *cpp; 3505 *cpp = cp; 3506 *cpp2 = cp + i; 3507 *slenp = siz + 1024; 3508 } 3509 3510 /* 3511 * Initialize the reply header data structures. 3512 */ 3513 APPLESTATIC void 3514 nfsrvd_rephead(struct nfsrv_descript *nd) 3515 { 3516 mbuf_t mreq; 3517 3518 /* 3519 * If this is a big reply, use a cluster. 3520 */ 3521 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 3522 nfs_bigreply[nd->nd_procnum]) { 3523 NFSMCLGET(mreq, M_WAITOK); 3524 nd->nd_mreq = mreq; 3525 nd->nd_mb = mreq; 3526 } else { 3527 NFSMGET(mreq); 3528 nd->nd_mreq = mreq; 3529 nd->nd_mb = mreq; 3530 } 3531 nd->nd_bpos = NFSMTOD(mreq, caddr_t); 3532 mbuf_setlen(mreq, 0); 3533 3534 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 3535 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 3536 } 3537 3538 /* 3539 * Lock a socket against others. 3540 * Currently used to serialize connect/disconnect attempts. 3541 */ 3542 int 3543 newnfs_sndlock(int *flagp) 3544 { 3545 struct timespec ts; 3546 3547 NFSLOCKSOCK(); 3548 while (*flagp & NFSR_SNDLOCK) { 3549 *flagp |= NFSR_WANTSND; 3550 ts.tv_sec = 0; 3551 ts.tv_nsec = 0; 3552 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 3553 PZERO - 1, "nfsndlck", &ts); 3554 } 3555 *flagp |= NFSR_SNDLOCK; 3556 NFSUNLOCKSOCK(); 3557 return (0); 3558 } 3559 3560 /* 3561 * Unlock the stream socket for others. 3562 */ 3563 void 3564 newnfs_sndunlock(int *flagp) 3565 { 3566 3567 NFSLOCKSOCK(); 3568 if ((*flagp & NFSR_SNDLOCK) == 0) 3569 panic("nfs sndunlock"); 3570 *flagp &= ~NFSR_SNDLOCK; 3571 if (*flagp & NFSR_WANTSND) { 3572 *flagp &= ~NFSR_WANTSND; 3573 wakeup((caddr_t)flagp); 3574 } 3575 NFSUNLOCKSOCK(); 3576 } 3577 3578 APPLESTATIC int 3579 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa, 3580 int *isudp) 3581 { 3582 struct sockaddr_in *sad; 3583 struct sockaddr_in6 *sad6; 3584 struct in_addr saddr; 3585 uint32_t portnum, *tl; 3586 int af = 0, i, j, k; 3587 char addr[64], protocol[5], *cp; 3588 int cantparse = 0, error = 0; 3589 uint16_t portv; 3590 3591 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3592 i = fxdr_unsigned(int, *tl); 3593 if (i >= 3 && i <= 4) { 3594 error = nfsrv_mtostr(nd, protocol, i); 3595 if (error) 3596 goto nfsmout; 3597 if (strcmp(protocol, "tcp") == 0) { 3598 af = AF_INET; 3599 *isudp = 0; 3600 } else if (strcmp(protocol, "udp") == 0) { 3601 af = AF_INET; 3602 *isudp = 1; 3603 } else if (strcmp(protocol, "tcp6") == 0) { 3604 af = AF_INET6; 3605 *isudp = 0; 3606 } else if (strcmp(protocol, "udp6") == 0) { 3607 af = AF_INET6; 3608 *isudp = 1; 3609 } else 3610 cantparse = 1; 3611 } else { 3612 cantparse = 1; 3613 if (i > 0) { 3614 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3615 if (error) 3616 goto nfsmout; 3617 } 3618 } 3619 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3620 i = fxdr_unsigned(int, *tl); 3621 if (i < 0) { 3622 error = NFSERR_BADXDR; 3623 goto nfsmout; 3624 } else if (cantparse == 0 && i >= 11 && i < 64) { 3625 /* 3626 * The shortest address is 11chars and the longest is < 64. 3627 */ 3628 error = nfsrv_mtostr(nd, addr, i); 3629 if (error) 3630 goto nfsmout; 3631 3632 /* Find the port# at the end and extract that. */ 3633 i = strlen(addr); 3634 k = 0; 3635 cp = &addr[i - 1]; 3636 /* Count back two '.'s from end to get port# field. */ 3637 for (j = 0; j < i; j++) { 3638 if (*cp == '.') { 3639 k++; 3640 if (k == 2) 3641 break; 3642 } 3643 cp--; 3644 } 3645 if (k == 2) { 3646 /* 3647 * The NFSv4 port# is appended as .N.N, where N is 3648 * a decimal # in the range 0-255, just like an inet4 3649 * address. Cheat and use inet_aton(), which will 3650 * return a Class A address and then shift the high 3651 * order 8bits over to convert it to the port#. 3652 */ 3653 *cp++ = '\0'; 3654 if (inet_aton(cp, &saddr) == 1) { 3655 portnum = ntohl(saddr.s_addr); 3656 portv = (uint16_t)((portnum >> 16) | 3657 (portnum & 0xff)); 3658 } else 3659 cantparse = 1; 3660 } else 3661 cantparse = 1; 3662 if (cantparse == 0) { 3663 if (af == AF_INET) { 3664 sad = (struct sockaddr_in *)sa; 3665 if (inet_pton(af, addr, &sad->sin_addr) == 1) { 3666 sad->sin_len = sizeof(*sad); 3667 sad->sin_family = AF_INET; 3668 sad->sin_port = htons(portv); 3669 return (0); 3670 } 3671 } else { 3672 sad6 = (struct sockaddr_in6 *)sa; 3673 if (inet_pton(af, addr, &sad6->sin6_addr) 3674 == 1) { 3675 sad6->sin6_len = sizeof(*sad6); 3676 sad6->sin6_family = AF_INET6; 3677 sad6->sin6_port = htons(portv); 3678 return (0); 3679 } 3680 } 3681 } 3682 } else { 3683 if (i > 0) { 3684 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3685 if (error) 3686 goto nfsmout; 3687 } 3688 } 3689 error = EPERM; 3690 nfsmout: 3691 return (error); 3692 } 3693 3694 /* 3695 * Handle an NFSv4.1 Sequence request for the session. 3696 * If reply != NULL, use it to return the cached reply, as required. 3697 * The client gets a cached reply via this call for callbacks, however the 3698 * server gets a cached reply via the nfsv4_seqsess_cachereply() call. 3699 */ 3700 int 3701 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 3702 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 3703 { 3704 int error; 3705 3706 error = 0; 3707 if (reply != NULL) 3708 *reply = NULL; 3709 if (slotid > maxslot) 3710 return (NFSERR_BADSLOT); 3711 if (seqid == slots[slotid].nfssl_seq) { 3712 /* A retry. */ 3713 if (slots[slotid].nfssl_inprog != 0) 3714 error = NFSERR_DELAY; 3715 else if (slots[slotid].nfssl_reply != NULL) { 3716 if (reply != NULL) { 3717 *reply = slots[slotid].nfssl_reply; 3718 slots[slotid].nfssl_reply = NULL; 3719 } 3720 slots[slotid].nfssl_inprog = 1; 3721 error = NFSERR_REPLYFROMCACHE; 3722 } else 3723 /* No reply cached, so just do it. */ 3724 slots[slotid].nfssl_inprog = 1; 3725 } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 3726 if (slots[slotid].nfssl_reply != NULL) 3727 m_freem(slots[slotid].nfssl_reply); 3728 slots[slotid].nfssl_reply = NULL; 3729 slots[slotid].nfssl_inprog = 1; 3730 slots[slotid].nfssl_seq++; 3731 } else 3732 error = NFSERR_SEQMISORDERED; 3733 return (error); 3734 } 3735 3736 /* 3737 * Cache this reply for the slot. 3738 * Use the "rep" argument to return the cached reply if repstat is set to 3739 * NFSERR_REPLYFROMCACHE. The client never sets repstat to this value. 3740 */ 3741 void 3742 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, int repstat, 3743 struct mbuf **rep) 3744 { 3745 3746 if (repstat == NFSERR_REPLYFROMCACHE) { 3747 *rep = slots[slotid].nfssl_reply; 3748 slots[slotid].nfssl_reply = NULL; 3749 } else { 3750 if (slots[slotid].nfssl_reply != NULL) 3751 m_freem(slots[slotid].nfssl_reply); 3752 slots[slotid].nfssl_reply = *rep; 3753 } 3754 slots[slotid].nfssl_inprog = 0; 3755 } 3756 3757 /* 3758 * Generate the xdr for an NFSv4.1 Sequence Operation. 3759 */ 3760 APPLESTATIC void 3761 nfsv4_setsequence(struct nfsmount *nmp, struct nfsrv_descript *nd, 3762 struct nfsclsession *sep, int dont_replycache) 3763 { 3764 uint32_t *tl, slotseq = 0; 3765 int error, maxslot, slotpos; 3766 uint8_t sessionid[NFSX_V4SESSIONID]; 3767 3768 error = nfsv4_sequencelookup(nmp, sep, &slotpos, &maxslot, &slotseq, 3769 sessionid); 3770 if (error != 0) 3771 return; 3772 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot")); 3773 3774 /* Build the Sequence arguments. */ 3775 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 3776 bcopy(sessionid, tl, NFSX_V4SESSIONID); 3777 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 3778 nd->nd_slotseq = tl; 3779 *tl++ = txdr_unsigned(slotseq); 3780 *tl++ = txdr_unsigned(slotpos); 3781 *tl++ = txdr_unsigned(maxslot); 3782 if (dont_replycache == 0) 3783 *tl = newnfs_true; 3784 else 3785 *tl = newnfs_false; 3786 nd->nd_flag |= ND_HASSEQUENCE; 3787 } 3788 3789 int 3790 nfsv4_sequencelookup(struct nfsmount *nmp, struct nfsclsession *sep, 3791 int *slotposp, int *maxslotp, uint32_t *slotseqp, uint8_t *sessionid) 3792 { 3793 int i, maxslot, slotpos; 3794 uint64_t bitval; 3795 3796 /* Find an unused slot. */ 3797 slotpos = -1; 3798 maxslot = -1; 3799 mtx_lock(&sep->nfsess_mtx); 3800 do { 3801 bitval = 1; 3802 for (i = 0; i < sep->nfsess_foreslots; i++) { 3803 if ((bitval & sep->nfsess_slots) == 0) { 3804 slotpos = i; 3805 sep->nfsess_slots |= bitval; 3806 sep->nfsess_slotseq[i]++; 3807 *slotseqp = sep->nfsess_slotseq[i]; 3808 break; 3809 } 3810 bitval <<= 1; 3811 } 3812 if (slotpos == -1) { 3813 /* 3814 * If a forced dismount is in progress, just return. 3815 * This RPC attempt will fail when it calls 3816 * newnfs_request(). 3817 */ 3818 if (nmp != NULL && 3819 (nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) 3820 != 0) { 3821 mtx_unlock(&sep->nfsess_mtx); 3822 return (ESTALE); 3823 } 3824 /* Wake up once/sec, to check for a forced dismount. */ 3825 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 3826 PZERO, "nfsclseq", hz); 3827 } 3828 } while (slotpos == -1); 3829 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 3830 bitval = 1; 3831 for (i = 0; i < 64; i++) { 3832 if ((bitval & sep->nfsess_slots) != 0) 3833 maxslot = i; 3834 bitval <<= 1; 3835 } 3836 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 3837 mtx_unlock(&sep->nfsess_mtx); 3838 *slotposp = slotpos; 3839 *maxslotp = maxslot; 3840 return (0); 3841 } 3842 3843 /* 3844 * Free a session slot. 3845 */ 3846 APPLESTATIC void 3847 nfsv4_freeslot(struct nfsclsession *sep, int slot) 3848 { 3849 uint64_t bitval; 3850 3851 bitval = 1; 3852 if (slot > 0) 3853 bitval <<= slot; 3854 mtx_lock(&sep->nfsess_mtx); 3855 if ((bitval & sep->nfsess_slots) == 0) 3856 printf("freeing free slot!!\n"); 3857 sep->nfsess_slots &= ~bitval; 3858 wakeup(&sep->nfsess_slots); 3859 mtx_unlock(&sep->nfsess_mtx); 3860 } 3861 3862