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