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