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