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