nfs_nfsdserv.c revision 336179
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: stable/10/sys/fs/nfsserver/nfs_nfsdserv.c 336179 2018-07-10 19:37:52Z rmacklem $"); 36 37/* 38 * nfs version 2, 3 and 4 server calls to vnode ops 39 * - these routines generally have 3 phases 40 * 1 - break down and validate rpc request in mbuf list 41 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX() 42 * function in nfsd_port.c 43 * 3 - build the rpc reply in an mbuf list 44 * For nfsv4, these functions are called for each Op within the Compound RPC. 45 */ 46 47#ifndef APPLEKEXT 48#include <fs/nfs/nfsport.h> 49 50/* Global vars */ 51extern u_int32_t newnfs_false, newnfs_true; 52extern enum vtype nv34tov_type[8]; 53extern struct timeval nfsboottime; 54extern int nfs_rootfhset; 55extern int nfsrv_enable_crossmntpt; 56extern int nfsrv_statehashsize; 57#endif /* !APPLEKEXT */ 58 59static int nfs_async = 0; 60SYSCTL_DECL(_vfs_nfsd); 61SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, 62 "Tell client that writes were synced even though they were not"); 63 64/* 65 * This list defines the GSS mechanisms supported. 66 * (Don't ask me how you get these strings from the RFC stuff like 67 * iso(1), org(3)... but someone did it, so I don't need to know.) 68 */ 69static struct nfsgss_mechlist nfsgss_mechlist[] = { 70 { 9, "\052\206\110\206\367\022\001\002\002", 11 }, 71 { 0, "", 0 }, 72}; 73 74/* local functions */ 75static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 76 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 77 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 78 int *diraft_retp, nfsattrbit_t *attrbitp, 79 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 80 int pathlen); 81static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 82 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 83 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 84 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 85 NFSPROC_T *p, struct nfsexstuff *exp); 86 87/* 88 * nfs access service (not a part of NFS V2) 89 */ 90APPLESTATIC int 91nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram, 92 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 93{ 94 u_int32_t *tl; 95 int getret, error = 0; 96 struct nfsvattr nva; 97 u_int32_t testmode, nfsmode, supported = 0; 98 accmode_t deletebit; 99 100 if (nd->nd_repstat) { 101 nfsrv_postopattr(nd, 1, &nva); 102 goto out; 103 } 104 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 105 nfsmode = fxdr_unsigned(u_int32_t, *tl); 106 if ((nd->nd_flag & ND_NFSV4) && 107 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | 108 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | 109 NFSACCESS_EXECUTE))) { 110 nd->nd_repstat = NFSERR_INVAL; 111 vput(vp); 112 goto out; 113 } 114 if (nfsmode & NFSACCESS_READ) { 115 supported |= NFSACCESS_READ; 116 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 117 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 118 nfsmode &= ~NFSACCESS_READ; 119 } 120 if (nfsmode & NFSACCESS_MODIFY) { 121 supported |= NFSACCESS_MODIFY; 122 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 123 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 124 nfsmode &= ~NFSACCESS_MODIFY; 125 } 126 if (nfsmode & NFSACCESS_EXTEND) { 127 supported |= NFSACCESS_EXTEND; 128 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p, 129 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 130 nfsmode &= ~NFSACCESS_EXTEND; 131 } 132 if (nfsmode & NFSACCESS_DELETE) { 133 supported |= NFSACCESS_DELETE; 134 if (vp->v_type == VDIR) 135 deletebit = VDELETE_CHILD; 136 else 137 deletebit = VDELETE; 138 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p, 139 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 140 nfsmode &= ~NFSACCESS_DELETE; 141 } 142 if (vnode_vtype(vp) == VDIR) 143 testmode = NFSACCESS_LOOKUP; 144 else 145 testmode = NFSACCESS_EXECUTE; 146 if (nfsmode & testmode) { 147 supported |= (nfsmode & testmode); 148 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, 149 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 150 nfsmode &= ~testmode; 151 } 152 nfsmode &= supported; 153 if (nd->nd_flag & ND_NFSV3) { 154 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 155 nfsrv_postopattr(nd, getret, &nva); 156 } 157 vput(vp); 158 if (nd->nd_flag & ND_NFSV4) { 159 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 160 *tl++ = txdr_unsigned(supported); 161 } else 162 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 163 *tl = txdr_unsigned(nfsmode); 164 165out: 166 NFSEXITCODE2(0, nd); 167 return (0); 168nfsmout: 169 vput(vp); 170 NFSEXITCODE2(error, nd); 171 return (error); 172} 173 174/* 175 * nfs getattr service 176 */ 177APPLESTATIC int 178nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, 179 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 180{ 181 struct nfsvattr nva; 182 fhandle_t fh; 183 int at_root = 0, error = 0, supports_nfsv4acls; 184 struct nfsreferral *refp; 185 nfsattrbit_t attrbits, tmpbits; 186 struct mount *mp; 187 struct vnode *tvp = NULL; 188 struct vattr va; 189 uint64_t mounted_on_fileno = 0; 190 accmode_t accmode; 191 192 if (nd->nd_repstat) 193 goto out; 194 if (nd->nd_flag & ND_NFSV4) { 195 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 196 if (error) { 197 vput(vp); 198 goto out; 199 } 200 201 /* 202 * Check for a referral. 203 */ 204 refp = nfsv4root_getreferral(vp, NULL, 0); 205 if (refp != NULL) { 206 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1, 207 &nd->nd_repstat); 208 vput(vp); 209 goto out; 210 } 211 if (nd->nd_repstat == 0) { 212 accmode = 0; 213 NFSSET_ATTRBIT(&tmpbits, &attrbits); 214 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { 215 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); 216 accmode |= VREAD_ACL; 217 } 218 if (NFSNONZERO_ATTRBIT(&tmpbits)) 219 accmode |= VREAD_ATTRIBUTES; 220 if (accmode != 0) 221 nd->nd_repstat = nfsvno_accchk(vp, accmode, 222 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 223 NFSACCCHK_VPISLOCKED, NULL); 224 } 225 } 226 if (!nd->nd_repstat) 227 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 228 if (!nd->nd_repstat) { 229 if (nd->nd_flag & ND_NFSV4) { 230 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE)) 231 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 232 if (!nd->nd_repstat) 233 nd->nd_repstat = nfsrv_checkgetattr(nd, vp, 234 &nva, &attrbits, nd->nd_cred, p); 235 if (nd->nd_repstat == 0) { 236 supports_nfsv4acls = nfs_supportsnfsv4acls(vp); 237 mp = vp->v_mount; 238 if (nfsrv_enable_crossmntpt != 0 && 239 vp->v_type == VDIR && 240 (vp->v_vflag & VV_ROOT) != 0 && 241 vp != rootvnode) { 242 tvp = mp->mnt_vnodecovered; 243 VREF(tvp); 244 at_root = 1; 245 } else 246 at_root = 0; 247 vfs_ref(mp); 248 NFSVOPUNLOCK(vp, 0); 249 if (at_root != 0) { 250 if ((nd->nd_repstat = 251 NFSVOPLOCK(tvp, LK_SHARED)) == 0) { 252 nd->nd_repstat = VOP_GETATTR( 253 tvp, &va, nd->nd_cred); 254 vput(tvp); 255 } else 256 vrele(tvp); 257 if (nd->nd_repstat == 0) 258 mounted_on_fileno = (uint64_t) 259 va.va_fileid; 260 else 261 at_root = 0; 262 } 263 if (nd->nd_repstat == 0) 264 nd->nd_repstat = vfs_busy(mp, 0); 265 vfs_rel(mp); 266 if (nd->nd_repstat == 0) { 267 (void)nfsvno_fillattr(nd, mp, vp, &nva, 268 &fh, 0, &attrbits, nd->nd_cred, p, 269 isdgram, 1, supports_nfsv4acls, 270 at_root, mounted_on_fileno); 271 vfs_unbusy(mp); 272 } 273 vrele(vp); 274 } else 275 vput(vp); 276 } else { 277 nfsrv_fillattr(nd, &nva); 278 vput(vp); 279 } 280 } else { 281 vput(vp); 282 } 283 284out: 285 NFSEXITCODE2(error, nd); 286 return (error); 287} 288 289/* 290 * nfs setattr service 291 */ 292APPLESTATIC int 293nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, 294 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 295{ 296 struct nfsvattr nva, nva2; 297 u_int32_t *tl; 298 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0; 299 struct timespec guard = { 0, 0 }; 300 nfsattrbit_t attrbits, retbits; 301 nfsv4stateid_t stateid; 302 NFSACL_T *aclp = NULL; 303 304 if (nd->nd_repstat) { 305 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 306 goto out; 307 } 308#ifdef NFS4_ACL_EXTATTR_NAME 309 aclp = acl_alloc(M_WAITOK); 310 aclp->acl_cnt = 0; 311#endif 312 NFSVNO_ATTRINIT(&nva); 313 NFSZERO_ATTRBIT(&retbits); 314 if (nd->nd_flag & ND_NFSV4) { 315 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 316 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 317 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 318 } 319 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p); 320 if (error) 321 goto nfsmout; 322 preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1); 323 if (!nd->nd_repstat) 324 nd->nd_repstat = preat_ret; 325 if (nd->nd_flag & ND_NFSV3) { 326 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 327 gcheck = fxdr_unsigned(int, *tl); 328 if (gcheck) { 329 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 330 fxdr_nfsv3time(tl, &guard); 331 } 332 if (!nd->nd_repstat && gcheck && 333 (nva2.na_ctime.tv_sec != guard.tv_sec || 334 nva2.na_ctime.tv_nsec != guard.tv_nsec)) 335 nd->nd_repstat = NFSERR_NOT_SYNC; 336 if (nd->nd_repstat) { 337 vput(vp); 338#ifdef NFS4_ACL_EXTATTR_NAME 339 acl_free(aclp); 340#endif 341 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 342 goto out; 343 } 344 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 345 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 346 347 /* 348 * Now that we have all the fields, lets do it. 349 * If the size is being changed write access is required, otherwise 350 * just check for a read only file system. 351 */ 352 if (!nd->nd_repstat) { 353 if (NFSVNO_NOTSETSIZE(&nva)) { 354 if (NFSVNO_EXRDONLY(exp) || 355 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY)) 356 nd->nd_repstat = EROFS; 357 } else { 358 if (vnode_vtype(vp) != VREG) 359 nd->nd_repstat = EINVAL; 360 else if (nva2.na_uid != nd->nd_cred->cr_uid || 361 NFSVNO_EXSTRICTACCESS(exp)) 362 nd->nd_repstat = nfsvno_accchk(vp, 363 VWRITE, nd->nd_cred, exp, p, 364 NFSACCCHK_NOOVERRIDE, 365 NFSACCCHK_VPISLOCKED, NULL); 366 } 367 } 368 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 369 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid, 370 &nva, &attrbits, exp, p); 371 372 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 373 /* 374 * For V4, try setting the attrbutes in sets, so that the 375 * reply bitmap will be correct for an error case. 376 */ 377 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) || 378 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) { 379 NFSVNO_ATTRINIT(&nva2); 380 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid); 381 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid); 382 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 383 exp); 384 if (!nd->nd_repstat) { 385 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER)) 386 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 387 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) 388 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP); 389 } 390 } 391 if (!nd->nd_repstat && 392 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) { 393 NFSVNO_ATTRINIT(&nva2); 394 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size); 395 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 396 exp); 397 if (!nd->nd_repstat) 398 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE); 399 } 400 if (!nd->nd_repstat && 401 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) || 402 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) { 403 NFSVNO_ATTRINIT(&nva2); 404 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime); 405 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime); 406 if (nva.na_vaflags & VA_UTIMES_NULL) { 407 nva2.na_vaflags |= VA_UTIMES_NULL; 408 NFSVNO_SETACTIVE(&nva2, vaflags); 409 } 410 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 411 exp); 412 if (!nd->nd_repstat) { 413 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) 414 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET); 415 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET)) 416 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET); 417 } 418 } 419 if (!nd->nd_repstat && 420 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) { 421 NFSVNO_ATTRINIT(&nva2); 422 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); 423 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 424 exp); 425 if (!nd->nd_repstat) 426 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); 427 } 428 429#ifdef NFS4_ACL_EXTATTR_NAME 430 if (!nd->nd_repstat && aclp->acl_cnt > 0 && 431 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) { 432 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p); 433 if (!nd->nd_repstat) 434 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL); 435 } 436#endif 437 } else if (!nd->nd_repstat) { 438 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p, 439 exp); 440 } 441 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) { 442 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 443 if (!nd->nd_repstat) 444 nd->nd_repstat = postat_ret; 445 } 446 vput(vp); 447#ifdef NFS4_ACL_EXTATTR_NAME 448 acl_free(aclp); 449#endif 450 if (nd->nd_flag & ND_NFSV3) 451 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 452 else if (nd->nd_flag & ND_NFSV4) 453 (void) nfsrv_putattrbit(nd, &retbits); 454 else if (!nd->nd_repstat) 455 nfsrv_fillattr(nd, &nva); 456 457out: 458 NFSEXITCODE2(0, nd); 459 return (0); 460nfsmout: 461 vput(vp); 462#ifdef NFS4_ACL_EXTATTR_NAME 463 acl_free(aclp); 464#endif 465 if (nd->nd_flag & ND_NFSV4) { 466 /* 467 * For all nd_repstat, the V4 reply includes a bitmap, 468 * even NFSERR_BADXDR, which is what this will end up 469 * returning. 470 */ 471 (void) nfsrv_putattrbit(nd, &retbits); 472 } 473 NFSEXITCODE2(error, nd); 474 return (error); 475} 476 477/* 478 * nfs lookup rpc 479 * (Also performs lookup parent for v4) 480 */ 481APPLESTATIC int 482nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, 483 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 484 struct nfsexstuff *exp) 485{ 486 struct nameidata named; 487 vnode_t vp, dirp = NULL; 488 int error = 0, dattr_ret = 1; 489 struct nfsvattr nva, dattr; 490 char *bufp; 491 u_long *hashp; 492 493 if (nd->nd_repstat) { 494 nfsrv_postopattr(nd, dattr_ret, &dattr); 495 goto out; 496 } 497 498 /* 499 * For some reason, if dp is a symlink, the error 500 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR. 501 */ 502 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) { 503 nd->nd_repstat = NFSERR_SYMLINK; 504 vrele(dp); 505 goto out; 506 } 507 508 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 509 LOCKLEAF | SAVESTART); 510 nfsvno_setpathbuf(&named, &bufp, &hashp); 511 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 512 if (error) { 513 vrele(dp); 514 nfsvno_relpathbuf(&named); 515 goto out; 516 } 517 if (!nd->nd_repstat) { 518 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 519 } else { 520 vrele(dp); 521 nfsvno_relpathbuf(&named); 522 } 523 if (nd->nd_repstat) { 524 if (dirp) { 525 if (nd->nd_flag & ND_NFSV3) 526 dattr_ret = nfsvno_getattr(dirp, &dattr, 527 nd->nd_cred, p, 0); 528 vrele(dirp); 529 } 530 if (nd->nd_flag & ND_NFSV3) 531 nfsrv_postopattr(nd, dattr_ret, &dattr); 532 goto out; 533 } 534 if (named.ni_startdir) 535 vrele(named.ni_startdir); 536 nfsvno_relpathbuf(&named); 537 vp = named.ni_vp; 538 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && 539 vp->v_type != VDIR && vp->v_type != VLNK) 540 /* 541 * Only allow lookup of VDIR and VLNK for traversal of 542 * non-exported volumes during NFSv4 mounting. 543 */ 544 nd->nd_repstat = ENOENT; 545 if (nd->nd_repstat == 0) 546 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 547 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 548 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 549 if (vpp != NULL && nd->nd_repstat == 0) 550 *vpp = vp; 551 else 552 vput(vp); 553 if (dirp) { 554 if (nd->nd_flag & ND_NFSV3) 555 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred, 556 p, 0); 557 vrele(dirp); 558 } 559 if (nd->nd_repstat) { 560 if (nd->nd_flag & ND_NFSV3) 561 nfsrv_postopattr(nd, dattr_ret, &dattr); 562 goto out; 563 } 564 if (nd->nd_flag & ND_NFSV2) { 565 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 566 nfsrv_fillattr(nd, &nva); 567 } else if (nd->nd_flag & ND_NFSV3) { 568 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 569 nfsrv_postopattr(nd, 0, &nva); 570 nfsrv_postopattr(nd, dattr_ret, &dattr); 571 } 572 573out: 574 NFSEXITCODE2(error, nd); 575 return (error); 576} 577 578/* 579 * nfs readlink service 580 */ 581APPLESTATIC int 582nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, 583 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 584{ 585 u_int32_t *tl; 586 mbuf_t mp = NULL, mpend = NULL; 587 int getret = 1, len; 588 struct nfsvattr nva; 589 590 if (nd->nd_repstat) { 591 nfsrv_postopattr(nd, getret, &nva); 592 goto out; 593 } 594 if (vnode_vtype(vp) != VLNK) { 595 if (nd->nd_flag & ND_NFSV2) 596 nd->nd_repstat = ENXIO; 597 else 598 nd->nd_repstat = EINVAL; 599 } 600 if (!nd->nd_repstat) 601 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p, 602 &mp, &mpend, &len); 603 if (nd->nd_flag & ND_NFSV3) 604 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 605 vput(vp); 606 if (nd->nd_flag & ND_NFSV3) 607 nfsrv_postopattr(nd, getret, &nva); 608 if (nd->nd_repstat) 609 goto out; 610 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 611 *tl = txdr_unsigned(len); 612 mbuf_setnext(nd->nd_mb, mp); 613 nd->nd_mb = mpend; 614 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend); 615 616out: 617 NFSEXITCODE2(0, nd); 618 return (0); 619} 620 621/* 622 * nfs read service 623 */ 624APPLESTATIC int 625nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, 626 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 627{ 628 u_int32_t *tl; 629 int error = 0, cnt, getret = 1, reqlen, eof = 0; 630 mbuf_t m2, m3; 631 struct nfsvattr nva; 632 off_t off = 0x0; 633 struct nfsstate st, *stp = &st; 634 struct nfslock lo, *lop = &lo; 635 nfsv4stateid_t stateid; 636 nfsquad_t clientid; 637 638 if (nd->nd_repstat) { 639 nfsrv_postopattr(nd, getret, &nva); 640 goto out; 641 } 642 if (nd->nd_flag & ND_NFSV2) { 643 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 644 off = (off_t)fxdr_unsigned(u_int32_t, *tl++); 645 reqlen = fxdr_unsigned(int, *tl); 646 } else if (nd->nd_flag & ND_NFSV3) { 647 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 648 off = fxdr_hyper(tl); 649 tl += 2; 650 reqlen = fxdr_unsigned(int, *tl); 651 } else { 652 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED); 653 reqlen = fxdr_unsigned(int, *(tl + 6)); 654 } 655 if (reqlen > NFS_SRVMAXDATA(nd)) { 656 reqlen = NFS_SRVMAXDATA(nd); 657 } else if (reqlen < 0) { 658 error = EBADRPC; 659 goto nfsmout; 660 } 661 if (nd->nd_flag & ND_NFSV4) { 662 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 663 lop->lo_flags = NFSLCK_READ; 664 stp->ls_ownerlen = 0; 665 stp->ls_op = NULL; 666 stp->ls_uid = nd->nd_cred->cr_uid; 667 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 668 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 669 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 670 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 671 if ((nd->nd_flag & ND_NFSV41) != 0) 672 clientid.qval = nd->nd_clientid.qval; 673 else if (nd->nd_clientid.qval != clientid.qval) 674 printf("EEK1 multiple clids\n"); 675 } else { 676 if ((nd->nd_flag & ND_NFSV41) != 0) 677 printf("EEK! no clientid from session\n"); 678 nd->nd_flag |= ND_IMPLIEDCLID; 679 nd->nd_clientid.qval = clientid.qval; 680 } 681 stp->ls_stateid.other[2] = *tl++; 682 off = fxdr_hyper(tl); 683 lop->lo_first = off; 684 tl += 2; 685 lop->lo_end = off + reqlen; 686 /* 687 * Paranoia, just in case it wraps around. 688 */ 689 if (lop->lo_end < off) 690 lop->lo_end = NFS64BITSSET; 691 } 692 if (vnode_vtype(vp) != VREG) { 693 if (nd->nd_flag & ND_NFSV3) 694 nd->nd_repstat = EINVAL; 695 else 696 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 697 EINVAL; 698 } 699 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 700 if (!nd->nd_repstat) 701 nd->nd_repstat = getret; 702 if (!nd->nd_repstat && 703 (nva.na_uid != nd->nd_cred->cr_uid || 704 NFSVNO_EXSTRICTACCESS(exp))) { 705 nd->nd_repstat = nfsvno_accchk(vp, VREAD, 706 nd->nd_cred, exp, p, 707 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 708 if (nd->nd_repstat) 709 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 710 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 711 NFSACCCHK_VPISLOCKED, NULL); 712 } 713 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 714 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 715 &stateid, exp, nd, p); 716 if (nd->nd_repstat) { 717 vput(vp); 718 if (nd->nd_flag & ND_NFSV3) 719 nfsrv_postopattr(nd, getret, &nva); 720 goto out; 721 } 722 if (off >= nva.na_size) { 723 cnt = 0; 724 eof = 1; 725 } else if (reqlen == 0) 726 cnt = 0; 727 else if ((off + reqlen) >= nva.na_size) { 728 cnt = nva.na_size - off; 729 eof = 1; 730 } else 731 cnt = reqlen; 732 m3 = NULL; 733 if (cnt > 0) { 734 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p, 735 &m3, &m2); 736 if (!(nd->nd_flag & ND_NFSV4)) { 737 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 738 if (!nd->nd_repstat) 739 nd->nd_repstat = getret; 740 } 741 if (nd->nd_repstat) { 742 vput(vp); 743 if (m3) 744 mbuf_freem(m3); 745 if (nd->nd_flag & ND_NFSV3) 746 nfsrv_postopattr(nd, getret, &nva); 747 goto out; 748 } 749 } 750 vput(vp); 751 if (nd->nd_flag & ND_NFSV2) { 752 nfsrv_fillattr(nd, &nva); 753 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 754 } else { 755 if (nd->nd_flag & ND_NFSV3) { 756 nfsrv_postopattr(nd, getret, &nva); 757 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 758 *tl++ = txdr_unsigned(cnt); 759 } else 760 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 761 if (eof) 762 *tl++ = newnfs_true; 763 else 764 *tl++ = newnfs_false; 765 } 766 *tl = txdr_unsigned(cnt); 767 if (m3) { 768 mbuf_setnext(nd->nd_mb, m3); 769 nd->nd_mb = m2; 770 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); 771 } 772 773out: 774 NFSEXITCODE2(0, nd); 775 return (0); 776nfsmout: 777 vput(vp); 778 NFSEXITCODE2(error, nd); 779 return (error); 780} 781 782/* 783 * nfs write service 784 */ 785APPLESTATIC int 786nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram, 787 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 788{ 789 int i, cnt; 790 u_int32_t *tl; 791 mbuf_t mp; 792 struct nfsvattr nva, forat; 793 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1; 794 int stable = NFSWRITE_FILESYNC; 795 off_t off; 796 struct nfsstate st, *stp = &st; 797 struct nfslock lo, *lop = &lo; 798 nfsv4stateid_t stateid; 799 nfsquad_t clientid; 800 801 if (nd->nd_repstat) { 802 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 803 goto out; 804 } 805 if (nd->nd_flag & ND_NFSV2) { 806 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 807 off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 808 tl += 2; 809 retlen = len = fxdr_unsigned(int32_t, *tl); 810 } else if (nd->nd_flag & ND_NFSV3) { 811 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 812 off = fxdr_hyper(tl); 813 tl += 3; 814 stable = fxdr_unsigned(int, *tl++); 815 retlen = len = fxdr_unsigned(int32_t, *tl); 816 } else { 817 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED); 818 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 819 lop->lo_flags = NFSLCK_WRITE; 820 stp->ls_ownerlen = 0; 821 stp->ls_op = NULL; 822 stp->ls_uid = nd->nd_cred->cr_uid; 823 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 824 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 825 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 826 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 827 if ((nd->nd_flag & ND_NFSV41) != 0) 828 clientid.qval = nd->nd_clientid.qval; 829 else if (nd->nd_clientid.qval != clientid.qval) 830 printf("EEK2 multiple clids\n"); 831 } else { 832 if ((nd->nd_flag & ND_NFSV41) != 0) 833 printf("EEK! no clientid from session\n"); 834 nd->nd_flag |= ND_IMPLIEDCLID; 835 nd->nd_clientid.qval = clientid.qval; 836 } 837 stp->ls_stateid.other[2] = *tl++; 838 off = fxdr_hyper(tl); 839 lop->lo_first = off; 840 tl += 2; 841 stable = fxdr_unsigned(int, *tl++); 842 retlen = len = fxdr_unsigned(int32_t, *tl); 843 lop->lo_end = off + len; 844 /* 845 * Paranoia, just in case it wraps around, which shouldn't 846 * ever happen anyhow. 847 */ 848 if (lop->lo_end < lop->lo_first) 849 lop->lo_end = NFS64BITSSET; 850 } 851 852 /* 853 * Loop through the mbuf chain, counting how many mbufs are a 854 * part of this write operation, so the iovec size is known. 855 */ 856 cnt = 0; 857 mp = nd->nd_md; 858 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos; 859 while (len > 0) { 860 if (i > 0) { 861 len -= i; 862 cnt++; 863 } 864 mp = mbuf_next(mp); 865 if (!mp) { 866 if (len > 0) { 867 error = EBADRPC; 868 goto nfsmout; 869 } 870 } else 871 i = mbuf_len(mp); 872 } 873 874 if (retlen > NFS_SRVMAXIO || retlen < 0) 875 nd->nd_repstat = EIO; 876 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) { 877 if (nd->nd_flag & ND_NFSV3) 878 nd->nd_repstat = EINVAL; 879 else 880 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 881 EINVAL; 882 } 883 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1); 884 if (!nd->nd_repstat) 885 nd->nd_repstat = forat_ret; 886 if (!nd->nd_repstat && 887 (forat.na_uid != nd->nd_cred->cr_uid || 888 NFSVNO_EXSTRICTACCESS(exp))) 889 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 890 nd->nd_cred, exp, p, 891 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 892 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 893 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 894 &stateid, exp, nd, p); 895 } 896 if (nd->nd_repstat) { 897 vput(vp); 898 if (nd->nd_flag & ND_NFSV3) 899 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 900 goto out; 901 } 902 903 /* 904 * For NFS Version 2, it is not obvious what a write of zero length 905 * should do, but I might as well be consistent with Version 3, 906 * which is to return ok so long as there are no permission problems. 907 */ 908 if (retlen > 0) { 909 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable, 910 nd->nd_md, nd->nd_dpos, nd->nd_cred, p); 911 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1); 912 if (error) 913 goto nfsmout; 914 } 915 if (nd->nd_flag & ND_NFSV4) 916 aftat_ret = 0; 917 else 918 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 919 vput(vp); 920 if (!nd->nd_repstat) 921 nd->nd_repstat = aftat_ret; 922 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 923 if (nd->nd_flag & ND_NFSV3) 924 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 925 if (nd->nd_repstat) 926 goto out; 927 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 928 *tl++ = txdr_unsigned(retlen); 929 /* 930 * If nfs_async is set, then pretend the write was FILESYNC. 931 * Warning: Doing this violates RFC1813 and runs a risk 932 * of data written by a client being lost when the server 933 * crashes/reboots. 934 */ 935 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0) 936 *tl++ = txdr_unsigned(stable); 937 else 938 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); 939 /* 940 * Actually, there is no need to txdr these fields, 941 * but it may make the values more human readable, 942 * for debugging purposes. 943 */ 944 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 945 *tl = txdr_unsigned(nfsboottime.tv_usec); 946 } else if (!nd->nd_repstat) 947 nfsrv_fillattr(nd, &nva); 948 949out: 950 NFSEXITCODE2(0, nd); 951 return (0); 952nfsmout: 953 vput(vp); 954 NFSEXITCODE2(error, nd); 955 return (error); 956} 957 958/* 959 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.) 960 * now does a truncate to 0 length via. setattr if it already exists 961 * The core creation routine has been extracted out into nfsrv_creatsub(), 962 * so it can also be used by nfsrv_open() for V4. 963 */ 964APPLESTATIC int 965nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, 966 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 967{ 968 struct nfsvattr nva, dirfor, diraft; 969 struct nfsv2_sattr *sp; 970 struct nameidata named; 971 u_int32_t *tl; 972 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1; 973 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0; 974 NFSDEV_T rdev = 0; 975 vnode_t vp = NULL, dirp = NULL; 976 fhandle_t fh; 977 char *bufp; 978 u_long *hashp; 979 enum vtype vtyp; 980 int32_t cverf[2], tverf[2] = { 0, 0 }; 981 982 if (nd->nd_repstat) { 983 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 984 goto out; 985 } 986 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 987 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 988 nfsvno_setpathbuf(&named, &bufp, &hashp); 989 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 990 if (error) 991 goto nfsmout; 992 if (!nd->nd_repstat) { 993 NFSVNO_ATTRINIT(&nva); 994 if (nd->nd_flag & ND_NFSV2) { 995 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 996 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 997 if (vtyp == VNON) 998 vtyp = VREG; 999 NFSVNO_SETATTRVAL(&nva, type, vtyp); 1000 NFSVNO_SETATTRVAL(&nva, mode, 1001 nfstov_mode(sp->sa_mode)); 1002 switch (nva.na_type) { 1003 case VREG: 1004 tsize = fxdr_unsigned(int32_t, sp->sa_size); 1005 if (tsize != -1) 1006 NFSVNO_SETATTRVAL(&nva, size, 1007 (u_quad_t)tsize); 1008 break; 1009 case VCHR: 1010 case VBLK: 1011 case VFIFO: 1012 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size); 1013 break; 1014 default: 1015 break; 1016 }; 1017 } else { 1018 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1019 how = fxdr_unsigned(int, *tl); 1020 switch (how) { 1021 case NFSCREATE_GUARDED: 1022 case NFSCREATE_UNCHECKED: 1023 error = nfsrv_sattr(nd, &nva, NULL, NULL, p); 1024 if (error) 1025 goto nfsmout; 1026 break; 1027 case NFSCREATE_EXCLUSIVE: 1028 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 1029 cverf[0] = *tl++; 1030 cverf[1] = *tl; 1031 exclusive_flag = 1; 1032 break; 1033 }; 1034 NFSVNO_SETATTRVAL(&nva, type, VREG); 1035 } 1036 } 1037 if (nd->nd_repstat) { 1038 nfsvno_relpathbuf(&named); 1039 if (nd->nd_flag & ND_NFSV3) { 1040 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, 1041 p, 1); 1042 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1043 &diraft); 1044 } 1045 vput(dp); 1046 goto out; 1047 } 1048 1049 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 1050 if (dirp) { 1051 if (nd->nd_flag & ND_NFSV2) { 1052 vrele(dirp); 1053 dirp = NULL; 1054 } else { 1055 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1056 p, 0); 1057 } 1058 } 1059 if (nd->nd_repstat) { 1060 if (nd->nd_flag & ND_NFSV3) 1061 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1062 &diraft); 1063 if (dirp) 1064 vrele(dirp); 1065 goto out; 1066 } 1067 1068 if (!(nd->nd_flag & ND_NFSV2)) { 1069 switch (how) { 1070 case NFSCREATE_GUARDED: 1071 if (named.ni_vp) 1072 nd->nd_repstat = EEXIST; 1073 break; 1074 case NFSCREATE_UNCHECKED: 1075 break; 1076 case NFSCREATE_EXCLUSIVE: 1077 if (named.ni_vp == NULL) 1078 NFSVNO_SETATTRVAL(&nva, mode, 0); 1079 break; 1080 }; 1081 } 1082 1083 /* 1084 * Iff doesn't exist, create it 1085 * otherwise just truncate to 0 length 1086 * should I set the mode too ? 1087 */ 1088 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, 1089 &exclusive_flag, cverf, rdev, p, exp); 1090 1091 if (!nd->nd_repstat) { 1092 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 1093 if (!nd->nd_repstat) 1094 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 1095 p, 1); 1096 vput(vp); 1097 if (!nd->nd_repstat) { 1098 tverf[0] = nva.na_atime.tv_sec; 1099 tverf[1] = nva.na_atime.tv_nsec; 1100 } 1101 } 1102 if (nd->nd_flag & ND_NFSV2) { 1103 if (!nd->nd_repstat) { 1104 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 1105 nfsrv_fillattr(nd, &nva); 1106 } 1107 } else { 1108 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0] 1109 || cverf[1] != tverf[1])) 1110 nd->nd_repstat = EEXIST; 1111 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 1112 vrele(dirp); 1113 if (!nd->nd_repstat) { 1114 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1); 1115 nfsrv_postopattr(nd, 0, &nva); 1116 } 1117 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1118 } 1119 1120out: 1121 NFSEXITCODE2(0, nd); 1122 return (0); 1123nfsmout: 1124 vput(dp); 1125 nfsvno_relpathbuf(&named); 1126 NFSEXITCODE2(error, nd); 1127 return (error); 1128} 1129 1130/* 1131 * nfs v3 mknod service (and v4 create) 1132 */ 1133APPLESTATIC int 1134nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, 1135 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1136 struct nfsexstuff *exp) 1137{ 1138 struct nfsvattr nva, dirfor, diraft; 1139 u_int32_t *tl; 1140 struct nameidata named; 1141 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 1142 u_int32_t major, minor; 1143 enum vtype vtyp = VNON; 1144 nfstype nfs4type = NFNON; 1145 vnode_t vp, dirp = NULL; 1146 nfsattrbit_t attrbits; 1147 char *bufp = NULL, *pathcp = NULL; 1148 u_long *hashp, cnflags; 1149 NFSACL_T *aclp = NULL; 1150 1151 NFSVNO_ATTRINIT(&nva); 1152 cnflags = (LOCKPARENT | SAVESTART); 1153 if (nd->nd_repstat) { 1154 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1155 goto out; 1156 } 1157#ifdef NFS4_ACL_EXTATTR_NAME 1158 aclp = acl_alloc(M_WAITOK); 1159 aclp->acl_cnt = 0; 1160#endif 1161 1162 /* 1163 * For V4, the creation stuff is here, Yuck! 1164 */ 1165 if (nd->nd_flag & ND_NFSV4) { 1166 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1167 vtyp = nfsv34tov_type(*tl); 1168 nfs4type = fxdr_unsigned(nfstype, *tl); 1169 switch (nfs4type) { 1170 case NFLNK: 1171 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, 1172 &pathlen); 1173 if (error) 1174 goto nfsmout; 1175 break; 1176 case NFCHR: 1177 case NFBLK: 1178 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1179 major = fxdr_unsigned(u_int32_t, *tl++); 1180 minor = fxdr_unsigned(u_int32_t, *tl); 1181 nva.na_rdev = NFSMAKEDEV(major, minor); 1182 break; 1183 case NFSOCK: 1184 case NFFIFO: 1185 break; 1186 case NFDIR: 1187 cnflags = (LOCKPARENT | SAVENAME); 1188 break; 1189 default: 1190 nd->nd_repstat = NFSERR_BADTYPE; 1191 vrele(dp); 1192#ifdef NFS4_ACL_EXTATTR_NAME 1193 acl_free(aclp); 1194#endif 1195 goto out; 1196 } 1197 } 1198 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE); 1199 nfsvno_setpathbuf(&named, &bufp, &hashp); 1200 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1201 if (error) 1202 goto nfsmout; 1203 if (!nd->nd_repstat) { 1204 if (nd->nd_flag & ND_NFSV3) { 1205 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1206 vtyp = nfsv34tov_type(*tl); 1207 } 1208 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p); 1209 if (error) 1210 goto nfsmout; 1211 nva.na_type = vtyp; 1212 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 1213 (vtyp == VCHR || vtyp == VBLK)) { 1214 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1215 major = fxdr_unsigned(u_int32_t, *tl++); 1216 minor = fxdr_unsigned(u_int32_t, *tl); 1217 nva.na_rdev = NFSMAKEDEV(major, minor); 1218 } 1219 } 1220 1221 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 1222 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 1223 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && 1224 dirfor.na_gid == nva.na_gid) 1225 NFSVNO_UNSET(&nva, gid); 1226 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 1227 } 1228 if (nd->nd_repstat) { 1229 vrele(dp); 1230#ifdef NFS4_ACL_EXTATTR_NAME 1231 acl_free(aclp); 1232#endif 1233 nfsvno_relpathbuf(&named); 1234 if (pathcp) 1235 FREE(pathcp, M_TEMP); 1236 if (nd->nd_flag & ND_NFSV3) 1237 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1238 &diraft); 1239 goto out; 1240 } 1241 1242 /* 1243 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill 1244 * in va_mode, so we'll have to set a default here. 1245 */ 1246 if (NFSVNO_NOTSETMODE(&nva)) { 1247 if (vtyp == VLNK) 1248 nva.na_mode = 0755; 1249 else 1250 nva.na_mode = 0400; 1251 } 1252 1253 if (vtyp == VDIR) 1254 named.ni_cnd.cn_flags |= WILLBEDIR; 1255 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1256 if (nd->nd_repstat) { 1257 if (dirp) { 1258 if (nd->nd_flag & ND_NFSV3) 1259 dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1260 nd->nd_cred, p, 0); 1261 vrele(dirp); 1262 } 1263#ifdef NFS4_ACL_EXTATTR_NAME 1264 acl_free(aclp); 1265#endif 1266 if (nd->nd_flag & ND_NFSV3) 1267 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1268 &diraft); 1269 goto out; 1270 } 1271 if (dirp) 1272 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 1273 1274 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { 1275 if (vtyp == VDIR) { 1276 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, 1277 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, 1278 exp); 1279#ifdef NFS4_ACL_EXTATTR_NAME 1280 acl_free(aclp); 1281#endif 1282 goto out; 1283 } else if (vtyp == VLNK) { 1284 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1285 &dirfor, &diraft, &diraft_ret, &attrbits, 1286 aclp, p, exp, pathcp, pathlen); 1287#ifdef NFS4_ACL_EXTATTR_NAME 1288 acl_free(aclp); 1289#endif 1290 FREE(pathcp, M_TEMP); 1291 goto out; 1292 } 1293 } 1294 1295 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); 1296 if (!nd->nd_repstat) { 1297 vp = named.ni_vp; 1298 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); 1299 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 1300 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) 1301 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 1302 p, 1); 1303 if (vpp != NULL && nd->nd_repstat == 0) { 1304 NFSVOPUNLOCK(vp, 0); 1305 *vpp = vp; 1306 } else 1307 vput(vp); 1308 } 1309 1310 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 1311 vrele(dirp); 1312 if (!nd->nd_repstat) { 1313 if (nd->nd_flag & ND_NFSV3) { 1314 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1315 nfsrv_postopattr(nd, 0, &nva); 1316 } else { 1317 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1318 *tl++ = newnfs_false; 1319 txdr_hyper(dirfor.na_filerev, tl); 1320 tl += 2; 1321 txdr_hyper(diraft.na_filerev, tl); 1322 (void) nfsrv_putattrbit(nd, &attrbits); 1323 } 1324 } 1325 if (nd->nd_flag & ND_NFSV3) 1326 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1327#ifdef NFS4_ACL_EXTATTR_NAME 1328 acl_free(aclp); 1329#endif 1330 1331out: 1332 NFSEXITCODE2(0, nd); 1333 return (0); 1334nfsmout: 1335 vrele(dp); 1336#ifdef NFS4_ACL_EXTATTR_NAME 1337 acl_free(aclp); 1338#endif 1339 if (bufp) 1340 nfsvno_relpathbuf(&named); 1341 if (pathcp) 1342 FREE(pathcp, M_TEMP); 1343 1344 NFSEXITCODE2(error, nd); 1345 return (error); 1346} 1347 1348/* 1349 * nfs remove service 1350 */ 1351APPLESTATIC int 1352nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, 1353 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 1354{ 1355 struct nameidata named; 1356 u_int32_t *tl; 1357 int error = 0, dirfor_ret = 1, diraft_ret = 1; 1358 vnode_t dirp = NULL; 1359 struct nfsvattr dirfor, diraft; 1360 char *bufp; 1361 u_long *hashp; 1362 1363 if (nd->nd_repstat) { 1364 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1365 goto out; 1366 } 1367 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, 1368 LOCKPARENT | LOCKLEAF); 1369 nfsvno_setpathbuf(&named, &bufp, &hashp); 1370 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1371 if (error) { 1372 vput(dp); 1373 nfsvno_relpathbuf(&named); 1374 goto out; 1375 } 1376 if (!nd->nd_repstat) { 1377 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 1378 } else { 1379 vput(dp); 1380 nfsvno_relpathbuf(&named); 1381 } 1382 if (dirp) { 1383 if (!(nd->nd_flag & ND_NFSV2)) { 1384 dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1385 nd->nd_cred, p, 0); 1386 } else { 1387 vrele(dirp); 1388 dirp = NULL; 1389 } 1390 } 1391 if (!nd->nd_repstat) { 1392 if (nd->nd_flag & ND_NFSV4) { 1393 if (vnode_vtype(named.ni_vp) == VDIR) 1394 nd->nd_repstat = nfsvno_rmdirsub(&named, 1, 1395 nd->nd_cred, p, exp); 1396 else 1397 nd->nd_repstat = nfsvno_removesub(&named, 1, 1398 nd->nd_cred, p, exp); 1399 } else if (nd->nd_procnum == NFSPROC_RMDIR) { 1400 nd->nd_repstat = nfsvno_rmdirsub(&named, 0, 1401 nd->nd_cred, p, exp); 1402 } else { 1403 nd->nd_repstat = nfsvno_removesub(&named, 0, 1404 nd->nd_cred, p, exp); 1405 } 1406 } 1407 if (!(nd->nd_flag & ND_NFSV2)) { 1408 if (dirp) { 1409 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, 1410 p, 0); 1411 vrele(dirp); 1412 } 1413 if (nd->nd_flag & ND_NFSV3) { 1414 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1415 &diraft); 1416 } else if (!nd->nd_repstat) { 1417 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1418 *tl++ = newnfs_false; 1419 txdr_hyper(dirfor.na_filerev, tl); 1420 tl += 2; 1421 txdr_hyper(diraft.na_filerev, tl); 1422 } 1423 } 1424 1425out: 1426 NFSEXITCODE2(error, nd); 1427 return (error); 1428} 1429 1430/* 1431 * nfs rename service 1432 */ 1433APPLESTATIC int 1434nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, 1435 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp, 1436 struct nfsexstuff *toexp) 1437{ 1438 u_int32_t *tl; 1439 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1; 1440 int tdirfor_ret = 1, tdiraft_ret = 1; 1441 struct nameidata fromnd, tond; 1442 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; 1443 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; 1444 struct nfsexstuff tnes; 1445 struct nfsrvfh tfh; 1446 char *bufp, *tbufp = NULL; 1447 u_long *hashp; 1448 fhandle_t fh; 1449 1450 if (nd->nd_repstat) { 1451 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1452 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1453 goto out; 1454 } 1455 if (!(nd->nd_flag & ND_NFSV2)) 1456 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1); 1457 tond.ni_cnd.cn_nameiop = 0; 1458 tond.ni_startdir = NULL; 1459 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART); 1460 nfsvno_setpathbuf(&fromnd, &bufp, &hashp); 1461 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); 1462 if (error) { 1463 vput(dp); 1464 if (todp) 1465 vrele(todp); 1466 nfsvno_relpathbuf(&fromnd); 1467 goto out; 1468 } 1469 /* 1470 * Unlock dp in this code section, so it is unlocked before 1471 * tdp gets locked. This avoids a potential LOR if tdp is the 1472 * parent directory of dp. 1473 */ 1474 if (nd->nd_flag & ND_NFSV4) { 1475 tdp = todp; 1476 tnes = *toexp; 1477 if (dp != tdp) { 1478 NFSVOPUNLOCK(dp, 0); 1479 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 1480 p, 0); /* Might lock tdp. */ 1481 } else { 1482 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 1483 p, 1); 1484 NFSVOPUNLOCK(dp, 0); 1485 } 1486 } else { 1487 tfh.nfsrvfh_len = 0; 1488 error = nfsrv_mtofh(nd, &tfh); 1489 if (error == 0) 1490 error = nfsvno_getfh(dp, &fh, p); 1491 if (error) { 1492 vput(dp); 1493 /* todp is always NULL except NFSv4 */ 1494 nfsvno_relpathbuf(&fromnd); 1495 goto out; 1496 } 1497 1498 /* If this is the same file handle, just VREF() the vnode. */ 1499 if (tfh.nfsrvfh_len == NFSX_MYFH && 1500 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) { 1501 VREF(dp); 1502 tdp = dp; 1503 tnes = *exp; 1504 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 1505 p, 1); 1506 NFSVOPUNLOCK(dp, 0); 1507 } else { 1508 NFSVOPUNLOCK(dp, 0); 1509 nd->nd_cred->cr_uid = nd->nd_saveduid; 1510 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 1511 0, p); /* Locks tdp. */ 1512 if (tdp) { 1513 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, 1514 nd->nd_cred, p, 1); 1515 NFSVOPUNLOCK(tdp, 0); 1516 } 1517 } 1518 } 1519 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART); 1520 nfsvno_setpathbuf(&tond, &tbufp, &hashp); 1521 if (!nd->nd_repstat) { 1522 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); 1523 if (error) { 1524 if (tdp) 1525 vrele(tdp); 1526 vrele(dp); 1527 nfsvno_relpathbuf(&fromnd); 1528 nfsvno_relpathbuf(&tond); 1529 goto out; 1530 } 1531 } 1532 if (nd->nd_repstat) { 1533 if (nd->nd_flag & ND_NFSV3) { 1534 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 1535 &fdiraft); 1536 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 1537 &tdiraft); 1538 } 1539 if (tdp) 1540 vrele(tdp); 1541 vrele(dp); 1542 nfsvno_relpathbuf(&fromnd); 1543 nfsvno_relpathbuf(&tond); 1544 goto out; 1545 } 1546 1547 /* 1548 * Done parsing, now down to business. 1549 */ 1550 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp); 1551 if (nd->nd_repstat) { 1552 if (nd->nd_flag & ND_NFSV3) { 1553 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 1554 &fdiraft); 1555 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 1556 &tdiraft); 1557 } 1558 if (fdirp) 1559 vrele(fdirp); 1560 if (tdp) 1561 vrele(tdp); 1562 nfsvno_relpathbuf(&tond); 1563 goto out; 1564 } 1565 if (vnode_vtype(fromnd.ni_vp) == VDIR) 1566 tond.ni_cnd.cn_flags |= WILLBEDIR; 1567 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp); 1568 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat, 1569 nd->nd_flag, nd->nd_cred, p); 1570 if (fdirp) 1571 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p, 1572 0); 1573 if (tdirp) 1574 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p, 1575 0); 1576 if (fdirp) 1577 vrele(fdirp); 1578 if (tdirp) 1579 vrele(tdirp); 1580 if (nd->nd_flag & ND_NFSV3) { 1581 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1582 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1583 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1584 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 1585 *tl++ = newnfs_false; 1586 txdr_hyper(fdirfor.na_filerev, tl); 1587 tl += 2; 1588 txdr_hyper(fdiraft.na_filerev, tl); 1589 tl += 2; 1590 *tl++ = newnfs_false; 1591 txdr_hyper(tdirfor.na_filerev, tl); 1592 tl += 2; 1593 txdr_hyper(tdiraft.na_filerev, tl); 1594 } 1595 1596out: 1597 NFSEXITCODE2(error, nd); 1598 return (error); 1599} 1600 1601/* 1602 * nfs link service 1603 */ 1604APPLESTATIC int 1605nfsrvd_link(struct nfsrv_descript *nd, int isdgram, 1606 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp, 1607 struct nfsexstuff *toexp) 1608{ 1609 struct nameidata named; 1610 u_int32_t *tl; 1611 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; 1612 vnode_t dirp = NULL, dp = NULL; 1613 struct nfsvattr dirfor, diraft, at; 1614 struct nfsexstuff tnes; 1615 struct nfsrvfh dfh; 1616 char *bufp; 1617 u_long *hashp; 1618 1619 if (nd->nd_repstat) { 1620 nfsrv_postopattr(nd, getret, &at); 1621 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1622 goto out; 1623 } 1624 NFSVOPUNLOCK(vp, 0); 1625 if (vnode_vtype(vp) == VDIR) { 1626 if (nd->nd_flag & ND_NFSV4) 1627 nd->nd_repstat = NFSERR_ISDIR; 1628 else 1629 nd->nd_repstat = NFSERR_INVAL; 1630 if (tovp) 1631 vrele(tovp); 1632 } 1633 if (!nd->nd_repstat) { 1634 if (nd->nd_flag & ND_NFSV4) { 1635 dp = tovp; 1636 tnes = *toexp; 1637 } else { 1638 error = nfsrv_mtofh(nd, &dfh); 1639 if (error) { 1640 vrele(vp); 1641 /* tovp is always NULL unless NFSv4 */ 1642 goto out; 1643 } 1644 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0, 1645 p); 1646 if (dp) 1647 NFSVOPUNLOCK(dp, 0); 1648 } 1649 } 1650 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1651 LOCKPARENT | SAVENAME | NOCACHE); 1652 if (!nd->nd_repstat) { 1653 nfsvno_setpathbuf(&named, &bufp, &hashp); 1654 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1655 if (error) { 1656 vrele(vp); 1657 if (dp) 1658 vrele(dp); 1659 nfsvno_relpathbuf(&named); 1660 goto out; 1661 } 1662 if (!nd->nd_repstat) { 1663 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 1664 p, &dirp); 1665 } else { 1666 if (dp) 1667 vrele(dp); 1668 nfsvno_relpathbuf(&named); 1669 } 1670 } 1671 if (dirp) { 1672 if (nd->nd_flag & ND_NFSV2) { 1673 vrele(dirp); 1674 dirp = NULL; 1675 } else { 1676 dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1677 nd->nd_cred, p, 0); 1678 } 1679 } 1680 if (!nd->nd_repstat) 1681 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 1682 if (nd->nd_flag & ND_NFSV3) 1683 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0); 1684 if (dirp) { 1685 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 1686 vrele(dirp); 1687 } 1688 vrele(vp); 1689 if (nd->nd_flag & ND_NFSV3) { 1690 nfsrv_postopattr(nd, getret, &at); 1691 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1692 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1693 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1694 *tl++ = newnfs_false; 1695 txdr_hyper(dirfor.na_filerev, tl); 1696 tl += 2; 1697 txdr_hyper(diraft.na_filerev, tl); 1698 } 1699 1700out: 1701 NFSEXITCODE2(error, nd); 1702 return (error); 1703} 1704 1705/* 1706 * nfs symbolic link service 1707 */ 1708APPLESTATIC int 1709nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1710 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1711 struct nfsexstuff *exp) 1712{ 1713 struct nfsvattr nva, dirfor, diraft; 1714 struct nameidata named; 1715 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 1716 vnode_t dirp = NULL; 1717 char *bufp, *pathcp = NULL; 1718 u_long *hashp; 1719 1720 if (nd->nd_repstat) { 1721 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1722 goto out; 1723 } 1724 if (vpp) 1725 *vpp = NULL; 1726 NFSVNO_ATTRINIT(&nva); 1727 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1728 LOCKPARENT | SAVESTART | NOCACHE); 1729 nfsvno_setpathbuf(&named, &bufp, &hashp); 1730 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1731 if (!error && !nd->nd_repstat) 1732 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 1733 if (error) { 1734 vrele(dp); 1735 nfsvno_relpathbuf(&named); 1736 goto out; 1737 } 1738 if (!nd->nd_repstat) { 1739 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1740 } else { 1741 vrele(dp); 1742 nfsvno_relpathbuf(&named); 1743 } 1744 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1745 vrele(dirp); 1746 dirp = NULL; 1747 } 1748 1749 /* 1750 * And call nfsrvd_symlinksub() to do the common code. It will 1751 * return EBADRPC upon a parsing error, 0 otherwise. 1752 */ 1753 if (!nd->nd_repstat) { 1754 if (dirp != NULL) 1755 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1756 p, 0); 1757 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1758 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 1759 pathcp, pathlen); 1760 } else if (dirp != NULL) { 1761 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 1762 vrele(dirp); 1763 } 1764 if (pathcp) 1765 FREE(pathcp, M_TEMP); 1766 1767 if (nd->nd_flag & ND_NFSV3) { 1768 if (!nd->nd_repstat) { 1769 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1770 nfsrv_postopattr(nd, 0, &nva); 1771 } 1772 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1773 } 1774 1775out: 1776 NFSEXITCODE2(error, nd); 1777 return (error); 1778} 1779 1780/* 1781 * Common code for creating a symbolic link. 1782 */ 1783static void 1784nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 1785 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1786 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1787 int *diraft_retp, nfsattrbit_t *attrbitp, 1788 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 1789 int pathlen) 1790{ 1791 u_int32_t *tl; 1792 1793 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 1794 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 1795 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 1796 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 1797 if (nd->nd_flag & ND_NFSV3) { 1798 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 1799 if (!nd->nd_repstat) 1800 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 1801 nvap, nd->nd_cred, p, 1); 1802 } 1803 if (vpp != NULL && nd->nd_repstat == 0) { 1804 NFSVOPUNLOCK(ndp->ni_vp, 0); 1805 *vpp = ndp->ni_vp; 1806 } else 1807 vput(ndp->ni_vp); 1808 } 1809 if (dirp) { 1810 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 1811 vrele(dirp); 1812 } 1813 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1814 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1815 *tl++ = newnfs_false; 1816 txdr_hyper(dirforp->na_filerev, tl); 1817 tl += 2; 1818 txdr_hyper(diraftp->na_filerev, tl); 1819 (void) nfsrv_putattrbit(nd, attrbitp); 1820 } 1821 1822 NFSEXITCODE2(0, nd); 1823} 1824 1825/* 1826 * nfs mkdir service 1827 */ 1828APPLESTATIC int 1829nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 1830 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1831 struct nfsexstuff *exp) 1832{ 1833 struct nfsvattr nva, dirfor, diraft; 1834 struct nameidata named; 1835 u_int32_t *tl; 1836 int error = 0, dirfor_ret = 1, diraft_ret = 1; 1837 vnode_t dirp = NULL; 1838 char *bufp; 1839 u_long *hashp; 1840 1841 if (nd->nd_repstat) { 1842 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1843 goto out; 1844 } 1845 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1846 LOCKPARENT | SAVENAME | NOCACHE); 1847 nfsvno_setpathbuf(&named, &bufp, &hashp); 1848 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1849 if (error) 1850 goto nfsmout; 1851 if (!nd->nd_repstat) { 1852 NFSVNO_ATTRINIT(&nva); 1853 if (nd->nd_flag & ND_NFSV3) { 1854 error = nfsrv_sattr(nd, &nva, NULL, NULL, p); 1855 if (error) 1856 goto nfsmout; 1857 } else { 1858 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1859 nva.na_mode = nfstov_mode(*tl++); 1860 } 1861 } 1862 if (!nd->nd_repstat) { 1863 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1864 } else { 1865 vrele(dp); 1866 nfsvno_relpathbuf(&named); 1867 } 1868 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1869 vrele(dirp); 1870 dirp = NULL; 1871 } 1872 if (nd->nd_repstat) { 1873 if (dirp != NULL) { 1874 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1875 p, 0); 1876 vrele(dirp); 1877 } 1878 if (nd->nd_flag & ND_NFSV3) 1879 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1880 &diraft); 1881 goto out; 1882 } 1883 if (dirp != NULL) 1884 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 1885 1886 /* 1887 * Call nfsrvd_mkdirsub() for the code common to V4 as well. 1888 */ 1889 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 1890 &diraft_ret, NULL, NULL, p, exp); 1891 1892 if (nd->nd_flag & ND_NFSV3) { 1893 if (!nd->nd_repstat) { 1894 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1895 nfsrv_postopattr(nd, 0, &nva); 1896 } 1897 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1898 } else if (!nd->nd_repstat) { 1899 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 1900 nfsrv_fillattr(nd, &nva); 1901 } 1902 1903out: 1904 NFSEXITCODE2(0, nd); 1905 return (0); 1906nfsmout: 1907 vrele(dp); 1908 nfsvno_relpathbuf(&named); 1909 NFSEXITCODE2(error, nd); 1910 return (error); 1911} 1912 1913/* 1914 * Code common to mkdir for V2,3 and 4. 1915 */ 1916static void 1917nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 1918 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1919 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1920 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 1921 NFSPROC_T *p, struct nfsexstuff *exp) 1922{ 1923 vnode_t vp; 1924 u_int32_t *tl; 1925 1926 NFSVNO_SETATTRVAL(nvap, type, VDIR); 1927 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 1928 nd->nd_cred, p, exp); 1929 if (!nd->nd_repstat) { 1930 vp = ndp->ni_vp; 1931 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 1932 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 1933 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 1934 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred, 1935 p, 1); 1936 if (vpp && !nd->nd_repstat) { 1937 NFSVOPUNLOCK(vp, 0); 1938 *vpp = vp; 1939 } else { 1940 vput(vp); 1941 } 1942 } 1943 if (dirp) { 1944 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 1945 vrele(dirp); 1946 } 1947 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1948 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1949 *tl++ = newnfs_false; 1950 txdr_hyper(dirforp->na_filerev, tl); 1951 tl += 2; 1952 txdr_hyper(diraftp->na_filerev, tl); 1953 (void) nfsrv_putattrbit(nd, attrbitp); 1954 } 1955 1956 NFSEXITCODE2(0, nd); 1957} 1958 1959/* 1960 * nfs commit service 1961 */ 1962APPLESTATIC int 1963nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 1964 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1965{ 1966 struct nfsvattr bfor, aft; 1967 u_int32_t *tl; 1968 int error = 0, for_ret = 1, aft_ret = 1, cnt; 1969 u_int64_t off; 1970 1971 if (nd->nd_repstat) { 1972 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1973 goto out; 1974 } 1975 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1976 /* 1977 * XXX At this time VOP_FSYNC() does not accept offset and byte 1978 * count parameters, so these arguments are useless (someday maybe). 1979 */ 1980 off = fxdr_hyper(tl); 1981 tl += 2; 1982 cnt = fxdr_unsigned(int, *tl); 1983 if (nd->nd_flag & ND_NFSV3) 1984 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1); 1985 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 1986 if (nd->nd_flag & ND_NFSV3) { 1987 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1); 1988 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1989 } 1990 vput(vp); 1991 if (!nd->nd_repstat) { 1992 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1993 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 1994 *tl = txdr_unsigned(nfsboottime.tv_usec); 1995 } 1996 1997out: 1998 NFSEXITCODE2(0, nd); 1999 return (0); 2000nfsmout: 2001 vput(vp); 2002 NFSEXITCODE2(error, nd); 2003 return (error); 2004} 2005 2006/* 2007 * nfs statfs service 2008 */ 2009APPLESTATIC int 2010nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 2011 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2012{ 2013 struct statfs *sf; 2014 u_int32_t *tl; 2015 int getret = 1; 2016 struct nfsvattr at; 2017 struct statfs sfs; 2018 u_quad_t tval; 2019 2020 if (nd->nd_repstat) { 2021 nfsrv_postopattr(nd, getret, &at); 2022 goto out; 2023 } 2024 sf = &sfs; 2025 nd->nd_repstat = nfsvno_statfs(vp, sf); 2026 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2027 vput(vp); 2028 if (nd->nd_flag & ND_NFSV3) 2029 nfsrv_postopattr(nd, getret, &at); 2030 if (nd->nd_repstat) 2031 goto out; 2032 if (nd->nd_flag & ND_NFSV2) { 2033 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 2034 *tl++ = txdr_unsigned(NFS_V2MAXDATA); 2035 *tl++ = txdr_unsigned(sf->f_bsize); 2036 *tl++ = txdr_unsigned(sf->f_blocks); 2037 *tl++ = txdr_unsigned(sf->f_bfree); 2038 *tl = txdr_unsigned(sf->f_bavail); 2039 } else { 2040 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 2041 tval = (u_quad_t)sf->f_blocks; 2042 tval *= (u_quad_t)sf->f_bsize; 2043 txdr_hyper(tval, tl); tl += 2; 2044 tval = (u_quad_t)sf->f_bfree; 2045 tval *= (u_quad_t)sf->f_bsize; 2046 txdr_hyper(tval, tl); tl += 2; 2047 tval = (u_quad_t)sf->f_bavail; 2048 tval *= (u_quad_t)sf->f_bsize; 2049 txdr_hyper(tval, tl); tl += 2; 2050 tval = (u_quad_t)sf->f_files; 2051 txdr_hyper(tval, tl); tl += 2; 2052 tval = (u_quad_t)sf->f_ffree; 2053 txdr_hyper(tval, tl); tl += 2; 2054 tval = (u_quad_t)sf->f_ffree; 2055 txdr_hyper(tval, tl); tl += 2; 2056 *tl = 0; 2057 } 2058 2059out: 2060 NFSEXITCODE2(0, nd); 2061 return (0); 2062} 2063 2064/* 2065 * nfs fsinfo service 2066 */ 2067APPLESTATIC int 2068nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 2069 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2070{ 2071 u_int32_t *tl; 2072 struct nfsfsinfo fs; 2073 int getret = 1; 2074 struct nfsvattr at; 2075 2076 if (nd->nd_repstat) { 2077 nfsrv_postopattr(nd, getret, &at); 2078 goto out; 2079 } 2080 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2081 nfsvno_getfs(&fs, isdgram); 2082 vput(vp); 2083 nfsrv_postopattr(nd, getret, &at); 2084 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 2085 *tl++ = txdr_unsigned(fs.fs_rtmax); 2086 *tl++ = txdr_unsigned(fs.fs_rtpref); 2087 *tl++ = txdr_unsigned(fs.fs_rtmult); 2088 *tl++ = txdr_unsigned(fs.fs_wtmax); 2089 *tl++ = txdr_unsigned(fs.fs_wtpref); 2090 *tl++ = txdr_unsigned(fs.fs_wtmult); 2091 *tl++ = txdr_unsigned(fs.fs_dtpref); 2092 txdr_hyper(fs.fs_maxfilesize, tl); 2093 tl += 2; 2094 txdr_nfsv3time(&fs.fs_timedelta, tl); 2095 tl += 2; 2096 *tl = txdr_unsigned(fs.fs_properties); 2097 2098out: 2099 NFSEXITCODE2(0, nd); 2100 return (0); 2101} 2102 2103/* 2104 * nfs pathconf service 2105 */ 2106APPLESTATIC int 2107nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 2108 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2109{ 2110 struct nfsv3_pathconf *pc; 2111 int getret = 1; 2112 register_t linkmax, namemax, chownres, notrunc; 2113 struct nfsvattr at; 2114 2115 if (nd->nd_repstat) { 2116 nfsrv_postopattr(nd, getret, &at); 2117 goto out; 2118 } 2119 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 2120 nd->nd_cred, p); 2121 if (!nd->nd_repstat) 2122 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 2123 nd->nd_cred, p); 2124 if (!nd->nd_repstat) 2125 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 2126 &chownres, nd->nd_cred, p); 2127 if (!nd->nd_repstat) 2128 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 2129 nd->nd_cred, p); 2130 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2131 vput(vp); 2132 nfsrv_postopattr(nd, getret, &at); 2133 if (!nd->nd_repstat) { 2134 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 2135 pc->pc_linkmax = txdr_unsigned(linkmax); 2136 pc->pc_namemax = txdr_unsigned(namemax); 2137 pc->pc_notrunc = txdr_unsigned(notrunc); 2138 pc->pc_chownrestricted = txdr_unsigned(chownres); 2139 2140 /* 2141 * These should probably be supported by VOP_PATHCONF(), but 2142 * until msdosfs is exportable (why would you want to?), the 2143 * Unix defaults should be ok. 2144 */ 2145 pc->pc_caseinsensitive = newnfs_false; 2146 pc->pc_casepreserving = newnfs_true; 2147 } 2148 2149out: 2150 NFSEXITCODE2(0, nd); 2151 return (0); 2152} 2153 2154/* 2155 * nfsv4 lock service 2156 */ 2157APPLESTATIC int 2158nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2159 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2160{ 2161 u_int32_t *tl; 2162 int i; 2163 struct nfsstate *stp = NULL; 2164 struct nfslock *lop; 2165 struct nfslockconflict cf; 2166 int error = 0; 2167 u_short flags = NFSLCK_LOCK, lflags; 2168 u_int64_t offset, len; 2169 nfsv4stateid_t stateid; 2170 nfsquad_t clientid; 2171 2172 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2173 i = fxdr_unsigned(int, *tl++); 2174 switch (i) { 2175 case NFSV4LOCKT_READW: 2176 flags |= NFSLCK_BLOCKING; 2177 case NFSV4LOCKT_READ: 2178 lflags = NFSLCK_READ; 2179 break; 2180 case NFSV4LOCKT_WRITEW: 2181 flags |= NFSLCK_BLOCKING; 2182 case NFSV4LOCKT_WRITE: 2183 lflags = NFSLCK_WRITE; 2184 break; 2185 default: 2186 nd->nd_repstat = NFSERR_BADXDR; 2187 goto nfsmout; 2188 }; 2189 if (*tl++ == newnfs_true) 2190 flags |= NFSLCK_RECLAIM; 2191 offset = fxdr_hyper(tl); 2192 tl += 2; 2193 len = fxdr_hyper(tl); 2194 tl += 2; 2195 if (*tl == newnfs_true) 2196 flags |= NFSLCK_OPENTOLOCK; 2197 if (flags & NFSLCK_OPENTOLOCK) { 2198 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 2199 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 2200 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2201 nd->nd_repstat = NFSERR_BADXDR; 2202 goto nfsmout; 2203 } 2204 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2205 M_NFSDSTATE, M_WAITOK); 2206 stp->ls_ownerlen = i; 2207 stp->ls_op = nd->nd_rp; 2208 stp->ls_seq = fxdr_unsigned(int, *tl++); 2209 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2210 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2211 NFSX_STATEIDOTHER); 2212 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2213 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 2214 clientid.lval[0] = *tl++; 2215 clientid.lval[1] = *tl++; 2216 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2217 if ((nd->nd_flag & ND_NFSV41) != 0) 2218 clientid.qval = nd->nd_clientid.qval; 2219 else if (nd->nd_clientid.qval != clientid.qval) 2220 printf("EEK3 multiple clids\n"); 2221 } else { 2222 if ((nd->nd_flag & ND_NFSV41) != 0) 2223 printf("EEK! no clientid from session\n"); 2224 nd->nd_flag |= ND_IMPLIEDCLID; 2225 nd->nd_clientid.qval = clientid.qval; 2226 } 2227 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2228 if (error) 2229 goto nfsmout; 2230 } else { 2231 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2232 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2233 M_NFSDSTATE, M_WAITOK); 2234 stp->ls_ownerlen = 0; 2235 stp->ls_op = nd->nd_rp; 2236 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2237 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2238 NFSX_STATEIDOTHER); 2239 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2240 stp->ls_seq = fxdr_unsigned(int, *tl); 2241 clientid.lval[0] = stp->ls_stateid.other[0]; 2242 clientid.lval[1] = stp->ls_stateid.other[1]; 2243 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2244 if ((nd->nd_flag & ND_NFSV41) != 0) 2245 clientid.qval = nd->nd_clientid.qval; 2246 else if (nd->nd_clientid.qval != clientid.qval) 2247 printf("EEK4 multiple clids\n"); 2248 } else { 2249 if ((nd->nd_flag & ND_NFSV41) != 0) 2250 printf("EEK! no clientid from session\n"); 2251 nd->nd_flag |= ND_IMPLIEDCLID; 2252 nd->nd_clientid.qval = clientid.qval; 2253 } 2254 } 2255 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2256 M_NFSDLOCK, M_WAITOK); 2257 lop->lo_first = offset; 2258 if (len == NFS64BITSSET) { 2259 lop->lo_end = NFS64BITSSET; 2260 } else { 2261 lop->lo_end = offset + len; 2262 if (lop->lo_end <= lop->lo_first) 2263 nd->nd_repstat = NFSERR_INVAL; 2264 } 2265 lop->lo_flags = lflags; 2266 stp->ls_flags = flags; 2267 stp->ls_uid = nd->nd_cred->cr_uid; 2268 2269 /* 2270 * Do basic access checking. 2271 */ 2272 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2273 if (vnode_vtype(vp) == VDIR) 2274 nd->nd_repstat = NFSERR_ISDIR; 2275 else 2276 nd->nd_repstat = NFSERR_INVAL; 2277 } 2278 if (!nd->nd_repstat) { 2279 if (lflags & NFSLCK_WRITE) { 2280 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 2281 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2282 NFSACCCHK_VPISLOCKED, NULL); 2283 } else { 2284 nd->nd_repstat = nfsvno_accchk(vp, VREAD, 2285 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2286 NFSACCCHK_VPISLOCKED, NULL); 2287 if (nd->nd_repstat) 2288 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2289 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2290 NFSACCCHK_VPISLOCKED, NULL); 2291 } 2292 } 2293 2294 /* 2295 * We call nfsrv_lockctrl() even if nd_repstat set, so that the 2296 * seqid# gets updated. nfsrv_lockctrl() will return the value 2297 * of nd_repstat, if it gets that far. 2298 */ 2299 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2300 &stateid, exp, nd, p); 2301 if (lop) 2302 FREE((caddr_t)lop, M_NFSDLOCK); 2303 if (stp) 2304 FREE((caddr_t)stp, M_NFSDSTATE); 2305 if (!nd->nd_repstat) { 2306 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2307 *tl++ = txdr_unsigned(stateid.seqid); 2308 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2309 } else if (nd->nd_repstat == NFSERR_DENIED) { 2310 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2311 txdr_hyper(cf.cl_first, tl); 2312 tl += 2; 2313 if (cf.cl_end == NFS64BITSSET) 2314 len = NFS64BITSSET; 2315 else 2316 len = cf.cl_end - cf.cl_first; 2317 txdr_hyper(len, tl); 2318 tl += 2; 2319 if (cf.cl_flags == NFSLCK_WRITE) 2320 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2321 else 2322 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2323 *tl++ = stateid.other[0]; 2324 *tl = stateid.other[1]; 2325 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2326 } 2327 vput(vp); 2328 NFSEXITCODE2(0, nd); 2329 return (0); 2330nfsmout: 2331 vput(vp); 2332 if (stp) 2333 free((caddr_t)stp, M_NFSDSTATE); 2334 NFSEXITCODE2(error, nd); 2335 return (error); 2336} 2337 2338/* 2339 * nfsv4 lock test service 2340 */ 2341APPLESTATIC int 2342nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2343 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2344{ 2345 u_int32_t *tl; 2346 int i; 2347 struct nfsstate *stp = NULL; 2348 struct nfslock lo, *lop = &lo; 2349 struct nfslockconflict cf; 2350 int error = 0; 2351 nfsv4stateid_t stateid; 2352 nfsquad_t clientid; 2353 u_int64_t len; 2354 2355 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 2356 i = fxdr_unsigned(int, *(tl + 7)); 2357 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2358 nd->nd_repstat = NFSERR_BADXDR; 2359 goto nfsmout; 2360 } 2361 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2362 M_NFSDSTATE, M_WAITOK); 2363 stp->ls_ownerlen = i; 2364 stp->ls_op = NULL; 2365 stp->ls_flags = NFSLCK_TEST; 2366 stp->ls_uid = nd->nd_cred->cr_uid; 2367 i = fxdr_unsigned(int, *tl++); 2368 switch (i) { 2369 case NFSV4LOCKT_READW: 2370 stp->ls_flags |= NFSLCK_BLOCKING; 2371 case NFSV4LOCKT_READ: 2372 lo.lo_flags = NFSLCK_READ; 2373 break; 2374 case NFSV4LOCKT_WRITEW: 2375 stp->ls_flags |= NFSLCK_BLOCKING; 2376 case NFSV4LOCKT_WRITE: 2377 lo.lo_flags = NFSLCK_WRITE; 2378 break; 2379 default: 2380 nd->nd_repstat = NFSERR_BADXDR; 2381 goto nfsmout; 2382 }; 2383 lo.lo_first = fxdr_hyper(tl); 2384 tl += 2; 2385 len = fxdr_hyper(tl); 2386 if (len == NFS64BITSSET) { 2387 lo.lo_end = NFS64BITSSET; 2388 } else { 2389 lo.lo_end = lo.lo_first + len; 2390 if (lo.lo_end <= lo.lo_first) 2391 nd->nd_repstat = NFSERR_INVAL; 2392 } 2393 tl += 2; 2394 clientid.lval[0] = *tl++; 2395 clientid.lval[1] = *tl; 2396 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2397 if ((nd->nd_flag & ND_NFSV41) != 0) 2398 clientid.qval = nd->nd_clientid.qval; 2399 else if (nd->nd_clientid.qval != clientid.qval) 2400 printf("EEK5 multiple clids\n"); 2401 } else { 2402 if ((nd->nd_flag & ND_NFSV41) != 0) 2403 printf("EEK! no clientid from session\n"); 2404 nd->nd_flag |= ND_IMPLIEDCLID; 2405 nd->nd_clientid.qval = clientid.qval; 2406 } 2407 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2408 if (error) 2409 goto nfsmout; 2410 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2411 if (vnode_vtype(vp) == VDIR) 2412 nd->nd_repstat = NFSERR_ISDIR; 2413 else 2414 nd->nd_repstat = NFSERR_INVAL; 2415 } 2416 if (!nd->nd_repstat) 2417 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2418 &stateid, exp, nd, p); 2419 if (nd->nd_repstat) { 2420 if (nd->nd_repstat == NFSERR_DENIED) { 2421 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2422 txdr_hyper(cf.cl_first, tl); 2423 tl += 2; 2424 if (cf.cl_end == NFS64BITSSET) 2425 len = NFS64BITSSET; 2426 else 2427 len = cf.cl_end - cf.cl_first; 2428 txdr_hyper(len, tl); 2429 tl += 2; 2430 if (cf.cl_flags == NFSLCK_WRITE) 2431 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2432 else 2433 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2434 *tl++ = stp->ls_stateid.other[0]; 2435 *tl = stp->ls_stateid.other[1]; 2436 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2437 } 2438 } 2439 vput(vp); 2440 if (stp) 2441 FREE((caddr_t)stp, M_NFSDSTATE); 2442 NFSEXITCODE2(0, nd); 2443 return (0); 2444nfsmout: 2445 vput(vp); 2446 if (stp) 2447 free((caddr_t)stp, M_NFSDSTATE); 2448 NFSEXITCODE2(error, nd); 2449 return (error); 2450} 2451 2452/* 2453 * nfsv4 unlock service 2454 */ 2455APPLESTATIC int 2456nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2457 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2458{ 2459 u_int32_t *tl; 2460 int i; 2461 struct nfsstate *stp; 2462 struct nfslock *lop; 2463 int error = 0; 2464 nfsv4stateid_t stateid; 2465 nfsquad_t clientid; 2466 u_int64_t len; 2467 2468 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2469 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2470 M_NFSDSTATE, M_WAITOK); 2471 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2472 M_NFSDLOCK, M_WAITOK); 2473 stp->ls_flags = NFSLCK_UNLOCK; 2474 lop->lo_flags = NFSLCK_UNLOCK; 2475 stp->ls_op = nd->nd_rp; 2476 i = fxdr_unsigned(int, *tl++); 2477 switch (i) { 2478 case NFSV4LOCKT_READW: 2479 stp->ls_flags |= NFSLCK_BLOCKING; 2480 case NFSV4LOCKT_READ: 2481 break; 2482 case NFSV4LOCKT_WRITEW: 2483 stp->ls_flags |= NFSLCK_BLOCKING; 2484 case NFSV4LOCKT_WRITE: 2485 break; 2486 default: 2487 nd->nd_repstat = NFSERR_BADXDR; 2488 free(stp, M_NFSDSTATE); 2489 free(lop, M_NFSDLOCK); 2490 goto nfsmout; 2491 }; 2492 stp->ls_ownerlen = 0; 2493 stp->ls_uid = nd->nd_cred->cr_uid; 2494 stp->ls_seq = fxdr_unsigned(int, *tl++); 2495 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2496 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2497 NFSX_STATEIDOTHER); 2498 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2499 lop->lo_first = fxdr_hyper(tl); 2500 tl += 2; 2501 len = fxdr_hyper(tl); 2502 if (len == NFS64BITSSET) { 2503 lop->lo_end = NFS64BITSSET; 2504 } else { 2505 lop->lo_end = lop->lo_first + len; 2506 if (lop->lo_end <= lop->lo_first) 2507 nd->nd_repstat = NFSERR_INVAL; 2508 } 2509 clientid.lval[0] = stp->ls_stateid.other[0]; 2510 clientid.lval[1] = stp->ls_stateid.other[1]; 2511 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2512 if ((nd->nd_flag & ND_NFSV41) != 0) 2513 clientid.qval = nd->nd_clientid.qval; 2514 else if (nd->nd_clientid.qval != clientid.qval) 2515 printf("EEK6 multiple clids\n"); 2516 } else { 2517 if ((nd->nd_flag & ND_NFSV41) != 0) 2518 printf("EEK! no clientid from session\n"); 2519 nd->nd_flag |= ND_IMPLIEDCLID; 2520 nd->nd_clientid.qval = clientid.qval; 2521 } 2522 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2523 if (vnode_vtype(vp) == VDIR) 2524 nd->nd_repstat = NFSERR_ISDIR; 2525 else 2526 nd->nd_repstat = NFSERR_INVAL; 2527 } 2528 /* 2529 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 2530 * seqid# gets incremented. nfsrv_lockctrl() will return the 2531 * value of nd_repstat, if it gets that far. 2532 */ 2533 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 2534 &stateid, exp, nd, p); 2535 if (stp) 2536 FREE((caddr_t)stp, M_NFSDSTATE); 2537 if (lop) 2538 free((caddr_t)lop, M_NFSDLOCK); 2539 if (!nd->nd_repstat) { 2540 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2541 *tl++ = txdr_unsigned(stateid.seqid); 2542 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2543 } 2544nfsmout: 2545 vput(vp); 2546 NFSEXITCODE2(error, nd); 2547 return (error); 2548} 2549 2550/* 2551 * nfsv4 open service 2552 */ 2553APPLESTATIC int 2554nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2555 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p, 2556 struct nfsexstuff *exp) 2557{ 2558 u_int32_t *tl; 2559 int i, retext; 2560 struct nfsstate *stp = NULL; 2561 int error = 0, create, claim, exclusive_flag = 0; 2562 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 2563 int how = NFSCREATE_UNCHECKED; 2564 int32_t cverf[2], tverf[2] = { 0, 0 }; 2565 vnode_t vp = NULL, dirp = NULL; 2566 struct nfsvattr nva, dirfor, diraft; 2567 struct nameidata named; 2568 nfsv4stateid_t stateid, delegstateid; 2569 nfsattrbit_t attrbits; 2570 nfsquad_t clientid; 2571 char *bufp = NULL; 2572 u_long *hashp; 2573 NFSACL_T *aclp = NULL; 2574 2575#ifdef NFS4_ACL_EXTATTR_NAME 2576 aclp = acl_alloc(M_WAITOK); 2577 aclp->acl_cnt = 0; 2578#endif 2579 NFSZERO_ATTRBIT(&attrbits); 2580 named.ni_startdir = NULL; 2581 named.ni_cnd.cn_nameiop = 0; 2582 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2583 i = fxdr_unsigned(int, *(tl + 5)); 2584 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2585 nd->nd_repstat = NFSERR_BADXDR; 2586 goto nfsmout; 2587 } 2588 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2589 M_NFSDSTATE, M_WAITOK); 2590 stp->ls_ownerlen = i; 2591 stp->ls_op = nd->nd_rp; 2592 stp->ls_flags = NFSLCK_OPEN; 2593 stp->ls_uid = nd->nd_cred->cr_uid; 2594 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2595 i = fxdr_unsigned(int, *tl++); 2596 retext = 0; 2597 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2598 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2599 retext = 1; 2600 /* For now, ignore these. */ 2601 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2602 switch (i & NFSV4OPEN_WANTDELEGMASK) { 2603 case NFSV4OPEN_WANTANYDELEG: 2604 stp->ls_flags |= (NFSLCK_WANTRDELEG | 2605 NFSLCK_WANTWDELEG); 2606 i &= ~NFSV4OPEN_WANTDELEGMASK; 2607 break; 2608 case NFSV4OPEN_WANTREADDELEG: 2609 stp->ls_flags |= NFSLCK_WANTRDELEG; 2610 i &= ~NFSV4OPEN_WANTDELEGMASK; 2611 break; 2612 case NFSV4OPEN_WANTWRITEDELEG: 2613 stp->ls_flags |= NFSLCK_WANTWDELEG; 2614 i &= ~NFSV4OPEN_WANTDELEGMASK; 2615 break; 2616 case NFSV4OPEN_WANTNODELEG: 2617 stp->ls_flags |= NFSLCK_WANTNODELEG; 2618 i &= ~NFSV4OPEN_WANTDELEGMASK; 2619 break; 2620 case NFSV4OPEN_WANTCANCEL: 2621 printf("NFSv4: ignore Open WantCancel\n"); 2622 i &= ~NFSV4OPEN_WANTDELEGMASK; 2623 break; 2624 default: 2625 /* nd_repstat will be set to NFSERR_INVAL below. */ 2626 break; 2627 }; 2628 } 2629 switch (i) { 2630 case NFSV4OPEN_ACCESSREAD: 2631 stp->ls_flags |= NFSLCK_READACCESS; 2632 break; 2633 case NFSV4OPEN_ACCESSWRITE: 2634 stp->ls_flags |= NFSLCK_WRITEACCESS; 2635 break; 2636 case NFSV4OPEN_ACCESSBOTH: 2637 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2638 break; 2639 default: 2640 nd->nd_repstat = NFSERR_INVAL; 2641 }; 2642 i = fxdr_unsigned(int, *tl++); 2643 switch (i) { 2644 case NFSV4OPEN_DENYNONE: 2645 break; 2646 case NFSV4OPEN_DENYREAD: 2647 stp->ls_flags |= NFSLCK_READDENY; 2648 break; 2649 case NFSV4OPEN_DENYWRITE: 2650 stp->ls_flags |= NFSLCK_WRITEDENY; 2651 break; 2652 case NFSV4OPEN_DENYBOTH: 2653 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 2654 break; 2655 default: 2656 nd->nd_repstat = NFSERR_INVAL; 2657 }; 2658 clientid.lval[0] = *tl++; 2659 clientid.lval[1] = *tl; 2660 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2661 if ((nd->nd_flag & ND_NFSV41) != 0) 2662 clientid.qval = nd->nd_clientid.qval; 2663 else if (nd->nd_clientid.qval != clientid.qval) 2664 printf("EEK7 multiple clids\n"); 2665 } else { 2666 if ((nd->nd_flag & ND_NFSV41) != 0) 2667 printf("EEK! no clientid from session\n"); 2668 nd->nd_flag |= ND_IMPLIEDCLID; 2669 nd->nd_clientid.qval = clientid.qval; 2670 } 2671 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2672 if (error) 2673 goto nfsmout; 2674 NFSVNO_ATTRINIT(&nva); 2675 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2676 create = fxdr_unsigned(int, *tl); 2677 if (!nd->nd_repstat) 2678 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 2679 if (create == NFSV4OPEN_CREATE) { 2680 nva.na_type = VREG; 2681 nva.na_mode = 0; 2682 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2683 how = fxdr_unsigned(int, *tl); 2684 switch (how) { 2685 case NFSCREATE_UNCHECKED: 2686 case NFSCREATE_GUARDED: 2687 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p); 2688 if (error) 2689 goto nfsmout; 2690 /* 2691 * If the na_gid being set is the same as that of 2692 * the directory it is going in, clear it, since 2693 * that is what will be set by default. This allows 2694 * a user that isn't in that group to do the create. 2695 */ 2696 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 2697 nva.na_gid == dirfor.na_gid) 2698 NFSVNO_UNSET(&nva, gid); 2699 if (!nd->nd_repstat) 2700 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2701 break; 2702 case NFSCREATE_EXCLUSIVE: 2703 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2704 cverf[0] = *tl++; 2705 cverf[1] = *tl; 2706 break; 2707 case NFSCREATE_EXCLUSIVE41: 2708 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2709 cverf[0] = *tl++; 2710 cverf[1] = *tl; 2711 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p); 2712 if (error != 0) 2713 goto nfsmout; 2714 if (NFSISSET_ATTRBIT(&attrbits, 2715 NFSATTRBIT_TIMEACCESSSET)) 2716 nd->nd_repstat = NFSERR_INVAL; 2717 /* 2718 * If the na_gid being set is the same as that of 2719 * the directory it is going in, clear it, since 2720 * that is what will be set by default. This allows 2721 * a user that isn't in that group to do the create. 2722 */ 2723 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2724 nva.na_gid == dirfor.na_gid) 2725 NFSVNO_UNSET(&nva, gid); 2726 if (nd->nd_repstat == 0) 2727 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2728 break; 2729 default: 2730 nd->nd_repstat = NFSERR_BADXDR; 2731 goto nfsmout; 2732 }; 2733 } else if (create != NFSV4OPEN_NOCREATE) { 2734 nd->nd_repstat = NFSERR_BADXDR; 2735 goto nfsmout; 2736 } 2737 2738 /* 2739 * Now, handle the claim, which usually includes looking up a 2740 * name in the directory referenced by dp. The exception is 2741 * NFSV4OPEN_CLAIMPREVIOUS. 2742 */ 2743 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2744 claim = fxdr_unsigned(int, *tl); 2745 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 2746 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2747 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2748 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 2749 stp->ls_flags |= NFSLCK_DELEGCUR; 2750 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2751 stp->ls_flags |= NFSLCK_DELEGPREV; 2752 } 2753 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 2754 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2755 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 2756 claim != NFSV4OPEN_CLAIMNULL) 2757 nd->nd_repstat = NFSERR_INVAL; 2758 if (nd->nd_repstat) { 2759 nd->nd_repstat = nfsrv_opencheck(clientid, 2760 &stateid, stp, NULL, nd, p, nd->nd_repstat); 2761 goto nfsmout; 2762 } 2763 if (create == NFSV4OPEN_CREATE) 2764 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 2765 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 2766 else 2767 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 2768 LOCKLEAF | SAVESTART); 2769 nfsvno_setpathbuf(&named, &bufp, &hashp); 2770 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2771 if (error) { 2772 vrele(dp); 2773#ifdef NFS4_ACL_EXTATTR_NAME 2774 acl_free(aclp); 2775#endif 2776 FREE((caddr_t)stp, M_NFSDSTATE); 2777 nfsvno_relpathbuf(&named); 2778 NFSEXITCODE2(error, nd); 2779 return (error); 2780 } 2781 if (!nd->nd_repstat) { 2782 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 2783 p, &dirp); 2784 } else { 2785 vrele(dp); 2786 nfsvno_relpathbuf(&named); 2787 } 2788 if (create == NFSV4OPEN_CREATE) { 2789 switch (how) { 2790 case NFSCREATE_UNCHECKED: 2791 if (named.ni_vp) { 2792 /* 2793 * Clear the setable attribute bits, except 2794 * for Size, if it is being truncated. 2795 */ 2796 NFSZERO_ATTRBIT(&attrbits); 2797 if (NFSVNO_ISSETSIZE(&nva)) 2798 NFSSETBIT_ATTRBIT(&attrbits, 2799 NFSATTRBIT_SIZE); 2800 } 2801 break; 2802 case NFSCREATE_GUARDED: 2803 if (named.ni_vp && !nd->nd_repstat) 2804 nd->nd_repstat = EEXIST; 2805 break; 2806 case NFSCREATE_EXCLUSIVE: 2807 exclusive_flag = 1; 2808 if (!named.ni_vp) 2809 nva.na_mode = 0; 2810 break; 2811 case NFSCREATE_EXCLUSIVE41: 2812 exclusive_flag = 1; 2813 break; 2814 }; 2815 } 2816 nfsvno_open(nd, &named, clientid, &stateid, stp, 2817 &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 2818 nd->nd_cred, p, exp, &vp); 2819 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 2820 NFSV4OPEN_CLAIMFH) { 2821 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2822 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2823 i = fxdr_unsigned(int, *tl); 2824 switch (i) { 2825 case NFSV4OPEN_DELEGATEREAD: 2826 stp->ls_flags |= NFSLCK_DELEGREAD; 2827 break; 2828 case NFSV4OPEN_DELEGATEWRITE: 2829 stp->ls_flags |= NFSLCK_DELEGWRITE; 2830 case NFSV4OPEN_DELEGATENONE: 2831 break; 2832 default: 2833 nd->nd_repstat = NFSERR_BADXDR; 2834 goto nfsmout; 2835 }; 2836 stp->ls_flags |= NFSLCK_RECLAIM; 2837 } else { 2838 /* CLAIM_NULL_FH */ 2839 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 2840 nd->nd_repstat = NFSERR_INVAL; 2841 } 2842 vp = dp; 2843 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 2844 if ((vp->v_iflag & VI_DOOMED) == 0) 2845 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 2846 stp, vp, nd, p, nd->nd_repstat); 2847 else 2848 nd->nd_repstat = NFSERR_PERM; 2849 } else { 2850 nd->nd_repstat = NFSERR_BADXDR; 2851 goto nfsmout; 2852 } 2853 2854 /* 2855 * Do basic access checking. 2856 */ 2857 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2858 /* 2859 * The IETF working group decided that this is the correct 2860 * error return for all non-regular files. 2861 */ 2862 nd->nd_repstat = NFSERR_SYMLINK; 2863 } 2864 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 2865 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 2866 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2867 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 2868 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 2869 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2870 if (nd->nd_repstat) 2871 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2872 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2873 NFSACCCHK_VPISLOCKED, NULL); 2874 } 2875 2876 if (!nd->nd_repstat) { 2877 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 2878 if (!nd->nd_repstat) { 2879 tverf[0] = nva.na_atime.tv_sec; 2880 tverf[1] = nva.na_atime.tv_nsec; 2881 } 2882 } 2883 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 2884 cverf[1] != tverf[1])) 2885 nd->nd_repstat = EEXIST; 2886 /* 2887 * Do the open locking/delegation stuff. 2888 */ 2889 if (!nd->nd_repstat) 2890 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 2891 &delegstateid, &rflags, exp, p, nva.na_filerev); 2892 2893 /* 2894 * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 2895 * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 2896 * (ie: Leave the NFSVOPUNLOCK() about here.) 2897 */ 2898 if (vp) 2899 NFSVOPUNLOCK(vp, 0); 2900 if (stp) 2901 FREE((caddr_t)stp, M_NFSDSTATE); 2902 if (!nd->nd_repstat && dirp) 2903 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 2904 0); 2905 if (!nd->nd_repstat) { 2906 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 2907 *tl++ = txdr_unsigned(stateid.seqid); 2908 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2909 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2910 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2911 *tl++ = newnfs_true; 2912 *tl++ = 0; 2913 *tl++ = 0; 2914 *tl++ = 0; 2915 *tl++ = 0; 2916 } else { 2917 *tl++ = newnfs_false; /* Since dirp is not locked */ 2918 txdr_hyper(dirfor.na_filerev, tl); 2919 tl += 2; 2920 txdr_hyper(diraft.na_filerev, tl); 2921 tl += 2; 2922 } 2923 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 2924 (void) nfsrv_putattrbit(nd, &attrbits); 2925 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2926 if (rflags & NFSV4OPEN_READDELEGATE) 2927 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 2928 else if (rflags & NFSV4OPEN_WRITEDELEGATE) 2929 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 2930 else if (retext != 0) { 2931 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 2932 if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 2933 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2934 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 2935 *tl = newnfs_false; 2936 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 2937 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2938 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 2939 *tl = newnfs_false; 2940 } else { 2941 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2942 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 2943 } 2944 } else 2945 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 2946 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 2947 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 2948 *tl++ = txdr_unsigned(delegstateid.seqid); 2949 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 2950 NFSX_STATEIDOTHER); 2951 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2952 if (rflags & NFSV4OPEN_RECALL) 2953 *tl = newnfs_true; 2954 else 2955 *tl = newnfs_false; 2956 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 2957 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2958 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 2959 txdr_hyper(nva.na_size, tl); 2960 } 2961 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2962 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 2963 *tl++ = txdr_unsigned(0x0); 2964 acemask = NFSV4ACE_ALLFILESMASK; 2965 if (nva.na_mode & S_IRUSR) 2966 acemask |= NFSV4ACE_READMASK; 2967 if (nva.na_mode & S_IWUSR) 2968 acemask |= NFSV4ACE_WRITEMASK; 2969 if (nva.na_mode & S_IXUSR) 2970 acemask |= NFSV4ACE_EXECUTEMASK; 2971 *tl = txdr_unsigned(acemask); 2972 (void) nfsm_strtom(nd, "OWNER@", 6); 2973 } 2974 *vpp = vp; 2975 } else if (vp) { 2976 vrele(vp); 2977 } 2978 if (dirp) 2979 vrele(dirp); 2980#ifdef NFS4_ACL_EXTATTR_NAME 2981 acl_free(aclp); 2982#endif 2983 NFSEXITCODE2(0, nd); 2984 return (0); 2985nfsmout: 2986 vrele(dp); 2987#ifdef NFS4_ACL_EXTATTR_NAME 2988 acl_free(aclp); 2989#endif 2990 if (stp) 2991 FREE((caddr_t)stp, M_NFSDSTATE); 2992 NFSEXITCODE2(error, nd); 2993 return (error); 2994} 2995 2996/* 2997 * nfsv4 close service 2998 */ 2999APPLESTATIC int 3000nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3001 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3002{ 3003 u_int32_t *tl; 3004 struct nfsstate st, *stp = &st; 3005 int error = 0; 3006 nfsv4stateid_t stateid; 3007 nfsquad_t clientid; 3008 3009 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 3010 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3011 stp->ls_ownerlen = 0; 3012 stp->ls_op = nd->nd_rp; 3013 stp->ls_uid = nd->nd_cred->cr_uid; 3014 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3015 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3016 NFSX_STATEIDOTHER); 3017 stp->ls_flags = NFSLCK_CLOSE; 3018 clientid.lval[0] = stp->ls_stateid.other[0]; 3019 clientid.lval[1] = stp->ls_stateid.other[1]; 3020 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3021 if ((nd->nd_flag & ND_NFSV41) != 0) 3022 clientid.qval = nd->nd_clientid.qval; 3023 else if (nd->nd_clientid.qval != clientid.qval) 3024 printf("EEK8 multiple clids\n"); 3025 } else { 3026 if ((nd->nd_flag & ND_NFSV41) != 0) 3027 printf("EEK! no clientid from session\n"); 3028 nd->nd_flag |= ND_IMPLIEDCLID; 3029 nd->nd_clientid.qval = clientid.qval; 3030 } 3031 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 3032 vput(vp); 3033 if (!nd->nd_repstat) { 3034 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3035 *tl++ = txdr_unsigned(stateid.seqid); 3036 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3037 } 3038 NFSEXITCODE2(0, nd); 3039 return (0); 3040nfsmout: 3041 vput(vp); 3042 NFSEXITCODE2(error, nd); 3043 return (error); 3044} 3045 3046/* 3047 * nfsv4 delegpurge service 3048 */ 3049APPLESTATIC int 3050nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3051 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3052{ 3053 u_int32_t *tl; 3054 int error = 0; 3055 nfsquad_t clientid; 3056 3057 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3058 nd->nd_repstat = NFSERR_WRONGSEC; 3059 goto nfsmout; 3060 } 3061 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3062 clientid.lval[0] = *tl++; 3063 clientid.lval[1] = *tl; 3064 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3065 if ((nd->nd_flag & ND_NFSV41) != 0) 3066 clientid.qval = nd->nd_clientid.qval; 3067 else if (nd->nd_clientid.qval != clientid.qval) 3068 printf("EEK9 multiple clids\n"); 3069 } else { 3070 if ((nd->nd_flag & ND_NFSV41) != 0) 3071 printf("EEK! no clientid from session\n"); 3072 nd->nd_flag |= ND_IMPLIEDCLID; 3073 nd->nd_clientid.qval = clientid.qval; 3074 } 3075 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 3076 NFSV4OP_DELEGPURGE, nd->nd_cred, p); 3077nfsmout: 3078 NFSEXITCODE2(error, nd); 3079 return (error); 3080} 3081 3082/* 3083 * nfsv4 delegreturn service 3084 */ 3085APPLESTATIC int 3086nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3087 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3088{ 3089 u_int32_t *tl; 3090 int error = 0; 3091 nfsv4stateid_t stateid; 3092 nfsquad_t clientid; 3093 3094 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3095 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3096 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 3097 clientid.lval[0] = stateid.other[0]; 3098 clientid.lval[1] = stateid.other[1]; 3099 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3100 if ((nd->nd_flag & ND_NFSV41) != 0) 3101 clientid.qval = nd->nd_clientid.qval; 3102 else if (nd->nd_clientid.qval != clientid.qval) 3103 printf("EEK10 multiple clids\n"); 3104 } else { 3105 if ((nd->nd_flag & ND_NFSV41) != 0) 3106 printf("EEK! no clientid from session\n"); 3107 nd->nd_flag |= ND_IMPLIEDCLID; 3108 nd->nd_clientid.qval = clientid.qval; 3109 } 3110 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 3111 NFSV4OP_DELEGRETURN, nd->nd_cred, p); 3112nfsmout: 3113 vput(vp); 3114 NFSEXITCODE2(error, nd); 3115 return (error); 3116} 3117 3118/* 3119 * nfsv4 get file handle service 3120 */ 3121APPLESTATIC int 3122nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3123 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3124{ 3125 fhandle_t fh; 3126 3127 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3128 vput(vp); 3129 if (!nd->nd_repstat) 3130 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3131 NFSEXITCODE2(0, nd); 3132 return (0); 3133} 3134 3135/* 3136 * nfsv4 open confirm service 3137 */ 3138APPLESTATIC int 3139nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3140 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3141{ 3142 u_int32_t *tl; 3143 struct nfsstate st, *stp = &st; 3144 int error = 0; 3145 nfsv4stateid_t stateid; 3146 nfsquad_t clientid; 3147 3148 if ((nd->nd_flag & ND_NFSV41) != 0) { 3149 nd->nd_repstat = NFSERR_NOTSUPP; 3150 goto nfsmout; 3151 } 3152 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3153 stp->ls_ownerlen = 0; 3154 stp->ls_op = nd->nd_rp; 3155 stp->ls_uid = nd->nd_cred->cr_uid; 3156 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3157 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3158 NFSX_STATEIDOTHER); 3159 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3160 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 3161 stp->ls_flags = NFSLCK_CONFIRM; 3162 clientid.lval[0] = stp->ls_stateid.other[0]; 3163 clientid.lval[1] = stp->ls_stateid.other[1]; 3164 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3165 if ((nd->nd_flag & ND_NFSV41) != 0) 3166 clientid.qval = nd->nd_clientid.qval; 3167 else if (nd->nd_clientid.qval != clientid.qval) 3168 printf("EEK11 multiple clids\n"); 3169 } else { 3170 if ((nd->nd_flag & ND_NFSV41) != 0) 3171 printf("EEK! no clientid from session\n"); 3172 nd->nd_flag |= ND_IMPLIEDCLID; 3173 nd->nd_clientid.qval = clientid.qval; 3174 } 3175 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 3176 if (!nd->nd_repstat) { 3177 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3178 *tl++ = txdr_unsigned(stateid.seqid); 3179 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3180 } 3181nfsmout: 3182 vput(vp); 3183 NFSEXITCODE2(error, nd); 3184 return (error); 3185} 3186 3187/* 3188 * nfsv4 open downgrade service 3189 */ 3190APPLESTATIC int 3191nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3192 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3193{ 3194 u_int32_t *tl; 3195 int i; 3196 struct nfsstate st, *stp = &st; 3197 int error = 0; 3198 nfsv4stateid_t stateid; 3199 nfsquad_t clientid; 3200 3201 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 3202 stp->ls_ownerlen = 0; 3203 stp->ls_op = nd->nd_rp; 3204 stp->ls_uid = nd->nd_cred->cr_uid; 3205 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3206 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3207 NFSX_STATEIDOTHER); 3208 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3209 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3210 i = fxdr_unsigned(int, *tl++); 3211 switch (i) { 3212 case NFSV4OPEN_ACCESSREAD: 3213 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3214 break; 3215 case NFSV4OPEN_ACCESSWRITE: 3216 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3217 break; 3218 case NFSV4OPEN_ACCESSBOTH: 3219 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3220 NFSLCK_DOWNGRADE); 3221 break; 3222 default: 3223 nd->nd_repstat = NFSERR_BADXDR; 3224 }; 3225 i = fxdr_unsigned(int, *tl); 3226 switch (i) { 3227 case NFSV4OPEN_DENYNONE: 3228 break; 3229 case NFSV4OPEN_DENYREAD: 3230 stp->ls_flags |= NFSLCK_READDENY; 3231 break; 3232 case NFSV4OPEN_DENYWRITE: 3233 stp->ls_flags |= NFSLCK_WRITEDENY; 3234 break; 3235 case NFSV4OPEN_DENYBOTH: 3236 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3237 break; 3238 default: 3239 nd->nd_repstat = NFSERR_BADXDR; 3240 }; 3241 3242 clientid.lval[0] = stp->ls_stateid.other[0]; 3243 clientid.lval[1] = stp->ls_stateid.other[1]; 3244 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3245 if ((nd->nd_flag & ND_NFSV41) != 0) 3246 clientid.qval = nd->nd_clientid.qval; 3247 else if (nd->nd_clientid.qval != clientid.qval) 3248 printf("EEK12 multiple clids\n"); 3249 } else { 3250 if ((nd->nd_flag & ND_NFSV41) != 0) 3251 printf("EEK! no clientid from session\n"); 3252 nd->nd_flag |= ND_IMPLIEDCLID; 3253 nd->nd_clientid.qval = clientid.qval; 3254 } 3255 if (!nd->nd_repstat) 3256 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3257 nd, p); 3258 if (!nd->nd_repstat) { 3259 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3260 *tl++ = txdr_unsigned(stateid.seqid); 3261 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3262 } 3263nfsmout: 3264 vput(vp); 3265 NFSEXITCODE2(error, nd); 3266 return (error); 3267} 3268 3269/* 3270 * nfsv4 renew lease service 3271 */ 3272APPLESTATIC int 3273nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3274 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3275{ 3276 u_int32_t *tl; 3277 int error = 0; 3278 nfsquad_t clientid; 3279 3280 if ((nd->nd_flag & ND_NFSV41) != 0) { 3281 nd->nd_repstat = NFSERR_NOTSUPP; 3282 goto nfsmout; 3283 } 3284 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3285 nd->nd_repstat = NFSERR_WRONGSEC; 3286 goto nfsmout; 3287 } 3288 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3289 clientid.lval[0] = *tl++; 3290 clientid.lval[1] = *tl; 3291 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3292 if ((nd->nd_flag & ND_NFSV41) != 0) 3293 clientid.qval = nd->nd_clientid.qval; 3294 else if (nd->nd_clientid.qval != clientid.qval) 3295 printf("EEK13 multiple clids\n"); 3296 } else { 3297 if ((nd->nd_flag & ND_NFSV41) != 0) 3298 printf("EEK! no clientid from session\n"); 3299 nd->nd_flag |= ND_IMPLIEDCLID; 3300 nd->nd_clientid.qval = clientid.qval; 3301 } 3302 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3303 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 3304nfsmout: 3305 NFSEXITCODE2(error, nd); 3306 return (error); 3307} 3308 3309/* 3310 * nfsv4 security info service 3311 */ 3312APPLESTATIC int 3313nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3314 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 3315{ 3316 u_int32_t *tl; 3317 int len; 3318 struct nameidata named; 3319 vnode_t dirp = NULL, vp; 3320 struct nfsrvfh fh; 3321 struct nfsexstuff retnes; 3322 u_int32_t *sizp; 3323 int error = 0, savflag, i; 3324 char *bufp; 3325 u_long *hashp; 3326 3327 /* 3328 * All this just to get the export flags for the name. 3329 */ 3330 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3331 LOCKLEAF | SAVESTART); 3332 nfsvno_setpathbuf(&named, &bufp, &hashp); 3333 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3334 if (error) { 3335 vput(dp); 3336 nfsvno_relpathbuf(&named); 3337 goto out; 3338 } 3339 if (!nd->nd_repstat) { 3340 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3341 } else { 3342 vput(dp); 3343 nfsvno_relpathbuf(&named); 3344 } 3345 if (dirp) 3346 vrele(dirp); 3347 if (nd->nd_repstat) 3348 goto out; 3349 vrele(named.ni_startdir); 3350 nfsvno_relpathbuf(&named); 3351 fh.nfsrvfh_len = NFSX_MYFH; 3352 vp = named.ni_vp; 3353 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3354 vput(vp); 3355 savflag = nd->nd_flag; 3356 if (!nd->nd_repstat) { 3357 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p); 3358 if (vp) 3359 vput(vp); 3360 } 3361 nd->nd_flag = savflag; 3362 if (nd->nd_repstat) 3363 goto out; 3364 3365 /* 3366 * Finally have the export flags for name, so we can create 3367 * the security info. 3368 */ 3369 len = 0; 3370 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3371 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3372 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3373 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3374 *tl = txdr_unsigned(RPCAUTH_UNIX); 3375 len++; 3376 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3377 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3378 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3379 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3380 nfsgss_mechlist[KERBV_MECH].len); 3381 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3382 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3383 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3384 len++; 3385 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3386 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3387 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3388 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3389 nfsgss_mechlist[KERBV_MECH].len); 3390 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3391 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3392 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3393 len++; 3394 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3395 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3396 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3397 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3398 nfsgss_mechlist[KERBV_MECH].len); 3399 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3400 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3401 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3402 len++; 3403 } 3404 } 3405 *sizp = txdr_unsigned(len); 3406 3407out: 3408 NFSEXITCODE2(error, nd); 3409 return (error); 3410} 3411 3412/* 3413 * nfsv4 set client id service 3414 */ 3415APPLESTATIC int 3416nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3417 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3418{ 3419 u_int32_t *tl; 3420 int i; 3421 int error = 0, idlen; 3422 struct nfsclient *clp = NULL; 3423 struct sockaddr_in *rad; 3424 u_char *verf, *ucp, *ucp2, addrbuf[24]; 3425 nfsquad_t clientid, confirm; 3426 3427 if ((nd->nd_flag & ND_NFSV41) != 0) { 3428 nd->nd_repstat = NFSERR_NOTSUPP; 3429 goto nfsmout; 3430 } 3431 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3432 nd->nd_repstat = NFSERR_WRONGSEC; 3433 goto out; 3434 } 3435 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3436 verf = (u_char *)tl; 3437 tl += (NFSX_VERF / NFSX_UNSIGNED); 3438 i = fxdr_unsigned(int, *tl); 3439 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3440 nd->nd_repstat = NFSERR_BADXDR; 3441 goto nfsmout; 3442 } 3443 idlen = i; 3444 if (nd->nd_flag & ND_GSS) 3445 i += nd->nd_princlen; 3446 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3447 M_ZERO); 3448 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3449 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3450 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3451 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3452 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3453 clp->lc_req.nr_cred = NULL; 3454 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3455 clp->lc_idlen = idlen; 3456 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3457 if (error) 3458 goto nfsmout; 3459 if (nd->nd_flag & ND_GSS) { 3460 clp->lc_flags = LCL_GSS; 3461 if (nd->nd_flag & ND_GSSINTEGRITY) 3462 clp->lc_flags |= LCL_GSSINTEGRITY; 3463 else if (nd->nd_flag & ND_GSSPRIVACY) 3464 clp->lc_flags |= LCL_GSSPRIVACY; 3465 } else { 3466 clp->lc_flags = 0; 3467 } 3468 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 3469 clp->lc_flags |= LCL_NAME; 3470 clp->lc_namelen = nd->nd_princlen; 3471 clp->lc_name = &clp->lc_id[idlen]; 3472 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3473 } else { 3474 clp->lc_uid = nd->nd_cred->cr_uid; 3475 clp->lc_gid = nd->nd_cred->cr_gid; 3476 } 3477 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3478 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 3479 error = nfsrv_getclientipaddr(nd, clp); 3480 if (error) 3481 goto nfsmout; 3482 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3483 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 3484 3485 /* 3486 * nfsrv_setclient() does the actual work of adding it to the 3487 * client list. If there is no error, the structure has been 3488 * linked into the client list and clp should no longer be used 3489 * here. When an error is returned, it has not been linked in, 3490 * so it should be free'd. 3491 */ 3492 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3493 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3494 if (clp->lc_flags & LCL_TCPCALLBACK) 3495 (void) nfsm_strtom(nd, "tcp", 3); 3496 else 3497 (void) nfsm_strtom(nd, "udp", 3); 3498 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3499 ucp = (u_char *)&rad->sin_addr.s_addr; 3500 ucp2 = (u_char *)&rad->sin_port; 3501 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 3502 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 3503 ucp2[0] & 0xff, ucp2[1] & 0xff); 3504 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3505 } 3506 if (clp) { 3507 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3508 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3509 free(clp->lc_stateid, M_NFSDCLIENT); 3510 free(clp, M_NFSDCLIENT); 3511 } 3512 if (!nd->nd_repstat) { 3513 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 3514 *tl++ = clientid.lval[0]; 3515 *tl++ = clientid.lval[1]; 3516 *tl++ = confirm.lval[0]; 3517 *tl = confirm.lval[1]; 3518 } 3519 3520out: 3521 NFSEXITCODE2(0, nd); 3522 return (0); 3523nfsmout: 3524 if (clp) { 3525 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3526 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3527 free(clp->lc_stateid, M_NFSDCLIENT); 3528 free(clp, M_NFSDCLIENT); 3529 } 3530 NFSEXITCODE2(error, nd); 3531 return (error); 3532} 3533 3534/* 3535 * nfsv4 set client id confirm service 3536 */ 3537APPLESTATIC int 3538nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3539 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p, 3540 __unused struct nfsexstuff *exp) 3541{ 3542 u_int32_t *tl; 3543 int error = 0; 3544 nfsquad_t clientid, confirm; 3545 3546 if ((nd->nd_flag & ND_NFSV41) != 0) { 3547 nd->nd_repstat = NFSERR_NOTSUPP; 3548 goto nfsmout; 3549 } 3550 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3551 nd->nd_repstat = NFSERR_WRONGSEC; 3552 goto nfsmout; 3553 } 3554 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 3555 clientid.lval[0] = *tl++; 3556 clientid.lval[1] = *tl++; 3557 confirm.lval[0] = *tl++; 3558 confirm.lval[1] = *tl; 3559 3560 /* 3561 * nfsrv_getclient() searches the client list for a match and 3562 * returns the appropriate NFSERR status. 3563 */ 3564 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3565 NULL, NULL, confirm, 0, nd, p); 3566nfsmout: 3567 NFSEXITCODE2(error, nd); 3568 return (error); 3569} 3570 3571/* 3572 * nfsv4 verify service 3573 */ 3574APPLESTATIC int 3575nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3576 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3577{ 3578 int error = 0, ret, fhsize = NFSX_MYFH; 3579 struct nfsvattr nva; 3580 struct statfs sf; 3581 struct nfsfsinfo fs; 3582 fhandle_t fh; 3583 3584 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 3585 if (!nd->nd_repstat) 3586 nd->nd_repstat = nfsvno_statfs(vp, &sf); 3587 if (!nd->nd_repstat) 3588 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3589 if (!nd->nd_repstat) { 3590 nfsvno_getfs(&fs, isdgram); 3591 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 3592 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 3593 if (!error) { 3594 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 3595 if (ret == 0) 3596 nd->nd_repstat = NFSERR_SAME; 3597 else if (ret != NFSERR_NOTSAME) 3598 nd->nd_repstat = ret; 3599 } else if (ret) 3600 nd->nd_repstat = ret; 3601 } 3602 } 3603 vput(vp); 3604 NFSEXITCODE2(error, nd); 3605 return (error); 3606} 3607 3608/* 3609 * nfs openattr rpc 3610 */ 3611APPLESTATIC int 3612nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 3613 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3614 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3615{ 3616 u_int32_t *tl; 3617 int error = 0, createdir; 3618 3619 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3620 createdir = fxdr_unsigned(int, *tl); 3621 nd->nd_repstat = NFSERR_NOTSUPP; 3622nfsmout: 3623 vrele(dp); 3624 NFSEXITCODE2(error, nd); 3625 return (error); 3626} 3627 3628/* 3629 * nfsv4 release lock owner service 3630 */ 3631APPLESTATIC int 3632nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 3633 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3634{ 3635 u_int32_t *tl; 3636 struct nfsstate *stp = NULL; 3637 int error = 0, len; 3638 nfsquad_t clientid; 3639 3640 if ((nd->nd_flag & ND_NFSV41) != 0) { 3641 nd->nd_repstat = NFSERR_NOTSUPP; 3642 goto nfsmout; 3643 } 3644 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3645 nd->nd_repstat = NFSERR_WRONGSEC; 3646 goto nfsmout; 3647 } 3648 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3649 len = fxdr_unsigned(int, *(tl + 2)); 3650 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 3651 nd->nd_repstat = NFSERR_BADXDR; 3652 goto nfsmout; 3653 } 3654 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len, 3655 M_NFSDSTATE, M_WAITOK); 3656 stp->ls_ownerlen = len; 3657 stp->ls_op = NULL; 3658 stp->ls_flags = NFSLCK_RELEASE; 3659 stp->ls_uid = nd->nd_cred->cr_uid; 3660 clientid.lval[0] = *tl++; 3661 clientid.lval[1] = *tl; 3662 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3663 if ((nd->nd_flag & ND_NFSV41) != 0) 3664 clientid.qval = nd->nd_clientid.qval; 3665 else if (nd->nd_clientid.qval != clientid.qval) 3666 printf("EEK14 multiple clids\n"); 3667 } else { 3668 if ((nd->nd_flag & ND_NFSV41) != 0) 3669 printf("EEK! no clientid from session\n"); 3670 nd->nd_flag |= ND_IMPLIEDCLID; 3671 nd->nd_clientid.qval = clientid.qval; 3672 } 3673 error = nfsrv_mtostr(nd, stp->ls_owner, len); 3674 if (error) 3675 goto nfsmout; 3676 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 3677 FREE((caddr_t)stp, M_NFSDSTATE); 3678 3679 NFSEXITCODE2(0, nd); 3680 return (0); 3681nfsmout: 3682 if (stp) 3683 free((caddr_t)stp, M_NFSDSTATE); 3684 NFSEXITCODE2(error, nd); 3685 return (error); 3686} 3687 3688/* 3689 * nfsv4 exchange_id service 3690 */ 3691APPLESTATIC int 3692nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 3693 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3694{ 3695 uint32_t *tl; 3696 int error = 0, i, idlen; 3697 struct nfsclient *clp = NULL; 3698 nfsquad_t clientid, confirm; 3699 uint8_t *verf; 3700 uint32_t sp4type, v41flags; 3701 uint64_t owner_minor; 3702 struct timespec verstime; 3703 struct sockaddr_in *sad, *rad; 3704 3705 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3706 nd->nd_repstat = NFSERR_WRONGSEC; 3707 goto nfsmout; 3708 } 3709 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3710 verf = (uint8_t *)tl; 3711 tl += (NFSX_VERF / NFSX_UNSIGNED); 3712 i = fxdr_unsigned(int, *tl); 3713 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3714 nd->nd_repstat = NFSERR_BADXDR; 3715 goto nfsmout; 3716 } 3717 idlen = i; 3718 if (nd->nd_flag & ND_GSS) 3719 i += nd->nd_princlen; 3720 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3721 M_ZERO); 3722 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3723 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3724 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3725 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3726 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3727 sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *); 3728 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3729 rad->sin_family = AF_INET; 3730 rad->sin_addr.s_addr = 0; 3731 rad->sin_port = 0; 3732 if (sad->sin_family == AF_INET) 3733 rad->sin_addr.s_addr = sad->sin_addr.s_addr; 3734 clp->lc_req.nr_cred = NULL; 3735 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3736 clp->lc_idlen = idlen; 3737 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3738 if (error != 0) 3739 goto nfsmout; 3740 if ((nd->nd_flag & ND_GSS) != 0) { 3741 clp->lc_flags = LCL_GSS | LCL_NFSV41; 3742 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 3743 clp->lc_flags |= LCL_GSSINTEGRITY; 3744 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 3745 clp->lc_flags |= LCL_GSSPRIVACY; 3746 } else 3747 clp->lc_flags = LCL_NFSV41; 3748 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 3749 clp->lc_flags |= LCL_NAME; 3750 clp->lc_namelen = nd->nd_princlen; 3751 clp->lc_name = &clp->lc_id[idlen]; 3752 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3753 } else { 3754 clp->lc_uid = nd->nd_cred->cr_uid; 3755 clp->lc_gid = nd->nd_cred->cr_gid; 3756 } 3757 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3758 v41flags = fxdr_unsigned(uint32_t, *tl++); 3759 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 3760 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 3761 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 3762 nd->nd_repstat = NFSERR_INVAL; 3763 goto nfsmout; 3764 } 3765 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 3766 confirm.lval[1] = 1; 3767 else 3768 confirm.lval[1] = 0; 3769 v41flags = NFSV4EXCH_USENONPNFS; 3770 sp4type = fxdr_unsigned(uint32_t, *tl); 3771 if (sp4type != NFSV4EXCH_SP4NONE) { 3772 nd->nd_repstat = NFSERR_NOTSUPP; 3773 goto nfsmout; 3774 } 3775 3776 /* 3777 * nfsrv_setclient() does the actual work of adding it to the 3778 * client list. If there is no error, the structure has been 3779 * linked into the client list and clp should no longer be used 3780 * here. When an error is returned, it has not been linked in, 3781 * so it should be free'd. 3782 */ 3783 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3784 if (clp != NULL) { 3785 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3786 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3787 free(clp->lc_stateid, M_NFSDCLIENT); 3788 free(clp, M_NFSDCLIENT); 3789 } 3790 if (nd->nd_repstat == 0) { 3791 if (confirm.lval[1] != 0) 3792 v41flags |= NFSV4EXCH_CONFIRMEDR; 3793 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 3794 *tl++ = clientid.lval[0]; /* ClientID */ 3795 *tl++ = clientid.lval[1]; 3796 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 3797 *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 3798 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 3799 owner_minor = 0; /* Owner */ 3800 txdr_hyper(owner_minor, tl); /* Minor */ 3801 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 3802 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 3803 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 3804 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */ 3805 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3806 *tl = txdr_unsigned(1); 3807 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 3808 (void)nfsm_strtom(nd, version, strlen(version)); 3809 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 3810 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 3811 verstime.tv_nsec = 0; 3812 txdr_nfsv4time(&verstime, tl); 3813 } 3814 NFSEXITCODE2(0, nd); 3815 return (0); 3816nfsmout: 3817 if (clp != NULL) { 3818 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3819 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3820 free(clp->lc_stateid, M_NFSDCLIENT); 3821 free(clp, M_NFSDCLIENT); 3822 } 3823 NFSEXITCODE2(error, nd); 3824 return (error); 3825} 3826 3827/* 3828 * nfsv4 create session service 3829 */ 3830APPLESTATIC int 3831nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 3832 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3833{ 3834 uint32_t *tl; 3835 int error = 0; 3836 nfsquad_t clientid, confirm; 3837 struct nfsdsession *sep = NULL; 3838 uint32_t rdmacnt; 3839 3840 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3841 nd->nd_repstat = NFSERR_WRONGSEC; 3842 goto nfsmout; 3843 } 3844 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 3845 M_NFSDSESSION, M_WAITOK | M_ZERO); 3846 sep->sess_refcnt = 1; 3847 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 3848 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 3849 clientid.lval[0] = *tl++; 3850 clientid.lval[1] = *tl++; 3851 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 3852 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 3853 /* Persistent sessions and RDMA are not supported. */ 3854 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 3855 3856 /* Fore channel attributes. */ 3857 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3858 tl++; /* Header pad always 0. */ 3859 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 3860 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 3861 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 3862 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 3863 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 3864 if (sep->sess_maxslots > NFSV4_SLOTS) 3865 sep->sess_maxslots = NFSV4_SLOTS; 3866 rdmacnt = fxdr_unsigned(uint32_t, *tl); 3867 if (rdmacnt > 1) { 3868 nd->nd_repstat = NFSERR_BADXDR; 3869 goto nfsmout; 3870 } else if (rdmacnt == 1) 3871 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3872 3873 /* Back channel attributes. */ 3874 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3875 tl++; /* Header pad always 0. */ 3876 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 3877 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 3878 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 3879 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 3880 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 3881 rdmacnt = fxdr_unsigned(uint32_t, *tl); 3882 if (rdmacnt > 1) { 3883 nd->nd_repstat = NFSERR_BADXDR; 3884 goto nfsmout; 3885 } else if (rdmacnt == 1) 3886 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3887 3888 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3889 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 3890 3891 /* 3892 * nfsrv_getclient() searches the client list for a match and 3893 * returns the appropriate NFSERR status. 3894 */ 3895 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 3896 NULL, sep, confirm, sep->sess_cbprogram, nd, p); 3897 if (nd->nd_repstat == 0) { 3898 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3899 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 3900 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 3901 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 3902 *tl++ = txdr_unsigned(sep->sess_crflags); 3903 3904 /* Fore channel attributes. */ 3905 *tl++ = 0; 3906 *tl++ = txdr_unsigned(sep->sess_maxreq); 3907 *tl++ = txdr_unsigned(sep->sess_maxresp); 3908 *tl++ = txdr_unsigned(sep->sess_maxrespcached); 3909 *tl++ = txdr_unsigned(sep->sess_maxops); 3910 *tl++ = txdr_unsigned(sep->sess_maxslots); 3911 *tl++ = txdr_unsigned(1); 3912 *tl++ = txdr_unsigned(0); /* No RDMA. */ 3913 3914 /* Back channel attributes. */ 3915 *tl++ = 0; 3916 *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 3917 *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 3918 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 3919 *tl++ = txdr_unsigned(sep->sess_cbmaxops); 3920 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 3921 *tl++ = txdr_unsigned(1); 3922 *tl = txdr_unsigned(0); /* No RDMA. */ 3923 } 3924nfsmout: 3925 if (nd->nd_repstat != 0 && sep != NULL) 3926 free(sep, M_NFSDSESSION); 3927 NFSEXITCODE2(error, nd); 3928 return (error); 3929} 3930 3931/* 3932 * nfsv4 sequence service 3933 */ 3934APPLESTATIC int 3935nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 3936 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3937{ 3938 uint32_t *tl; 3939 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 3940 int cache_this, error = 0; 3941 3942 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3943 nd->nd_repstat = NFSERR_WRONGSEC; 3944 goto nfsmout; 3945 } 3946 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 3947 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 3948 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 3949 sequenceid = fxdr_unsigned(uint32_t, *tl++); 3950 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 3951 highest_slotid = fxdr_unsigned(uint32_t, *tl++); 3952 if (*tl == newnfs_true) 3953 cache_this = 1; 3954 else 3955 cache_this = 0; 3956 nd->nd_flag |= ND_HASSEQUENCE; 3957 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 3958 &target_highest_slotid, cache_this, &sflags, p); 3959 if (nd->nd_repstat == 0) { 3960 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3961 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 3962 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 3963 *tl++ = txdr_unsigned(sequenceid); 3964 *tl++ = txdr_unsigned(nd->nd_slotid); 3965 *tl++ = txdr_unsigned(highest_slotid); 3966 *tl++ = txdr_unsigned(target_highest_slotid); 3967 *tl = txdr_unsigned(sflags); 3968 } 3969nfsmout: 3970 NFSEXITCODE2(error, nd); 3971 return (error); 3972} 3973 3974/* 3975 * nfsv4 reclaim complete service 3976 */ 3977APPLESTATIC int 3978nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 3979 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3980{ 3981 uint32_t *tl; 3982 int error = 0; 3983 3984 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3985 nd->nd_repstat = NFSERR_WRONGSEC; 3986 goto nfsmout; 3987 } 3988 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3989 if (*tl == newnfs_true) 3990 nd->nd_repstat = NFSERR_NOTSUPP; 3991 else 3992 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd); 3993nfsmout: 3994 NFSEXITCODE2(error, nd); 3995 return (error); 3996} 3997 3998/* 3999 * nfsv4 destroy clientid service 4000 */ 4001APPLESTATIC int 4002nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4003 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4004{ 4005 uint32_t *tl; 4006 nfsquad_t clientid; 4007 int error = 0; 4008 4009 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4010 nd->nd_repstat = NFSERR_WRONGSEC; 4011 goto nfsmout; 4012 } 4013 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4014 clientid.lval[0] = *tl++; 4015 clientid.lval[1] = *tl; 4016 nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4017nfsmout: 4018 NFSEXITCODE2(error, nd); 4019 return (error); 4020} 4021 4022/* 4023 * nfsv4 destroy session service 4024 */ 4025APPLESTATIC int 4026nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4027 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4028{ 4029 uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4030 int error = 0; 4031 4032 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4033 nd->nd_repstat = NFSERR_WRONGSEC; 4034 goto nfsmout; 4035 } 4036 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4037 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4038 nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4039nfsmout: 4040 NFSEXITCODE2(error, nd); 4041 return (error); 4042} 4043 4044/* 4045 * nfsv4 free stateid service 4046 */ 4047APPLESTATIC int 4048nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4049 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4050{ 4051 uint32_t *tl; 4052 nfsv4stateid_t stateid; 4053 int error = 0; 4054 4055 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4056 nd->nd_repstat = NFSERR_WRONGSEC; 4057 goto nfsmout; 4058 } 4059 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4060 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4061 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4062 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 4063nfsmout: 4064 NFSEXITCODE2(error, nd); 4065 return (error); 4066} 4067 4068/* 4069 * nfsv4 test stateid service 4070 */ 4071APPLESTATIC int 4072nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, 4073 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4074{ 4075 uint32_t *tl; 4076 nfsv4stateid_t *stateidp = NULL, *tstateidp; 4077 int cnt, error = 0, i, ret; 4078 4079 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4080 nd->nd_repstat = NFSERR_WRONGSEC; 4081 goto nfsmout; 4082 } 4083 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4084 cnt = fxdr_unsigned(int, *tl); 4085 if (cnt <= 0 || cnt > 1024) { 4086 nd->nd_repstat = NFSERR_BADXDR; 4087 goto nfsmout; 4088 } 4089 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); 4090 tstateidp = stateidp; 4091 for (i = 0; i < cnt; i++) { 4092 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4093 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 4094 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); 4095 tstateidp++; 4096 } 4097 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4098 *tl = txdr_unsigned(cnt); 4099 tstateidp = stateidp; 4100 for (i = 0; i < cnt; i++) { 4101 ret = nfsrv_teststateid(nd, tstateidp, p); 4102 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4103 *tl = txdr_unsigned(ret); 4104 tstateidp++; 4105 } 4106nfsmout: 4107 free(stateidp, M_TEMP); 4108 NFSEXITCODE2(error, nd); 4109 return (error); 4110} 4111 4112/* 4113 * nfsv4 service not supported 4114 */ 4115APPLESTATIC int 4116nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 4117 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4118{ 4119 4120 nd->nd_repstat = NFSERR_NOTSUPP; 4121 NFSEXITCODE2(0, nd); 4122 return (0); 4123} 4124 4125