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