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