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 * 3. 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 u_quad_t tval; 2039 2040 sf = NULL; 2041 if (nd->nd_repstat) { 2042 nfsrv_postopattr(nd, getret, &at); 2043 goto out; 2044 } 2045 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 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 free(sf, M_STATFS); 2082 NFSEXITCODE2(0, nd); 2083 return (0); 2084 } 2085 2086 /* 2087 * nfs fsinfo service 2088 */ 2089 APPLESTATIC int 2090 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 2091 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2092 { 2093 u_int32_t *tl; 2094 struct nfsfsinfo fs; 2095 int getret = 1; 2096 struct nfsvattr at; 2097 2098 if (nd->nd_repstat) { 2099 nfsrv_postopattr(nd, getret, &at); 2100 goto out; 2101 } 2102 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2103 nfsvno_getfs(&fs, isdgram); 2104 vput(vp); 2105 nfsrv_postopattr(nd, getret, &at); 2106 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 2107 *tl++ = txdr_unsigned(fs.fs_rtmax); 2108 *tl++ = txdr_unsigned(fs.fs_rtpref); 2109 *tl++ = txdr_unsigned(fs.fs_rtmult); 2110 *tl++ = txdr_unsigned(fs.fs_wtmax); 2111 *tl++ = txdr_unsigned(fs.fs_wtpref); 2112 *tl++ = txdr_unsigned(fs.fs_wtmult); 2113 *tl++ = txdr_unsigned(fs.fs_dtpref); 2114 txdr_hyper(fs.fs_maxfilesize, tl); 2115 tl += 2; 2116 txdr_nfsv3time(&fs.fs_timedelta, tl); 2117 tl += 2; 2118 *tl = txdr_unsigned(fs.fs_properties); 2119 2120 out: 2121 NFSEXITCODE2(0, nd); 2122 return (0); 2123 } 2124 2125 /* 2126 * nfs pathconf service 2127 */ 2128 APPLESTATIC int 2129 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 2130 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2131 { 2132 struct nfsv3_pathconf *pc; 2133 int getret = 1; 2134 register_t linkmax, namemax, chownres, notrunc; 2135 struct nfsvattr at; 2136 2137 if (nd->nd_repstat) { 2138 nfsrv_postopattr(nd, getret, &at); 2139 goto out; 2140 } 2141 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 2142 nd->nd_cred, p); 2143 if (!nd->nd_repstat) 2144 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 2145 nd->nd_cred, p); 2146 if (!nd->nd_repstat) 2147 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 2148 &chownres, nd->nd_cred, p); 2149 if (!nd->nd_repstat) 2150 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 2151 nd->nd_cred, p); 2152 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2153 vput(vp); 2154 nfsrv_postopattr(nd, getret, &at); 2155 if (!nd->nd_repstat) { 2156 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 2157 pc->pc_linkmax = txdr_unsigned(linkmax); 2158 pc->pc_namemax = txdr_unsigned(namemax); 2159 pc->pc_notrunc = txdr_unsigned(notrunc); 2160 pc->pc_chownrestricted = txdr_unsigned(chownres); 2161 2162 /* 2163 * These should probably be supported by VOP_PATHCONF(), but 2164 * until msdosfs is exportable (why would you want to?), the 2165 * Unix defaults should be ok. 2166 */ 2167 pc->pc_caseinsensitive = newnfs_false; 2168 pc->pc_casepreserving = newnfs_true; 2169 } 2170 2171 out: 2172 NFSEXITCODE2(0, nd); 2173 return (0); 2174 } 2175 2176 /* 2177 * nfsv4 lock service 2178 */ 2179 APPLESTATIC int 2180 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2181 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2182 { 2183 u_int32_t *tl; 2184 int i; 2185 struct nfsstate *stp = NULL; 2186 struct nfslock *lop; 2187 struct nfslockconflict cf; 2188 int error = 0; 2189 u_short flags = NFSLCK_LOCK, lflags; 2190 u_int64_t offset, len; 2191 nfsv4stateid_t stateid; 2192 nfsquad_t clientid; 2193 2194 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2195 i = fxdr_unsigned(int, *tl++); 2196 switch (i) { 2197 case NFSV4LOCKT_READW: 2198 flags |= NFSLCK_BLOCKING; 2199 case NFSV4LOCKT_READ: 2200 lflags = NFSLCK_READ; 2201 break; 2202 case NFSV4LOCKT_WRITEW: 2203 flags |= NFSLCK_BLOCKING; 2204 case NFSV4LOCKT_WRITE: 2205 lflags = NFSLCK_WRITE; 2206 break; 2207 default: 2208 nd->nd_repstat = NFSERR_BADXDR; 2209 goto nfsmout; 2210 } 2211 if (*tl++ == newnfs_true) 2212 flags |= NFSLCK_RECLAIM; 2213 offset = fxdr_hyper(tl); 2214 tl += 2; 2215 len = fxdr_hyper(tl); 2216 tl += 2; 2217 if (*tl == newnfs_true) 2218 flags |= NFSLCK_OPENTOLOCK; 2219 if (flags & NFSLCK_OPENTOLOCK) { 2220 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 2221 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 2222 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2223 nd->nd_repstat = NFSERR_BADXDR; 2224 goto nfsmout; 2225 } 2226 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2227 M_NFSDSTATE, M_WAITOK); 2228 stp->ls_ownerlen = i; 2229 stp->ls_op = nd->nd_rp; 2230 stp->ls_seq = fxdr_unsigned(int, *tl++); 2231 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2232 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2233 NFSX_STATEIDOTHER); 2234 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2235 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 2236 clientid.lval[0] = *tl++; 2237 clientid.lval[1] = *tl++; 2238 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2239 if ((nd->nd_flag & ND_NFSV41) != 0) 2240 clientid.qval = nd->nd_clientid.qval; 2241 else if (nd->nd_clientid.qval != clientid.qval) 2242 printf("EEK3 multiple clids\n"); 2243 } else { 2244 if ((nd->nd_flag & ND_NFSV41) != 0) 2245 printf("EEK! no clientid from session\n"); 2246 nd->nd_flag |= ND_IMPLIEDCLID; 2247 nd->nd_clientid.qval = clientid.qval; 2248 } 2249 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2250 if (error) 2251 goto nfsmout; 2252 } else { 2253 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2254 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2255 M_NFSDSTATE, M_WAITOK); 2256 stp->ls_ownerlen = 0; 2257 stp->ls_op = nd->nd_rp; 2258 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2259 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2260 NFSX_STATEIDOTHER); 2261 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2262 stp->ls_seq = fxdr_unsigned(int, *tl); 2263 clientid.lval[0] = stp->ls_stateid.other[0]; 2264 clientid.lval[1] = stp->ls_stateid.other[1]; 2265 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2266 if ((nd->nd_flag & ND_NFSV41) != 0) 2267 clientid.qval = nd->nd_clientid.qval; 2268 else if (nd->nd_clientid.qval != clientid.qval) 2269 printf("EEK4 multiple clids\n"); 2270 } else { 2271 if ((nd->nd_flag & ND_NFSV41) != 0) 2272 printf("EEK! no clientid from session\n"); 2273 nd->nd_flag |= ND_IMPLIEDCLID; 2274 nd->nd_clientid.qval = clientid.qval; 2275 } 2276 } 2277 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2278 M_NFSDLOCK, M_WAITOK); 2279 lop->lo_first = offset; 2280 if (len == NFS64BITSSET) { 2281 lop->lo_end = NFS64BITSSET; 2282 } else { 2283 lop->lo_end = offset + len; 2284 if (lop->lo_end <= lop->lo_first) 2285 nd->nd_repstat = NFSERR_INVAL; 2286 } 2287 lop->lo_flags = lflags; 2288 stp->ls_flags = flags; 2289 stp->ls_uid = nd->nd_cred->cr_uid; 2290 2291 /* 2292 * Do basic access checking. 2293 */ 2294 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2295 if (vnode_vtype(vp) == VDIR) 2296 nd->nd_repstat = NFSERR_ISDIR; 2297 else 2298 nd->nd_repstat = NFSERR_INVAL; 2299 } 2300 if (!nd->nd_repstat) { 2301 if (lflags & NFSLCK_WRITE) { 2302 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 2303 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2304 NFSACCCHK_VPISLOCKED, NULL); 2305 } else { 2306 nd->nd_repstat = nfsvno_accchk(vp, VREAD, 2307 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2308 NFSACCCHK_VPISLOCKED, NULL); 2309 if (nd->nd_repstat) 2310 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2311 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2312 NFSACCCHK_VPISLOCKED, NULL); 2313 } 2314 } 2315 2316 /* 2317 * We call nfsrv_lockctrl() even if nd_repstat set, so that the 2318 * seqid# gets updated. nfsrv_lockctrl() will return the value 2319 * of nd_repstat, if it gets that far. 2320 */ 2321 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2322 &stateid, exp, nd, p); 2323 if (lop) 2324 FREE((caddr_t)lop, M_NFSDLOCK); 2325 if (stp) 2326 FREE((caddr_t)stp, M_NFSDSTATE); 2327 if (!nd->nd_repstat) { 2328 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2329 *tl++ = txdr_unsigned(stateid.seqid); 2330 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2331 } else if (nd->nd_repstat == NFSERR_DENIED) { 2332 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2333 txdr_hyper(cf.cl_first, tl); 2334 tl += 2; 2335 if (cf.cl_end == NFS64BITSSET) 2336 len = NFS64BITSSET; 2337 else 2338 len = cf.cl_end - cf.cl_first; 2339 txdr_hyper(len, tl); 2340 tl += 2; 2341 if (cf.cl_flags == NFSLCK_WRITE) 2342 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2343 else 2344 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2345 *tl++ = stateid.other[0]; 2346 *tl = stateid.other[1]; 2347 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2348 } 2349 vput(vp); 2350 NFSEXITCODE2(0, nd); 2351 return (0); 2352 nfsmout: 2353 vput(vp); 2354 if (stp) 2355 free((caddr_t)stp, M_NFSDSTATE); 2356 NFSEXITCODE2(error, nd); 2357 return (error); 2358 } 2359 2360 /* 2361 * nfsv4 lock test service 2362 */ 2363 APPLESTATIC int 2364 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2365 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2366 { 2367 u_int32_t *tl; 2368 int i; 2369 struct nfsstate *stp = NULL; 2370 struct nfslock lo, *lop = &lo; 2371 struct nfslockconflict cf; 2372 int error = 0; 2373 nfsv4stateid_t stateid; 2374 nfsquad_t clientid; 2375 u_int64_t len; 2376 2377 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 2378 i = fxdr_unsigned(int, *(tl + 7)); 2379 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2380 nd->nd_repstat = NFSERR_BADXDR; 2381 goto nfsmout; 2382 } 2383 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2384 M_NFSDSTATE, M_WAITOK); 2385 stp->ls_ownerlen = i; 2386 stp->ls_op = NULL; 2387 stp->ls_flags = NFSLCK_TEST; 2388 stp->ls_uid = nd->nd_cred->cr_uid; 2389 i = fxdr_unsigned(int, *tl++); 2390 switch (i) { 2391 case NFSV4LOCKT_READW: 2392 stp->ls_flags |= NFSLCK_BLOCKING; 2393 case NFSV4LOCKT_READ: 2394 lo.lo_flags = NFSLCK_READ; 2395 break; 2396 case NFSV4LOCKT_WRITEW: 2397 stp->ls_flags |= NFSLCK_BLOCKING; 2398 case NFSV4LOCKT_WRITE: 2399 lo.lo_flags = NFSLCK_WRITE; 2400 break; 2401 default: 2402 nd->nd_repstat = NFSERR_BADXDR; 2403 goto nfsmout; 2404 } 2405 lo.lo_first = fxdr_hyper(tl); 2406 tl += 2; 2407 len = fxdr_hyper(tl); 2408 if (len == NFS64BITSSET) { 2409 lo.lo_end = NFS64BITSSET; 2410 } else { 2411 lo.lo_end = lo.lo_first + len; 2412 if (lo.lo_end <= lo.lo_first) 2413 nd->nd_repstat = NFSERR_INVAL; 2414 } 2415 tl += 2; 2416 clientid.lval[0] = *tl++; 2417 clientid.lval[1] = *tl; 2418 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2419 if ((nd->nd_flag & ND_NFSV41) != 0) 2420 clientid.qval = nd->nd_clientid.qval; 2421 else if (nd->nd_clientid.qval != clientid.qval) 2422 printf("EEK5 multiple clids\n"); 2423 } else { 2424 if ((nd->nd_flag & ND_NFSV41) != 0) 2425 printf("EEK! no clientid from session\n"); 2426 nd->nd_flag |= ND_IMPLIEDCLID; 2427 nd->nd_clientid.qval = clientid.qval; 2428 } 2429 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2430 if (error) 2431 goto nfsmout; 2432 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2433 if (vnode_vtype(vp) == VDIR) 2434 nd->nd_repstat = NFSERR_ISDIR; 2435 else 2436 nd->nd_repstat = NFSERR_INVAL; 2437 } 2438 if (!nd->nd_repstat) 2439 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2440 &stateid, exp, nd, p); 2441 if (nd->nd_repstat) { 2442 if (nd->nd_repstat == NFSERR_DENIED) { 2443 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2444 txdr_hyper(cf.cl_first, tl); 2445 tl += 2; 2446 if (cf.cl_end == NFS64BITSSET) 2447 len = NFS64BITSSET; 2448 else 2449 len = cf.cl_end - cf.cl_first; 2450 txdr_hyper(len, tl); 2451 tl += 2; 2452 if (cf.cl_flags == NFSLCK_WRITE) 2453 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2454 else 2455 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2456 *tl++ = stp->ls_stateid.other[0]; 2457 *tl = stp->ls_stateid.other[1]; 2458 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2459 } 2460 } 2461 vput(vp); 2462 if (stp) 2463 FREE((caddr_t)stp, M_NFSDSTATE); 2464 NFSEXITCODE2(0, nd); 2465 return (0); 2466 nfsmout: 2467 vput(vp); 2468 if (stp) 2469 free((caddr_t)stp, M_NFSDSTATE); 2470 NFSEXITCODE2(error, nd); 2471 return (error); 2472 } 2473 2474 /* 2475 * nfsv4 unlock service 2476 */ 2477 APPLESTATIC int 2478 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2479 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2480 { 2481 u_int32_t *tl; 2482 int i; 2483 struct nfsstate *stp; 2484 struct nfslock *lop; 2485 int error = 0; 2486 nfsv4stateid_t stateid; 2487 nfsquad_t clientid; 2488 u_int64_t len; 2489 2490 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2491 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2492 M_NFSDSTATE, M_WAITOK); 2493 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2494 M_NFSDLOCK, M_WAITOK); 2495 stp->ls_flags = NFSLCK_UNLOCK; 2496 lop->lo_flags = NFSLCK_UNLOCK; 2497 stp->ls_op = nd->nd_rp; 2498 i = fxdr_unsigned(int, *tl++); 2499 switch (i) { 2500 case NFSV4LOCKT_READW: 2501 stp->ls_flags |= NFSLCK_BLOCKING; 2502 case NFSV4LOCKT_READ: 2503 break; 2504 case NFSV4LOCKT_WRITEW: 2505 stp->ls_flags |= NFSLCK_BLOCKING; 2506 case NFSV4LOCKT_WRITE: 2507 break; 2508 default: 2509 nd->nd_repstat = NFSERR_BADXDR; 2510 free(stp, M_NFSDSTATE); 2511 free(lop, M_NFSDLOCK); 2512 goto nfsmout; 2513 } 2514 stp->ls_ownerlen = 0; 2515 stp->ls_uid = nd->nd_cred->cr_uid; 2516 stp->ls_seq = fxdr_unsigned(int, *tl++); 2517 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2518 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2519 NFSX_STATEIDOTHER); 2520 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2521 lop->lo_first = fxdr_hyper(tl); 2522 tl += 2; 2523 len = fxdr_hyper(tl); 2524 if (len == NFS64BITSSET) { 2525 lop->lo_end = NFS64BITSSET; 2526 } else { 2527 lop->lo_end = lop->lo_first + len; 2528 if (lop->lo_end <= lop->lo_first) 2529 nd->nd_repstat = NFSERR_INVAL; 2530 } 2531 clientid.lval[0] = stp->ls_stateid.other[0]; 2532 clientid.lval[1] = stp->ls_stateid.other[1]; 2533 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2534 if ((nd->nd_flag & ND_NFSV41) != 0) 2535 clientid.qval = nd->nd_clientid.qval; 2536 else if (nd->nd_clientid.qval != clientid.qval) 2537 printf("EEK6 multiple clids\n"); 2538 } else { 2539 if ((nd->nd_flag & ND_NFSV41) != 0) 2540 printf("EEK! no clientid from session\n"); 2541 nd->nd_flag |= ND_IMPLIEDCLID; 2542 nd->nd_clientid.qval = clientid.qval; 2543 } 2544 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2545 if (vnode_vtype(vp) == VDIR) 2546 nd->nd_repstat = NFSERR_ISDIR; 2547 else 2548 nd->nd_repstat = NFSERR_INVAL; 2549 } 2550 /* 2551 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 2552 * seqid# gets incremented. nfsrv_lockctrl() will return the 2553 * value of nd_repstat, if it gets that far. 2554 */ 2555 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 2556 &stateid, exp, nd, p); 2557 if (stp) 2558 FREE((caddr_t)stp, M_NFSDSTATE); 2559 if (lop) 2560 free((caddr_t)lop, M_NFSDLOCK); 2561 if (!nd->nd_repstat) { 2562 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2563 *tl++ = txdr_unsigned(stateid.seqid); 2564 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2565 } 2566 nfsmout: 2567 vput(vp); 2568 NFSEXITCODE2(error, nd); 2569 return (error); 2570 } 2571 2572 /* 2573 * nfsv4 open service 2574 */ 2575 APPLESTATIC int 2576 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2577 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p, 2578 struct nfsexstuff *exp) 2579 { 2580 u_int32_t *tl; 2581 int i, retext; 2582 struct nfsstate *stp = NULL; 2583 int error = 0, create, claim, exclusive_flag = 0; 2584 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 2585 int how = NFSCREATE_UNCHECKED; 2586 int32_t cverf[2], tverf[2] = { 0, 0 }; 2587 vnode_t vp = NULL, dirp = NULL; 2588 struct nfsvattr nva, dirfor, diraft; 2589 struct nameidata named; 2590 nfsv4stateid_t stateid, delegstateid; 2591 nfsattrbit_t attrbits; 2592 nfsquad_t clientid; 2593 char *bufp = NULL; 2594 u_long *hashp; 2595 NFSACL_T *aclp = NULL; 2596 2597 #ifdef NFS4_ACL_EXTATTR_NAME 2598 aclp = acl_alloc(M_WAITOK); 2599 aclp->acl_cnt = 0; 2600 #endif 2601 NFSZERO_ATTRBIT(&attrbits); 2602 named.ni_startdir = NULL; 2603 named.ni_cnd.cn_nameiop = 0; 2604 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2605 i = fxdr_unsigned(int, *(tl + 5)); 2606 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2607 nd->nd_repstat = NFSERR_BADXDR; 2608 goto nfsmout; 2609 } 2610 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2611 M_NFSDSTATE, M_WAITOK); 2612 stp->ls_ownerlen = i; 2613 stp->ls_op = nd->nd_rp; 2614 stp->ls_flags = NFSLCK_OPEN; 2615 stp->ls_uid = nd->nd_cred->cr_uid; 2616 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2617 i = fxdr_unsigned(int, *tl++); 2618 retext = 0; 2619 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2620 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2621 retext = 1; 2622 /* For now, ignore these. */ 2623 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2624 switch (i & NFSV4OPEN_WANTDELEGMASK) { 2625 case NFSV4OPEN_WANTANYDELEG: 2626 stp->ls_flags |= (NFSLCK_WANTRDELEG | 2627 NFSLCK_WANTWDELEG); 2628 i &= ~NFSV4OPEN_WANTDELEGMASK; 2629 break; 2630 case NFSV4OPEN_WANTREADDELEG: 2631 stp->ls_flags |= NFSLCK_WANTRDELEG; 2632 i &= ~NFSV4OPEN_WANTDELEGMASK; 2633 break; 2634 case NFSV4OPEN_WANTWRITEDELEG: 2635 stp->ls_flags |= NFSLCK_WANTWDELEG; 2636 i &= ~NFSV4OPEN_WANTDELEGMASK; 2637 break; 2638 case NFSV4OPEN_WANTNODELEG: 2639 stp->ls_flags |= NFSLCK_WANTNODELEG; 2640 i &= ~NFSV4OPEN_WANTDELEGMASK; 2641 break; 2642 case NFSV4OPEN_WANTCANCEL: 2643 printf("NFSv4: ignore Open WantCancel\n"); 2644 i &= ~NFSV4OPEN_WANTDELEGMASK; 2645 break; 2646 default: 2647 /* nd_repstat will be set to NFSERR_INVAL below. */ 2648 break; 2649 } 2650 } 2651 switch (i) { 2652 case NFSV4OPEN_ACCESSREAD: 2653 stp->ls_flags |= NFSLCK_READACCESS; 2654 break; 2655 case NFSV4OPEN_ACCESSWRITE: 2656 stp->ls_flags |= NFSLCK_WRITEACCESS; 2657 break; 2658 case NFSV4OPEN_ACCESSBOTH: 2659 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2660 break; 2661 default: 2662 nd->nd_repstat = NFSERR_INVAL; 2663 } 2664 i = fxdr_unsigned(int, *tl++); 2665 switch (i) { 2666 case NFSV4OPEN_DENYNONE: 2667 break; 2668 case NFSV4OPEN_DENYREAD: 2669 stp->ls_flags |= NFSLCK_READDENY; 2670 break; 2671 case NFSV4OPEN_DENYWRITE: 2672 stp->ls_flags |= NFSLCK_WRITEDENY; 2673 break; 2674 case NFSV4OPEN_DENYBOTH: 2675 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 2676 break; 2677 default: 2678 nd->nd_repstat = NFSERR_INVAL; 2679 } 2680 clientid.lval[0] = *tl++; 2681 clientid.lval[1] = *tl; 2682 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2683 if ((nd->nd_flag & ND_NFSV41) != 0) 2684 clientid.qval = nd->nd_clientid.qval; 2685 else if (nd->nd_clientid.qval != clientid.qval) 2686 printf("EEK7 multiple clids\n"); 2687 } else { 2688 if ((nd->nd_flag & ND_NFSV41) != 0) 2689 printf("EEK! no clientid from session\n"); 2690 nd->nd_flag |= ND_IMPLIEDCLID; 2691 nd->nd_clientid.qval = clientid.qval; 2692 } 2693 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2694 if (error) 2695 goto nfsmout; 2696 NFSVNO_ATTRINIT(&nva); 2697 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2698 create = fxdr_unsigned(int, *tl); 2699 if (!nd->nd_repstat) 2700 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 2701 if (create == NFSV4OPEN_CREATE) { 2702 nva.na_type = VREG; 2703 nva.na_mode = 0; 2704 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2705 how = fxdr_unsigned(int, *tl); 2706 switch (how) { 2707 case NFSCREATE_UNCHECKED: 2708 case NFSCREATE_GUARDED: 2709 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2710 if (error) 2711 goto nfsmout; 2712 /* 2713 * If the na_gid being set is the same as that of 2714 * the directory it is going in, clear it, since 2715 * that is what will be set by default. This allows 2716 * a user that isn't in that group to do the create. 2717 */ 2718 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 2719 nva.na_gid == dirfor.na_gid) 2720 NFSVNO_UNSET(&nva, gid); 2721 if (!nd->nd_repstat) 2722 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2723 break; 2724 case NFSCREATE_EXCLUSIVE: 2725 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2726 cverf[0] = *tl++; 2727 cverf[1] = *tl; 2728 break; 2729 case NFSCREATE_EXCLUSIVE41: 2730 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2731 cverf[0] = *tl++; 2732 cverf[1] = *tl; 2733 error = nfsv4_sattr(nd, vp, &nva, &attrbits, aclp, p); 2734 if (error != 0) 2735 goto nfsmout; 2736 if (NFSISSET_ATTRBIT(&attrbits, 2737 NFSATTRBIT_TIMEACCESSSET)) 2738 nd->nd_repstat = NFSERR_INVAL; 2739 /* 2740 * If the na_gid being set is the same as that of 2741 * the directory it is going in, clear it, since 2742 * that is what will be set by default. This allows 2743 * a user that isn't in that group to do the create. 2744 */ 2745 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2746 nva.na_gid == dirfor.na_gid) 2747 NFSVNO_UNSET(&nva, gid); 2748 if (nd->nd_repstat == 0) 2749 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2750 break; 2751 default: 2752 nd->nd_repstat = NFSERR_BADXDR; 2753 goto nfsmout; 2754 } 2755 } else if (create != NFSV4OPEN_NOCREATE) { 2756 nd->nd_repstat = NFSERR_BADXDR; 2757 goto nfsmout; 2758 } 2759 2760 /* 2761 * Now, handle the claim, which usually includes looking up a 2762 * name in the directory referenced by dp. The exception is 2763 * NFSV4OPEN_CLAIMPREVIOUS. 2764 */ 2765 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2766 claim = fxdr_unsigned(int, *tl); 2767 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 2768 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2769 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2770 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 2771 stp->ls_flags |= NFSLCK_DELEGCUR; 2772 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2773 stp->ls_flags |= NFSLCK_DELEGPREV; 2774 } 2775 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 2776 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2777 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 2778 claim != NFSV4OPEN_CLAIMNULL) 2779 nd->nd_repstat = NFSERR_INVAL; 2780 if (nd->nd_repstat) { 2781 nd->nd_repstat = nfsrv_opencheck(clientid, 2782 &stateid, stp, NULL, nd, p, nd->nd_repstat); 2783 goto nfsmout; 2784 } 2785 if (create == NFSV4OPEN_CREATE) 2786 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 2787 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 2788 else 2789 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 2790 LOCKLEAF | SAVESTART); 2791 nfsvno_setpathbuf(&named, &bufp, &hashp); 2792 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2793 if (error) { 2794 vrele(dp); 2795 #ifdef NFS4_ACL_EXTATTR_NAME 2796 acl_free(aclp); 2797 #endif 2798 FREE((caddr_t)stp, M_NFSDSTATE); 2799 nfsvno_relpathbuf(&named); 2800 NFSEXITCODE2(error, nd); 2801 return (error); 2802 } 2803 if (!nd->nd_repstat) { 2804 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 2805 p, &dirp); 2806 } else { 2807 vrele(dp); 2808 nfsvno_relpathbuf(&named); 2809 } 2810 if (create == NFSV4OPEN_CREATE) { 2811 switch (how) { 2812 case NFSCREATE_UNCHECKED: 2813 if (named.ni_vp) { 2814 /* 2815 * Clear the setable attribute bits, except 2816 * for Size, if it is being truncated. 2817 */ 2818 NFSZERO_ATTRBIT(&attrbits); 2819 if (NFSVNO_ISSETSIZE(&nva)) 2820 NFSSETBIT_ATTRBIT(&attrbits, 2821 NFSATTRBIT_SIZE); 2822 } 2823 break; 2824 case NFSCREATE_GUARDED: 2825 if (named.ni_vp && !nd->nd_repstat) 2826 nd->nd_repstat = EEXIST; 2827 break; 2828 case NFSCREATE_EXCLUSIVE: 2829 exclusive_flag = 1; 2830 if (!named.ni_vp) 2831 nva.na_mode = 0; 2832 break; 2833 case NFSCREATE_EXCLUSIVE41: 2834 exclusive_flag = 1; 2835 break; 2836 } 2837 } 2838 nfsvno_open(nd, &named, clientid, &stateid, stp, 2839 &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 2840 nd->nd_cred, p, exp, &vp); 2841 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 2842 NFSV4OPEN_CLAIMFH) { 2843 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2844 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2845 i = fxdr_unsigned(int, *tl); 2846 switch (i) { 2847 case NFSV4OPEN_DELEGATEREAD: 2848 stp->ls_flags |= NFSLCK_DELEGREAD; 2849 break; 2850 case NFSV4OPEN_DELEGATEWRITE: 2851 stp->ls_flags |= NFSLCK_DELEGWRITE; 2852 case NFSV4OPEN_DELEGATENONE: 2853 break; 2854 default: 2855 nd->nd_repstat = NFSERR_BADXDR; 2856 goto nfsmout; 2857 } 2858 stp->ls_flags |= NFSLCK_RECLAIM; 2859 } else { 2860 /* CLAIM_NULL_FH */ 2861 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 2862 nd->nd_repstat = NFSERR_INVAL; 2863 } 2864 vp = dp; 2865 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 2866 if ((vp->v_iflag & VI_DOOMED) == 0) 2867 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 2868 stp, vp, nd, p, nd->nd_repstat); 2869 else 2870 nd->nd_repstat = NFSERR_PERM; 2871 } else { 2872 nd->nd_repstat = NFSERR_BADXDR; 2873 goto nfsmout; 2874 } 2875 2876 /* 2877 * Do basic access checking. 2878 */ 2879 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2880 /* 2881 * The IETF working group decided that this is the correct 2882 * error return for all non-regular files. 2883 */ 2884 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK; 2885 } 2886 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 2887 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 2888 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2889 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 2890 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 2891 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2892 if (nd->nd_repstat) 2893 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2894 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2895 NFSACCCHK_VPISLOCKED, NULL); 2896 } 2897 2898 if (!nd->nd_repstat) { 2899 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 2900 if (!nd->nd_repstat) { 2901 tverf[0] = nva.na_atime.tv_sec; 2902 tverf[1] = nva.na_atime.tv_nsec; 2903 } 2904 } 2905 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 2906 cverf[1] != tverf[1])) 2907 nd->nd_repstat = EEXIST; 2908 /* 2909 * Do the open locking/delegation stuff. 2910 */ 2911 if (!nd->nd_repstat) 2912 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 2913 &delegstateid, &rflags, exp, p, nva.na_filerev); 2914 2915 /* 2916 * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 2917 * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 2918 * (ie: Leave the NFSVOPUNLOCK() about here.) 2919 */ 2920 if (vp) 2921 NFSVOPUNLOCK(vp, 0); 2922 if (stp) 2923 FREE((caddr_t)stp, M_NFSDSTATE); 2924 if (!nd->nd_repstat && dirp) 2925 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 2926 0); 2927 if (!nd->nd_repstat) { 2928 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 2929 *tl++ = txdr_unsigned(stateid.seqid); 2930 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2931 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2932 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2933 *tl++ = newnfs_true; 2934 *tl++ = 0; 2935 *tl++ = 0; 2936 *tl++ = 0; 2937 *tl++ = 0; 2938 } else { 2939 *tl++ = newnfs_false; /* Since dirp is not locked */ 2940 txdr_hyper(dirfor.na_filerev, tl); 2941 tl += 2; 2942 txdr_hyper(diraft.na_filerev, tl); 2943 tl += 2; 2944 } 2945 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 2946 (void) nfsrv_putattrbit(nd, &attrbits); 2947 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2948 if (rflags & NFSV4OPEN_READDELEGATE) 2949 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 2950 else if (rflags & NFSV4OPEN_WRITEDELEGATE) 2951 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 2952 else if (retext != 0) { 2953 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 2954 if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 2955 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2956 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 2957 *tl = newnfs_false; 2958 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 2959 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2960 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 2961 *tl = newnfs_false; 2962 } else { 2963 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2964 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 2965 } 2966 } else 2967 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 2968 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 2969 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 2970 *tl++ = txdr_unsigned(delegstateid.seqid); 2971 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 2972 NFSX_STATEIDOTHER); 2973 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2974 if (rflags & NFSV4OPEN_RECALL) 2975 *tl = newnfs_true; 2976 else 2977 *tl = newnfs_false; 2978 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 2979 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2980 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 2981 txdr_hyper(nva.na_size, tl); 2982 } 2983 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2984 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 2985 *tl++ = txdr_unsigned(0x0); 2986 acemask = NFSV4ACE_ALLFILESMASK; 2987 if (nva.na_mode & S_IRUSR) 2988 acemask |= NFSV4ACE_READMASK; 2989 if (nva.na_mode & S_IWUSR) 2990 acemask |= NFSV4ACE_WRITEMASK; 2991 if (nva.na_mode & S_IXUSR) 2992 acemask |= NFSV4ACE_EXECUTEMASK; 2993 *tl = txdr_unsigned(acemask); 2994 (void) nfsm_strtom(nd, "OWNER@", 6); 2995 } 2996 *vpp = vp; 2997 } else if (vp) { 2998 vrele(vp); 2999 } 3000 if (dirp) 3001 vrele(dirp); 3002 #ifdef NFS4_ACL_EXTATTR_NAME 3003 acl_free(aclp); 3004 #endif 3005 NFSEXITCODE2(0, nd); 3006 return (0); 3007 nfsmout: 3008 vrele(dp); 3009 #ifdef NFS4_ACL_EXTATTR_NAME 3010 acl_free(aclp); 3011 #endif 3012 if (stp) 3013 FREE((caddr_t)stp, M_NFSDSTATE); 3014 NFSEXITCODE2(error, nd); 3015 return (error); 3016 } 3017 3018 /* 3019 * nfsv4 close service 3020 */ 3021 APPLESTATIC int 3022 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3023 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3024 { 3025 u_int32_t *tl; 3026 struct nfsstate st, *stp = &st; 3027 int error = 0; 3028 nfsv4stateid_t stateid; 3029 nfsquad_t clientid; 3030 3031 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 3032 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3033 stp->ls_ownerlen = 0; 3034 stp->ls_op = nd->nd_rp; 3035 stp->ls_uid = nd->nd_cred->cr_uid; 3036 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3037 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3038 NFSX_STATEIDOTHER); 3039 stp->ls_flags = NFSLCK_CLOSE; 3040 clientid.lval[0] = stp->ls_stateid.other[0]; 3041 clientid.lval[1] = stp->ls_stateid.other[1]; 3042 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3043 if ((nd->nd_flag & ND_NFSV41) != 0) 3044 clientid.qval = nd->nd_clientid.qval; 3045 else if (nd->nd_clientid.qval != clientid.qval) 3046 printf("EEK8 multiple clids\n"); 3047 } else { 3048 if ((nd->nd_flag & ND_NFSV41) != 0) 3049 printf("EEK! no clientid from session\n"); 3050 nd->nd_flag |= ND_IMPLIEDCLID; 3051 nd->nd_clientid.qval = clientid.qval; 3052 } 3053 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 3054 vput(vp); 3055 if (!nd->nd_repstat) { 3056 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3057 *tl++ = txdr_unsigned(stateid.seqid); 3058 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3059 } 3060 NFSEXITCODE2(0, nd); 3061 return (0); 3062 nfsmout: 3063 vput(vp); 3064 NFSEXITCODE2(error, nd); 3065 return (error); 3066 } 3067 3068 /* 3069 * nfsv4 delegpurge service 3070 */ 3071 APPLESTATIC int 3072 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3073 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3074 { 3075 u_int32_t *tl; 3076 int error = 0; 3077 nfsquad_t clientid; 3078 3079 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3080 nd->nd_repstat = NFSERR_WRONGSEC; 3081 goto nfsmout; 3082 } 3083 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3084 clientid.lval[0] = *tl++; 3085 clientid.lval[1] = *tl; 3086 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3087 if ((nd->nd_flag & ND_NFSV41) != 0) 3088 clientid.qval = nd->nd_clientid.qval; 3089 else if (nd->nd_clientid.qval != clientid.qval) 3090 printf("EEK9 multiple clids\n"); 3091 } else { 3092 if ((nd->nd_flag & ND_NFSV41) != 0) 3093 printf("EEK! no clientid from session\n"); 3094 nd->nd_flag |= ND_IMPLIEDCLID; 3095 nd->nd_clientid.qval = clientid.qval; 3096 } 3097 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 3098 NFSV4OP_DELEGPURGE, nd->nd_cred, p); 3099 nfsmout: 3100 NFSEXITCODE2(error, nd); 3101 return (error); 3102 } 3103 3104 /* 3105 * nfsv4 delegreturn service 3106 */ 3107 APPLESTATIC int 3108 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3109 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3110 { 3111 u_int32_t *tl; 3112 int error = 0; 3113 nfsv4stateid_t stateid; 3114 nfsquad_t clientid; 3115 3116 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3117 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3118 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 3119 clientid.lval[0] = stateid.other[0]; 3120 clientid.lval[1] = stateid.other[1]; 3121 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3122 if ((nd->nd_flag & ND_NFSV41) != 0) 3123 clientid.qval = nd->nd_clientid.qval; 3124 else if (nd->nd_clientid.qval != clientid.qval) 3125 printf("EEK10 multiple clids\n"); 3126 } else { 3127 if ((nd->nd_flag & ND_NFSV41) != 0) 3128 printf("EEK! no clientid from session\n"); 3129 nd->nd_flag |= ND_IMPLIEDCLID; 3130 nd->nd_clientid.qval = clientid.qval; 3131 } 3132 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 3133 NFSV4OP_DELEGRETURN, nd->nd_cred, p); 3134 nfsmout: 3135 vput(vp); 3136 NFSEXITCODE2(error, nd); 3137 return (error); 3138 } 3139 3140 /* 3141 * nfsv4 get file handle service 3142 */ 3143 APPLESTATIC int 3144 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3145 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3146 { 3147 fhandle_t fh; 3148 3149 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3150 vput(vp); 3151 if (!nd->nd_repstat) 3152 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3153 NFSEXITCODE2(0, nd); 3154 return (0); 3155 } 3156 3157 /* 3158 * nfsv4 open confirm service 3159 */ 3160 APPLESTATIC int 3161 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3162 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3163 { 3164 u_int32_t *tl; 3165 struct nfsstate st, *stp = &st; 3166 int error = 0; 3167 nfsv4stateid_t stateid; 3168 nfsquad_t clientid; 3169 3170 if ((nd->nd_flag & ND_NFSV41) != 0) { 3171 nd->nd_repstat = NFSERR_NOTSUPP; 3172 goto nfsmout; 3173 } 3174 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3175 stp->ls_ownerlen = 0; 3176 stp->ls_op = nd->nd_rp; 3177 stp->ls_uid = nd->nd_cred->cr_uid; 3178 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3179 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3180 NFSX_STATEIDOTHER); 3181 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3182 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 3183 stp->ls_flags = NFSLCK_CONFIRM; 3184 clientid.lval[0] = stp->ls_stateid.other[0]; 3185 clientid.lval[1] = stp->ls_stateid.other[1]; 3186 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3187 if ((nd->nd_flag & ND_NFSV41) != 0) 3188 clientid.qval = nd->nd_clientid.qval; 3189 else if (nd->nd_clientid.qval != clientid.qval) 3190 printf("EEK11 multiple clids\n"); 3191 } else { 3192 if ((nd->nd_flag & ND_NFSV41) != 0) 3193 printf("EEK! no clientid from session\n"); 3194 nd->nd_flag |= ND_IMPLIEDCLID; 3195 nd->nd_clientid.qval = clientid.qval; 3196 } 3197 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 3198 if (!nd->nd_repstat) { 3199 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3200 *tl++ = txdr_unsigned(stateid.seqid); 3201 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3202 } 3203 nfsmout: 3204 vput(vp); 3205 NFSEXITCODE2(error, nd); 3206 return (error); 3207 } 3208 3209 /* 3210 * nfsv4 open downgrade service 3211 */ 3212 APPLESTATIC int 3213 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3214 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3215 { 3216 u_int32_t *tl; 3217 int i; 3218 struct nfsstate st, *stp = &st; 3219 int error = 0; 3220 nfsv4stateid_t stateid; 3221 nfsquad_t clientid; 3222 3223 /* opendowngrade can only work on a file object.*/ 3224 if (vp->v_type != VREG) { 3225 error = NFSERR_INVAL; 3226 goto nfsmout; 3227 } 3228 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 3229 stp->ls_ownerlen = 0; 3230 stp->ls_op = nd->nd_rp; 3231 stp->ls_uid = nd->nd_cred->cr_uid; 3232 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3233 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3234 NFSX_STATEIDOTHER); 3235 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3236 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3237 i = fxdr_unsigned(int, *tl++); 3238 switch (i) { 3239 case NFSV4OPEN_ACCESSREAD: 3240 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3241 break; 3242 case NFSV4OPEN_ACCESSWRITE: 3243 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3244 break; 3245 case NFSV4OPEN_ACCESSBOTH: 3246 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3247 NFSLCK_DOWNGRADE); 3248 break; 3249 default: 3250 nd->nd_repstat = NFSERR_BADXDR; 3251 } 3252 i = fxdr_unsigned(int, *tl); 3253 switch (i) { 3254 case NFSV4OPEN_DENYNONE: 3255 break; 3256 case NFSV4OPEN_DENYREAD: 3257 stp->ls_flags |= NFSLCK_READDENY; 3258 break; 3259 case NFSV4OPEN_DENYWRITE: 3260 stp->ls_flags |= NFSLCK_WRITEDENY; 3261 break; 3262 case NFSV4OPEN_DENYBOTH: 3263 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3264 break; 3265 default: 3266 nd->nd_repstat = NFSERR_BADXDR; 3267 } 3268 3269 clientid.lval[0] = stp->ls_stateid.other[0]; 3270 clientid.lval[1] = stp->ls_stateid.other[1]; 3271 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3272 if ((nd->nd_flag & ND_NFSV41) != 0) 3273 clientid.qval = nd->nd_clientid.qval; 3274 else if (nd->nd_clientid.qval != clientid.qval) 3275 printf("EEK12 multiple clids\n"); 3276 } else { 3277 if ((nd->nd_flag & ND_NFSV41) != 0) 3278 printf("EEK! no clientid from session\n"); 3279 nd->nd_flag |= ND_IMPLIEDCLID; 3280 nd->nd_clientid.qval = clientid.qval; 3281 } 3282 if (!nd->nd_repstat) 3283 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3284 nd, p); 3285 if (!nd->nd_repstat) { 3286 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3287 *tl++ = txdr_unsigned(stateid.seqid); 3288 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3289 } 3290 nfsmout: 3291 vput(vp); 3292 NFSEXITCODE2(error, nd); 3293 return (error); 3294 } 3295 3296 /* 3297 * nfsv4 renew lease service 3298 */ 3299 APPLESTATIC int 3300 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3301 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3302 { 3303 u_int32_t *tl; 3304 int error = 0; 3305 nfsquad_t clientid; 3306 3307 if ((nd->nd_flag & ND_NFSV41) != 0) { 3308 nd->nd_repstat = NFSERR_NOTSUPP; 3309 goto nfsmout; 3310 } 3311 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3312 nd->nd_repstat = NFSERR_WRONGSEC; 3313 goto nfsmout; 3314 } 3315 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3316 clientid.lval[0] = *tl++; 3317 clientid.lval[1] = *tl; 3318 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3319 if ((nd->nd_flag & ND_NFSV41) != 0) 3320 clientid.qval = nd->nd_clientid.qval; 3321 else if (nd->nd_clientid.qval != clientid.qval) 3322 printf("EEK13 multiple clids\n"); 3323 } else { 3324 if ((nd->nd_flag & ND_NFSV41) != 0) 3325 printf("EEK! no clientid from session\n"); 3326 nd->nd_flag |= ND_IMPLIEDCLID; 3327 nd->nd_clientid.qval = clientid.qval; 3328 } 3329 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3330 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 3331 nfsmout: 3332 NFSEXITCODE2(error, nd); 3333 return (error); 3334 } 3335 3336 /* 3337 * nfsv4 security info service 3338 */ 3339 APPLESTATIC int 3340 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3341 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 3342 { 3343 u_int32_t *tl; 3344 int len; 3345 struct nameidata named; 3346 vnode_t dirp = NULL, vp; 3347 struct nfsrvfh fh; 3348 struct nfsexstuff retnes; 3349 u_int32_t *sizp; 3350 int error = 0, savflag, i; 3351 char *bufp; 3352 u_long *hashp; 3353 3354 /* 3355 * All this just to get the export flags for the name. 3356 */ 3357 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3358 LOCKLEAF | SAVESTART); 3359 nfsvno_setpathbuf(&named, &bufp, &hashp); 3360 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3361 if (error) { 3362 vput(dp); 3363 nfsvno_relpathbuf(&named); 3364 goto out; 3365 } 3366 if (!nd->nd_repstat) { 3367 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3368 } else { 3369 vput(dp); 3370 nfsvno_relpathbuf(&named); 3371 } 3372 if (dirp) 3373 vrele(dirp); 3374 if (nd->nd_repstat) 3375 goto out; 3376 vrele(named.ni_startdir); 3377 nfsvno_relpathbuf(&named); 3378 fh.nfsrvfh_len = NFSX_MYFH; 3379 vp = named.ni_vp; 3380 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3381 vput(vp); 3382 savflag = nd->nd_flag; 3383 if (!nd->nd_repstat) { 3384 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p); 3385 if (vp) 3386 vput(vp); 3387 } 3388 nd->nd_flag = savflag; 3389 if (nd->nd_repstat) 3390 goto out; 3391 3392 /* 3393 * Finally have the export flags for name, so we can create 3394 * the security info. 3395 */ 3396 len = 0; 3397 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3398 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3399 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3400 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3401 *tl = txdr_unsigned(RPCAUTH_UNIX); 3402 len++; 3403 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3404 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3405 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3406 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3407 nfsgss_mechlist[KERBV_MECH].len); 3408 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3409 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3410 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3411 len++; 3412 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3413 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3414 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3415 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3416 nfsgss_mechlist[KERBV_MECH].len); 3417 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3418 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3419 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3420 len++; 3421 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3422 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3423 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3424 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3425 nfsgss_mechlist[KERBV_MECH].len); 3426 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3427 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3428 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3429 len++; 3430 } 3431 } 3432 *sizp = txdr_unsigned(len); 3433 3434 out: 3435 NFSEXITCODE2(error, nd); 3436 return (error); 3437 } 3438 3439 /* 3440 * nfsv4 set client id service 3441 */ 3442 APPLESTATIC int 3443 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3444 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3445 { 3446 u_int32_t *tl; 3447 int i; 3448 int error = 0, idlen; 3449 struct nfsclient *clp = NULL; 3450 struct sockaddr_in *rad; 3451 u_char *verf, *ucp, *ucp2, addrbuf[24]; 3452 nfsquad_t clientid, confirm; 3453 3454 if ((nd->nd_flag & ND_NFSV41) != 0) { 3455 nd->nd_repstat = NFSERR_NOTSUPP; 3456 goto nfsmout; 3457 } 3458 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3459 nd->nd_repstat = NFSERR_WRONGSEC; 3460 goto out; 3461 } 3462 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3463 verf = (u_char *)tl; 3464 tl += (NFSX_VERF / NFSX_UNSIGNED); 3465 i = fxdr_unsigned(int, *tl); 3466 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3467 nd->nd_repstat = NFSERR_BADXDR; 3468 goto nfsmout; 3469 } 3470 idlen = i; 3471 if (nd->nd_flag & ND_GSS) 3472 i += nd->nd_princlen; 3473 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3474 M_ZERO); 3475 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3476 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3477 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3478 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3479 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3480 clp->lc_req.nr_cred = NULL; 3481 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3482 clp->lc_idlen = idlen; 3483 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3484 if (error) 3485 goto nfsmout; 3486 if (nd->nd_flag & ND_GSS) { 3487 clp->lc_flags = LCL_GSS; 3488 if (nd->nd_flag & ND_GSSINTEGRITY) 3489 clp->lc_flags |= LCL_GSSINTEGRITY; 3490 else if (nd->nd_flag & ND_GSSPRIVACY) 3491 clp->lc_flags |= LCL_GSSPRIVACY; 3492 } else { 3493 clp->lc_flags = 0; 3494 } 3495 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 3496 clp->lc_flags |= LCL_NAME; 3497 clp->lc_namelen = nd->nd_princlen; 3498 clp->lc_name = &clp->lc_id[idlen]; 3499 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3500 } else { 3501 clp->lc_uid = nd->nd_cred->cr_uid; 3502 clp->lc_gid = nd->nd_cred->cr_gid; 3503 } 3504 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3505 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 3506 error = nfsrv_getclientipaddr(nd, clp); 3507 if (error) 3508 goto nfsmout; 3509 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3510 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 3511 3512 /* 3513 * nfsrv_setclient() does the actual work of adding it to the 3514 * client list. If there is no error, the structure has been 3515 * linked into the client list and clp should no longer be used 3516 * here. When an error is returned, it has not been linked in, 3517 * so it should be free'd. 3518 */ 3519 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3520 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3521 if (clp->lc_flags & LCL_TCPCALLBACK) 3522 (void) nfsm_strtom(nd, "tcp", 3); 3523 else 3524 (void) nfsm_strtom(nd, "udp", 3); 3525 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3526 ucp = (u_char *)&rad->sin_addr.s_addr; 3527 ucp2 = (u_char *)&rad->sin_port; 3528 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 3529 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 3530 ucp2[0] & 0xff, ucp2[1] & 0xff); 3531 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3532 } 3533 if (clp) { 3534 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3535 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3536 free(clp->lc_stateid, M_NFSDCLIENT); 3537 free(clp, M_NFSDCLIENT); 3538 } 3539 if (!nd->nd_repstat) { 3540 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 3541 *tl++ = clientid.lval[0]; 3542 *tl++ = clientid.lval[1]; 3543 *tl++ = confirm.lval[0]; 3544 *tl = confirm.lval[1]; 3545 } 3546 3547 out: 3548 NFSEXITCODE2(0, nd); 3549 return (0); 3550 nfsmout: 3551 if (clp) { 3552 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3553 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3554 free(clp->lc_stateid, M_NFSDCLIENT); 3555 free(clp, M_NFSDCLIENT); 3556 } 3557 NFSEXITCODE2(error, nd); 3558 return (error); 3559 } 3560 3561 /* 3562 * nfsv4 set client id confirm service 3563 */ 3564 APPLESTATIC int 3565 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3566 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p, 3567 __unused struct nfsexstuff *exp) 3568 { 3569 u_int32_t *tl; 3570 int error = 0; 3571 nfsquad_t clientid, confirm; 3572 3573 if ((nd->nd_flag & ND_NFSV41) != 0) { 3574 nd->nd_repstat = NFSERR_NOTSUPP; 3575 goto nfsmout; 3576 } 3577 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3578 nd->nd_repstat = NFSERR_WRONGSEC; 3579 goto nfsmout; 3580 } 3581 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 3582 clientid.lval[0] = *tl++; 3583 clientid.lval[1] = *tl++; 3584 confirm.lval[0] = *tl++; 3585 confirm.lval[1] = *tl; 3586 3587 /* 3588 * nfsrv_getclient() searches the client list for a match and 3589 * returns the appropriate NFSERR status. 3590 */ 3591 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3592 NULL, NULL, confirm, 0, nd, p); 3593 nfsmout: 3594 NFSEXITCODE2(error, nd); 3595 return (error); 3596 } 3597 3598 /* 3599 * nfsv4 verify service 3600 */ 3601 APPLESTATIC int 3602 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3603 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3604 { 3605 int error = 0, ret, fhsize = NFSX_MYFH; 3606 struct nfsvattr nva; 3607 struct statfs *sf; 3608 struct nfsfsinfo fs; 3609 fhandle_t fh; 3610 3611 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 3612 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 3613 if (!nd->nd_repstat) 3614 nd->nd_repstat = nfsvno_statfs(vp, sf); 3615 if (!nd->nd_repstat) 3616 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3617 if (!nd->nd_repstat) { 3618 nfsvno_getfs(&fs, isdgram); 3619 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 3620 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 3621 if (!error) { 3622 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 3623 if (ret == 0) 3624 nd->nd_repstat = NFSERR_SAME; 3625 else if (ret != NFSERR_NOTSAME) 3626 nd->nd_repstat = ret; 3627 } else if (ret) 3628 nd->nd_repstat = ret; 3629 } 3630 } 3631 vput(vp); 3632 free(sf, M_STATFS); 3633 NFSEXITCODE2(error, nd); 3634 return (error); 3635 } 3636 3637 /* 3638 * nfs openattr rpc 3639 */ 3640 APPLESTATIC int 3641 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 3642 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3643 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3644 { 3645 u_int32_t *tl; 3646 int error = 0, createdir; 3647 3648 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3649 createdir = fxdr_unsigned(int, *tl); 3650 nd->nd_repstat = NFSERR_NOTSUPP; 3651 nfsmout: 3652 vrele(dp); 3653 NFSEXITCODE2(error, nd); 3654 return (error); 3655 } 3656 3657 /* 3658 * nfsv4 release lock owner service 3659 */ 3660 APPLESTATIC int 3661 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 3662 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3663 { 3664 u_int32_t *tl; 3665 struct nfsstate *stp = NULL; 3666 int error = 0, len; 3667 nfsquad_t clientid; 3668 3669 if ((nd->nd_flag & ND_NFSV41) != 0) { 3670 nd->nd_repstat = NFSERR_NOTSUPP; 3671 goto nfsmout; 3672 } 3673 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3674 nd->nd_repstat = NFSERR_WRONGSEC; 3675 goto nfsmout; 3676 } 3677 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3678 len = fxdr_unsigned(int, *(tl + 2)); 3679 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 3680 nd->nd_repstat = NFSERR_BADXDR; 3681 goto nfsmout; 3682 } 3683 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len, 3684 M_NFSDSTATE, M_WAITOK); 3685 stp->ls_ownerlen = len; 3686 stp->ls_op = NULL; 3687 stp->ls_flags = NFSLCK_RELEASE; 3688 stp->ls_uid = nd->nd_cred->cr_uid; 3689 clientid.lval[0] = *tl++; 3690 clientid.lval[1] = *tl; 3691 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3692 if ((nd->nd_flag & ND_NFSV41) != 0) 3693 clientid.qval = nd->nd_clientid.qval; 3694 else if (nd->nd_clientid.qval != clientid.qval) 3695 printf("EEK14 multiple clids\n"); 3696 } else { 3697 if ((nd->nd_flag & ND_NFSV41) != 0) 3698 printf("EEK! no clientid from session\n"); 3699 nd->nd_flag |= ND_IMPLIEDCLID; 3700 nd->nd_clientid.qval = clientid.qval; 3701 } 3702 error = nfsrv_mtostr(nd, stp->ls_owner, len); 3703 if (error) 3704 goto nfsmout; 3705 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 3706 FREE((caddr_t)stp, M_NFSDSTATE); 3707 3708 NFSEXITCODE2(0, nd); 3709 return (0); 3710 nfsmout: 3711 if (stp) 3712 free((caddr_t)stp, M_NFSDSTATE); 3713 NFSEXITCODE2(error, nd); 3714 return (error); 3715 } 3716 3717 /* 3718 * nfsv4 exchange_id service 3719 */ 3720 APPLESTATIC int 3721 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 3722 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3723 { 3724 uint32_t *tl; 3725 int error = 0, i, idlen; 3726 struct nfsclient *clp = NULL; 3727 nfsquad_t clientid, confirm; 3728 uint8_t *verf; 3729 uint32_t sp4type, v41flags; 3730 uint64_t owner_minor; 3731 struct timespec verstime; 3732 3733 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3734 nd->nd_repstat = NFSERR_WRONGSEC; 3735 goto nfsmout; 3736 } 3737 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3738 verf = (uint8_t *)tl; 3739 tl += (NFSX_VERF / NFSX_UNSIGNED); 3740 i = fxdr_unsigned(int, *tl); 3741 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3742 nd->nd_repstat = NFSERR_BADXDR; 3743 goto nfsmout; 3744 } 3745 idlen = i; 3746 if (nd->nd_flag & ND_GSS) 3747 i += nd->nd_princlen; 3748 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3749 M_ZERO); 3750 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3751 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3752 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3753 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3754 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3755 clp->lc_req.nr_cred = NULL; 3756 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3757 clp->lc_idlen = idlen; 3758 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3759 if (error != 0) 3760 goto nfsmout; 3761 if ((nd->nd_flag & ND_GSS) != 0) { 3762 clp->lc_flags = LCL_GSS | LCL_NFSV41; 3763 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 3764 clp->lc_flags |= LCL_GSSINTEGRITY; 3765 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 3766 clp->lc_flags |= LCL_GSSPRIVACY; 3767 } else 3768 clp->lc_flags = LCL_NFSV41; 3769 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 3770 clp->lc_flags |= LCL_NAME; 3771 clp->lc_namelen = nd->nd_princlen; 3772 clp->lc_name = &clp->lc_id[idlen]; 3773 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3774 } else { 3775 clp->lc_uid = nd->nd_cred->cr_uid; 3776 clp->lc_gid = nd->nd_cred->cr_gid; 3777 } 3778 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3779 v41flags = fxdr_unsigned(uint32_t, *tl++); 3780 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 3781 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 3782 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 3783 nd->nd_repstat = NFSERR_INVAL; 3784 goto nfsmout; 3785 } 3786 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 3787 confirm.lval[1] = 1; 3788 else 3789 confirm.lval[1] = 0; 3790 v41flags = NFSV4EXCH_USENONPNFS; 3791 sp4type = fxdr_unsigned(uint32_t, *tl); 3792 if (sp4type != NFSV4EXCH_SP4NONE) { 3793 nd->nd_repstat = NFSERR_NOTSUPP; 3794 goto nfsmout; 3795 } 3796 3797 /* 3798 * nfsrv_setclient() does the actual work of adding it to the 3799 * client list. If there is no error, the structure has been 3800 * linked into the client list and clp should no longer be used 3801 * here. When an error is returned, it has not been linked in, 3802 * so it should be free'd. 3803 */ 3804 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3805 if (clp != NULL) { 3806 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3807 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3808 free(clp->lc_stateid, M_NFSDCLIENT); 3809 free(clp, M_NFSDCLIENT); 3810 } 3811 if (nd->nd_repstat == 0) { 3812 if (confirm.lval[1] != 0) 3813 v41flags |= NFSV4EXCH_CONFIRMEDR; 3814 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 3815 *tl++ = clientid.lval[0]; /* ClientID */ 3816 *tl++ = clientid.lval[1]; 3817 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 3818 *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 3819 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 3820 owner_minor = 0; /* Owner */ 3821 txdr_hyper(owner_minor, tl); /* Minor */ 3822 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 3823 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 3824 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3825 *tl++ = txdr_unsigned(NFSX_UNSIGNED); 3826 *tl++ = time_uptime; /* Make scope a unique value. */ 3827 *tl = txdr_unsigned(1); 3828 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 3829 (void)nfsm_strtom(nd, version, strlen(version)); 3830 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 3831 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 3832 verstime.tv_nsec = 0; 3833 txdr_nfsv4time(&verstime, tl); 3834 } 3835 NFSEXITCODE2(0, nd); 3836 return (0); 3837 nfsmout: 3838 if (clp != NULL) { 3839 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3840 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3841 free(clp->lc_stateid, M_NFSDCLIENT); 3842 free(clp, M_NFSDCLIENT); 3843 } 3844 NFSEXITCODE2(error, nd); 3845 return (error); 3846 } 3847 3848 /* 3849 * nfsv4 create session service 3850 */ 3851 APPLESTATIC int 3852 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 3853 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3854 { 3855 uint32_t *tl; 3856 int error = 0; 3857 nfsquad_t clientid, confirm; 3858 struct nfsdsession *sep = NULL; 3859 uint32_t rdmacnt; 3860 3861 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3862 nd->nd_repstat = NFSERR_WRONGSEC; 3863 goto nfsmout; 3864 } 3865 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 3866 M_NFSDSESSION, M_WAITOK | M_ZERO); 3867 sep->sess_refcnt = 1; 3868 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 3869 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 3870 clientid.lval[0] = *tl++; 3871 clientid.lval[1] = *tl++; 3872 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 3873 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 3874 /* Persistent sessions and RDMA are not supported. */ 3875 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 3876 3877 /* Fore channel attributes. */ 3878 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3879 tl++; /* Header pad always 0. */ 3880 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 3881 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 3882 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 3883 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 3884 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 3885 if (sep->sess_maxslots > NFSV4_SLOTS) 3886 sep->sess_maxslots = NFSV4_SLOTS; 3887 rdmacnt = fxdr_unsigned(uint32_t, *tl); 3888 if (rdmacnt > 1) { 3889 nd->nd_repstat = NFSERR_BADXDR; 3890 goto nfsmout; 3891 } else if (rdmacnt == 1) 3892 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3893 3894 /* Back channel attributes. */ 3895 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3896 tl++; /* Header pad always 0. */ 3897 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 3898 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 3899 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 3900 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 3901 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 3902 rdmacnt = fxdr_unsigned(uint32_t, *tl); 3903 if (rdmacnt > 1) { 3904 nd->nd_repstat = NFSERR_BADXDR; 3905 goto nfsmout; 3906 } else if (rdmacnt == 1) 3907 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3908 3909 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3910 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 3911 3912 /* 3913 * nfsrv_getclient() searches the client list for a match and 3914 * returns the appropriate NFSERR status. 3915 */ 3916 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 3917 NULL, sep, confirm, sep->sess_cbprogram, nd, p); 3918 if (nd->nd_repstat == 0) { 3919 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3920 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 3921 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 3922 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 3923 *tl++ = txdr_unsigned(sep->sess_crflags); 3924 3925 /* Fore channel attributes. */ 3926 *tl++ = 0; 3927 *tl++ = txdr_unsigned(sep->sess_maxreq); 3928 *tl++ = txdr_unsigned(sep->sess_maxresp); 3929 *tl++ = txdr_unsigned(sep->sess_maxrespcached); 3930 *tl++ = txdr_unsigned(sep->sess_maxops); 3931 *tl++ = txdr_unsigned(sep->sess_maxslots); 3932 *tl++ = txdr_unsigned(1); 3933 *tl++ = txdr_unsigned(0); /* No RDMA. */ 3934 3935 /* Back channel attributes. */ 3936 *tl++ = 0; 3937 *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 3938 *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 3939 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 3940 *tl++ = txdr_unsigned(sep->sess_cbmaxops); 3941 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 3942 *tl++ = txdr_unsigned(1); 3943 *tl = txdr_unsigned(0); /* No RDMA. */ 3944 } 3945 nfsmout: 3946 if (nd->nd_repstat != 0 && sep != NULL) 3947 free(sep, M_NFSDSESSION); 3948 NFSEXITCODE2(error, nd); 3949 return (error); 3950 } 3951 3952 /* 3953 * nfsv4 sequence service 3954 */ 3955 APPLESTATIC int 3956 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 3957 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3958 { 3959 uint32_t *tl; 3960 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 3961 int cache_this, error = 0; 3962 3963 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3964 nd->nd_repstat = NFSERR_WRONGSEC; 3965 goto nfsmout; 3966 } 3967 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 3968 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 3969 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 3970 sequenceid = fxdr_unsigned(uint32_t, *tl++); 3971 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 3972 highest_slotid = fxdr_unsigned(uint32_t, *tl++); 3973 if (*tl == newnfs_true) 3974 cache_this = 1; 3975 else 3976 cache_this = 0; 3977 nd->nd_flag |= ND_HASSEQUENCE; 3978 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 3979 &target_highest_slotid, cache_this, &sflags, p); 3980 if (nd->nd_repstat == 0) { 3981 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3982 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 3983 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 3984 *tl++ = txdr_unsigned(sequenceid); 3985 *tl++ = txdr_unsigned(nd->nd_slotid); 3986 *tl++ = txdr_unsigned(highest_slotid); 3987 *tl++ = txdr_unsigned(target_highest_slotid); 3988 *tl = txdr_unsigned(sflags); 3989 } 3990 nfsmout: 3991 NFSEXITCODE2(error, nd); 3992 return (error); 3993 } 3994 3995 /* 3996 * nfsv4 reclaim complete service 3997 */ 3998 APPLESTATIC int 3999 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 4000 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4001 { 4002 uint32_t *tl; 4003 int error = 0; 4004 4005 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4006 nd->nd_repstat = NFSERR_WRONGSEC; 4007 goto nfsmout; 4008 } 4009 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4010 if (*tl == newnfs_true) 4011 nd->nd_repstat = NFSERR_NOTSUPP; 4012 else 4013 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd); 4014 nfsmout: 4015 NFSEXITCODE2(error, nd); 4016 return (error); 4017 } 4018 4019 /* 4020 * nfsv4 destroy clientid service 4021 */ 4022 APPLESTATIC int 4023 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4024 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4025 { 4026 uint32_t *tl; 4027 nfsquad_t clientid; 4028 int error = 0; 4029 4030 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4031 nd->nd_repstat = NFSERR_WRONGSEC; 4032 goto nfsmout; 4033 } 4034 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4035 clientid.lval[0] = *tl++; 4036 clientid.lval[1] = *tl; 4037 nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4038 nfsmout: 4039 NFSEXITCODE2(error, nd); 4040 return (error); 4041 } 4042 4043 /* 4044 * nfsv4 destroy session service 4045 */ 4046 APPLESTATIC int 4047 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4048 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4049 { 4050 uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4051 int error = 0; 4052 4053 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4054 nd->nd_repstat = NFSERR_WRONGSEC; 4055 goto nfsmout; 4056 } 4057 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4058 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4059 nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4060 nfsmout: 4061 NFSEXITCODE2(error, nd); 4062 return (error); 4063 } 4064 4065 /* 4066 * nfsv4 free stateid service 4067 */ 4068 APPLESTATIC int 4069 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4070 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4071 { 4072 uint32_t *tl; 4073 nfsv4stateid_t stateid; 4074 int error = 0; 4075 4076 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4077 nd->nd_repstat = NFSERR_WRONGSEC; 4078 goto nfsmout; 4079 } 4080 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4081 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4082 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4083 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 4084 nfsmout: 4085 NFSEXITCODE2(error, nd); 4086 return (error); 4087 } 4088 4089 /* 4090 * nfsv4 service not supported 4091 */ 4092 APPLESTATIC int 4093 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 4094 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4095 { 4096 4097 nd->nd_repstat = NFSERR_NOTSUPP; 4098 NFSEXITCODE2(0, nd); 4099 return (0); 4100 } 4101 4102