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