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 */ 51 extern u_int32_t newnfs_false, newnfs_true; 52 extern enum vtype nv34tov_type[8]; 53 extern struct timeval nfsboottime; 54 extern int nfs_rootfhset; 55 extern int nfsrv_enable_crossmntpt; 56 #endif /* !APPLEKEXT */ 57 58 static int nfs_async = 0; 59 SYSCTL_DECL(_vfs_nfsd); 60 SYSCTL_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 */ 68 static 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 */ 74 static 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); 80 static 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 */ 89 APPLESTATIC int 90 nfsrvd_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 164 out: 165 NFSEXITCODE2(0, nd); 166 return (0); 167 nfsmout: 168 vput(vp); 169 NFSEXITCODE2(error, nd); 170 return (error); 171 } 172 173 /* 174 * nfs getattr service 175 */ 176 APPLESTATIC int 177 nfsrvd_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 283 out: 284 NFSEXITCODE2(error, nd); 285 return (error); 286 } 287 288 /* 289 * nfs setattr service 290 */ 291 APPLESTATIC int 292 nfsrvd_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 456 out: 457 NFSEXITCODE2(0, nd); 458 return (0); 459 nfsmout: 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 */ 480 APPLESTATIC int 481 nfsrvd_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 572 out: 573 NFSEXITCODE2(error, nd); 574 return (error); 575 } 576 577 /* 578 * nfs readlink service 579 */ 580 APPLESTATIC int 581 nfsrvd_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 615 out: 616 NFSEXITCODE2(0, nd); 617 return (0); 618 } 619 620 /* 621 * nfs read service 622 */ 623 APPLESTATIC int 624 nfsrvd_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 768 out: 769 NFSEXITCODE2(0, nd); 770 return (0); 771 nfsmout: 772 vput(vp); 773 NFSEXITCODE2(error, nd); 774 return (error); 775 } 776 777 /* 778 * nfs write service 779 */ 780 APPLESTATIC int 781 nfsrvd_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 940 out: 941 NFSEXITCODE2(0, nd); 942 return (0); 943 nfsmout: 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 */ 955 APPLESTATIC int 956 nfsrvd_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 1111 out: 1112 NFSEXITCODE2(0, nd); 1113 return (0); 1114 nfsmout: 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 */ 1124 APPLESTATIC int 1125 nfsrvd_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 1322 out: 1323 NFSEXITCODE2(0, nd); 1324 return (0); 1325 nfsmout: 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 */ 1342 APPLESTATIC int 1343 nfsrvd_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 1416 out: 1417 NFSEXITCODE2(error, nd); 1418 return (error); 1419 } 1420 1421 /* 1422 * nfs rename service 1423 */ 1424 APPLESTATIC int 1425 nfsrvd_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 1587 out: 1588 NFSEXITCODE2(error, nd); 1589 return (error); 1590 } 1591 1592 /* 1593 * nfs link service 1594 */ 1595 APPLESTATIC int 1596 nfsrvd_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 } else if (vnode_vtype(vp) == VLNK) { 1624 if (nd->nd_flag & ND_NFSV2) 1625 nd->nd_repstat = NFSERR_INVAL; 1626 else 1627 nd->nd_repstat = NFSERR_NOTSUPP; 1628 if (tovp) 1629 vrele(tovp); 1630 } 1631 if (!nd->nd_repstat) { 1632 if (nd->nd_flag & ND_NFSV4) { 1633 dp = tovp; 1634 tnes = *toexp; 1635 } else { 1636 error = nfsrv_mtofh(nd, &dfh); 1637 if (error) { 1638 vrele(vp); 1639 /* tovp is always NULL unless NFSv4 */ 1640 goto out; 1641 } 1642 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0, 1643 p); 1644 if (dp) 1645 NFSVOPUNLOCK(dp, 0); 1646 } 1647 } 1648 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1649 LOCKPARENT | SAVENAME); 1650 if (!nd->nd_repstat) { 1651 nfsvno_setpathbuf(&named, &bufp, &hashp); 1652 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1653 if (error) { 1654 vrele(vp); 1655 if (dp) 1656 vrele(dp); 1657 nfsvno_relpathbuf(&named); 1658 goto out; 1659 } 1660 if (!nd->nd_repstat) { 1661 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 1662 p, &dirp); 1663 } else { 1664 if (dp) 1665 vrele(dp); 1666 nfsvno_relpathbuf(&named); 1667 } 1668 } 1669 if (dirp) { 1670 if (nd->nd_flag & ND_NFSV2) { 1671 vrele(dirp); 1672 dirp = NULL; 1673 } else { 1674 dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1675 nd->nd_cred, p, 0); 1676 } 1677 } 1678 if (!nd->nd_repstat) 1679 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 1680 if (nd->nd_flag & ND_NFSV3) 1681 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0); 1682 if (dirp) { 1683 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 1684 vrele(dirp); 1685 } 1686 vrele(vp); 1687 if (nd->nd_flag & ND_NFSV3) { 1688 nfsrv_postopattr(nd, getret, &at); 1689 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1690 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1691 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1692 *tl++ = newnfs_false; 1693 txdr_hyper(dirfor.na_filerev, tl); 1694 tl += 2; 1695 txdr_hyper(diraft.na_filerev, tl); 1696 } 1697 1698 out: 1699 NFSEXITCODE2(error, nd); 1700 return (error); 1701 } 1702 1703 /* 1704 * nfs symbolic link service 1705 */ 1706 APPLESTATIC int 1707 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1708 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1709 struct nfsexstuff *exp) 1710 { 1711 struct nfsvattr nva, dirfor, diraft; 1712 struct nameidata named; 1713 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 1714 vnode_t dirp = NULL; 1715 char *bufp, *pathcp = NULL; 1716 u_long *hashp; 1717 1718 if (nd->nd_repstat) { 1719 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1720 goto out; 1721 } 1722 if (vpp) 1723 *vpp = NULL; 1724 NFSVNO_ATTRINIT(&nva); 1725 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1726 LOCKPARENT | SAVESTART); 1727 nfsvno_setpathbuf(&named, &bufp, &hashp); 1728 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1729 if (!error && !nd->nd_repstat) 1730 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 1731 if (error) { 1732 vrele(dp); 1733 nfsvno_relpathbuf(&named); 1734 goto out; 1735 } 1736 if (!nd->nd_repstat) { 1737 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1738 } else { 1739 vrele(dp); 1740 nfsvno_relpathbuf(&named); 1741 } 1742 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1743 vrele(dirp); 1744 dirp = NULL; 1745 } 1746 1747 /* 1748 * And call nfsrvd_symlinksub() to do the common code. It will 1749 * return EBADRPC upon a parsing error, 0 otherwise. 1750 */ 1751 if (!nd->nd_repstat) { 1752 if (dirp != NULL) 1753 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1754 p, 0); 1755 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1756 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 1757 pathcp, pathlen); 1758 } else if (dirp != NULL) { 1759 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 1760 vrele(dirp); 1761 } 1762 if (pathcp) 1763 FREE(pathcp, M_TEMP); 1764 1765 if (nd->nd_flag & ND_NFSV3) { 1766 if (!nd->nd_repstat) { 1767 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1768 nfsrv_postopattr(nd, 0, &nva); 1769 } 1770 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1771 } 1772 1773 out: 1774 NFSEXITCODE2(error, nd); 1775 return (error); 1776 } 1777 1778 /* 1779 * Common code for creating a symbolic link. 1780 */ 1781 static void 1782 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 1783 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1784 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1785 int *diraft_retp, nfsattrbit_t *attrbitp, 1786 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 1787 int pathlen) 1788 { 1789 u_int32_t *tl; 1790 1791 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 1792 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 1793 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 1794 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 1795 if (nd->nd_flag & ND_NFSV3) { 1796 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 1797 if (!nd->nd_repstat) 1798 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 1799 nvap, nd->nd_cred, p, 1); 1800 } 1801 if (vpp != NULL && nd->nd_repstat == 0) { 1802 NFSVOPUNLOCK(ndp->ni_vp, 0); 1803 *vpp = ndp->ni_vp; 1804 } else 1805 vput(ndp->ni_vp); 1806 } 1807 if (dirp) { 1808 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 1809 vrele(dirp); 1810 } 1811 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1812 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1813 *tl++ = newnfs_false; 1814 txdr_hyper(dirforp->na_filerev, tl); 1815 tl += 2; 1816 txdr_hyper(diraftp->na_filerev, tl); 1817 (void) nfsrv_putattrbit(nd, attrbitp); 1818 } 1819 1820 NFSEXITCODE2(0, nd); 1821 } 1822 1823 /* 1824 * nfs mkdir service 1825 */ 1826 APPLESTATIC int 1827 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 1828 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1829 struct nfsexstuff *exp) 1830 { 1831 struct nfsvattr nva, dirfor, diraft; 1832 struct nameidata named; 1833 u_int32_t *tl; 1834 int error = 0, dirfor_ret = 1, diraft_ret = 1; 1835 vnode_t dirp = NULL; 1836 char *bufp; 1837 u_long *hashp; 1838 1839 if (nd->nd_repstat) { 1840 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1841 goto out; 1842 } 1843 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1844 LOCKPARENT | SAVENAME); 1845 nfsvno_setpathbuf(&named, &bufp, &hashp); 1846 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1847 if (error) 1848 goto nfsmout; 1849 if (!nd->nd_repstat) { 1850 NFSVNO_ATTRINIT(&nva); 1851 if (nd->nd_flag & ND_NFSV3) { 1852 error = nfsrv_sattr(nd, &nva, NULL, NULL, p); 1853 if (error) 1854 goto nfsmout; 1855 } else { 1856 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1857 nva.na_mode = nfstov_mode(*tl++); 1858 } 1859 } 1860 if (!nd->nd_repstat) { 1861 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1862 } else { 1863 vrele(dp); 1864 nfsvno_relpathbuf(&named); 1865 } 1866 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1867 vrele(dirp); 1868 dirp = NULL; 1869 } 1870 if (nd->nd_repstat) { 1871 if (dirp != NULL) { 1872 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1873 p, 0); 1874 vrele(dirp); 1875 } 1876 if (nd->nd_flag & ND_NFSV3) 1877 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1878 &diraft); 1879 goto out; 1880 } 1881 if (dirp != NULL) 1882 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 1883 1884 /* 1885 * Call nfsrvd_mkdirsub() for the code common to V4 as well. 1886 */ 1887 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 1888 &diraft_ret, NULL, NULL, p, exp); 1889 1890 if (nd->nd_flag & ND_NFSV3) { 1891 if (!nd->nd_repstat) { 1892 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1893 nfsrv_postopattr(nd, 0, &nva); 1894 } 1895 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1896 } else if (!nd->nd_repstat) { 1897 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 1898 nfsrv_fillattr(nd, &nva); 1899 } 1900 1901 out: 1902 NFSEXITCODE2(0, nd); 1903 return (0); 1904 nfsmout: 1905 vrele(dp); 1906 nfsvno_relpathbuf(&named); 1907 NFSEXITCODE2(error, nd); 1908 return (error); 1909 } 1910 1911 /* 1912 * Code common to mkdir for V2,3 and 4. 1913 */ 1914 static void 1915 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 1916 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1917 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1918 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 1919 NFSPROC_T *p, struct nfsexstuff *exp) 1920 { 1921 vnode_t vp; 1922 u_int32_t *tl; 1923 1924 NFSVNO_SETATTRVAL(nvap, type, VDIR); 1925 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 1926 nd->nd_cred, p, exp); 1927 if (!nd->nd_repstat) { 1928 vp = ndp->ni_vp; 1929 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 1930 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 1931 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 1932 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred, 1933 p, 1); 1934 if (vpp && !nd->nd_repstat) { 1935 NFSVOPUNLOCK(vp, 0); 1936 *vpp = vp; 1937 } else { 1938 vput(vp); 1939 } 1940 } 1941 if (dirp) { 1942 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 1943 vrele(dirp); 1944 } 1945 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1946 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1947 *tl++ = newnfs_false; 1948 txdr_hyper(dirforp->na_filerev, tl); 1949 tl += 2; 1950 txdr_hyper(diraftp->na_filerev, tl); 1951 (void) nfsrv_putattrbit(nd, attrbitp); 1952 } 1953 1954 NFSEXITCODE2(0, nd); 1955 } 1956 1957 /* 1958 * nfs commit service 1959 */ 1960 APPLESTATIC int 1961 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 1962 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1963 { 1964 struct nfsvattr bfor, aft; 1965 u_int32_t *tl; 1966 int error = 0, for_ret = 1, aft_ret = 1, cnt; 1967 u_int64_t off; 1968 1969 if (nd->nd_repstat) { 1970 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1971 goto out; 1972 } 1973 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1974 /* 1975 * XXX At this time VOP_FSYNC() does not accept offset and byte 1976 * count parameters, so these arguments are useless (someday maybe). 1977 */ 1978 off = fxdr_hyper(tl); 1979 tl += 2; 1980 cnt = fxdr_unsigned(int, *tl); 1981 if (nd->nd_flag & ND_NFSV3) 1982 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1); 1983 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 1984 if (nd->nd_flag & ND_NFSV3) { 1985 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1); 1986 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1987 } 1988 vput(vp); 1989 if (!nd->nd_repstat) { 1990 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1991 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 1992 *tl = txdr_unsigned(nfsboottime.tv_usec); 1993 } 1994 1995 out: 1996 NFSEXITCODE2(0, nd); 1997 return (0); 1998 nfsmout: 1999 vput(vp); 2000 NFSEXITCODE2(error, nd); 2001 return (error); 2002 } 2003 2004 /* 2005 * nfs statfs service 2006 */ 2007 APPLESTATIC int 2008 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 2009 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2010 { 2011 struct statfs *sf; 2012 u_int32_t *tl; 2013 int getret = 1; 2014 struct nfsvattr at; 2015 struct statfs sfs; 2016 u_quad_t tval; 2017 2018 if (nd->nd_repstat) { 2019 nfsrv_postopattr(nd, getret, &at); 2020 goto out; 2021 } 2022 sf = &sfs; 2023 nd->nd_repstat = nfsvno_statfs(vp, sf); 2024 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2025 vput(vp); 2026 if (nd->nd_flag & ND_NFSV3) 2027 nfsrv_postopattr(nd, getret, &at); 2028 if (nd->nd_repstat) 2029 goto out; 2030 if (nd->nd_flag & ND_NFSV2) { 2031 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 2032 *tl++ = txdr_unsigned(NFS_V2MAXDATA); 2033 *tl++ = txdr_unsigned(sf->f_bsize); 2034 *tl++ = txdr_unsigned(sf->f_blocks); 2035 *tl++ = txdr_unsigned(sf->f_bfree); 2036 *tl = txdr_unsigned(sf->f_bavail); 2037 } else { 2038 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 2039 tval = (u_quad_t)sf->f_blocks; 2040 tval *= (u_quad_t)sf->f_bsize; 2041 txdr_hyper(tval, tl); tl += 2; 2042 tval = (u_quad_t)sf->f_bfree; 2043 tval *= (u_quad_t)sf->f_bsize; 2044 txdr_hyper(tval, tl); tl += 2; 2045 tval = (u_quad_t)sf->f_bavail; 2046 tval *= (u_quad_t)sf->f_bsize; 2047 txdr_hyper(tval, tl); tl += 2; 2048 tval = (u_quad_t)sf->f_files; 2049 txdr_hyper(tval, tl); tl += 2; 2050 tval = (u_quad_t)sf->f_ffree; 2051 txdr_hyper(tval, tl); tl += 2; 2052 tval = (u_quad_t)sf->f_ffree; 2053 txdr_hyper(tval, tl); tl += 2; 2054 *tl = 0; 2055 } 2056 2057 out: 2058 NFSEXITCODE2(0, nd); 2059 return (0); 2060 } 2061 2062 /* 2063 * nfs fsinfo service 2064 */ 2065 APPLESTATIC int 2066 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 2067 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2068 { 2069 u_int32_t *tl; 2070 struct nfsfsinfo fs; 2071 int getret = 1; 2072 struct nfsvattr at; 2073 2074 if (nd->nd_repstat) { 2075 nfsrv_postopattr(nd, getret, &at); 2076 goto out; 2077 } 2078 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2079 nfsvno_getfs(&fs, isdgram); 2080 vput(vp); 2081 nfsrv_postopattr(nd, getret, &at); 2082 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 2083 *tl++ = txdr_unsigned(fs.fs_rtmax); 2084 *tl++ = txdr_unsigned(fs.fs_rtpref); 2085 *tl++ = txdr_unsigned(fs.fs_rtmult); 2086 *tl++ = txdr_unsigned(fs.fs_wtmax); 2087 *tl++ = txdr_unsigned(fs.fs_wtpref); 2088 *tl++ = txdr_unsigned(fs.fs_wtmult); 2089 *tl++ = txdr_unsigned(fs.fs_dtpref); 2090 txdr_hyper(fs.fs_maxfilesize, tl); 2091 tl += 2; 2092 txdr_nfsv3time(&fs.fs_timedelta, tl); 2093 tl += 2; 2094 *tl = txdr_unsigned(fs.fs_properties); 2095 2096 out: 2097 NFSEXITCODE2(0, nd); 2098 return (0); 2099 } 2100 2101 /* 2102 * nfs pathconf service 2103 */ 2104 APPLESTATIC int 2105 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 2106 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2107 { 2108 struct nfsv3_pathconf *pc; 2109 int getret = 1; 2110 register_t linkmax, namemax, chownres, notrunc; 2111 struct nfsvattr at; 2112 2113 if (nd->nd_repstat) { 2114 nfsrv_postopattr(nd, getret, &at); 2115 goto out; 2116 } 2117 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 2118 nd->nd_cred, p); 2119 if (!nd->nd_repstat) 2120 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 2121 nd->nd_cred, p); 2122 if (!nd->nd_repstat) 2123 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 2124 &chownres, nd->nd_cred, p); 2125 if (!nd->nd_repstat) 2126 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 2127 nd->nd_cred, p); 2128 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2129 vput(vp); 2130 nfsrv_postopattr(nd, getret, &at); 2131 if (!nd->nd_repstat) { 2132 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 2133 pc->pc_linkmax = txdr_unsigned(linkmax); 2134 pc->pc_namemax = txdr_unsigned(namemax); 2135 pc->pc_notrunc = txdr_unsigned(notrunc); 2136 pc->pc_chownrestricted = txdr_unsigned(chownres); 2137 2138 /* 2139 * These should probably be supported by VOP_PATHCONF(), but 2140 * until msdosfs is exportable (why would you want to?), the 2141 * Unix defaults should be ok. 2142 */ 2143 pc->pc_caseinsensitive = newnfs_false; 2144 pc->pc_casepreserving = newnfs_true; 2145 } 2146 2147 out: 2148 NFSEXITCODE2(0, nd); 2149 return (0); 2150 } 2151 2152 /* 2153 * nfsv4 lock service 2154 */ 2155 APPLESTATIC int 2156 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2157 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2158 { 2159 u_int32_t *tl; 2160 int i; 2161 struct nfsstate *stp = NULL; 2162 struct nfslock *lop; 2163 struct nfslockconflict cf; 2164 int error = 0; 2165 u_short flags = NFSLCK_LOCK, lflags; 2166 u_int64_t offset, len; 2167 nfsv4stateid_t stateid; 2168 nfsquad_t clientid; 2169 2170 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2171 i = fxdr_unsigned(int, *tl++); 2172 switch (i) { 2173 case NFSV4LOCKT_READW: 2174 flags |= NFSLCK_BLOCKING; 2175 case NFSV4LOCKT_READ: 2176 lflags = NFSLCK_READ; 2177 break; 2178 case NFSV4LOCKT_WRITEW: 2179 flags |= NFSLCK_BLOCKING; 2180 case NFSV4LOCKT_WRITE: 2181 lflags = NFSLCK_WRITE; 2182 break; 2183 default: 2184 nd->nd_repstat = NFSERR_BADXDR; 2185 goto nfsmout; 2186 }; 2187 if (*tl++ == newnfs_true) 2188 flags |= NFSLCK_RECLAIM; 2189 offset = fxdr_hyper(tl); 2190 tl += 2; 2191 len = fxdr_hyper(tl); 2192 tl += 2; 2193 if (*tl == newnfs_true) 2194 flags |= NFSLCK_OPENTOLOCK; 2195 if (flags & NFSLCK_OPENTOLOCK) { 2196 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 2197 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 2198 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2199 nd->nd_repstat = NFSERR_BADXDR; 2200 goto nfsmout; 2201 } 2202 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2203 M_NFSDSTATE, M_WAITOK); 2204 stp->ls_ownerlen = i; 2205 stp->ls_op = nd->nd_rp; 2206 stp->ls_seq = fxdr_unsigned(int, *tl++); 2207 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2208 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2209 NFSX_STATEIDOTHER); 2210 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2211 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 2212 clientid.lval[0] = *tl++; 2213 clientid.lval[1] = *tl++; 2214 if (nd->nd_flag & ND_IMPLIEDCLID) { 2215 if (nd->nd_clientid.qval != clientid.qval) 2216 printf("EEK! multiple clids\n"); 2217 } else { 2218 nd->nd_flag |= ND_IMPLIEDCLID; 2219 nd->nd_clientid.qval = clientid.qval; 2220 } 2221 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2222 if (error) 2223 goto nfsmout; 2224 } else { 2225 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2226 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2227 M_NFSDSTATE, M_WAITOK); 2228 stp->ls_ownerlen = 0; 2229 stp->ls_op = nd->nd_rp; 2230 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2231 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2232 NFSX_STATEIDOTHER); 2233 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2234 stp->ls_seq = fxdr_unsigned(int, *tl); 2235 clientid.lval[0] = stp->ls_stateid.other[0]; 2236 clientid.lval[1] = stp->ls_stateid.other[1]; 2237 if (nd->nd_flag & ND_IMPLIEDCLID) { 2238 if (nd->nd_clientid.qval != clientid.qval) 2239 printf("EEK! multiple clids\n"); 2240 } else { 2241 nd->nd_flag |= ND_IMPLIEDCLID; 2242 nd->nd_clientid.qval = clientid.qval; 2243 } 2244 } 2245 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2246 M_NFSDLOCK, M_WAITOK); 2247 lop->lo_first = offset; 2248 if (len == NFS64BITSSET) { 2249 lop->lo_end = NFS64BITSSET; 2250 } else { 2251 lop->lo_end = offset + len; 2252 if (lop->lo_end <= lop->lo_first) 2253 nd->nd_repstat = NFSERR_INVAL; 2254 } 2255 lop->lo_flags = lflags; 2256 stp->ls_flags = flags; 2257 stp->ls_uid = nd->nd_cred->cr_uid; 2258 2259 /* 2260 * Do basic access checking. 2261 */ 2262 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2263 if (vnode_vtype(vp) == VDIR) 2264 nd->nd_repstat = NFSERR_ISDIR; 2265 else 2266 nd->nd_repstat = NFSERR_INVAL; 2267 } 2268 if (!nd->nd_repstat) { 2269 if (lflags & NFSLCK_WRITE) { 2270 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 2271 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2272 NFSACCCHK_VPISLOCKED, NULL); 2273 } else { 2274 nd->nd_repstat = nfsvno_accchk(vp, VREAD, 2275 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2276 NFSACCCHK_VPISLOCKED, NULL); 2277 if (nd->nd_repstat) 2278 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2279 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2280 NFSACCCHK_VPISLOCKED, NULL); 2281 } 2282 } 2283 2284 /* 2285 * We call nfsrv_lockctrl() even if nd_repstat set, so that the 2286 * seqid# gets updated. nfsrv_lockctrl() will return the value 2287 * of nd_repstat, if it gets that far. 2288 */ 2289 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2290 &stateid, exp, nd, p); 2291 if (lop) 2292 FREE((caddr_t)lop, M_NFSDLOCK); 2293 if (stp) 2294 FREE((caddr_t)stp, M_NFSDSTATE); 2295 if (!nd->nd_repstat) { 2296 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2297 *tl++ = txdr_unsigned(stateid.seqid); 2298 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2299 } else if (nd->nd_repstat == NFSERR_DENIED) { 2300 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2301 txdr_hyper(cf.cl_first, tl); 2302 tl += 2; 2303 if (cf.cl_end == NFS64BITSSET) 2304 len = NFS64BITSSET; 2305 else 2306 len = cf.cl_end - cf.cl_first; 2307 txdr_hyper(len, tl); 2308 tl += 2; 2309 if (cf.cl_flags == NFSLCK_WRITE) 2310 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2311 else 2312 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2313 *tl++ = stateid.other[0]; 2314 *tl = stateid.other[1]; 2315 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2316 } 2317 vput(vp); 2318 NFSEXITCODE2(0, nd); 2319 return (0); 2320 nfsmout: 2321 vput(vp); 2322 if (stp) 2323 free((caddr_t)stp, M_NFSDSTATE); 2324 NFSEXITCODE2(error, nd); 2325 return (error); 2326 } 2327 2328 /* 2329 * nfsv4 lock test service 2330 */ 2331 APPLESTATIC int 2332 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2333 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2334 { 2335 u_int32_t *tl; 2336 int i; 2337 struct nfsstate *stp = NULL; 2338 struct nfslock lo, *lop = &lo; 2339 struct nfslockconflict cf; 2340 int error = 0; 2341 nfsv4stateid_t stateid; 2342 nfsquad_t clientid; 2343 u_int64_t len; 2344 2345 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 2346 i = fxdr_unsigned(int, *(tl + 7)); 2347 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2348 nd->nd_repstat = NFSERR_BADXDR; 2349 goto nfsmout; 2350 } 2351 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2352 M_NFSDSTATE, M_WAITOK); 2353 stp->ls_ownerlen = i; 2354 stp->ls_op = NULL; 2355 stp->ls_flags = NFSLCK_TEST; 2356 stp->ls_uid = nd->nd_cred->cr_uid; 2357 i = fxdr_unsigned(int, *tl++); 2358 switch (i) { 2359 case NFSV4LOCKT_READW: 2360 stp->ls_flags |= NFSLCK_BLOCKING; 2361 case NFSV4LOCKT_READ: 2362 lo.lo_flags = NFSLCK_READ; 2363 break; 2364 case NFSV4LOCKT_WRITEW: 2365 stp->ls_flags |= NFSLCK_BLOCKING; 2366 case NFSV4LOCKT_WRITE: 2367 lo.lo_flags = NFSLCK_WRITE; 2368 break; 2369 default: 2370 nd->nd_repstat = NFSERR_BADXDR; 2371 goto nfsmout; 2372 }; 2373 lo.lo_first = fxdr_hyper(tl); 2374 tl += 2; 2375 len = fxdr_hyper(tl); 2376 if (len == NFS64BITSSET) { 2377 lo.lo_end = NFS64BITSSET; 2378 } else { 2379 lo.lo_end = lo.lo_first + len; 2380 if (lo.lo_end <= lo.lo_first) 2381 nd->nd_repstat = NFSERR_INVAL; 2382 } 2383 tl += 2; 2384 clientid.lval[0] = *tl++; 2385 clientid.lval[1] = *tl; 2386 if (nd->nd_flag & ND_IMPLIEDCLID) { 2387 if (nd->nd_clientid.qval != clientid.qval) 2388 printf("EEK! multiple clids\n"); 2389 } else { 2390 nd->nd_flag |= ND_IMPLIEDCLID; 2391 nd->nd_clientid.qval = clientid.qval; 2392 } 2393 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2394 if (error) 2395 goto nfsmout; 2396 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2397 if (vnode_vtype(vp) == VDIR) 2398 nd->nd_repstat = NFSERR_ISDIR; 2399 else 2400 nd->nd_repstat = NFSERR_INVAL; 2401 } 2402 if (!nd->nd_repstat) 2403 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2404 &stateid, exp, nd, p); 2405 if (stp) 2406 FREE((caddr_t)stp, M_NFSDSTATE); 2407 if (nd->nd_repstat) { 2408 if (nd->nd_repstat == NFSERR_DENIED) { 2409 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2410 txdr_hyper(cf.cl_first, tl); 2411 tl += 2; 2412 if (cf.cl_end == NFS64BITSSET) 2413 len = NFS64BITSSET; 2414 else 2415 len = cf.cl_end - cf.cl_first; 2416 txdr_hyper(len, tl); 2417 tl += 2; 2418 if (cf.cl_flags == NFSLCK_WRITE) 2419 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2420 else 2421 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2422 *tl++ = stp->ls_stateid.other[0]; 2423 *tl = stp->ls_stateid.other[1]; 2424 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2425 } 2426 } 2427 vput(vp); 2428 NFSEXITCODE2(0, nd); 2429 return (0); 2430 nfsmout: 2431 vput(vp); 2432 if (stp) 2433 free((caddr_t)stp, M_NFSDSTATE); 2434 NFSEXITCODE2(error, nd); 2435 return (error); 2436 } 2437 2438 /* 2439 * nfsv4 unlock service 2440 */ 2441 APPLESTATIC int 2442 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2443 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2444 { 2445 u_int32_t *tl; 2446 int i; 2447 struct nfsstate *stp; 2448 struct nfslock *lop; 2449 int error = 0; 2450 nfsv4stateid_t stateid; 2451 nfsquad_t clientid; 2452 u_int64_t len; 2453 2454 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2455 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2456 M_NFSDSTATE, M_WAITOK); 2457 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2458 M_NFSDLOCK, M_WAITOK); 2459 stp->ls_flags = NFSLCK_UNLOCK; 2460 lop->lo_flags = NFSLCK_UNLOCK; 2461 stp->ls_op = nd->nd_rp; 2462 i = fxdr_unsigned(int, *tl++); 2463 switch (i) { 2464 case NFSV4LOCKT_READW: 2465 stp->ls_flags |= NFSLCK_BLOCKING; 2466 case NFSV4LOCKT_READ: 2467 break; 2468 case NFSV4LOCKT_WRITEW: 2469 stp->ls_flags |= NFSLCK_BLOCKING; 2470 case NFSV4LOCKT_WRITE: 2471 break; 2472 default: 2473 nd->nd_repstat = NFSERR_BADXDR; 2474 free(stp, M_NFSDSTATE); 2475 free(lop, M_NFSDLOCK); 2476 goto nfsmout; 2477 }; 2478 stp->ls_ownerlen = 0; 2479 stp->ls_uid = nd->nd_cred->cr_uid; 2480 stp->ls_seq = fxdr_unsigned(int, *tl++); 2481 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2482 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2483 NFSX_STATEIDOTHER); 2484 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2485 lop->lo_first = fxdr_hyper(tl); 2486 tl += 2; 2487 len = fxdr_hyper(tl); 2488 if (len == NFS64BITSSET) { 2489 lop->lo_end = NFS64BITSSET; 2490 } else { 2491 lop->lo_end = lop->lo_first + len; 2492 if (lop->lo_end <= lop->lo_first) 2493 nd->nd_repstat = NFSERR_INVAL; 2494 } 2495 clientid.lval[0] = stp->ls_stateid.other[0]; 2496 clientid.lval[1] = stp->ls_stateid.other[1]; 2497 if (nd->nd_flag & ND_IMPLIEDCLID) { 2498 if (nd->nd_clientid.qval != clientid.qval) 2499 printf("EEK! multiple clids\n"); 2500 } else { 2501 nd->nd_flag |= ND_IMPLIEDCLID; 2502 nd->nd_clientid.qval = clientid.qval; 2503 } 2504 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2505 if (vnode_vtype(vp) == VDIR) 2506 nd->nd_repstat = NFSERR_ISDIR; 2507 else 2508 nd->nd_repstat = NFSERR_INVAL; 2509 } 2510 /* 2511 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 2512 * seqid# gets incremented. nfsrv_lockctrl() will return the 2513 * value of nd_repstat, if it gets that far. 2514 */ 2515 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 2516 &stateid, exp, nd, p); 2517 if (stp) 2518 FREE((caddr_t)stp, M_NFSDSTATE); 2519 if (lop) 2520 free((caddr_t)lop, M_NFSDLOCK); 2521 if (!nd->nd_repstat) { 2522 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2523 *tl++ = txdr_unsigned(stateid.seqid); 2524 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2525 } 2526 nfsmout: 2527 vput(vp); 2528 NFSEXITCODE2(error, nd); 2529 return (error); 2530 } 2531 2532 /* 2533 * nfsv4 open service 2534 */ 2535 APPLESTATIC int 2536 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2537 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p, 2538 struct nfsexstuff *exp) 2539 { 2540 u_int32_t *tl; 2541 int i; 2542 struct nfsstate *stp = NULL; 2543 int error = 0, create, claim, exclusive_flag = 0; 2544 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 2545 int how = NFSCREATE_UNCHECKED; 2546 int32_t cverf[2], tverf[2] = { 0, 0 }; 2547 vnode_t vp = NULL, dirp = NULL; 2548 struct nfsvattr nva, dirfor, diraft; 2549 struct nameidata named; 2550 nfsv4stateid_t stateid, delegstateid; 2551 nfsattrbit_t attrbits; 2552 nfsquad_t clientid; 2553 char *bufp = NULL; 2554 u_long *hashp; 2555 NFSACL_T *aclp = NULL; 2556 2557 #ifdef NFS4_ACL_EXTATTR_NAME 2558 aclp = acl_alloc(M_WAITOK); 2559 aclp->acl_cnt = 0; 2560 #endif 2561 NFSZERO_ATTRBIT(&attrbits); 2562 named.ni_startdir = NULL; 2563 named.ni_cnd.cn_nameiop = 0; 2564 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2565 i = fxdr_unsigned(int, *(tl + 5)); 2566 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2567 nd->nd_repstat = NFSERR_BADXDR; 2568 goto nfsmout; 2569 } 2570 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2571 M_NFSDSTATE, M_WAITOK); 2572 stp->ls_ownerlen = i; 2573 stp->ls_op = nd->nd_rp; 2574 stp->ls_flags = NFSLCK_OPEN; 2575 stp->ls_uid = nd->nd_cred->cr_uid; 2576 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2577 i = fxdr_unsigned(int, *tl++); 2578 switch (i) { 2579 case NFSV4OPEN_ACCESSREAD: 2580 stp->ls_flags |= NFSLCK_READACCESS; 2581 break; 2582 case NFSV4OPEN_ACCESSWRITE: 2583 stp->ls_flags |= NFSLCK_WRITEACCESS; 2584 break; 2585 case NFSV4OPEN_ACCESSBOTH: 2586 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2587 break; 2588 default: 2589 nd->nd_repstat = NFSERR_INVAL; 2590 }; 2591 i = fxdr_unsigned(int, *tl++); 2592 switch (i) { 2593 case NFSV4OPEN_DENYNONE: 2594 break; 2595 case NFSV4OPEN_DENYREAD: 2596 stp->ls_flags |= NFSLCK_READDENY; 2597 break; 2598 case NFSV4OPEN_DENYWRITE: 2599 stp->ls_flags |= NFSLCK_WRITEDENY; 2600 break; 2601 case NFSV4OPEN_DENYBOTH: 2602 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 2603 break; 2604 default: 2605 nd->nd_repstat = NFSERR_INVAL; 2606 }; 2607 clientid.lval[0] = *tl++; 2608 clientid.lval[1] = *tl; 2609 if (nd->nd_flag & ND_IMPLIEDCLID) { 2610 if (nd->nd_clientid.qval != clientid.qval) 2611 printf("EEK! multiple clids\n"); 2612 } else { 2613 nd->nd_flag |= ND_IMPLIEDCLID; 2614 nd->nd_clientid.qval = clientid.qval; 2615 } 2616 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2617 if (error) 2618 goto nfsmout; 2619 NFSVNO_ATTRINIT(&nva); 2620 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2621 create = fxdr_unsigned(int, *tl); 2622 if (!nd->nd_repstat) 2623 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 2624 if (create == NFSV4OPEN_CREATE) { 2625 nva.na_type = VREG; 2626 nva.na_mode = 0; 2627 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2628 how = fxdr_unsigned(int, *tl); 2629 switch (how) { 2630 case NFSCREATE_UNCHECKED: 2631 case NFSCREATE_GUARDED: 2632 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p); 2633 if (error) 2634 goto nfsmout; 2635 /* 2636 * If the na_gid being set is the same as that of 2637 * the directory it is going in, clear it, since 2638 * that is what will be set by default. This allows 2639 * a user that isn't in that group to do the create. 2640 */ 2641 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 2642 nva.na_gid == dirfor.na_gid) 2643 NFSVNO_UNSET(&nva, gid); 2644 if (!nd->nd_repstat) 2645 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2646 break; 2647 case NFSCREATE_EXCLUSIVE: 2648 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2649 cverf[0] = *tl++; 2650 cverf[1] = *tl; 2651 break; 2652 default: 2653 nd->nd_repstat = NFSERR_BADXDR; 2654 goto nfsmout; 2655 }; 2656 } else if (create != NFSV4OPEN_NOCREATE) { 2657 nd->nd_repstat = NFSERR_BADXDR; 2658 goto nfsmout; 2659 } 2660 2661 /* 2662 * Now, handle the claim, which usually includes looking up a 2663 * name in the directory referenced by dp. The exception is 2664 * NFSV4OPEN_CLAIMPREVIOUS. 2665 */ 2666 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2667 claim = fxdr_unsigned(int, *tl); 2668 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 2669 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2670 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2671 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 2672 stp->ls_flags |= NFSLCK_DELEGCUR; 2673 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2674 stp->ls_flags |= NFSLCK_DELEGPREV; 2675 } 2676 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 2677 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2678 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 2679 claim != NFSV4OPEN_CLAIMNULL) 2680 nd->nd_repstat = NFSERR_INVAL; 2681 if (nd->nd_repstat) { 2682 nd->nd_repstat = nfsrv_opencheck(clientid, 2683 &stateid, stp, NULL, nd, p, nd->nd_repstat); 2684 goto nfsmout; 2685 } 2686 if (create == NFSV4OPEN_CREATE) 2687 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 2688 LOCKPARENT | LOCKLEAF | SAVESTART); 2689 else 2690 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 2691 LOCKLEAF | SAVESTART); 2692 nfsvno_setpathbuf(&named, &bufp, &hashp); 2693 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2694 if (error) { 2695 vrele(dp); 2696 #ifdef NFS4_ACL_EXTATTR_NAME 2697 acl_free(aclp); 2698 #endif 2699 FREE((caddr_t)stp, M_NFSDSTATE); 2700 nfsvno_relpathbuf(&named); 2701 NFSEXITCODE2(error, nd); 2702 return (error); 2703 } 2704 if (!nd->nd_repstat) { 2705 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 2706 p, &dirp); 2707 } else { 2708 vrele(dp); 2709 nfsvno_relpathbuf(&named); 2710 } 2711 if (create == NFSV4OPEN_CREATE) { 2712 switch (how) { 2713 case NFSCREATE_UNCHECKED: 2714 if (named.ni_vp) { 2715 /* 2716 * Clear the setable attribute bits, except 2717 * for Size, if it is being truncated. 2718 */ 2719 NFSZERO_ATTRBIT(&attrbits); 2720 if (NFSVNO_ISSETSIZE(&nva)) 2721 NFSSETBIT_ATTRBIT(&attrbits, 2722 NFSATTRBIT_SIZE); 2723 } 2724 break; 2725 case NFSCREATE_GUARDED: 2726 if (named.ni_vp && !nd->nd_repstat) 2727 nd->nd_repstat = EEXIST; 2728 break; 2729 case NFSCREATE_EXCLUSIVE: 2730 exclusive_flag = 1; 2731 if (!named.ni_vp) 2732 nva.na_mode = 0; 2733 }; 2734 } 2735 nfsvno_open(nd, &named, clientid, &stateid, stp, 2736 &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 2737 nd->nd_cred, p, exp, &vp); 2738 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2739 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2740 i = fxdr_unsigned(int, *tl); 2741 switch (i) { 2742 case NFSV4OPEN_DELEGATEREAD: 2743 stp->ls_flags |= NFSLCK_DELEGREAD; 2744 break; 2745 case NFSV4OPEN_DELEGATEWRITE: 2746 stp->ls_flags |= NFSLCK_DELEGWRITE; 2747 case NFSV4OPEN_DELEGATENONE: 2748 break; 2749 default: 2750 nd->nd_repstat = NFSERR_BADXDR; 2751 goto nfsmout; 2752 }; 2753 stp->ls_flags |= NFSLCK_RECLAIM; 2754 vp = dp; 2755 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 2756 if ((vp->v_iflag & VI_DOOMED) == 0) 2757 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 2758 stp, vp, nd, p, nd->nd_repstat); 2759 else 2760 nd->nd_repstat = NFSERR_PERM; 2761 } else { 2762 nd->nd_repstat = NFSERR_BADXDR; 2763 goto nfsmout; 2764 } 2765 2766 /* 2767 * Do basic access checking. 2768 */ 2769 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2770 /* 2771 * The IETF working group decided that this is the correct 2772 * error return for all non-regular files. 2773 */ 2774 nd->nd_repstat = NFSERR_SYMLINK; 2775 } 2776 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 2777 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 2778 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2779 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 2780 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 2781 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2782 if (nd->nd_repstat) 2783 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2784 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2785 NFSACCCHK_VPISLOCKED, NULL); 2786 } 2787 2788 if (!nd->nd_repstat) { 2789 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 2790 if (!nd->nd_repstat) { 2791 tverf[0] = nva.na_atime.tv_sec; 2792 tverf[1] = nva.na_atime.tv_nsec; 2793 } 2794 } 2795 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 2796 cverf[1] != tverf[1])) 2797 nd->nd_repstat = EEXIST; 2798 /* 2799 * Do the open locking/delegation stuff. 2800 */ 2801 if (!nd->nd_repstat) 2802 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 2803 &delegstateid, &rflags, exp, p, nva.na_filerev); 2804 2805 /* 2806 * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 2807 * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 2808 * (ie: Leave the NFSVOPUNLOCK() about here.) 2809 */ 2810 if (vp) 2811 NFSVOPUNLOCK(vp, 0); 2812 if (stp) 2813 FREE((caddr_t)stp, M_NFSDSTATE); 2814 if (!nd->nd_repstat && dirp) 2815 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 2816 0); 2817 if (!nd->nd_repstat) { 2818 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 2819 *tl++ = txdr_unsigned(stateid.seqid); 2820 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2821 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2822 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2823 *tl++ = newnfs_true; 2824 *tl++ = 0; 2825 *tl++ = 0; 2826 *tl++ = 0; 2827 *tl++ = 0; 2828 } else { 2829 *tl++ = newnfs_false; /* Since dirp is not locked */ 2830 txdr_hyper(dirfor.na_filerev, tl); 2831 tl += 2; 2832 txdr_hyper(diraft.na_filerev, tl); 2833 tl += 2; 2834 } 2835 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 2836 (void) nfsrv_putattrbit(nd, &attrbits); 2837 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2838 if (rflags & NFSV4OPEN_READDELEGATE) 2839 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 2840 else if (rflags & NFSV4OPEN_WRITEDELEGATE) 2841 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 2842 else 2843 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 2844 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 2845 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 2846 *tl++ = txdr_unsigned(delegstateid.seqid); 2847 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 2848 NFSX_STATEIDOTHER); 2849 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2850 if (rflags & NFSV4OPEN_RECALL) 2851 *tl = newnfs_true; 2852 else 2853 *tl = newnfs_false; 2854 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 2855 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2856 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 2857 txdr_hyper(nva.na_size, tl); 2858 } 2859 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2860 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 2861 *tl++ = txdr_unsigned(0x0); 2862 acemask = NFSV4ACE_ALLFILESMASK; 2863 if (nva.na_mode & S_IRUSR) 2864 acemask |= NFSV4ACE_READMASK; 2865 if (nva.na_mode & S_IWUSR) 2866 acemask |= NFSV4ACE_WRITEMASK; 2867 if (nva.na_mode & S_IXUSR) 2868 acemask |= NFSV4ACE_EXECUTEMASK; 2869 *tl = txdr_unsigned(acemask); 2870 (void) nfsm_strtom(nd, "OWNER@", 6); 2871 } 2872 *vpp = vp; 2873 } else if (vp) { 2874 vrele(vp); 2875 } 2876 if (dirp) 2877 vrele(dirp); 2878 #ifdef NFS4_ACL_EXTATTR_NAME 2879 acl_free(aclp); 2880 #endif 2881 NFSEXITCODE2(0, nd); 2882 return (0); 2883 nfsmout: 2884 vrele(dp); 2885 #ifdef NFS4_ACL_EXTATTR_NAME 2886 acl_free(aclp); 2887 #endif 2888 if (stp) 2889 FREE((caddr_t)stp, M_NFSDSTATE); 2890 NFSEXITCODE2(error, nd); 2891 return (error); 2892 } 2893 2894 /* 2895 * nfsv4 close service 2896 */ 2897 APPLESTATIC int 2898 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 2899 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2900 { 2901 u_int32_t *tl; 2902 struct nfsstate st, *stp = &st; 2903 int error = 0; 2904 nfsv4stateid_t stateid; 2905 nfsquad_t clientid; 2906 2907 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 2908 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2909 stp->ls_ownerlen = 0; 2910 stp->ls_op = nd->nd_rp; 2911 stp->ls_uid = nd->nd_cred->cr_uid; 2912 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2913 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2914 NFSX_STATEIDOTHER); 2915 stp->ls_flags = NFSLCK_CLOSE; 2916 clientid.lval[0] = stp->ls_stateid.other[0]; 2917 clientid.lval[1] = stp->ls_stateid.other[1]; 2918 if (nd->nd_flag & ND_IMPLIEDCLID) { 2919 if (nd->nd_clientid.qval != clientid.qval) 2920 printf("EEK! multiple clids\n"); 2921 } else { 2922 nd->nd_flag |= ND_IMPLIEDCLID; 2923 nd->nd_clientid.qval = clientid.qval; 2924 } 2925 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 2926 vput(vp); 2927 if (!nd->nd_repstat) { 2928 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2929 *tl++ = txdr_unsigned(stateid.seqid); 2930 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2931 } 2932 NFSEXITCODE2(0, nd); 2933 return (0); 2934 nfsmout: 2935 vput(vp); 2936 NFSEXITCODE2(error, nd); 2937 return (error); 2938 } 2939 2940 /* 2941 * nfsv4 delegpurge service 2942 */ 2943 APPLESTATIC int 2944 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 2945 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 2946 { 2947 u_int32_t *tl; 2948 int error = 0; 2949 nfsquad_t clientid; 2950 2951 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 2952 nd->nd_repstat = NFSERR_WRONGSEC; 2953 goto nfsmout; 2954 } 2955 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2956 clientid.lval[0] = *tl++; 2957 clientid.lval[1] = *tl; 2958 if (nd->nd_flag & ND_IMPLIEDCLID) { 2959 if (nd->nd_clientid.qval != clientid.qval) 2960 printf("EEK! multiple clids\n"); 2961 } else { 2962 nd->nd_flag |= ND_IMPLIEDCLID; 2963 nd->nd_clientid.qval = clientid.qval; 2964 } 2965 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL, 2966 NFSV4OP_DELEGPURGE, nd->nd_cred, p); 2967 nfsmout: 2968 NFSEXITCODE2(error, nd); 2969 return (error); 2970 } 2971 2972 /* 2973 * nfsv4 delegreturn service 2974 */ 2975 APPLESTATIC int 2976 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 2977 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2978 { 2979 u_int32_t *tl; 2980 int error = 0; 2981 nfsv4stateid_t stateid; 2982 nfsquad_t clientid; 2983 2984 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2985 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2986 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 2987 clientid.lval[0] = stateid.other[0]; 2988 clientid.lval[1] = stateid.other[1]; 2989 if (nd->nd_flag & ND_IMPLIEDCLID) { 2990 if (nd->nd_clientid.qval != clientid.qval) 2991 printf("EEK! multiple clids\n"); 2992 } else { 2993 nd->nd_flag |= ND_IMPLIEDCLID; 2994 nd->nd_clientid.qval = clientid.qval; 2995 } 2996 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp, 2997 NFSV4OP_DELEGRETURN, nd->nd_cred, p); 2998 nfsmout: 2999 vput(vp); 3000 NFSEXITCODE2(error, nd); 3001 return (error); 3002 } 3003 3004 /* 3005 * nfsv4 get file handle service 3006 */ 3007 APPLESTATIC int 3008 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3009 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3010 { 3011 fhandle_t fh; 3012 3013 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3014 vput(vp); 3015 if (!nd->nd_repstat) 3016 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3017 NFSEXITCODE2(0, nd); 3018 return (0); 3019 } 3020 3021 /* 3022 * nfsv4 open confirm service 3023 */ 3024 APPLESTATIC int 3025 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3026 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3027 { 3028 u_int32_t *tl; 3029 struct nfsstate st, *stp = &st; 3030 int error = 0; 3031 nfsv4stateid_t stateid; 3032 nfsquad_t clientid; 3033 3034 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3035 stp->ls_ownerlen = 0; 3036 stp->ls_op = nd->nd_rp; 3037 stp->ls_uid = nd->nd_cred->cr_uid; 3038 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3039 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3040 NFSX_STATEIDOTHER); 3041 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3042 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 3043 stp->ls_flags = NFSLCK_CONFIRM; 3044 clientid.lval[0] = stp->ls_stateid.other[0]; 3045 clientid.lval[1] = stp->ls_stateid.other[1]; 3046 if (nd->nd_flag & ND_IMPLIEDCLID) { 3047 if (nd->nd_clientid.qval != clientid.qval) 3048 printf("EEK! multiple clids\n"); 3049 } else { 3050 nd->nd_flag |= ND_IMPLIEDCLID; 3051 nd->nd_clientid.qval = clientid.qval; 3052 } 3053 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 3054 if (!nd->nd_repstat) { 3055 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3056 *tl++ = txdr_unsigned(stateid.seqid); 3057 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3058 } 3059 nfsmout: 3060 vput(vp); 3061 NFSEXITCODE2(error, nd); 3062 return (error); 3063 } 3064 3065 /* 3066 * nfsv4 open downgrade service 3067 */ 3068 APPLESTATIC int 3069 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3070 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3071 { 3072 u_int32_t *tl; 3073 int i; 3074 struct nfsstate st, *stp = &st; 3075 int error = 0; 3076 nfsv4stateid_t stateid; 3077 nfsquad_t clientid; 3078 3079 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 3080 stp->ls_ownerlen = 0; 3081 stp->ls_op = nd->nd_rp; 3082 stp->ls_uid = nd->nd_cred->cr_uid; 3083 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3084 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3085 NFSX_STATEIDOTHER); 3086 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3087 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3088 i = fxdr_unsigned(int, *tl++); 3089 switch (i) { 3090 case NFSV4OPEN_ACCESSREAD: 3091 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3092 break; 3093 case NFSV4OPEN_ACCESSWRITE: 3094 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3095 break; 3096 case NFSV4OPEN_ACCESSBOTH: 3097 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3098 NFSLCK_DOWNGRADE); 3099 break; 3100 default: 3101 nd->nd_repstat = NFSERR_BADXDR; 3102 }; 3103 i = fxdr_unsigned(int, *tl); 3104 switch (i) { 3105 case NFSV4OPEN_DENYNONE: 3106 break; 3107 case NFSV4OPEN_DENYREAD: 3108 stp->ls_flags |= NFSLCK_READDENY; 3109 break; 3110 case NFSV4OPEN_DENYWRITE: 3111 stp->ls_flags |= NFSLCK_WRITEDENY; 3112 break; 3113 case NFSV4OPEN_DENYBOTH: 3114 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3115 break; 3116 default: 3117 nd->nd_repstat = NFSERR_BADXDR; 3118 }; 3119 3120 clientid.lval[0] = stp->ls_stateid.other[0]; 3121 clientid.lval[1] = stp->ls_stateid.other[1]; 3122 if (nd->nd_flag & ND_IMPLIEDCLID) { 3123 if (nd->nd_clientid.qval != clientid.qval) 3124 printf("EEK! multiple clids\n"); 3125 } else { 3126 nd->nd_flag |= ND_IMPLIEDCLID; 3127 nd->nd_clientid.qval = clientid.qval; 3128 } 3129 if (!nd->nd_repstat) 3130 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3131 nd, p); 3132 if (!nd->nd_repstat) { 3133 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3134 *tl++ = txdr_unsigned(stateid.seqid); 3135 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3136 } 3137 nfsmout: 3138 vput(vp); 3139 NFSEXITCODE2(error, nd); 3140 return (error); 3141 } 3142 3143 /* 3144 * nfsv4 renew lease service 3145 */ 3146 APPLESTATIC int 3147 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3148 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3149 { 3150 u_int32_t *tl; 3151 int error = 0; 3152 nfsquad_t clientid; 3153 3154 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3155 nd->nd_repstat = NFSERR_WRONGSEC; 3156 goto nfsmout; 3157 } 3158 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3159 clientid.lval[0] = *tl++; 3160 clientid.lval[1] = *tl; 3161 if (nd->nd_flag & ND_IMPLIEDCLID) { 3162 if (nd->nd_clientid.qval != clientid.qval) 3163 printf("EEK! multiple clids\n"); 3164 } else { 3165 nd->nd_flag |= ND_IMPLIEDCLID; 3166 nd->nd_clientid.qval = clientid.qval; 3167 } 3168 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3169 NULL, (nfsquad_t)((u_quad_t)0), nd, p); 3170 nfsmout: 3171 NFSEXITCODE2(error, nd); 3172 return (error); 3173 } 3174 3175 /* 3176 * nfsv4 security info service 3177 */ 3178 APPLESTATIC int 3179 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3180 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 3181 { 3182 u_int32_t *tl; 3183 int len; 3184 struct nameidata named; 3185 vnode_t dirp = NULL, vp; 3186 struct nfsrvfh fh; 3187 struct nfsexstuff retnes; 3188 u_int32_t *sizp; 3189 int error = 0, savflag, i; 3190 char *bufp; 3191 u_long *hashp; 3192 3193 /* 3194 * All this just to get the export flags for the name. 3195 */ 3196 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3197 LOCKLEAF | SAVESTART); 3198 nfsvno_setpathbuf(&named, &bufp, &hashp); 3199 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3200 if (error) { 3201 vput(dp); 3202 nfsvno_relpathbuf(&named); 3203 goto out; 3204 } 3205 if (!nd->nd_repstat) { 3206 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3207 } else { 3208 vput(dp); 3209 nfsvno_relpathbuf(&named); 3210 } 3211 if (dirp) 3212 vrele(dirp); 3213 if (nd->nd_repstat) 3214 goto out; 3215 vrele(named.ni_startdir); 3216 nfsvno_relpathbuf(&named); 3217 fh.nfsrvfh_len = NFSX_MYFH; 3218 vp = named.ni_vp; 3219 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3220 vput(vp); 3221 savflag = nd->nd_flag; 3222 if (!nd->nd_repstat) { 3223 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p); 3224 if (vp) 3225 vput(vp); 3226 } 3227 nd->nd_flag = savflag; 3228 if (nd->nd_repstat) 3229 goto out; 3230 3231 /* 3232 * Finally have the export flags for name, so we can create 3233 * the security info. 3234 */ 3235 len = 0; 3236 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3237 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3238 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3239 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3240 *tl = txdr_unsigned(RPCAUTH_UNIX); 3241 len++; 3242 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3243 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3244 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3245 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3246 nfsgss_mechlist[KERBV_MECH].len); 3247 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3248 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3249 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3250 len++; 3251 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3252 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3253 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3254 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3255 nfsgss_mechlist[KERBV_MECH].len); 3256 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3257 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3258 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3259 len++; 3260 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3261 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3262 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3263 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3264 nfsgss_mechlist[KERBV_MECH].len); 3265 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3266 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3267 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3268 len++; 3269 } 3270 } 3271 *sizp = txdr_unsigned(len); 3272 3273 out: 3274 NFSEXITCODE2(error, nd); 3275 return (error); 3276 } 3277 3278 /* 3279 * nfsv4 set client id service 3280 */ 3281 APPLESTATIC int 3282 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3283 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3284 { 3285 u_int32_t *tl; 3286 int i; 3287 int error = 0, idlen; 3288 struct nfsclient *clp = NULL; 3289 struct sockaddr_in *rad; 3290 u_char *verf, *ucp, *ucp2, addrbuf[24]; 3291 nfsquad_t clientid, confirm; 3292 3293 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3294 nd->nd_repstat = NFSERR_WRONGSEC; 3295 goto out; 3296 } 3297 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3298 verf = (u_char *)tl; 3299 tl += (NFSX_VERF / NFSX_UNSIGNED); 3300 i = fxdr_unsigned(int, *tl); 3301 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3302 nd->nd_repstat = NFSERR_BADXDR; 3303 goto nfsmout; 3304 } 3305 idlen = i; 3306 if (nd->nd_flag & ND_GSS) 3307 i += nd->nd_princlen; 3308 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i, 3309 M_NFSDCLIENT, M_WAITOK); 3310 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i); 3311 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3312 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3313 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3314 clp->lc_req.nr_cred = NULL; 3315 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3316 clp->lc_idlen = idlen; 3317 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3318 if (error) 3319 goto nfsmout; 3320 if (nd->nd_flag & ND_GSS) { 3321 clp->lc_flags = LCL_GSS; 3322 if (nd->nd_flag & ND_GSSINTEGRITY) 3323 clp->lc_flags |= LCL_GSSINTEGRITY; 3324 else if (nd->nd_flag & ND_GSSPRIVACY) 3325 clp->lc_flags |= LCL_GSSPRIVACY; 3326 } else { 3327 clp->lc_flags = 0; 3328 } 3329 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 3330 clp->lc_flags |= LCL_NAME; 3331 clp->lc_namelen = nd->nd_princlen; 3332 clp->lc_name = &clp->lc_id[idlen]; 3333 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3334 } else { 3335 clp->lc_uid = nd->nd_cred->cr_uid; 3336 clp->lc_gid = nd->nd_cred->cr_gid; 3337 } 3338 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3339 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 3340 error = nfsrv_getclientipaddr(nd, clp); 3341 if (error) 3342 goto nfsmout; 3343 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3344 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 3345 3346 /* 3347 * nfsrv_setclient() does the actual work of adding it to the 3348 * client list. If there is no error, the structure has been 3349 * linked into the client list and clp should no longer be used 3350 * here. When an error is returned, it has not been linked in, 3351 * so it should be free'd. 3352 */ 3353 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3354 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3355 if (clp->lc_flags & LCL_TCPCALLBACK) 3356 (void) nfsm_strtom(nd, "tcp", 3); 3357 else 3358 (void) nfsm_strtom(nd, "udp", 3); 3359 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3360 ucp = (u_char *)&rad->sin_addr.s_addr; 3361 ucp2 = (u_char *)&rad->sin_port; 3362 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 3363 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 3364 ucp2[0] & 0xff, ucp2[1] & 0xff); 3365 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3366 } 3367 if (clp) { 3368 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3369 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3370 free((caddr_t)clp, M_NFSDCLIENT); 3371 } 3372 if (!nd->nd_repstat) { 3373 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 3374 *tl++ = clientid.lval[0]; 3375 *tl++ = clientid.lval[1]; 3376 *tl++ = confirm.lval[0]; 3377 *tl = confirm.lval[1]; 3378 } 3379 3380 out: 3381 NFSEXITCODE2(0, nd); 3382 return (0); 3383 nfsmout: 3384 if (clp) { 3385 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3386 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3387 free((caddr_t)clp, M_NFSDCLIENT); 3388 } 3389 NFSEXITCODE2(error, nd); 3390 return (error); 3391 } 3392 3393 /* 3394 * nfsv4 set client id confirm service 3395 */ 3396 APPLESTATIC int 3397 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3398 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p, 3399 __unused struct nfsexstuff *exp) 3400 { 3401 u_int32_t *tl; 3402 int error = 0; 3403 nfsquad_t clientid, confirm; 3404 3405 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3406 nd->nd_repstat = NFSERR_WRONGSEC; 3407 goto nfsmout; 3408 } 3409 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 3410 clientid.lval[0] = *tl++; 3411 clientid.lval[1] = *tl++; 3412 confirm.lval[0] = *tl++; 3413 confirm.lval[1] = *tl; 3414 3415 /* 3416 * nfsrv_getclient() searches the client list for a match and 3417 * returns the appropriate NFSERR status. 3418 */ 3419 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3420 NULL, confirm, nd, p); 3421 nfsmout: 3422 NFSEXITCODE2(error, nd); 3423 return (error); 3424 } 3425 3426 /* 3427 * nfsv4 verify service 3428 */ 3429 APPLESTATIC int 3430 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3431 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3432 { 3433 int error = 0, ret, fhsize = NFSX_MYFH; 3434 struct nfsvattr nva; 3435 struct statfs sf; 3436 struct nfsfsinfo fs; 3437 fhandle_t fh; 3438 3439 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 3440 if (!nd->nd_repstat) 3441 nd->nd_repstat = nfsvno_statfs(vp, &sf); 3442 if (!nd->nd_repstat) 3443 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3444 if (!nd->nd_repstat) { 3445 nfsvno_getfs(&fs, isdgram); 3446 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 3447 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 3448 if (!error) { 3449 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 3450 if (ret == 0) 3451 nd->nd_repstat = NFSERR_SAME; 3452 else if (ret != NFSERR_NOTSAME) 3453 nd->nd_repstat = ret; 3454 } else if (ret) 3455 nd->nd_repstat = ret; 3456 } 3457 } 3458 vput(vp); 3459 NFSEXITCODE2(error, nd); 3460 return (error); 3461 } 3462 3463 /* 3464 * nfs openattr rpc 3465 */ 3466 APPLESTATIC int 3467 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 3468 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3469 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3470 { 3471 u_int32_t *tl; 3472 int error = 0, createdir; 3473 3474 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3475 createdir = fxdr_unsigned(int, *tl); 3476 nd->nd_repstat = NFSERR_NOTSUPP; 3477 nfsmout: 3478 vrele(dp); 3479 NFSEXITCODE2(error, nd); 3480 return (error); 3481 } 3482 3483 /* 3484 * nfsv4 release lock owner service 3485 */ 3486 APPLESTATIC int 3487 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 3488 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3489 { 3490 u_int32_t *tl; 3491 struct nfsstate *stp = NULL; 3492 int error = 0, len; 3493 nfsquad_t clientid; 3494 3495 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3496 nd->nd_repstat = NFSERR_WRONGSEC; 3497 goto nfsmout; 3498 } 3499 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3500 len = fxdr_unsigned(int, *(tl + 2)); 3501 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 3502 nd->nd_repstat = NFSERR_BADXDR; 3503 goto nfsmout; 3504 } 3505 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len, 3506 M_NFSDSTATE, M_WAITOK); 3507 stp->ls_ownerlen = len; 3508 stp->ls_op = NULL; 3509 stp->ls_flags = NFSLCK_RELEASE; 3510 stp->ls_uid = nd->nd_cred->cr_uid; 3511 clientid.lval[0] = *tl++; 3512 clientid.lval[1] = *tl; 3513 if (nd->nd_flag & ND_IMPLIEDCLID) { 3514 if (nd->nd_clientid.qval != clientid.qval) 3515 printf("EEK! multiple clids\n"); 3516 } else { 3517 nd->nd_flag |= ND_IMPLIEDCLID; 3518 nd->nd_clientid.qval = clientid.qval; 3519 } 3520 error = nfsrv_mtostr(nd, stp->ls_owner, len); 3521 if (error) 3522 goto nfsmout; 3523 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 3524 FREE((caddr_t)stp, M_NFSDSTATE); 3525 3526 NFSEXITCODE2(0, nd); 3527 return (0); 3528 nfsmout: 3529 if (stp) 3530 free((caddr_t)stp, M_NFSDSTATE); 3531 NFSEXITCODE2(error, nd); 3532 return (error); 3533 } 3534