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