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