nfs_nfsdserv.c revision 338132
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 338132 2018-08-21 11:17:25Z 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_WDNOTWANTED) != 0) { 2933 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2934 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 2935 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) { 2936 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2937 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE); 2938 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 2939 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2940 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 2941 *tl = newnfs_false; 2942 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 2943 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2944 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 2945 *tl = newnfs_false; 2946 } else { 2947 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2948 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 2949 } 2950 } else 2951 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 2952 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 2953 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 2954 *tl++ = txdr_unsigned(delegstateid.seqid); 2955 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 2956 NFSX_STATEIDOTHER); 2957 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2958 if (rflags & NFSV4OPEN_RECALL) 2959 *tl = newnfs_true; 2960 else 2961 *tl = newnfs_false; 2962 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 2963 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2964 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 2965 txdr_hyper(nva.na_size, tl); 2966 } 2967 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2968 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 2969 *tl++ = txdr_unsigned(0x0); 2970 acemask = NFSV4ACE_ALLFILESMASK; 2971 if (nva.na_mode & S_IRUSR) 2972 acemask |= NFSV4ACE_READMASK; 2973 if (nva.na_mode & S_IWUSR) 2974 acemask |= NFSV4ACE_WRITEMASK; 2975 if (nva.na_mode & S_IXUSR) 2976 acemask |= NFSV4ACE_EXECUTEMASK; 2977 *tl = txdr_unsigned(acemask); 2978 (void) nfsm_strtom(nd, "OWNER@", 6); 2979 } 2980 *vpp = vp; 2981 } else if (vp) { 2982 vrele(vp); 2983 } 2984 if (dirp) 2985 vrele(dirp); 2986#ifdef NFS4_ACL_EXTATTR_NAME 2987 acl_free(aclp); 2988#endif 2989 NFSEXITCODE2(0, nd); 2990 return (0); 2991nfsmout: 2992 vrele(dp); 2993#ifdef NFS4_ACL_EXTATTR_NAME 2994 acl_free(aclp); 2995#endif 2996 if (stp) 2997 FREE((caddr_t)stp, M_NFSDSTATE); 2998 NFSEXITCODE2(error, nd); 2999 return (error); 3000} 3001 3002/* 3003 * nfsv4 close service 3004 */ 3005APPLESTATIC int 3006nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3007 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3008{ 3009 u_int32_t *tl; 3010 struct nfsstate st, *stp = &st; 3011 int error = 0; 3012 nfsv4stateid_t stateid; 3013 nfsquad_t clientid; 3014 3015 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 3016 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3017 stp->ls_ownerlen = 0; 3018 stp->ls_op = nd->nd_rp; 3019 stp->ls_uid = nd->nd_cred->cr_uid; 3020 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3021 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3022 NFSX_STATEIDOTHER); 3023 stp->ls_flags = NFSLCK_CLOSE; 3024 clientid.lval[0] = stp->ls_stateid.other[0]; 3025 clientid.lval[1] = stp->ls_stateid.other[1]; 3026 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3027 if ((nd->nd_flag & ND_NFSV41) != 0) 3028 clientid.qval = nd->nd_clientid.qval; 3029 else if (nd->nd_clientid.qval != clientid.qval) 3030 printf("EEK8 multiple clids\n"); 3031 } else { 3032 if ((nd->nd_flag & ND_NFSV41) != 0) 3033 printf("EEK! no clientid from session\n"); 3034 nd->nd_flag |= ND_IMPLIEDCLID; 3035 nd->nd_clientid.qval = clientid.qval; 3036 } 3037 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 3038 vput(vp); 3039 if (!nd->nd_repstat) { 3040 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3041 *tl++ = txdr_unsigned(stateid.seqid); 3042 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3043 } 3044 NFSEXITCODE2(0, nd); 3045 return (0); 3046nfsmout: 3047 vput(vp); 3048 NFSEXITCODE2(error, nd); 3049 return (error); 3050} 3051 3052/* 3053 * nfsv4 delegpurge service 3054 */ 3055APPLESTATIC int 3056nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3057 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3058{ 3059 u_int32_t *tl; 3060 int error = 0; 3061 nfsquad_t clientid; 3062 3063 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3064 nd->nd_repstat = NFSERR_WRONGSEC; 3065 goto nfsmout; 3066 } 3067 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3068 clientid.lval[0] = *tl++; 3069 clientid.lval[1] = *tl; 3070 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3071 if ((nd->nd_flag & ND_NFSV41) != 0) 3072 clientid.qval = nd->nd_clientid.qval; 3073 else if (nd->nd_clientid.qval != clientid.qval) 3074 printf("EEK9 multiple clids\n"); 3075 } else { 3076 if ((nd->nd_flag & ND_NFSV41) != 0) 3077 printf("EEK! no clientid from session\n"); 3078 nd->nd_flag |= ND_IMPLIEDCLID; 3079 nd->nd_clientid.qval = clientid.qval; 3080 } 3081 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 3082 NFSV4OP_DELEGPURGE, nd->nd_cred, p); 3083nfsmout: 3084 NFSEXITCODE2(error, nd); 3085 return (error); 3086} 3087 3088/* 3089 * nfsv4 delegreturn service 3090 */ 3091APPLESTATIC int 3092nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3093 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3094{ 3095 u_int32_t *tl; 3096 int error = 0; 3097 nfsv4stateid_t stateid; 3098 nfsquad_t clientid; 3099 3100 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3101 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3102 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 3103 clientid.lval[0] = stateid.other[0]; 3104 clientid.lval[1] = stateid.other[1]; 3105 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3106 if ((nd->nd_flag & ND_NFSV41) != 0) 3107 clientid.qval = nd->nd_clientid.qval; 3108 else if (nd->nd_clientid.qval != clientid.qval) 3109 printf("EEK10 multiple clids\n"); 3110 } else { 3111 if ((nd->nd_flag & ND_NFSV41) != 0) 3112 printf("EEK! no clientid from session\n"); 3113 nd->nd_flag |= ND_IMPLIEDCLID; 3114 nd->nd_clientid.qval = clientid.qval; 3115 } 3116 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 3117 NFSV4OP_DELEGRETURN, nd->nd_cred, p); 3118nfsmout: 3119 vput(vp); 3120 NFSEXITCODE2(error, nd); 3121 return (error); 3122} 3123 3124/* 3125 * nfsv4 get file handle service 3126 */ 3127APPLESTATIC int 3128nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3129 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3130{ 3131 fhandle_t fh; 3132 3133 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3134 vput(vp); 3135 if (!nd->nd_repstat) 3136 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3137 NFSEXITCODE2(0, nd); 3138 return (0); 3139} 3140 3141/* 3142 * nfsv4 open confirm service 3143 */ 3144APPLESTATIC int 3145nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3146 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3147{ 3148 u_int32_t *tl; 3149 struct nfsstate st, *stp = &st; 3150 int error = 0; 3151 nfsv4stateid_t stateid; 3152 nfsquad_t clientid; 3153 3154 if ((nd->nd_flag & ND_NFSV41) != 0) { 3155 nd->nd_repstat = NFSERR_NOTSUPP; 3156 goto nfsmout; 3157 } 3158 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3159 stp->ls_ownerlen = 0; 3160 stp->ls_op = nd->nd_rp; 3161 stp->ls_uid = nd->nd_cred->cr_uid; 3162 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3163 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3164 NFSX_STATEIDOTHER); 3165 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3166 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 3167 stp->ls_flags = NFSLCK_CONFIRM; 3168 clientid.lval[0] = stp->ls_stateid.other[0]; 3169 clientid.lval[1] = stp->ls_stateid.other[1]; 3170 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3171 if ((nd->nd_flag & ND_NFSV41) != 0) 3172 clientid.qval = nd->nd_clientid.qval; 3173 else if (nd->nd_clientid.qval != clientid.qval) 3174 printf("EEK11 multiple clids\n"); 3175 } else { 3176 if ((nd->nd_flag & ND_NFSV41) != 0) 3177 printf("EEK! no clientid from session\n"); 3178 nd->nd_flag |= ND_IMPLIEDCLID; 3179 nd->nd_clientid.qval = clientid.qval; 3180 } 3181 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 3182 if (!nd->nd_repstat) { 3183 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3184 *tl++ = txdr_unsigned(stateid.seqid); 3185 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3186 } 3187nfsmout: 3188 vput(vp); 3189 NFSEXITCODE2(error, nd); 3190 return (error); 3191} 3192 3193/* 3194 * nfsv4 open downgrade service 3195 */ 3196APPLESTATIC int 3197nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3198 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3199{ 3200 u_int32_t *tl; 3201 int i; 3202 struct nfsstate st, *stp = &st; 3203 int error = 0; 3204 nfsv4stateid_t stateid; 3205 nfsquad_t clientid; 3206 3207 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 3208 stp->ls_ownerlen = 0; 3209 stp->ls_op = nd->nd_rp; 3210 stp->ls_uid = nd->nd_cred->cr_uid; 3211 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3212 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3213 NFSX_STATEIDOTHER); 3214 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3215 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3216 i = fxdr_unsigned(int, *tl++); 3217 switch (i) { 3218 case NFSV4OPEN_ACCESSREAD: 3219 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3220 break; 3221 case NFSV4OPEN_ACCESSWRITE: 3222 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3223 break; 3224 case NFSV4OPEN_ACCESSBOTH: 3225 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3226 NFSLCK_DOWNGRADE); 3227 break; 3228 default: 3229 nd->nd_repstat = NFSERR_BADXDR; 3230 }; 3231 i = fxdr_unsigned(int, *tl); 3232 switch (i) { 3233 case NFSV4OPEN_DENYNONE: 3234 break; 3235 case NFSV4OPEN_DENYREAD: 3236 stp->ls_flags |= NFSLCK_READDENY; 3237 break; 3238 case NFSV4OPEN_DENYWRITE: 3239 stp->ls_flags |= NFSLCK_WRITEDENY; 3240 break; 3241 case NFSV4OPEN_DENYBOTH: 3242 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3243 break; 3244 default: 3245 nd->nd_repstat = NFSERR_BADXDR; 3246 }; 3247 3248 clientid.lval[0] = stp->ls_stateid.other[0]; 3249 clientid.lval[1] = stp->ls_stateid.other[1]; 3250 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3251 if ((nd->nd_flag & ND_NFSV41) != 0) 3252 clientid.qval = nd->nd_clientid.qval; 3253 else if (nd->nd_clientid.qval != clientid.qval) 3254 printf("EEK12 multiple clids\n"); 3255 } else { 3256 if ((nd->nd_flag & ND_NFSV41) != 0) 3257 printf("EEK! no clientid from session\n"); 3258 nd->nd_flag |= ND_IMPLIEDCLID; 3259 nd->nd_clientid.qval = clientid.qval; 3260 } 3261 if (!nd->nd_repstat) 3262 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3263 nd, p); 3264 if (!nd->nd_repstat) { 3265 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3266 *tl++ = txdr_unsigned(stateid.seqid); 3267 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3268 } 3269nfsmout: 3270 vput(vp); 3271 NFSEXITCODE2(error, nd); 3272 return (error); 3273} 3274 3275/* 3276 * nfsv4 renew lease service 3277 */ 3278APPLESTATIC int 3279nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3280 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3281{ 3282 u_int32_t *tl; 3283 int error = 0; 3284 nfsquad_t clientid; 3285 3286 if ((nd->nd_flag & ND_NFSV41) != 0) { 3287 nd->nd_repstat = NFSERR_NOTSUPP; 3288 goto nfsmout; 3289 } 3290 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3291 nd->nd_repstat = NFSERR_WRONGSEC; 3292 goto nfsmout; 3293 } 3294 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3295 clientid.lval[0] = *tl++; 3296 clientid.lval[1] = *tl; 3297 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3298 if ((nd->nd_flag & ND_NFSV41) != 0) 3299 clientid.qval = nd->nd_clientid.qval; 3300 else if (nd->nd_clientid.qval != clientid.qval) 3301 printf("EEK13 multiple clids\n"); 3302 } else { 3303 if ((nd->nd_flag & ND_NFSV41) != 0) 3304 printf("EEK! no clientid from session\n"); 3305 nd->nd_flag |= ND_IMPLIEDCLID; 3306 nd->nd_clientid.qval = clientid.qval; 3307 } 3308 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3309 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 3310nfsmout: 3311 NFSEXITCODE2(error, nd); 3312 return (error); 3313} 3314 3315/* 3316 * nfsv4 security info service 3317 */ 3318APPLESTATIC int 3319nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3320 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 3321{ 3322 u_int32_t *tl; 3323 int len; 3324 struct nameidata named; 3325 vnode_t dirp = NULL, vp; 3326 struct nfsrvfh fh; 3327 struct nfsexstuff retnes; 3328 u_int32_t *sizp; 3329 int error = 0, savflag, i; 3330 char *bufp; 3331 u_long *hashp; 3332 3333 /* 3334 * All this just to get the export flags for the name. 3335 */ 3336 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3337 LOCKLEAF | SAVESTART); 3338 nfsvno_setpathbuf(&named, &bufp, &hashp); 3339 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3340 if (error) { 3341 vput(dp); 3342 nfsvno_relpathbuf(&named); 3343 goto out; 3344 } 3345 if (!nd->nd_repstat) { 3346 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3347 } else { 3348 vput(dp); 3349 nfsvno_relpathbuf(&named); 3350 } 3351 if (dirp) 3352 vrele(dirp); 3353 if (nd->nd_repstat) 3354 goto out; 3355 vrele(named.ni_startdir); 3356 nfsvno_relpathbuf(&named); 3357 fh.nfsrvfh_len = NFSX_MYFH; 3358 vp = named.ni_vp; 3359 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3360 vput(vp); 3361 savflag = nd->nd_flag; 3362 if (!nd->nd_repstat) { 3363 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p); 3364 if (vp) 3365 vput(vp); 3366 } 3367 nd->nd_flag = savflag; 3368 if (nd->nd_repstat) 3369 goto out; 3370 3371 /* 3372 * Finally have the export flags for name, so we can create 3373 * the security info. 3374 */ 3375 len = 0; 3376 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3377 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3378 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3379 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3380 *tl = txdr_unsigned(RPCAUTH_UNIX); 3381 len++; 3382 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3383 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3384 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3385 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3386 nfsgss_mechlist[KERBV_MECH].len); 3387 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3388 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3389 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3390 len++; 3391 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3392 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3393 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3394 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3395 nfsgss_mechlist[KERBV_MECH].len); 3396 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3397 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3398 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3399 len++; 3400 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3401 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3402 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3403 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3404 nfsgss_mechlist[KERBV_MECH].len); 3405 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3406 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3407 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3408 len++; 3409 } 3410 } 3411 *sizp = txdr_unsigned(len); 3412 3413out: 3414 NFSEXITCODE2(error, nd); 3415 return (error); 3416} 3417 3418/* 3419 * nfsv4 set client id service 3420 */ 3421APPLESTATIC int 3422nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3423 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3424{ 3425 u_int32_t *tl; 3426 int i; 3427 int error = 0, idlen; 3428 struct nfsclient *clp = NULL; 3429 struct sockaddr_in *rad; 3430 u_char *verf, *ucp, *ucp2, addrbuf[24]; 3431 nfsquad_t clientid, confirm; 3432 3433 if ((nd->nd_flag & ND_NFSV41) != 0) { 3434 nd->nd_repstat = NFSERR_NOTSUPP; 3435 goto nfsmout; 3436 } 3437 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3438 nd->nd_repstat = NFSERR_WRONGSEC; 3439 goto out; 3440 } 3441 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3442 verf = (u_char *)tl; 3443 tl += (NFSX_VERF / NFSX_UNSIGNED); 3444 i = fxdr_unsigned(int, *tl); 3445 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3446 nd->nd_repstat = NFSERR_BADXDR; 3447 goto nfsmout; 3448 } 3449 idlen = i; 3450 if (nd->nd_flag & ND_GSS) 3451 i += nd->nd_princlen; 3452 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3453 M_ZERO); 3454 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3455 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3456 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3457 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3458 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3459 clp->lc_req.nr_cred = NULL; 3460 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3461 clp->lc_idlen = idlen; 3462 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3463 if (error) 3464 goto nfsmout; 3465 if (nd->nd_flag & ND_GSS) { 3466 clp->lc_flags = LCL_GSS; 3467 if (nd->nd_flag & ND_GSSINTEGRITY) 3468 clp->lc_flags |= LCL_GSSINTEGRITY; 3469 else if (nd->nd_flag & ND_GSSPRIVACY) 3470 clp->lc_flags |= LCL_GSSPRIVACY; 3471 } else { 3472 clp->lc_flags = 0; 3473 } 3474 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 3475 clp->lc_flags |= LCL_NAME; 3476 clp->lc_namelen = nd->nd_princlen; 3477 clp->lc_name = &clp->lc_id[idlen]; 3478 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3479 } else { 3480 clp->lc_uid = nd->nd_cred->cr_uid; 3481 clp->lc_gid = nd->nd_cred->cr_gid; 3482 } 3483 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3484 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 3485 error = nfsrv_getclientipaddr(nd, clp); 3486 if (error) 3487 goto nfsmout; 3488 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3489 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 3490 3491 /* 3492 * nfsrv_setclient() does the actual work of adding it to the 3493 * client list. If there is no error, the structure has been 3494 * linked into the client list and clp should no longer be used 3495 * here. When an error is returned, it has not been linked in, 3496 * so it should be free'd. 3497 */ 3498 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3499 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3500 if (clp->lc_flags & LCL_TCPCALLBACK) 3501 (void) nfsm_strtom(nd, "tcp", 3); 3502 else 3503 (void) nfsm_strtom(nd, "udp", 3); 3504 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3505 ucp = (u_char *)&rad->sin_addr.s_addr; 3506 ucp2 = (u_char *)&rad->sin_port; 3507 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 3508 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 3509 ucp2[0] & 0xff, ucp2[1] & 0xff); 3510 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3511 } 3512 if (clp) { 3513 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3514 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3515 free(clp->lc_stateid, M_NFSDCLIENT); 3516 free(clp, M_NFSDCLIENT); 3517 } 3518 if (!nd->nd_repstat) { 3519 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 3520 *tl++ = clientid.lval[0]; 3521 *tl++ = clientid.lval[1]; 3522 *tl++ = confirm.lval[0]; 3523 *tl = confirm.lval[1]; 3524 } 3525 3526out: 3527 NFSEXITCODE2(0, nd); 3528 return (0); 3529nfsmout: 3530 if (clp) { 3531 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3532 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3533 free(clp->lc_stateid, M_NFSDCLIENT); 3534 free(clp, M_NFSDCLIENT); 3535 } 3536 NFSEXITCODE2(error, nd); 3537 return (error); 3538} 3539 3540/* 3541 * nfsv4 set client id confirm service 3542 */ 3543APPLESTATIC int 3544nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3545 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p, 3546 __unused struct nfsexstuff *exp) 3547{ 3548 u_int32_t *tl; 3549 int error = 0; 3550 nfsquad_t clientid, confirm; 3551 3552 if ((nd->nd_flag & ND_NFSV41) != 0) { 3553 nd->nd_repstat = NFSERR_NOTSUPP; 3554 goto nfsmout; 3555 } 3556 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3557 nd->nd_repstat = NFSERR_WRONGSEC; 3558 goto nfsmout; 3559 } 3560 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 3561 clientid.lval[0] = *tl++; 3562 clientid.lval[1] = *tl++; 3563 confirm.lval[0] = *tl++; 3564 confirm.lval[1] = *tl; 3565 3566 /* 3567 * nfsrv_getclient() searches the client list for a match and 3568 * returns the appropriate NFSERR status. 3569 */ 3570 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3571 NULL, NULL, confirm, 0, nd, p); 3572nfsmout: 3573 NFSEXITCODE2(error, nd); 3574 return (error); 3575} 3576 3577/* 3578 * nfsv4 verify service 3579 */ 3580APPLESTATIC int 3581nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3582 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3583{ 3584 int error = 0, ret, fhsize = NFSX_MYFH; 3585 struct nfsvattr nva; 3586 struct statfs sf; 3587 struct nfsfsinfo fs; 3588 fhandle_t fh; 3589 3590 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 3591 if (!nd->nd_repstat) 3592 nd->nd_repstat = nfsvno_statfs(vp, &sf); 3593 if (!nd->nd_repstat) 3594 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3595 if (!nd->nd_repstat) { 3596 nfsvno_getfs(&fs, isdgram); 3597 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 3598 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 3599 if (!error) { 3600 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 3601 if (ret == 0) 3602 nd->nd_repstat = NFSERR_SAME; 3603 else if (ret != NFSERR_NOTSAME) 3604 nd->nd_repstat = ret; 3605 } else if (ret) 3606 nd->nd_repstat = ret; 3607 } 3608 } 3609 vput(vp); 3610 NFSEXITCODE2(error, nd); 3611 return (error); 3612} 3613 3614/* 3615 * nfs openattr rpc 3616 */ 3617APPLESTATIC int 3618nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 3619 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3620 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3621{ 3622 u_int32_t *tl; 3623 int error = 0, createdir; 3624 3625 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3626 createdir = fxdr_unsigned(int, *tl); 3627 nd->nd_repstat = NFSERR_NOTSUPP; 3628nfsmout: 3629 vrele(dp); 3630 NFSEXITCODE2(error, nd); 3631 return (error); 3632} 3633 3634/* 3635 * nfsv4 release lock owner service 3636 */ 3637APPLESTATIC int 3638nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 3639 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3640{ 3641 u_int32_t *tl; 3642 struct nfsstate *stp = NULL; 3643 int error = 0, len; 3644 nfsquad_t clientid; 3645 3646 if ((nd->nd_flag & ND_NFSV41) != 0) { 3647 nd->nd_repstat = NFSERR_NOTSUPP; 3648 goto nfsmout; 3649 } 3650 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3651 nd->nd_repstat = NFSERR_WRONGSEC; 3652 goto nfsmout; 3653 } 3654 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3655 len = fxdr_unsigned(int, *(tl + 2)); 3656 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 3657 nd->nd_repstat = NFSERR_BADXDR; 3658 goto nfsmout; 3659 } 3660 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len, 3661 M_NFSDSTATE, M_WAITOK); 3662 stp->ls_ownerlen = len; 3663 stp->ls_op = NULL; 3664 stp->ls_flags = NFSLCK_RELEASE; 3665 stp->ls_uid = nd->nd_cred->cr_uid; 3666 clientid.lval[0] = *tl++; 3667 clientid.lval[1] = *tl; 3668 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3669 if ((nd->nd_flag & ND_NFSV41) != 0) 3670 clientid.qval = nd->nd_clientid.qval; 3671 else if (nd->nd_clientid.qval != clientid.qval) 3672 printf("EEK14 multiple clids\n"); 3673 } else { 3674 if ((nd->nd_flag & ND_NFSV41) != 0) 3675 printf("EEK! no clientid from session\n"); 3676 nd->nd_flag |= ND_IMPLIEDCLID; 3677 nd->nd_clientid.qval = clientid.qval; 3678 } 3679 error = nfsrv_mtostr(nd, stp->ls_owner, len); 3680 if (error) 3681 goto nfsmout; 3682 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 3683 FREE((caddr_t)stp, M_NFSDSTATE); 3684 3685 NFSEXITCODE2(0, nd); 3686 return (0); 3687nfsmout: 3688 if (stp) 3689 free((caddr_t)stp, M_NFSDSTATE); 3690 NFSEXITCODE2(error, nd); 3691 return (error); 3692} 3693 3694/* 3695 * nfsv4 exchange_id service 3696 */ 3697APPLESTATIC int 3698nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 3699 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3700{ 3701 uint32_t *tl; 3702 int error = 0, i, idlen; 3703 struct nfsclient *clp = NULL; 3704 nfsquad_t clientid, confirm; 3705 uint8_t *verf; 3706 uint32_t sp4type, v41flags; 3707 uint64_t owner_minor; 3708 struct timespec verstime; 3709 struct sockaddr_in *sad, *rad; 3710 3711 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3712 nd->nd_repstat = NFSERR_WRONGSEC; 3713 goto nfsmout; 3714 } 3715 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3716 verf = (uint8_t *)tl; 3717 tl += (NFSX_VERF / NFSX_UNSIGNED); 3718 i = fxdr_unsigned(int, *tl); 3719 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3720 nd->nd_repstat = NFSERR_BADXDR; 3721 goto nfsmout; 3722 } 3723 idlen = i; 3724 if (nd->nd_flag & ND_GSS) 3725 i += nd->nd_princlen; 3726 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3727 M_ZERO); 3728 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3729 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3730 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3731 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3732 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3733 sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *); 3734 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3735 rad->sin_family = AF_INET; 3736 rad->sin_addr.s_addr = 0; 3737 rad->sin_port = 0; 3738 if (sad->sin_family == AF_INET) 3739 rad->sin_addr.s_addr = sad->sin_addr.s_addr; 3740 clp->lc_req.nr_cred = NULL; 3741 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3742 clp->lc_idlen = idlen; 3743 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3744 if (error != 0) 3745 goto nfsmout; 3746 if ((nd->nd_flag & ND_GSS) != 0) { 3747 clp->lc_flags = LCL_GSS | LCL_NFSV41; 3748 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 3749 clp->lc_flags |= LCL_GSSINTEGRITY; 3750 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 3751 clp->lc_flags |= LCL_GSSPRIVACY; 3752 } else 3753 clp->lc_flags = LCL_NFSV41; 3754 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 3755 clp->lc_flags |= LCL_NAME; 3756 clp->lc_namelen = nd->nd_princlen; 3757 clp->lc_name = &clp->lc_id[idlen]; 3758 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3759 } else { 3760 clp->lc_uid = nd->nd_cred->cr_uid; 3761 clp->lc_gid = nd->nd_cred->cr_gid; 3762 } 3763 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3764 v41flags = fxdr_unsigned(uint32_t, *tl++); 3765 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 3766 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 3767 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 3768 nd->nd_repstat = NFSERR_INVAL; 3769 goto nfsmout; 3770 } 3771 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 3772 confirm.lval[1] = 1; 3773 else 3774 confirm.lval[1] = 0; 3775 v41flags = NFSV4EXCH_USENONPNFS; 3776 sp4type = fxdr_unsigned(uint32_t, *tl); 3777 if (sp4type != NFSV4EXCH_SP4NONE) { 3778 nd->nd_repstat = NFSERR_NOTSUPP; 3779 goto nfsmout; 3780 } 3781 3782 /* 3783 * nfsrv_setclient() does the actual work of adding it to the 3784 * client list. If there is no error, the structure has been 3785 * linked into the client list and clp should no longer be used 3786 * here. When an error is returned, it has not been linked in, 3787 * so it should be free'd. 3788 */ 3789 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3790 if (clp != NULL) { 3791 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3792 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3793 free(clp->lc_stateid, M_NFSDCLIENT); 3794 free(clp, M_NFSDCLIENT); 3795 } 3796 if (nd->nd_repstat == 0) { 3797 if (confirm.lval[1] != 0) 3798 v41flags |= NFSV4EXCH_CONFIRMEDR; 3799 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 3800 *tl++ = clientid.lval[0]; /* ClientID */ 3801 *tl++ = clientid.lval[1]; 3802 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 3803 *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 3804 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 3805 owner_minor = 0; /* Owner */ 3806 txdr_hyper(owner_minor, tl); /* Minor */ 3807 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 3808 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 3809 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 3810 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */ 3811 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3812 *tl = txdr_unsigned(1); 3813 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 3814 (void)nfsm_strtom(nd, version, strlen(version)); 3815 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 3816 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 3817 verstime.tv_nsec = 0; 3818 txdr_nfsv4time(&verstime, tl); 3819 } 3820 NFSEXITCODE2(0, nd); 3821 return (0); 3822nfsmout: 3823 if (clp != NULL) { 3824 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3825 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3826 free(clp->lc_stateid, M_NFSDCLIENT); 3827 free(clp, M_NFSDCLIENT); 3828 } 3829 NFSEXITCODE2(error, nd); 3830 return (error); 3831} 3832 3833/* 3834 * nfsv4 create session service 3835 */ 3836APPLESTATIC int 3837nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 3838 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3839{ 3840 uint32_t *tl; 3841 int error = 0; 3842 nfsquad_t clientid, confirm; 3843 struct nfsdsession *sep = NULL; 3844 uint32_t rdmacnt; 3845 3846 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3847 nd->nd_repstat = NFSERR_WRONGSEC; 3848 goto nfsmout; 3849 } 3850 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 3851 M_NFSDSESSION, M_WAITOK | M_ZERO); 3852 sep->sess_refcnt = 1; 3853 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 3854 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 3855 clientid.lval[0] = *tl++; 3856 clientid.lval[1] = *tl++; 3857 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 3858 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 3859 /* Persistent sessions and RDMA are not supported. */ 3860 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 3861 3862 /* Fore channel attributes. */ 3863 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3864 tl++; /* Header pad always 0. */ 3865 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 3866 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 3867 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 3868 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 3869 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 3870 if (sep->sess_maxslots > NFSV4_SLOTS) 3871 sep->sess_maxslots = NFSV4_SLOTS; 3872 rdmacnt = fxdr_unsigned(uint32_t, *tl); 3873 if (rdmacnt > 1) { 3874 nd->nd_repstat = NFSERR_BADXDR; 3875 goto nfsmout; 3876 } else if (rdmacnt == 1) 3877 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3878 3879 /* Back channel attributes. */ 3880 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3881 tl++; /* Header pad always 0. */ 3882 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 3883 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 3884 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 3885 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 3886 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 3887 rdmacnt = fxdr_unsigned(uint32_t, *tl); 3888 if (rdmacnt > 1) { 3889 nd->nd_repstat = NFSERR_BADXDR; 3890 goto nfsmout; 3891 } else if (rdmacnt == 1) 3892 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3893 3894 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3895 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 3896 3897 /* 3898 * nfsrv_getclient() searches the client list for a match and 3899 * returns the appropriate NFSERR status. 3900 */ 3901 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 3902 NULL, sep, confirm, sep->sess_cbprogram, nd, p); 3903 if (nd->nd_repstat == 0) { 3904 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3905 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 3906 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 3907 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 3908 *tl++ = txdr_unsigned(sep->sess_crflags); 3909 3910 /* Fore channel attributes. */ 3911 *tl++ = 0; 3912 *tl++ = txdr_unsigned(sep->sess_maxreq); 3913 *tl++ = txdr_unsigned(sep->sess_maxresp); 3914 *tl++ = txdr_unsigned(sep->sess_maxrespcached); 3915 *tl++ = txdr_unsigned(sep->sess_maxops); 3916 *tl++ = txdr_unsigned(sep->sess_maxslots); 3917 *tl++ = txdr_unsigned(1); 3918 *tl++ = txdr_unsigned(0); /* No RDMA. */ 3919 3920 /* Back channel attributes. */ 3921 *tl++ = 0; 3922 *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 3923 *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 3924 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 3925 *tl++ = txdr_unsigned(sep->sess_cbmaxops); 3926 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 3927 *tl++ = txdr_unsigned(1); 3928 *tl = txdr_unsigned(0); /* No RDMA. */ 3929 } 3930nfsmout: 3931 if (nd->nd_repstat != 0 && sep != NULL) 3932 free(sep, M_NFSDSESSION); 3933 NFSEXITCODE2(error, nd); 3934 return (error); 3935} 3936 3937/* 3938 * nfsv4 sequence service 3939 */ 3940APPLESTATIC int 3941nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 3942 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3943{ 3944 uint32_t *tl; 3945 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 3946 int cache_this, error = 0; 3947 3948 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3949 nd->nd_repstat = NFSERR_WRONGSEC; 3950 goto nfsmout; 3951 } 3952 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 3953 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 3954 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 3955 sequenceid = fxdr_unsigned(uint32_t, *tl++); 3956 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 3957 highest_slotid = fxdr_unsigned(uint32_t, *tl++); 3958 if (*tl == newnfs_true) 3959 cache_this = 1; 3960 else 3961 cache_this = 0; 3962 nd->nd_flag |= ND_HASSEQUENCE; 3963 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 3964 &target_highest_slotid, cache_this, &sflags, p); 3965 if (nd->nd_repstat == 0) { 3966 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3967 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 3968 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 3969 *tl++ = txdr_unsigned(sequenceid); 3970 *tl++ = txdr_unsigned(nd->nd_slotid); 3971 *tl++ = txdr_unsigned(highest_slotid); 3972 *tl++ = txdr_unsigned(target_highest_slotid); 3973 *tl = txdr_unsigned(sflags); 3974 } 3975nfsmout: 3976 NFSEXITCODE2(error, nd); 3977 return (error); 3978} 3979 3980/* 3981 * nfsv4 reclaim complete service 3982 */ 3983APPLESTATIC int 3984nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 3985 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3986{ 3987 uint32_t *tl; 3988 int error = 0, onefs; 3989 3990 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3991 nd->nd_repstat = NFSERR_WRONGSEC; 3992 goto nfsmout; 3993 } 3994 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3995 /* 3996 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only 3997 * to be used after a file system has been transferred to a different 3998 * file server. However, RFC5661 is somewhat vague w.r.t. this and 3999 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs 4000 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE. 4001 * Therefore, just ignore the rca_one_fs == TRUE operation and return 4002 * NFS_OK without doing anything. 4003 */ 4004 onefs = 0; 4005 if (*tl == newnfs_true) 4006 onefs = 1; 4007 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs); 4008nfsmout: 4009 NFSEXITCODE2(error, nd); 4010 return (error); 4011} 4012 4013/* 4014 * nfsv4 destroy clientid service 4015 */ 4016APPLESTATIC int 4017nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4018 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4019{ 4020 uint32_t *tl; 4021 nfsquad_t clientid; 4022 int error = 0; 4023 4024 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4025 nd->nd_repstat = NFSERR_WRONGSEC; 4026 goto nfsmout; 4027 } 4028 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4029 clientid.lval[0] = *tl++; 4030 clientid.lval[1] = *tl; 4031 nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4032nfsmout: 4033 NFSEXITCODE2(error, nd); 4034 return (error); 4035} 4036 4037/* 4038 * nfsv4 bind connection to session service 4039 */ 4040APPLESTATIC int 4041nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram, 4042 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4043{ 4044 uint32_t *tl; 4045 uint8_t sessid[NFSX_V4SESSIONID]; 4046 int error = 0, foreaft; 4047 4048 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4049 nd->nd_repstat = NFSERR_WRONGSEC; 4050 goto nfsmout; 4051 } 4052 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 4053 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID); 4054 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4055 foreaft = fxdr_unsigned(int, *tl++); 4056 if (*tl == newnfs_true) { 4057 /* RDMA is not supported. */ 4058 nd->nd_repstat = NFSERR_NOTSUPP; 4059 goto nfsmout; 4060 } 4061 4062 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft); 4063 if (nd->nd_repstat == 0) { 4064 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * 4065 NFSX_UNSIGNED); 4066 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID); 4067 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4068 *tl++ = txdr_unsigned(foreaft); 4069 *tl = newnfs_false; 4070 } 4071nfsmout: 4072 NFSEXITCODE2(error, nd); 4073 return (error); 4074} 4075 4076/* 4077 * nfsv4 destroy session service 4078 */ 4079APPLESTATIC int 4080nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4081 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4082{ 4083 uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4084 int error = 0; 4085 4086 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4087 nd->nd_repstat = NFSERR_WRONGSEC; 4088 goto nfsmout; 4089 } 4090 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4091 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4092 nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4093nfsmout: 4094 NFSEXITCODE2(error, nd); 4095 return (error); 4096} 4097 4098/* 4099 * nfsv4 free stateid service 4100 */ 4101APPLESTATIC int 4102nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4103 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4104{ 4105 uint32_t *tl; 4106 nfsv4stateid_t stateid; 4107 int error = 0; 4108 4109 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4110 nd->nd_repstat = NFSERR_WRONGSEC; 4111 goto nfsmout; 4112 } 4113 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4114 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4115 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4116 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 4117nfsmout: 4118 NFSEXITCODE2(error, nd); 4119 return (error); 4120} 4121 4122/* 4123 * nfsv4 test stateid service 4124 */ 4125APPLESTATIC int 4126nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, 4127 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4128{ 4129 uint32_t *tl; 4130 nfsv4stateid_t *stateidp = NULL, *tstateidp; 4131 int cnt, error = 0, i, ret; 4132 4133 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4134 nd->nd_repstat = NFSERR_WRONGSEC; 4135 goto nfsmout; 4136 } 4137 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4138 cnt = fxdr_unsigned(int, *tl); 4139 if (cnt <= 0 || cnt > 1024) { 4140 nd->nd_repstat = NFSERR_BADXDR; 4141 goto nfsmout; 4142 } 4143 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); 4144 tstateidp = stateidp; 4145 for (i = 0; i < cnt; i++) { 4146 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4147 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 4148 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); 4149 tstateidp++; 4150 } 4151 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4152 *tl = txdr_unsigned(cnt); 4153 tstateidp = stateidp; 4154 for (i = 0; i < cnt; i++) { 4155 ret = nfsrv_teststateid(nd, tstateidp, p); 4156 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4157 *tl = txdr_unsigned(ret); 4158 tstateidp++; 4159 } 4160nfsmout: 4161 free(stateidp, M_TEMP); 4162 NFSEXITCODE2(error, nd); 4163 return (error); 4164} 4165 4166/* 4167 * nfsv4 service not supported 4168 */ 4169APPLESTATIC int 4170nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 4171 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4172{ 4173 4174 nd->nd_repstat = NFSERR_NOTSUPP; 4175 NFSEXITCODE2(0, nd); 4176 return (0); 4177} 4178 4179