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