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 struct timeval curtime; 2002 NFSACL_T *aclp, *naclp = NULL; 2003 #ifdef QUOTA 2004 struct dqblk dqb; 2005 uid_t savuid; 2006 #endif 2007 2008 /* 2009 * First, set the bits that can be filled and get fsinfo. 2010 */ 2011 NFSSET_ATTRBIT(retbitp, attrbitp); 2012 /* If p and cred are NULL, it is a client side call */ 2013 if (p == NULL && cred == NULL) { 2014 NFSCLRNOTSETABLE_ATTRBIT(retbitp); 2015 aclp = saclp; 2016 } else { 2017 NFSCLRNOTFILLABLE_ATTRBIT(retbitp); 2018 naclp = acl_alloc(M_WAITOK); 2019 aclp = naclp; 2020 } 2021 nfsvno_getfs(&fsinf, isdgram); 2022 #ifndef APPLE 2023 /* 2024 * Get the VFS_STATFS(), since some attributes need them. 2025 */ 2026 if (NFSISSETSTATFS_ATTRBIT(retbitp)) { 2027 error = VFS_STATFS(mp, &fs); 2028 if (error != 0) { 2029 if (reterr) { 2030 nd->nd_repstat = NFSERR_ACCES; 2031 return (0); 2032 } 2033 NFSCLRSTATFS_ATTRBIT(retbitp); 2034 } 2035 } 2036 #endif 2037 2038 /* 2039 * And the NFSv4 ACL... 2040 */ 2041 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && 2042 (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2043 supports_nfsv4acls == 0))) { 2044 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); 2045 } 2046 if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { 2047 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && 2048 supports_nfsv4acls == 0)) { 2049 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2050 } else if (naclp != NULL) { 2051 if (NFSVOPLOCK(vp, LK_SHARED) == 0) { 2052 error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); 2053 if (error == 0) 2054 error = VOP_GETACL(vp, ACL_TYPE_NFS4, 2055 naclp, cred, p); 2056 NFSVOPUNLOCK(vp, 0); 2057 } else 2058 error = NFSERR_PERM; 2059 if (error != 0) { 2060 if (reterr) { 2061 nd->nd_repstat = NFSERR_ACCES; 2062 return (0); 2063 } 2064 NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); 2065 } 2066 } 2067 } 2068 /* 2069 * Put out the attribute bitmap for the ones being filled in 2070 * and get the field for the number of attributes returned. 2071 */ 2072 prefixnum = nfsrv_putattrbit(nd, retbitp); 2073 NFSM_BUILD(retnump, u_int32_t *, NFSX_UNSIGNED); 2074 prefixnum += NFSX_UNSIGNED; 2075 2076 /* 2077 * Now, loop around filling in the attributes for each bit set. 2078 */ 2079 for (bitpos = 0; bitpos < NFSATTRBIT_MAX; bitpos++) { 2080 if (NFSISSET_ATTRBIT(retbitp, bitpos)) { 2081 switch (bitpos) { 2082 case NFSATTRBIT_SUPPORTEDATTRS: 2083 NFSSETSUPP_ATTRBIT(&attrbits); 2084 if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) 2085 && supports_nfsv4acls == 0)) { 2086 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); 2087 NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); 2088 } 2089 retnum += nfsrv_putattrbit(nd, &attrbits); 2090 break; 2091 case NFSATTRBIT_TYPE: 2092 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2093 *tl = vtonfsv34_type(vap->va_type); 2094 retnum += NFSX_UNSIGNED; 2095 break; 2096 case NFSATTRBIT_FHEXPIRETYPE: 2097 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2098 *tl = txdr_unsigned(NFSV4FHTYPE_PERSISTENT); 2099 retnum += NFSX_UNSIGNED; 2100 break; 2101 case NFSATTRBIT_CHANGE: 2102 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2103 txdr_hyper(vap->va_filerev, tl); 2104 retnum += NFSX_HYPER; 2105 break; 2106 case NFSATTRBIT_SIZE: 2107 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2108 txdr_hyper(vap->va_size, tl); 2109 retnum += NFSX_HYPER; 2110 break; 2111 case NFSATTRBIT_LINKSUPPORT: 2112 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2113 if (fsinf.fs_properties & NFSV3FSINFO_LINK) 2114 *tl = newnfs_true; 2115 else 2116 *tl = newnfs_false; 2117 retnum += NFSX_UNSIGNED; 2118 break; 2119 case NFSATTRBIT_SYMLINKSUPPORT: 2120 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2121 if (fsinf.fs_properties & NFSV3FSINFO_SYMLINK) 2122 *tl = newnfs_true; 2123 else 2124 *tl = newnfs_false; 2125 retnum += NFSX_UNSIGNED; 2126 break; 2127 case NFSATTRBIT_NAMEDATTR: 2128 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2129 *tl = newnfs_false; 2130 retnum += NFSX_UNSIGNED; 2131 break; 2132 case NFSATTRBIT_FSID: 2133 NFSM_BUILD(tl, u_int32_t *, NFSX_V4FSID); 2134 *tl++ = 0; 2135 *tl++ = txdr_unsigned(mp->mnt_stat.f_fsid.val[0]); 2136 *tl++ = 0; 2137 *tl = txdr_unsigned(mp->mnt_stat.f_fsid.val[1]); 2138 retnum += NFSX_V4FSID; 2139 break; 2140 case NFSATTRBIT_UNIQUEHANDLES: 2141 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2142 *tl = newnfs_true; 2143 retnum += NFSX_UNSIGNED; 2144 break; 2145 case NFSATTRBIT_LEASETIME: 2146 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2147 *tl = txdr_unsigned(nfsrv_lease); 2148 retnum += NFSX_UNSIGNED; 2149 break; 2150 case NFSATTRBIT_RDATTRERROR: 2151 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2152 *tl = txdr_unsigned(rderror); 2153 retnum += NFSX_UNSIGNED; 2154 break; 2155 /* 2156 * Recommended Attributes. (Only the supported ones.) 2157 */ 2158 case NFSATTRBIT_ACL: 2159 retnum += nfsrv_buildacl(nd, aclp, vnode_vtype(vp), p); 2160 break; 2161 case NFSATTRBIT_ACLSUPPORT: 2162 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2163 *tl = txdr_unsigned(NFSV4ACE_SUPTYPES); 2164 retnum += NFSX_UNSIGNED; 2165 break; 2166 case NFSATTRBIT_CANSETTIME: 2167 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2168 if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME) 2169 *tl = newnfs_true; 2170 else 2171 *tl = newnfs_false; 2172 retnum += NFSX_UNSIGNED; 2173 break; 2174 case NFSATTRBIT_CASEINSENSITIVE: 2175 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2176 *tl = newnfs_false; 2177 retnum += NFSX_UNSIGNED; 2178 break; 2179 case NFSATTRBIT_CASEPRESERVING: 2180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2181 *tl = newnfs_true; 2182 retnum += NFSX_UNSIGNED; 2183 break; 2184 case NFSATTRBIT_CHOWNRESTRICTED: 2185 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2186 *tl = newnfs_true; 2187 retnum += NFSX_UNSIGNED; 2188 break; 2189 case NFSATTRBIT_FILEHANDLE: 2190 retnum += nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2191 break; 2192 case NFSATTRBIT_FILEID: 2193 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2194 *tl++ = 0; 2195 *tl = txdr_unsigned(vap->va_fileid); 2196 retnum += NFSX_HYPER; 2197 break; 2198 case NFSATTRBIT_FILESAVAIL: 2199 /* 2200 * Check quota and use min(quota, f_ffree). 2201 */ 2202 freenum = fs.f_ffree; 2203 #ifdef QUOTA 2204 /* 2205 * ufs_quotactl() insists that the uid argument 2206 * equal p_ruid for non-root quota access, so 2207 * we'll just make sure that's the case. 2208 */ 2209 savuid = p->p_cred->p_ruid; 2210 p->p_cred->p_ruid = cred->cr_uid; 2211 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2212 cred->cr_uid, (caddr_t)&dqb)) 2213 freenum = min(dqb.dqb_isoftlimit-dqb.dqb_curinodes, 2214 freenum); 2215 p->p_cred->p_ruid = savuid; 2216 #endif /* QUOTA */ 2217 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2218 *tl++ = 0; 2219 *tl = txdr_unsigned(freenum); 2220 retnum += NFSX_HYPER; 2221 break; 2222 case NFSATTRBIT_FILESFREE: 2223 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2224 *tl++ = 0; 2225 *tl = txdr_unsigned(fs.f_ffree); 2226 retnum += NFSX_HYPER; 2227 break; 2228 case NFSATTRBIT_FILESTOTAL: 2229 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2230 *tl++ = 0; 2231 *tl = txdr_unsigned(fs.f_files); 2232 retnum += NFSX_HYPER; 2233 break; 2234 case NFSATTRBIT_FSLOCATIONS: 2235 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2236 *tl++ = 0; 2237 *tl = 0; 2238 retnum += 2 * NFSX_UNSIGNED; 2239 break; 2240 case NFSATTRBIT_HOMOGENEOUS: 2241 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2242 if (fsinf.fs_properties & NFSV3FSINFO_HOMOGENEOUS) 2243 *tl = newnfs_true; 2244 else 2245 *tl = newnfs_false; 2246 retnum += NFSX_UNSIGNED; 2247 break; 2248 case NFSATTRBIT_MAXFILESIZE: 2249 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2250 uquad = NFSRV_MAXFILESIZE; 2251 txdr_hyper(uquad, tl); 2252 retnum += NFSX_HYPER; 2253 break; 2254 case NFSATTRBIT_MAXLINK: 2255 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2256 *tl = txdr_unsigned(LINK_MAX); 2257 retnum += NFSX_UNSIGNED; 2258 break; 2259 case NFSATTRBIT_MAXNAME: 2260 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2261 *tl = txdr_unsigned(NFS_MAXNAMLEN); 2262 retnum += NFSX_UNSIGNED; 2263 break; 2264 case NFSATTRBIT_MAXREAD: 2265 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2266 *tl++ = 0; 2267 *tl = txdr_unsigned(fsinf.fs_rtmax); 2268 retnum += NFSX_HYPER; 2269 break; 2270 case NFSATTRBIT_MAXWRITE: 2271 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2272 *tl++ = 0; 2273 *tl = txdr_unsigned(fsinf.fs_wtmax); 2274 retnum += NFSX_HYPER; 2275 break; 2276 case NFSATTRBIT_MODE: 2277 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2278 *tl = vtonfsv34_mode(vap->va_mode); 2279 retnum += NFSX_UNSIGNED; 2280 break; 2281 case NFSATTRBIT_NOTRUNC: 2282 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2283 *tl = newnfs_true; 2284 retnum += NFSX_UNSIGNED; 2285 break; 2286 case NFSATTRBIT_NUMLINKS: 2287 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2288 *tl = txdr_unsigned(vap->va_nlink); 2289 retnum += NFSX_UNSIGNED; 2290 break; 2291 case NFSATTRBIT_OWNER: 2292 cp = namestr; 2293 nfsv4_uidtostr(vap->va_uid, &cp, &siz, p); 2294 retnum += nfsm_strtom(nd, cp, siz); 2295 if (cp != namestr) 2296 free(cp, M_NFSSTRING); 2297 break; 2298 case NFSATTRBIT_OWNERGROUP: 2299 cp = namestr; 2300 nfsv4_gidtostr(vap->va_gid, &cp, &siz, p); 2301 retnum += nfsm_strtom(nd, cp, siz); 2302 if (cp != namestr) 2303 free(cp, M_NFSSTRING); 2304 break; 2305 case NFSATTRBIT_QUOTAHARD: 2306 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2307 freenum = fs.f_bfree; 2308 else 2309 freenum = fs.f_bavail; 2310 #ifdef QUOTA 2311 /* 2312 * ufs_quotactl() insists that the uid argument 2313 * equal p_ruid for non-root quota access, so 2314 * we'll just make sure that's the case. 2315 */ 2316 savuid = p->p_cred->p_ruid; 2317 p->p_cred->p_ruid = cred->cr_uid; 2318 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2319 cred->cr_uid, (caddr_t)&dqb)) 2320 freenum = min(dqb.dqb_bhardlimit, freenum); 2321 p->p_cred->p_ruid = savuid; 2322 #endif /* QUOTA */ 2323 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2324 uquad = (u_int64_t)freenum; 2325 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2326 txdr_hyper(uquad, tl); 2327 retnum += NFSX_HYPER; 2328 break; 2329 case NFSATTRBIT_QUOTASOFT: 2330 if (priv_check_cred(cred, PRIV_VFS_EXCEEDQUOTA, 0)) 2331 freenum = fs.f_bfree; 2332 else 2333 freenum = fs.f_bavail; 2334 #ifdef QUOTA 2335 /* 2336 * ufs_quotactl() insists that the uid argument 2337 * equal p_ruid for non-root quota access, so 2338 * we'll just make sure that's the case. 2339 */ 2340 savuid = p->p_cred->p_ruid; 2341 p->p_cred->p_ruid = cred->cr_uid; 2342 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2343 cred->cr_uid, (caddr_t)&dqb)) 2344 freenum = min(dqb.dqb_bsoftlimit, freenum); 2345 p->p_cred->p_ruid = savuid; 2346 #endif /* QUOTA */ 2347 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2348 uquad = (u_int64_t)freenum; 2349 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2350 txdr_hyper(uquad, tl); 2351 retnum += NFSX_HYPER; 2352 break; 2353 case NFSATTRBIT_QUOTAUSED: 2354 freenum = 0; 2355 #ifdef QUOTA 2356 /* 2357 * ufs_quotactl() insists that the uid argument 2358 * equal p_ruid for non-root quota access, so 2359 * we'll just make sure that's the case. 2360 */ 2361 savuid = p->p_cred->p_ruid; 2362 p->p_cred->p_ruid = cred->cr_uid; 2363 if (!VFS_QUOTACTL(mp, QCMD(Q_GETQUOTA,USRQUOTA), 2364 cred->cr_uid, (caddr_t)&dqb)) 2365 freenum = dqb.dqb_curblocks; 2366 p->p_cred->p_ruid = savuid; 2367 #endif /* QUOTA */ 2368 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2369 uquad = (u_int64_t)freenum; 2370 NFSQUOTABLKTOBYTE(uquad, fs.f_bsize); 2371 txdr_hyper(uquad, tl); 2372 retnum += NFSX_HYPER; 2373 break; 2374 case NFSATTRBIT_RAWDEV: 2375 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SPECDATA); 2376 *tl++ = txdr_unsigned(NFSMAJOR(vap->va_rdev)); 2377 *tl = txdr_unsigned(NFSMINOR(vap->va_rdev)); 2378 retnum += NFSX_V4SPECDATA; 2379 break; 2380 case NFSATTRBIT_SPACEAVAIL: 2381 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2382 if (priv_check_cred(cred, PRIV_VFS_BLOCKRESERVE, 0)) 2383 uquad = (u_int64_t)fs.f_bfree; 2384 else 2385 uquad = (u_int64_t)fs.f_bavail; 2386 uquad *= fs.f_bsize; 2387 txdr_hyper(uquad, tl); 2388 retnum += NFSX_HYPER; 2389 break; 2390 case NFSATTRBIT_SPACEFREE: 2391 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2392 uquad = (u_int64_t)fs.f_bfree; 2393 uquad *= fs.f_bsize; 2394 txdr_hyper(uquad, tl); 2395 retnum += NFSX_HYPER; 2396 break; 2397 case NFSATTRBIT_SPACETOTAL: 2398 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2399 uquad = (u_int64_t)fs.f_blocks; 2400 uquad *= fs.f_bsize; 2401 txdr_hyper(uquad, tl); 2402 retnum += NFSX_HYPER; 2403 break; 2404 case NFSATTRBIT_SPACEUSED: 2405 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2406 txdr_hyper(vap->va_bytes, tl); 2407 retnum += NFSX_HYPER; 2408 break; 2409 case NFSATTRBIT_TIMEACCESS: 2410 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2411 txdr_nfsv4time(&vap->va_atime, tl); 2412 retnum += NFSX_V4TIME; 2413 break; 2414 case NFSATTRBIT_TIMEACCESSSET: 2415 NFSGETTIME(&curtime); 2416 if (vap->va_atime.tv_sec != curtime.tv_sec) { 2417 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2418 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2419 txdr_nfsv4time(&vap->va_atime, tl); 2420 retnum += NFSX_V4SETTIME; 2421 } else { 2422 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2423 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2424 retnum += NFSX_UNSIGNED; 2425 } 2426 break; 2427 case NFSATTRBIT_TIMEDELTA: 2428 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2429 temptime.tv_sec = 0; 2430 temptime.tv_nsec = 1000000000 / hz; 2431 txdr_nfsv4time(&temptime, tl); 2432 retnum += NFSX_V4TIME; 2433 break; 2434 case NFSATTRBIT_TIMEMETADATA: 2435 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2436 txdr_nfsv4time(&vap->va_ctime, tl); 2437 retnum += NFSX_V4TIME; 2438 break; 2439 case NFSATTRBIT_TIMEMODIFY: 2440 NFSM_BUILD(tl, u_int32_t *, NFSX_V4TIME); 2441 txdr_nfsv4time(&vap->va_mtime, tl); 2442 retnum += NFSX_V4TIME; 2443 break; 2444 case NFSATTRBIT_TIMEMODIFYSET: 2445 NFSGETTIME(&curtime); 2446 if (vap->va_mtime.tv_sec != curtime.tv_sec) { 2447 NFSM_BUILD(tl, u_int32_t *, NFSX_V4SETTIME); 2448 *tl++ = txdr_unsigned(NFSV4SATTRTIME_TOCLIENT); 2449 txdr_nfsv4time(&vap->va_mtime, tl); 2450 retnum += NFSX_V4SETTIME; 2451 } else { 2452 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2453 *tl = txdr_unsigned(NFSV4SATTRTIME_TOSERVER); 2454 retnum += NFSX_UNSIGNED; 2455 } 2456 break; 2457 case NFSATTRBIT_MOUNTEDONFILEID: 2458 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER); 2459 if (at_root != 0) 2460 uquad = mounted_on_fileno; 2461 else 2462 uquad = (u_int64_t)vap->va_fileid; 2463 txdr_hyper(uquad, tl); 2464 retnum += NFSX_HYPER; 2465 break; 2466 default: 2467 printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); 2468 }; 2469 } 2470 } 2471 if (naclp != NULL) 2472 acl_free(naclp); 2473 *retnump = txdr_unsigned(retnum); 2474 return (retnum + prefixnum); 2475 } 2476 2477 /* 2478 * Put the attribute bits onto an mbuf list. 2479 * Return the number of bytes of output generated. 2480 */ 2481 APPLESTATIC int 2482 nfsrv_putattrbit(struct nfsrv_descript *nd, nfsattrbit_t *attrbitp) 2483 { 2484 u_int32_t *tl; 2485 int cnt, i, bytesize; 2486 2487 for (cnt = NFSATTRBIT_MAXWORDS; cnt > 0; cnt--) 2488 if (attrbitp->bits[cnt - 1]) 2489 break; 2490 bytesize = (cnt + 1) * NFSX_UNSIGNED; 2491 NFSM_BUILD(tl, u_int32_t *, bytesize); 2492 *tl++ = txdr_unsigned(cnt); 2493 for (i = 0; i < cnt; i++) 2494 *tl++ = txdr_unsigned(attrbitp->bits[i]); 2495 return (bytesize); 2496 } 2497 2498 /* 2499 * Convert a uid to a string. 2500 * If the lookup fails, just output the digits. 2501 * uid - the user id 2502 * cpp - points to a buffer of size NFSV4_SMALLSTR 2503 * (malloc a larger one, as required) 2504 * retlenp - pointer to length to be returned 2505 */ 2506 APPLESTATIC void 2507 nfsv4_uidtostr(uid_t uid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2508 { 2509 int i; 2510 struct nfsusrgrp *usrp; 2511 u_char *cp = *cpp; 2512 uid_t tmp; 2513 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2514 2515 cnt = 0; 2516 tryagain: 2517 NFSLOCKNAMEID(); 2518 if (nfsrv_dnsname) { 2519 /* 2520 * Always map nfsrv_defaultuid to "nobody". 2521 */ 2522 if (uid == nfsrv_defaultuid) { 2523 i = nfsrv_dnsnamelen + 7; 2524 if (i > len) { 2525 NFSUNLOCKNAMEID(); 2526 if (len > NFSV4_SMALLSTR) 2527 free(cp, M_NFSSTRING); 2528 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2529 *cpp = cp; 2530 len = i; 2531 goto tryagain; 2532 } 2533 *retlenp = i; 2534 NFSBCOPY("nobody@", cp, 7); 2535 cp += 7; 2536 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2537 NFSUNLOCKNAMEID(); 2538 return; 2539 } 2540 hasampersand = 0; 2541 LIST_FOREACH(usrp, NFSUSERHASH(uid), lug_numhash) { 2542 if (usrp->lug_uid == uid) { 2543 if (usrp->lug_expiry < NFSD_MONOSEC) 2544 break; 2545 /* 2546 * If the name doesn't already have an '@' 2547 * in it, append @domainname to it. 2548 */ 2549 for (i = 0; i < usrp->lug_namelen; i++) { 2550 if (usrp->lug_name[i] == '@') { 2551 hasampersand = 1; 2552 break; 2553 } 2554 } 2555 if (hasampersand) 2556 i = usrp->lug_namelen; 2557 else 2558 i = usrp->lug_namelen + 2559 nfsrv_dnsnamelen + 1; 2560 if (i > len) { 2561 NFSUNLOCKNAMEID(); 2562 if (len > NFSV4_SMALLSTR) 2563 free(cp, M_NFSSTRING); 2564 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2565 *cpp = cp; 2566 len = i; 2567 goto tryagain; 2568 } 2569 *retlenp = i; 2570 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2571 if (!hasampersand) { 2572 cp += usrp->lug_namelen; 2573 *cp++ = '@'; 2574 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2575 } 2576 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2577 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2578 NFSUNLOCKNAMEID(); 2579 return; 2580 } 2581 } 2582 NFSUNLOCKNAMEID(); 2583 cnt++; 2584 ret = nfsrv_getuser(RPCNFSUSERD_GETUID, uid, (gid_t)0, 2585 NULL, p); 2586 if (ret == 0 && cnt < 2) 2587 goto tryagain; 2588 } else { 2589 NFSUNLOCKNAMEID(); 2590 } 2591 2592 /* 2593 * No match, just return a string of digits. 2594 */ 2595 tmp = uid; 2596 i = 0; 2597 while (tmp || i == 0) { 2598 tmp /= 10; 2599 i++; 2600 } 2601 len = (i > len) ? len : i; 2602 *retlenp = len; 2603 cp += (len - 1); 2604 tmp = uid; 2605 for (i = 0; i < len; i++) { 2606 *cp-- = '0' + (tmp % 10); 2607 tmp /= 10; 2608 } 2609 return; 2610 } 2611 2612 /* 2613 * Convert a string to a uid. 2614 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2615 * return 0. 2616 * If this is called from a client side mount using AUTH_SYS and the 2617 * string is made up entirely of digits, just convert the string to 2618 * a number. 2619 */ 2620 APPLESTATIC int 2621 nfsv4_strtouid(struct nfsrv_descript *nd, u_char *str, int len, uid_t *uidp, 2622 NFSPROC_T *p) 2623 { 2624 int i; 2625 char *cp, *endstr, *str0; 2626 struct nfsusrgrp *usrp; 2627 int cnt, ret; 2628 int error = 0; 2629 uid_t tuid; 2630 2631 if (len == 0) { 2632 error = NFSERR_BADOWNER; 2633 goto out; 2634 } 2635 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2636 str0 = str; 2637 tuid = (uid_t)strtoul(str0, &endstr, 10); 2638 if ((endstr - str0) == len && 2639 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) { 2640 *uidp = tuid; 2641 goto out; 2642 } 2643 /* 2644 * Look for an '@'. 2645 */ 2646 cp = strchr(str0, '@'); 2647 if (cp != NULL) 2648 i = (int)(cp++ - str0); 2649 else 2650 i = len; 2651 2652 cnt = 0; 2653 tryagain: 2654 NFSLOCKNAMEID(); 2655 /* 2656 * If an '@' is found and the domain name matches, search for the name 2657 * with dns stripped off. 2658 * Mixed case alpahbetics will match for the domain name, but all 2659 * upper case will not. 2660 */ 2661 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2662 (len - 1 - i) == nfsrv_dnsnamelen && 2663 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2664 len -= (nfsrv_dnsnamelen + 1); 2665 *(cp - 1) = '\0'; 2666 } 2667 2668 /* 2669 * Check for the special case of "nobody". 2670 */ 2671 if (len == 6 && !NFSBCMP(str, "nobody", 6)) { 2672 *uidp = nfsrv_defaultuid; 2673 NFSUNLOCKNAMEID(); 2674 error = 0; 2675 goto out; 2676 } 2677 2678 LIST_FOREACH(usrp, NFSUSERNAMEHASH(str, len), lug_namehash) { 2679 if (usrp->lug_namelen == len && 2680 !NFSBCMP(usrp->lug_name, str, len)) { 2681 if (usrp->lug_expiry < NFSD_MONOSEC) 2682 break; 2683 *uidp = usrp->lug_uid; 2684 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2685 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2686 NFSUNLOCKNAMEID(); 2687 error = 0; 2688 goto out; 2689 } 2690 } 2691 NFSUNLOCKNAMEID(); 2692 cnt++; 2693 ret = nfsrv_getuser(RPCNFSUSERD_GETUSER, (uid_t)0, (gid_t)0, 2694 str, p); 2695 if (ret == 0 && cnt < 2) 2696 goto tryagain; 2697 error = NFSERR_BADOWNER; 2698 2699 out: 2700 NFSEXITCODE(error); 2701 return (error); 2702 } 2703 2704 /* 2705 * Convert a gid to a string. 2706 * gid - the group id 2707 * cpp - points to a buffer of size NFSV4_SMALLSTR 2708 * (malloc a larger one, as required) 2709 * retlenp - pointer to length to be returned 2710 */ 2711 APPLESTATIC void 2712 nfsv4_gidtostr(gid_t gid, u_char **cpp, int *retlenp, NFSPROC_T *p) 2713 { 2714 int i; 2715 struct nfsusrgrp *usrp; 2716 u_char *cp = *cpp; 2717 gid_t tmp; 2718 int cnt, hasampersand, len = NFSV4_SMALLSTR, ret; 2719 2720 cnt = 0; 2721 tryagain: 2722 NFSLOCKNAMEID(); 2723 if (nfsrv_dnsname) { 2724 /* 2725 * Always map nfsrv_defaultgid to "nogroup". 2726 */ 2727 if (gid == nfsrv_defaultgid) { 2728 i = nfsrv_dnsnamelen + 8; 2729 if (i > len) { 2730 NFSUNLOCKNAMEID(); 2731 if (len > NFSV4_SMALLSTR) 2732 free(cp, M_NFSSTRING); 2733 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2734 *cpp = cp; 2735 len = i; 2736 goto tryagain; 2737 } 2738 *retlenp = i; 2739 NFSBCOPY("nogroup@", cp, 8); 2740 cp += 8; 2741 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2742 NFSUNLOCKNAMEID(); 2743 return; 2744 } 2745 hasampersand = 0; 2746 LIST_FOREACH(usrp, NFSGROUPHASH(gid), lug_numhash) { 2747 if (usrp->lug_gid == gid) { 2748 if (usrp->lug_expiry < NFSD_MONOSEC) 2749 break; 2750 /* 2751 * If the name doesn't already have an '@' 2752 * in it, append @domainname to it. 2753 */ 2754 for (i = 0; i < usrp->lug_namelen; i++) { 2755 if (usrp->lug_name[i] == '@') { 2756 hasampersand = 1; 2757 break; 2758 } 2759 } 2760 if (hasampersand) 2761 i = usrp->lug_namelen; 2762 else 2763 i = usrp->lug_namelen + 2764 nfsrv_dnsnamelen + 1; 2765 if (i > len) { 2766 NFSUNLOCKNAMEID(); 2767 if (len > NFSV4_SMALLSTR) 2768 free(cp, M_NFSSTRING); 2769 cp = malloc(i, M_NFSSTRING, M_WAITOK); 2770 *cpp = cp; 2771 len = i; 2772 goto tryagain; 2773 } 2774 *retlenp = i; 2775 NFSBCOPY(usrp->lug_name, cp, usrp->lug_namelen); 2776 if (!hasampersand) { 2777 cp += usrp->lug_namelen; 2778 *cp++ = '@'; 2779 NFSBCOPY(nfsrv_dnsname, cp, nfsrv_dnsnamelen); 2780 } 2781 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2782 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2783 NFSUNLOCKNAMEID(); 2784 return; 2785 } 2786 } 2787 NFSUNLOCKNAMEID(); 2788 cnt++; 2789 ret = nfsrv_getuser(RPCNFSUSERD_GETGID, (uid_t)0, gid, 2790 NULL, p); 2791 if (ret == 0 && cnt < 2) 2792 goto tryagain; 2793 } else { 2794 NFSUNLOCKNAMEID(); 2795 } 2796 2797 /* 2798 * No match, just return a string of digits. 2799 */ 2800 tmp = gid; 2801 i = 0; 2802 while (tmp || i == 0) { 2803 tmp /= 10; 2804 i++; 2805 } 2806 len = (i > len) ? len : i; 2807 *retlenp = len; 2808 cp += (len - 1); 2809 tmp = gid; 2810 for (i = 0; i < len; i++) { 2811 *cp-- = '0' + (tmp % 10); 2812 tmp /= 10; 2813 } 2814 return; 2815 } 2816 2817 /* 2818 * Convert a string to a gid. 2819 * If no conversion is possible return NFSERR_BADOWNER, otherwise 2820 * return 0. 2821 * If this is called from a client side mount using AUTH_SYS and the 2822 * string is made up entirely of digits, just convert the string to 2823 * a number. 2824 */ 2825 APPLESTATIC int 2826 nfsv4_strtogid(struct nfsrv_descript *nd, u_char *str, int len, gid_t *gidp, 2827 NFSPROC_T *p) 2828 { 2829 int i; 2830 char *cp, *endstr, *str0; 2831 struct nfsusrgrp *usrp; 2832 int cnt, ret; 2833 int error = 0; 2834 gid_t tgid; 2835 2836 if (len == 0) { 2837 error = NFSERR_BADOWNER; 2838 goto out; 2839 } 2840 /* If a string of digits and an AUTH_SYS mount, just convert it. */ 2841 str0 = str; 2842 tgid = (gid_t)strtoul(str0, &endstr, 10); 2843 if ((endstr - str0) == len && 2844 (nd->nd_flag & (ND_KERBV | ND_NFSCL)) == ND_NFSCL) { 2845 *gidp = tgid; 2846 goto out; 2847 } 2848 /* 2849 * Look for an '@'. 2850 */ 2851 cp = strchr(str0, '@'); 2852 if (cp != NULL) 2853 i = (int)(cp++ - str0); 2854 else 2855 i = len; 2856 2857 cnt = 0; 2858 tryagain: 2859 NFSLOCKNAMEID(); 2860 /* 2861 * If an '@' is found and the dns name matches, search for the name 2862 * with the dns stripped off. 2863 */ 2864 if (cnt == 0 && i < len && i > 0 && nfsrv_dnsname && 2865 (len - 1 - i) == nfsrv_dnsnamelen && 2866 !nfsrv_cmpmixedcase(cp, nfsrv_dnsname, nfsrv_dnsnamelen)) { 2867 len -= (nfsrv_dnsnamelen + 1); 2868 *(cp - 1) = '\0'; 2869 } 2870 2871 /* 2872 * Check for the special case of "nogroup". 2873 */ 2874 if (len == 7 && !NFSBCMP(str, "nogroup", 7)) { 2875 *gidp = nfsrv_defaultgid; 2876 NFSUNLOCKNAMEID(); 2877 error = 0; 2878 goto out; 2879 } 2880 2881 LIST_FOREACH(usrp, NFSGROUPNAMEHASH(str, len), lug_namehash) { 2882 if (usrp->lug_namelen == len && 2883 !NFSBCMP(usrp->lug_name, str, len)) { 2884 if (usrp->lug_expiry < NFSD_MONOSEC) 2885 break; 2886 *gidp = usrp->lug_gid; 2887 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 2888 TAILQ_INSERT_TAIL(&nfsuserlruhead, usrp, lug_lru); 2889 NFSUNLOCKNAMEID(); 2890 error = 0; 2891 goto out; 2892 } 2893 } 2894 NFSUNLOCKNAMEID(); 2895 cnt++; 2896 ret = nfsrv_getuser(RPCNFSUSERD_GETGROUP, (uid_t)0, (gid_t)0, 2897 str, p); 2898 if (ret == 0 && cnt < 2) 2899 goto tryagain; 2900 error = NFSERR_BADOWNER; 2901 2902 out: 2903 NFSEXITCODE(error); 2904 return (error); 2905 } 2906 2907 /* 2908 * Cmp len chars, allowing mixed case in the first argument to match lower 2909 * case in the second, but not if the first argument is all upper case. 2910 * Return 0 for a match, 1 otherwise. 2911 */ 2912 static int 2913 nfsrv_cmpmixedcase(u_char *cp, u_char *cp2, int len) 2914 { 2915 int i; 2916 u_char tmp; 2917 int fndlower = 0; 2918 2919 for (i = 0; i < len; i++) { 2920 if (*cp >= 'A' && *cp <= 'Z') { 2921 tmp = *cp++ + ('a' - 'A'); 2922 } else { 2923 tmp = *cp++; 2924 if (tmp >= 'a' && tmp <= 'z') 2925 fndlower = 1; 2926 } 2927 if (tmp != *cp2++) 2928 return (1); 2929 } 2930 if (fndlower) 2931 return (0); 2932 else 2933 return (1); 2934 } 2935 2936 /* 2937 * Set the port for the nfsuserd. 2938 */ 2939 APPLESTATIC int 2940 nfsrv_nfsuserdport(u_short port, NFSPROC_T *p) 2941 { 2942 struct nfssockreq *rp; 2943 struct sockaddr_in *ad; 2944 int error; 2945 2946 NFSLOCKNAMEID(); 2947 if (nfsrv_nfsuserd) { 2948 NFSUNLOCKNAMEID(); 2949 error = EPERM; 2950 goto out; 2951 } 2952 nfsrv_nfsuserd = 1; 2953 NFSUNLOCKNAMEID(); 2954 /* 2955 * Set up the socket record and connect. 2956 */ 2957 rp = &nfsrv_nfsuserdsock; 2958 rp->nr_client = NULL; 2959 rp->nr_sotype = SOCK_DGRAM; 2960 rp->nr_soproto = IPPROTO_UDP; 2961 rp->nr_lock = (NFSR_RESERVEDPORT | NFSR_LOCALHOST); 2962 rp->nr_cred = NULL; 2963 NFSSOCKADDRALLOC(rp->nr_nam); 2964 NFSSOCKADDRSIZE(rp->nr_nam, sizeof (struct sockaddr_in)); 2965 ad = NFSSOCKADDR(rp->nr_nam, struct sockaddr_in *); 2966 ad->sin_family = AF_INET; 2967 ad->sin_addr.s_addr = htonl((u_int32_t)0x7f000001); /* 127.0.0.1 */ 2968 ad->sin_port = port; 2969 rp->nr_prog = RPCPROG_NFSUSERD; 2970 rp->nr_vers = RPCNFSUSERD_VERS; 2971 error = newnfs_connect(NULL, rp, NFSPROCCRED(p), p, 0); 2972 if (error) { 2973 NFSSOCKADDRFREE(rp->nr_nam); 2974 nfsrv_nfsuserd = 0; 2975 } 2976 out: 2977 NFSEXITCODE(error); 2978 return (error); 2979 } 2980 2981 /* 2982 * Delete the nfsuserd port. 2983 */ 2984 APPLESTATIC void 2985 nfsrv_nfsuserddelport(void) 2986 { 2987 2988 NFSLOCKNAMEID(); 2989 if (nfsrv_nfsuserd == 0) { 2990 NFSUNLOCKNAMEID(); 2991 return; 2992 } 2993 nfsrv_nfsuserd = 0; 2994 NFSUNLOCKNAMEID(); 2995 newnfs_disconnect(&nfsrv_nfsuserdsock); 2996 NFSSOCKADDRFREE(nfsrv_nfsuserdsock.nr_nam); 2997 } 2998 2999 /* 3000 * Do upcalls to the nfsuserd, for cache misses of the owner/ownergroup 3001 * name<-->id cache. 3002 * Returns 0 upon success, non-zero otherwise. 3003 */ 3004 static int 3005 nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name, NFSPROC_T *p) 3006 { 3007 u_int32_t *tl; 3008 struct nfsrv_descript *nd; 3009 int len; 3010 struct nfsrv_descript nfsd; 3011 struct ucred *cred; 3012 int error; 3013 3014 NFSLOCKNAMEID(); 3015 if (nfsrv_nfsuserd == 0) { 3016 NFSUNLOCKNAMEID(); 3017 error = EPERM; 3018 goto out; 3019 } 3020 NFSUNLOCKNAMEID(); 3021 nd = &nfsd; 3022 cred = newnfs_getcred(); 3023 nd->nd_flag = ND_GSSINITREPLY; 3024 nfsrvd_rephead(nd); 3025 3026 nd->nd_procnum = procnum; 3027 if (procnum == RPCNFSUSERD_GETUID || procnum == RPCNFSUSERD_GETGID) { 3028 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3029 if (procnum == RPCNFSUSERD_GETUID) 3030 *tl = txdr_unsigned(uid); 3031 else 3032 *tl = txdr_unsigned(gid); 3033 } else { 3034 len = strlen(name); 3035 (void) nfsm_strtom(nd, name, len); 3036 } 3037 error = newnfs_request(nd, NULL, NULL, &nfsrv_nfsuserdsock, NULL, NULL, 3038 cred, RPCPROG_NFSUSERD, RPCNFSUSERD_VERS, NULL, 0, NULL, NULL); 3039 NFSFREECRED(cred); 3040 if (!error) { 3041 mbuf_freem(nd->nd_mrep); 3042 error = nd->nd_repstat; 3043 } 3044 out: 3045 NFSEXITCODE(error); 3046 return (error); 3047 } 3048 3049 /* 3050 * This function is called from the nfssvc(2) system call, to update the 3051 * kernel user/group name list(s) for the V4 owner and ownergroup attributes. 3052 */ 3053 APPLESTATIC int 3054 nfssvc_idname(struct nfsd_idargs *nidp) 3055 { 3056 struct nfsusrgrp *nusrp, *usrp, *newusrp; 3057 struct nfsuserhashhead *hp; 3058 int i; 3059 int error = 0; 3060 u_char *cp; 3061 3062 if (nidp->nid_flag & NFSID_INITIALIZE) { 3063 cp = (u_char *)malloc(nidp->nid_namelen + 1, 3064 M_NFSSTRING, M_WAITOK); 3065 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), cp, 3066 nidp->nid_namelen); 3067 NFSLOCKNAMEID(); 3068 if (nfsrv_dnsname) { 3069 /* 3070 * Free up all the old stuff and reinitialize hash lists. 3071 */ 3072 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 3073 nfsrv_removeuser(usrp); 3074 } 3075 free(nfsrv_dnsname, M_NFSSTRING); 3076 nfsrv_dnsname = NULL; 3077 } 3078 TAILQ_INIT(&nfsuserlruhead); 3079 for (i = 0; i < NFSUSERHASHSIZE; i++) 3080 LIST_INIT(&nfsuserhash[i]); 3081 for (i = 0; i < NFSGROUPHASHSIZE; i++) 3082 LIST_INIT(&nfsgrouphash[i]); 3083 for (i = 0; i < NFSUSERHASHSIZE; i++) 3084 LIST_INIT(&nfsusernamehash[i]); 3085 for (i = 0; i < NFSGROUPHASHSIZE; i++) 3086 LIST_INIT(&nfsgroupnamehash[i]); 3087 3088 /* 3089 * Put name in "DNS" string. 3090 */ 3091 if (!error) { 3092 nfsrv_dnsname = cp; 3093 nfsrv_dnsnamelen = nidp->nid_namelen; 3094 nfsrv_defaultuid = nidp->nid_uid; 3095 nfsrv_defaultgid = nidp->nid_gid; 3096 nfsrv_usercnt = 0; 3097 nfsrv_usermax = nidp->nid_usermax; 3098 } 3099 NFSUNLOCKNAMEID(); 3100 if (error) 3101 free(cp, M_NFSSTRING); 3102 goto out; 3103 } 3104 3105 /* 3106 * malloc the new one now, so any potential sleep occurs before 3107 * manipulation of the lists. 3108 */ 3109 MALLOC(newusrp, struct nfsusrgrp *, sizeof (struct nfsusrgrp) + 3110 nidp->nid_namelen, M_NFSUSERGROUP, M_WAITOK); 3111 error = copyin(CAST_USER_ADDR_T(nidp->nid_name), newusrp->lug_name, 3112 nidp->nid_namelen); 3113 if (error) { 3114 free((caddr_t)newusrp, M_NFSUSERGROUP); 3115 goto out; 3116 } 3117 newusrp->lug_namelen = nidp->nid_namelen; 3118 3119 NFSLOCKNAMEID(); 3120 /* 3121 * Delete old entries, as required. 3122 */ 3123 if (nidp->nid_flag & (NFSID_DELUID | NFSID_ADDUID)) { 3124 hp = NFSUSERHASH(nidp->nid_uid); 3125 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 3126 if (usrp->lug_uid == nidp->nid_uid) 3127 nfsrv_removeuser(usrp); 3128 } 3129 } 3130 if (nidp->nid_flag & (NFSID_DELUSERNAME | NFSID_ADDUSERNAME)) { 3131 hp = NFSUSERNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3132 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 3133 if (usrp->lug_namelen == newusrp->lug_namelen && 3134 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3135 usrp->lug_namelen)) 3136 nfsrv_removeuser(usrp); 3137 } 3138 } 3139 if (nidp->nid_flag & (NFSID_DELGID | NFSID_ADDGID)) { 3140 hp = NFSGROUPHASH(nidp->nid_gid); 3141 LIST_FOREACH_SAFE(usrp, hp, lug_numhash, nusrp) { 3142 if (usrp->lug_gid == nidp->nid_gid) 3143 nfsrv_removeuser(usrp); 3144 } 3145 } 3146 if (nidp->nid_flag & (NFSID_DELGROUPNAME | NFSID_ADDGROUPNAME)) { 3147 hp = NFSGROUPNAMEHASH(newusrp->lug_name, newusrp->lug_namelen); 3148 LIST_FOREACH_SAFE(usrp, hp, lug_namehash, nusrp) { 3149 if (usrp->lug_namelen == newusrp->lug_namelen && 3150 !NFSBCMP(usrp->lug_name, newusrp->lug_name, 3151 usrp->lug_namelen)) 3152 nfsrv_removeuser(usrp); 3153 } 3154 } 3155 TAILQ_FOREACH_SAFE(usrp, &nfsuserlruhead, lug_lru, nusrp) { 3156 if (usrp->lug_expiry < NFSD_MONOSEC) 3157 nfsrv_removeuser(usrp); 3158 } 3159 while (nfsrv_usercnt >= nfsrv_usermax) { 3160 usrp = TAILQ_FIRST(&nfsuserlruhead); 3161 nfsrv_removeuser(usrp); 3162 } 3163 3164 /* 3165 * Now, we can add the new one. 3166 */ 3167 if (nidp->nid_usertimeout) 3168 newusrp->lug_expiry = NFSD_MONOSEC + nidp->nid_usertimeout; 3169 else 3170 newusrp->lug_expiry = NFSD_MONOSEC + 5; 3171 if (nidp->nid_flag & (NFSID_ADDUID | NFSID_ADDUSERNAME)) { 3172 newusrp->lug_uid = nidp->nid_uid; 3173 LIST_INSERT_HEAD(NFSUSERHASH(newusrp->lug_uid), newusrp, 3174 lug_numhash); 3175 LIST_INSERT_HEAD(NFSUSERNAMEHASH(newusrp->lug_name, 3176 newusrp->lug_namelen), newusrp, lug_namehash); 3177 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3178 nfsrv_usercnt++; 3179 } else if (nidp->nid_flag & (NFSID_ADDGID | NFSID_ADDGROUPNAME)) { 3180 newusrp->lug_gid = nidp->nid_gid; 3181 LIST_INSERT_HEAD(NFSGROUPHASH(newusrp->lug_gid), newusrp, 3182 lug_numhash); 3183 LIST_INSERT_HEAD(NFSGROUPNAMEHASH(newusrp->lug_name, 3184 newusrp->lug_namelen), newusrp, lug_namehash); 3185 TAILQ_INSERT_TAIL(&nfsuserlruhead, newusrp, lug_lru); 3186 nfsrv_usercnt++; 3187 } else 3188 FREE((caddr_t)newusrp, M_NFSUSERGROUP); 3189 NFSUNLOCKNAMEID(); 3190 out: 3191 NFSEXITCODE(error); 3192 return (error); 3193 } 3194 3195 /* 3196 * Remove a user/group name element. 3197 */ 3198 static void 3199 nfsrv_removeuser(struct nfsusrgrp *usrp) 3200 { 3201 3202 NFSNAMEIDREQUIRED(); 3203 LIST_REMOVE(usrp, lug_numhash); 3204 LIST_REMOVE(usrp, lug_namehash); 3205 TAILQ_REMOVE(&nfsuserlruhead, usrp, lug_lru); 3206 nfsrv_usercnt--; 3207 FREE((caddr_t)usrp, M_NFSUSERGROUP); 3208 } 3209 3210 /* 3211 * This function scans a byte string and checks for UTF-8 compliance. 3212 * It returns 0 if it conforms and NFSERR_INVAL if not. 3213 */ 3214 APPLESTATIC int 3215 nfsrv_checkutf8(u_int8_t *cp, int len) 3216 { 3217 u_int32_t val = 0x0; 3218 int cnt = 0, gotd = 0, shift = 0; 3219 u_int8_t byte; 3220 static int utf8_shift[5] = { 7, 11, 16, 21, 26 }; 3221 int error = 0; 3222 3223 /* 3224 * Here are what the variables are used for: 3225 * val - the calculated value of a multibyte char, used to check 3226 * that it was coded with the correct range 3227 * cnt - the number of 10xxxxxx bytes to follow 3228 * gotd - set for a char of Dxxx, so D800<->DFFF can be checked for 3229 * shift - lower order bits of range (ie. "val >> shift" should 3230 * not be 0, in other words, dividing by the lower bound 3231 * of the range should get a non-zero value) 3232 * byte - used to calculate cnt 3233 */ 3234 while (len > 0) { 3235 if (cnt > 0) { 3236 /* This handles the 10xxxxxx bytes */ 3237 if ((*cp & 0xc0) != 0x80 || 3238 (gotd && (*cp & 0x20))) { 3239 error = NFSERR_INVAL; 3240 goto out; 3241 } 3242 gotd = 0; 3243 val <<= 6; 3244 val |= (*cp & 0x3f); 3245 cnt--; 3246 if (cnt == 0 && (val >> shift) == 0x0) { 3247 error = NFSERR_INVAL; 3248 goto out; 3249 } 3250 } else if (*cp & 0x80) { 3251 /* first byte of multi byte char */ 3252 byte = *cp; 3253 while ((byte & 0x40) && cnt < 6) { 3254 cnt++; 3255 byte <<= 1; 3256 } 3257 if (cnt == 0 || cnt == 6) { 3258 error = NFSERR_INVAL; 3259 goto out; 3260 } 3261 val = (*cp & (0x3f >> cnt)); 3262 shift = utf8_shift[cnt - 1]; 3263 if (cnt == 2 && val == 0xd) 3264 /* Check for the 0xd800-0xdfff case */ 3265 gotd = 1; 3266 } 3267 cp++; 3268 len--; 3269 } 3270 if (cnt > 0) 3271 error = NFSERR_INVAL; 3272 3273 out: 3274 NFSEXITCODE(error); 3275 return (error); 3276 } 3277 3278 /* 3279 * Parse the xdr for an NFSv4 FsLocations attribute. Return two malloc'd 3280 * strings, one with the root path in it and the other with the list of 3281 * locations. The list is in the same format as is found in nfr_refs. 3282 * It is a "," separated list of entries, where each of them is of the 3283 * form <server>:<rootpath>. For example 3284 * "nfsv4-test:/sub2,nfsv4-test2:/user/mnt,nfsv4-test2:/user/mnt2" 3285 * The nilp argument is set to 1 for the special case of a null fs_root 3286 * and an empty server list. 3287 * It returns NFSERR_BADXDR, if the xdr can't be parsed and returns the 3288 * number of xdr bytes parsed in sump. 3289 */ 3290 static int 3291 nfsrv_getrefstr(struct nfsrv_descript *nd, u_char **fsrootp, u_char **srvp, 3292 int *sump, int *nilp) 3293 { 3294 u_int32_t *tl; 3295 u_char *cp = NULL, *cp2 = NULL, *cp3, *str; 3296 int i, j, len, stringlen, cnt, slen, siz, xdrsum, error = 0, nsrv; 3297 struct list { 3298 SLIST_ENTRY(list) next; 3299 int len; 3300 u_char host[1]; 3301 } *lsp, *nlsp; 3302 SLIST_HEAD(, list) head; 3303 3304 *fsrootp = NULL; 3305 *srvp = NULL; 3306 *nilp = 0; 3307 3308 /* 3309 * Get the fs_root path and check for the special case of null path 3310 * and 0 length server list. 3311 */ 3312 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3313 len = fxdr_unsigned(int, *tl); 3314 if (len < 0 || len > 10240) { 3315 error = NFSERR_BADXDR; 3316 goto nfsmout; 3317 } 3318 if (len == 0) { 3319 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3320 if (*tl != 0) { 3321 error = NFSERR_BADXDR; 3322 goto nfsmout; 3323 } 3324 *nilp = 1; 3325 *sump = 2 * NFSX_UNSIGNED; 3326 error = 0; 3327 goto nfsmout; 3328 } 3329 cp = malloc(len + 1, M_NFSSTRING, M_WAITOK); 3330 error = nfsrv_mtostr(nd, cp, len); 3331 if (!error) { 3332 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3333 cnt = fxdr_unsigned(int, *tl); 3334 if (cnt <= 0) 3335 error = NFSERR_BADXDR; 3336 } 3337 if (error) 3338 goto nfsmout; 3339 3340 /* 3341 * Now, loop through the location list and make up the srvlist. 3342 */ 3343 xdrsum = (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3344 cp2 = cp3 = malloc(1024, M_NFSSTRING, M_WAITOK); 3345 slen = 1024; 3346 siz = 0; 3347 for (i = 0; i < cnt; i++) { 3348 SLIST_INIT(&head); 3349 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3350 nsrv = fxdr_unsigned(int, *tl); 3351 if (nsrv <= 0) { 3352 error = NFSERR_BADXDR; 3353 goto nfsmout; 3354 } 3355 3356 /* 3357 * Handle the first server by putting it in the srvstr. 3358 */ 3359 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3360 len = fxdr_unsigned(int, *tl); 3361 if (len <= 0 || len > 1024) { 3362 error = NFSERR_BADXDR; 3363 goto nfsmout; 3364 } 3365 nfsrv_refstrbigenough(siz + len + 3, &cp2, &cp3, &slen); 3366 if (cp3 != cp2) { 3367 *cp3++ = ','; 3368 siz++; 3369 } 3370 error = nfsrv_mtostr(nd, cp3, len); 3371 if (error) 3372 goto nfsmout; 3373 cp3 += len; 3374 *cp3++ = ':'; 3375 siz += (len + 1); 3376 xdrsum += (2 * NFSX_UNSIGNED) + NFSM_RNDUP(len); 3377 for (j = 1; j < nsrv; j++) { 3378 /* 3379 * Yuck, put them in an slist and process them later. 3380 */ 3381 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3382 len = fxdr_unsigned(int, *tl); 3383 if (len <= 0 || len > 1024) { 3384 error = NFSERR_BADXDR; 3385 goto nfsmout; 3386 } 3387 lsp = (struct list *)malloc(sizeof (struct list) 3388 + len, M_TEMP, M_WAITOK); 3389 error = nfsrv_mtostr(nd, lsp->host, len); 3390 if (error) 3391 goto nfsmout; 3392 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3393 lsp->len = len; 3394 SLIST_INSERT_HEAD(&head, lsp, next); 3395 } 3396 3397 /* 3398 * Finally, we can get the path. 3399 */ 3400 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3401 len = fxdr_unsigned(int, *tl); 3402 if (len <= 0 || len > 1024) { 3403 error = NFSERR_BADXDR; 3404 goto nfsmout; 3405 } 3406 nfsrv_refstrbigenough(siz + len + 1, &cp2, &cp3, &slen); 3407 error = nfsrv_mtostr(nd, cp3, len); 3408 if (error) 3409 goto nfsmout; 3410 xdrsum += NFSX_UNSIGNED + NFSM_RNDUP(len); 3411 str = cp3; 3412 stringlen = len; 3413 cp3 += len; 3414 siz += len; 3415 SLIST_FOREACH_SAFE(lsp, &head, next, nlsp) { 3416 nfsrv_refstrbigenough(siz + lsp->len + stringlen + 3, 3417 &cp2, &cp3, &slen); 3418 *cp3++ = ','; 3419 NFSBCOPY(lsp->host, cp3, lsp->len); 3420 cp3 += lsp->len; 3421 *cp3++ = ':'; 3422 NFSBCOPY(str, cp3, stringlen); 3423 cp3 += stringlen; 3424 *cp3 = '\0'; 3425 siz += (lsp->len + stringlen + 2); 3426 free((caddr_t)lsp, M_TEMP); 3427 } 3428 } 3429 *fsrootp = cp; 3430 *srvp = cp2; 3431 *sump = xdrsum; 3432 NFSEXITCODE2(0, nd); 3433 return (0); 3434 nfsmout: 3435 if (cp != NULL) 3436 free(cp, M_NFSSTRING); 3437 if (cp2 != NULL) 3438 free(cp2, M_NFSSTRING); 3439 NFSEXITCODE2(error, nd); 3440 return (error); 3441 } 3442 3443 /* 3444 * Make the malloc'd space large enough. This is a pain, but the xdr 3445 * doesn't set an upper bound on the side, so... 3446 */ 3447 static void 3448 nfsrv_refstrbigenough(int siz, u_char **cpp, u_char **cpp2, int *slenp) 3449 { 3450 u_char *cp; 3451 int i; 3452 3453 if (siz <= *slenp) 3454 return; 3455 cp = malloc(siz + 1024, M_NFSSTRING, M_WAITOK); 3456 NFSBCOPY(*cpp, cp, *slenp); 3457 free(*cpp, M_NFSSTRING); 3458 i = *cpp2 - *cpp; 3459 *cpp = cp; 3460 *cpp2 = cp + i; 3461 *slenp = siz + 1024; 3462 } 3463 3464 /* 3465 * Initialize the reply header data structures. 3466 */ 3467 APPLESTATIC void 3468 nfsrvd_rephead(struct nfsrv_descript *nd) 3469 { 3470 mbuf_t mreq; 3471 3472 /* 3473 * If this is a big reply, use a cluster. 3474 */ 3475 if ((nd->nd_flag & ND_GSSINITREPLY) == 0 && 3476 nfs_bigreply[nd->nd_procnum]) { 3477 NFSMCLGET(mreq, M_WAITOK); 3478 nd->nd_mreq = mreq; 3479 nd->nd_mb = mreq; 3480 } else { 3481 NFSMGET(mreq); 3482 nd->nd_mreq = mreq; 3483 nd->nd_mb = mreq; 3484 } 3485 nd->nd_bpos = NFSMTOD(mreq, caddr_t); 3486 mbuf_setlen(mreq, 0); 3487 3488 if ((nd->nd_flag & ND_GSSINITREPLY) == 0) 3489 NFSM_BUILD(nd->nd_errp, int *, NFSX_UNSIGNED); 3490 } 3491 3492 /* 3493 * Lock a socket against others. 3494 * Currently used to serialize connect/disconnect attempts. 3495 */ 3496 int 3497 newnfs_sndlock(int *flagp) 3498 { 3499 struct timespec ts; 3500 3501 NFSLOCKSOCK(); 3502 while (*flagp & NFSR_SNDLOCK) { 3503 *flagp |= NFSR_WANTSND; 3504 ts.tv_sec = 0; 3505 ts.tv_nsec = 0; 3506 (void) nfsmsleep((caddr_t)flagp, NFSSOCKMUTEXPTR, 3507 PZERO - 1, "nfsndlck", &ts); 3508 } 3509 *flagp |= NFSR_SNDLOCK; 3510 NFSUNLOCKSOCK(); 3511 return (0); 3512 } 3513 3514 /* 3515 * Unlock the stream socket for others. 3516 */ 3517 void 3518 newnfs_sndunlock(int *flagp) 3519 { 3520 3521 NFSLOCKSOCK(); 3522 if ((*flagp & NFSR_SNDLOCK) == 0) 3523 panic("nfs sndunlock"); 3524 *flagp &= ~NFSR_SNDLOCK; 3525 if (*flagp & NFSR_WANTSND) { 3526 *flagp &= ~NFSR_WANTSND; 3527 wakeup((caddr_t)flagp); 3528 } 3529 NFSUNLOCKSOCK(); 3530 } 3531 3532 APPLESTATIC int 3533 nfsv4_getipaddr(struct nfsrv_descript *nd, struct sockaddr_storage *sa, 3534 int *isudp) 3535 { 3536 struct sockaddr_in *sad; 3537 struct sockaddr_in6 *sad6; 3538 struct in_addr saddr; 3539 uint32_t portnum, *tl; 3540 int af = 0, i, j, k; 3541 char addr[64], protocol[5], *cp; 3542 int cantparse = 0, error = 0; 3543 uint16_t portv; 3544 3545 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3546 i = fxdr_unsigned(int, *tl); 3547 if (i >= 3 && i <= 4) { 3548 error = nfsrv_mtostr(nd, protocol, i); 3549 if (error) 3550 goto nfsmout; 3551 if (strcmp(protocol, "tcp") == 0) { 3552 af = AF_INET; 3553 *isudp = 0; 3554 } else if (strcmp(protocol, "udp") == 0) { 3555 af = AF_INET; 3556 *isudp = 1; 3557 } else if (strcmp(protocol, "tcp6") == 0) { 3558 af = AF_INET6; 3559 *isudp = 0; 3560 } else if (strcmp(protocol, "udp6") == 0) { 3561 af = AF_INET6; 3562 *isudp = 1; 3563 } else 3564 cantparse = 1; 3565 } else { 3566 cantparse = 1; 3567 if (i > 0) { 3568 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3569 if (error) 3570 goto nfsmout; 3571 } 3572 } 3573 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3574 i = fxdr_unsigned(int, *tl); 3575 if (i < 0) { 3576 error = NFSERR_BADXDR; 3577 goto nfsmout; 3578 } else if (cantparse == 0 && i >= 11 && i < 64) { 3579 /* 3580 * The shortest address is 11chars and the longest is < 64. 3581 */ 3582 error = nfsrv_mtostr(nd, addr, i); 3583 if (error) 3584 goto nfsmout; 3585 3586 /* Find the port# at the end and extract that. */ 3587 i = strlen(addr); 3588 k = 0; 3589 cp = &addr[i - 1]; 3590 /* Count back two '.'s from end to get port# field. */ 3591 for (j = 0; j < i; j++) { 3592 if (*cp == '.') { 3593 k++; 3594 if (k == 2) 3595 break; 3596 } 3597 cp--; 3598 } 3599 if (k == 2) { 3600 /* 3601 * The NFSv4 port# is appended as .N.N, where N is 3602 * a decimal # in the range 0-255, just like an inet4 3603 * address. Cheat and use inet_aton(), which will 3604 * return a Class A address and then shift the high 3605 * order 8bits over to convert it to the port#. 3606 */ 3607 *cp++ = '\0'; 3608 if (inet_aton(cp, &saddr) == 1) { 3609 portnum = ntohl(saddr.s_addr); 3610 portv = (uint16_t)((portnum >> 16) | 3611 (portnum & 0xff)); 3612 } else 3613 cantparse = 1; 3614 } else 3615 cantparse = 1; 3616 if (cantparse == 0) { 3617 if (af == AF_INET) { 3618 sad = (struct sockaddr_in *)sa; 3619 if (inet_pton(af, addr, &sad->sin_addr) == 1) { 3620 sad->sin_len = sizeof(*sad); 3621 sad->sin_family = AF_INET; 3622 sad->sin_port = htons(portv); 3623 return (0); 3624 } 3625 } else { 3626 sad6 = (struct sockaddr_in6 *)sa; 3627 if (inet_pton(af, addr, &sad6->sin6_addr) 3628 == 1) { 3629 sad6->sin6_len = sizeof(*sad6); 3630 sad6->sin6_family = AF_INET6; 3631 sad6->sin6_port = htons(portv); 3632 return (0); 3633 } 3634 } 3635 } 3636 } else { 3637 if (i > 0) { 3638 error = nfsm_advance(nd, NFSM_RNDUP(i), -1); 3639 if (error) 3640 goto nfsmout; 3641 } 3642 } 3643 error = EPERM; 3644 nfsmout: 3645 return (error); 3646 } 3647 3648 /* 3649 * Handle an NFSv4.1 Sequence request for the session. 3650 */ 3651 int 3652 nfsv4_seqsession(uint32_t seqid, uint32_t slotid, uint32_t highslot, 3653 struct nfsslot *slots, struct mbuf **reply, uint16_t maxslot) 3654 { 3655 int error; 3656 3657 error = 0; 3658 *reply = NULL; 3659 if (slotid > maxslot) 3660 return (NFSERR_BADSLOT); 3661 if (seqid == slots[slotid].nfssl_seq) { 3662 /* A retry. */ 3663 if (slots[slotid].nfssl_inprog != 0) 3664 error = NFSERR_DELAY; 3665 else if (slots[slotid].nfssl_reply != NULL) { 3666 *reply = slots[slotid].nfssl_reply; 3667 slots[slotid].nfssl_reply = NULL; 3668 slots[slotid].nfssl_inprog = 1; 3669 } else 3670 error = NFSERR_SEQMISORDERED; 3671 } else if ((slots[slotid].nfssl_seq + 1) == seqid) { 3672 m_freem(slots[slotid].nfssl_reply); 3673 slots[slotid].nfssl_reply = NULL; 3674 slots[slotid].nfssl_inprog = 1; 3675 slots[slotid].nfssl_seq++; 3676 } else 3677 error = NFSERR_SEQMISORDERED; 3678 return (error); 3679 } 3680 3681 /* 3682 * Cache this reply for the slot. 3683 */ 3684 void 3685 nfsv4_seqsess_cacherep(uint32_t slotid, struct nfsslot *slots, struct mbuf *rep) 3686 { 3687 3688 slots[slotid].nfssl_reply = rep; 3689 slots[slotid].nfssl_inprog = 0; 3690 } 3691 3692 /* 3693 * Generate the xdr for an NFSv4.1 Sequence Operation. 3694 */ 3695 APPLESTATIC void 3696 nfsv4_setsequence(struct nfsrv_descript *nd, struct nfsclsession *sep, 3697 int dont_replycache) 3698 { 3699 uint32_t *tl, slotseq = 0; 3700 int i, maxslot, slotpos; 3701 uint64_t bitval; 3702 uint8_t sessionid[NFSX_V4SESSIONID]; 3703 3704 /* Find an unused slot. */ 3705 slotpos = -1; 3706 maxslot = -1; 3707 mtx_lock(&sep->nfsess_mtx); 3708 do { 3709 bitval = 1; 3710 for (i = 0; i < sep->nfsess_foreslots; i++) { 3711 if ((bitval & sep->nfsess_slots) == 0) { 3712 slotpos = i; 3713 sep->nfsess_slots |= bitval; 3714 sep->nfsess_slotseq[i]++; 3715 slotseq = sep->nfsess_slotseq[i]; 3716 break; 3717 } 3718 bitval <<= 1; 3719 } 3720 if (slotpos == -1) 3721 (void)mtx_sleep(&sep->nfsess_slots, &sep->nfsess_mtx, 3722 PZERO, "nfsclseq", 0); 3723 } while (slotpos == -1); 3724 /* Now, find the highest slot in use. (nfsc_slots is 64bits) */ 3725 bitval = 1; 3726 for (i = 0; i < 64; i++) { 3727 if ((bitval & sep->nfsess_slots) != 0) 3728 maxslot = i; 3729 bitval <<= 1; 3730 } 3731 bcopy(sep->nfsess_sessionid, sessionid, NFSX_V4SESSIONID); 3732 mtx_unlock(&sep->nfsess_mtx); 3733 KASSERT(maxslot >= 0, ("nfscl_setsequence neg maxslot")); 3734 3735 /* Build the Sequence arguments. */ 3736 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 4 * NFSX_UNSIGNED); 3737 bcopy(sessionid, tl, NFSX_V4SESSIONID); 3738 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 3739 nd->nd_slotseq = tl; 3740 *tl++ = txdr_unsigned(slotseq); 3741 *tl++ = txdr_unsigned(slotpos); 3742 *tl++ = txdr_unsigned(maxslot); 3743 if (dont_replycache == 0) 3744 *tl = newnfs_true; 3745 else 3746 *tl = newnfs_false; 3747 nd->nd_flag |= ND_HASSEQUENCE; 3748 } 3749 3750 /* 3751 * Free a session slot. 3752 */ 3753 APPLESTATIC void 3754 nfsv4_freeslot(struct nfsclsession *sep, int slot) 3755 { 3756 uint64_t bitval; 3757 3758 bitval = 1; 3759 if (slot > 0) 3760 bitval <<= slot; 3761 mtx_lock(&sep->nfsess_mtx); 3762 if ((bitval & sep->nfsess_slots) == 0) 3763 printf("freeing free slot!!\n"); 3764 sep->nfsess_slots &= ~bitval; 3765 wakeup(&sep->nfsess_slots); 3766 mtx_unlock(&sep->nfsess_mtx); 3767 } 3768 3769