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