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