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 #include "opt_inet.h" 38 #include "opt_inet6.h" 39 /* 40 * nfs version 2, 3 and 4 server calls to vnode ops 41 * - these routines generally have 3 phases 42 * 1 - break down and validate rpc request in mbuf list 43 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX() 44 * function in nfsd_port.c 45 * 3 - build the rpc reply in an mbuf list 46 * For nfsv4, these functions are called for each Op within the Compound RPC. 47 */ 48 49 #include <fs/nfs/nfsport.h> 50 #include <sys/extattr.h> 51 #include <sys/filio.h> 52 53 /* Global vars */ 54 extern u_int32_t newnfs_false, newnfs_true; 55 extern __enum_uint8(vtype) nv34tov_type[8]; 56 extern struct timeval nfsboottime; 57 extern int nfsrv_enable_crossmntpt; 58 extern int nfsrv_statehashsize; 59 extern int nfsrv_layouthashsize; 60 extern time_t nfsdev_time; 61 extern volatile int nfsrv_devidcnt; 62 extern int nfsd_debuglevel; 63 extern u_long sb_max_adj; 64 extern int nfsrv_pnfsatime; 65 extern int nfsrv_maxpnfsmirror; 66 extern uint32_t nfs_srvmaxio; 67 extern int nfsrv_issuedelegs; 68 69 static int nfs_async = 0; 70 SYSCTL_DECL(_vfs_nfsd); 71 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, 72 "Tell client that writes were synced even though they were not"); 73 extern int nfsrv_doflexfile; 74 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW, 75 &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS"); 76 static int nfsrv_linux42server = 1; 77 SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW, 78 &nfsrv_linux42server, 0, 79 "Enable Linux style NFSv4.2 server (non-RFC compliant)"); 80 static bool nfsrv_openaccess = true; 81 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW, 82 &nfsrv_openaccess, 0, 83 "Enable Linux style NFSv4 Open access check"); 84 static char nfsrv_scope[NFSV4_OPAQUELIMIT]; 85 SYSCTL_STRING(_vfs_nfsd, OID_AUTO, scope, CTLFLAG_RWTUN, 86 &nfsrv_scope, NFSV4_OPAQUELIMIT, "Server scope"); 87 static char nfsrv_owner_major[NFSV4_OPAQUELIMIT]; 88 SYSCTL_STRING(_vfs_nfsd, OID_AUTO, owner_major, CTLFLAG_RWTUN, 89 &nfsrv_owner_major, NFSV4_OPAQUELIMIT, "Server owner major"); 90 static uint64_t nfsrv_owner_minor; 91 SYSCTL_U64(_vfs_nfsd, OID_AUTO, owner_minor, CTLFLAG_RWTUN, 92 &nfsrv_owner_minor, 0, "Server owner minor"); 93 /* 94 * Only enable this if all your exported file systems 95 * (or pNFS DSs for the pNFS case) support VOP_ALLOCATE. 96 */ 97 static bool nfsrv_doallocate = false; 98 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, enable_v42allocate, CTLFLAG_RW, 99 &nfsrv_doallocate, 0, 100 "Enable NFSv4.2 Allocate operation"); 101 static uint64_t nfsrv_maxcopyrange = SSIZE_MAX; 102 SYSCTL_U64(_vfs_nfsd, OID_AUTO, maxcopyrange, CTLFLAG_RW, 103 &nfsrv_maxcopyrange, 0, "Max size of a Copy so RPC times reasonable"); 104 105 /* 106 * This list defines the GSS mechanisms supported. 107 * (Don't ask me how you get these strings from the RFC stuff like 108 * iso(1), org(3)... but someone did it, so I don't need to know.) 109 */ 110 static struct nfsgss_mechlist nfsgss_mechlist[] = { 111 { 9, "\052\206\110\206\367\022\001\002\002", 11 }, 112 { 0, "", 0 }, 113 }; 114 115 /* local functions */ 116 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 117 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 118 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 119 int *diraft_retp, nfsattrbit_t *attrbitp, 120 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 121 int pathlen); 122 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 123 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 124 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 125 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 126 NFSPROC_T *p, struct nfsexstuff *exp); 127 128 /* 129 * nfs access service (not a part of NFS V2) 130 */ 131 int 132 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram, 133 vnode_t vp, struct nfsexstuff *exp) 134 { 135 u_int32_t *tl; 136 int getret, error = 0; 137 struct nfsvattr nva; 138 u_int32_t testmode, nfsmode, supported = 0; 139 accmode_t deletebit; 140 struct thread *p = curthread; 141 142 if (nd->nd_repstat) { 143 nfsrv_postopattr(nd, 1, &nva); 144 goto out; 145 } 146 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 147 nfsmode = fxdr_unsigned(u_int32_t, *tl); 148 if ((nd->nd_flag & ND_NFSV4) && 149 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | 150 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | 151 NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE | 152 NFSACCESS_XALIST))) { 153 nd->nd_repstat = NFSERR_INVAL; 154 vput(vp); 155 goto out; 156 } 157 if (nfsmode & NFSACCESS_READ) { 158 supported |= NFSACCESS_READ; 159 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 160 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 161 nfsmode &= ~NFSACCESS_READ; 162 } 163 if (nfsmode & NFSACCESS_MODIFY) { 164 supported |= NFSACCESS_MODIFY; 165 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 166 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 167 nfsmode &= ~NFSACCESS_MODIFY; 168 } 169 if (nfsmode & NFSACCESS_EXTEND) { 170 supported |= NFSACCESS_EXTEND; 171 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p, 172 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 173 nfsmode &= ~NFSACCESS_EXTEND; 174 } 175 if (nfsmode & NFSACCESS_XAREAD) { 176 supported |= NFSACCESS_XAREAD; 177 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 178 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 179 nfsmode &= ~NFSACCESS_XAREAD; 180 } 181 if (nfsmode & NFSACCESS_XAWRITE) { 182 supported |= NFSACCESS_XAWRITE; 183 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 184 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 185 nfsmode &= ~NFSACCESS_XAWRITE; 186 } 187 if (nfsmode & NFSACCESS_XALIST) { 188 supported |= NFSACCESS_XALIST; 189 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 190 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 191 nfsmode &= ~NFSACCESS_XALIST; 192 } 193 if (nfsmode & NFSACCESS_DELETE) { 194 supported |= NFSACCESS_DELETE; 195 if (vp->v_type == VDIR) 196 deletebit = VDELETE_CHILD; 197 else 198 deletebit = VDELETE; 199 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p, 200 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 201 nfsmode &= ~NFSACCESS_DELETE; 202 } 203 if (vp->v_type == VDIR) 204 testmode = NFSACCESS_LOOKUP; 205 else 206 testmode = NFSACCESS_EXECUTE; 207 if (nfsmode & testmode) { 208 supported |= (nfsmode & testmode); 209 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, 210 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 211 nfsmode &= ~testmode; 212 } 213 nfsmode &= supported; 214 if (nd->nd_flag & ND_NFSV3) { 215 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 216 nfsrv_postopattr(nd, getret, &nva); 217 } 218 vput(vp); 219 if (nd->nd_flag & ND_NFSV4) { 220 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 221 *tl++ = txdr_unsigned(supported); 222 } else 223 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 224 *tl = txdr_unsigned(nfsmode); 225 226 out: 227 NFSEXITCODE2(0, nd); 228 return (0); 229 nfsmout: 230 vput(vp); 231 NFSEXITCODE2(error, nd); 232 return (error); 233 } 234 235 /* 236 * nfs getattr service 237 */ 238 int 239 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, 240 vnode_t vp, __unused struct nfsexstuff *exp) 241 { 242 struct nfsvattr nva; 243 fhandle_t fh; 244 int at_root = 0, error = 0, ret, supports_nfsv4acls; 245 struct nfsreferral *refp; 246 nfsattrbit_t attrbits, tmpbits; 247 struct mount *mp; 248 struct vnode *tvp = NULL; 249 struct vattr va; 250 uint64_t mounted_on_fileno = 0; 251 accmode_t accmode; 252 struct thread *p = curthread; 253 size_t atsiz; 254 long pathval; 255 bool has_hiddensystem, has_namedattr, xattrsupp; 256 uint32_t clone_blksize; 257 258 if (nd->nd_repstat) 259 goto out; 260 if (nd->nd_flag & ND_NFSV4) { 261 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 262 if (error) { 263 vput(vp); 264 goto out; 265 } 266 267 /* 268 * Check for a referral. 269 */ 270 refp = nfsv4root_getreferral(vp, NULL, 0); 271 if (refp != NULL) { 272 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1, 273 &nd->nd_repstat); 274 vput(vp); 275 goto out; 276 } 277 if (nd->nd_repstat == 0) { 278 accmode = 0; 279 NFSSET_ATTRBIT(&tmpbits, &attrbits); 280 281 /* 282 * GETATTR with write-only attr time_access_set and time_modify_set 283 * should return NFS4ERR_INVAL. 284 */ 285 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) || 286 NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){ 287 error = NFSERR_INVAL; 288 vput(vp); 289 goto out; 290 } 291 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { 292 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); 293 accmode |= VREAD_ACL; 294 } 295 if (NFSNONZERO_ATTRBIT(&tmpbits)) 296 accmode |= VREAD_ATTRIBUTES; 297 if (accmode != 0) 298 nd->nd_repstat = nfsvno_accchk(vp, accmode, 299 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 300 NFSACCCHK_VPISLOCKED, NULL); 301 } 302 } 303 if (!nd->nd_repstat) 304 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 305 if (!nd->nd_repstat) { 306 if (nd->nd_flag & ND_NFSV4) { 307 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE)) 308 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 309 if (!nd->nd_repstat) 310 nd->nd_repstat = nfsrv_checkgetattr(nd, vp, 311 &nva, &attrbits, p); 312 if (nd->nd_repstat == 0) { 313 supports_nfsv4acls = nfs_supportsnfsv4acls(vp); 314 xattrsupp = false; 315 if (NFSISSET_ATTRBIT(&attrbits, 316 NFSATTRBIT_XATTRSUPPORT)) { 317 ret = VOP_GETEXTATTR(vp, 318 EXTATTR_NAMESPACE_USER, 319 "xxx", NULL, &atsiz, nd->nd_cred, 320 p); 321 xattrsupp = ret != EOPNOTSUPP; 322 } 323 if (VOP_PATHCONF(vp, _PC_HAS_HIDDENSYSTEM, 324 &pathval) != 0) 325 pathval = 0; 326 has_hiddensystem = pathval > 0; 327 pathval = 0; 328 if (NFSISSET_ATTRBIT(&attrbits, 329 NFSATTRBIT_NAMEDATTR) && 330 VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR, 331 &pathval) != 0) 332 pathval = 0; 333 has_namedattr = pathval > 0; 334 pathval = 0; 335 if (VOP_PATHCONF(vp, _PC_CLONE_BLKSIZE, 336 &pathval) != 0) 337 pathval = 0; 338 clone_blksize = pathval; 339 mp = vp->v_mount; 340 if (nfsrv_enable_crossmntpt != 0 && 341 vp->v_type == VDIR && 342 (vp->v_vflag & VV_ROOT) != 0 && 343 vp != rootvnode) { 344 tvp = mp->mnt_vnodecovered; 345 vref(tvp); 346 at_root = 1; 347 } else 348 at_root = 0; 349 vfs_ref(mp); 350 NFSVOPUNLOCK(vp); 351 if (at_root != 0) { 352 if ((nd->nd_repstat = 353 NFSVOPLOCK(tvp, LK_SHARED)) == 0) { 354 nd->nd_repstat = VOP_GETATTR( 355 tvp, &va, nd->nd_cred); 356 vput(tvp); 357 } else 358 vrele(tvp); 359 if (nd->nd_repstat == 0) 360 mounted_on_fileno = (uint64_t) 361 va.va_fileid; 362 else 363 at_root = 0; 364 } 365 if (nd->nd_repstat == 0) 366 nd->nd_repstat = vfs_busy(mp, 0); 367 vfs_rel(mp); 368 if (nd->nd_repstat == 0) { 369 (void)nfsvno_fillattr(nd, mp, vp, &nva, 370 &fh, 0, &attrbits, nd->nd_cred, p, 371 isdgram, 1, supports_nfsv4acls, 372 at_root, mounted_on_fileno, 373 xattrsupp, has_hiddensystem, 374 has_namedattr, clone_blksize); 375 vfs_unbusy(mp); 376 } 377 vrele(vp); 378 } else 379 vput(vp); 380 } else { 381 nfsrv_fillattr(nd, &nva); 382 vput(vp); 383 } 384 } else { 385 vput(vp); 386 } 387 388 out: 389 NFSEXITCODE2(error, nd); 390 return (error); 391 } 392 393 /* 394 * nfs setattr service 395 */ 396 int 397 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, 398 vnode_t vp, struct nfsexstuff *exp) 399 { 400 struct nfsvattr nva, nva2; 401 u_int32_t *tl; 402 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0; 403 int gotproxystateid; 404 struct timespec guard = { 0, 0 }; 405 nfsattrbit_t attrbits, retbits; 406 nfsv4stateid_t stateid; 407 NFSACL_T *aclp = NULL; 408 struct thread *p = curthread; 409 410 NFSZERO_ATTRBIT(&retbits); 411 if (nd->nd_repstat) { 412 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 413 goto out; 414 } 415 #ifdef NFS4_ACL_EXTATTR_NAME 416 aclp = acl_alloc(M_WAITOK); 417 aclp->acl_cnt = 0; 418 #endif 419 gotproxystateid = 0; 420 NFSVNO_ATTRINIT(&nva); 421 if (nd->nd_flag & ND_NFSV4) { 422 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 423 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 424 stateid.other[0] = *tl++; 425 stateid.other[1] = *tl++; 426 stateid.other[2] = *tl; 427 if (stateid.other[0] == 0x55555555 && 428 stateid.other[1] == 0x55555555 && 429 stateid.other[2] == 0x55555555 && 430 stateid.seqid == 0xffffffff) 431 gotproxystateid = 1; 432 } 433 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p); 434 if (error) 435 goto nfsmout; 436 437 /* For NFSv4, only va_uid and va_flags is used from nva2. */ 438 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 439 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN); 440 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM); 441 preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits); 442 if (!nd->nd_repstat) 443 nd->nd_repstat = preat_ret; 444 445 NFSZERO_ATTRBIT(&retbits); 446 if (nd->nd_flag & ND_NFSV3) { 447 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 448 gcheck = fxdr_unsigned(int, *tl); 449 if (gcheck) { 450 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 451 fxdr_nfsv3time(tl, &guard); 452 } 453 if (!nd->nd_repstat && gcheck && 454 (nva2.na_ctime.tv_sec != guard.tv_sec || 455 nva2.na_ctime.tv_nsec != guard.tv_nsec)) 456 nd->nd_repstat = NFSERR_NOT_SYNC; 457 if (nd->nd_repstat) { 458 vput(vp); 459 #ifdef NFS4_ACL_EXTATTR_NAME 460 acl_free(aclp); 461 #endif 462 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 463 goto out; 464 } 465 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 466 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 467 468 /* 469 * Now that we have all the fields, lets do it. 470 * If the size is being changed write access is required, otherwise 471 * just check for a read only file system. 472 */ 473 if (!nd->nd_repstat) { 474 if (NFSVNO_NOTSETSIZE(&nva)) { 475 if (NFSVNO_EXRDONLY(exp) || 476 (vp->v_mount->mnt_flag & MNT_RDONLY)) 477 nd->nd_repstat = EROFS; 478 } else { 479 if (vp->v_type != VREG) 480 nd->nd_repstat = EINVAL; 481 else if (nva2.na_uid != nd->nd_cred->cr_uid || 482 NFSVNO_EXSTRICTACCESS(exp)) 483 nd->nd_repstat = nfsvno_accchk(vp, 484 VWRITE, nd->nd_cred, exp, p, 485 NFSACCCHK_NOOVERRIDE, 486 NFSACCCHK_VPISLOCKED, NULL); 487 } 488 } 489 /* 490 * Proxy operations from the MDS are allowed via the all 0s special 491 * stateid. 492 */ 493 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 && 494 gotproxystateid == 0) 495 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid, 496 &nva, &attrbits, exp, p); 497 498 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 499 u_long oldflags; 500 501 oldflags = nva2.na_flags; 502 /* 503 * For V4, try setting the attributes in sets, so that the 504 * reply bitmap will be correct for an error case. 505 */ 506 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) || 507 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) { 508 NFSVNO_ATTRINIT(&nva2); 509 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid); 510 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid); 511 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 512 exp); 513 if (!nd->nd_repstat) { 514 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER)) 515 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 516 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) 517 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP); 518 } 519 } 520 if (!nd->nd_repstat && 521 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) { 522 NFSVNO_ATTRINIT(&nva2); 523 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size); 524 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 525 exp); 526 if (!nd->nd_repstat) 527 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE); 528 } 529 if (!nd->nd_repstat && 530 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) || 531 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) { 532 NFSVNO_ATTRINIT(&nva2); 533 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime); 534 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime); 535 if (nva.na_vaflags & VA_UTIMES_NULL) { 536 nva2.na_vaflags |= VA_UTIMES_NULL; 537 NFSVNO_SETACTIVE(&nva2, vaflags); 538 } 539 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 540 exp); 541 if (!nd->nd_repstat) { 542 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) 543 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET); 544 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET)) 545 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET); 546 } 547 } 548 if (!nd->nd_repstat && 549 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE)) { 550 NFSVNO_ATTRINIT(&nva2); 551 NFSVNO_SETATTRVAL(&nva2, btime, nva.na_btime); 552 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 553 exp); 554 if (!nd->nd_repstat) 555 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMECREATE); 556 } 557 if (!nd->nd_repstat && 558 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) || 559 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) { 560 NFSVNO_ATTRINIT(&nva2); 561 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); 562 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 563 exp); 564 if (!nd->nd_repstat) { 565 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) 566 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); 567 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED)) 568 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED); 569 } 570 } 571 if (!nd->nd_repstat && 572 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN) || 573 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM))) { 574 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN)) { 575 if ((nva.na_flags & UF_HIDDEN) != 0) 576 oldflags |= UF_HIDDEN; 577 else 578 oldflags &= ~UF_HIDDEN; 579 } 580 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM)) { 581 if ((nva.na_flags & UF_SYSTEM) != 0) 582 oldflags |= UF_SYSTEM; 583 else 584 oldflags &= ~UF_SYSTEM; 585 } 586 NFSVNO_ATTRINIT(&nva2); 587 NFSVNO_SETATTRVAL(&nva2, flags, oldflags); 588 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 589 exp); 590 if (!nd->nd_repstat) { 591 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN)) 592 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN); 593 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM)) 594 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM); 595 } 596 } 597 598 #ifdef NFS4_ACL_EXTATTR_NAME 599 if (!nd->nd_repstat && aclp->acl_cnt > 0 && 600 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) { 601 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p); 602 if (!nd->nd_repstat) 603 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL); 604 } 605 #endif 606 } else if (!nd->nd_repstat) { 607 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p, 608 exp); 609 } 610 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) { 611 postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 612 if (!nd->nd_repstat) 613 nd->nd_repstat = postat_ret; 614 } 615 vput(vp); 616 #ifdef NFS4_ACL_EXTATTR_NAME 617 acl_free(aclp); 618 #endif 619 if (nd->nd_flag & ND_NFSV3) 620 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 621 else if (nd->nd_flag & ND_NFSV4) 622 (void) nfsrv_putattrbit(nd, &retbits); 623 else if (!nd->nd_repstat) 624 nfsrv_fillattr(nd, &nva); 625 626 out: 627 NFSEXITCODE2(0, nd); 628 return (0); 629 nfsmout: 630 vput(vp); 631 #ifdef NFS4_ACL_EXTATTR_NAME 632 acl_free(aclp); 633 #endif 634 if (nd->nd_flag & ND_NFSV4) { 635 /* 636 * For all nd_repstat, the V4 reply includes a bitmap, 637 * even NFSERR_BADXDR, which is what this will end up 638 * returning. 639 */ 640 (void) nfsrv_putattrbit(nd, &retbits); 641 } 642 NFSEXITCODE2(error, nd); 643 return (error); 644 } 645 646 /* 647 * nfs lookup rpc 648 * (Also performs lookup parent for v4) 649 */ 650 int 651 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, 652 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 653 { 654 struct nameidata named; 655 vnode_t vp, dirp = NULL; 656 int error = 0, dattr_ret = 1; 657 struct nfsvattr nva, dattr; 658 char *bufp; 659 u_long *hashp; 660 struct thread *p = curthread; 661 struct componentname *cnp; 662 short irflag; 663 664 if (nd->nd_repstat) { 665 nfsrv_postopattr(nd, dattr_ret, &dattr); 666 goto out; 667 } 668 669 /* 670 * For some reason, if dp is a symlink, the error 671 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR. 672 */ 673 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) { 674 nd->nd_repstat = NFSERR_SYMLINK; 675 vrele(dp); 676 goto out; 677 } 678 679 cnp = &named.ni_cnd; 680 irflag = vn_irflag_read(dp); 681 if ((irflag & VIRF_NAMEDDIR) != 0) 682 NFSNAMEICNDSET(cnp, nd->nd_cred, LOOKUP, LOCKLEAF | OPENNAMED); 683 else 684 NFSNAMEICNDSET(cnp, nd->nd_cred, LOOKUP, LOCKLEAF); 685 nfsvno_setpathbuf(&named, &bufp, &hashp); 686 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 687 if (error) { 688 vrele(dp); 689 nfsvno_relpathbuf(&named); 690 goto out; 691 } 692 if (!nd->nd_repstat) { 693 /* Don't set OPENNAMED for Lookupp (".."). */ 694 if (cnp->cn_namelen == 2 && *cnp->cn_pnbuf == '.' && 695 *(cnp->cn_pnbuf + 1) == '.') 696 cnp->cn_flags &= ~OPENNAMED; 697 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); 698 } else { 699 vrele(dp); 700 nfsvno_relpathbuf(&named); 701 } 702 if (nd->nd_repstat) { 703 if (dirp) { 704 if (nd->nd_flag & ND_NFSV3) 705 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 706 0, NULL); 707 vrele(dirp); 708 } 709 if (nd->nd_flag & ND_NFSV3) 710 nfsrv_postopattr(nd, dattr_ret, &dattr); 711 goto out; 712 } 713 nfsvno_relpathbuf(&named); 714 vp = named.ni_vp; 715 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && 716 vp->v_type != VDIR && vp->v_type != VLNK) 717 /* 718 * Only allow lookup of VDIR and VLNK for traversal of 719 * non-exported volumes during NFSv4 mounting. 720 */ 721 nd->nd_repstat = ENOENT; 722 if (nd->nd_repstat == 0) { 723 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 724 /* 725 * EOPNOTSUPP indicates the file system cannot be exported, 726 * so just pretend the entry does not exist. 727 */ 728 if (nd->nd_repstat == EOPNOTSUPP) 729 nd->nd_repstat = ENOENT; 730 } 731 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 732 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 733 if (vpp != NULL && nd->nd_repstat == 0) 734 *vpp = vp; 735 else 736 vput(vp); 737 if (dirp) { 738 if (nd->nd_flag & ND_NFSV3) 739 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0, 740 NULL); 741 vrele(dirp); 742 } 743 if (nd->nd_repstat) { 744 if (nd->nd_flag & ND_NFSV3) 745 nfsrv_postopattr(nd, dattr_ret, &dattr); 746 goto out; 747 } 748 if (nd->nd_flag & ND_NFSV2) { 749 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0); 750 nfsrv_fillattr(nd, &nva); 751 } else if (nd->nd_flag & ND_NFSV3) { 752 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0); 753 nfsrv_postopattr(nd, 0, &nva); 754 nfsrv_postopattr(nd, dattr_ret, &dattr); 755 } 756 757 out: 758 NFSEXITCODE2(error, nd); 759 return (error); 760 } 761 762 /* 763 * nfs readlink service 764 */ 765 int 766 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, 767 vnode_t vp, __unused struct nfsexstuff *exp) 768 { 769 u_int32_t *tl; 770 struct mbuf *mp = NULL, *mpend = NULL; 771 int getret = 1, len; 772 struct nfsvattr nva; 773 struct thread *p = curthread; 774 uint16_t off; 775 776 if (nd->nd_repstat) { 777 nfsrv_postopattr(nd, getret, &nva); 778 goto out; 779 } 780 if (vp->v_type != VLNK) { 781 if (nd->nd_flag & ND_NFSV2) 782 nd->nd_repstat = ENXIO; 783 else 784 nd->nd_repstat = EINVAL; 785 } 786 if (nd->nd_repstat == 0) { 787 if ((nd->nd_flag & ND_EXTPG) != 0) 788 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, 789 nd->nd_maxextsiz, p, &mp, &mpend, &len); 790 else 791 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, 792 0, p, &mp, &mpend, &len); 793 } 794 if (nd->nd_flag & ND_NFSV3) 795 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 796 vput(vp); 797 if (nd->nd_flag & ND_NFSV3) 798 nfsrv_postopattr(nd, getret, &nva); 799 if (nd->nd_repstat) 800 goto out; 801 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 802 *tl = txdr_unsigned(len); 803 if (mp != NULL) { 804 nd->nd_mb->m_next = mp; 805 nd->nd_mb = mpend; 806 if ((mpend->m_flags & M_EXTPG) != 0) { 807 nd->nd_bextpg = mpend->m_epg_npgs - 1; 808 nd->nd_bpos = (char *)(void *) 809 PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]); 810 off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0; 811 nd->nd_bpos += off + mpend->m_epg_last_len; 812 nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len - 813 off; 814 } else 815 nd->nd_bpos = mtod(mpend, char *) + mpend->m_len; 816 } 817 818 out: 819 NFSEXITCODE2(0, nd); 820 return (0); 821 } 822 823 /* 824 * nfs read service 825 */ 826 int 827 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, 828 vnode_t vp, struct nfsexstuff *exp) 829 { 830 u_int32_t *tl; 831 int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0; 832 struct mbuf *m2, *m3; 833 struct nfsvattr nva; 834 off_t off = 0x0; 835 struct nfsstate st, *stp = &st; 836 struct nfslock lo, *lop = &lo; 837 nfsv4stateid_t stateid; 838 nfsquad_t clientid; 839 struct thread *p = curthread; 840 uint16_t poff; 841 842 if (nd->nd_repstat) { 843 nfsrv_postopattr(nd, getret, &nva); 844 goto out; 845 } 846 if (nd->nd_flag & ND_NFSV2) { 847 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 848 off = (off_t)fxdr_unsigned(u_int32_t, *tl++); 849 reqlen = fxdr_unsigned(int, *tl); 850 } else if (nd->nd_flag & ND_NFSV3) { 851 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 852 off = fxdr_hyper(tl); 853 tl += 2; 854 reqlen = fxdr_unsigned(int, *tl); 855 } else { 856 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED); 857 reqlen = fxdr_unsigned(int, *(tl + 6)); 858 } 859 if (reqlen > NFS_SRVMAXDATA(nd)) { 860 reqlen = NFS_SRVMAXDATA(nd); 861 } else if (reqlen < 0) { 862 error = EBADRPC; 863 goto nfsmout; 864 } 865 gotproxystateid = 0; 866 if (nd->nd_flag & ND_NFSV4) { 867 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 868 lop->lo_flags = NFSLCK_READ; 869 stp->ls_ownerlen = 0; 870 stp->ls_op = NULL; 871 stp->ls_uid = nd->nd_cred->cr_uid; 872 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 873 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 874 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 875 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 876 if ((nd->nd_flag & ND_NFSV41) != 0) 877 clientid.qval = nd->nd_clientid.qval; 878 else if (nd->nd_clientid.qval != clientid.qval) 879 printf("EEK1 multiple clids\n"); 880 } else { 881 if ((nd->nd_flag & ND_NFSV41) != 0) 882 printf("EEK! no clientid from session\n"); 883 nd->nd_flag |= ND_IMPLIEDCLID; 884 nd->nd_clientid.qval = clientid.qval; 885 } 886 stp->ls_stateid.other[2] = *tl++; 887 /* 888 * Don't allow the client to use a special stateid for a DS op. 889 */ 890 if ((nd->nd_flag & ND_DSSERVER) != 0 && 891 ((stp->ls_stateid.other[0] == 0x0 && 892 stp->ls_stateid.other[1] == 0x0 && 893 stp->ls_stateid.other[2] == 0x0) || 894 (stp->ls_stateid.other[0] == 0xffffffff && 895 stp->ls_stateid.other[1] == 0xffffffff && 896 stp->ls_stateid.other[2] == 0xffffffff) || 897 stp->ls_stateid.seqid != 0)) 898 nd->nd_repstat = NFSERR_BADSTATEID; 899 /* However, allow the proxy stateid. */ 900 if (stp->ls_stateid.seqid == 0xffffffff && 901 stp->ls_stateid.other[0] == 0x55555555 && 902 stp->ls_stateid.other[1] == 0x55555555 && 903 stp->ls_stateid.other[2] == 0x55555555) 904 gotproxystateid = 1; 905 off = fxdr_hyper(tl); 906 lop->lo_first = off; 907 tl += 2; 908 lop->lo_end = off + reqlen; 909 /* 910 * Paranoia, just in case it wraps around. 911 */ 912 if (lop->lo_end < off) 913 lop->lo_end = NFS64BITSSET; 914 } 915 if (vp->v_type != VREG) { 916 if (nd->nd_flag & ND_NFSV3) 917 nd->nd_repstat = EINVAL; 918 else 919 nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR : 920 EINVAL; 921 } 922 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 923 if (!nd->nd_repstat) 924 nd->nd_repstat = getret; 925 if (!nd->nd_repstat && 926 (nva.na_uid != nd->nd_cred->cr_uid || 927 NFSVNO_EXSTRICTACCESS(exp))) { 928 nd->nd_repstat = nfsvno_accchk(vp, VREAD, 929 nd->nd_cred, exp, p, 930 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 931 if (nd->nd_repstat) 932 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 933 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 934 NFSACCCHK_VPISLOCKED, NULL); 935 } 936 /* 937 * DS reads are marked by ND_DSSERVER or use the proxy special 938 * stateid. 939 */ 940 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == 941 ND_NFSV4 && gotproxystateid == 0) 942 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 943 &stateid, exp, nd, p); 944 if (nd->nd_repstat) { 945 vput(vp); 946 if (nd->nd_flag & ND_NFSV3) 947 nfsrv_postopattr(nd, getret, &nva); 948 goto out; 949 } 950 if (off >= nva.na_size) { 951 cnt = 0; 952 eof = 1; 953 } else if (reqlen == 0) 954 cnt = 0; 955 else if ((off + reqlen) >= nva.na_size) { 956 cnt = nva.na_size - off; 957 eof = 1; 958 } else 959 cnt = reqlen; 960 m3 = NULL; 961 if (cnt > 0) { 962 /* 963 * If cnt > MCLBYTES and the reply will not be saved, use 964 * ext_pgs mbufs for TLS. 965 * For NFSv4.0, we do not know for sure if the reply will 966 * be saved, so do not use ext_pgs mbufs for NFSv4.0. 967 * Always use ext_pgs mbufs if ND_EXTPG is set. 968 */ 969 if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES && 970 (nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS && 971 (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4)) 972 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, 973 nd->nd_maxextsiz, p, &m3, &m2); 974 else 975 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, 976 0, p, &m3, &m2); 977 if (!(nd->nd_flag & ND_NFSV4)) { 978 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 979 if (!nd->nd_repstat) 980 nd->nd_repstat = getret; 981 } 982 if (nd->nd_repstat) { 983 vput(vp); 984 if (m3) 985 m_freem(m3); 986 if (nd->nd_flag & ND_NFSV3) 987 nfsrv_postopattr(nd, getret, &nva); 988 goto out; 989 } 990 } 991 vput(vp); 992 if (nd->nd_flag & ND_NFSV2) { 993 nfsrv_fillattr(nd, &nva); 994 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 995 } else { 996 if (nd->nd_flag & ND_NFSV3) { 997 nfsrv_postopattr(nd, getret, &nva); 998 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 999 *tl++ = txdr_unsigned(cnt); 1000 } else 1001 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1002 if (eof) 1003 *tl++ = newnfs_true; 1004 else 1005 *tl++ = newnfs_false; 1006 } 1007 *tl = txdr_unsigned(cnt); 1008 if (m3) { 1009 nd->nd_mb->m_next = m3; 1010 nd->nd_mb = m2; 1011 if ((m2->m_flags & M_EXTPG) != 0) { 1012 nd->nd_flag |= ND_EXTPG; 1013 nd->nd_bextpg = m2->m_epg_npgs - 1; 1014 nd->nd_bpos = (char *)(void *) 1015 PHYS_TO_DMAP(m2->m_epg_pa[nd->nd_bextpg]); 1016 poff = (nd->nd_bextpg == 0) ? m2->m_epg_1st_off : 0; 1017 nd->nd_bpos += poff + m2->m_epg_last_len; 1018 nd->nd_bextpgsiz = PAGE_SIZE - m2->m_epg_last_len - 1019 poff; 1020 } else 1021 nd->nd_bpos = mtod(m2, char *) + m2->m_len; 1022 } 1023 1024 out: 1025 NFSEXITCODE2(0, nd); 1026 return (0); 1027 nfsmout: 1028 vput(vp); 1029 NFSEXITCODE2(error, nd); 1030 return (error); 1031 } 1032 1033 /* 1034 * nfs write service 1035 */ 1036 int 1037 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram, 1038 vnode_t vp, struct nfsexstuff *exp) 1039 { 1040 u_int32_t *tl; 1041 struct nfsvattr nva, forat; 1042 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1; 1043 int gotproxystateid, stable = NFSWRITE_FILESYNC; 1044 off_t off; 1045 struct nfsstate st, *stp = &st; 1046 struct nfslock lo, *lop = &lo; 1047 nfsv4stateid_t stateid; 1048 nfsquad_t clientid; 1049 nfsattrbit_t attrbits; 1050 struct thread *p = curthread; 1051 1052 if (nd->nd_repstat) { 1053 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 1054 goto out; 1055 } 1056 gotproxystateid = 0; 1057 if (nd->nd_flag & ND_NFSV2) { 1058 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1059 off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 1060 tl += 2; 1061 retlen = len = fxdr_unsigned(int32_t, *tl); 1062 } else if (nd->nd_flag & ND_NFSV3) { 1063 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1064 off = fxdr_hyper(tl); 1065 tl += 3; 1066 stable = fxdr_unsigned(int, *tl++); 1067 retlen = len = fxdr_unsigned(int32_t, *tl); 1068 } else { 1069 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED); 1070 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 1071 lop->lo_flags = NFSLCK_WRITE; 1072 stp->ls_ownerlen = 0; 1073 stp->ls_op = NULL; 1074 stp->ls_uid = nd->nd_cred->cr_uid; 1075 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 1076 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 1077 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 1078 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 1079 if ((nd->nd_flag & ND_NFSV41) != 0) 1080 clientid.qval = nd->nd_clientid.qval; 1081 else if (nd->nd_clientid.qval != clientid.qval) 1082 printf("EEK2 multiple clids\n"); 1083 } else { 1084 if ((nd->nd_flag & ND_NFSV41) != 0) 1085 printf("EEK! no clientid from session\n"); 1086 nd->nd_flag |= ND_IMPLIEDCLID; 1087 nd->nd_clientid.qval = clientid.qval; 1088 } 1089 stp->ls_stateid.other[2] = *tl++; 1090 /* 1091 * Don't allow the client to use a special stateid for a DS op. 1092 */ 1093 if ((nd->nd_flag & ND_DSSERVER) != 0 && 1094 ((stp->ls_stateid.other[0] == 0x0 && 1095 stp->ls_stateid.other[1] == 0x0 && 1096 stp->ls_stateid.other[2] == 0x0) || 1097 (stp->ls_stateid.other[0] == 0xffffffff && 1098 stp->ls_stateid.other[1] == 0xffffffff && 1099 stp->ls_stateid.other[2] == 0xffffffff) || 1100 stp->ls_stateid.seqid != 0)) 1101 nd->nd_repstat = NFSERR_BADSTATEID; 1102 /* However, allow the proxy stateid. */ 1103 if (stp->ls_stateid.seqid == 0xffffffff && 1104 stp->ls_stateid.other[0] == 0x55555555 && 1105 stp->ls_stateid.other[1] == 0x55555555 && 1106 stp->ls_stateid.other[2] == 0x55555555) 1107 gotproxystateid = 1; 1108 off = fxdr_hyper(tl); 1109 lop->lo_first = off; 1110 tl += 2; 1111 stable = fxdr_unsigned(int, *tl++); 1112 retlen = len = fxdr_unsigned(int32_t, *tl); 1113 lop->lo_end = off + len; 1114 /* 1115 * Paranoia, just in case it wraps around, which shouldn't 1116 * ever happen anyhow. 1117 */ 1118 if (lop->lo_end < lop->lo_first) 1119 lop->lo_end = NFS64BITSSET; 1120 } 1121 1122 if (retlen > nfs_srvmaxio || retlen < 0) 1123 nd->nd_repstat = EIO; 1124 if (vp->v_type != VREG && !nd->nd_repstat) { 1125 if (nd->nd_flag & ND_NFSV3) 1126 nd->nd_repstat = EINVAL; 1127 else 1128 nd->nd_repstat = (vp->v_type == VDIR) ? EISDIR : 1129 EINVAL; 1130 } 1131 NFSZERO_ATTRBIT(&attrbits); 1132 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 1133 forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits); 1134 if (!nd->nd_repstat) 1135 nd->nd_repstat = forat_ret; 1136 if (!nd->nd_repstat && 1137 (forat.na_uid != nd->nd_cred->cr_uid || 1138 NFSVNO_EXSTRICTACCESS(exp))) 1139 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 1140 nd->nd_cred, exp, p, 1141 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 1142 /* 1143 * DS reads are marked by ND_DSSERVER or use the proxy special 1144 * stateid. 1145 */ 1146 if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) == 1147 ND_NFSV4 && gotproxystateid == 0) 1148 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 1149 &stateid, exp, nd, p); 1150 if (nd->nd_repstat) { 1151 vput(vp); 1152 if (nd->nd_flag & ND_NFSV3) 1153 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 1154 goto out; 1155 } 1156 1157 /* 1158 * For NFS Version 2, it is not obvious what a write of zero length 1159 * should do, but I might as well be consistent with Version 3, 1160 * which is to return ok so long as there are no permission problems. 1161 */ 1162 if (retlen > 0) { 1163 nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable, 1164 nd->nd_md, nd->nd_dpos, nd->nd_cred, p); 1165 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1); 1166 if (error) 1167 goto nfsmout; 1168 } 1169 if (nd->nd_flag & ND_NFSV4) 1170 aftat_ret = 0; 1171 else 1172 aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 1173 vput(vp); 1174 if (!nd->nd_repstat) 1175 nd->nd_repstat = aftat_ret; 1176 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1177 if (nd->nd_flag & ND_NFSV3) 1178 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 1179 if (nd->nd_repstat) 1180 goto out; 1181 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1182 *tl++ = txdr_unsigned(retlen); 1183 /* 1184 * If nfs_async is set, then pretend the write was FILESYNC. 1185 * Warning: Doing this violates RFC1813 and runs a risk 1186 * of data written by a client being lost when the server 1187 * crashes/reboots. 1188 */ 1189 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0) 1190 *tl++ = txdr_unsigned(stable); 1191 else 1192 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); 1193 /* 1194 * Actually, there is no need to txdr these fields, 1195 * but it may make the values more human readable, 1196 * for debugging purposes. 1197 */ 1198 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 1199 *tl = txdr_unsigned(nfsboottime.tv_usec); 1200 } else if (!nd->nd_repstat) 1201 nfsrv_fillattr(nd, &nva); 1202 1203 out: 1204 NFSEXITCODE2(0, nd); 1205 return (0); 1206 nfsmout: 1207 vput(vp); 1208 NFSEXITCODE2(error, nd); 1209 return (error); 1210 } 1211 1212 /* 1213 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.) 1214 * now does a truncate to 0 length via. setattr if it already exists 1215 * The core creation routine has been extracted out into nfsrv_creatsub(), 1216 * so it can also be used by nfsrv_open() for V4. 1217 */ 1218 int 1219 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, 1220 vnode_t dp, struct nfsexstuff *exp) 1221 { 1222 struct nfsvattr nva, dirfor, diraft; 1223 struct nfsv2_sattr *sp; 1224 struct nameidata named; 1225 u_int32_t *tl; 1226 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1; 1227 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0; 1228 NFSDEV_T rdev = 0; 1229 vnode_t vp = NULL, dirp = NULL; 1230 fhandle_t fh; 1231 char *bufp; 1232 u_long *hashp; 1233 __enum_uint8(vtype) vtyp; 1234 int32_t cverf[2], tverf[2] = { 0, 0 }; 1235 struct thread *p = curthread; 1236 1237 if (nd->nd_repstat) { 1238 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1239 goto out; 1240 } 1241 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1242 LOCKPARENT | LOCKLEAF | NOCACHE); 1243 nfsvno_setpathbuf(&named, &bufp, &hashp); 1244 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1245 if (error) 1246 goto nfsmout; 1247 if (!nd->nd_repstat) { 1248 NFSVNO_ATTRINIT(&nva); 1249 if (nd->nd_flag & ND_NFSV2) { 1250 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 1251 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 1252 if (vtyp == VNON) 1253 vtyp = VREG; 1254 NFSVNO_SETATTRVAL(&nva, type, vtyp); 1255 NFSVNO_SETATTRVAL(&nva, mode, 1256 nfstov_mode(sp->sa_mode)); 1257 switch (nva.na_type) { 1258 case VREG: 1259 tsize = fxdr_unsigned(int32_t, sp->sa_size); 1260 if (tsize != -1) 1261 NFSVNO_SETATTRVAL(&nva, size, 1262 (u_quad_t)tsize); 1263 break; 1264 case VCHR: 1265 case VBLK: 1266 case VFIFO: 1267 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size); 1268 break; 1269 default: 1270 break; 1271 } 1272 } else { 1273 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1274 how = fxdr_unsigned(int, *tl); 1275 switch (how) { 1276 case NFSCREATE_GUARDED: 1277 case NFSCREATE_UNCHECKED: 1278 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 1279 if (error) 1280 goto nfsmout; 1281 break; 1282 case NFSCREATE_EXCLUSIVE: 1283 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 1284 cverf[0] = *tl++; 1285 cverf[1] = *tl; 1286 exclusive_flag = 1; 1287 break; 1288 } 1289 NFSVNO_SETATTRVAL(&nva, type, VREG); 1290 } 1291 } 1292 if (nd->nd_repstat) { 1293 nfsvno_relpathbuf(&named); 1294 if (nd->nd_flag & ND_NFSV3) { 1295 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1, 1296 NULL); 1297 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1298 &diraft); 1299 } 1300 vput(dp); 1301 goto out; 1302 } 1303 1304 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); 1305 if (dirp) { 1306 if (nd->nd_flag & ND_NFSV2) { 1307 vrele(dirp); 1308 dirp = NULL; 1309 } else { 1310 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 1311 NULL); 1312 } 1313 } 1314 if (nd->nd_repstat) { 1315 if (nd->nd_flag & ND_NFSV3) 1316 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1317 &diraft); 1318 if (dirp) 1319 vrele(dirp); 1320 goto out; 1321 } 1322 1323 if (!(nd->nd_flag & ND_NFSV2)) { 1324 switch (how) { 1325 case NFSCREATE_GUARDED: 1326 if (named.ni_vp) 1327 nd->nd_repstat = EEXIST; 1328 break; 1329 case NFSCREATE_UNCHECKED: 1330 break; 1331 case NFSCREATE_EXCLUSIVE: 1332 if (named.ni_vp == NULL) 1333 NFSVNO_SETATTRVAL(&nva, mode, 0); 1334 break; 1335 } 1336 } 1337 1338 /* 1339 * Iff doesn't exist, create it 1340 * otherwise just truncate to 0 length 1341 * should I set the mode too ? 1342 */ 1343 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, 1344 &exclusive_flag, cverf, rdev, exp); 1345 1346 if (!nd->nd_repstat) { 1347 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 1348 if (!nd->nd_repstat) 1349 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, 1350 NULL); 1351 vput(vp); 1352 if (!nd->nd_repstat) { 1353 tverf[0] = nva.na_atime.tv_sec; 1354 tverf[1] = nva.na_atime.tv_nsec; 1355 } 1356 } 1357 if (nd->nd_flag & ND_NFSV2) { 1358 if (!nd->nd_repstat) { 1359 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 0); 1360 nfsrv_fillattr(nd, &nva); 1361 } 1362 } else { 1363 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0] 1364 || cverf[1] != tverf[1])) 1365 nd->nd_repstat = EEXIST; 1366 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 1367 vrele(dirp); 1368 if (!nd->nd_repstat) { 1369 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, 0, 1); 1370 nfsrv_postopattr(nd, 0, &nva); 1371 } 1372 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1373 } 1374 1375 out: 1376 NFSEXITCODE2(0, nd); 1377 return (0); 1378 nfsmout: 1379 vput(dp); 1380 nfsvno_relpathbuf(&named); 1381 NFSEXITCODE2(error, nd); 1382 return (error); 1383 } 1384 1385 /* 1386 * nfs v3 mknod service (and v4 create) 1387 */ 1388 int 1389 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, 1390 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 1391 { 1392 struct nfsvattr nva, dirfor, diraft; 1393 u_int32_t *tl; 1394 struct nameidata named; 1395 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 1396 u_int32_t major, minor; 1397 __enum_uint8(vtype) vtyp = VNON; 1398 nfstype nfs4type = NFNON; 1399 vnode_t vp, dirp = NULL; 1400 nfsattrbit_t attrbits; 1401 char *bufp = NULL, *pathcp = NULL; 1402 u_long *hashp, cnflags; 1403 NFSACL_T *aclp = NULL; 1404 struct thread *p = curthread; 1405 1406 NFSVNO_ATTRINIT(&nva); 1407 cnflags = LOCKPARENT; 1408 if (nd->nd_repstat) { 1409 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1410 goto out; 1411 } 1412 #ifdef NFS4_ACL_EXTATTR_NAME 1413 aclp = acl_alloc(M_WAITOK); 1414 aclp->acl_cnt = 0; 1415 #endif 1416 1417 /* 1418 * For V4, the creation stuff is here, Yuck! 1419 */ 1420 if (nd->nd_flag & ND_NFSV4) { 1421 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1422 vtyp = nfsv34tov_type(*tl); 1423 nfs4type = fxdr_unsigned(nfstype, *tl); 1424 if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0) { 1425 /* 1426 * Don't allow creation of non-regular file objects 1427 * in a named attribute directory. 1428 */ 1429 nd->nd_repstat = NFSERR_INVAL; 1430 vrele(dp); 1431 #ifdef NFS4_ACL_EXTATTR_NAME 1432 acl_free(aclp); 1433 #endif 1434 goto out; 1435 } 1436 switch (nfs4type) { 1437 case NFLNK: 1438 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, 1439 &pathlen); 1440 if (error) 1441 goto nfsmout; 1442 break; 1443 case NFCHR: 1444 case NFBLK: 1445 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1446 major = fxdr_unsigned(u_int32_t, *tl++); 1447 minor = fxdr_unsigned(u_int32_t, *tl); 1448 nva.na_rdev = NFSMAKEDEV(major, minor); 1449 break; 1450 case NFSOCK: 1451 case NFFIFO: 1452 break; 1453 case NFDIR: 1454 cnflags = LOCKPARENT; 1455 break; 1456 default: 1457 nd->nd_repstat = NFSERR_BADTYPE; 1458 vrele(dp); 1459 #ifdef NFS4_ACL_EXTATTR_NAME 1460 acl_free(aclp); 1461 #endif 1462 goto out; 1463 } 1464 } 1465 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE); 1466 nfsvno_setpathbuf(&named, &bufp, &hashp); 1467 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1468 if (error) 1469 goto nfsmout; 1470 if (!nd->nd_repstat) { 1471 if (nd->nd_flag & ND_NFSV3) { 1472 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1473 vtyp = nfsv34tov_type(*tl); 1474 } 1475 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p); 1476 if (error) 1477 goto nfsmout; 1478 nva.na_type = vtyp; 1479 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 1480 (vtyp == VCHR || vtyp == VBLK)) { 1481 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1482 major = fxdr_unsigned(u_int32_t, *tl++); 1483 minor = fxdr_unsigned(u_int32_t, *tl); 1484 nva.na_rdev = NFSMAKEDEV(major, minor); 1485 } 1486 } 1487 1488 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 1489 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 1490 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && 1491 dirfor.na_gid == nva.na_gid) 1492 NFSVNO_UNSET(&nva, gid); 1493 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 1494 } 1495 if (nd->nd_repstat) { 1496 vrele(dp); 1497 #ifdef NFS4_ACL_EXTATTR_NAME 1498 acl_free(aclp); 1499 #endif 1500 nfsvno_relpathbuf(&named); 1501 if (pathcp) 1502 free(pathcp, M_TEMP); 1503 if (nd->nd_flag & ND_NFSV3) 1504 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1505 &diraft); 1506 goto out; 1507 } 1508 1509 /* 1510 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill 1511 * in va_mode, so we'll have to set a default here. 1512 */ 1513 if (NFSVNO_NOTSETMODE(&nva)) { 1514 if (vtyp == VLNK) 1515 nva.na_mode = 0755; 1516 else 1517 nva.na_mode = 0400; 1518 } 1519 1520 if (vtyp == VDIR) 1521 named.ni_cnd.cn_flags |= WILLBEDIR; 1522 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); 1523 if (nd->nd_repstat) { 1524 if (dirp) { 1525 if (nd->nd_flag & ND_NFSV3) 1526 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, 1527 p, 0, NULL); 1528 vrele(dirp); 1529 } 1530 #ifdef NFS4_ACL_EXTATTR_NAME 1531 acl_free(aclp); 1532 #endif 1533 if (nd->nd_flag & ND_NFSV3) 1534 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1535 &diraft); 1536 goto out; 1537 } 1538 if (dirp) 1539 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 1540 1541 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { 1542 if (vtyp == VDIR) { 1543 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, 1544 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, 1545 exp); 1546 #ifdef NFS4_ACL_EXTATTR_NAME 1547 acl_free(aclp); 1548 #endif 1549 goto out; 1550 } else if (vtyp == VLNK) { 1551 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1552 &dirfor, &diraft, &diraft_ret, &attrbits, 1553 aclp, p, exp, pathcp, pathlen); 1554 #ifdef NFS4_ACL_EXTATTR_NAME 1555 acl_free(aclp); 1556 #endif 1557 free(pathcp, M_TEMP); 1558 goto out; 1559 } 1560 } 1561 1562 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); 1563 if (!nd->nd_repstat) { 1564 vp = named.ni_vp; 1565 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); 1566 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 1567 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) 1568 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, 1569 NULL); 1570 if (vpp != NULL && nd->nd_repstat == 0) { 1571 NFSVOPUNLOCK(vp); 1572 *vpp = vp; 1573 } else 1574 vput(vp); 1575 } 1576 1577 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 1578 vrele(dirp); 1579 if (!nd->nd_repstat) { 1580 if (nd->nd_flag & ND_NFSV3) { 1581 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1); 1582 nfsrv_postopattr(nd, 0, &nva); 1583 } else { 1584 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1585 *tl++ = newnfs_false; 1586 txdr_hyper(dirfor.na_filerev, tl); 1587 tl += 2; 1588 txdr_hyper(diraft.na_filerev, tl); 1589 (void) nfsrv_putattrbit(nd, &attrbits); 1590 } 1591 } 1592 if (nd->nd_flag & ND_NFSV3) 1593 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1594 #ifdef NFS4_ACL_EXTATTR_NAME 1595 acl_free(aclp); 1596 #endif 1597 1598 out: 1599 NFSEXITCODE2(0, nd); 1600 return (0); 1601 nfsmout: 1602 vrele(dp); 1603 #ifdef NFS4_ACL_EXTATTR_NAME 1604 acl_free(aclp); 1605 #endif 1606 if (bufp) 1607 nfsvno_relpathbuf(&named); 1608 if (pathcp) 1609 free(pathcp, M_TEMP); 1610 1611 NFSEXITCODE2(error, nd); 1612 return (error); 1613 } 1614 1615 /* 1616 * nfs remove service 1617 */ 1618 int 1619 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, 1620 vnode_t dp, struct nfsexstuff *exp) 1621 { 1622 struct nameidata named; 1623 u_int32_t *tl; 1624 int error = 0, dirfor_ret = 1, diraft_ret = 1; 1625 vnode_t dirp = NULL; 1626 struct nfsvattr dirfor, diraft; 1627 char *bufp; 1628 u_long *hashp; 1629 struct thread *p = curthread; 1630 1631 if (nd->nd_repstat) { 1632 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1633 goto out; 1634 } 1635 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, 1636 LOCKPARENT | LOCKLEAF); 1637 nfsvno_setpathbuf(&named, &bufp, &hashp); 1638 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1639 if (error) { 1640 vput(dp); 1641 nfsvno_relpathbuf(&named); 1642 goto out; 1643 } 1644 if (!nd->nd_repstat) { 1645 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); 1646 } else { 1647 vput(dp); 1648 nfsvno_relpathbuf(&named); 1649 } 1650 if (dirp) { 1651 if (!(nd->nd_flag & ND_NFSV2)) { 1652 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 1653 NULL); 1654 } else { 1655 vrele(dirp); 1656 dirp = NULL; 1657 } 1658 } 1659 if (!nd->nd_repstat) { 1660 if (nd->nd_flag & ND_NFSV4) { 1661 if (named.ni_vp->v_type == VDIR) 1662 nd->nd_repstat = nfsvno_rmdirsub(&named, 1, 1663 nd->nd_cred, p, exp); 1664 else 1665 nd->nd_repstat = nfsvno_removesub(&named, true, 1666 nd, p, exp); 1667 } else if (nd->nd_procnum == NFSPROC_RMDIR) { 1668 nd->nd_repstat = nfsvno_rmdirsub(&named, 0, 1669 nd->nd_cred, p, exp); 1670 } else { 1671 nd->nd_repstat = nfsvno_removesub(&named, false, nd, p, 1672 exp); 1673 } 1674 } 1675 if (!(nd->nd_flag & ND_NFSV2)) { 1676 if (dirp) { 1677 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, 1678 NULL); 1679 vrele(dirp); 1680 } 1681 if (nd->nd_flag & ND_NFSV3) { 1682 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1683 &diraft); 1684 } else if (!nd->nd_repstat) { 1685 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1686 *tl++ = newnfs_false; 1687 txdr_hyper(dirfor.na_filerev, tl); 1688 tl += 2; 1689 txdr_hyper(diraft.na_filerev, tl); 1690 } 1691 } 1692 1693 out: 1694 NFSEXITCODE2(error, nd); 1695 return (error); 1696 } 1697 1698 /* 1699 * nfs rename service 1700 */ 1701 int 1702 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, 1703 vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 1704 { 1705 u_int32_t *tl; 1706 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1; 1707 int tdirfor_ret = 1, tdiraft_ret = 1; 1708 struct nameidata fromnd, tond; 1709 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; 1710 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; 1711 struct nfsexstuff tnes; 1712 struct nfsrvfh tfh; 1713 char *bufp, *tbufp = NULL; 1714 u_long *hashp; 1715 fhandle_t fh; 1716 struct thread *p = curthread; 1717 1718 if (nd->nd_repstat) { 1719 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1720 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1721 goto out; 1722 } 1723 if (!(nd->nd_flag & ND_NFSV2)) 1724 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL); 1725 tond.ni_cnd.cn_nameiop = 0; 1726 tond.ni_startdir = NULL; 1727 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT); 1728 nfsvno_setpathbuf(&fromnd, &bufp, &hashp); 1729 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); 1730 if (error) { 1731 vput(dp); 1732 if (todp) 1733 vrele(todp); 1734 nfsvno_relpathbuf(&fromnd); 1735 goto out; 1736 } 1737 /* 1738 * Unlock dp in this code section, so it is unlocked before 1739 * tdp gets locked. This avoids a potential LOR if tdp is the 1740 * parent directory of dp. 1741 */ 1742 if (nd->nd_flag & ND_NFSV4) { 1743 tdp = todp; 1744 tnes = *toexp; 1745 if (dp != tdp) { 1746 NFSVOPUNLOCK(dp); 1747 /* Might lock tdp. */ 1748 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0, 1749 NULL); 1750 } else { 1751 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, 1752 NULL); 1753 NFSVOPUNLOCK(dp); 1754 } 1755 } else { 1756 tfh.nfsrvfh_len = 0; 1757 error = nfsrv_mtofh(nd, &tfh); 1758 if (error == 0) 1759 error = nfsvno_getfh(dp, &fh, p); 1760 if (error) { 1761 vput(dp); 1762 /* todp is always NULL except NFSv4 */ 1763 nfsvno_relpathbuf(&fromnd); 1764 goto out; 1765 } 1766 1767 /* If this is the same file handle, just VREF() the vnode. */ 1768 if (!NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) { 1769 vref(dp); 1770 tdp = dp; 1771 tnes = *exp; 1772 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1, 1773 NULL); 1774 NFSVOPUNLOCK(dp); 1775 } else { 1776 NFSVOPUNLOCK(dp); 1777 nd->nd_cred->cr_uid = nd->nd_saveduid; 1778 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 1779 0, -1); /* Locks tdp. */ 1780 if (tdp) { 1781 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, 1782 p, 1, NULL); 1783 NFSVOPUNLOCK(tdp); 1784 } 1785 } 1786 } 1787 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE); 1788 nfsvno_setpathbuf(&tond, &tbufp, &hashp); 1789 if (!nd->nd_repstat) { 1790 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); 1791 if (error) { 1792 if (tdp) 1793 vrele(tdp); 1794 vrele(dp); 1795 nfsvno_relpathbuf(&fromnd); 1796 nfsvno_relpathbuf(&tond); 1797 goto out; 1798 } 1799 } 1800 if (nd->nd_repstat) { 1801 if (nd->nd_flag & ND_NFSV3) { 1802 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 1803 &fdiraft); 1804 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 1805 &tdiraft); 1806 } 1807 if (tdp) 1808 vrele(tdp); 1809 vrele(dp); 1810 nfsvno_relpathbuf(&fromnd); 1811 nfsvno_relpathbuf(&tond); 1812 goto out; 1813 } 1814 1815 /* 1816 * Done parsing, now down to business. 1817 */ 1818 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, &fdirp); 1819 if (nd->nd_repstat) { 1820 if (nd->nd_flag & ND_NFSV3) { 1821 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 1822 &fdiraft); 1823 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 1824 &tdiraft); 1825 } 1826 if (fdirp) 1827 vrele(fdirp); 1828 if (tdp) 1829 vrele(tdp); 1830 nfsvno_relpathbuf(&tond); 1831 goto out; 1832 } 1833 if (fromnd.ni_vp->v_type == VDIR) 1834 tond.ni_cnd.cn_flags |= WILLBEDIR; 1835 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, &tdirp); 1836 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd, p); 1837 if (fdirp) 1838 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL); 1839 if (tdirp) 1840 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL); 1841 if (fdirp) 1842 vrele(fdirp); 1843 if (tdirp) 1844 vrele(tdirp); 1845 if (nd->nd_flag & ND_NFSV3) { 1846 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1847 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1848 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1849 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 1850 *tl++ = newnfs_false; 1851 txdr_hyper(fdirfor.na_filerev, tl); 1852 tl += 2; 1853 txdr_hyper(fdiraft.na_filerev, tl); 1854 tl += 2; 1855 *tl++ = newnfs_false; 1856 txdr_hyper(tdirfor.na_filerev, tl); 1857 tl += 2; 1858 txdr_hyper(tdiraft.na_filerev, tl); 1859 } 1860 1861 out: 1862 NFSEXITCODE2(error, nd); 1863 return (error); 1864 } 1865 1866 /* 1867 * nfs link service 1868 */ 1869 int 1870 nfsrvd_link(struct nfsrv_descript *nd, int isdgram, 1871 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 1872 { 1873 struct nameidata named; 1874 u_int32_t *tl; 1875 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; 1876 vnode_t dirp = NULL, dp = NULL; 1877 struct nfsvattr dirfor, diraft, at; 1878 struct nfsexstuff tnes; 1879 struct nfsrvfh dfh; 1880 char *bufp; 1881 u_long *hashp; 1882 struct thread *p = curthread; 1883 nfsquad_t clientid; 1884 1885 if (nd->nd_repstat) { 1886 nfsrv_postopattr(nd, getret, &at); 1887 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1888 goto out; 1889 } 1890 if ((vn_irflag_read(vp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0 || 1891 (tovp != NULL && 1892 (vn_irflag_read(tovp) & (VIRF_NAMEDDIR | VIRF_NAMEDATTR)) != 0)) { 1893 nd->nd_repstat = NFSERR_INVAL; 1894 if (tovp != NULL) 1895 vrele(tovp); 1896 } 1897 NFSVOPUNLOCK(vp); 1898 if (!nd->nd_repstat && vp->v_type == VDIR) { 1899 if (nd->nd_flag & ND_NFSV4) 1900 nd->nd_repstat = NFSERR_ISDIR; 1901 else 1902 nd->nd_repstat = NFSERR_INVAL; 1903 if (tovp) 1904 vrele(tovp); 1905 } 1906 if (!nd->nd_repstat) { 1907 if (nd->nd_flag & ND_NFSV4) { 1908 dp = tovp; 1909 tnes = *toexp; 1910 } else { 1911 error = nfsrv_mtofh(nd, &dfh); 1912 if (error) { 1913 vrele(vp); 1914 /* tovp is always NULL unless NFSv4 */ 1915 goto out; 1916 } 1917 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 1918 0, -1); 1919 if (dp) 1920 NFSVOPUNLOCK(dp); 1921 } 1922 } 1923 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE); 1924 if (!nd->nd_repstat) { 1925 nfsvno_setpathbuf(&named, &bufp, &hashp); 1926 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1927 if (error) { 1928 vrele(vp); 1929 if (dp) 1930 vrele(dp); 1931 nfsvno_relpathbuf(&named); 1932 goto out; 1933 } 1934 if (!nd->nd_repstat) { 1935 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 1936 &dirp); 1937 } else { 1938 if (dp) 1939 vrele(dp); 1940 nfsvno_relpathbuf(&named); 1941 } 1942 } 1943 if (dirp) { 1944 if (nd->nd_flag & ND_NFSV2) { 1945 vrele(dirp); 1946 dirp = NULL; 1947 } else { 1948 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 1949 NULL); 1950 } 1951 } 1952 if (!nd->nd_repstat) { 1953 clientid.qval = 0; 1954 if ((nd->nd_flag & (ND_IMPLIEDCLID | ND_NFSV41)) == 1955 (ND_IMPLIEDCLID | ND_NFSV41)) 1956 clientid.qval = nd->nd_clientid.qval; 1957 nd->nd_repstat = nfsvno_link(&named, vp, clientid, nd->nd_cred, 1958 p, exp); 1959 } 1960 if (nd->nd_flag & ND_NFSV3) 1961 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL); 1962 if (dirp) { 1963 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 1964 vrele(dirp); 1965 } 1966 vrele(vp); 1967 if (nd->nd_flag & ND_NFSV3) { 1968 nfsrv_postopattr(nd, getret, &at); 1969 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1970 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1971 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1972 *tl++ = newnfs_false; 1973 txdr_hyper(dirfor.na_filerev, tl); 1974 tl += 2; 1975 txdr_hyper(diraft.na_filerev, tl); 1976 } 1977 1978 out: 1979 NFSEXITCODE2(error, nd); 1980 return (error); 1981 } 1982 1983 /* 1984 * nfs symbolic link service 1985 */ 1986 int 1987 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1988 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 1989 { 1990 struct nfsvattr nva, dirfor, diraft; 1991 struct nameidata named; 1992 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 1993 vnode_t dirp = NULL; 1994 char *bufp, *pathcp = NULL; 1995 u_long *hashp; 1996 struct thread *p = curthread; 1997 1998 if (nd->nd_repstat) { 1999 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 2000 goto out; 2001 } 2002 if (vpp) 2003 *vpp = NULL; 2004 NFSVNO_ATTRINIT(&nva); 2005 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 2006 LOCKPARENT | NOCACHE); 2007 nfsvno_setpathbuf(&named, &bufp, &hashp); 2008 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2009 if (!error && !nd->nd_repstat) 2010 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 2011 if (error) { 2012 vrele(dp); 2013 nfsvno_relpathbuf(&named); 2014 goto out; 2015 } 2016 if (!nd->nd_repstat) { 2017 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); 2018 } else { 2019 vrele(dp); 2020 nfsvno_relpathbuf(&named); 2021 } 2022 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 2023 vrele(dirp); 2024 dirp = NULL; 2025 } 2026 2027 /* 2028 * And call nfsrvd_symlinksub() to do the common code. It will 2029 * return EBADRPC upon a parsing error, 0 otherwise. 2030 */ 2031 if (!nd->nd_repstat) { 2032 if (dirp != NULL) 2033 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 2034 NULL); 2035 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 2036 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 2037 pathcp, pathlen); 2038 } else if (dirp != NULL) { 2039 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 2040 vrele(dirp); 2041 } 2042 if (pathcp) 2043 free(pathcp, M_TEMP); 2044 2045 if (nd->nd_flag & ND_NFSV3) { 2046 if (!nd->nd_repstat) { 2047 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1); 2048 nfsrv_postopattr(nd, 0, &nva); 2049 } 2050 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 2051 } 2052 2053 out: 2054 NFSEXITCODE2(error, nd); 2055 return (error); 2056 } 2057 2058 /* 2059 * Common code for creating a symbolic link. 2060 */ 2061 static void 2062 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 2063 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 2064 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 2065 int *diraft_retp, nfsattrbit_t *attrbitp, 2066 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 2067 int pathlen) 2068 { 2069 u_int32_t *tl; 2070 2071 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 2072 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 2073 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 2074 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 2075 if (nd->nd_flag & ND_NFSV3) { 2076 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 2077 if (!nd->nd_repstat) 2078 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 2079 nvap, nd, p, 1, NULL); 2080 } 2081 if (vpp != NULL && nd->nd_repstat == 0) { 2082 NFSVOPUNLOCK(ndp->ni_vp); 2083 *vpp = ndp->ni_vp; 2084 } else 2085 vput(ndp->ni_vp); 2086 } 2087 if (dirp) { 2088 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 2089 vrele(dirp); 2090 } 2091 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 2092 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2093 *tl++ = newnfs_false; 2094 txdr_hyper(dirforp->na_filerev, tl); 2095 tl += 2; 2096 txdr_hyper(diraftp->na_filerev, tl); 2097 (void) nfsrv_putattrbit(nd, attrbitp); 2098 } 2099 2100 NFSEXITCODE2(0, nd); 2101 } 2102 2103 /* 2104 * nfs mkdir service 2105 */ 2106 int 2107 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 2108 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 2109 { 2110 struct nfsvattr nva, dirfor, diraft; 2111 struct nameidata named; 2112 u_int32_t *tl; 2113 int error = 0, dirfor_ret = 1, diraft_ret = 1; 2114 vnode_t dirp = NULL; 2115 char *bufp; 2116 u_long *hashp; 2117 struct thread *p = curthread; 2118 2119 if (nd->nd_repstat) { 2120 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 2121 goto out; 2122 } 2123 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT | NOCACHE); 2124 nfsvno_setpathbuf(&named, &bufp, &hashp); 2125 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2126 if (error) 2127 goto nfsmout; 2128 if (!nd->nd_repstat) { 2129 NFSVNO_ATTRINIT(&nva); 2130 if (nd->nd_flag & ND_NFSV3) { 2131 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 2132 if (error) 2133 goto nfsmout; 2134 } else { 2135 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2136 nva.na_mode = nfstov_mode(*tl++); 2137 } 2138 } 2139 if (!nd->nd_repstat) { 2140 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, &dirp); 2141 } else { 2142 vrele(dp); 2143 nfsvno_relpathbuf(&named); 2144 } 2145 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 2146 vrele(dirp); 2147 dirp = NULL; 2148 } 2149 if (nd->nd_repstat) { 2150 if (dirp != NULL) { 2151 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 2152 NULL); 2153 vrele(dirp); 2154 } 2155 if (nd->nd_flag & ND_NFSV3) 2156 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 2157 &diraft); 2158 goto out; 2159 } 2160 if (dirp != NULL) 2161 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 2162 2163 /* 2164 * Call nfsrvd_mkdirsub() for the code common to V4 as well. 2165 */ 2166 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 2167 &diraft_ret, NULL, NULL, p, exp); 2168 2169 if (nd->nd_flag & ND_NFSV3) { 2170 if (!nd->nd_repstat) { 2171 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 1); 2172 nfsrv_postopattr(nd, 0, &nva); 2173 } 2174 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 2175 } else if (!nd->nd_repstat) { 2176 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)fhp, 0, 0); 2177 nfsrv_fillattr(nd, &nva); 2178 } 2179 2180 out: 2181 NFSEXITCODE2(0, nd); 2182 return (0); 2183 nfsmout: 2184 vrele(dp); 2185 nfsvno_relpathbuf(&named); 2186 NFSEXITCODE2(error, nd); 2187 return (error); 2188 } 2189 2190 /* 2191 * Code common to mkdir for V2,3 and 4. 2192 */ 2193 static void 2194 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 2195 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 2196 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 2197 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 2198 NFSPROC_T *p, struct nfsexstuff *exp) 2199 { 2200 vnode_t vp; 2201 u_int32_t *tl; 2202 2203 NFSVNO_SETATTRVAL(nvap, type, VDIR); 2204 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 2205 nd->nd_cred, p, exp); 2206 if (!nd->nd_repstat) { 2207 vp = ndp->ni_vp; 2208 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 2209 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 2210 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 2211 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1, 2212 NULL); 2213 if (vpp && !nd->nd_repstat) { 2214 NFSVOPUNLOCK(vp); 2215 *vpp = vp; 2216 } else { 2217 vput(vp); 2218 } 2219 } 2220 if (dirp) { 2221 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 2222 vrele(dirp); 2223 } 2224 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 2225 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2226 *tl++ = newnfs_false; 2227 txdr_hyper(dirforp->na_filerev, tl); 2228 tl += 2; 2229 txdr_hyper(diraftp->na_filerev, tl); 2230 (void) nfsrv_putattrbit(nd, attrbitp); 2231 } 2232 2233 NFSEXITCODE2(0, nd); 2234 } 2235 2236 /* 2237 * nfs commit service 2238 */ 2239 int 2240 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 2241 vnode_t vp, __unused struct nfsexstuff *exp) 2242 { 2243 struct nfsvattr bfor, aft; 2244 u_int32_t *tl; 2245 int error = 0, for_ret = 1, aft_ret = 1, cnt; 2246 u_int64_t off; 2247 struct thread *p = curthread; 2248 2249 if (nd->nd_repstat) { 2250 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 2251 goto out; 2252 } 2253 2254 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */ 2255 if (vp->v_type != VREG) { 2256 if (nd->nd_flag & ND_NFSV3) 2257 error = NFSERR_NOTSUPP; 2258 else 2259 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL; 2260 goto nfsmout; 2261 } 2262 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2263 2264 /* 2265 * XXX At this time VOP_FSYNC() does not accept offset and byte 2266 * count parameters, so these arguments are useless (someday maybe). 2267 */ 2268 off = fxdr_hyper(tl); 2269 tl += 2; 2270 cnt = fxdr_unsigned(int, *tl); 2271 if (nd->nd_flag & ND_NFSV3) 2272 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL); 2273 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 2274 if (nd->nd_flag & ND_NFSV3) { 2275 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL); 2276 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 2277 } 2278 vput(vp); 2279 if (!nd->nd_repstat) { 2280 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2281 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 2282 *tl = txdr_unsigned(nfsboottime.tv_usec); 2283 } 2284 2285 out: 2286 NFSEXITCODE2(0, nd); 2287 return (0); 2288 nfsmout: 2289 vput(vp); 2290 NFSEXITCODE2(error, nd); 2291 return (error); 2292 } 2293 2294 /* 2295 * nfs statfs service 2296 */ 2297 int 2298 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 2299 vnode_t vp, __unused struct nfsexstuff *exp) 2300 { 2301 struct statfs *sf; 2302 u_int32_t *tl; 2303 int getret = 1; 2304 struct nfsvattr at; 2305 u_quad_t tval; 2306 struct thread *p = curthread; 2307 2308 sf = NULL; 2309 if (nd->nd_repstat) { 2310 nfsrv_postopattr(nd, getret, &at); 2311 goto out; 2312 } 2313 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 2314 nd->nd_repstat = nfsvno_statfs(vp, sf); 2315 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 2316 vput(vp); 2317 if (nd->nd_flag & ND_NFSV3) 2318 nfsrv_postopattr(nd, getret, &at); 2319 if (nd->nd_repstat) 2320 goto out; 2321 if (nd->nd_flag & ND_NFSV2) { 2322 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 2323 *tl++ = txdr_unsigned(NFS_V2MAXDATA); 2324 *tl++ = txdr_unsigned(sf->f_bsize); 2325 *tl++ = txdr_unsigned(sf->f_blocks); 2326 *tl++ = txdr_unsigned(sf->f_bfree); 2327 *tl = txdr_unsigned(sf->f_bavail); 2328 } else { 2329 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 2330 tval = (u_quad_t)sf->f_blocks; 2331 tval *= (u_quad_t)sf->f_bsize; 2332 txdr_hyper(tval, tl); tl += 2; 2333 tval = (u_quad_t)sf->f_bfree; 2334 tval *= (u_quad_t)sf->f_bsize; 2335 txdr_hyper(tval, tl); tl += 2; 2336 tval = (u_quad_t)sf->f_bavail; 2337 tval *= (u_quad_t)sf->f_bsize; 2338 txdr_hyper(tval, tl); tl += 2; 2339 tval = (u_quad_t)sf->f_files; 2340 txdr_hyper(tval, tl); tl += 2; 2341 tval = (u_quad_t)sf->f_ffree; 2342 txdr_hyper(tval, tl); tl += 2; 2343 tval = (u_quad_t)sf->f_ffree; 2344 txdr_hyper(tval, tl); tl += 2; 2345 *tl = 0; 2346 } 2347 2348 out: 2349 free(sf, M_STATFS); 2350 NFSEXITCODE2(0, nd); 2351 return (0); 2352 } 2353 2354 /* 2355 * nfs fsinfo service 2356 */ 2357 int 2358 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 2359 vnode_t vp, __unused struct nfsexstuff *exp) 2360 { 2361 u_int32_t *tl; 2362 struct nfsfsinfo fs; 2363 int getret = 1; 2364 struct nfsvattr at; 2365 struct thread *p = curthread; 2366 2367 if (nd->nd_repstat) { 2368 nfsrv_postopattr(nd, getret, &at); 2369 goto out; 2370 } 2371 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 2372 nfsvno_getfs(&fs, isdgram); 2373 vput(vp); 2374 nfsrv_postopattr(nd, getret, &at); 2375 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 2376 *tl++ = txdr_unsigned(fs.fs_rtmax); 2377 *tl++ = txdr_unsigned(fs.fs_rtpref); 2378 *tl++ = txdr_unsigned(fs.fs_rtmult); 2379 *tl++ = txdr_unsigned(fs.fs_wtmax); 2380 *tl++ = txdr_unsigned(fs.fs_wtpref); 2381 *tl++ = txdr_unsigned(fs.fs_wtmult); 2382 *tl++ = txdr_unsigned(fs.fs_dtpref); 2383 txdr_hyper(fs.fs_maxfilesize, tl); 2384 tl += 2; 2385 txdr_nfsv3time(&fs.fs_timedelta, tl); 2386 tl += 2; 2387 *tl = txdr_unsigned(fs.fs_properties); 2388 2389 out: 2390 NFSEXITCODE2(0, nd); 2391 return (0); 2392 } 2393 2394 /* 2395 * nfs pathconf service 2396 */ 2397 int 2398 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 2399 vnode_t vp, __unused struct nfsexstuff *exp) 2400 { 2401 struct nfsv3_pathconf *pc; 2402 int getret = 1; 2403 long linkmax, namemax, chownres, notrunc; 2404 struct nfsvattr at; 2405 struct thread *p = curthread; 2406 2407 if (nd->nd_repstat) { 2408 nfsrv_postopattr(nd, getret, &at); 2409 goto out; 2410 } 2411 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 2412 nd->nd_cred, p); 2413 if (!nd->nd_repstat) 2414 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 2415 nd->nd_cred, p); 2416 if (!nd->nd_repstat) 2417 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 2418 &chownres, nd->nd_cred, p); 2419 if (!nd->nd_repstat) 2420 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 2421 nd->nd_cred, p); 2422 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 2423 vput(vp); 2424 nfsrv_postopattr(nd, getret, &at); 2425 if (!nd->nd_repstat) { 2426 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 2427 pc->pc_linkmax = txdr_unsigned(linkmax); 2428 pc->pc_namemax = txdr_unsigned(namemax); 2429 pc->pc_notrunc = txdr_unsigned(notrunc); 2430 pc->pc_chownrestricted = txdr_unsigned(chownres); 2431 2432 /* 2433 * These should probably be supported by VOP_PATHCONF(), but 2434 * until msdosfs is exportable (why would you want to?), the 2435 * Unix defaults should be ok. 2436 */ 2437 pc->pc_caseinsensitive = newnfs_false; 2438 pc->pc_casepreserving = newnfs_true; 2439 } 2440 2441 out: 2442 NFSEXITCODE2(0, nd); 2443 return (0); 2444 } 2445 2446 /* 2447 * nfsv4 lock service 2448 */ 2449 int 2450 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2451 vnode_t vp, struct nfsexstuff *exp) 2452 { 2453 u_int32_t *tl; 2454 int i; 2455 struct nfsstate *stp = NULL; 2456 struct nfslock *lop; 2457 struct nfslockconflict cf; 2458 int error = 0; 2459 u_short flags = NFSLCK_LOCK, lflags; 2460 u_int64_t offset, len; 2461 nfsv4stateid_t stateid; 2462 nfsquad_t clientid; 2463 struct thread *p = curthread; 2464 2465 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2466 i = fxdr_unsigned(int, *tl++); 2467 switch (i) { 2468 case NFSV4LOCKT_READW: 2469 flags |= NFSLCK_BLOCKING; 2470 case NFSV4LOCKT_READ: 2471 lflags = NFSLCK_READ; 2472 break; 2473 case NFSV4LOCKT_WRITEW: 2474 flags |= NFSLCK_BLOCKING; 2475 case NFSV4LOCKT_WRITE: 2476 lflags = NFSLCK_WRITE; 2477 break; 2478 default: 2479 nd->nd_repstat = NFSERR_BADXDR; 2480 goto nfsmout; 2481 } 2482 if (*tl++ == newnfs_true) 2483 flags |= NFSLCK_RECLAIM; 2484 offset = fxdr_hyper(tl); 2485 tl += 2; 2486 len = fxdr_hyper(tl); 2487 tl += 2; 2488 if (*tl == newnfs_true) 2489 flags |= NFSLCK_OPENTOLOCK; 2490 if (flags & NFSLCK_OPENTOLOCK) { 2491 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 2492 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 2493 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2494 nd->nd_repstat = NFSERR_BADXDR; 2495 goto nfsmout; 2496 } 2497 stp = malloc(sizeof (struct nfsstate) + i, 2498 M_NFSDSTATE, M_WAITOK); 2499 stp->ls_ownerlen = i; 2500 stp->ls_op = nd->nd_rp; 2501 stp->ls_seq = fxdr_unsigned(int, *tl++); 2502 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2503 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2504 NFSX_STATEIDOTHER); 2505 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2506 2507 /* 2508 * For the special stateid of other all 0s and seqid == 1, set 2509 * the stateid to the current stateid, if it is set. 2510 */ 2511 if ((nd->nd_flag & ND_NFSV41) != 0 && 2512 stp->ls_stateid.seqid == 1 && 2513 stp->ls_stateid.other[0] == 0 && 2514 stp->ls_stateid.other[1] == 0 && 2515 stp->ls_stateid.other[2] == 0) { 2516 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 2517 stp->ls_stateid = nd->nd_curstateid; 2518 stp->ls_stateid.seqid = 0; 2519 } else { 2520 nd->nd_repstat = NFSERR_BADSTATEID; 2521 goto nfsmout; 2522 } 2523 } 2524 2525 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 2526 clientid.lval[0] = *tl++; 2527 clientid.lval[1] = *tl++; 2528 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2529 if ((nd->nd_flag & ND_NFSV41) != 0) 2530 clientid.qval = nd->nd_clientid.qval; 2531 else if (nd->nd_clientid.qval != clientid.qval) 2532 printf("EEK3 multiple clids\n"); 2533 } else { 2534 if ((nd->nd_flag & ND_NFSV41) != 0) 2535 printf("EEK! no clientid from session\n"); 2536 nd->nd_flag |= ND_IMPLIEDCLID; 2537 nd->nd_clientid.qval = clientid.qval; 2538 } 2539 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2540 if (error) 2541 goto nfsmout; 2542 } else { 2543 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2544 stp = malloc(sizeof (struct nfsstate), 2545 M_NFSDSTATE, M_WAITOK); 2546 stp->ls_ownerlen = 0; 2547 stp->ls_op = nd->nd_rp; 2548 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2549 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2550 NFSX_STATEIDOTHER); 2551 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2552 2553 /* 2554 * For the special stateid of other all 0s and seqid == 1, set 2555 * the stateid to the current stateid, if it is set. 2556 */ 2557 if ((nd->nd_flag & ND_NFSV41) != 0 && 2558 stp->ls_stateid.seqid == 1 && 2559 stp->ls_stateid.other[0] == 0 && 2560 stp->ls_stateid.other[1] == 0 && 2561 stp->ls_stateid.other[2] == 0) { 2562 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 2563 stp->ls_stateid = nd->nd_curstateid; 2564 stp->ls_stateid.seqid = 0; 2565 } else { 2566 nd->nd_repstat = NFSERR_BADSTATEID; 2567 goto nfsmout; 2568 } 2569 } 2570 2571 stp->ls_seq = fxdr_unsigned(int, *tl); 2572 clientid.lval[0] = stp->ls_stateid.other[0]; 2573 clientid.lval[1] = stp->ls_stateid.other[1]; 2574 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2575 if ((nd->nd_flag & ND_NFSV41) != 0) 2576 clientid.qval = nd->nd_clientid.qval; 2577 else if (nd->nd_clientid.qval != clientid.qval) 2578 printf("EEK4 multiple clids\n"); 2579 } else { 2580 if ((nd->nd_flag & ND_NFSV41) != 0) 2581 printf("EEK! no clientid from session\n"); 2582 nd->nd_flag |= ND_IMPLIEDCLID; 2583 nd->nd_clientid.qval = clientid.qval; 2584 } 2585 } 2586 lop = malloc(sizeof (struct nfslock), 2587 M_NFSDLOCK, M_WAITOK); 2588 lop->lo_first = offset; 2589 if (len == NFS64BITSSET) { 2590 lop->lo_end = NFS64BITSSET; 2591 } else { 2592 lop->lo_end = offset + len; 2593 if (lop->lo_end <= lop->lo_first) 2594 nd->nd_repstat = NFSERR_INVAL; 2595 } 2596 lop->lo_flags = lflags; 2597 stp->ls_flags = flags; 2598 stp->ls_uid = nd->nd_cred->cr_uid; 2599 2600 /* 2601 * Do basic access checking. 2602 */ 2603 if (!nd->nd_repstat && vp->v_type != VREG) { 2604 if (vp->v_type == VDIR) 2605 nd->nd_repstat = NFSERR_ISDIR; 2606 else 2607 nd->nd_repstat = NFSERR_INVAL; 2608 } 2609 if (!nd->nd_repstat) { 2610 if (lflags & NFSLCK_WRITE) { 2611 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 2612 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2613 NFSACCCHK_VPISLOCKED, NULL); 2614 } else { 2615 nd->nd_repstat = nfsvno_accchk(vp, VREAD, 2616 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2617 NFSACCCHK_VPISLOCKED, NULL); 2618 if (nd->nd_repstat) 2619 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2620 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2621 NFSACCCHK_VPISLOCKED, NULL); 2622 } 2623 } 2624 2625 /* 2626 * We call nfsrv_lockctrl() even if nd_repstat set, so that the 2627 * seqid# gets updated. nfsrv_lockctrl() will return the value 2628 * of nd_repstat, if it gets that far. 2629 */ 2630 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2631 &stateid, exp, nd, p); 2632 if (lop) 2633 free(lop, M_NFSDLOCK); 2634 if (stp) 2635 free(stp, M_NFSDSTATE); 2636 if (!nd->nd_repstat) { 2637 /* For NFSv4.1, set the Current StateID. */ 2638 if ((nd->nd_flag & ND_NFSV41) != 0) { 2639 nd->nd_curstateid = stateid; 2640 nd->nd_flag |= ND_CURSTATEID; 2641 } 2642 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2643 *tl++ = txdr_unsigned(stateid.seqid); 2644 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2645 } else if (nd->nd_repstat == NFSERR_DENIED) { 2646 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2647 txdr_hyper(cf.cl_first, tl); 2648 tl += 2; 2649 if (cf.cl_end == NFS64BITSSET) 2650 len = NFS64BITSSET; 2651 else 2652 len = cf.cl_end - cf.cl_first; 2653 txdr_hyper(len, tl); 2654 tl += 2; 2655 if (cf.cl_flags == NFSLCK_WRITE) 2656 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2657 else 2658 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2659 *tl++ = stateid.other[0]; 2660 *tl = stateid.other[1]; 2661 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2662 } 2663 vput(vp); 2664 NFSEXITCODE2(0, nd); 2665 return (0); 2666 nfsmout: 2667 vput(vp); 2668 if (stp) 2669 free(stp, M_NFSDSTATE); 2670 NFSEXITCODE2(error, nd); 2671 return (error); 2672 } 2673 2674 /* 2675 * nfsv4 lock test service 2676 */ 2677 int 2678 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2679 vnode_t vp, struct nfsexstuff *exp) 2680 { 2681 u_int32_t *tl; 2682 int i; 2683 struct nfsstate *stp = NULL; 2684 struct nfslock lo, *lop = &lo; 2685 struct nfslockconflict cf; 2686 int error = 0; 2687 nfsv4stateid_t stateid; 2688 nfsquad_t clientid; 2689 u_int64_t len; 2690 struct thread *p = curthread; 2691 2692 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 2693 i = fxdr_unsigned(int, *(tl + 7)); 2694 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2695 nd->nd_repstat = NFSERR_BADXDR; 2696 goto nfsmout; 2697 } 2698 stp = malloc(sizeof (struct nfsstate) + i, 2699 M_NFSDSTATE, M_WAITOK); 2700 stp->ls_ownerlen = i; 2701 stp->ls_op = NULL; 2702 stp->ls_flags = NFSLCK_TEST; 2703 stp->ls_uid = nd->nd_cred->cr_uid; 2704 i = fxdr_unsigned(int, *tl++); 2705 switch (i) { 2706 case NFSV4LOCKT_READW: 2707 stp->ls_flags |= NFSLCK_BLOCKING; 2708 case NFSV4LOCKT_READ: 2709 lo.lo_flags = NFSLCK_READ; 2710 break; 2711 case NFSV4LOCKT_WRITEW: 2712 stp->ls_flags |= NFSLCK_BLOCKING; 2713 case NFSV4LOCKT_WRITE: 2714 lo.lo_flags = NFSLCK_WRITE; 2715 break; 2716 default: 2717 nd->nd_repstat = NFSERR_BADXDR; 2718 goto nfsmout; 2719 } 2720 lo.lo_first = fxdr_hyper(tl); 2721 tl += 2; 2722 len = fxdr_hyper(tl); 2723 if (len == NFS64BITSSET) { 2724 lo.lo_end = NFS64BITSSET; 2725 } else { 2726 lo.lo_end = lo.lo_first + len; 2727 if (lo.lo_end <= lo.lo_first) 2728 nd->nd_repstat = NFSERR_INVAL; 2729 } 2730 tl += 2; 2731 clientid.lval[0] = *tl++; 2732 clientid.lval[1] = *tl; 2733 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2734 if ((nd->nd_flag & ND_NFSV41) != 0) 2735 clientid.qval = nd->nd_clientid.qval; 2736 else if (nd->nd_clientid.qval != clientid.qval) 2737 printf("EEK5 multiple clids\n"); 2738 } else { 2739 if ((nd->nd_flag & ND_NFSV41) != 0) 2740 printf("EEK! no clientid from session\n"); 2741 nd->nd_flag |= ND_IMPLIEDCLID; 2742 nd->nd_clientid.qval = clientid.qval; 2743 } 2744 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2745 if (error) 2746 goto nfsmout; 2747 if (!nd->nd_repstat && vp->v_type != VREG) { 2748 if (vp->v_type == VDIR) 2749 nd->nd_repstat = NFSERR_ISDIR; 2750 else 2751 nd->nd_repstat = NFSERR_INVAL; 2752 } 2753 if (!nd->nd_repstat) 2754 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2755 &stateid, exp, nd, p); 2756 if (nd->nd_repstat) { 2757 if (nd->nd_repstat == NFSERR_DENIED) { 2758 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2759 txdr_hyper(cf.cl_first, tl); 2760 tl += 2; 2761 if (cf.cl_end == NFS64BITSSET) 2762 len = NFS64BITSSET; 2763 else 2764 len = cf.cl_end - cf.cl_first; 2765 txdr_hyper(len, tl); 2766 tl += 2; 2767 if (cf.cl_flags == NFSLCK_WRITE) 2768 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2769 else 2770 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2771 *tl++ = stp->ls_stateid.other[0]; 2772 *tl = stp->ls_stateid.other[1]; 2773 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2774 } 2775 } 2776 vput(vp); 2777 if (stp) 2778 free(stp, M_NFSDSTATE); 2779 NFSEXITCODE2(0, nd); 2780 return (0); 2781 nfsmout: 2782 vput(vp); 2783 if (stp) 2784 free(stp, M_NFSDSTATE); 2785 NFSEXITCODE2(error, nd); 2786 return (error); 2787 } 2788 2789 /* 2790 * nfsv4 unlock service 2791 */ 2792 int 2793 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2794 vnode_t vp, struct nfsexstuff *exp) 2795 { 2796 u_int32_t *tl; 2797 int i; 2798 struct nfsstate *stp; 2799 struct nfslock *lop; 2800 int error = 0; 2801 nfsv4stateid_t stateid; 2802 nfsquad_t clientid; 2803 u_int64_t len; 2804 struct thread *p = curthread; 2805 2806 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2807 stp = malloc(sizeof (struct nfsstate), 2808 M_NFSDSTATE, M_WAITOK); 2809 lop = malloc(sizeof (struct nfslock), 2810 M_NFSDLOCK, M_WAITOK); 2811 stp->ls_flags = NFSLCK_UNLOCK; 2812 lop->lo_flags = NFSLCK_UNLOCK; 2813 stp->ls_op = nd->nd_rp; 2814 i = fxdr_unsigned(int, *tl++); 2815 switch (i) { 2816 case NFSV4LOCKT_READW: 2817 stp->ls_flags |= NFSLCK_BLOCKING; 2818 case NFSV4LOCKT_READ: 2819 break; 2820 case NFSV4LOCKT_WRITEW: 2821 stp->ls_flags |= NFSLCK_BLOCKING; 2822 case NFSV4LOCKT_WRITE: 2823 break; 2824 default: 2825 nd->nd_repstat = NFSERR_BADXDR; 2826 free(stp, M_NFSDSTATE); 2827 free(lop, M_NFSDLOCK); 2828 goto nfsmout; 2829 } 2830 stp->ls_ownerlen = 0; 2831 stp->ls_uid = nd->nd_cred->cr_uid; 2832 stp->ls_seq = fxdr_unsigned(int, *tl++); 2833 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2834 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2835 NFSX_STATEIDOTHER); 2836 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2837 2838 /* 2839 * For the special stateid of other all 0s and seqid == 1, set the 2840 * stateid to the current stateid, if it is set. 2841 */ 2842 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 2843 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 2844 stp->ls_stateid.other[2] == 0) { 2845 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 2846 stp->ls_stateid = nd->nd_curstateid; 2847 stp->ls_stateid.seqid = 0; 2848 } else { 2849 nd->nd_repstat = NFSERR_BADSTATEID; 2850 free(stp, M_NFSDSTATE); 2851 free(lop, M_NFSDLOCK); 2852 goto nfsmout; 2853 } 2854 } 2855 2856 lop->lo_first = fxdr_hyper(tl); 2857 tl += 2; 2858 len = fxdr_hyper(tl); 2859 if (len == NFS64BITSSET) { 2860 lop->lo_end = NFS64BITSSET; 2861 } else { 2862 lop->lo_end = lop->lo_first + len; 2863 if (lop->lo_end <= lop->lo_first) 2864 nd->nd_repstat = NFSERR_INVAL; 2865 } 2866 clientid.lval[0] = stp->ls_stateid.other[0]; 2867 clientid.lval[1] = stp->ls_stateid.other[1]; 2868 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2869 if ((nd->nd_flag & ND_NFSV41) != 0) 2870 clientid.qval = nd->nd_clientid.qval; 2871 else if (nd->nd_clientid.qval != clientid.qval) 2872 printf("EEK6 multiple clids\n"); 2873 } else { 2874 if ((nd->nd_flag & ND_NFSV41) != 0) 2875 printf("EEK! no clientid from session\n"); 2876 nd->nd_flag |= ND_IMPLIEDCLID; 2877 nd->nd_clientid.qval = clientid.qval; 2878 } 2879 if (!nd->nd_repstat && vp->v_type != VREG) { 2880 if (vp->v_type == VDIR) 2881 nd->nd_repstat = NFSERR_ISDIR; 2882 else 2883 nd->nd_repstat = NFSERR_INVAL; 2884 } 2885 /* 2886 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 2887 * seqid# gets incremented. nfsrv_lockctrl() will return the 2888 * value of nd_repstat, if it gets that far. 2889 */ 2890 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 2891 &stateid, exp, nd, p); 2892 if (stp) 2893 free(stp, M_NFSDSTATE); 2894 if (lop) 2895 free(lop, M_NFSDLOCK); 2896 if (!nd->nd_repstat) { 2897 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2898 *tl++ = txdr_unsigned(stateid.seqid); 2899 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2900 } 2901 nfsmout: 2902 vput(vp); 2903 NFSEXITCODE2(error, nd); 2904 return (error); 2905 } 2906 2907 /* 2908 * nfsv4 open service 2909 */ 2910 int 2911 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2912 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp) 2913 { 2914 u_int32_t *tl; 2915 int i, retext; 2916 struct nfsstate *stp = NULL; 2917 int error = 0, create, claim, exclusive_flag = 0, override; 2918 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 2919 int how = NFSCREATE_UNCHECKED; 2920 int32_t cverf[2], tverf[2] = { 0, 0 }; 2921 vnode_t vp = NULL, dirp = NULL; 2922 struct nfsvattr nva, dirfor, diraft, nva2; 2923 struct nameidata named; 2924 nfsv4stateid_t stateid, delegstateid; 2925 nfsattrbit_t attrbits; 2926 nfsquad_t clientid; 2927 char *bufp = NULL; 2928 u_long *hashp; 2929 NFSACL_T *aclp = NULL; 2930 struct thread *p = curthread; 2931 bool done_namei; 2932 __enum_uint8_decl(wdelegace) { USENONE, USEMODE, USENFSV4ACL } 2933 delegace; 2934 2935 #ifdef NFS4_ACL_EXTATTR_NAME 2936 aclp = acl_alloc(M_WAITOK); 2937 aclp->acl_cnt = 0; 2938 #endif 2939 NFSZERO_ATTRBIT(&attrbits); 2940 done_namei = false; 2941 delegace = USEMODE; 2942 named.ni_cnd.cn_nameiop = 0; 2943 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2944 i = fxdr_unsigned(int, *(tl + 5)); 2945 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2946 nd->nd_repstat = NFSERR_BADXDR; 2947 goto nfsmout; 2948 } 2949 stp = malloc(sizeof (struct nfsstate) + i, 2950 M_NFSDSTATE, M_WAITOK); 2951 stp->ls_ownerlen = i; 2952 stp->ls_op = nd->nd_rp; 2953 stp->ls_flags = NFSLCK_OPEN; 2954 stp->ls_uid = nd->nd_cred->cr_uid; 2955 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2956 i = fxdr_unsigned(int, *tl++); 2957 retext = 0; 2958 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2959 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2960 retext = 1; 2961 /* For now, ignore these. */ 2962 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2963 switch (i & NFSV4OPEN_WANTDELEGMASK) { 2964 case NFSV4OPEN_WANTANYDELEG: 2965 stp->ls_flags |= (NFSLCK_WANTRDELEG | 2966 NFSLCK_WANTWDELEG); 2967 i &= ~NFSV4OPEN_WANTDELEGMASK; 2968 break; 2969 case NFSV4OPEN_WANTREADDELEG: 2970 stp->ls_flags |= NFSLCK_WANTRDELEG; 2971 i &= ~NFSV4OPEN_WANTDELEGMASK; 2972 break; 2973 case NFSV4OPEN_WANTWRITEDELEG: 2974 stp->ls_flags |= NFSLCK_WANTWDELEG; 2975 i &= ~NFSV4OPEN_WANTDELEGMASK; 2976 break; 2977 case NFSV4OPEN_WANTNODELEG: 2978 stp->ls_flags |= NFSLCK_WANTNODELEG; 2979 i &= ~NFSV4OPEN_WANTDELEGMASK; 2980 break; 2981 case NFSV4OPEN_WANTCANCEL: 2982 printf("NFSv4: ignore Open WantCancel\n"); 2983 i &= ~NFSV4OPEN_WANTDELEGMASK; 2984 break; 2985 default: 2986 /* nd_repstat will be set to NFSERR_INVAL below. */ 2987 break; 2988 } 2989 } 2990 switch (i) { 2991 case NFSV4OPEN_ACCESSREAD: 2992 stp->ls_flags |= NFSLCK_READACCESS; 2993 break; 2994 case NFSV4OPEN_ACCESSWRITE: 2995 stp->ls_flags |= NFSLCK_WRITEACCESS; 2996 break; 2997 case NFSV4OPEN_ACCESSBOTH: 2998 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2999 break; 3000 default: 3001 nd->nd_repstat = NFSERR_INVAL; 3002 } 3003 i = fxdr_unsigned(int, *tl++); 3004 switch (i) { 3005 case NFSV4OPEN_DENYNONE: 3006 break; 3007 case NFSV4OPEN_DENYREAD: 3008 stp->ls_flags |= NFSLCK_READDENY; 3009 break; 3010 case NFSV4OPEN_DENYWRITE: 3011 stp->ls_flags |= NFSLCK_WRITEDENY; 3012 break; 3013 case NFSV4OPEN_DENYBOTH: 3014 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3015 break; 3016 default: 3017 nd->nd_repstat = NFSERR_INVAL; 3018 } 3019 clientid.lval[0] = *tl++; 3020 clientid.lval[1] = *tl; 3021 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3022 if ((nd->nd_flag & ND_NFSV41) != 0) 3023 clientid.qval = nd->nd_clientid.qval; 3024 else if (nd->nd_clientid.qval != clientid.qval) 3025 printf("EEK7 multiple clids\n"); 3026 } else { 3027 if ((nd->nd_flag & ND_NFSV41) != 0) 3028 printf("EEK! no clientid from session\n"); 3029 nd->nd_flag |= ND_IMPLIEDCLID; 3030 nd->nd_clientid.qval = clientid.qval; 3031 } 3032 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 3033 if (error) 3034 goto nfsmout; 3035 NFSVNO_ATTRINIT(&nva); 3036 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3037 create = fxdr_unsigned(int, *tl); 3038 if (!nd->nd_repstat) 3039 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 3040 if (create == NFSV4OPEN_CREATE) { 3041 nva.na_type = VREG; 3042 nva.na_mode = 0; 3043 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3044 how = fxdr_unsigned(int, *tl); 3045 switch (how) { 3046 case NFSCREATE_UNCHECKED: 3047 case NFSCREATE_GUARDED: 3048 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 3049 if (error) 3050 goto nfsmout; 3051 /* 3052 * If the na_gid being set is the same as that of 3053 * the directory it is going in, clear it, since 3054 * that is what will be set by default. This allows 3055 * a user that isn't in that group to do the create. 3056 */ 3057 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 3058 nva.na_gid == dirfor.na_gid) 3059 NFSVNO_UNSET(&nva, gid); 3060 if (!nd->nd_repstat) 3061 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 3062 break; 3063 case NFSCREATE_EXCLUSIVE: 3064 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 3065 cverf[0] = *tl++; 3066 cverf[1] = *tl; 3067 if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0) 3068 nd->nd_repstat = NFSERR_INVAL; 3069 break; 3070 case NFSCREATE_EXCLUSIVE41: 3071 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 3072 cverf[0] = *tl++; 3073 cverf[1] = *tl; 3074 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 3075 if (error != 0) 3076 goto nfsmout; 3077 if ((vn_irflag_read(dp) & VIRF_NAMEDDIR) != 0 || 3078 NFSISSET_ATTRBIT(&attrbits, 3079 NFSATTRBIT_TIMEACCESSSET)) 3080 nd->nd_repstat = NFSERR_INVAL; 3081 /* 3082 * If the na_gid being set is the same as that of 3083 * the directory it is going in, clear it, since 3084 * that is what will be set by default. This allows 3085 * a user that isn't in that group to do the create. 3086 */ 3087 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 3088 nva.na_gid == dirfor.na_gid) 3089 NFSVNO_UNSET(&nva, gid); 3090 if (nd->nd_repstat == 0) 3091 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 3092 break; 3093 default: 3094 nd->nd_repstat = NFSERR_BADXDR; 3095 goto nfsmout; 3096 } 3097 } else if (create != NFSV4OPEN_NOCREATE) { 3098 nd->nd_repstat = NFSERR_BADXDR; 3099 goto nfsmout; 3100 } 3101 3102 /* 3103 * Now, handle the claim, which usually includes looking up a 3104 * name in the directory referenced by dp. The exception is 3105 * NFSV4OPEN_CLAIMPREVIOUS. 3106 */ 3107 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3108 claim = fxdr_unsigned(int, *tl); 3109 if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim == 3110 NFSV4OPEN_CLAIMDELEGATECURFH) { 3111 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3112 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3113 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 3114 stp->ls_flags |= NFSLCK_DELEGCUR; 3115 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim == 3116 NFSV4OPEN_CLAIMDELEGATEPREVFH) { 3117 stp->ls_flags |= NFSLCK_DELEGPREV; 3118 } 3119 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 3120 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 3121 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 3122 claim != NFSV4OPEN_CLAIMNULL) 3123 nd->nd_repstat = NFSERR_INVAL; 3124 if (nd->nd_repstat) { 3125 nd->nd_repstat = nfsrv_opencheck(clientid, 3126 &stateid, stp, NULL, nd, p, nd->nd_repstat); 3127 goto nfsmout; 3128 } 3129 if (create == NFSV4OPEN_CREATE) 3130 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 3131 LOCKPARENT | LOCKLEAF | NOCACHE); 3132 else 3133 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3134 LOCKLEAF); 3135 nfsvno_setpathbuf(&named, &bufp, &hashp); 3136 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3137 if (error) { 3138 vrele(dp); 3139 #ifdef NFS4_ACL_EXTATTR_NAME 3140 acl_free(aclp); 3141 #endif 3142 free(stp, M_NFSDSTATE); 3143 nfsvno_relpathbuf(&named); 3144 NFSEXITCODE2(error, nd); 3145 return (error); 3146 } 3147 if (!nd->nd_repstat) { 3148 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 3149 &dirp); 3150 } else { 3151 vrele(dp); 3152 nfsvno_relpathbuf(&named); 3153 } 3154 if (create == NFSV4OPEN_CREATE) { 3155 switch (how) { 3156 case NFSCREATE_UNCHECKED: 3157 if (nd->nd_repstat == 0 && named.ni_vp != NULL) { 3158 /* 3159 * Clear the setable attribute bits, except 3160 * for Size, if it is being truncated. 3161 */ 3162 NFSZERO_ATTRBIT(&attrbits); 3163 if (NFSVNO_ISSETSIZE(&nva)) 3164 NFSSETBIT_ATTRBIT(&attrbits, 3165 NFSATTRBIT_SIZE); 3166 } 3167 break; 3168 case NFSCREATE_GUARDED: 3169 if (nd->nd_repstat == 0 && named.ni_vp != NULL) { 3170 nd->nd_repstat = EEXIST; 3171 done_namei = true; 3172 } 3173 break; 3174 case NFSCREATE_EXCLUSIVE: 3175 if (nd->nd_repstat == 0 && named.ni_vp == NULL) 3176 nva.na_mode = 0; 3177 /* FALLTHROUGH */ 3178 case NFSCREATE_EXCLUSIVE41: 3179 if (nd->nd_repstat == 0 && named.ni_vp != NULL) { 3180 nd->nd_repstat = nfsvno_getattr(named.ni_vp, 3181 &nva2, nd, p, 1, NULL); 3182 if (nd->nd_repstat == 0) { 3183 tverf[0] = nva2.na_atime.tv_sec; 3184 tverf[1] = nva2.na_atime.tv_nsec; 3185 if (cverf[0] != tverf[0] || 3186 cverf[1] != tverf[1]) 3187 nd->nd_repstat = EEXIST; 3188 } 3189 if (nd->nd_repstat != 0) 3190 done_namei = true; 3191 } 3192 exclusive_flag = 1; 3193 break; 3194 } 3195 } 3196 nfsvno_open(nd, &named, clientid, &stateid, stp, 3197 &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 3198 nd->nd_cred, done_namei, exp, &vp); 3199 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 3200 NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH || 3201 claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) { 3202 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 3203 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3204 i = fxdr_unsigned(int, *tl); 3205 switch (i) { 3206 case NFSV4OPEN_DELEGATEREAD: 3207 stp->ls_flags |= NFSLCK_DELEGREAD; 3208 break; 3209 case NFSV4OPEN_DELEGATEWRITE: 3210 stp->ls_flags |= NFSLCK_DELEGWRITE; 3211 case NFSV4OPEN_DELEGATENONE: 3212 break; 3213 default: 3214 nd->nd_repstat = NFSERR_BADXDR; 3215 goto nfsmout; 3216 } 3217 stp->ls_flags |= NFSLCK_RECLAIM; 3218 } else { 3219 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 3220 nd->nd_repstat = NFSERR_INVAL; 3221 } 3222 vp = dp; 3223 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3224 if (!VN_IS_DOOMED(vp)) 3225 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 3226 stp, vp, nd, p, nd->nd_repstat); 3227 else 3228 nd->nd_repstat = NFSERR_PERM; 3229 } else { 3230 nd->nd_repstat = NFSERR_BADXDR; 3231 goto nfsmout; 3232 } 3233 3234 /* 3235 * Do basic access checking. 3236 */ 3237 if (!nd->nd_repstat && vp->v_type != VREG) { 3238 /* 3239 * The IETF working group decided that this is the correct 3240 * error return for all non-regular files. 3241 */ 3242 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK; 3243 } 3244 3245 /* 3246 * If the Open is being done for a file that already exists, apply 3247 * normal permission checking including for the file owner, if 3248 * vfs.nfsd.v4openaccess is set. 3249 * Previously, the owner was always allowed to open the file to 3250 * be consistent with the NFS tradition of always allowing the 3251 * owner of the file to write to the file regardless of permissions. 3252 * It now appears that the Linux client expects the owner 3253 * permissions to be checked for opens that are not creating the 3254 * file. I believe the correct approach is to use the Access 3255 * operation's results to be consistent with NFSv3, but that is 3256 * not what the current Linux client appears to be doing. 3257 * Since both the Linux and OpenSolaris NFSv4 servers do this check, 3258 * I have enabled it by default. Since Linux does not apply this 3259 * check for claim_delegate_cur, this code does the same. 3260 * If this semantic change causes a problem, it can be disabled by 3261 * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the 3262 * previous semantics. 3263 */ 3264 if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE && 3265 (stp->ls_flags & NFSLCK_DELEGCUR) == 0) 3266 override = NFSACCCHK_NOOVERRIDE; 3267 else 3268 override = NFSACCCHK_ALLOWOWNER; 3269 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 3270 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 3271 exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 3272 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 3273 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 3274 exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 3275 if (nd->nd_repstat) 3276 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 3277 nd->nd_cred, exp, p, override, 3278 NFSACCCHK_VPISLOCKED, NULL); 3279 } 3280 3281 if (!nd->nd_repstat) 3282 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 3283 3284 if (nd->nd_repstat == 0 && aclp != NULL && nfsrv_issuedelegs != 0 && 3285 (dp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) { 3286 if (aclp->acl_cnt == 0 && create == NFSV4OPEN_NOCREATE) { 3287 int retacl; 3288 3289 /* We do not yet have an ACL, so try and get one. */ 3290 retacl = VOP_GETACL(vp, ACL_TYPE_NFS4, aclp, 3291 nd->nd_cred, p); 3292 if (retacl != 0 && retacl != ENOATTR && 3293 retacl != EOPNOTSUPP && retacl != EINVAL) 3294 delegace = USENONE; 3295 else if (retacl == 0 && aclp->acl_cnt > 0) 3296 delegace = USENFSV4ACL; 3297 } else if (aclp->acl_cnt > 0 && create == NFSV4OPEN_CREATE) { 3298 delegace = USENFSV4ACL; 3299 } 3300 } 3301 3302 /* 3303 * Do the open locking/delegation stuff. 3304 */ 3305 if (!nd->nd_repstat) 3306 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 3307 &delegstateid, &rflags, exp, p, nva.na_filerev); 3308 3309 /* 3310 * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 3311 * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 3312 * (ie: Leave the NFSVOPUNLOCK() about here.) 3313 */ 3314 if (vp) 3315 NFSVOPUNLOCK(vp); 3316 if (stp) 3317 free(stp, M_NFSDSTATE); 3318 if (!nd->nd_repstat && dirp) 3319 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 3320 if (!nd->nd_repstat) { 3321 /* For NFSv4.1, set the Current StateID. */ 3322 if ((nd->nd_flag & ND_NFSV41) != 0) { 3323 nd->nd_curstateid = stateid; 3324 nd->nd_flag |= ND_CURSTATEID; 3325 } 3326 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 3327 *tl++ = txdr_unsigned(stateid.seqid); 3328 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3329 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3330 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 3331 *tl++ = newnfs_true; 3332 *tl++ = 0; 3333 *tl++ = 0; 3334 *tl++ = 0; 3335 *tl++ = 0; 3336 } else { 3337 *tl++ = newnfs_false; /* Since dirp is not locked */ 3338 txdr_hyper(dirfor.na_filerev, tl); 3339 tl += 2; 3340 txdr_hyper(diraft.na_filerev, tl); 3341 tl += 2; 3342 } 3343 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 3344 (void) nfsrv_putattrbit(nd, &attrbits); 3345 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3346 if (rflags & NFSV4OPEN_READDELEGATE) 3347 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 3348 else if (rflags & NFSV4OPEN_WRITEDELEGATE) 3349 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 3350 else if (retext != 0) { 3351 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 3352 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) { 3353 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3354 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3355 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) { 3356 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3357 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE); 3358 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 3359 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3360 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 3361 *tl = newnfs_false; 3362 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 3363 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3364 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 3365 *tl = newnfs_false; 3366 } else if ((rflags & 3367 NFSV4OPEN_WDNOTSUPPDOWNGRADE) != 0) { 3368 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3369 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPDOWNGRADE); 3370 } else if ((rflags & NFSV4OPEN_WDNOTSUPPUPGRADE) != 0) { 3371 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3372 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPUPGRADE); 3373 } else { 3374 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3375 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3376 } 3377 } else 3378 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 3379 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 3380 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 3381 *tl++ = txdr_unsigned(delegstateid.seqid); 3382 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 3383 NFSX_STATEIDOTHER); 3384 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3385 if (rflags & NFSV4OPEN_RECALL) 3386 *tl = newnfs_true; 3387 else 3388 *tl = newnfs_false; 3389 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 3390 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3391 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 3392 txdr_hyper(nva.na_size, tl); 3393 } 3394 3395 /* Set up the write delegation ACE. */ 3396 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3397 if (delegace == USENFSV4ACL) { 3398 int j; 3399 3400 for (j = 0; j < aclp->acl_cnt; j++) { 3401 if (aclp->acl_entry[j].ae_tag == 3402 ACL_USER_OBJ || 3403 aclp->acl_entry[j].ae_entry_type != 3404 ACL_ENTRY_TYPE_ALLOW) 3405 break; 3406 } 3407 if (j < aclp->acl_cnt && 3408 aclp->acl_entry[j].ae_tag == 3409 ACL_USER_OBJ && 3410 aclp->acl_entry[j].ae_entry_type == 3411 ACL_ENTRY_TYPE_ALLOW) { 3412 /* Use this ACE. */ 3413 *tl++ = txdr_unsigned( 3414 NFSV4ACE_ALLOWEDTYPE); 3415 *tl++ = txdr_unsigned(0x0); 3416 *tl = txdr_unsigned( 3417 nfs_aceperm( 3418 aclp->acl_entry[j].ae_perm)); 3419 (void)nfsm_strtom(nd, "OWNER@", 6); 3420 } else 3421 delegace = USENONE; 3422 } 3423 if (delegace == USENONE) { 3424 /* Don't allow anything. */ 3425 *tl++ = 0x0; 3426 *tl++ = 0x0; 3427 *tl = 0x0; 3428 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3429 *tl = 0; 3430 } else if (delegace == USEMODE) { 3431 /* Build from mode. */ 3432 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 3433 *tl++ = txdr_unsigned(0x0); 3434 acemask = NFSV4ACE_ALLFILESMASK; 3435 if (nva.na_mode & S_IRUSR) 3436 acemask |= NFSV4ACE_READMASK; 3437 if (nva.na_mode & S_IWUSR) 3438 acemask |= NFSV4ACE_WRITEMASK; 3439 if (nva.na_mode & S_IXUSR) 3440 acemask |= NFSV4ACE_EXECUTEMASK; 3441 *tl = txdr_unsigned(acemask); 3442 (void)nfsm_strtom(nd, "OWNER@", 6); 3443 } 3444 } 3445 *vpp = vp; 3446 } else if (vp) { 3447 vrele(vp); 3448 } 3449 if (dirp) 3450 vrele(dirp); 3451 #ifdef NFS4_ACL_EXTATTR_NAME 3452 acl_free(aclp); 3453 #endif 3454 NFSEXITCODE2(0, nd); 3455 return (0); 3456 nfsmout: 3457 vrele(dp); 3458 #ifdef NFS4_ACL_EXTATTR_NAME 3459 acl_free(aclp); 3460 #endif 3461 if (stp) 3462 free(stp, M_NFSDSTATE); 3463 NFSEXITCODE2(error, nd); 3464 return (error); 3465 } 3466 3467 /* 3468 * nfsv4 close service 3469 */ 3470 int 3471 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3472 vnode_t vp, __unused struct nfsexstuff *exp) 3473 { 3474 u_int32_t *tl; 3475 struct nfsstate st, *stp = &st; 3476 int error = 0, writeacc; 3477 nfsv4stateid_t stateid; 3478 nfsquad_t clientid; 3479 struct nfsvattr na; 3480 struct thread *p = curthread; 3481 3482 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 3483 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3484 stp->ls_ownerlen = 0; 3485 stp->ls_op = nd->nd_rp; 3486 stp->ls_uid = nd->nd_cred->cr_uid; 3487 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3488 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3489 NFSX_STATEIDOTHER); 3490 3491 /* 3492 * For the special stateid of other all 0s and seqid == 1, set the 3493 * stateid to the current stateid, if it is set. 3494 */ 3495 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 3496 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 3497 stp->ls_stateid.other[2] == 0) { 3498 if ((nd->nd_flag & ND_CURSTATEID) != 0) 3499 stp->ls_stateid = nd->nd_curstateid; 3500 else { 3501 nd->nd_repstat = NFSERR_BADSTATEID; 3502 goto nfsmout; 3503 } 3504 } 3505 3506 stp->ls_flags = NFSLCK_CLOSE; 3507 clientid.lval[0] = stp->ls_stateid.other[0]; 3508 clientid.lval[1] = stp->ls_stateid.other[1]; 3509 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3510 if ((nd->nd_flag & ND_NFSV41) != 0) 3511 clientid.qval = nd->nd_clientid.qval; 3512 else if (nd->nd_clientid.qval != clientid.qval) 3513 printf("EEK8 multiple clids\n"); 3514 } else { 3515 if ((nd->nd_flag & ND_NFSV41) != 0) 3516 printf("EEK! no clientid from session\n"); 3517 nd->nd_flag |= ND_IMPLIEDCLID; 3518 nd->nd_clientid.qval = clientid.qval; 3519 } 3520 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 3521 &writeacc); 3522 /* For pNFS, update the attributes. */ 3523 if (writeacc != 0 || nfsrv_pnfsatime != 0) 3524 nfsrv_updatemdsattr(vp, &na, p); 3525 vput(vp); 3526 if (!nd->nd_repstat) { 3527 /* 3528 * If the stateid that has been closed is the current stateid, 3529 * unset it. 3530 */ 3531 if ((nd->nd_flag & ND_CURSTATEID) != 0 && 3532 stateid.other[0] == nd->nd_curstateid.other[0] && 3533 stateid.other[1] == nd->nd_curstateid.other[1] && 3534 stateid.other[2] == nd->nd_curstateid.other[2]) 3535 nd->nd_flag &= ~ND_CURSTATEID; 3536 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3537 *tl++ = txdr_unsigned(stateid.seqid); 3538 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3539 } 3540 NFSEXITCODE2(0, nd); 3541 return (0); 3542 nfsmout: 3543 vput(vp); 3544 NFSEXITCODE2(error, nd); 3545 return (error); 3546 } 3547 3548 /* 3549 * nfsv4 delegpurge service 3550 */ 3551 int 3552 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3553 __unused vnode_t vp, __unused struct nfsexstuff *exp) 3554 { 3555 u_int32_t *tl; 3556 int error = 0; 3557 nfsquad_t clientid; 3558 struct thread *p = curthread; 3559 3560 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 3561 goto nfsmout; 3562 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3563 clientid.lval[0] = *tl++; 3564 clientid.lval[1] = *tl; 3565 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3566 if ((nd->nd_flag & ND_NFSV41) != 0) 3567 clientid.qval = nd->nd_clientid.qval; 3568 else if (nd->nd_clientid.qval != clientid.qval) 3569 printf("EEK9 multiple clids\n"); 3570 } else { 3571 if ((nd->nd_flag & ND_NFSV41) != 0) 3572 printf("EEK! no clientid from session\n"); 3573 nd->nd_flag |= ND_IMPLIEDCLID; 3574 nd->nd_clientid.qval = clientid.qval; 3575 } 3576 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 3577 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL); 3578 nfsmout: 3579 NFSEXITCODE2(error, nd); 3580 return (error); 3581 } 3582 3583 /* 3584 * nfsv4 delegreturn service 3585 */ 3586 int 3587 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3588 vnode_t vp, __unused struct nfsexstuff *exp) 3589 { 3590 u_int32_t *tl; 3591 int error = 0, writeacc; 3592 nfsv4stateid_t stateid; 3593 nfsquad_t clientid; 3594 struct nfsvattr na; 3595 struct thread *p = curthread; 3596 3597 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3598 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3599 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 3600 clientid.lval[0] = stateid.other[0]; 3601 clientid.lval[1] = stateid.other[1]; 3602 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3603 if ((nd->nd_flag & ND_NFSV41) != 0) 3604 clientid.qval = nd->nd_clientid.qval; 3605 else if (nd->nd_clientid.qval != clientid.qval) 3606 printf("EEK10 multiple clids\n"); 3607 } else { 3608 if ((nd->nd_flag & ND_NFSV41) != 0) 3609 printf("EEK! no clientid from session\n"); 3610 nd->nd_flag |= ND_IMPLIEDCLID; 3611 nd->nd_clientid.qval = clientid.qval; 3612 } 3613 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 3614 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc); 3615 /* For pNFS, update the attributes. */ 3616 if (writeacc != 0 || nfsrv_pnfsatime != 0) 3617 nfsrv_updatemdsattr(vp, &na, p); 3618 nfsmout: 3619 vput(vp); 3620 NFSEXITCODE2(error, nd); 3621 return (error); 3622 } 3623 3624 /* 3625 * nfsv4 get file handle service 3626 */ 3627 int 3628 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3629 vnode_t vp, __unused struct nfsexstuff *exp) 3630 { 3631 fhandle_t fh; 3632 struct thread *p = curthread; 3633 int siz; 3634 short irflag; 3635 3636 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3637 irflag = vn_irflag_read(vp); 3638 vput(vp); 3639 if (nd->nd_repstat == 0) { 3640 siz = 0; 3641 if ((irflag & VIRF_NAMEDDIR) != 0) 3642 siz = NFSX_FHMAX + NFSX_V4NAMEDDIRFH; 3643 else if ((irflag & VIRF_NAMEDATTR) != 0) 3644 siz = NFSX_FHMAX + NFSX_V4NAMEDATTRFH; 3645 (void)nfsm_fhtom(NULL, nd, (u_int8_t *)&fh, siz, 0); 3646 } 3647 NFSEXITCODE2(0, nd); 3648 return (0); 3649 } 3650 3651 /* 3652 * nfsv4 open confirm service 3653 */ 3654 int 3655 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3656 vnode_t vp, __unused struct nfsexstuff *exp) 3657 { 3658 u_int32_t *tl; 3659 struct nfsstate st, *stp = &st; 3660 int error = 0; 3661 nfsv4stateid_t stateid; 3662 nfsquad_t clientid; 3663 struct thread *p = curthread; 3664 3665 if ((nd->nd_flag & ND_NFSV41) != 0) { 3666 nd->nd_repstat = NFSERR_NOTSUPP; 3667 goto nfsmout; 3668 } 3669 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3670 stp->ls_ownerlen = 0; 3671 stp->ls_op = nd->nd_rp; 3672 stp->ls_uid = nd->nd_cred->cr_uid; 3673 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3674 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3675 NFSX_STATEIDOTHER); 3676 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3677 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 3678 stp->ls_flags = NFSLCK_CONFIRM; 3679 clientid.lval[0] = stp->ls_stateid.other[0]; 3680 clientid.lval[1] = stp->ls_stateid.other[1]; 3681 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3682 if ((nd->nd_flag & ND_NFSV41) != 0) 3683 clientid.qval = nd->nd_clientid.qval; 3684 else if (nd->nd_clientid.qval != clientid.qval) 3685 printf("EEK11 multiple clids\n"); 3686 } else { 3687 if ((nd->nd_flag & ND_NFSV41) != 0) 3688 printf("EEK! no clientid from session\n"); 3689 nd->nd_flag |= ND_IMPLIEDCLID; 3690 nd->nd_clientid.qval = clientid.qval; 3691 } 3692 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 3693 NULL); 3694 if (!nd->nd_repstat) { 3695 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3696 *tl++ = txdr_unsigned(stateid.seqid); 3697 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3698 } 3699 nfsmout: 3700 vput(vp); 3701 NFSEXITCODE2(error, nd); 3702 return (error); 3703 } 3704 3705 /* 3706 * nfsv4 open downgrade service 3707 */ 3708 int 3709 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3710 vnode_t vp, __unused struct nfsexstuff *exp) 3711 { 3712 u_int32_t *tl; 3713 int i; 3714 struct nfsstate st, *stp = &st; 3715 int error = 0; 3716 nfsv4stateid_t stateid; 3717 nfsquad_t clientid; 3718 struct thread *p = curthread; 3719 3720 /* opendowngrade can only work on a file object.*/ 3721 if (vp->v_type != VREG) { 3722 error = NFSERR_INVAL; 3723 goto nfsmout; 3724 } 3725 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 3726 stp->ls_ownerlen = 0; 3727 stp->ls_op = nd->nd_rp; 3728 stp->ls_uid = nd->nd_cred->cr_uid; 3729 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3730 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3731 NFSX_STATEIDOTHER); 3732 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3733 3734 /* 3735 * For the special stateid of other all 0s and seqid == 1, set the 3736 * stateid to the current stateid, if it is set. 3737 */ 3738 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 3739 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 3740 stp->ls_stateid.other[2] == 0) { 3741 if ((nd->nd_flag & ND_CURSTATEID) != 0) 3742 stp->ls_stateid = nd->nd_curstateid; 3743 else { 3744 nd->nd_repstat = NFSERR_BADSTATEID; 3745 goto nfsmout; 3746 } 3747 } 3748 3749 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3750 i = fxdr_unsigned(int, *tl++); 3751 if ((nd->nd_flag & ND_NFSV41) != 0) 3752 i &= ~NFSV4OPEN_WANTDELEGMASK; 3753 switch (i) { 3754 case NFSV4OPEN_ACCESSREAD: 3755 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3756 break; 3757 case NFSV4OPEN_ACCESSWRITE: 3758 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3759 break; 3760 case NFSV4OPEN_ACCESSBOTH: 3761 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3762 NFSLCK_DOWNGRADE); 3763 break; 3764 default: 3765 nd->nd_repstat = NFSERR_INVAL; 3766 } 3767 i = fxdr_unsigned(int, *tl); 3768 switch (i) { 3769 case NFSV4OPEN_DENYNONE: 3770 break; 3771 case NFSV4OPEN_DENYREAD: 3772 stp->ls_flags |= NFSLCK_READDENY; 3773 break; 3774 case NFSV4OPEN_DENYWRITE: 3775 stp->ls_flags |= NFSLCK_WRITEDENY; 3776 break; 3777 case NFSV4OPEN_DENYBOTH: 3778 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3779 break; 3780 default: 3781 nd->nd_repstat = NFSERR_INVAL; 3782 } 3783 3784 clientid.lval[0] = stp->ls_stateid.other[0]; 3785 clientid.lval[1] = stp->ls_stateid.other[1]; 3786 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3787 if ((nd->nd_flag & ND_NFSV41) != 0) 3788 clientid.qval = nd->nd_clientid.qval; 3789 else if (nd->nd_clientid.qval != clientid.qval) 3790 printf("EEK12 multiple clids\n"); 3791 } else { 3792 if ((nd->nd_flag & ND_NFSV41) != 0) 3793 printf("EEK! no clientid from session\n"); 3794 nd->nd_flag |= ND_IMPLIEDCLID; 3795 nd->nd_clientid.qval = clientid.qval; 3796 } 3797 if (!nd->nd_repstat) 3798 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3799 nd, p, NULL); 3800 if (!nd->nd_repstat) { 3801 /* For NFSv4.1, set the Current StateID. */ 3802 if ((nd->nd_flag & ND_NFSV41) != 0) { 3803 nd->nd_curstateid = stateid; 3804 nd->nd_flag |= ND_CURSTATEID; 3805 } 3806 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3807 *tl++ = txdr_unsigned(stateid.seqid); 3808 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3809 } 3810 nfsmout: 3811 vput(vp); 3812 NFSEXITCODE2(error, nd); 3813 return (error); 3814 } 3815 3816 /* 3817 * nfsv4 renew lease service 3818 */ 3819 int 3820 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3821 __unused vnode_t vp, __unused struct nfsexstuff *exp) 3822 { 3823 u_int32_t *tl; 3824 int error = 0; 3825 nfsquad_t clientid; 3826 struct thread *p = curthread; 3827 3828 if ((nd->nd_flag & ND_NFSV41) != 0) { 3829 nd->nd_repstat = NFSERR_NOTSUPP; 3830 goto nfsmout; 3831 } 3832 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 3833 goto nfsmout; 3834 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3835 clientid.lval[0] = *tl++; 3836 clientid.lval[1] = *tl; 3837 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3838 if ((nd->nd_flag & ND_NFSV41) != 0) 3839 clientid.qval = nd->nd_clientid.qval; 3840 else if (nd->nd_clientid.qval != clientid.qval) 3841 printf("EEK13 multiple clids\n"); 3842 } else { 3843 if ((nd->nd_flag & ND_NFSV41) != 0) 3844 printf("EEK! no clientid from session\n"); 3845 nd->nd_flag |= ND_IMPLIEDCLID; 3846 nd->nd_clientid.qval = clientid.qval; 3847 } 3848 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3849 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 3850 nfsmout: 3851 NFSEXITCODE2(error, nd); 3852 return (error); 3853 } 3854 3855 /* 3856 * nfsv4 security info service 3857 */ 3858 int 3859 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3860 vnode_t dp, struct nfsexstuff *exp) 3861 { 3862 u_int32_t *tl; 3863 int len; 3864 struct nameidata named; 3865 vnode_t dirp = NULL, vp; 3866 struct nfsrvfh fh; 3867 struct nfsexstuff retnes; 3868 u_int32_t *sizp; 3869 int error = 0, i; 3870 uint64_t savflag; 3871 char *bufp; 3872 u_long *hashp; 3873 struct thread *p = curthread; 3874 3875 /* 3876 * All this just to get the export flags for the name. 3877 */ 3878 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3879 LOCKLEAF); 3880 nfsvno_setpathbuf(&named, &bufp, &hashp); 3881 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3882 if (error) { 3883 vput(dp); 3884 nfsvno_relpathbuf(&named); 3885 goto out; 3886 } 3887 if (!nd->nd_repstat) { 3888 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); 3889 } else { 3890 vput(dp); 3891 nfsvno_relpathbuf(&named); 3892 } 3893 if (dirp) 3894 vrele(dirp); 3895 if (nd->nd_repstat) 3896 goto out; 3897 nfsvno_relpathbuf(&named); 3898 fh.nfsrvfh_len = NFSX_MYFH; 3899 vp = named.ni_vp; 3900 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3901 vput(vp); 3902 savflag = nd->nd_flag; 3903 if (!nd->nd_repstat) { 3904 /* 3905 * Pretend the next op is Secinfo, so that no wrongsec 3906 * test will be done. 3907 */ 3908 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, 3909 NFSV4OP_SECINFO); 3910 if (vp) 3911 vput(vp); 3912 } 3913 nd->nd_flag = savflag; 3914 if (nd->nd_repstat) 3915 goto out; 3916 3917 /* 3918 * Finally have the export flags for name, so we can create 3919 * the security info. 3920 */ 3921 len = 0; 3922 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3923 3924 /* If nes_numsecflavor == 0, all are allowed. */ 3925 if (retnes.nes_numsecflavor == 0) { 3926 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3927 *tl++ = txdr_unsigned(RPCAUTH_UNIX); 3928 *tl = txdr_unsigned(RPCAUTH_GSS); 3929 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3930 nfsgss_mechlist[KERBV_MECH].len); 3931 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3932 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3933 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3934 *tl = txdr_unsigned(RPCAUTH_GSS); 3935 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3936 nfsgss_mechlist[KERBV_MECH].len); 3937 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3938 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3939 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3940 *tl = txdr_unsigned(RPCAUTH_GSS); 3941 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3942 nfsgss_mechlist[KERBV_MECH].len); 3943 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3944 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3945 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3946 len = 4; 3947 } 3948 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3949 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3950 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3951 *tl = txdr_unsigned(RPCAUTH_UNIX); 3952 len++; 3953 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3954 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3955 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3956 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3957 nfsgss_mechlist[KERBV_MECH].len); 3958 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3959 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3960 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3961 len++; 3962 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3963 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3964 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3965 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3966 nfsgss_mechlist[KERBV_MECH].len); 3967 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3968 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3969 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3970 len++; 3971 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3972 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3973 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3974 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3975 nfsgss_mechlist[KERBV_MECH].len); 3976 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3977 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3978 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3979 len++; 3980 } 3981 } 3982 *sizp = txdr_unsigned(len); 3983 3984 out: 3985 NFSEXITCODE2(error, nd); 3986 return (error); 3987 } 3988 3989 /* 3990 * nfsv4 security info no name service 3991 */ 3992 int 3993 nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram, 3994 vnode_t dp, struct nfsexstuff *exp) 3995 { 3996 uint32_t *tl, *sizp; 3997 struct nameidata named; 3998 vnode_t dirp = NULL, vp; 3999 struct nfsrvfh fh; 4000 struct nfsexstuff retnes; 4001 int error = 0, fhstyle, i, len; 4002 uint64_t savflag; 4003 char *bufp; 4004 u_long *hashp; 4005 struct thread *p = curthread; 4006 4007 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4008 fhstyle = fxdr_unsigned(int, *tl); 4009 switch (fhstyle) { 4010 case NFSSECINFONONAME_PARENT: 4011 if (dp->v_type != VDIR) { 4012 vput(dp); 4013 nd->nd_repstat = NFSERR_NOTDIR; 4014 goto nfsmout; 4015 } 4016 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 4017 LOCKLEAF); 4018 nfsvno_setpathbuf(&named, &bufp, &hashp); 4019 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 4020 if (error != 0) { 4021 vput(dp); 4022 nfsvno_relpathbuf(&named); 4023 goto nfsmout; 4024 } 4025 if (nd->nd_repstat == 0) 4026 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); 4027 else 4028 vput(dp); 4029 if (dirp != NULL) 4030 vrele(dirp); 4031 nfsvno_relpathbuf(&named); 4032 vp = named.ni_vp; 4033 break; 4034 case NFSSECINFONONAME_CURFH: 4035 vp = dp; 4036 break; 4037 default: 4038 nd->nd_repstat = NFSERR_INVAL; 4039 vput(dp); 4040 } 4041 if (nd->nd_repstat != 0) 4042 goto nfsmout; 4043 fh.nfsrvfh_len = NFSX_MYFH; 4044 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 4045 vput(vp); 4046 savflag = nd->nd_flag; 4047 if (nd->nd_repstat == 0) { 4048 /* 4049 * Pretend the next op is Secinfo, so that no wrongsec 4050 * test will be done. 4051 */ 4052 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, 4053 NFSV4OP_SECINFO); 4054 if (vp != NULL) 4055 vput(vp); 4056 } 4057 nd->nd_flag = savflag; 4058 if (nd->nd_repstat != 0) 4059 goto nfsmout; 4060 4061 /* 4062 * Finally have the export flags for fh/parent, so we can create 4063 * the security info. 4064 */ 4065 len = 0; 4066 NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED); 4067 4068 /* If nes_numsecflavor == 0, all are allowed. */ 4069 if (retnes.nes_numsecflavor == 0) { 4070 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4071 *tl++ = txdr_unsigned(RPCAUTH_UNIX); 4072 *tl = txdr_unsigned(RPCAUTH_GSS); 4073 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 4074 nfsgss_mechlist[KERBV_MECH].len); 4075 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 4076 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 4077 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE); 4078 *tl = txdr_unsigned(RPCAUTH_GSS); 4079 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 4080 nfsgss_mechlist[KERBV_MECH].len); 4081 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 4082 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 4083 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 4084 *tl = txdr_unsigned(RPCAUTH_GSS); 4085 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 4086 nfsgss_mechlist[KERBV_MECH].len); 4087 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4088 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 4089 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 4090 len = 4; 4091 } 4092 for (i = 0; i < retnes.nes_numsecflavor; i++) { 4093 if (retnes.nes_secflavors[i] == AUTH_SYS) { 4094 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4095 *tl = txdr_unsigned(RPCAUTH_UNIX); 4096 len++; 4097 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 4098 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4099 *tl = txdr_unsigned(RPCAUTH_GSS); 4100 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 4101 nfsgss_mechlist[KERBV_MECH].len); 4102 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4103 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 4104 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 4105 len++; 4106 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 4107 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4108 *tl = txdr_unsigned(RPCAUTH_GSS); 4109 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 4110 nfsgss_mechlist[KERBV_MECH].len); 4111 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4112 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 4113 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 4114 len++; 4115 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 4116 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4117 *tl = txdr_unsigned(RPCAUTH_GSS); 4118 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 4119 nfsgss_mechlist[KERBV_MECH].len); 4120 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4121 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 4122 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 4123 len++; 4124 } 4125 } 4126 *sizp = txdr_unsigned(len); 4127 4128 nfsmout: 4129 NFSEXITCODE2(error, nd); 4130 return (error); 4131 } 4132 4133 /* 4134 * nfsv4 set client id service 4135 */ 4136 int 4137 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 4138 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4139 { 4140 u_int32_t *tl; 4141 int i; 4142 int error = 0, idlen; 4143 struct nfsclient *clp = NULL; 4144 #ifdef INET 4145 struct sockaddr_in *rin; 4146 #endif 4147 #ifdef INET6 4148 struct sockaddr_in6 *rin6; 4149 #endif 4150 #if defined(INET) || defined(INET6) 4151 u_char *ucp, *ucp2; 4152 #endif 4153 u_char *verf, *addrbuf; 4154 nfsquad_t clientid, confirm; 4155 struct thread *p = curthread; 4156 4157 if ((nd->nd_flag & ND_NFSV41) != 0) { 4158 nd->nd_repstat = NFSERR_NOTSUPP; 4159 goto nfsmout; 4160 } 4161 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4162 goto out; 4163 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 4164 verf = (u_char *)tl; 4165 tl += (NFSX_VERF / NFSX_UNSIGNED); 4166 i = fxdr_unsigned(int, *tl); 4167 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 4168 nd->nd_repstat = NFSERR_BADXDR; 4169 goto nfsmout; 4170 } 4171 idlen = i; 4172 if (nd->nd_flag & ND_GSS) 4173 i += nd->nd_princlen; 4174 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 4175 M_ZERO); 4176 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 4177 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 4178 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 4179 /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 4180 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 4181 M_WAITOK | M_ZERO); 4182 clp->lc_req.nr_cred = NULL; 4183 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 4184 clp->lc_idlen = idlen; 4185 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 4186 if (error) 4187 goto nfsmout; 4188 if (nd->nd_flag & ND_GSS) { 4189 clp->lc_flags = LCL_GSS; 4190 if (nd->nd_flag & ND_GSSINTEGRITY) 4191 clp->lc_flags |= LCL_GSSINTEGRITY; 4192 else if (nd->nd_flag & ND_GSSPRIVACY) 4193 clp->lc_flags |= LCL_GSSPRIVACY; 4194 } else { 4195 clp->lc_flags = 0; 4196 } 4197 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 4198 clp->lc_flags |= LCL_NAME; 4199 clp->lc_namelen = nd->nd_princlen; 4200 clp->lc_name = &clp->lc_id[idlen]; 4201 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 4202 } else { 4203 clp->lc_uid = nd->nd_cred->cr_uid; 4204 clp->lc_gid = nd->nd_cred->cr_gid; 4205 } 4206 4207 /* If the client is using TLS, do so for the callback connection. */ 4208 if (nd->nd_flag & ND_TLS) 4209 clp->lc_flags |= LCL_TLSCB; 4210 4211 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4212 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 4213 error = nfsrv_getclientipaddr(nd, clp); 4214 if (error) 4215 goto nfsmout; 4216 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4217 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 4218 4219 /* 4220 * nfsrv_setclient() does the actual work of adding it to the 4221 * client list. If there is no error, the structure has been 4222 * linked into the client list and clp should no longer be used 4223 * here. When an error is returned, it has not been linked in, 4224 * so it should be free'd. 4225 */ 4226 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 4227 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 4228 /* 4229 * 8 is the maximum length of the port# string. 4230 */ 4231 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK); 4232 switch (clp->lc_req.nr_nam->sa_family) { 4233 #ifdef INET 4234 case AF_INET: 4235 if (clp->lc_flags & LCL_TCPCALLBACK) 4236 (void) nfsm_strtom(nd, "tcp", 3); 4237 else 4238 (void) nfsm_strtom(nd, "udp", 3); 4239 rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4240 ucp = (u_char *)&rin->sin_addr.s_addr; 4241 ucp2 = (u_char *)&rin->sin_port; 4242 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 4243 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 4244 ucp2[0] & 0xff, ucp2[1] & 0xff); 4245 break; 4246 #endif 4247 #ifdef INET6 4248 case AF_INET6: 4249 if (clp->lc_flags & LCL_TCPCALLBACK) 4250 (void) nfsm_strtom(nd, "tcp6", 4); 4251 else 4252 (void) nfsm_strtom(nd, "udp6", 4); 4253 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4254 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf, 4255 INET6_ADDRSTRLEN); 4256 if (ucp != NULL) 4257 i = strlen(ucp); 4258 else 4259 i = 0; 4260 ucp2 = (u_char *)&rin6->sin6_port; 4261 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff, 4262 ucp2[1] & 0xff); 4263 break; 4264 #endif 4265 } 4266 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 4267 free(addrbuf, M_TEMP); 4268 } 4269 if (clp) { 4270 free(clp->lc_req.nr_nam, M_SONAME); 4271 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4272 free(clp->lc_stateid, M_NFSDCLIENT); 4273 free(clp, M_NFSDCLIENT); 4274 } 4275 if (!nd->nd_repstat) { 4276 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 4277 *tl++ = clientid.lval[0]; 4278 *tl++ = clientid.lval[1]; 4279 *tl++ = confirm.lval[0]; 4280 *tl = confirm.lval[1]; 4281 } 4282 4283 out: 4284 NFSEXITCODE2(0, nd); 4285 return (0); 4286 nfsmout: 4287 if (clp) { 4288 free(clp->lc_req.nr_nam, M_SONAME); 4289 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4290 free(clp->lc_stateid, M_NFSDCLIENT); 4291 free(clp, M_NFSDCLIENT); 4292 } 4293 NFSEXITCODE2(error, nd); 4294 return (error); 4295 } 4296 4297 /* 4298 * nfsv4 set client id confirm service 4299 */ 4300 int 4301 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 4302 __unused int isdgram, __unused vnode_t vp, 4303 __unused struct nfsexstuff *exp) 4304 { 4305 u_int32_t *tl; 4306 int error = 0; 4307 nfsquad_t clientid, confirm; 4308 struct thread *p = curthread; 4309 4310 if ((nd->nd_flag & ND_NFSV41) != 0) { 4311 nd->nd_repstat = NFSERR_NOTSUPP; 4312 goto nfsmout; 4313 } 4314 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4315 goto nfsmout; 4316 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 4317 clientid.lval[0] = *tl++; 4318 clientid.lval[1] = *tl++; 4319 confirm.lval[0] = *tl++; 4320 confirm.lval[1] = *tl; 4321 4322 /* 4323 * nfsrv_getclient() searches the client list for a match and 4324 * returns the appropriate NFSERR status. 4325 */ 4326 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 4327 NULL, NULL, confirm, 0, nd, p); 4328 nfsmout: 4329 NFSEXITCODE2(error, nd); 4330 return (error); 4331 } 4332 4333 /* 4334 * nfsv4 verify service 4335 */ 4336 int 4337 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 4338 vnode_t vp, __unused struct nfsexstuff *exp) 4339 { 4340 int error = 0, ret, fhsize = NFSX_MYFH; 4341 struct nfsvattr nva; 4342 struct statfs *sf; 4343 struct nfsfsinfo fs; 4344 fhandle_t fh; 4345 struct thread *p = curthread; 4346 4347 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 4348 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 4349 if (!nd->nd_repstat) 4350 nd->nd_repstat = nfsvno_statfs(vp, sf); 4351 if (!nd->nd_repstat) 4352 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 4353 if (!nd->nd_repstat) { 4354 nfsvno_getfs(&fs, isdgram); 4355 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 4356 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, NULL, NULL, p, 4357 nd->nd_cred); 4358 if (!error) { 4359 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 4360 if (ret == 0) 4361 nd->nd_repstat = NFSERR_SAME; 4362 else if (ret != NFSERR_NOTSAME) 4363 nd->nd_repstat = ret; 4364 } else if (ret) 4365 nd->nd_repstat = ret; 4366 } 4367 } 4368 vput(vp); 4369 free(sf, M_STATFS); 4370 NFSEXITCODE2(error, nd); 4371 return (error); 4372 } 4373 4374 /* 4375 * nfs openattr rpc 4376 */ 4377 int 4378 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 4379 struct vnode *dp, struct vnode **vpp, __unused fhandle_t *fhp, 4380 __unused struct nfsexstuff *exp) 4381 { 4382 uint32_t *tl; 4383 struct componentname cn; 4384 int error = 0; 4385 4386 NFSNAMEICNDSET(&cn, nd->nd_cred, LOOKUP, OPENNAMED | ISLASTCN | 4387 NOFOLLOW | LOCKLEAF); 4388 cn.cn_nameptr = "."; 4389 cn.cn_namelen = 1; 4390 cn.cn_lkflags = LK_SHARED; 4391 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4392 if (*tl == newnfs_true) 4393 cn.cn_flags |= CREATENAMED; 4394 4395 nd->nd_repstat = vn_lock(dp, LK_SHARED); 4396 if (nd->nd_repstat != 0) 4397 goto nfsmout; 4398 4399 if ((dp->v_mount->mnt_flag & MNT_NAMEDATTR) == 0) 4400 nd->nd_repstat = NFSERR_NOTSUPP; 4401 if (nd->nd_repstat == 0 && (vn_irflag_read(dp) & (VIRF_NAMEDDIR | 4402 VIRF_NAMEDATTR)) != 0) 4403 nd->nd_repstat = NFSERR_WRONGTYPE; 4404 if (nd->nd_repstat == 0) { 4405 nd->nd_repstat = VOP_LOOKUP(dp, vpp, &cn); 4406 if (nd->nd_repstat == ENOATTR) 4407 nd->nd_repstat = NFSERR_NOENT; 4408 } 4409 if (nd->nd_repstat == 0) 4410 NFSVOPUNLOCK(*vpp); 4411 4412 vput(dp); 4413 NFSEXITCODE2(0, nd); 4414 return (0); 4415 nfsmout: 4416 vrele(dp); 4417 NFSEXITCODE2(error, nd); 4418 return (error); 4419 } 4420 4421 /* 4422 * nfsv4 release lock owner service 4423 */ 4424 int 4425 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 4426 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4427 { 4428 u_int32_t *tl; 4429 struct nfsstate *stp = NULL; 4430 int error = 0, len; 4431 nfsquad_t clientid; 4432 struct thread *p = curthread; 4433 4434 if ((nd->nd_flag & ND_NFSV41) != 0) { 4435 nd->nd_repstat = NFSERR_NOTSUPP; 4436 goto nfsmout; 4437 } 4438 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4439 goto nfsmout; 4440 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 4441 len = fxdr_unsigned(int, *(tl + 2)); 4442 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 4443 nd->nd_repstat = NFSERR_BADXDR; 4444 goto nfsmout; 4445 } 4446 stp = malloc(sizeof (struct nfsstate) + len, 4447 M_NFSDSTATE, M_WAITOK); 4448 stp->ls_ownerlen = len; 4449 stp->ls_op = NULL; 4450 stp->ls_flags = NFSLCK_RELEASE; 4451 stp->ls_uid = nd->nd_cred->cr_uid; 4452 clientid.lval[0] = *tl++; 4453 clientid.lval[1] = *tl; 4454 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 4455 if ((nd->nd_flag & ND_NFSV41) != 0) 4456 clientid.qval = nd->nd_clientid.qval; 4457 else if (nd->nd_clientid.qval != clientid.qval) 4458 printf("EEK14 multiple clids\n"); 4459 } else { 4460 if ((nd->nd_flag & ND_NFSV41) != 0) 4461 printf("EEK! no clientid from session\n"); 4462 nd->nd_flag |= ND_IMPLIEDCLID; 4463 nd->nd_clientid.qval = clientid.qval; 4464 } 4465 error = nfsrv_mtostr(nd, stp->ls_owner, len); 4466 if (error) 4467 goto nfsmout; 4468 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 4469 free(stp, M_NFSDSTATE); 4470 4471 NFSEXITCODE2(0, nd); 4472 return (0); 4473 nfsmout: 4474 if (stp) 4475 free(stp, M_NFSDSTATE); 4476 NFSEXITCODE2(error, nd); 4477 return (error); 4478 } 4479 4480 /* 4481 * nfsv4 exchange_id service 4482 */ 4483 int 4484 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 4485 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4486 { 4487 uint32_t *tl; 4488 int error = 0, i, idlen; 4489 struct nfsclient *clp = NULL; 4490 nfsquad_t clientid, confirm; 4491 uint8_t *verf; 4492 uint32_t sp4type, v41flags; 4493 struct timespec verstime; 4494 nfsopbit_t mustops, allowops; 4495 #ifdef INET 4496 struct sockaddr_in *sin, *rin; 4497 #endif 4498 #ifdef INET6 4499 struct sockaddr_in6 *sin6, *rin6; 4500 #endif 4501 struct thread *p = curthread; 4502 char *s; 4503 4504 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4505 goto nfsmout; 4506 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 4507 verf = (uint8_t *)tl; 4508 tl += (NFSX_VERF / NFSX_UNSIGNED); 4509 i = fxdr_unsigned(int, *tl); 4510 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 4511 nd->nd_repstat = NFSERR_BADXDR; 4512 goto nfsmout; 4513 } 4514 idlen = i; 4515 if (nd->nd_flag & ND_GSS) 4516 i += nd->nd_princlen; 4517 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 4518 M_ZERO); 4519 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 4520 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 4521 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 4522 /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 4523 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 4524 M_WAITOK | M_ZERO); 4525 switch (nd->nd_nam->sa_family) { 4526 #ifdef INET 4527 case AF_INET: 4528 rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4529 sin = (struct sockaddr_in *)nd->nd_nam; 4530 rin->sin_family = AF_INET; 4531 rin->sin_len = sizeof(struct sockaddr_in); 4532 rin->sin_port = 0; 4533 rin->sin_addr.s_addr = sin->sin_addr.s_addr; 4534 break; 4535 #endif 4536 #ifdef INET6 4537 case AF_INET6: 4538 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4539 sin6 = (struct sockaddr_in6 *)nd->nd_nam; 4540 rin6->sin6_family = AF_INET6; 4541 rin6->sin6_len = sizeof(struct sockaddr_in6); 4542 rin6->sin6_port = 0; 4543 rin6->sin6_addr = sin6->sin6_addr; 4544 break; 4545 #endif 4546 } 4547 clp->lc_req.nr_cred = NULL; 4548 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 4549 clp->lc_idlen = idlen; 4550 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 4551 if (error != 0) 4552 goto nfsmout; 4553 if ((nd->nd_flag & ND_GSS) != 0) { 4554 clp->lc_flags = LCL_GSS | LCL_NFSV41; 4555 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 4556 clp->lc_flags |= LCL_GSSINTEGRITY; 4557 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 4558 clp->lc_flags |= LCL_GSSPRIVACY; 4559 } else 4560 clp->lc_flags = LCL_NFSV41; 4561 if ((nd->nd_flag & ND_NFSV42) != 0) 4562 clp->lc_flags |= LCL_NFSV42; 4563 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 4564 clp->lc_flags |= LCL_NAME; 4565 clp->lc_namelen = nd->nd_princlen; 4566 clp->lc_name = &clp->lc_id[idlen]; 4567 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 4568 } else { 4569 clp->lc_uid = nd->nd_cred->cr_uid; 4570 clp->lc_gid = nd->nd_cred->cr_gid; 4571 } 4572 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4573 v41flags = fxdr_unsigned(uint32_t, *tl++); 4574 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 4575 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 4576 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 4577 nd->nd_repstat = NFSERR_INVAL; 4578 goto nfsmout; 4579 } 4580 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 4581 confirm.lval[1] = 1; 4582 else 4583 confirm.lval[1] = 0; 4584 if (nfsrv_devidcnt == 0) 4585 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS; 4586 else 4587 v41flags = NFSV4EXCH_USEPNFSMDS; 4588 sp4type = fxdr_unsigned(uint32_t, *tl); 4589 if (sp4type == NFSV4EXCH_SP4MACHCRED) { 4590 if ((nd->nd_flag & (ND_GSSINTEGRITY | ND_GSSPRIVACY)) == 0 || 4591 nd->nd_princlen == 0) 4592 nd->nd_repstat = (NFSERR_AUTHERR | AUTH_TOOWEAK); 4593 if (nd->nd_repstat == 0) 4594 nd->nd_repstat = nfsrv_getopbits(nd, &mustops, NULL); 4595 if (nd->nd_repstat == 0) 4596 nd->nd_repstat = nfsrv_getopbits(nd, &allowops, NULL); 4597 if (nd->nd_repstat != 0) 4598 goto nfsmout; 4599 NFSOPBIT_CLRNOTMUST(&mustops); 4600 NFSSET_OPBIT(&clp->lc_mustops, &mustops); 4601 NFSOPBIT_CLRNOTALLOWED(&allowops); 4602 NFSSET_OPBIT(&clp->lc_allowops, &allowops); 4603 clp->lc_flags |= LCL_MACHCRED; 4604 } else if (sp4type != NFSV4EXCH_SP4NONE) { 4605 nd->nd_repstat = NFSERR_NOTSUPP; 4606 goto nfsmout; 4607 } 4608 4609 /* 4610 * nfsrv_setclient() does the actual work of adding it to the 4611 * client list. If there is no error, the structure has been 4612 * linked into the client list and clp should no longer be used 4613 * here. When an error is returned, it has not been linked in, 4614 * so it should be free'd. 4615 */ 4616 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 4617 if (clp != NULL) { 4618 free(clp->lc_req.nr_nam, M_SONAME); 4619 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4620 free(clp->lc_stateid, M_NFSDCLIENT); 4621 free(clp, M_NFSDCLIENT); 4622 } 4623 if (nd->nd_repstat == 0) { 4624 if (confirm.lval[1] != 0) 4625 v41flags |= NFSV4EXCH_CONFIRMEDR; 4626 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 4627 *tl++ = clientid.lval[0]; /* ClientID */ 4628 *tl++ = clientid.lval[1]; 4629 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 4630 *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 4631 *tl = txdr_unsigned(sp4type); /* No SSV */ 4632 if (sp4type == NFSV4EXCH_SP4MACHCRED) { 4633 nfsrv_putopbit(nd, &mustops); 4634 nfsrv_putopbit(nd, &allowops); 4635 } 4636 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER); 4637 txdr_hyper(nfsrv_owner_minor, tl); /* Owner Minor */ 4638 if (nfsrv_owner_major[0] != 0) 4639 s = nfsrv_owner_major; 4640 else 4641 s = nd->nd_cred->cr_prison->pr_hostuuid; 4642 nfsm_strtom(nd, s, strlen(s)); /* Owner Major */ 4643 if (nfsrv_scope[0] != 0) 4644 s = nfsrv_scope; 4645 else 4646 s = nd->nd_cred->cr_prison->pr_hostuuid; 4647 nfsm_strtom(nd, s, strlen(s) ); /* Scope */ 4648 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4649 *tl = txdr_unsigned(1); 4650 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4651 (void)nfsm_strtom(nd, version, strlen(version)); 4652 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4653 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4654 verstime.tv_nsec = 0; 4655 txdr_nfsv4time(&verstime, tl); 4656 } 4657 NFSEXITCODE2(0, nd); 4658 return (0); 4659 nfsmout: 4660 if (clp != NULL) { 4661 free(clp->lc_req.nr_nam, M_SONAME); 4662 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4663 free(clp->lc_stateid, M_NFSDCLIENT); 4664 free(clp, M_NFSDCLIENT); 4665 } 4666 NFSEXITCODE2(error, nd); 4667 return (error); 4668 } 4669 4670 /* 4671 * nfsv4 create session service 4672 */ 4673 int 4674 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 4675 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4676 { 4677 uint32_t *tl; 4678 int error = 0; 4679 nfsquad_t clientid, confirm; 4680 struct nfsdsession *sep = NULL; 4681 uint32_t rdmacnt; 4682 struct thread *p = curthread; 4683 static bool do_printf = true; 4684 4685 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4686 goto nfsmout; 4687 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 4688 M_NFSDSESSION, M_WAITOK | M_ZERO); 4689 sep->sess_refcnt = 1; 4690 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 4691 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 4692 clientid.lval[0] = *tl++; 4693 clientid.lval[1] = *tl++; 4694 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 4695 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 4696 /* Persistent sessions and RDMA are not supported. */ 4697 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 4698 4699 /* Fore channel attributes. */ 4700 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4701 tl++; /* Header pad always 0. */ 4702 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 4703 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) { 4704 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR; 4705 if (do_printf) 4706 printf("Consider increasing kern.ipc.maxsockbuf\n"); 4707 do_printf = false; 4708 } 4709 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 4710 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) { 4711 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR; 4712 if (do_printf) 4713 printf("Consider increasing kern.ipc.maxsockbuf\n"); 4714 do_printf = false; 4715 } 4716 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 4717 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 4718 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 4719 if (sep->sess_maxslots > NFSV4_SLOTS) 4720 sep->sess_maxslots = NFSV4_SLOTS; 4721 rdmacnt = fxdr_unsigned(uint32_t, *tl); 4722 if (rdmacnt > 1) { 4723 nd->nd_repstat = NFSERR_BADXDR; 4724 goto nfsmout; 4725 } else if (rdmacnt == 1) 4726 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4727 4728 /* Back channel attributes. */ 4729 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4730 tl++; /* Header pad always 0. */ 4731 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 4732 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 4733 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 4734 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 4735 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 4736 rdmacnt = fxdr_unsigned(uint32_t, *tl); 4737 if (rdmacnt > 1) { 4738 nd->nd_repstat = NFSERR_BADXDR; 4739 goto nfsmout; 4740 } else if (rdmacnt == 1) 4741 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4742 4743 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4744 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 4745 4746 /* 4747 * nfsrv_getclient() searches the client list for a match and 4748 * returns the appropriate NFSERR status. 4749 */ 4750 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 4751 NULL, sep, confirm, sep->sess_cbprogram, nd, p); 4752 if (nd->nd_repstat == 0) { 4753 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4754 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 4755 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 4756 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 4757 *tl++ = txdr_unsigned(sep->sess_crflags); 4758 4759 /* Fore channel attributes. */ 4760 *tl++ = 0; 4761 *tl++ = txdr_unsigned(sep->sess_maxreq); 4762 *tl++ = txdr_unsigned(sep->sess_maxresp); 4763 *tl++ = txdr_unsigned(sep->sess_maxrespcached); 4764 *tl++ = txdr_unsigned(sep->sess_maxops); 4765 *tl++ = txdr_unsigned(sep->sess_maxslots); 4766 *tl++ = txdr_unsigned(1); 4767 *tl++ = txdr_unsigned(0); /* No RDMA. */ 4768 4769 /* Back channel attributes. */ 4770 *tl++ = 0; 4771 *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 4772 *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 4773 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 4774 *tl++ = txdr_unsigned(sep->sess_cbmaxops); 4775 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 4776 *tl++ = txdr_unsigned(1); 4777 *tl = txdr_unsigned(0); /* No RDMA. */ 4778 } 4779 nfsmout: 4780 if (nd->nd_repstat != 0 && sep != NULL) 4781 free(sep, M_NFSDSESSION); 4782 NFSEXITCODE2(error, nd); 4783 return (error); 4784 } 4785 4786 /* 4787 * nfsv4 sequence service 4788 */ 4789 int 4790 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 4791 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4792 { 4793 uint32_t *tl; 4794 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 4795 int cache_this, error = 0; 4796 struct thread *p = curthread; 4797 4798 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4799 goto nfsmout; 4800 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 4801 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 4802 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4803 sequenceid = fxdr_unsigned(uint32_t, *tl++); 4804 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 4805 highest_slotid = fxdr_unsigned(uint32_t, *tl++); 4806 if (*tl == newnfs_true) 4807 cache_this = 1; 4808 else 4809 cache_this = 0; 4810 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 4811 &target_highest_slotid, cache_this, &sflags, p); 4812 if (nd->nd_repstat != NFSERR_BADSLOT) 4813 nd->nd_flag |= ND_HASSEQUENCE; 4814 if (nd->nd_repstat == 0) { 4815 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4816 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 4817 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 4818 *tl++ = txdr_unsigned(sequenceid); 4819 *tl++ = txdr_unsigned(nd->nd_slotid); 4820 *tl++ = txdr_unsigned(highest_slotid); 4821 *tl++ = txdr_unsigned(target_highest_slotid); 4822 *tl = txdr_unsigned(sflags); 4823 } 4824 nfsmout: 4825 NFSEXITCODE2(error, nd); 4826 return (error); 4827 } 4828 4829 /* 4830 * nfsv4 reclaim complete service 4831 */ 4832 int 4833 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 4834 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4835 { 4836 uint32_t *tl; 4837 int error = 0, onefs; 4838 4839 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4840 /* 4841 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only 4842 * to be used after a file system has been transferred to a different 4843 * file server. However, RFC5661 is somewhat vague w.r.t. this and 4844 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs 4845 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE. 4846 * Therefore, just ignore the rca_one_fs == TRUE operation and return 4847 * NFS_OK without doing anything. 4848 */ 4849 onefs = 0; 4850 if (*tl == newnfs_true) 4851 onefs = 1; 4852 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs); 4853 nfsmout: 4854 NFSEXITCODE2(error, nd); 4855 return (error); 4856 } 4857 4858 /* 4859 * nfsv4 destroy clientid service 4860 */ 4861 int 4862 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4863 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4864 { 4865 uint32_t *tl; 4866 nfsquad_t clientid; 4867 int error = 0; 4868 struct thread *p = curthread; 4869 4870 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4871 goto nfsmout; 4872 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4873 clientid.lval[0] = *tl++; 4874 clientid.lval[1] = *tl; 4875 nd->nd_repstat = nfsrv_destroyclient(nd, clientid, p); 4876 nfsmout: 4877 NFSEXITCODE2(error, nd); 4878 return (error); 4879 } 4880 4881 /* 4882 * nfsv4 bind connection to session service 4883 */ 4884 int 4885 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram, 4886 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4887 { 4888 uint32_t *tl; 4889 uint8_t sessid[NFSX_V4SESSIONID]; 4890 int error = 0, foreaft; 4891 4892 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4893 goto nfsmout; 4894 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 4895 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID); 4896 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4897 foreaft = fxdr_unsigned(int, *tl++); 4898 if (*tl == newnfs_true) { 4899 /* RDMA is not supported. */ 4900 nd->nd_repstat = NFSERR_NOTSUPP; 4901 goto nfsmout; 4902 } 4903 4904 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft); 4905 if (nd->nd_repstat == 0) { 4906 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * 4907 NFSX_UNSIGNED); 4908 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID); 4909 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4910 *tl++ = txdr_unsigned(foreaft); 4911 *tl = newnfs_false; 4912 } 4913 nfsmout: 4914 NFSEXITCODE2(error, nd); 4915 return (error); 4916 } 4917 4918 /* 4919 * nfsv4 destroy session service 4920 */ 4921 int 4922 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4923 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4924 { 4925 uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4926 int error = 0; 4927 4928 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4929 goto nfsmout; 4930 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4931 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4932 nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4933 nfsmout: 4934 NFSEXITCODE2(error, nd); 4935 return (error); 4936 } 4937 4938 /* 4939 * nfsv4 free stateid service 4940 */ 4941 int 4942 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4943 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4944 { 4945 uint32_t *tl; 4946 nfsv4stateid_t stateid; 4947 int error = 0; 4948 struct thread *p = curthread; 4949 4950 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4951 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4952 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4953 4954 /* 4955 * For the special stateid of other all 0s and seqid == 1, set the 4956 * stateid to the current stateid, if it is set. 4957 */ 4958 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4959 stateid.other[1] == 0 && stateid.other[2] == 0) { 4960 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4961 stateid = nd->nd_curstateid; 4962 stateid.seqid = 0; 4963 } else { 4964 nd->nd_repstat = NFSERR_BADSTATEID; 4965 goto nfsmout; 4966 } 4967 } 4968 4969 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 4970 4971 /* If the current stateid has been free'd, unset it. */ 4972 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 && 4973 stateid.other[0] == nd->nd_curstateid.other[0] && 4974 stateid.other[1] == nd->nd_curstateid.other[1] && 4975 stateid.other[2] == nd->nd_curstateid.other[2]) 4976 nd->nd_flag &= ~ND_CURSTATEID; 4977 nfsmout: 4978 NFSEXITCODE2(error, nd); 4979 return (error); 4980 } 4981 4982 /* 4983 * nfsv4 layoutget service 4984 */ 4985 int 4986 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram, 4987 vnode_t vp, struct nfsexstuff *exp) 4988 { 4989 uint32_t *tl; 4990 nfsv4stateid_t stateid; 4991 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose; 4992 uint64_t offset, len, minlen; 4993 char *layp; 4994 struct thread *p = curthread; 4995 4996 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 4997 NFSX_STATEID); 4998 tl++; /* Signal layout available. Ignore for now. */ 4999 layouttype = fxdr_unsigned(int, *tl++); 5000 iomode = fxdr_unsigned(int, *tl++); 5001 offset = fxdr_hyper(tl); tl += 2; 5002 len = fxdr_hyper(tl); tl += 2; 5003 minlen = fxdr_hyper(tl); tl += 2; 5004 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5005 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5006 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5007 maxcnt = fxdr_unsigned(int, *tl); 5008 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n", 5009 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len, 5010 (uintmax_t)minlen); 5011 if (len < minlen || 5012 (minlen != UINT64_MAX && offset + minlen < offset) || 5013 (len != UINT64_MAX && offset + len < offset)) { 5014 nd->nd_repstat = NFSERR_INVAL; 5015 goto nfsmout; 5016 } 5017 5018 /* 5019 * For the special stateid of other all 0s and seqid == 1, set the 5020 * stateid to the current stateid, if it is set. 5021 */ 5022 if (stateid.seqid == 1 && stateid.other[0] == 0 && 5023 stateid.other[1] == 0 && stateid.other[2] == 0) { 5024 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5025 stateid = nd->nd_curstateid; 5026 stateid.seqid = 0; 5027 } else { 5028 nd->nd_repstat = NFSERR_BADSTATEID; 5029 goto nfsmout; 5030 } 5031 } 5032 5033 layp = NULL; 5034 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1) 5035 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK); 5036 else if (layouttype == NFSLAYOUT_FLEXFILE) 5037 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP, 5038 M_WAITOK); 5039 else 5040 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE; 5041 if (layp != NULL) 5042 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype, 5043 &iomode, &offset, &len, minlen, &stateid, maxcnt, 5044 &retonclose, &layoutlen, layp, nd->nd_cred, p); 5045 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat, 5046 layoutlen); 5047 if (nd->nd_repstat == 0) { 5048 /* For NFSv4.1, set the Current StateID. */ 5049 if ((nd->nd_flag & ND_NFSV41) != 0) { 5050 nd->nd_curstateid = stateid; 5051 nd->nd_flag |= ND_CURSTATEID; 5052 } 5053 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID + 5054 2 * NFSX_HYPER); 5055 *tl++ = txdr_unsigned(retonclose); 5056 *tl++ = txdr_unsigned(stateid.seqid); 5057 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 5058 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5059 *tl++ = txdr_unsigned(1); /* Only returns one layout. */ 5060 txdr_hyper(offset, tl); tl += 2; 5061 txdr_hyper(len, tl); tl += 2; 5062 *tl++ = txdr_unsigned(iomode); 5063 *tl = txdr_unsigned(layouttype); 5064 nfsm_strtom(nd, layp, layoutlen); 5065 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) { 5066 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5067 *tl = newnfs_false; 5068 } 5069 free(layp, M_TEMP); 5070 nfsmout: 5071 vput(vp); 5072 NFSEXITCODE2(error, nd); 5073 return (error); 5074 } 5075 5076 /* 5077 * nfsv4 layoutcommit service 5078 */ 5079 int 5080 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram, 5081 vnode_t vp, struct nfsexstuff *exp) 5082 { 5083 uint32_t *tl; 5084 nfsv4stateid_t stateid; 5085 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim; 5086 int hasnewsize; 5087 uint64_t offset, len, newoff = 0, newsize; 5088 struct timespec newmtime; 5089 char *layp; 5090 struct thread *p = curthread; 5091 5092 layp = NULL; 5093 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER + 5094 NFSX_STATEID); 5095 offset = fxdr_hyper(tl); tl += 2; 5096 len = fxdr_hyper(tl); tl += 2; 5097 reclaim = fxdr_unsigned(int, *tl++); 5098 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5099 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5100 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5101 /* 5102 * For the special stateid of other all 0s and seqid == 1, set the 5103 * stateid to the current stateid, if it is set. 5104 */ 5105 if (stateid.seqid == 1 && stateid.other[0] == 0 && 5106 stateid.other[1] == 0 && stateid.other[2] == 0) { 5107 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5108 stateid = nd->nd_curstateid; 5109 stateid.seqid = 0; 5110 } else { 5111 nd->nd_repstat = NFSERR_BADSTATEID; 5112 goto nfsmout; 5113 } 5114 } 5115 5116 hasnewoff = fxdr_unsigned(int, *tl); 5117 if (hasnewoff != 0) { 5118 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 5119 newoff = fxdr_hyper(tl); tl += 2; 5120 } else 5121 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5122 hasnewmtime = fxdr_unsigned(int, *tl); 5123 if (hasnewmtime != 0) { 5124 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED); 5125 fxdr_nfsv4time(tl, &newmtime); 5126 tl += (NFSX_V4TIME / NFSX_UNSIGNED); 5127 } else 5128 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5129 layouttype = fxdr_unsigned(int, *tl++); 5130 maxcnt = fxdr_unsigned(int, *tl); 5131 if (maxcnt > 0) { 5132 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 5133 error = nfsrv_mtostr(nd, layp, maxcnt); 5134 if (error != 0) 5135 goto nfsmout; 5136 } 5137 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff, 5138 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid, 5139 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p); 5140 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat); 5141 if (nd->nd_repstat == 0) { 5142 if (hasnewsize != 0) { 5143 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 5144 *tl++ = newnfs_true; 5145 txdr_hyper(newsize, tl); 5146 } else { 5147 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5148 *tl = newnfs_false; 5149 } 5150 } 5151 nfsmout: 5152 free(layp, M_TEMP); 5153 vput(vp); 5154 NFSEXITCODE2(error, nd); 5155 return (error); 5156 } 5157 5158 /* 5159 * nfsv4 layoutreturn service 5160 */ 5161 int 5162 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram, 5163 vnode_t vp, struct nfsexstuff *exp) 5164 { 5165 uint32_t *tl, *layp; 5166 nfsv4stateid_t stateid; 5167 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim; 5168 uint64_t offset, len; 5169 struct thread *p = curthread; 5170 5171 layp = NULL; 5172 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5173 reclaim = *tl++; 5174 layouttype = fxdr_unsigned(int, *tl++); 5175 iomode = fxdr_unsigned(int, *tl++); 5176 kind = fxdr_unsigned(int, *tl); 5177 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim, 5178 layouttype, iomode, kind); 5179 if (kind == NFSV4LAYOUTRET_FILE) { 5180 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5181 NFSX_UNSIGNED); 5182 offset = fxdr_hyper(tl); tl += 2; 5183 len = fxdr_hyper(tl); tl += 2; 5184 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5185 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5186 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5187 5188 /* 5189 * For the special stateid of other all 0s and seqid == 1, set 5190 * the stateid to the current stateid, if it is set. 5191 */ 5192 if (stateid.seqid == 1 && stateid.other[0] == 0 && 5193 stateid.other[1] == 0 && stateid.other[2] == 0) { 5194 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5195 stateid = nd->nd_curstateid; 5196 stateid.seqid = 0; 5197 } else { 5198 nd->nd_repstat = NFSERR_BADSTATEID; 5199 goto nfsmout; 5200 } 5201 } 5202 5203 maxcnt = fxdr_unsigned(int, *tl); 5204 /* 5205 * There is no fixed upper bound defined in the RFCs, 5206 * but 128Kbytes should be more than sufficient. 5207 */ 5208 if (maxcnt < 0 || maxcnt > 131072) 5209 maxcnt = 0; 5210 if (maxcnt > 0) { 5211 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 5212 error = nfsrv_mtostr(nd, (char *)layp, maxcnt); 5213 if (error != 0) 5214 goto nfsmout; 5215 } 5216 } else { 5217 if (reclaim == newnfs_true) { 5218 nd->nd_repstat = NFSERR_INVAL; 5219 goto nfsmout; 5220 } 5221 offset = len = 0; 5222 maxcnt = 0; 5223 } 5224 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode, 5225 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd, 5226 nd->nd_cred, p); 5227 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat, 5228 fnd); 5229 if (nd->nd_repstat == 0) { 5230 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5231 if (fnd != 0) { 5232 *tl = newnfs_true; 5233 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID); 5234 *tl++ = txdr_unsigned(stateid.seqid); 5235 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 5236 } else 5237 *tl = newnfs_false; 5238 } 5239 nfsmout: 5240 free(layp, M_TEMP); 5241 vput(vp); 5242 NFSEXITCODE2(error, nd); 5243 return (error); 5244 } 5245 5246 /* 5247 * nfsv4 layout error service 5248 */ 5249 int 5250 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram, 5251 vnode_t vp, struct nfsexstuff *exp) 5252 { 5253 uint32_t *tl; 5254 nfsv4stateid_t stateid; 5255 int cnt, error = 0, i, stat; 5256 int opnum __unused; 5257 char devid[NFSX_V4DEVICEID]; 5258 uint64_t offset, len; 5259 5260 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5261 NFSX_UNSIGNED); 5262 offset = fxdr_hyper(tl); tl += 2; 5263 len = fxdr_hyper(tl); tl += 2; 5264 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5265 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5266 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5267 cnt = fxdr_unsigned(int, *tl); 5268 NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset, 5269 (uintmax_t)len, cnt); 5270 /* 5271 * For the special stateid of other all 0s and seqid == 1, set 5272 * the stateid to the current stateid, if it is set. 5273 */ 5274 if (stateid.seqid == 1 && stateid.other[0] == 0 && 5275 stateid.other[1] == 0 && stateid.other[2] == 0) { 5276 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5277 stateid = nd->nd_curstateid; 5278 stateid.seqid = 0; 5279 } else { 5280 nd->nd_repstat = NFSERR_BADSTATEID; 5281 goto nfsmout; 5282 } 5283 } 5284 5285 /* 5286 * Ignore offset, len and stateid for now. 5287 */ 5288 for (i = 0; i < cnt; i++) { 5289 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 * 5290 NFSX_UNSIGNED); 5291 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5292 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5293 stat = fxdr_unsigned(int, *tl++); 5294 opnum = fxdr_unsigned(int, *tl); 5295 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat); 5296 /* 5297 * Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC 5298 * errors, disable the mirror. 5299 */ 5300 if (stat != NFSERR_ACCES && stat != NFSERR_STALE && 5301 stat != NFSERR_NOSPC) 5302 nfsrv_delds(devid, curthread); 5303 5304 /* For NFSERR_NOSPC, mark all deviceids and layouts. */ 5305 if (stat == NFSERR_NOSPC) 5306 nfsrv_marknospc(devid, true); 5307 } 5308 nfsmout: 5309 vput(vp); 5310 NFSEXITCODE2(error, nd); 5311 return (error); 5312 } 5313 5314 /* 5315 * nfsv4 layout stats service 5316 */ 5317 int 5318 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram, 5319 vnode_t vp, struct nfsexstuff *exp) 5320 { 5321 uint32_t *tl; 5322 nfsv4stateid_t stateid; 5323 int cnt, error = 0; 5324 int layouttype __unused; 5325 char devid[NFSX_V4DEVICEID] __unused; 5326 uint64_t offset __unused, len __unused, readcount __unused; 5327 uint64_t readbytes __unused, writecount __unused, writebytes __unused; 5328 5329 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID + 5330 NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED); 5331 offset = fxdr_hyper(tl); tl += 2; 5332 len = fxdr_hyper(tl); tl += 2; 5333 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5334 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5335 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5336 readcount = fxdr_hyper(tl); tl += 2; 5337 readbytes = fxdr_hyper(tl); tl += 2; 5338 writecount = fxdr_hyper(tl); tl += 2; 5339 writebytes = fxdr_hyper(tl); tl += 2; 5340 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5341 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5342 layouttype = fxdr_unsigned(int, *tl++); 5343 cnt = fxdr_unsigned(int, *tl); 5344 error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1); 5345 if (error != 0) 5346 goto nfsmout; 5347 NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt); 5348 /* 5349 * For the special stateid of other all 0s and seqid == 1, set 5350 * the stateid to the current stateid, if it is set. 5351 */ 5352 if (stateid.seqid == 1 && stateid.other[0] == 0 && 5353 stateid.other[1] == 0 && stateid.other[2] == 0) { 5354 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5355 stateid = nd->nd_curstateid; 5356 stateid.seqid = 0; 5357 } else { 5358 nd->nd_repstat = NFSERR_BADSTATEID; 5359 goto nfsmout; 5360 } 5361 } 5362 5363 /* 5364 * No use for the stats for now. 5365 */ 5366 nfsmout: 5367 vput(vp); 5368 NFSEXITCODE2(error, nd); 5369 return (error); 5370 } 5371 5372 /* 5373 * nfsv4 io_advise service 5374 */ 5375 int 5376 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram, 5377 vnode_t vp, struct nfsexstuff *exp) 5378 { 5379 uint32_t *tl; 5380 nfsv4stateid_t stateid; 5381 nfsattrbit_t hints; 5382 int error = 0, ret; 5383 off_t offset, len; 5384 5385 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5386 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5387 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5388 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5389 offset = fxdr_hyper(tl); tl += 2; 5390 len = fxdr_hyper(tl); 5391 error = nfsrv_getattrbits(nd, &hints, NULL, NULL); 5392 if (error != 0) 5393 goto nfsmout; 5394 /* 5395 * For the special stateid of other all 0s and seqid == 1, set 5396 * the stateid to the current stateid, if it is set. 5397 */ 5398 if (stateid.seqid == 1 && stateid.other[0] == 0 && 5399 stateid.other[1] == 0 && stateid.other[2] == 0) { 5400 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5401 stateid = nd->nd_curstateid; 5402 stateid.seqid = 0; 5403 } else { 5404 nd->nd_repstat = NFSERR_BADSTATEID; 5405 goto nfsmout; 5406 } 5407 } 5408 5409 if (offset < 0) { 5410 nd->nd_repstat = NFSERR_INVAL; 5411 goto nfsmout; 5412 } 5413 if (len < 0) 5414 len = 0; 5415 if (vp->v_type != VREG) { 5416 if (vp->v_type == VDIR) 5417 nd->nd_repstat = NFSERR_ISDIR; 5418 else 5419 nd->nd_repstat = NFSERR_WRONGTYPE; 5420 goto nfsmout; 5421 } 5422 5423 /* 5424 * For now, we can only handle WILLNEED and DONTNEED and don't use 5425 * the stateid. 5426 */ 5427 if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) && 5428 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) || 5429 (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) && 5430 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) { 5431 NFSVOPUNLOCK(vp); 5432 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) { 5433 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED); 5434 NFSZERO_ATTRBIT(&hints); 5435 if (ret == 0) 5436 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 5437 else 5438 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5439 } else { 5440 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED); 5441 NFSZERO_ATTRBIT(&hints); 5442 if (ret == 0) 5443 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 5444 else 5445 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5446 } 5447 vrele(vp); 5448 } else { 5449 NFSZERO_ATTRBIT(&hints); 5450 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5451 vput(vp); 5452 } 5453 nfsrv_putattrbit(nd, &hints); 5454 NFSEXITCODE2(error, nd); 5455 return (error); 5456 nfsmout: 5457 vput(vp); 5458 NFSEXITCODE2(error, nd); 5459 return (error); 5460 } 5461 5462 /* 5463 * nfsv4 getdeviceinfo service 5464 */ 5465 int 5466 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram, 5467 __unused vnode_t vp, __unused struct nfsexstuff *exp) 5468 { 5469 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP]; 5470 int cnt, devaddrlen, error = 0, i, layouttype; 5471 char devid[NFSX_V4DEVICEID], *devaddr; 5472 time_t dev_time; 5473 5474 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID); 5475 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5476 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5477 layouttype = fxdr_unsigned(int, *tl++); 5478 maxcnt = fxdr_unsigned(uint32_t, *tl++); 5479 cnt = fxdr_unsigned(int, *tl); 5480 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype, 5481 maxcnt, cnt); 5482 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) { 5483 nd->nd_repstat = NFSERR_INVAL; 5484 goto nfsmout; 5485 } 5486 if (cnt > 0) { 5487 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED); 5488 for (i = 0; i < cnt; i++) 5489 notify[i] = fxdr_unsigned(uint32_t, *tl++); 5490 } 5491 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++) 5492 notify[i] = 0; 5493 5494 /* 5495 * Check that the device id is not stale. Device ids are recreated 5496 * each time the nfsd threads are restarted. 5497 */ 5498 NFSBCOPY(devid, &dev_time, sizeof(dev_time)); 5499 if (dev_time != nfsdev_time) { 5500 nd->nd_repstat = NFSERR_NOENT; 5501 goto nfsmout; 5502 } 5503 5504 /* Look for the device id. */ 5505 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt, 5506 notify, &devaddrlen, &devaddr); 5507 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat); 5508 if (nd->nd_repstat == 0) { 5509 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5510 *tl = txdr_unsigned(layouttype); 5511 nfsm_strtom(nd, devaddr, devaddrlen); 5512 cnt = 0; 5513 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) { 5514 if (notify[i] != 0) 5515 cnt = i + 1; 5516 } 5517 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED); 5518 *tl++ = txdr_unsigned(cnt); 5519 for (i = 0; i < cnt; i++) 5520 *tl++ = txdr_unsigned(notify[i]); 5521 } else if (nd->nd_repstat == NFSERR_TOOSMALL) { 5522 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5523 *tl = txdr_unsigned(maxcnt); 5524 } 5525 nfsmout: 5526 NFSEXITCODE2(error, nd); 5527 return (error); 5528 } 5529 5530 /* 5531 * nfsv4 test stateid service 5532 */ 5533 int 5534 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, 5535 __unused vnode_t vp, __unused struct nfsexstuff *exp) 5536 { 5537 uint32_t *tl; 5538 nfsv4stateid_t *stateidp = NULL, *tstateidp; 5539 int cnt, error = 0, i, ret; 5540 struct thread *p = curthread; 5541 5542 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5543 cnt = fxdr_unsigned(int, *tl); 5544 if (cnt <= 0 || cnt > 1024) { 5545 nd->nd_repstat = NFSERR_BADXDR; 5546 goto nfsmout; 5547 } 5548 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); 5549 tstateidp = stateidp; 5550 for (i = 0; i < cnt; i++) { 5551 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5552 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5553 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); 5554 tstateidp++; 5555 } 5556 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5557 *tl = txdr_unsigned(cnt); 5558 tstateidp = stateidp; 5559 for (i = 0; i < cnt; i++) { 5560 ret = nfsrv_teststateid(nd, tstateidp, p); 5561 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5562 *tl = txdr_unsigned(ret); 5563 tstateidp++; 5564 } 5565 nfsmout: 5566 free(stateidp, M_TEMP); 5567 NFSEXITCODE2(error, nd); 5568 return (error); 5569 } 5570 5571 /* 5572 * nfs allocate service 5573 */ 5574 int 5575 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram, 5576 vnode_t vp, struct nfsexstuff *exp) 5577 { 5578 uint32_t *tl; 5579 struct nfsvattr forat; 5580 int error = 0, forat_ret = 1, gotproxystateid; 5581 off_t off, len; 5582 struct nfsstate st, *stp = &st; 5583 struct nfslock lo, *lop = &lo; 5584 nfsv4stateid_t stateid; 5585 nfsquad_t clientid; 5586 nfsattrbit_t attrbits; 5587 5588 if (!nfsrv_doallocate) { 5589 /* 5590 * If any exported file system, such as a ZFS one, cannot 5591 * do VOP_ALLOCATE(), this operation cannot be supported 5592 * for NFSv4.2. This cannot be done 'per filesystem', but 5593 * must be for the entire nfsd NFSv4.2 service. 5594 */ 5595 nd->nd_repstat = NFSERR_NOTSUPP; 5596 goto nfsmout; 5597 } 5598 gotproxystateid = 0; 5599 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5600 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5601 lop->lo_flags = NFSLCK_WRITE; 5602 stp->ls_ownerlen = 0; 5603 stp->ls_op = NULL; 5604 stp->ls_uid = nd->nd_cred->cr_uid; 5605 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 5606 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 5607 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 5608 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 5609 if ((nd->nd_flag & ND_NFSV41) != 0) 5610 clientid.qval = nd->nd_clientid.qval; 5611 else if (nd->nd_clientid.qval != clientid.qval) 5612 printf("EEK2 multiple clids\n"); 5613 } else { 5614 if ((nd->nd_flag & ND_NFSV41) != 0) 5615 printf("EEK! no clientid from session\n"); 5616 nd->nd_flag |= ND_IMPLIEDCLID; 5617 nd->nd_clientid.qval = clientid.qval; 5618 } 5619 stp->ls_stateid.other[2] = *tl++; 5620 /* 5621 * Don't allow this to be done for a DS. 5622 */ 5623 if ((nd->nd_flag & ND_DSSERVER) != 0) 5624 nd->nd_repstat = NFSERR_NOTSUPP; 5625 /* However, allow the proxy stateid. */ 5626 if (stp->ls_stateid.seqid == 0xffffffff && 5627 stp->ls_stateid.other[0] == 0x55555555 && 5628 stp->ls_stateid.other[1] == 0x55555555 && 5629 stp->ls_stateid.other[2] == 0x55555555) 5630 gotproxystateid = 1; 5631 off = fxdr_hyper(tl); tl += 2; 5632 lop->lo_first = off; 5633 len = fxdr_hyper(tl); 5634 lop->lo_end = lop->lo_first + len; 5635 /* 5636 * Sanity check the offset and length. 5637 * off and len are off_t (signed int64_t) whereas 5638 * lo_first and lo_end are uint64_t and, as such, 5639 * if off >= 0 && len > 0, lo_end cannot overflow 5640 * unless off_t is changed to something other than 5641 * int64_t. Check lo_end < lo_first in case that 5642 * is someday the case. 5643 */ 5644 if (nd->nd_repstat == 0 && (len <= 0 || off < 0 || lop->lo_end > 5645 OFF_MAX || lop->lo_end < lop->lo_first)) 5646 nd->nd_repstat = NFSERR_INVAL; 5647 5648 if (nd->nd_repstat == 0 && vp->v_type != VREG) 5649 nd->nd_repstat = NFSERR_WRONGTYPE; 5650 NFSZERO_ATTRBIT(&attrbits); 5651 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5652 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); 5653 if (nd->nd_repstat == 0) 5654 nd->nd_repstat = forat_ret; 5655 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || 5656 NFSVNO_EXSTRICTACCESS(exp))) 5657 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, 5658 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5659 NULL); 5660 if (nd->nd_repstat == 0 && gotproxystateid == 0) 5661 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 5662 &stateid, exp, nd, curthread); 5663 5664 NFSD_DEBUG(4, "nfsrvd_allocate: off=%jd len=%jd stat=%d\n", 5665 (intmax_t)off, (intmax_t)len, nd->nd_repstat); 5666 if (nd->nd_repstat == 0) 5667 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred, 5668 curthread); 5669 NFSD_DEBUG(4, "nfsrvd_allocate: aft nfsvno_allocate=%d\n", 5670 nd->nd_repstat); 5671 vput(vp); 5672 NFSEXITCODE2(0, nd); 5673 return (0); 5674 nfsmout: 5675 vput(vp); 5676 NFSEXITCODE2(error, nd); 5677 return (error); 5678 } 5679 5680 /* 5681 * nfs deallocate service 5682 */ 5683 int 5684 nfsrvd_deallocate(struct nfsrv_descript *nd, __unused int isdgram, 5685 vnode_t vp, struct nfsexstuff *exp) 5686 { 5687 uint32_t *tl; 5688 struct nfsvattr forat; 5689 int error = 0, forat_ret = 1, gotproxystateid; 5690 off_t off, len; 5691 struct nfsstate st, *stp = &st; 5692 struct nfslock lo, *lop = &lo; 5693 nfsv4stateid_t stateid; 5694 nfsquad_t clientid; 5695 nfsattrbit_t attrbits; 5696 5697 gotproxystateid = 0; 5698 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5699 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5700 lop->lo_flags = NFSLCK_WRITE; 5701 stp->ls_ownerlen = 0; 5702 stp->ls_op = NULL; 5703 stp->ls_uid = nd->nd_cred->cr_uid; 5704 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 5705 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 5706 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 5707 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 5708 if ((nd->nd_flag & ND_NFSV41) != 0) 5709 clientid.qval = nd->nd_clientid.qval; 5710 else if (nd->nd_clientid.qval != clientid.qval) 5711 printf("EEK2 multiple clids\n"); 5712 } else { 5713 if ((nd->nd_flag & ND_NFSV41) != 0) 5714 printf("EEK! no clientid from session\n"); 5715 nd->nd_flag |= ND_IMPLIEDCLID; 5716 nd->nd_clientid.qval = clientid.qval; 5717 } 5718 stp->ls_stateid.other[2] = *tl++; 5719 /* 5720 * Don't allow this to be done for a DS. 5721 */ 5722 if ((nd->nd_flag & ND_DSSERVER) != 0) 5723 nd->nd_repstat = NFSERR_NOTSUPP; 5724 /* However, allow the proxy stateid. */ 5725 if (stp->ls_stateid.seqid == 0xffffffff && 5726 stp->ls_stateid.other[0] == 0x55555555 && 5727 stp->ls_stateid.other[1] == 0x55555555 && 5728 stp->ls_stateid.other[2] == 0x55555555) 5729 gotproxystateid = 1; 5730 off = fxdr_hyper(tl); tl += 2; 5731 lop->lo_first = off; 5732 len = fxdr_hyper(tl); 5733 if (len < 0) 5734 len = OFF_MAX; 5735 NFSD_DEBUG(4, "dealloc: off=%jd len=%jd\n", (intmax_t)off, 5736 (intmax_t)len); 5737 lop->lo_end = lop->lo_first + len; 5738 /* 5739 * Sanity check the offset and length. 5740 * off and len are off_t (signed int64_t) whereas 5741 * lo_first and lo_end are uint64_t and, as such, 5742 * if off >= 0 && len > 0, lo_end cannot overflow 5743 * unless off_t is changed to something other than 5744 * int64_t. Check lo_end < lo_first in case that 5745 * is someday the case. 5746 * The error to return is not specified by RFC 7862 so I 5747 * made this compatible with the Linux knfsd. 5748 */ 5749 if (nd->nd_repstat == 0) { 5750 if (off < 0 || lop->lo_end > NFSRV_MAXFILESIZE) 5751 nd->nd_repstat = NFSERR_FBIG; 5752 else if (len == 0 || lop->lo_end < lop->lo_first) 5753 nd->nd_repstat = NFSERR_INVAL; 5754 } 5755 5756 if (nd->nd_repstat == 0 && vp->v_type != VREG) 5757 nd->nd_repstat = NFSERR_WRONGTYPE; 5758 NFSZERO_ATTRBIT(&attrbits); 5759 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5760 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); 5761 if (nd->nd_repstat == 0) 5762 nd->nd_repstat = forat_ret; 5763 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || 5764 NFSVNO_EXSTRICTACCESS(exp))) 5765 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, 5766 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5767 NULL); 5768 if (nd->nd_repstat == 0 && gotproxystateid == 0) 5769 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 5770 &stateid, exp, nd, curthread); 5771 5772 if (nd->nd_repstat == 0) 5773 nd->nd_repstat = nfsvno_deallocate(vp, off, len, nd->nd_cred, 5774 curthread); 5775 vput(vp); 5776 NFSD_DEBUG(4, "eo deallocate=%d\n", nd->nd_repstat); 5777 NFSEXITCODE2(0, nd); 5778 return (0); 5779 nfsmout: 5780 vput(vp); 5781 NFSEXITCODE2(error, nd); 5782 return (error); 5783 } 5784 5785 /* 5786 * nfs copy service 5787 */ 5788 int 5789 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram, 5790 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 5791 { 5792 uint32_t *tl; 5793 struct nfsvattr at; 5794 int cnt, error = 0, ret; 5795 off_t inoff, outoff; 5796 uint64_t len; 5797 size_t xfer; 5798 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst; 5799 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo; 5800 nfsquad_t clientid; 5801 nfsv4stateid_t stateid; 5802 nfsattrbit_t attrbits; 5803 void *rl_rcookie, *rl_wcookie; 5804 5805 rl_rcookie = rl_wcookie = NULL; 5806 if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0) { 5807 /* 5808 * For a pNFS server, reply NFSERR_NOTSUPP so that the client 5809 * will do the copy via I/O on the DS(s). 5810 * If vfs.nfsd.maxcopyrange set to 0, disable Copy. 5811 */ 5812 nd->nd_repstat = NFSERR_NOTSUPP; 5813 goto nfsmout; 5814 } 5815 if (vp == tovp) { 5816 /* Copying a byte range within the same file is not allowed. */ 5817 nd->nd_repstat = NFSERR_INVAL; 5818 goto nfsmout; 5819 } 5820 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER + 5821 3 * NFSX_UNSIGNED); 5822 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 5823 inlop->lo_flags = NFSLCK_READ; 5824 instp->ls_ownerlen = 0; 5825 instp->ls_op = NULL; 5826 instp->ls_uid = nd->nd_cred->cr_uid; 5827 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5828 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++; 5829 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++; 5830 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) 5831 clientid.qval = nd->nd_clientid.qval; 5832 instp->ls_stateid.other[2] = *tl++; 5833 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5834 outlop->lo_flags = NFSLCK_WRITE; 5835 outstp->ls_ownerlen = 0; 5836 outstp->ls_op = NULL; 5837 outstp->ls_uid = nd->nd_cred->cr_uid; 5838 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5839 outstp->ls_stateid.other[0] = *tl++; 5840 outstp->ls_stateid.other[1] = *tl++; 5841 outstp->ls_stateid.other[2] = *tl++; 5842 inoff = fxdr_hyper(tl); tl += 2; 5843 inlop->lo_first = inoff; 5844 outoff = fxdr_hyper(tl); tl += 2; 5845 outlop->lo_first = outoff; 5846 len = fxdr_hyper(tl); tl += 2; 5847 if (len == 0) { 5848 /* len == 0 means to EOF. */ 5849 inlop->lo_end = OFF_MAX; 5850 outlop->lo_end = OFF_MAX; 5851 } else { 5852 inlop->lo_end = inlop->lo_first + len; 5853 outlop->lo_end = outlop->lo_first + len; 5854 } 5855 5856 /* 5857 * At this time only consecutive, synchronous copy is supported, 5858 * so ca_consecutive and ca_synchronous can be ignored. 5859 */ 5860 tl += 2; 5861 5862 cnt = fxdr_unsigned(int, *tl); 5863 if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0) 5864 nd->nd_repstat = NFSERR_NOTSUPP; 5865 if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX || 5866 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX || 5867 inlop->lo_end < inlop->lo_first || outlop->lo_end < 5868 outlop->lo_first)) 5869 nd->nd_repstat = NFSERR_INVAL; 5870 5871 if (nd->nd_repstat == 0 && vp->v_type != VREG) 5872 nd->nd_repstat = NFSERR_WRONGTYPE; 5873 5874 /* Check permissions for the input file. */ 5875 NFSZERO_ATTRBIT(&attrbits); 5876 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5877 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits); 5878 if (nd->nd_repstat == 0) 5879 nd->nd_repstat = ret; 5880 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5881 NFSVNO_EXSTRICTACCESS(exp))) 5882 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5883 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5884 NULL); 5885 if (nd->nd_repstat == 0) 5886 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL, 5887 clientid, &stateid, exp, nd, curthread); 5888 NFSVOPUNLOCK(vp); 5889 if (nd->nd_repstat != 0) 5890 goto out; 5891 5892 error = NFSVOPLOCK(tovp, LK_SHARED); 5893 if (error != 0) 5894 goto out; 5895 if (tovp->v_type != VREG) 5896 nd->nd_repstat = NFSERR_WRONGTYPE; 5897 5898 /* For the output file, we only need the Owner attribute. */ 5899 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits); 5900 if (nd->nd_repstat == 0) 5901 nd->nd_repstat = ret; 5902 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5903 NFSVNO_EXSTRICTACCESS(exp))) 5904 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp, 5905 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5906 NULL); 5907 if (nd->nd_repstat == 0) 5908 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL, 5909 clientid, &stateid, toexp, nd, curthread); 5910 NFSVOPUNLOCK(tovp); 5911 5912 /* Range lock the byte ranges for both invp and outvp. */ 5913 if (nd->nd_repstat == 0) { 5914 for (;;) { 5915 if (len == 0) { 5916 rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5917 OFF_MAX); 5918 rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5919 OFF_MAX); 5920 } else { 5921 rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5922 outoff + len); 5923 rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5924 inoff + len); 5925 } 5926 if (rl_rcookie != NULL) 5927 break; 5928 vn_rangelock_unlock(tovp, rl_wcookie); 5929 if (len == 0) 5930 rl_rcookie = vn_rangelock_rlock(vp, inoff, 5931 OFF_MAX); 5932 else 5933 rl_rcookie = vn_rangelock_rlock(vp, inoff, 5934 inoff + len); 5935 vn_rangelock_unlock(vp, rl_rcookie); 5936 } 5937 5938 error = NFSVOPLOCK(vp, LK_SHARED); 5939 if (error == 0) { 5940 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL); 5941 if (ret == 0) { 5942 /* 5943 * Since invp is range locked, na_size should 5944 * not change. 5945 */ 5946 if (len == 0 && at.na_size > inoff) { 5947 /* 5948 * If len == 0, set it based on invp's 5949 * size. If offset is past EOF, just 5950 * leave len == 0. 5951 */ 5952 len = at.na_size - inoff; 5953 } else if (nfsrv_linux42server == 0 && 5954 inoff + len > at.na_size) { 5955 /* 5956 * RFC-7862 says that NFSERR_INVAL must 5957 * be returned when inoff + len exceeds 5958 * the file size, however the NFSv4.2 5959 * Linux client likes to do this, so 5960 * only check if nfsrv_linux42server 5961 * is not set. 5962 */ 5963 nd->nd_repstat = NFSERR_INVAL; 5964 } 5965 } 5966 NFSVOPUNLOCK(vp); 5967 if (ret != 0 && nd->nd_repstat == 0) 5968 nd->nd_repstat = ret; 5969 } else if (nd->nd_repstat == 0) 5970 nd->nd_repstat = error; 5971 } 5972 5973 /* 5974 * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange. 5975 * This size limit can be set to limit the time a copy RPC will 5976 * take. 5977 */ 5978 if (len > nfsrv_maxcopyrange) 5979 xfer = nfsrv_maxcopyrange; 5980 else 5981 xfer = len; 5982 if (nd->nd_repstat == 0) { 5983 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff, 5984 &xfer, COPY_FILE_RANGE_TIMEO1SEC, nd->nd_cred, nd->nd_cred, 5985 NULL); 5986 if (nd->nd_repstat == 0) 5987 len = xfer; 5988 } 5989 5990 /* Unlock the ranges. */ 5991 if (rl_rcookie != NULL) 5992 vn_rangelock_unlock(vp, rl_rcookie); 5993 if (rl_wcookie != NULL) 5994 vn_rangelock_unlock(tovp, rl_wcookie); 5995 5996 if (nd->nd_repstat == 0) { 5997 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER + 5998 NFSX_VERF); 5999 *tl++ = txdr_unsigned(0); /* No callback ids. */ 6000 txdr_hyper(len, tl); tl += 2; 6001 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE); 6002 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 6003 *tl++ = txdr_unsigned(nfsboottime.tv_usec); 6004 *tl++ = newnfs_true; 6005 *tl = newnfs_true; 6006 } 6007 out: 6008 vrele(vp); 6009 vrele(tovp); 6010 NFSEXITCODE2(error, nd); 6011 return (error); 6012 nfsmout: 6013 vput(vp); 6014 vrele(tovp); 6015 NFSEXITCODE2(error, nd); 6016 return (error); 6017 } 6018 6019 /* 6020 * nfs clone service 6021 */ 6022 int 6023 nfsrvd_clone(struct nfsrv_descript *nd, __unused int isdgram, 6024 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 6025 { 6026 uint32_t *tl; 6027 struct nfsvattr at; 6028 int error = 0, ret; 6029 off_t inoff, outoff; 6030 uint64_t len; 6031 size_t xfer; 6032 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst; 6033 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo; 6034 nfsquad_t clientid; 6035 nfsv4stateid_t stateid; 6036 nfsattrbit_t attrbits; 6037 void *rl_rcookie, *rl_wcookie; 6038 long pathval; 6039 6040 rl_rcookie = rl_wcookie = NULL; 6041 pathval = 0; 6042 if (nfsrv_maxcopyrange == 0 || nfsrv_devidcnt > 0 || 6043 VOP_PATHCONF(vp, _PC_CLONE_BLKSIZE, &pathval) != 0 || 6044 pathval == 0) { 6045 /* 6046 * For a pNFS server, reply NFSERR_NOTSUPP so that the client 6047 * will not do the clone and will do I/O on the DS(s). 6048 * If vfs.nfsd.maxcopyrange set to 0, disable Clone. 6049 */ 6050 nd->nd_repstat = NFSERR_NOTSUPP; 6051 goto nfsmout; 6052 } 6053 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER); 6054 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 6055 inlop->lo_flags = NFSLCK_READ; 6056 instp->ls_ownerlen = 0; 6057 instp->ls_op = NULL; 6058 instp->ls_uid = nd->nd_cred->cr_uid; 6059 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 6060 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++; 6061 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++; 6062 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) 6063 clientid.qval = nd->nd_clientid.qval; 6064 instp->ls_stateid.other[2] = *tl++; 6065 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 6066 outlop->lo_flags = NFSLCK_WRITE; 6067 outstp->ls_ownerlen = 0; 6068 outstp->ls_op = NULL; 6069 outstp->ls_uid = nd->nd_cred->cr_uid; 6070 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 6071 outstp->ls_stateid.other[0] = *tl++; 6072 outstp->ls_stateid.other[1] = *tl++; 6073 outstp->ls_stateid.other[2] = *tl++; 6074 inoff = fxdr_hyper(tl); tl += 2; 6075 inlop->lo_first = inoff; 6076 outoff = fxdr_hyper(tl); tl += 2; 6077 outlop->lo_first = outoff; 6078 len = fxdr_hyper(tl); 6079 if (len == 0) { 6080 /* len == 0 means to EOF. */ 6081 inlop->lo_end = OFF_MAX; 6082 outlop->lo_end = OFF_MAX; 6083 } else { 6084 inlop->lo_end = inlop->lo_first + len; 6085 outlop->lo_end = outlop->lo_first + len; 6086 } 6087 6088 if ((inoff > OFF_MAX || outoff > OFF_MAX || 6089 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX || 6090 inlop->lo_end < inlop->lo_first || outlop->lo_end < 6091 outlop->lo_first)) 6092 nd->nd_repstat = NFSERR_INVAL; 6093 6094 if (nd->nd_repstat == 0 && vp->v_type != VREG) 6095 nd->nd_repstat = NFSERR_WRONGTYPE; 6096 6097 /* Check permissions for the input file. */ 6098 NFSZERO_ATTRBIT(&attrbits); 6099 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 6100 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits); 6101 if (nd->nd_repstat == 0) 6102 nd->nd_repstat = ret; 6103 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 6104 NFSVNO_EXSTRICTACCESS(exp))) 6105 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 6106 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 6107 NULL); 6108 if (nd->nd_repstat == 0) 6109 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL, 6110 clientid, &stateid, exp, nd, curthread); 6111 if (vp != tovp) { 6112 NFSVOPUNLOCK(vp); 6113 if (nd->nd_repstat != 0) 6114 goto out; 6115 6116 error = NFSVOPLOCK(tovp, LK_SHARED); 6117 if (error != 0) 6118 goto out; 6119 pathval = 0; 6120 if (VOP_PATHCONF(tovp, _PC_CLONE_BLKSIZE, &pathval) != 0 || 6121 pathval == 0) 6122 nd->nd_repstat = NFSERR_NOTSUPP; 6123 else if (tovp->v_type != VREG) 6124 nd->nd_repstat = NFSERR_WRONGTYPE; 6125 } 6126 6127 /* For the output file, we only need the Owner attribute. */ 6128 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits); 6129 if (nd->nd_repstat == 0) 6130 nd->nd_repstat = ret; 6131 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 6132 NFSVNO_EXSTRICTACCESS(exp))) 6133 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp, 6134 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 6135 NULL); 6136 if (nd->nd_repstat == 0) 6137 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL, 6138 clientid, &stateid, toexp, nd, curthread); 6139 NFSVOPUNLOCK(tovp); 6140 6141 /* Range lock the byte ranges for both invp and outvp. */ 6142 if (nd->nd_repstat == 0) { 6143 for (;;) { 6144 if (len == 0) 6145 rl_wcookie = vn_rangelock_wlock(tovp, outoff, 6146 OFF_MAX); 6147 else 6148 rl_wcookie = vn_rangelock_wlock(tovp, outoff, 6149 outoff + len); 6150 if (vp != tovp) { 6151 if (len == 0) 6152 rl_rcookie = vn_rangelock_tryrlock(vp, 6153 inoff, OFF_MAX); 6154 else 6155 rl_rcookie = vn_rangelock_tryrlock(vp, 6156 inoff, inoff + len); 6157 if (rl_rcookie != NULL) 6158 break; 6159 } else { 6160 rl_rcookie = NULL; 6161 break; 6162 } 6163 vn_rangelock_unlock(tovp, rl_wcookie); 6164 if (len == 0) 6165 rl_rcookie = vn_rangelock_rlock(vp, inoff, 6166 OFF_MAX); 6167 else 6168 rl_rcookie = vn_rangelock_rlock(vp, inoff, 6169 inoff + len); 6170 vn_rangelock_unlock(vp, rl_rcookie); 6171 } 6172 6173 error = NFSVOPLOCK(vp, LK_SHARED); 6174 if (error == 0) { 6175 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL); 6176 if (ret == 0) { 6177 /* 6178 * Since invp is range locked, na_size should 6179 * not change. 6180 */ 6181 if (len == 0 && at.na_size > inoff) 6182 len = SSIZE_MAX; /* To EOF. */ 6183 else if (inoff + len > at.na_size) 6184 nd->nd_repstat = NFSERR_INVAL; 6185 } 6186 NFSVOPUNLOCK(vp); 6187 if (ret != 0 && nd->nd_repstat == 0) 6188 nd->nd_repstat = ret; 6189 } else if (nd->nd_repstat == 0) 6190 nd->nd_repstat = error; 6191 } 6192 6193 /* 6194 * Do the actual copy to an upper limit of vfs.nfsd.maxcopyrange. 6195 * This size limit can be set to limit the time a copy RPC will 6196 * take. 6197 */ 6198 xfer = len; 6199 if (nd->nd_repstat == 0) { 6200 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff, 6201 &xfer, COPY_FILE_RANGE_CLONE, nd->nd_cred, nd->nd_cred, 6202 NULL); 6203 if (nd->nd_repstat == ENOSYS) 6204 nd->nd_repstat = NFSERR_INVAL; 6205 } 6206 6207 /* Unlock the ranges. */ 6208 if (rl_rcookie != NULL) 6209 vn_rangelock_unlock(vp, rl_rcookie); 6210 if (rl_wcookie != NULL) 6211 vn_rangelock_unlock(tovp, rl_wcookie); 6212 6213 out: 6214 vrele(vp); 6215 vrele(tovp); 6216 NFSEXITCODE2(error, nd); 6217 return (error); 6218 nfsmout: 6219 vput(vp); 6220 vrele(tovp); 6221 NFSEXITCODE2(error, nd); 6222 return (error); 6223 } 6224 6225 /* 6226 * nfs seek service 6227 */ 6228 int 6229 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram, 6230 vnode_t vp, struct nfsexstuff *exp) 6231 { 6232 uint32_t *tl; 6233 struct nfsvattr at; 6234 int content, error = 0; 6235 off_t off; 6236 u_long cmd; 6237 nfsattrbit_t attrbits; 6238 bool eof; 6239 6240 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED); 6241 /* Ignore the stateid for now. */ 6242 tl += (NFSX_STATEID / NFSX_UNSIGNED); 6243 off = fxdr_hyper(tl); tl += 2; 6244 content = fxdr_unsigned(int, *tl); 6245 if (content == NFSV4CONTENT_DATA) 6246 cmd = FIOSEEKDATA; 6247 else if (content == NFSV4CONTENT_HOLE) 6248 cmd = FIOSEEKHOLE; 6249 else 6250 nd->nd_repstat = NFSERR_BADXDR; 6251 if (nd->nd_repstat == 0 && vp->v_type == VDIR) 6252 nd->nd_repstat = NFSERR_ISDIR; 6253 if (nd->nd_repstat == 0 && vp->v_type != VREG) 6254 nd->nd_repstat = NFSERR_WRONGTYPE; 6255 if (nd->nd_repstat == 0 && off < 0) 6256 nd->nd_repstat = NFSERR_NXIO; 6257 if (nd->nd_repstat == 0) { 6258 /* Check permissions for the input file. */ 6259 NFSZERO_ATTRBIT(&attrbits); 6260 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 6261 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1, 6262 &attrbits); 6263 } 6264 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 6265 NFSVNO_EXSTRICTACCESS(exp))) 6266 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 6267 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 6268 NULL); 6269 if (nd->nd_repstat != 0) 6270 goto nfsmout; 6271 6272 /* nfsvno_seek() unlocks and vrele()s the vp. */ 6273 nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof, 6274 nd->nd_cred, curthread); 6275 if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA && 6276 nfsrv_linux42server != 0) 6277 nd->nd_repstat = NFSERR_NXIO; 6278 if (nd->nd_repstat == 0) { 6279 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 6280 if (eof) 6281 *tl++ = newnfs_true; 6282 else 6283 *tl++ = newnfs_false; 6284 txdr_hyper(off, tl); 6285 } 6286 NFSEXITCODE2(error, nd); 6287 return (error); 6288 nfsmout: 6289 vput(vp); 6290 NFSEXITCODE2(error, nd); 6291 return (error); 6292 } 6293 6294 /* 6295 * nfs get extended attribute service 6296 */ 6297 int 6298 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram, 6299 vnode_t vp, __unused struct nfsexstuff *exp) 6300 { 6301 uint32_t *tl; 6302 struct mbuf *mp = NULL, *mpend = NULL; 6303 int error, len; 6304 char *name; 6305 struct thread *p = curthread; 6306 uint16_t off; 6307 6308 error = 0; 6309 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6310 len = fxdr_unsigned(int, *tl); 6311 if (len <= 0) { 6312 nd->nd_repstat = NFSERR_BADXDR; 6313 goto nfsmout; 6314 } 6315 if (len > EXTATTR_MAXNAMELEN) { 6316 nd->nd_repstat = NFSERR_NOXATTR; 6317 goto nfsmout; 6318 } 6319 name = malloc(len + 1, M_TEMP, M_WAITOK); 6320 nd->nd_repstat = nfsrv_mtostr(nd, name, len); 6321 if (nd->nd_repstat == 0) 6322 nd->nd_repstat = nfsvno_getxattr(vp, name, 6323 nd->nd_maxresp, nd->nd_cred, nd->nd_flag, 6324 nd->nd_maxextsiz, p, &mp, &mpend, &len); 6325 if (nd->nd_repstat == ENOATTR) 6326 nd->nd_repstat = NFSERR_NOXATTR; 6327 else if (nd->nd_repstat == EOPNOTSUPP) 6328 nd->nd_repstat = NFSERR_NOTSUPP; 6329 if (nd->nd_repstat == 0) { 6330 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 6331 *tl = txdr_unsigned(len); 6332 if (len > 0) { 6333 nd->nd_mb->m_next = mp; 6334 nd->nd_mb = mpend; 6335 if ((mpend->m_flags & M_EXTPG) != 0) { 6336 nd->nd_flag |= ND_EXTPG; 6337 nd->nd_bextpg = mpend->m_epg_npgs - 1; 6338 nd->nd_bpos = (char *)(void *) 6339 PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]); 6340 off = (nd->nd_bextpg == 0) ? 6341 mpend->m_epg_1st_off : 0; 6342 nd->nd_bpos += off + mpend->m_epg_last_len; 6343 nd->nd_bextpgsiz = PAGE_SIZE - 6344 mpend->m_epg_last_len - off; 6345 } else 6346 nd->nd_bpos = mtod(mpend, char *) + 6347 mpend->m_len; 6348 } 6349 } 6350 free(name, M_TEMP); 6351 6352 nfsmout: 6353 if (nd->nd_repstat == 0) 6354 nd->nd_repstat = error; 6355 vput(vp); 6356 NFSEXITCODE2(0, nd); 6357 return (0); 6358 } 6359 6360 /* 6361 * nfs set extended attribute service 6362 */ 6363 int 6364 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram, 6365 vnode_t vp, __unused struct nfsexstuff *exp) 6366 { 6367 uint32_t *tl; 6368 struct nfsvattr ova, nva; 6369 nfsattrbit_t attrbits; 6370 int error, len, opt; 6371 char *name; 6372 size_t siz; 6373 struct thread *p = curthread; 6374 6375 error = 0; 6376 name = NULL; 6377 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6378 opt = fxdr_unsigned(int, *tl++); 6379 len = fxdr_unsigned(int, *tl); 6380 if (len <= 0) { 6381 nd->nd_repstat = NFSERR_BADXDR; 6382 goto nfsmout; 6383 } 6384 if (len > EXTATTR_MAXNAMELEN) { 6385 nd->nd_repstat = NFSERR_NOXATTR; 6386 goto nfsmout; 6387 } 6388 name = malloc(len + 1, M_TEMP, M_WAITOK); 6389 error = nfsrv_mtostr(nd, name, len); 6390 if (error != 0) 6391 goto nfsmout; 6392 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6393 len = fxdr_unsigned(int, *tl); 6394 if (len < 0 || len > IOSIZE_MAX) { 6395 nd->nd_repstat = NFSERR_XATTR2BIG; 6396 goto nfsmout; 6397 } 6398 switch (opt) { 6399 case NFSV4SXATTR_CREATE: 6400 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 6401 &siz, nd->nd_cred, p); 6402 if (error != ENOATTR) 6403 nd->nd_repstat = NFSERR_EXIST; 6404 error = 0; 6405 break; 6406 case NFSV4SXATTR_REPLACE: 6407 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 6408 &siz, nd->nd_cred, p); 6409 if (error != 0) 6410 nd->nd_repstat = NFSERR_NOXATTR; 6411 break; 6412 case NFSV4SXATTR_EITHER: 6413 break; 6414 default: 6415 nd->nd_repstat = NFSERR_BADXDR; 6416 } 6417 if (nd->nd_repstat != 0) 6418 goto nfsmout; 6419 6420 /* Now, do the Set Extended attribute, with Change before and after. */ 6421 NFSZERO_ATTRBIT(&attrbits); 6422 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 6423 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 6424 if (nd->nd_repstat == 0) { 6425 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md, 6426 nd->nd_dpos, nd->nd_cred, p); 6427 if (nd->nd_repstat == ENXIO) 6428 nd->nd_repstat = NFSERR_XATTR2BIG; 6429 } 6430 if (nd->nd_repstat == 0 && len > 0) 6431 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1); 6432 if (nd->nd_repstat == 0) 6433 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 6434 if (nd->nd_repstat == 0) { 6435 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 6436 *tl++ = newnfs_true; 6437 txdr_hyper(ova.na_filerev, tl); tl += 2; 6438 txdr_hyper(nva.na_filerev, tl); 6439 } 6440 6441 nfsmout: 6442 free(name, M_TEMP); 6443 if (nd->nd_repstat == 0) 6444 nd->nd_repstat = error; 6445 vput(vp); 6446 NFSEXITCODE2(0, nd); 6447 return (0); 6448 } 6449 6450 /* 6451 * nfs remove extended attribute service 6452 */ 6453 int 6454 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram, 6455 vnode_t vp, __unused struct nfsexstuff *exp) 6456 { 6457 uint32_t *tl; 6458 struct nfsvattr ova, nva; 6459 nfsattrbit_t attrbits; 6460 int error, len; 6461 char *name; 6462 struct thread *p = curthread; 6463 6464 error = 0; 6465 name = NULL; 6466 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6467 len = fxdr_unsigned(int, *tl); 6468 if (len <= 0) { 6469 nd->nd_repstat = NFSERR_BADXDR; 6470 goto nfsmout; 6471 } 6472 if (len > EXTATTR_MAXNAMELEN) { 6473 nd->nd_repstat = NFSERR_NOXATTR; 6474 goto nfsmout; 6475 } 6476 name = malloc(len + 1, M_TEMP, M_WAITOK); 6477 error = nfsrv_mtostr(nd, name, len); 6478 if (error != 0) 6479 goto nfsmout; 6480 6481 if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) { 6482 printf("EEK! nfsrvd_rmxattr: no implied clientid\n"); 6483 error = NFSERR_NOXATTR; 6484 goto nfsmout; 6485 } 6486 /* 6487 * Now, do the Remove Extended attribute, with Change before and 6488 * after. 6489 */ 6490 NFSZERO_ATTRBIT(&attrbits); 6491 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 6492 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 6493 if (nd->nd_repstat == 0) { 6494 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p); 6495 if (nd->nd_repstat == ENOATTR) 6496 nd->nd_repstat = NFSERR_NOXATTR; 6497 } 6498 if (nd->nd_repstat == 0) 6499 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 6500 if (nd->nd_repstat == 0) { 6501 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 6502 *tl++ = newnfs_true; 6503 txdr_hyper(ova.na_filerev, tl); tl += 2; 6504 txdr_hyper(nva.na_filerev, tl); 6505 } 6506 6507 nfsmout: 6508 free(name, M_TEMP); 6509 if (nd->nd_repstat == 0) 6510 nd->nd_repstat = error; 6511 vput(vp); 6512 NFSEXITCODE2(0, nd); 6513 return (0); 6514 } 6515 6516 /* 6517 * nfs list extended attribute service 6518 */ 6519 int 6520 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram, 6521 vnode_t vp, __unused struct nfsexstuff *exp) 6522 { 6523 uint32_t cnt, *tl, len, len2, i, pos, retlen; 6524 int error; 6525 uint64_t cookie, cookie2; 6526 u_char *buf; 6527 bool eof; 6528 struct thread *p = curthread; 6529 6530 error = 0; 6531 buf = NULL; 6532 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 6533 /* 6534 * The cookie doesn't need to be in net byte order, but FreeBSD 6535 * does so to make it more readable in packet traces. 6536 */ 6537 cookie = fxdr_hyper(tl); tl += 2; 6538 len = fxdr_unsigned(uint32_t, *tl); 6539 if (len == 0 || cookie >= IOSIZE_MAX) { 6540 nd->nd_repstat = NFSERR_BADXDR; 6541 goto nfsmout; 6542 } 6543 if (len > nd->nd_maxresp - NFS_MAXXDR) 6544 len = nd->nd_maxresp - NFS_MAXXDR; 6545 len2 = len; 6546 nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf, 6547 &len, &eof); 6548 if (nd->nd_repstat == EOPNOTSUPP) 6549 nd->nd_repstat = NFSERR_NOTSUPP; 6550 if (nd->nd_repstat == 0) { 6551 cookie2 = cookie + len; 6552 if (cookie2 < cookie) 6553 nd->nd_repstat = NFSERR_BADXDR; 6554 } 6555 retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED; 6556 if (nd->nd_repstat == 0 && len2 < retlen) 6557 nd->nd_repstat = NFSERR_TOOSMALL; 6558 if (nd->nd_repstat == 0) { 6559 /* Now copy the entries out. */ 6560 if (len == 0) { 6561 /* The cookie was at eof. */ 6562 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * 6563 NFSX_UNSIGNED); 6564 txdr_hyper(cookie2, tl); tl += 2; 6565 *tl++ = txdr_unsigned(0); 6566 *tl = newnfs_true; 6567 goto nfsmout; 6568 } 6569 6570 /* Sanity check the cookie. */ 6571 for (pos = 0; pos < len; pos += (i + 1)) { 6572 if (pos == cookie) 6573 break; 6574 i = buf[pos]; 6575 } 6576 if (pos != cookie) { 6577 nd->nd_repstat = NFSERR_INVAL; 6578 goto nfsmout; 6579 } 6580 6581 /* Loop around copying the entrie(s) out. */ 6582 cnt = 0; 6583 len -= cookie; 6584 i = buf[pos]; 6585 while (i < len && len2 >= retlen + NFSM_RNDUP(i) + 6586 NFSX_UNSIGNED) { 6587 if (cnt == 0) { 6588 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 6589 NFSX_UNSIGNED); 6590 txdr_hyper(cookie2, tl); tl += 2; 6591 } 6592 retlen += nfsm_strtom(nd, &buf[pos + 1], i); 6593 len -= (i + 1); 6594 pos += (i + 1); 6595 i = buf[pos]; 6596 cnt++; 6597 } 6598 /* 6599 * eof is set true/false by nfsvno_listxattr(), but if we 6600 * can't copy all entries returned by nfsvno_listxattr(), 6601 * we are not at eof. 6602 */ 6603 if (len > 0) 6604 eof = false; 6605 if (cnt > 0) { 6606 /* *tl is set above. */ 6607 *tl = txdr_unsigned(cnt); 6608 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 6609 if (eof) 6610 *tl = newnfs_true; 6611 else 6612 *tl = newnfs_false; 6613 } else 6614 nd->nd_repstat = NFSERR_TOOSMALL; 6615 } 6616 6617 nfsmout: 6618 free(buf, M_TEMP); 6619 if (nd->nd_repstat == 0) 6620 nd->nd_repstat = error; 6621 vput(vp); 6622 NFSEXITCODE2(0, nd); 6623 return (0); 6624 } 6625 6626 /* 6627 * nfsv4 service not supported 6628 */ 6629 int 6630 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 6631 __unused vnode_t vp, __unused struct nfsexstuff *exp) 6632 { 6633 6634 nd->nd_repstat = NFSERR_NOTSUPP; 6635 NFSEXITCODE2(0, nd); 6636 return (0); 6637 } 6638