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