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_WDCONTENTION) != 0) { 3099 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3100 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 3101 *tl = newnfs_false; 3102 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 3103 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3104 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 3105 *tl = newnfs_false; 3106 } else { 3107 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3108 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3109 } 3110 } else 3111 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 3112 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 3113 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 3114 *tl++ = txdr_unsigned(delegstateid.seqid); 3115 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 3116 NFSX_STATEIDOTHER); 3117 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3118 if (rflags & NFSV4OPEN_RECALL) 3119 *tl = newnfs_true; 3120 else 3121 *tl = newnfs_false; 3122 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 3123 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3124 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 3125 txdr_hyper(nva.na_size, tl); 3126 } 3127 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3128 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 3129 *tl++ = txdr_unsigned(0x0); 3130 acemask = NFSV4ACE_ALLFILESMASK; 3131 if (nva.na_mode & S_IRUSR) 3132 acemask |= NFSV4ACE_READMASK; 3133 if (nva.na_mode & S_IWUSR) 3134 acemask |= NFSV4ACE_WRITEMASK; 3135 if (nva.na_mode & S_IXUSR) 3136 acemask |= NFSV4ACE_EXECUTEMASK; 3137 *tl = txdr_unsigned(acemask); 3138 (void) nfsm_strtom(nd, "OWNER@", 6); 3139 } 3140 *vpp = vp; 3141 } else if (vp) { 3142 vrele(vp); 3143 } 3144 if (dirp) 3145 vrele(dirp); 3146 #ifdef NFS4_ACL_EXTATTR_NAME 3147 acl_free(aclp); 3148 #endif 3149 NFSEXITCODE2(0, nd); 3150 return (0); 3151 nfsmout: 3152 vrele(dp); 3153 #ifdef NFS4_ACL_EXTATTR_NAME 3154 acl_free(aclp); 3155 #endif 3156 if (stp) 3157 free(stp, M_NFSDSTATE); 3158 NFSEXITCODE2(error, nd); 3159 return (error); 3160 } 3161 3162 /* 3163 * nfsv4 close service 3164 */ 3165 APPLESTATIC int 3166 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3167 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3168 { 3169 u_int32_t *tl; 3170 struct nfsstate st, *stp = &st; 3171 int error = 0, writeacc; 3172 nfsv4stateid_t stateid; 3173 nfsquad_t clientid; 3174 struct nfsvattr na; 3175 3176 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 3177 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3178 stp->ls_ownerlen = 0; 3179 stp->ls_op = nd->nd_rp; 3180 stp->ls_uid = nd->nd_cred->cr_uid; 3181 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3182 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3183 NFSX_STATEIDOTHER); 3184 3185 /* 3186 * For the special stateid of other all 0s and seqid == 1, set the 3187 * stateid to the current stateid, if it is set. 3188 */ 3189 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 3190 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 3191 stp->ls_stateid.other[2] == 0) { 3192 if ((nd->nd_flag & ND_CURSTATEID) != 0) 3193 stp->ls_stateid = nd->nd_curstateid; 3194 else { 3195 nd->nd_repstat = NFSERR_BADSTATEID; 3196 goto nfsmout; 3197 } 3198 } 3199 3200 stp->ls_flags = NFSLCK_CLOSE; 3201 clientid.lval[0] = stp->ls_stateid.other[0]; 3202 clientid.lval[1] = stp->ls_stateid.other[1]; 3203 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3204 if ((nd->nd_flag & ND_NFSV41) != 0) 3205 clientid.qval = nd->nd_clientid.qval; 3206 else if (nd->nd_clientid.qval != clientid.qval) 3207 printf("EEK8 multiple clids\n"); 3208 } else { 3209 if ((nd->nd_flag & ND_NFSV41) != 0) 3210 printf("EEK! no clientid from session\n"); 3211 nd->nd_flag |= ND_IMPLIEDCLID; 3212 nd->nd_clientid.qval = clientid.qval; 3213 } 3214 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 3215 &writeacc); 3216 /* For pNFS, update the attributes. */ 3217 if (writeacc != 0 || nfsrv_pnfsatime != 0) 3218 nfsrv_updatemdsattr(vp, &na, p); 3219 vput(vp); 3220 if (!nd->nd_repstat) { 3221 /* 3222 * If the stateid that has been closed is the current stateid, 3223 * unset it. 3224 */ 3225 if ((nd->nd_flag & ND_CURSTATEID) != 0 && 3226 stateid.other[0] == nd->nd_curstateid.other[0] && 3227 stateid.other[1] == nd->nd_curstateid.other[1] && 3228 stateid.other[2] == nd->nd_curstateid.other[2]) 3229 nd->nd_flag &= ~ND_CURSTATEID; 3230 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3231 *tl++ = txdr_unsigned(stateid.seqid); 3232 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3233 } 3234 NFSEXITCODE2(0, nd); 3235 return (0); 3236 nfsmout: 3237 vput(vp); 3238 NFSEXITCODE2(error, nd); 3239 return (error); 3240 } 3241 3242 /* 3243 * nfsv4 delegpurge service 3244 */ 3245 APPLESTATIC int 3246 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3247 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3248 { 3249 u_int32_t *tl; 3250 int error = 0; 3251 nfsquad_t clientid; 3252 3253 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3254 nd->nd_repstat = NFSERR_WRONGSEC; 3255 goto nfsmout; 3256 } 3257 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3258 clientid.lval[0] = *tl++; 3259 clientid.lval[1] = *tl; 3260 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3261 if ((nd->nd_flag & ND_NFSV41) != 0) 3262 clientid.qval = nd->nd_clientid.qval; 3263 else if (nd->nd_clientid.qval != clientid.qval) 3264 printf("EEK9 multiple clids\n"); 3265 } else { 3266 if ((nd->nd_flag & ND_NFSV41) != 0) 3267 printf("EEK! no clientid from session\n"); 3268 nd->nd_flag |= ND_IMPLIEDCLID; 3269 nd->nd_clientid.qval = clientid.qval; 3270 } 3271 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 3272 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL); 3273 nfsmout: 3274 NFSEXITCODE2(error, nd); 3275 return (error); 3276 } 3277 3278 /* 3279 * nfsv4 delegreturn service 3280 */ 3281 APPLESTATIC int 3282 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3283 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3284 { 3285 u_int32_t *tl; 3286 int error = 0, writeacc; 3287 nfsv4stateid_t stateid; 3288 nfsquad_t clientid; 3289 struct nfsvattr na; 3290 3291 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3292 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3293 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 3294 clientid.lval[0] = stateid.other[0]; 3295 clientid.lval[1] = stateid.other[1]; 3296 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3297 if ((nd->nd_flag & ND_NFSV41) != 0) 3298 clientid.qval = nd->nd_clientid.qval; 3299 else if (nd->nd_clientid.qval != clientid.qval) 3300 printf("EEK10 multiple clids\n"); 3301 } else { 3302 if ((nd->nd_flag & ND_NFSV41) != 0) 3303 printf("EEK! no clientid from session\n"); 3304 nd->nd_flag |= ND_IMPLIEDCLID; 3305 nd->nd_clientid.qval = clientid.qval; 3306 } 3307 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 3308 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc); 3309 /* For pNFS, update the attributes. */ 3310 if (writeacc != 0 || nfsrv_pnfsatime != 0) 3311 nfsrv_updatemdsattr(vp, &na, p); 3312 nfsmout: 3313 vput(vp); 3314 NFSEXITCODE2(error, nd); 3315 return (error); 3316 } 3317 3318 /* 3319 * nfsv4 get file handle service 3320 */ 3321 APPLESTATIC int 3322 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3323 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3324 { 3325 fhandle_t fh; 3326 3327 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3328 vput(vp); 3329 if (!nd->nd_repstat) 3330 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3331 NFSEXITCODE2(0, nd); 3332 return (0); 3333 } 3334 3335 /* 3336 * nfsv4 open confirm service 3337 */ 3338 APPLESTATIC int 3339 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3340 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3341 { 3342 u_int32_t *tl; 3343 struct nfsstate st, *stp = &st; 3344 int error = 0; 3345 nfsv4stateid_t stateid; 3346 nfsquad_t clientid; 3347 3348 if ((nd->nd_flag & ND_NFSV41) != 0) { 3349 nd->nd_repstat = NFSERR_NOTSUPP; 3350 goto nfsmout; 3351 } 3352 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3353 stp->ls_ownerlen = 0; 3354 stp->ls_op = nd->nd_rp; 3355 stp->ls_uid = nd->nd_cred->cr_uid; 3356 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3357 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3358 NFSX_STATEIDOTHER); 3359 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3360 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 3361 stp->ls_flags = NFSLCK_CONFIRM; 3362 clientid.lval[0] = stp->ls_stateid.other[0]; 3363 clientid.lval[1] = stp->ls_stateid.other[1]; 3364 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3365 if ((nd->nd_flag & ND_NFSV41) != 0) 3366 clientid.qval = nd->nd_clientid.qval; 3367 else if (nd->nd_clientid.qval != clientid.qval) 3368 printf("EEK11 multiple clids\n"); 3369 } else { 3370 if ((nd->nd_flag & ND_NFSV41) != 0) 3371 printf("EEK! no clientid from session\n"); 3372 nd->nd_flag |= ND_IMPLIEDCLID; 3373 nd->nd_clientid.qval = clientid.qval; 3374 } 3375 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 3376 NULL); 3377 if (!nd->nd_repstat) { 3378 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3379 *tl++ = txdr_unsigned(stateid.seqid); 3380 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3381 } 3382 nfsmout: 3383 vput(vp); 3384 NFSEXITCODE2(error, nd); 3385 return (error); 3386 } 3387 3388 /* 3389 * nfsv4 open downgrade service 3390 */ 3391 APPLESTATIC int 3392 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3393 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3394 { 3395 u_int32_t *tl; 3396 int i; 3397 struct nfsstate st, *stp = &st; 3398 int error = 0; 3399 nfsv4stateid_t stateid; 3400 nfsquad_t clientid; 3401 3402 /* opendowngrade can only work on a file object.*/ 3403 if (vp->v_type != VREG) { 3404 error = NFSERR_INVAL; 3405 goto nfsmout; 3406 } 3407 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 3408 stp->ls_ownerlen = 0; 3409 stp->ls_op = nd->nd_rp; 3410 stp->ls_uid = nd->nd_cred->cr_uid; 3411 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3412 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3413 NFSX_STATEIDOTHER); 3414 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3415 3416 /* 3417 * For the special stateid of other all 0s and seqid == 1, set the 3418 * stateid to the current stateid, if it is set. 3419 */ 3420 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 3421 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 3422 stp->ls_stateid.other[2] == 0) { 3423 if ((nd->nd_flag & ND_CURSTATEID) != 0) 3424 stp->ls_stateid = nd->nd_curstateid; 3425 else { 3426 nd->nd_repstat = NFSERR_BADSTATEID; 3427 goto nfsmout; 3428 } 3429 } 3430 3431 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3432 i = fxdr_unsigned(int, *tl++); 3433 if ((nd->nd_flag & ND_NFSV41) != 0) 3434 i &= ~NFSV4OPEN_WANTDELEGMASK; 3435 switch (i) { 3436 case NFSV4OPEN_ACCESSREAD: 3437 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3438 break; 3439 case NFSV4OPEN_ACCESSWRITE: 3440 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3441 break; 3442 case NFSV4OPEN_ACCESSBOTH: 3443 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3444 NFSLCK_DOWNGRADE); 3445 break; 3446 default: 3447 nd->nd_repstat = NFSERR_INVAL; 3448 } 3449 i = fxdr_unsigned(int, *tl); 3450 switch (i) { 3451 case NFSV4OPEN_DENYNONE: 3452 break; 3453 case NFSV4OPEN_DENYREAD: 3454 stp->ls_flags |= NFSLCK_READDENY; 3455 break; 3456 case NFSV4OPEN_DENYWRITE: 3457 stp->ls_flags |= NFSLCK_WRITEDENY; 3458 break; 3459 case NFSV4OPEN_DENYBOTH: 3460 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3461 break; 3462 default: 3463 nd->nd_repstat = NFSERR_INVAL; 3464 } 3465 3466 clientid.lval[0] = stp->ls_stateid.other[0]; 3467 clientid.lval[1] = stp->ls_stateid.other[1]; 3468 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3469 if ((nd->nd_flag & ND_NFSV41) != 0) 3470 clientid.qval = nd->nd_clientid.qval; 3471 else if (nd->nd_clientid.qval != clientid.qval) 3472 printf("EEK12 multiple clids\n"); 3473 } else { 3474 if ((nd->nd_flag & ND_NFSV41) != 0) 3475 printf("EEK! no clientid from session\n"); 3476 nd->nd_flag |= ND_IMPLIEDCLID; 3477 nd->nd_clientid.qval = clientid.qval; 3478 } 3479 if (!nd->nd_repstat) 3480 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3481 nd, p, NULL); 3482 if (!nd->nd_repstat) { 3483 /* For NFSv4.1, set the Current StateID. */ 3484 if ((nd->nd_flag & ND_NFSV41) != 0) { 3485 nd->nd_curstateid = stateid; 3486 nd->nd_flag |= ND_CURSTATEID; 3487 } 3488 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3489 *tl++ = txdr_unsigned(stateid.seqid); 3490 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3491 } 3492 nfsmout: 3493 vput(vp); 3494 NFSEXITCODE2(error, nd); 3495 return (error); 3496 } 3497 3498 /* 3499 * nfsv4 renew lease service 3500 */ 3501 APPLESTATIC int 3502 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3503 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3504 { 3505 u_int32_t *tl; 3506 int error = 0; 3507 nfsquad_t clientid; 3508 3509 if ((nd->nd_flag & ND_NFSV41) != 0) { 3510 nd->nd_repstat = NFSERR_NOTSUPP; 3511 goto nfsmout; 3512 } 3513 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3514 nd->nd_repstat = NFSERR_WRONGSEC; 3515 goto nfsmout; 3516 } 3517 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3518 clientid.lval[0] = *tl++; 3519 clientid.lval[1] = *tl; 3520 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3521 if ((nd->nd_flag & ND_NFSV41) != 0) 3522 clientid.qval = nd->nd_clientid.qval; 3523 else if (nd->nd_clientid.qval != clientid.qval) 3524 printf("EEK13 multiple clids\n"); 3525 } else { 3526 if ((nd->nd_flag & ND_NFSV41) != 0) 3527 printf("EEK! no clientid from session\n"); 3528 nd->nd_flag |= ND_IMPLIEDCLID; 3529 nd->nd_clientid.qval = clientid.qval; 3530 } 3531 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3532 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 3533 nfsmout: 3534 NFSEXITCODE2(error, nd); 3535 return (error); 3536 } 3537 3538 /* 3539 * nfsv4 security info service 3540 */ 3541 APPLESTATIC int 3542 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3543 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 3544 { 3545 u_int32_t *tl; 3546 int len; 3547 struct nameidata named; 3548 vnode_t dirp = NULL, vp; 3549 struct nfsrvfh fh; 3550 struct nfsexstuff retnes; 3551 u_int32_t *sizp; 3552 int error = 0, savflag, i; 3553 char *bufp; 3554 u_long *hashp; 3555 3556 /* 3557 * All this just to get the export flags for the name. 3558 */ 3559 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3560 LOCKLEAF | SAVESTART); 3561 nfsvno_setpathbuf(&named, &bufp, &hashp); 3562 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3563 if (error) { 3564 vput(dp); 3565 nfsvno_relpathbuf(&named); 3566 goto out; 3567 } 3568 if (!nd->nd_repstat) { 3569 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3570 } else { 3571 vput(dp); 3572 nfsvno_relpathbuf(&named); 3573 } 3574 if (dirp) 3575 vrele(dirp); 3576 if (nd->nd_repstat) 3577 goto out; 3578 vrele(named.ni_startdir); 3579 nfsvno_relpathbuf(&named); 3580 fh.nfsrvfh_len = NFSX_MYFH; 3581 vp = named.ni_vp; 3582 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3583 vput(vp); 3584 savflag = nd->nd_flag; 3585 if (!nd->nd_repstat) { 3586 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p); 3587 if (vp) 3588 vput(vp); 3589 } 3590 nd->nd_flag = savflag; 3591 if (nd->nd_repstat) 3592 goto out; 3593 3594 /* 3595 * Finally have the export flags for name, so we can create 3596 * the security info. 3597 */ 3598 len = 0; 3599 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3600 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3601 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3602 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3603 *tl = txdr_unsigned(RPCAUTH_UNIX); 3604 len++; 3605 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3606 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3607 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3608 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3609 nfsgss_mechlist[KERBV_MECH].len); 3610 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3611 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3612 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3613 len++; 3614 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3615 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3616 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3617 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3618 nfsgss_mechlist[KERBV_MECH].len); 3619 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3620 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3621 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3622 len++; 3623 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3624 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3625 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3626 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3627 nfsgss_mechlist[KERBV_MECH].len); 3628 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3629 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3630 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3631 len++; 3632 } 3633 } 3634 *sizp = txdr_unsigned(len); 3635 3636 out: 3637 NFSEXITCODE2(error, nd); 3638 return (error); 3639 } 3640 3641 /* 3642 * nfsv4 set client id service 3643 */ 3644 APPLESTATIC int 3645 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3646 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3647 { 3648 u_int32_t *tl; 3649 int i; 3650 int error = 0, idlen; 3651 struct nfsclient *clp = NULL; 3652 struct sockaddr_in *rad; 3653 u_char *verf, *ucp, *ucp2, addrbuf[24]; 3654 nfsquad_t clientid, confirm; 3655 3656 if ((nd->nd_flag & ND_NFSV41) != 0) { 3657 nd->nd_repstat = NFSERR_NOTSUPP; 3658 goto nfsmout; 3659 } 3660 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3661 nd->nd_repstat = NFSERR_WRONGSEC; 3662 goto out; 3663 } 3664 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3665 verf = (u_char *)tl; 3666 tl += (NFSX_VERF / NFSX_UNSIGNED); 3667 i = fxdr_unsigned(int, *tl); 3668 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3669 nd->nd_repstat = NFSERR_BADXDR; 3670 goto nfsmout; 3671 } 3672 idlen = i; 3673 if (nd->nd_flag & ND_GSS) 3674 i += nd->nd_princlen; 3675 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3676 M_ZERO); 3677 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3678 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3679 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3680 clp->lc_req.nr_nam = malloc(sizeof(*clp->lc_req.nr_nam), M_SONAME, 3681 M_WAITOK | M_ZERO); 3682 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3683 clp->lc_req.nr_cred = NULL; 3684 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3685 clp->lc_idlen = idlen; 3686 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3687 if (error) 3688 goto nfsmout; 3689 if (nd->nd_flag & ND_GSS) { 3690 clp->lc_flags = LCL_GSS; 3691 if (nd->nd_flag & ND_GSSINTEGRITY) 3692 clp->lc_flags |= LCL_GSSINTEGRITY; 3693 else if (nd->nd_flag & ND_GSSPRIVACY) 3694 clp->lc_flags |= LCL_GSSPRIVACY; 3695 } else { 3696 clp->lc_flags = 0; 3697 } 3698 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 3699 clp->lc_flags |= LCL_NAME; 3700 clp->lc_namelen = nd->nd_princlen; 3701 clp->lc_name = &clp->lc_id[idlen]; 3702 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3703 } else { 3704 clp->lc_uid = nd->nd_cred->cr_uid; 3705 clp->lc_gid = nd->nd_cred->cr_gid; 3706 } 3707 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3708 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 3709 error = nfsrv_getclientipaddr(nd, clp); 3710 if (error) 3711 goto nfsmout; 3712 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3713 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 3714 3715 /* 3716 * nfsrv_setclient() does the actual work of adding it to the 3717 * client list. If there is no error, the structure has been 3718 * linked into the client list and clp should no longer be used 3719 * here. When an error is returned, it has not been linked in, 3720 * so it should be free'd. 3721 */ 3722 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3723 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3724 if (clp->lc_flags & LCL_TCPCALLBACK) 3725 (void) nfsm_strtom(nd, "tcp", 3); 3726 else 3727 (void) nfsm_strtom(nd, "udp", 3); 3728 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3729 ucp = (u_char *)&rad->sin_addr.s_addr; 3730 ucp2 = (u_char *)&rad->sin_port; 3731 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 3732 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 3733 ucp2[0] & 0xff, ucp2[1] & 0xff); 3734 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3735 } 3736 if (clp) { 3737 free(clp->lc_req.nr_nam, M_SONAME); 3738 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3739 free(clp->lc_stateid, M_NFSDCLIENT); 3740 free(clp, M_NFSDCLIENT); 3741 } 3742 if (!nd->nd_repstat) { 3743 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 3744 *tl++ = clientid.lval[0]; 3745 *tl++ = clientid.lval[1]; 3746 *tl++ = confirm.lval[0]; 3747 *tl = confirm.lval[1]; 3748 } 3749 3750 out: 3751 NFSEXITCODE2(0, nd); 3752 return (0); 3753 nfsmout: 3754 if (clp) { 3755 free(clp->lc_req.nr_nam, M_SONAME); 3756 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3757 free(clp->lc_stateid, M_NFSDCLIENT); 3758 free(clp, M_NFSDCLIENT); 3759 } 3760 NFSEXITCODE2(error, nd); 3761 return (error); 3762 } 3763 3764 /* 3765 * nfsv4 set client id confirm service 3766 */ 3767 APPLESTATIC int 3768 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3769 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p, 3770 __unused struct nfsexstuff *exp) 3771 { 3772 u_int32_t *tl; 3773 int error = 0; 3774 nfsquad_t clientid, confirm; 3775 3776 if ((nd->nd_flag & ND_NFSV41) != 0) { 3777 nd->nd_repstat = NFSERR_NOTSUPP; 3778 goto nfsmout; 3779 } 3780 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3781 nd->nd_repstat = NFSERR_WRONGSEC; 3782 goto nfsmout; 3783 } 3784 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 3785 clientid.lval[0] = *tl++; 3786 clientid.lval[1] = *tl++; 3787 confirm.lval[0] = *tl++; 3788 confirm.lval[1] = *tl; 3789 3790 /* 3791 * nfsrv_getclient() searches the client list for a match and 3792 * returns the appropriate NFSERR status. 3793 */ 3794 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3795 NULL, NULL, confirm, 0, nd, p); 3796 nfsmout: 3797 NFSEXITCODE2(error, nd); 3798 return (error); 3799 } 3800 3801 /* 3802 * nfsv4 verify service 3803 */ 3804 APPLESTATIC int 3805 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3806 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3807 { 3808 int error = 0, ret, fhsize = NFSX_MYFH; 3809 struct nfsvattr nva; 3810 struct statfs *sf; 3811 struct nfsfsinfo fs; 3812 fhandle_t fh; 3813 3814 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 3815 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 3816 if (!nd->nd_repstat) 3817 nd->nd_repstat = nfsvno_statfs(vp, sf); 3818 if (!nd->nd_repstat) 3819 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3820 if (!nd->nd_repstat) { 3821 nfsvno_getfs(&fs, isdgram); 3822 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 3823 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 3824 if (!error) { 3825 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 3826 if (ret == 0) 3827 nd->nd_repstat = NFSERR_SAME; 3828 else if (ret != NFSERR_NOTSAME) 3829 nd->nd_repstat = ret; 3830 } else if (ret) 3831 nd->nd_repstat = ret; 3832 } 3833 } 3834 vput(vp); 3835 free(sf, M_STATFS); 3836 NFSEXITCODE2(error, nd); 3837 return (error); 3838 } 3839 3840 /* 3841 * nfs openattr rpc 3842 */ 3843 APPLESTATIC int 3844 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 3845 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3846 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3847 { 3848 u_int32_t *tl; 3849 int error = 0, createdir; 3850 3851 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3852 createdir = fxdr_unsigned(int, *tl); 3853 nd->nd_repstat = NFSERR_NOTSUPP; 3854 nfsmout: 3855 vrele(dp); 3856 NFSEXITCODE2(error, nd); 3857 return (error); 3858 } 3859 3860 /* 3861 * nfsv4 release lock owner service 3862 */ 3863 APPLESTATIC int 3864 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 3865 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3866 { 3867 u_int32_t *tl; 3868 struct nfsstate *stp = NULL; 3869 int error = 0, len; 3870 nfsquad_t clientid; 3871 3872 if ((nd->nd_flag & ND_NFSV41) != 0) { 3873 nd->nd_repstat = NFSERR_NOTSUPP; 3874 goto nfsmout; 3875 } 3876 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3877 nd->nd_repstat = NFSERR_WRONGSEC; 3878 goto nfsmout; 3879 } 3880 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3881 len = fxdr_unsigned(int, *(tl + 2)); 3882 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 3883 nd->nd_repstat = NFSERR_BADXDR; 3884 goto nfsmout; 3885 } 3886 stp = malloc(sizeof (struct nfsstate) + len, 3887 M_NFSDSTATE, M_WAITOK); 3888 stp->ls_ownerlen = len; 3889 stp->ls_op = NULL; 3890 stp->ls_flags = NFSLCK_RELEASE; 3891 stp->ls_uid = nd->nd_cred->cr_uid; 3892 clientid.lval[0] = *tl++; 3893 clientid.lval[1] = *tl; 3894 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3895 if ((nd->nd_flag & ND_NFSV41) != 0) 3896 clientid.qval = nd->nd_clientid.qval; 3897 else if (nd->nd_clientid.qval != clientid.qval) 3898 printf("EEK14 multiple clids\n"); 3899 } else { 3900 if ((nd->nd_flag & ND_NFSV41) != 0) 3901 printf("EEK! no clientid from session\n"); 3902 nd->nd_flag |= ND_IMPLIEDCLID; 3903 nd->nd_clientid.qval = clientid.qval; 3904 } 3905 error = nfsrv_mtostr(nd, stp->ls_owner, len); 3906 if (error) 3907 goto nfsmout; 3908 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 3909 free(stp, M_NFSDSTATE); 3910 3911 NFSEXITCODE2(0, nd); 3912 return (0); 3913 nfsmout: 3914 if (stp) 3915 free(stp, M_NFSDSTATE); 3916 NFSEXITCODE2(error, nd); 3917 return (error); 3918 } 3919 3920 /* 3921 * nfsv4 exchange_id service 3922 */ 3923 APPLESTATIC int 3924 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 3925 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3926 { 3927 uint32_t *tl; 3928 int error = 0, i, idlen; 3929 struct nfsclient *clp = NULL; 3930 nfsquad_t clientid, confirm; 3931 uint8_t *verf; 3932 uint32_t sp4type, v41flags; 3933 uint64_t owner_minor; 3934 struct timespec verstime; 3935 struct sockaddr_in *sad, *rad; 3936 3937 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3938 nd->nd_repstat = NFSERR_WRONGSEC; 3939 goto nfsmout; 3940 } 3941 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3942 verf = (uint8_t *)tl; 3943 tl += (NFSX_VERF / NFSX_UNSIGNED); 3944 i = fxdr_unsigned(int, *tl); 3945 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3946 nd->nd_repstat = NFSERR_BADXDR; 3947 goto nfsmout; 3948 } 3949 idlen = i; 3950 if (nd->nd_flag & ND_GSS) 3951 i += nd->nd_princlen; 3952 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3953 M_ZERO); 3954 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3955 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3956 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3957 clp->lc_req.nr_nam = malloc(sizeof(*clp->lc_req.nr_nam), M_SONAME, 3958 M_WAITOK | M_ZERO); 3959 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3960 sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *); 3961 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3962 rad->sin_family = AF_INET; 3963 rad->sin_addr.s_addr = 0; 3964 rad->sin_port = 0; 3965 if (sad->sin_family == AF_INET) 3966 rad->sin_addr.s_addr = sad->sin_addr.s_addr; 3967 clp->lc_req.nr_cred = NULL; 3968 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3969 clp->lc_idlen = idlen; 3970 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3971 if (error != 0) 3972 goto nfsmout; 3973 if ((nd->nd_flag & ND_GSS) != 0) { 3974 clp->lc_flags = LCL_GSS | LCL_NFSV41; 3975 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 3976 clp->lc_flags |= LCL_GSSINTEGRITY; 3977 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 3978 clp->lc_flags |= LCL_GSSPRIVACY; 3979 } else 3980 clp->lc_flags = LCL_NFSV41; 3981 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 3982 clp->lc_flags |= LCL_NAME; 3983 clp->lc_namelen = nd->nd_princlen; 3984 clp->lc_name = &clp->lc_id[idlen]; 3985 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3986 } else { 3987 clp->lc_uid = nd->nd_cred->cr_uid; 3988 clp->lc_gid = nd->nd_cred->cr_gid; 3989 } 3990 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3991 v41flags = fxdr_unsigned(uint32_t, *tl++); 3992 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 3993 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 3994 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 3995 nd->nd_repstat = NFSERR_INVAL; 3996 goto nfsmout; 3997 } 3998 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 3999 confirm.lval[1] = 1; 4000 else 4001 confirm.lval[1] = 0; 4002 if (nfsrv_devidcnt == 0) 4003 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS; 4004 else 4005 v41flags = NFSV4EXCH_USEPNFSMDS; 4006 sp4type = fxdr_unsigned(uint32_t, *tl); 4007 if (sp4type != NFSV4EXCH_SP4NONE) { 4008 nd->nd_repstat = NFSERR_NOTSUPP; 4009 goto nfsmout; 4010 } 4011 4012 /* 4013 * nfsrv_setclient() does the actual work of adding it to the 4014 * client list. If there is no error, the structure has been 4015 * linked into the client list and clp should no longer be used 4016 * here. When an error is returned, it has not been linked in, 4017 * so it should be free'd. 4018 */ 4019 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 4020 if (clp != NULL) { 4021 free(clp->lc_req.nr_nam, M_SONAME); 4022 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4023 free(clp->lc_stateid, M_NFSDCLIENT); 4024 free(clp, M_NFSDCLIENT); 4025 } 4026 if (nd->nd_repstat == 0) { 4027 if (confirm.lval[1] != 0) 4028 v41flags |= NFSV4EXCH_CONFIRMEDR; 4029 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 4030 *tl++ = clientid.lval[0]; /* ClientID */ 4031 *tl++ = clientid.lval[1]; 4032 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 4033 *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 4034 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 4035 owner_minor = 0; /* Owner */ 4036 txdr_hyper(owner_minor, tl); /* Minor */ 4037 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 4038 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 4039 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 4040 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */ 4041 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4042 *tl = txdr_unsigned(1); 4043 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4044 (void)nfsm_strtom(nd, version, strlen(version)); 4045 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4046 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4047 verstime.tv_nsec = 0; 4048 txdr_nfsv4time(&verstime, tl); 4049 } 4050 NFSEXITCODE2(0, nd); 4051 return (0); 4052 nfsmout: 4053 if (clp != NULL) { 4054 free(clp->lc_req.nr_nam, M_SONAME); 4055 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4056 free(clp->lc_stateid, M_NFSDCLIENT); 4057 free(clp, M_NFSDCLIENT); 4058 } 4059 NFSEXITCODE2(error, nd); 4060 return (error); 4061 } 4062 4063 /* 4064 * nfsv4 create session service 4065 */ 4066 APPLESTATIC int 4067 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 4068 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4069 { 4070 uint32_t *tl; 4071 int error = 0; 4072 nfsquad_t clientid, confirm; 4073 struct nfsdsession *sep = NULL; 4074 uint32_t rdmacnt; 4075 4076 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4077 nd->nd_repstat = NFSERR_WRONGSEC; 4078 goto nfsmout; 4079 } 4080 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 4081 M_NFSDSESSION, M_WAITOK | M_ZERO); 4082 sep->sess_refcnt = 1; 4083 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 4084 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 4085 clientid.lval[0] = *tl++; 4086 clientid.lval[1] = *tl++; 4087 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 4088 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 4089 /* Persistent sessions and RDMA are not supported. */ 4090 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 4091 4092 /* Fore channel attributes. */ 4093 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4094 tl++; /* Header pad always 0. */ 4095 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 4096 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) { 4097 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR; 4098 printf("Consider increasing kern.ipc.maxsockbuf\n"); 4099 } 4100 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 4101 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) { 4102 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR; 4103 printf("Consider increasing kern.ipc.maxsockbuf\n"); 4104 } 4105 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 4106 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 4107 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 4108 if (sep->sess_maxslots > NFSV4_SLOTS) 4109 sep->sess_maxslots = NFSV4_SLOTS; 4110 rdmacnt = fxdr_unsigned(uint32_t, *tl); 4111 if (rdmacnt > 1) { 4112 nd->nd_repstat = NFSERR_BADXDR; 4113 goto nfsmout; 4114 } else if (rdmacnt == 1) 4115 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4116 4117 /* Back channel attributes. */ 4118 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4119 tl++; /* Header pad always 0. */ 4120 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 4121 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 4122 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 4123 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 4124 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 4125 rdmacnt = fxdr_unsigned(uint32_t, *tl); 4126 if (rdmacnt > 1) { 4127 nd->nd_repstat = NFSERR_BADXDR; 4128 goto nfsmout; 4129 } else if (rdmacnt == 1) 4130 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4131 4132 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4133 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 4134 4135 /* 4136 * nfsrv_getclient() searches the client list for a match and 4137 * returns the appropriate NFSERR status. 4138 */ 4139 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 4140 NULL, sep, confirm, sep->sess_cbprogram, nd, p); 4141 if (nd->nd_repstat == 0) { 4142 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4143 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 4144 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 4145 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 4146 *tl++ = txdr_unsigned(sep->sess_crflags); 4147 4148 /* Fore channel attributes. */ 4149 *tl++ = 0; 4150 *tl++ = txdr_unsigned(sep->sess_maxreq); 4151 *tl++ = txdr_unsigned(sep->sess_maxresp); 4152 *tl++ = txdr_unsigned(sep->sess_maxrespcached); 4153 *tl++ = txdr_unsigned(sep->sess_maxops); 4154 *tl++ = txdr_unsigned(sep->sess_maxslots); 4155 *tl++ = txdr_unsigned(1); 4156 *tl++ = txdr_unsigned(0); /* No RDMA. */ 4157 4158 /* Back channel attributes. */ 4159 *tl++ = 0; 4160 *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 4161 *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 4162 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 4163 *tl++ = txdr_unsigned(sep->sess_cbmaxops); 4164 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 4165 *tl++ = txdr_unsigned(1); 4166 *tl = txdr_unsigned(0); /* No RDMA. */ 4167 } 4168 nfsmout: 4169 if (nd->nd_repstat != 0 && sep != NULL) 4170 free(sep, M_NFSDSESSION); 4171 NFSEXITCODE2(error, nd); 4172 return (error); 4173 } 4174 4175 /* 4176 * nfsv4 sequence service 4177 */ 4178 APPLESTATIC int 4179 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 4180 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4181 { 4182 uint32_t *tl; 4183 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 4184 int cache_this, error = 0; 4185 4186 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4187 nd->nd_repstat = NFSERR_WRONGSEC; 4188 goto nfsmout; 4189 } 4190 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 4191 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 4192 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4193 sequenceid = fxdr_unsigned(uint32_t, *tl++); 4194 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 4195 highest_slotid = fxdr_unsigned(uint32_t, *tl++); 4196 if (*tl == newnfs_true) 4197 cache_this = 1; 4198 else 4199 cache_this = 0; 4200 nd->nd_flag |= ND_HASSEQUENCE; 4201 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 4202 &target_highest_slotid, cache_this, &sflags, p); 4203 if (nd->nd_repstat == 0) { 4204 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4205 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 4206 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 4207 *tl++ = txdr_unsigned(sequenceid); 4208 *tl++ = txdr_unsigned(nd->nd_slotid); 4209 *tl++ = txdr_unsigned(highest_slotid); 4210 *tl++ = txdr_unsigned(target_highest_slotid); 4211 *tl = txdr_unsigned(sflags); 4212 } 4213 nfsmout: 4214 NFSEXITCODE2(error, nd); 4215 return (error); 4216 } 4217 4218 /* 4219 * nfsv4 reclaim complete service 4220 */ 4221 APPLESTATIC int 4222 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 4223 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4224 { 4225 uint32_t *tl; 4226 int error = 0; 4227 4228 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4229 nd->nd_repstat = NFSERR_WRONGSEC; 4230 goto nfsmout; 4231 } 4232 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4233 if (*tl == newnfs_true) 4234 nd->nd_repstat = NFSERR_NOTSUPP; 4235 else 4236 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd); 4237 nfsmout: 4238 NFSEXITCODE2(error, nd); 4239 return (error); 4240 } 4241 4242 /* 4243 * nfsv4 destroy clientid service 4244 */ 4245 APPLESTATIC int 4246 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4247 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4248 { 4249 uint32_t *tl; 4250 nfsquad_t clientid; 4251 int error = 0; 4252 4253 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4254 nd->nd_repstat = NFSERR_WRONGSEC; 4255 goto nfsmout; 4256 } 4257 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4258 clientid.lval[0] = *tl++; 4259 clientid.lval[1] = *tl; 4260 nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4261 nfsmout: 4262 NFSEXITCODE2(error, nd); 4263 return (error); 4264 } 4265 4266 /* 4267 * nfsv4 bind connection to session service 4268 */ 4269 APPLESTATIC int 4270 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram, 4271 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4272 { 4273 uint32_t *tl; 4274 uint8_t sessid[NFSX_V4SESSIONID]; 4275 int error = 0, foreaft; 4276 4277 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4278 nd->nd_repstat = NFSERR_WRONGSEC; 4279 goto nfsmout; 4280 } 4281 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 4282 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID); 4283 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4284 foreaft = fxdr_unsigned(int, *tl++); 4285 if (*tl == newnfs_true) { 4286 /* RDMA is not supported. */ 4287 nd->nd_repstat = NFSERR_NOTSUPP; 4288 goto nfsmout; 4289 } 4290 4291 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft); 4292 if (nd->nd_repstat == 0) { 4293 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * 4294 NFSX_UNSIGNED); 4295 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID); 4296 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4297 *tl++ = txdr_unsigned(foreaft); 4298 *tl = newnfs_false; 4299 } 4300 nfsmout: 4301 NFSEXITCODE2(error, nd); 4302 return (error); 4303 } 4304 4305 /* 4306 * nfsv4 destroy session service 4307 */ 4308 APPLESTATIC int 4309 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4310 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4311 { 4312 uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4313 int error = 0; 4314 4315 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4316 nd->nd_repstat = NFSERR_WRONGSEC; 4317 goto nfsmout; 4318 } 4319 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4320 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4321 nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4322 nfsmout: 4323 NFSEXITCODE2(error, nd); 4324 return (error); 4325 } 4326 4327 /* 4328 * nfsv4 free stateid service 4329 */ 4330 APPLESTATIC int 4331 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4332 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4333 { 4334 uint32_t *tl; 4335 nfsv4stateid_t stateid; 4336 int error = 0; 4337 4338 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4339 nd->nd_repstat = NFSERR_WRONGSEC; 4340 goto nfsmout; 4341 } 4342 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4343 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4344 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4345 4346 /* 4347 * For the special stateid of other all 0s and seqid == 1, set the 4348 * stateid to the current stateid, if it is set. 4349 */ 4350 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4351 stateid.other[1] == 0 && stateid.other[2] == 0) { 4352 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4353 stateid = nd->nd_curstateid; 4354 stateid.seqid = 0; 4355 } else { 4356 nd->nd_repstat = NFSERR_BADSTATEID; 4357 goto nfsmout; 4358 } 4359 } 4360 4361 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 4362 4363 /* If the current stateid has been free'd, unset it. */ 4364 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 && 4365 stateid.other[0] == nd->nd_curstateid.other[0] && 4366 stateid.other[1] == nd->nd_curstateid.other[1] && 4367 stateid.other[2] == nd->nd_curstateid.other[2]) 4368 nd->nd_flag &= ~ND_CURSTATEID; 4369 nfsmout: 4370 NFSEXITCODE2(error, nd); 4371 return (error); 4372 } 4373 4374 /* 4375 * nfsv4 layoutget service 4376 */ 4377 APPLESTATIC int 4378 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram, 4379 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 4380 { 4381 uint32_t *tl; 4382 nfsv4stateid_t stateid; 4383 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose; 4384 uint64_t offset, len, minlen; 4385 char *layp; 4386 4387 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4388 nd->nd_repstat = NFSERR_WRONGSEC; 4389 goto nfsmout; 4390 } 4391 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 4392 NFSX_STATEID); 4393 tl++; /* Signal layout available. Ignore for now. */ 4394 layouttype = fxdr_unsigned(int, *tl++); 4395 iomode = fxdr_unsigned(int, *tl++); 4396 offset = fxdr_hyper(tl); tl += 2; 4397 len = fxdr_hyper(tl); tl += 2; 4398 minlen = fxdr_hyper(tl); tl += 2; 4399 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4400 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4401 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4402 maxcnt = fxdr_unsigned(int, *tl); 4403 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n", 4404 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len, 4405 (uintmax_t)minlen); 4406 if (len < minlen || 4407 (minlen != UINT64_MAX && offset + minlen < offset) || 4408 (len != UINT64_MAX && offset + len < offset)) { 4409 nd->nd_repstat = NFSERR_INVAL; 4410 goto nfsmout; 4411 } 4412 4413 /* 4414 * For the special stateid of other all 0s and seqid == 1, set the 4415 * stateid to the current stateid, if it is set. 4416 */ 4417 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4418 stateid.other[1] == 0 && stateid.other[2] == 0) { 4419 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4420 stateid = nd->nd_curstateid; 4421 stateid.seqid = 0; 4422 } else { 4423 nd->nd_repstat = NFSERR_BADSTATEID; 4424 goto nfsmout; 4425 } 4426 } 4427 4428 layp = NULL; 4429 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1) 4430 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK); 4431 else if (layouttype == NFSLAYOUT_FLEXFILE) 4432 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP, 4433 M_WAITOK); 4434 else 4435 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE; 4436 if (layp != NULL) 4437 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype, 4438 &iomode, &offset, &len, minlen, &stateid, maxcnt, 4439 &retonclose, &layoutlen, layp, nd->nd_cred, p); 4440 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat, 4441 layoutlen); 4442 if (nd->nd_repstat == 0) { 4443 /* For NFSv4.1, set the Current StateID. */ 4444 if ((nd->nd_flag & ND_NFSV41) != 0) { 4445 nd->nd_curstateid = stateid; 4446 nd->nd_flag |= ND_CURSTATEID; 4447 } 4448 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID + 4449 2 * NFSX_HYPER); 4450 *tl++ = txdr_unsigned(retonclose); 4451 *tl++ = txdr_unsigned(stateid.seqid); 4452 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 4453 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4454 *tl++ = txdr_unsigned(1); /* Only returns one layout. */ 4455 txdr_hyper(offset, tl); tl += 2; 4456 txdr_hyper(len, tl); tl += 2; 4457 *tl++ = txdr_unsigned(iomode); 4458 *tl = txdr_unsigned(layouttype); 4459 nfsm_strtom(nd, layp, layoutlen); 4460 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) { 4461 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4462 *tl = newnfs_false; 4463 } 4464 free(layp, M_TEMP); 4465 nfsmout: 4466 vput(vp); 4467 NFSEXITCODE2(error, nd); 4468 return (error); 4469 } 4470 4471 /* 4472 * nfsv4 layoutcommit service 4473 */ 4474 APPLESTATIC int 4475 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram, 4476 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 4477 { 4478 uint32_t *tl; 4479 nfsv4stateid_t stateid; 4480 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim; 4481 int hasnewsize; 4482 uint64_t offset, len, newoff, newsize; 4483 struct timespec newmtime; 4484 char *layp; 4485 4486 layp = NULL; 4487 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4488 nd->nd_repstat = NFSERR_WRONGSEC; 4489 goto nfsmout; 4490 } 4491 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER + 4492 NFSX_STATEID); 4493 offset = fxdr_hyper(tl); tl += 2; 4494 len = fxdr_hyper(tl); tl += 2; 4495 reclaim = fxdr_unsigned(int, *tl++); 4496 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4497 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4498 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4499 /* 4500 * For the special stateid of other all 0s and seqid == 1, set the 4501 * stateid to the current stateid, if it is set. 4502 */ 4503 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4504 stateid.other[1] == 0 && stateid.other[2] == 0) { 4505 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4506 stateid = nd->nd_curstateid; 4507 stateid.seqid = 0; 4508 } else { 4509 nd->nd_repstat = NFSERR_BADSTATEID; 4510 goto nfsmout; 4511 } 4512 } 4513 4514 hasnewoff = fxdr_unsigned(int, *tl); 4515 if (hasnewoff != 0) { 4516 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 4517 newoff = fxdr_hyper(tl); tl += 2; 4518 } else 4519 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4520 hasnewmtime = fxdr_unsigned(int, *tl); 4521 if (hasnewmtime != 0) { 4522 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED); 4523 fxdr_nfsv4time(tl, &newmtime); 4524 tl += (NFSX_V4TIME / NFSX_UNSIGNED); 4525 } else 4526 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4527 layouttype = fxdr_unsigned(int, *tl++); 4528 maxcnt = fxdr_unsigned(int, *tl); 4529 if (maxcnt > 0) { 4530 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 4531 error = nfsrv_mtostr(nd, layp, maxcnt); 4532 if (error != 0) 4533 goto nfsmout; 4534 } 4535 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff, 4536 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid, 4537 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p); 4538 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat); 4539 if (nd->nd_repstat == 0) { 4540 if (hasnewsize != 0) { 4541 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 4542 *tl++ = newnfs_true; 4543 txdr_hyper(newsize, tl); 4544 } else { 4545 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4546 *tl = newnfs_false; 4547 } 4548 } 4549 nfsmout: 4550 free(layp, M_TEMP); 4551 vput(vp); 4552 NFSEXITCODE2(error, nd); 4553 return (error); 4554 } 4555 4556 /* 4557 * nfsv4 layoutreturn service 4558 */ 4559 APPLESTATIC int 4560 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram, 4561 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 4562 { 4563 uint32_t *tl, *layp; 4564 nfsv4stateid_t stateid; 4565 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim; 4566 uint64_t offset, len; 4567 4568 layp = NULL; 4569 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4570 nd->nd_repstat = NFSERR_WRONGSEC; 4571 goto nfsmout; 4572 } 4573 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4574 reclaim = *tl++; 4575 layouttype = fxdr_unsigned(int, *tl++); 4576 iomode = fxdr_unsigned(int, *tl++); 4577 kind = fxdr_unsigned(int, *tl); 4578 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim, 4579 layouttype, iomode, kind); 4580 if (kind == NFSV4LAYOUTRET_FILE) { 4581 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 4582 NFSX_UNSIGNED); 4583 offset = fxdr_hyper(tl); tl += 2; 4584 len = fxdr_hyper(tl); tl += 2; 4585 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4586 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4587 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4588 4589 /* 4590 * For the special stateid of other all 0s and seqid == 1, set 4591 * the stateid to the current stateid, if it is set. 4592 */ 4593 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4594 stateid.other[1] == 0 && stateid.other[2] == 0) { 4595 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4596 stateid = nd->nd_curstateid; 4597 stateid.seqid = 0; 4598 } else { 4599 nd->nd_repstat = NFSERR_BADSTATEID; 4600 goto nfsmout; 4601 } 4602 } 4603 4604 maxcnt = fxdr_unsigned(int, *tl); 4605 if (maxcnt > 0) { 4606 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 4607 error = nfsrv_mtostr(nd, (char *)layp, maxcnt); 4608 if (error != 0) 4609 goto nfsmout; 4610 } 4611 } else { 4612 if (reclaim == newnfs_true) { 4613 nd->nd_repstat = NFSERR_INVAL; 4614 goto nfsmout; 4615 } 4616 offset = len = 0; 4617 maxcnt = 0; 4618 } 4619 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode, 4620 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd, 4621 nd->nd_cred, p); 4622 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat, 4623 fnd); 4624 if (nd->nd_repstat == 0) { 4625 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4626 if (fnd != 0) { 4627 *tl = newnfs_true; 4628 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID); 4629 *tl++ = txdr_unsigned(stateid.seqid); 4630 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 4631 } else 4632 *tl = newnfs_false; 4633 } 4634 nfsmout: 4635 free(layp, M_TEMP); 4636 vput(vp); 4637 NFSEXITCODE2(error, nd); 4638 return (error); 4639 } 4640 4641 /* 4642 * nfsv4 getdeviceinfo service 4643 */ 4644 APPLESTATIC int 4645 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram, 4646 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4647 { 4648 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP]; 4649 int cnt, devaddrlen, error = 0, i, layouttype; 4650 char devid[NFSX_V4DEVICEID], *devaddr; 4651 time_t dev_time; 4652 4653 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4654 nd->nd_repstat = NFSERR_WRONGSEC; 4655 goto nfsmout; 4656 } 4657 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID); 4658 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 4659 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 4660 layouttype = fxdr_unsigned(int, *tl++); 4661 maxcnt = fxdr_unsigned(uint32_t, *tl++); 4662 cnt = fxdr_unsigned(int, *tl); 4663 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype, 4664 maxcnt, cnt); 4665 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) { 4666 nd->nd_repstat = NFSERR_INVAL; 4667 goto nfsmout; 4668 } 4669 if (cnt > 0) { 4670 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED); 4671 for (i = 0; i < cnt; i++) 4672 notify[i] = fxdr_unsigned(uint32_t, *tl++); 4673 } 4674 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++) 4675 notify[i] = 0; 4676 4677 /* 4678 * Check that the device id is not stale. Device ids are recreated 4679 * each time the nfsd threads are restarted. 4680 */ 4681 NFSBCOPY(devid, &dev_time, sizeof(dev_time)); 4682 if (dev_time != nfsdev_time) { 4683 nd->nd_repstat = NFSERR_NOENT; 4684 goto nfsmout; 4685 } 4686 4687 /* Look for the device id. */ 4688 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt, 4689 notify, &devaddrlen, &devaddr); 4690 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat); 4691 if (nd->nd_repstat == 0) { 4692 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4693 *tl = txdr_unsigned(layouttype); 4694 nfsm_strtom(nd, devaddr, devaddrlen); 4695 cnt = 0; 4696 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) { 4697 if (notify[i] != 0) 4698 cnt = i + 1; 4699 } 4700 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED); 4701 *tl++ = txdr_unsigned(cnt); 4702 for (i = 0; i < cnt; i++) 4703 *tl++ = txdr_unsigned(notify[i]); 4704 } else if (nd->nd_repstat == NFSERR_TOOSMALL) { 4705 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4706 *tl = txdr_unsigned(maxcnt); 4707 } 4708 nfsmout: 4709 NFSEXITCODE2(error, nd); 4710 return (error); 4711 } 4712 4713 /* 4714 * nfsv4 test stateid service 4715 */ 4716 APPLESTATIC int 4717 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, 4718 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4719 { 4720 uint32_t *tl; 4721 nfsv4stateid_t *stateidp = NULL, *tstateidp; 4722 int cnt, error = 0, i, ret; 4723 4724 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4725 nd->nd_repstat = NFSERR_WRONGSEC; 4726 goto nfsmout; 4727 } 4728 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4729 cnt = fxdr_unsigned(int, *tl); 4730 if (cnt <= 0 || cnt > 1024) { 4731 nd->nd_repstat = NFSERR_BADXDR; 4732 goto nfsmout; 4733 } 4734 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); 4735 tstateidp = stateidp; 4736 for (i = 0; i < cnt; i++) { 4737 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4738 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 4739 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); 4740 tstateidp++; 4741 } 4742 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4743 *tl = txdr_unsigned(cnt); 4744 tstateidp = stateidp; 4745 for (i = 0; i < cnt; i++) { 4746 ret = nfsrv_teststateid(nd, tstateidp, p); 4747 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4748 *tl = txdr_unsigned(ret); 4749 tstateidp++; 4750 } 4751 nfsmout: 4752 free(stateidp, M_TEMP); 4753 NFSEXITCODE2(error, nd); 4754 return (error); 4755 } 4756 4757 /* 4758 * nfsv4 service not supported 4759 */ 4760 APPLESTATIC int 4761 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 4762 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4763 { 4764 4765 nd->nd_repstat = NFSERR_NOTSUPP; 4766 NFSEXITCODE2(0, nd); 4767 return (0); 4768 } 4769 4770