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