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