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