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