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