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