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