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