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