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 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(nd, (u_int8_t *)fhp, 0, 0); 676 nfsrv_fillattr(nd, &nva); 677 } else if (nd->nd_flag & ND_NFSV3) { 678 (void) nfsm_fhtom(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 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(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(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 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(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(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(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(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 2834 #ifdef NFS4_ACL_EXTATTR_NAME 2835 aclp = acl_alloc(M_WAITOK); 2836 aclp->acl_cnt = 0; 2837 #endif 2838 NFSZERO_ATTRBIT(&attrbits); 2839 named.ni_startdir = NULL; 2840 named.ni_cnd.cn_nameiop = 0; 2841 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2842 i = fxdr_unsigned(int, *(tl + 5)); 2843 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2844 nd->nd_repstat = NFSERR_BADXDR; 2845 goto nfsmout; 2846 } 2847 stp = malloc(sizeof (struct nfsstate) + i, 2848 M_NFSDSTATE, M_WAITOK); 2849 stp->ls_ownerlen = i; 2850 stp->ls_op = nd->nd_rp; 2851 stp->ls_flags = NFSLCK_OPEN; 2852 stp->ls_uid = nd->nd_cred->cr_uid; 2853 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2854 i = fxdr_unsigned(int, *tl++); 2855 retext = 0; 2856 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2857 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2858 retext = 1; 2859 /* For now, ignore these. */ 2860 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2861 switch (i & NFSV4OPEN_WANTDELEGMASK) { 2862 case NFSV4OPEN_WANTANYDELEG: 2863 stp->ls_flags |= (NFSLCK_WANTRDELEG | 2864 NFSLCK_WANTWDELEG); 2865 i &= ~NFSV4OPEN_WANTDELEGMASK; 2866 break; 2867 case NFSV4OPEN_WANTREADDELEG: 2868 stp->ls_flags |= NFSLCK_WANTRDELEG; 2869 i &= ~NFSV4OPEN_WANTDELEGMASK; 2870 break; 2871 case NFSV4OPEN_WANTWRITEDELEG: 2872 stp->ls_flags |= NFSLCK_WANTWDELEG; 2873 i &= ~NFSV4OPEN_WANTDELEGMASK; 2874 break; 2875 case NFSV4OPEN_WANTNODELEG: 2876 stp->ls_flags |= NFSLCK_WANTNODELEG; 2877 i &= ~NFSV4OPEN_WANTDELEGMASK; 2878 break; 2879 case NFSV4OPEN_WANTCANCEL: 2880 printf("NFSv4: ignore Open WantCancel\n"); 2881 i &= ~NFSV4OPEN_WANTDELEGMASK; 2882 break; 2883 default: 2884 /* nd_repstat will be set to NFSERR_INVAL below. */ 2885 break; 2886 } 2887 } 2888 switch (i) { 2889 case NFSV4OPEN_ACCESSREAD: 2890 stp->ls_flags |= NFSLCK_READACCESS; 2891 break; 2892 case NFSV4OPEN_ACCESSWRITE: 2893 stp->ls_flags |= NFSLCK_WRITEACCESS; 2894 break; 2895 case NFSV4OPEN_ACCESSBOTH: 2896 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2897 break; 2898 default: 2899 nd->nd_repstat = NFSERR_INVAL; 2900 } 2901 i = fxdr_unsigned(int, *tl++); 2902 switch (i) { 2903 case NFSV4OPEN_DENYNONE: 2904 break; 2905 case NFSV4OPEN_DENYREAD: 2906 stp->ls_flags |= NFSLCK_READDENY; 2907 break; 2908 case NFSV4OPEN_DENYWRITE: 2909 stp->ls_flags |= NFSLCK_WRITEDENY; 2910 break; 2911 case NFSV4OPEN_DENYBOTH: 2912 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 2913 break; 2914 default: 2915 nd->nd_repstat = NFSERR_INVAL; 2916 } 2917 clientid.lval[0] = *tl++; 2918 clientid.lval[1] = *tl; 2919 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2920 if ((nd->nd_flag & ND_NFSV41) != 0) 2921 clientid.qval = nd->nd_clientid.qval; 2922 else if (nd->nd_clientid.qval != clientid.qval) 2923 printf("EEK7 multiple clids\n"); 2924 } else { 2925 if ((nd->nd_flag & ND_NFSV41) != 0) 2926 printf("EEK! no clientid from session\n"); 2927 nd->nd_flag |= ND_IMPLIEDCLID; 2928 nd->nd_clientid.qval = clientid.qval; 2929 } 2930 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2931 if (error) 2932 goto nfsmout; 2933 NFSVNO_ATTRINIT(&nva); 2934 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2935 create = fxdr_unsigned(int, *tl); 2936 if (!nd->nd_repstat) 2937 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 2938 if (create == NFSV4OPEN_CREATE) { 2939 nva.na_type = VREG; 2940 nva.na_mode = 0; 2941 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2942 how = fxdr_unsigned(int, *tl); 2943 switch (how) { 2944 case NFSCREATE_UNCHECKED: 2945 case NFSCREATE_GUARDED: 2946 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2947 if (error) 2948 goto nfsmout; 2949 /* 2950 * If the na_gid being set is the same as that of 2951 * the directory it is going in, clear it, since 2952 * that is what will be set by default. This allows 2953 * a user that isn't in that group to do the create. 2954 */ 2955 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 2956 nva.na_gid == dirfor.na_gid) 2957 NFSVNO_UNSET(&nva, gid); 2958 if (!nd->nd_repstat) 2959 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2960 break; 2961 case NFSCREATE_EXCLUSIVE: 2962 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2963 cverf[0] = *tl++; 2964 cverf[1] = *tl; 2965 break; 2966 case NFSCREATE_EXCLUSIVE41: 2967 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2968 cverf[0] = *tl++; 2969 cverf[1] = *tl; 2970 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2971 if (error != 0) 2972 goto nfsmout; 2973 if (NFSISSET_ATTRBIT(&attrbits, 2974 NFSATTRBIT_TIMEACCESSSET)) 2975 nd->nd_repstat = NFSERR_INVAL; 2976 /* 2977 * If the na_gid being set is the same as that of 2978 * the directory it is going in, clear it, since 2979 * that is what will be set by default. This allows 2980 * a user that isn't in that group to do the create. 2981 */ 2982 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2983 nva.na_gid == dirfor.na_gid) 2984 NFSVNO_UNSET(&nva, gid); 2985 if (nd->nd_repstat == 0) 2986 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2987 break; 2988 default: 2989 nd->nd_repstat = NFSERR_BADXDR; 2990 goto nfsmout; 2991 } 2992 } else if (create != NFSV4OPEN_NOCREATE) { 2993 nd->nd_repstat = NFSERR_BADXDR; 2994 goto nfsmout; 2995 } 2996 2997 /* 2998 * Now, handle the claim, which usually includes looking up a 2999 * name in the directory referenced by dp. The exception is 3000 * NFSV4OPEN_CLAIMPREVIOUS. 3001 */ 3002 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3003 claim = fxdr_unsigned(int, *tl); 3004 if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim == 3005 NFSV4OPEN_CLAIMDELEGATECURFH) { 3006 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3007 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3008 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 3009 stp->ls_flags |= NFSLCK_DELEGCUR; 3010 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim == 3011 NFSV4OPEN_CLAIMDELEGATEPREVFH) { 3012 stp->ls_flags |= NFSLCK_DELEGPREV; 3013 } 3014 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 3015 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 3016 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 3017 claim != NFSV4OPEN_CLAIMNULL) 3018 nd->nd_repstat = NFSERR_INVAL; 3019 if (nd->nd_repstat) { 3020 nd->nd_repstat = nfsrv_opencheck(clientid, 3021 &stateid, stp, NULL, nd, p, nd->nd_repstat); 3022 goto nfsmout; 3023 } 3024 if (create == NFSV4OPEN_CREATE) 3025 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 3026 LOCKPARENT | LOCKLEAF | NOCACHE); 3027 else 3028 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3029 LOCKLEAF); 3030 nfsvno_setpathbuf(&named, &bufp, &hashp); 3031 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3032 if (error) { 3033 vrele(dp); 3034 #ifdef NFS4_ACL_EXTATTR_NAME 3035 acl_free(aclp); 3036 #endif 3037 free(stp, M_NFSDSTATE); 3038 nfsvno_relpathbuf(&named); 3039 NFSEXITCODE2(error, nd); 3040 return (error); 3041 } 3042 if (!nd->nd_repstat) { 3043 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 3044 &dirp); 3045 } else { 3046 vrele(dp); 3047 nfsvno_relpathbuf(&named); 3048 } 3049 if (create == NFSV4OPEN_CREATE) { 3050 switch (how) { 3051 case NFSCREATE_UNCHECKED: 3052 if (named.ni_vp) { 3053 /* 3054 * Clear the setable attribute bits, except 3055 * for Size, if it is being truncated. 3056 */ 3057 NFSZERO_ATTRBIT(&attrbits); 3058 if (NFSVNO_ISSETSIZE(&nva)) 3059 NFSSETBIT_ATTRBIT(&attrbits, 3060 NFSATTRBIT_SIZE); 3061 } 3062 break; 3063 case NFSCREATE_GUARDED: 3064 if (named.ni_vp && !nd->nd_repstat) 3065 nd->nd_repstat = EEXIST; 3066 break; 3067 case NFSCREATE_EXCLUSIVE: 3068 exclusive_flag = 1; 3069 if (!named.ni_vp) 3070 nva.na_mode = 0; 3071 break; 3072 case NFSCREATE_EXCLUSIVE41: 3073 exclusive_flag = 1; 3074 break; 3075 } 3076 } 3077 nfsvno_open(nd, &named, clientid, &stateid, stp, 3078 &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 3079 nd->nd_cred, exp, &vp); 3080 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 3081 NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH || 3082 claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) { 3083 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 3084 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3085 i = fxdr_unsigned(int, *tl); 3086 switch (i) { 3087 case NFSV4OPEN_DELEGATEREAD: 3088 stp->ls_flags |= NFSLCK_DELEGREAD; 3089 break; 3090 case NFSV4OPEN_DELEGATEWRITE: 3091 stp->ls_flags |= NFSLCK_DELEGWRITE; 3092 case NFSV4OPEN_DELEGATENONE: 3093 break; 3094 default: 3095 nd->nd_repstat = NFSERR_BADXDR; 3096 goto nfsmout; 3097 } 3098 stp->ls_flags |= NFSLCK_RECLAIM; 3099 } else { 3100 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 3101 nd->nd_repstat = NFSERR_INVAL; 3102 } 3103 vp = dp; 3104 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3105 if (!VN_IS_DOOMED(vp)) 3106 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 3107 stp, vp, nd, p, nd->nd_repstat); 3108 else 3109 nd->nd_repstat = NFSERR_PERM; 3110 } else { 3111 nd->nd_repstat = NFSERR_BADXDR; 3112 goto nfsmout; 3113 } 3114 3115 /* 3116 * Do basic access checking. 3117 */ 3118 if (!nd->nd_repstat && vp->v_type != VREG) { 3119 /* 3120 * The IETF working group decided that this is the correct 3121 * error return for all non-regular files. 3122 */ 3123 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK; 3124 } 3125 3126 /* 3127 * If the Open is being done for a file that already exists, apply 3128 * normal permission checking including for the file owner, if 3129 * vfs.nfsd.v4openaccess is set. 3130 * Previously, the owner was always allowed to open the file to 3131 * be consistent with the NFS tradition of always allowing the 3132 * owner of the file to write to the file regardless of permissions. 3133 * It now appears that the Linux client expects the owner 3134 * permissions to be checked for opens that are not creating the 3135 * file. I believe the correct approach is to use the Access 3136 * operation's results to be consistent with NFSv3, but that is 3137 * not what the current Linux client appears to be doing. 3138 * Since both the Linux and OpenSolaris NFSv4 servers do this check, 3139 * I have enabled it by default. Since Linux does not apply this 3140 * check for claim_delegate_cur, this code does the same. 3141 * If this semantic change causes a problem, it can be disabled by 3142 * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the 3143 * previous semantics. 3144 */ 3145 if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE && 3146 (stp->ls_flags & NFSLCK_DELEGCUR) == 0) 3147 override = NFSACCCHK_NOOVERRIDE; 3148 else 3149 override = NFSACCCHK_ALLOWOWNER; 3150 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 3151 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 3152 exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 3153 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 3154 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 3155 exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 3156 if (nd->nd_repstat) 3157 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 3158 nd->nd_cred, exp, p, override, 3159 NFSACCCHK_VPISLOCKED, NULL); 3160 } 3161 3162 if (!nd->nd_repstat) { 3163 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 3164 if (!nd->nd_repstat) { 3165 tverf[0] = nva.na_atime.tv_sec; 3166 tverf[1] = nva.na_atime.tv_nsec; 3167 } 3168 } 3169 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 3170 cverf[1] != tverf[1])) 3171 nd->nd_repstat = EEXIST; 3172 /* 3173 * Do the open locking/delegation stuff. 3174 */ 3175 if (!nd->nd_repstat) 3176 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 3177 &delegstateid, &rflags, exp, p, nva.na_filerev); 3178 3179 /* 3180 * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 3181 * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 3182 * (ie: Leave the NFSVOPUNLOCK() about here.) 3183 */ 3184 if (vp) 3185 NFSVOPUNLOCK(vp); 3186 if (stp) 3187 free(stp, M_NFSDSTATE); 3188 if (!nd->nd_repstat && dirp) 3189 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 3190 if (!nd->nd_repstat) { 3191 /* For NFSv4.1, set the Current StateID. */ 3192 if ((nd->nd_flag & ND_NFSV41) != 0) { 3193 nd->nd_curstateid = stateid; 3194 nd->nd_flag |= ND_CURSTATEID; 3195 } 3196 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 3197 *tl++ = txdr_unsigned(stateid.seqid); 3198 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3199 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3200 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 3201 *tl++ = newnfs_true; 3202 *tl++ = 0; 3203 *tl++ = 0; 3204 *tl++ = 0; 3205 *tl++ = 0; 3206 } else { 3207 *tl++ = newnfs_false; /* Since dirp is not locked */ 3208 txdr_hyper(dirfor.na_filerev, tl); 3209 tl += 2; 3210 txdr_hyper(diraft.na_filerev, tl); 3211 tl += 2; 3212 } 3213 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 3214 (void) nfsrv_putattrbit(nd, &attrbits); 3215 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3216 if (rflags & NFSV4OPEN_READDELEGATE) 3217 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 3218 else if (rflags & NFSV4OPEN_WRITEDELEGATE) 3219 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 3220 else if (retext != 0) { 3221 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 3222 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) { 3223 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3224 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3225 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) { 3226 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3227 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE); 3228 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 3229 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3230 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 3231 *tl = newnfs_false; 3232 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 3233 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3234 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 3235 *tl = newnfs_false; 3236 } else { 3237 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3238 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3239 } 3240 } else 3241 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 3242 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 3243 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 3244 *tl++ = txdr_unsigned(delegstateid.seqid); 3245 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 3246 NFSX_STATEIDOTHER); 3247 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3248 if (rflags & NFSV4OPEN_RECALL) 3249 *tl = newnfs_true; 3250 else 3251 *tl = newnfs_false; 3252 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 3253 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3254 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 3255 txdr_hyper(nva.na_size, tl); 3256 } 3257 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3258 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 3259 *tl++ = txdr_unsigned(0x0); 3260 acemask = NFSV4ACE_ALLFILESMASK; 3261 if (nva.na_mode & S_IRUSR) 3262 acemask |= NFSV4ACE_READMASK; 3263 if (nva.na_mode & S_IWUSR) 3264 acemask |= NFSV4ACE_WRITEMASK; 3265 if (nva.na_mode & S_IXUSR) 3266 acemask |= NFSV4ACE_EXECUTEMASK; 3267 *tl = txdr_unsigned(acemask); 3268 (void) nfsm_strtom(nd, "OWNER@", 6); 3269 } 3270 *vpp = vp; 3271 } else if (vp) { 3272 vrele(vp); 3273 } 3274 if (dirp) 3275 vrele(dirp); 3276 #ifdef NFS4_ACL_EXTATTR_NAME 3277 acl_free(aclp); 3278 #endif 3279 NFSEXITCODE2(0, nd); 3280 return (0); 3281 nfsmout: 3282 vrele(dp); 3283 #ifdef NFS4_ACL_EXTATTR_NAME 3284 acl_free(aclp); 3285 #endif 3286 if (stp) 3287 free(stp, M_NFSDSTATE); 3288 NFSEXITCODE2(error, nd); 3289 return (error); 3290 } 3291 3292 /* 3293 * nfsv4 close service 3294 */ 3295 int 3296 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3297 vnode_t vp, __unused struct nfsexstuff *exp) 3298 { 3299 u_int32_t *tl; 3300 struct nfsstate st, *stp = &st; 3301 int error = 0, writeacc; 3302 nfsv4stateid_t stateid; 3303 nfsquad_t clientid; 3304 struct nfsvattr na; 3305 struct thread *p = curthread; 3306 3307 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 3308 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3309 stp->ls_ownerlen = 0; 3310 stp->ls_op = nd->nd_rp; 3311 stp->ls_uid = nd->nd_cred->cr_uid; 3312 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3313 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3314 NFSX_STATEIDOTHER); 3315 3316 /* 3317 * For the special stateid of other all 0s and seqid == 1, set the 3318 * stateid to the current stateid, if it is set. 3319 */ 3320 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 3321 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 3322 stp->ls_stateid.other[2] == 0) { 3323 if ((nd->nd_flag & ND_CURSTATEID) != 0) 3324 stp->ls_stateid = nd->nd_curstateid; 3325 else { 3326 nd->nd_repstat = NFSERR_BADSTATEID; 3327 goto nfsmout; 3328 } 3329 } 3330 3331 stp->ls_flags = NFSLCK_CLOSE; 3332 clientid.lval[0] = stp->ls_stateid.other[0]; 3333 clientid.lval[1] = stp->ls_stateid.other[1]; 3334 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3335 if ((nd->nd_flag & ND_NFSV41) != 0) 3336 clientid.qval = nd->nd_clientid.qval; 3337 else if (nd->nd_clientid.qval != clientid.qval) 3338 printf("EEK8 multiple clids\n"); 3339 } else { 3340 if ((nd->nd_flag & ND_NFSV41) != 0) 3341 printf("EEK! no clientid from session\n"); 3342 nd->nd_flag |= ND_IMPLIEDCLID; 3343 nd->nd_clientid.qval = clientid.qval; 3344 } 3345 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 3346 &writeacc); 3347 /* For pNFS, update the attributes. */ 3348 if (writeacc != 0 || nfsrv_pnfsatime != 0) 3349 nfsrv_updatemdsattr(vp, &na, p); 3350 vput(vp); 3351 if (!nd->nd_repstat) { 3352 /* 3353 * If the stateid that has been closed is the current stateid, 3354 * unset it. 3355 */ 3356 if ((nd->nd_flag & ND_CURSTATEID) != 0 && 3357 stateid.other[0] == nd->nd_curstateid.other[0] && 3358 stateid.other[1] == nd->nd_curstateid.other[1] && 3359 stateid.other[2] == nd->nd_curstateid.other[2]) 3360 nd->nd_flag &= ~ND_CURSTATEID; 3361 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3362 *tl++ = txdr_unsigned(stateid.seqid); 3363 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3364 } 3365 NFSEXITCODE2(0, nd); 3366 return (0); 3367 nfsmout: 3368 vput(vp); 3369 NFSEXITCODE2(error, nd); 3370 return (error); 3371 } 3372 3373 /* 3374 * nfsv4 delegpurge service 3375 */ 3376 int 3377 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3378 __unused vnode_t vp, __unused struct nfsexstuff *exp) 3379 { 3380 u_int32_t *tl; 3381 int error = 0; 3382 nfsquad_t clientid; 3383 struct thread *p = curthread; 3384 3385 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 3386 goto nfsmout; 3387 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3388 clientid.lval[0] = *tl++; 3389 clientid.lval[1] = *tl; 3390 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3391 if ((nd->nd_flag & ND_NFSV41) != 0) 3392 clientid.qval = nd->nd_clientid.qval; 3393 else if (nd->nd_clientid.qval != clientid.qval) 3394 printf("EEK9 multiple clids\n"); 3395 } else { 3396 if ((nd->nd_flag & ND_NFSV41) != 0) 3397 printf("EEK! no clientid from session\n"); 3398 nd->nd_flag |= ND_IMPLIEDCLID; 3399 nd->nd_clientid.qval = clientid.qval; 3400 } 3401 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 3402 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL); 3403 nfsmout: 3404 NFSEXITCODE2(error, nd); 3405 return (error); 3406 } 3407 3408 /* 3409 * nfsv4 delegreturn service 3410 */ 3411 int 3412 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3413 vnode_t vp, __unused struct nfsexstuff *exp) 3414 { 3415 u_int32_t *tl; 3416 int error = 0, writeacc; 3417 nfsv4stateid_t stateid; 3418 nfsquad_t clientid; 3419 struct nfsvattr na; 3420 struct thread *p = curthread; 3421 3422 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3423 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3424 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 3425 clientid.lval[0] = stateid.other[0]; 3426 clientid.lval[1] = stateid.other[1]; 3427 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3428 if ((nd->nd_flag & ND_NFSV41) != 0) 3429 clientid.qval = nd->nd_clientid.qval; 3430 else if (nd->nd_clientid.qval != clientid.qval) 3431 printf("EEK10 multiple clids\n"); 3432 } else { 3433 if ((nd->nd_flag & ND_NFSV41) != 0) 3434 printf("EEK! no clientid from session\n"); 3435 nd->nd_flag |= ND_IMPLIEDCLID; 3436 nd->nd_clientid.qval = clientid.qval; 3437 } 3438 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 3439 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc); 3440 /* For pNFS, update the attributes. */ 3441 if (writeacc != 0 || nfsrv_pnfsatime != 0) 3442 nfsrv_updatemdsattr(vp, &na, p); 3443 nfsmout: 3444 vput(vp); 3445 NFSEXITCODE2(error, nd); 3446 return (error); 3447 } 3448 3449 /* 3450 * nfsv4 get file handle service 3451 */ 3452 int 3453 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3454 vnode_t vp, __unused struct nfsexstuff *exp) 3455 { 3456 fhandle_t fh; 3457 struct thread *p = curthread; 3458 3459 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3460 vput(vp); 3461 if (!nd->nd_repstat) 3462 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3463 NFSEXITCODE2(0, nd); 3464 return (0); 3465 } 3466 3467 /* 3468 * nfsv4 open confirm service 3469 */ 3470 int 3471 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3472 vnode_t vp, __unused struct nfsexstuff *exp) 3473 { 3474 u_int32_t *tl; 3475 struct nfsstate st, *stp = &st; 3476 int error = 0; 3477 nfsv4stateid_t stateid; 3478 nfsquad_t clientid; 3479 struct thread *p = curthread; 3480 3481 if ((nd->nd_flag & ND_NFSV41) != 0) { 3482 nd->nd_repstat = NFSERR_NOTSUPP; 3483 goto nfsmout; 3484 } 3485 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3486 stp->ls_ownerlen = 0; 3487 stp->ls_op = nd->nd_rp; 3488 stp->ls_uid = nd->nd_cred->cr_uid; 3489 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3490 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3491 NFSX_STATEIDOTHER); 3492 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3493 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 3494 stp->ls_flags = NFSLCK_CONFIRM; 3495 clientid.lval[0] = stp->ls_stateid.other[0]; 3496 clientid.lval[1] = stp->ls_stateid.other[1]; 3497 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3498 if ((nd->nd_flag & ND_NFSV41) != 0) 3499 clientid.qval = nd->nd_clientid.qval; 3500 else if (nd->nd_clientid.qval != clientid.qval) 3501 printf("EEK11 multiple clids\n"); 3502 } else { 3503 if ((nd->nd_flag & ND_NFSV41) != 0) 3504 printf("EEK! no clientid from session\n"); 3505 nd->nd_flag |= ND_IMPLIEDCLID; 3506 nd->nd_clientid.qval = clientid.qval; 3507 } 3508 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 3509 NULL); 3510 if (!nd->nd_repstat) { 3511 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3512 *tl++ = txdr_unsigned(stateid.seqid); 3513 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3514 } 3515 nfsmout: 3516 vput(vp); 3517 NFSEXITCODE2(error, nd); 3518 return (error); 3519 } 3520 3521 /* 3522 * nfsv4 open downgrade service 3523 */ 3524 int 3525 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3526 vnode_t vp, __unused struct nfsexstuff *exp) 3527 { 3528 u_int32_t *tl; 3529 int i; 3530 struct nfsstate st, *stp = &st; 3531 int error = 0; 3532 nfsv4stateid_t stateid; 3533 nfsquad_t clientid; 3534 struct thread *p = curthread; 3535 3536 /* opendowngrade can only work on a file object.*/ 3537 if (vp->v_type != VREG) { 3538 error = NFSERR_INVAL; 3539 goto nfsmout; 3540 } 3541 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 3542 stp->ls_ownerlen = 0; 3543 stp->ls_op = nd->nd_rp; 3544 stp->ls_uid = nd->nd_cred->cr_uid; 3545 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3546 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3547 NFSX_STATEIDOTHER); 3548 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3549 3550 /* 3551 * For the special stateid of other all 0s and seqid == 1, set the 3552 * stateid to the current stateid, if it is set. 3553 */ 3554 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 3555 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 3556 stp->ls_stateid.other[2] == 0) { 3557 if ((nd->nd_flag & ND_CURSTATEID) != 0) 3558 stp->ls_stateid = nd->nd_curstateid; 3559 else { 3560 nd->nd_repstat = NFSERR_BADSTATEID; 3561 goto nfsmout; 3562 } 3563 } 3564 3565 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3566 i = fxdr_unsigned(int, *tl++); 3567 if ((nd->nd_flag & ND_NFSV41) != 0) 3568 i &= ~NFSV4OPEN_WANTDELEGMASK; 3569 switch (i) { 3570 case NFSV4OPEN_ACCESSREAD: 3571 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3572 break; 3573 case NFSV4OPEN_ACCESSWRITE: 3574 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3575 break; 3576 case NFSV4OPEN_ACCESSBOTH: 3577 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3578 NFSLCK_DOWNGRADE); 3579 break; 3580 default: 3581 nd->nd_repstat = NFSERR_INVAL; 3582 } 3583 i = fxdr_unsigned(int, *tl); 3584 switch (i) { 3585 case NFSV4OPEN_DENYNONE: 3586 break; 3587 case NFSV4OPEN_DENYREAD: 3588 stp->ls_flags |= NFSLCK_READDENY; 3589 break; 3590 case NFSV4OPEN_DENYWRITE: 3591 stp->ls_flags |= NFSLCK_WRITEDENY; 3592 break; 3593 case NFSV4OPEN_DENYBOTH: 3594 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3595 break; 3596 default: 3597 nd->nd_repstat = NFSERR_INVAL; 3598 } 3599 3600 clientid.lval[0] = stp->ls_stateid.other[0]; 3601 clientid.lval[1] = stp->ls_stateid.other[1]; 3602 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3603 if ((nd->nd_flag & ND_NFSV41) != 0) 3604 clientid.qval = nd->nd_clientid.qval; 3605 else if (nd->nd_clientid.qval != clientid.qval) 3606 printf("EEK12 multiple clids\n"); 3607 } else { 3608 if ((nd->nd_flag & ND_NFSV41) != 0) 3609 printf("EEK! no clientid from session\n"); 3610 nd->nd_flag |= ND_IMPLIEDCLID; 3611 nd->nd_clientid.qval = clientid.qval; 3612 } 3613 if (!nd->nd_repstat) 3614 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3615 nd, p, NULL); 3616 if (!nd->nd_repstat) { 3617 /* For NFSv4.1, set the Current StateID. */ 3618 if ((nd->nd_flag & ND_NFSV41) != 0) { 3619 nd->nd_curstateid = stateid; 3620 nd->nd_flag |= ND_CURSTATEID; 3621 } 3622 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3623 *tl++ = txdr_unsigned(stateid.seqid); 3624 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3625 } 3626 nfsmout: 3627 vput(vp); 3628 NFSEXITCODE2(error, nd); 3629 return (error); 3630 } 3631 3632 /* 3633 * nfsv4 renew lease service 3634 */ 3635 int 3636 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3637 __unused vnode_t vp, __unused struct nfsexstuff *exp) 3638 { 3639 u_int32_t *tl; 3640 int error = 0; 3641 nfsquad_t clientid; 3642 struct thread *p = curthread; 3643 3644 if ((nd->nd_flag & ND_NFSV41) != 0) { 3645 nd->nd_repstat = NFSERR_NOTSUPP; 3646 goto nfsmout; 3647 } 3648 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 3649 goto nfsmout; 3650 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3651 clientid.lval[0] = *tl++; 3652 clientid.lval[1] = *tl; 3653 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3654 if ((nd->nd_flag & ND_NFSV41) != 0) 3655 clientid.qval = nd->nd_clientid.qval; 3656 else if (nd->nd_clientid.qval != clientid.qval) 3657 printf("EEK13 multiple clids\n"); 3658 } else { 3659 if ((nd->nd_flag & ND_NFSV41) != 0) 3660 printf("EEK! no clientid from session\n"); 3661 nd->nd_flag |= ND_IMPLIEDCLID; 3662 nd->nd_clientid.qval = clientid.qval; 3663 } 3664 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3665 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 3666 nfsmout: 3667 NFSEXITCODE2(error, nd); 3668 return (error); 3669 } 3670 3671 /* 3672 * nfsv4 security info service 3673 */ 3674 int 3675 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3676 vnode_t dp, struct nfsexstuff *exp) 3677 { 3678 u_int32_t *tl; 3679 int len; 3680 struct nameidata named; 3681 vnode_t dirp = NULL, vp; 3682 struct nfsrvfh fh; 3683 struct nfsexstuff retnes; 3684 u_int32_t *sizp; 3685 int error = 0, i; 3686 uint64_t savflag; 3687 char *bufp; 3688 u_long *hashp; 3689 struct thread *p = curthread; 3690 3691 /* 3692 * All this just to get the export flags for the name. 3693 */ 3694 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3695 LOCKLEAF); 3696 nfsvno_setpathbuf(&named, &bufp, &hashp); 3697 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3698 if (error) { 3699 vput(dp); 3700 nfsvno_relpathbuf(&named); 3701 goto out; 3702 } 3703 if (!nd->nd_repstat) { 3704 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); 3705 } else { 3706 vput(dp); 3707 nfsvno_relpathbuf(&named); 3708 } 3709 if (dirp) 3710 vrele(dirp); 3711 if (nd->nd_repstat) 3712 goto out; 3713 nfsvno_relpathbuf(&named); 3714 fh.nfsrvfh_len = NFSX_MYFH; 3715 vp = named.ni_vp; 3716 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3717 vput(vp); 3718 savflag = nd->nd_flag; 3719 if (!nd->nd_repstat) { 3720 /* 3721 * Pretend the next op is Secinfo, so that no wrongsec 3722 * test will be done. 3723 */ 3724 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, 3725 NFSV4OP_SECINFO); 3726 if (vp) 3727 vput(vp); 3728 } 3729 nd->nd_flag = savflag; 3730 if (nd->nd_repstat) 3731 goto out; 3732 3733 /* 3734 * Finally have the export flags for name, so we can create 3735 * the security info. 3736 */ 3737 len = 0; 3738 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3739 3740 /* If nes_numsecflavor == 0, all are allowed. */ 3741 if (retnes.nes_numsecflavor == 0) { 3742 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3743 *tl++ = txdr_unsigned(RPCAUTH_UNIX); 3744 *tl = txdr_unsigned(RPCAUTH_GSS); 3745 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3746 nfsgss_mechlist[KERBV_MECH].len); 3747 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3748 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3749 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3750 *tl = txdr_unsigned(RPCAUTH_GSS); 3751 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3752 nfsgss_mechlist[KERBV_MECH].len); 3753 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3754 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3755 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3756 *tl = txdr_unsigned(RPCAUTH_GSS); 3757 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3758 nfsgss_mechlist[KERBV_MECH].len); 3759 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3760 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3761 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3762 len = 4; 3763 } 3764 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3765 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3766 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3767 *tl = txdr_unsigned(RPCAUTH_UNIX); 3768 len++; 3769 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3770 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3771 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3772 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3773 nfsgss_mechlist[KERBV_MECH].len); 3774 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3775 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3776 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3777 len++; 3778 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3779 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3780 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3781 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3782 nfsgss_mechlist[KERBV_MECH].len); 3783 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3784 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3785 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3786 len++; 3787 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3788 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3789 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3790 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3791 nfsgss_mechlist[KERBV_MECH].len); 3792 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3793 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3794 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3795 len++; 3796 } 3797 } 3798 *sizp = txdr_unsigned(len); 3799 3800 out: 3801 NFSEXITCODE2(error, nd); 3802 return (error); 3803 } 3804 3805 /* 3806 * nfsv4 security info no name service 3807 */ 3808 int 3809 nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram, 3810 vnode_t dp, struct nfsexstuff *exp) 3811 { 3812 uint32_t *tl, *sizp; 3813 struct nameidata named; 3814 vnode_t dirp = NULL, vp; 3815 struct nfsrvfh fh; 3816 struct nfsexstuff retnes; 3817 int error = 0, fhstyle, i, len; 3818 uint64_t savflag; 3819 char *bufp; 3820 u_long *hashp; 3821 struct thread *p = curthread; 3822 3823 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3824 fhstyle = fxdr_unsigned(int, *tl); 3825 switch (fhstyle) { 3826 case NFSSECINFONONAME_PARENT: 3827 if (dp->v_type != VDIR) { 3828 vput(dp); 3829 nd->nd_repstat = NFSERR_NOTDIR; 3830 goto nfsmout; 3831 } 3832 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3833 LOCKLEAF); 3834 nfsvno_setpathbuf(&named, &bufp, &hashp); 3835 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3836 if (error != 0) { 3837 vput(dp); 3838 nfsvno_relpathbuf(&named); 3839 goto nfsmout; 3840 } 3841 if (nd->nd_repstat == 0) 3842 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, &dirp); 3843 else 3844 vput(dp); 3845 if (dirp != NULL) 3846 vrele(dirp); 3847 nfsvno_relpathbuf(&named); 3848 vp = named.ni_vp; 3849 break; 3850 case NFSSECINFONONAME_CURFH: 3851 vp = dp; 3852 break; 3853 default: 3854 nd->nd_repstat = NFSERR_INVAL; 3855 vput(dp); 3856 } 3857 if (nd->nd_repstat != 0) 3858 goto nfsmout; 3859 fh.nfsrvfh_len = NFSX_MYFH; 3860 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3861 vput(vp); 3862 savflag = nd->nd_flag; 3863 if (nd->nd_repstat == 0) { 3864 /* 3865 * Pretend the next op is Secinfo, so that no wrongsec 3866 * test will be done. 3867 */ 3868 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, 3869 NFSV4OP_SECINFO); 3870 if (vp != NULL) 3871 vput(vp); 3872 } 3873 nd->nd_flag = savflag; 3874 if (nd->nd_repstat != 0) 3875 goto nfsmout; 3876 3877 /* 3878 * Finally have the export flags for fh/parent, so we can create 3879 * the security info. 3880 */ 3881 len = 0; 3882 NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED); 3883 3884 /* If nes_numsecflavor == 0, all are allowed. */ 3885 if (retnes.nes_numsecflavor == 0) { 3886 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3887 *tl++ = txdr_unsigned(RPCAUTH_UNIX); 3888 *tl = txdr_unsigned(RPCAUTH_GSS); 3889 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3890 nfsgss_mechlist[KERBV_MECH].len); 3891 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3892 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3893 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3894 *tl = txdr_unsigned(RPCAUTH_GSS); 3895 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3896 nfsgss_mechlist[KERBV_MECH].len); 3897 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3898 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3899 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3900 *tl = txdr_unsigned(RPCAUTH_GSS); 3901 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3902 nfsgss_mechlist[KERBV_MECH].len); 3903 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3904 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3905 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3906 len = 4; 3907 } 3908 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3909 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3910 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3911 *tl = txdr_unsigned(RPCAUTH_UNIX); 3912 len++; 3913 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3914 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3915 *tl = txdr_unsigned(RPCAUTH_GSS); 3916 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3917 nfsgss_mechlist[KERBV_MECH].len); 3918 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3919 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3920 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3921 len++; 3922 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3923 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3924 *tl = txdr_unsigned(RPCAUTH_GSS); 3925 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3926 nfsgss_mechlist[KERBV_MECH].len); 3927 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3928 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3929 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3930 len++; 3931 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3932 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3933 *tl = txdr_unsigned(RPCAUTH_GSS); 3934 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3935 nfsgss_mechlist[KERBV_MECH].len); 3936 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3937 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3938 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3939 len++; 3940 } 3941 } 3942 *sizp = txdr_unsigned(len); 3943 3944 nfsmout: 3945 NFSEXITCODE2(error, nd); 3946 return (error); 3947 } 3948 3949 /* 3950 * nfsv4 set client id service 3951 */ 3952 int 3953 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3954 __unused vnode_t vp, __unused struct nfsexstuff *exp) 3955 { 3956 u_int32_t *tl; 3957 int i; 3958 int error = 0, idlen; 3959 struct nfsclient *clp = NULL; 3960 #ifdef INET 3961 struct sockaddr_in *rin; 3962 #endif 3963 #ifdef INET6 3964 struct sockaddr_in6 *rin6; 3965 #endif 3966 #if defined(INET) || defined(INET6) 3967 u_char *ucp, *ucp2; 3968 #endif 3969 u_char *verf, *addrbuf; 3970 nfsquad_t clientid, confirm; 3971 struct thread *p = curthread; 3972 3973 if ((nd->nd_flag & ND_NFSV41) != 0) { 3974 nd->nd_repstat = NFSERR_NOTSUPP; 3975 goto nfsmout; 3976 } 3977 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 3978 goto out; 3979 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3980 verf = (u_char *)tl; 3981 tl += (NFSX_VERF / NFSX_UNSIGNED); 3982 i = fxdr_unsigned(int, *tl); 3983 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3984 nd->nd_repstat = NFSERR_BADXDR; 3985 goto nfsmout; 3986 } 3987 idlen = i; 3988 if (nd->nd_flag & ND_GSS) 3989 i += nd->nd_princlen; 3990 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3991 M_ZERO); 3992 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3993 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3994 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3995 /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 3996 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 3997 M_WAITOK | M_ZERO); 3998 clp->lc_req.nr_cred = NULL; 3999 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 4000 clp->lc_idlen = idlen; 4001 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 4002 if (error) 4003 goto nfsmout; 4004 if (nd->nd_flag & ND_GSS) { 4005 clp->lc_flags = LCL_GSS; 4006 if (nd->nd_flag & ND_GSSINTEGRITY) 4007 clp->lc_flags |= LCL_GSSINTEGRITY; 4008 else if (nd->nd_flag & ND_GSSPRIVACY) 4009 clp->lc_flags |= LCL_GSSPRIVACY; 4010 } else { 4011 clp->lc_flags = 0; 4012 } 4013 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 4014 clp->lc_flags |= LCL_NAME; 4015 clp->lc_namelen = nd->nd_princlen; 4016 clp->lc_name = &clp->lc_id[idlen]; 4017 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 4018 } else { 4019 clp->lc_uid = nd->nd_cred->cr_uid; 4020 clp->lc_gid = nd->nd_cred->cr_gid; 4021 } 4022 4023 /* If the client is using TLS, do so for the callback connection. */ 4024 if (nd->nd_flag & ND_TLS) 4025 clp->lc_flags |= LCL_TLSCB; 4026 4027 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4028 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 4029 error = nfsrv_getclientipaddr(nd, clp); 4030 if (error) 4031 goto nfsmout; 4032 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4033 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 4034 4035 /* 4036 * nfsrv_setclient() does the actual work of adding it to the 4037 * client list. If there is no error, the structure has been 4038 * linked into the client list and clp should no longer be used 4039 * here. When an error is returned, it has not been linked in, 4040 * so it should be free'd. 4041 */ 4042 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 4043 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 4044 /* 4045 * 8 is the maximum length of the port# string. 4046 */ 4047 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK); 4048 switch (clp->lc_req.nr_nam->sa_family) { 4049 #ifdef INET 4050 case AF_INET: 4051 if (clp->lc_flags & LCL_TCPCALLBACK) 4052 (void) nfsm_strtom(nd, "tcp", 3); 4053 else 4054 (void) nfsm_strtom(nd, "udp", 3); 4055 rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4056 ucp = (u_char *)&rin->sin_addr.s_addr; 4057 ucp2 = (u_char *)&rin->sin_port; 4058 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 4059 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 4060 ucp2[0] & 0xff, ucp2[1] & 0xff); 4061 break; 4062 #endif 4063 #ifdef INET6 4064 case AF_INET6: 4065 if (clp->lc_flags & LCL_TCPCALLBACK) 4066 (void) nfsm_strtom(nd, "tcp6", 4); 4067 else 4068 (void) nfsm_strtom(nd, "udp6", 4); 4069 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4070 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf, 4071 INET6_ADDRSTRLEN); 4072 if (ucp != NULL) 4073 i = strlen(ucp); 4074 else 4075 i = 0; 4076 ucp2 = (u_char *)&rin6->sin6_port; 4077 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff, 4078 ucp2[1] & 0xff); 4079 break; 4080 #endif 4081 } 4082 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 4083 free(addrbuf, M_TEMP); 4084 } 4085 if (clp) { 4086 free(clp->lc_req.nr_nam, M_SONAME); 4087 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4088 free(clp->lc_stateid, M_NFSDCLIENT); 4089 free(clp, M_NFSDCLIENT); 4090 } 4091 if (!nd->nd_repstat) { 4092 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 4093 *tl++ = clientid.lval[0]; 4094 *tl++ = clientid.lval[1]; 4095 *tl++ = confirm.lval[0]; 4096 *tl = confirm.lval[1]; 4097 } 4098 4099 out: 4100 NFSEXITCODE2(0, nd); 4101 return (0); 4102 nfsmout: 4103 if (clp) { 4104 free(clp->lc_req.nr_nam, M_SONAME); 4105 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4106 free(clp->lc_stateid, M_NFSDCLIENT); 4107 free(clp, M_NFSDCLIENT); 4108 } 4109 NFSEXITCODE2(error, nd); 4110 return (error); 4111 } 4112 4113 /* 4114 * nfsv4 set client id confirm service 4115 */ 4116 int 4117 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 4118 __unused int isdgram, __unused vnode_t vp, 4119 __unused struct nfsexstuff *exp) 4120 { 4121 u_int32_t *tl; 4122 int error = 0; 4123 nfsquad_t clientid, confirm; 4124 struct thread *p = curthread; 4125 4126 if ((nd->nd_flag & ND_NFSV41) != 0) { 4127 nd->nd_repstat = NFSERR_NOTSUPP; 4128 goto nfsmout; 4129 } 4130 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4131 goto nfsmout; 4132 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 4133 clientid.lval[0] = *tl++; 4134 clientid.lval[1] = *tl++; 4135 confirm.lval[0] = *tl++; 4136 confirm.lval[1] = *tl; 4137 4138 /* 4139 * nfsrv_getclient() searches the client list for a match and 4140 * returns the appropriate NFSERR status. 4141 */ 4142 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 4143 NULL, NULL, confirm, 0, nd, p); 4144 nfsmout: 4145 NFSEXITCODE2(error, nd); 4146 return (error); 4147 } 4148 4149 /* 4150 * nfsv4 verify service 4151 */ 4152 int 4153 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 4154 vnode_t vp, __unused struct nfsexstuff *exp) 4155 { 4156 int error = 0, ret, fhsize = NFSX_MYFH; 4157 struct nfsvattr nva; 4158 struct statfs *sf; 4159 struct nfsfsinfo fs; 4160 fhandle_t fh; 4161 struct thread *p = curthread; 4162 4163 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 4164 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 4165 if (!nd->nd_repstat) 4166 nd->nd_repstat = nfsvno_statfs(vp, sf); 4167 if (!nd->nd_repstat) 4168 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 4169 if (!nd->nd_repstat) { 4170 nfsvno_getfs(&fs, isdgram); 4171 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 4172 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 4173 if (!error) { 4174 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 4175 if (ret == 0) 4176 nd->nd_repstat = NFSERR_SAME; 4177 else if (ret != NFSERR_NOTSAME) 4178 nd->nd_repstat = ret; 4179 } else if (ret) 4180 nd->nd_repstat = ret; 4181 } 4182 } 4183 vput(vp); 4184 free(sf, M_STATFS); 4185 NFSEXITCODE2(error, nd); 4186 return (error); 4187 } 4188 4189 /* 4190 * nfs openattr rpc 4191 */ 4192 int 4193 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 4194 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 4195 __unused struct nfsexstuff *exp) 4196 { 4197 u_int32_t *tl; 4198 int error = 0, createdir __unused; 4199 4200 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4201 createdir = fxdr_unsigned(int, *tl); 4202 nd->nd_repstat = NFSERR_NOTSUPP; 4203 nfsmout: 4204 vrele(dp); 4205 NFSEXITCODE2(error, nd); 4206 return (error); 4207 } 4208 4209 /* 4210 * nfsv4 release lock owner service 4211 */ 4212 int 4213 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 4214 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4215 { 4216 u_int32_t *tl; 4217 struct nfsstate *stp = NULL; 4218 int error = 0, len; 4219 nfsquad_t clientid; 4220 struct thread *p = curthread; 4221 4222 if ((nd->nd_flag & ND_NFSV41) != 0) { 4223 nd->nd_repstat = NFSERR_NOTSUPP; 4224 goto nfsmout; 4225 } 4226 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4227 goto nfsmout; 4228 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 4229 len = fxdr_unsigned(int, *(tl + 2)); 4230 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 4231 nd->nd_repstat = NFSERR_BADXDR; 4232 goto nfsmout; 4233 } 4234 stp = malloc(sizeof (struct nfsstate) + len, 4235 M_NFSDSTATE, M_WAITOK); 4236 stp->ls_ownerlen = len; 4237 stp->ls_op = NULL; 4238 stp->ls_flags = NFSLCK_RELEASE; 4239 stp->ls_uid = nd->nd_cred->cr_uid; 4240 clientid.lval[0] = *tl++; 4241 clientid.lval[1] = *tl; 4242 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 4243 if ((nd->nd_flag & ND_NFSV41) != 0) 4244 clientid.qval = nd->nd_clientid.qval; 4245 else if (nd->nd_clientid.qval != clientid.qval) 4246 printf("EEK14 multiple clids\n"); 4247 } else { 4248 if ((nd->nd_flag & ND_NFSV41) != 0) 4249 printf("EEK! no clientid from session\n"); 4250 nd->nd_flag |= ND_IMPLIEDCLID; 4251 nd->nd_clientid.qval = clientid.qval; 4252 } 4253 error = nfsrv_mtostr(nd, stp->ls_owner, len); 4254 if (error) 4255 goto nfsmout; 4256 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 4257 free(stp, M_NFSDSTATE); 4258 4259 NFSEXITCODE2(0, nd); 4260 return (0); 4261 nfsmout: 4262 if (stp) 4263 free(stp, M_NFSDSTATE); 4264 NFSEXITCODE2(error, nd); 4265 return (error); 4266 } 4267 4268 /* 4269 * nfsv4 exchange_id service 4270 */ 4271 int 4272 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 4273 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4274 { 4275 uint32_t *tl; 4276 int error = 0, i, idlen; 4277 struct nfsclient *clp = NULL; 4278 nfsquad_t clientid, confirm; 4279 uint8_t *verf; 4280 uint32_t sp4type, v41flags; 4281 struct timespec verstime; 4282 #ifdef INET 4283 struct sockaddr_in *sin, *rin; 4284 #endif 4285 #ifdef INET6 4286 struct sockaddr_in6 *sin6, *rin6; 4287 #endif 4288 struct thread *p = curthread; 4289 char *s; 4290 4291 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4292 goto nfsmout; 4293 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 4294 verf = (uint8_t *)tl; 4295 tl += (NFSX_VERF / NFSX_UNSIGNED); 4296 i = fxdr_unsigned(int, *tl); 4297 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 4298 nd->nd_repstat = NFSERR_BADXDR; 4299 goto nfsmout; 4300 } 4301 idlen = i; 4302 if (nd->nd_flag & ND_GSS) 4303 i += nd->nd_princlen; 4304 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 4305 M_ZERO); 4306 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 4307 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 4308 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 4309 /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 4310 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 4311 M_WAITOK | M_ZERO); 4312 switch (nd->nd_nam->sa_family) { 4313 #ifdef INET 4314 case AF_INET: 4315 rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4316 sin = (struct sockaddr_in *)nd->nd_nam; 4317 rin->sin_family = AF_INET; 4318 rin->sin_len = sizeof(struct sockaddr_in); 4319 rin->sin_port = 0; 4320 rin->sin_addr.s_addr = sin->sin_addr.s_addr; 4321 break; 4322 #endif 4323 #ifdef INET6 4324 case AF_INET6: 4325 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4326 sin6 = (struct sockaddr_in6 *)nd->nd_nam; 4327 rin6->sin6_family = AF_INET6; 4328 rin6->sin6_len = sizeof(struct sockaddr_in6); 4329 rin6->sin6_port = 0; 4330 rin6->sin6_addr = sin6->sin6_addr; 4331 break; 4332 #endif 4333 } 4334 clp->lc_req.nr_cred = NULL; 4335 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 4336 clp->lc_idlen = idlen; 4337 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 4338 if (error != 0) 4339 goto nfsmout; 4340 if ((nd->nd_flag & ND_GSS) != 0) { 4341 clp->lc_flags = LCL_GSS | LCL_NFSV41; 4342 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 4343 clp->lc_flags |= LCL_GSSINTEGRITY; 4344 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 4345 clp->lc_flags |= LCL_GSSPRIVACY; 4346 } else 4347 clp->lc_flags = LCL_NFSV41; 4348 if ((nd->nd_flag & ND_NFSV42) != 0) 4349 clp->lc_flags |= LCL_NFSV42; 4350 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 4351 clp->lc_flags |= LCL_NAME; 4352 clp->lc_namelen = nd->nd_princlen; 4353 clp->lc_name = &clp->lc_id[idlen]; 4354 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 4355 } else { 4356 clp->lc_uid = nd->nd_cred->cr_uid; 4357 clp->lc_gid = nd->nd_cred->cr_gid; 4358 } 4359 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4360 v41flags = fxdr_unsigned(uint32_t, *tl++); 4361 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 4362 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 4363 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 4364 nd->nd_repstat = NFSERR_INVAL; 4365 goto nfsmout; 4366 } 4367 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 4368 confirm.lval[1] = 1; 4369 else 4370 confirm.lval[1] = 0; 4371 if (nfsrv_devidcnt == 0) 4372 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS; 4373 else 4374 v41flags = NFSV4EXCH_USEPNFSMDS; 4375 sp4type = fxdr_unsigned(uint32_t, *tl); 4376 if (sp4type != NFSV4EXCH_SP4NONE) { 4377 nd->nd_repstat = NFSERR_NOTSUPP; 4378 goto nfsmout; 4379 } 4380 4381 /* 4382 * nfsrv_setclient() does the actual work of adding it to the 4383 * client list. If there is no error, the structure has been 4384 * linked into the client list and clp should no longer be used 4385 * here. When an error is returned, it has not been linked in, 4386 * so it should be free'd. 4387 */ 4388 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 4389 if (clp != NULL) { 4390 free(clp->lc_req.nr_nam, M_SONAME); 4391 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4392 free(clp->lc_stateid, M_NFSDCLIENT); 4393 free(clp, M_NFSDCLIENT); 4394 } 4395 if (nd->nd_repstat == 0) { 4396 if (confirm.lval[1] != 0) 4397 v41flags |= NFSV4EXCH_CONFIRMEDR; 4398 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 4399 *tl++ = clientid.lval[0]; /* ClientID */ 4400 *tl++ = clientid.lval[1]; 4401 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 4402 *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 4403 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 4404 txdr_hyper(nfsrv_owner_minor, tl); /* Owner Minor */ 4405 if (nfsrv_owner_major[0] != 0) 4406 s = nfsrv_owner_major; 4407 else 4408 s = nd->nd_cred->cr_prison->pr_hostuuid; 4409 nfsm_strtom(nd, s, strlen(s)); /* Owner Major */ 4410 if (nfsrv_scope[0] != 0) 4411 s = nfsrv_scope; 4412 else 4413 s = nd->nd_cred->cr_prison->pr_hostuuid; 4414 nfsm_strtom(nd, s, strlen(s) ); /* Scope */ 4415 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4416 *tl = txdr_unsigned(1); 4417 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4418 (void)nfsm_strtom(nd, version, strlen(version)); 4419 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4420 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4421 verstime.tv_nsec = 0; 4422 txdr_nfsv4time(&verstime, tl); 4423 } 4424 NFSEXITCODE2(0, nd); 4425 return (0); 4426 nfsmout: 4427 if (clp != NULL) { 4428 free(clp->lc_req.nr_nam, M_SONAME); 4429 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4430 free(clp->lc_stateid, M_NFSDCLIENT); 4431 free(clp, M_NFSDCLIENT); 4432 } 4433 NFSEXITCODE2(error, nd); 4434 return (error); 4435 } 4436 4437 /* 4438 * nfsv4 create session service 4439 */ 4440 int 4441 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 4442 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4443 { 4444 uint32_t *tl; 4445 int error = 0; 4446 nfsquad_t clientid, confirm; 4447 struct nfsdsession *sep = NULL; 4448 uint32_t rdmacnt; 4449 struct thread *p = curthread; 4450 static bool do_printf = true; 4451 4452 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4453 goto nfsmout; 4454 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 4455 M_NFSDSESSION, M_WAITOK | M_ZERO); 4456 sep->sess_refcnt = 1; 4457 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 4458 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 4459 clientid.lval[0] = *tl++; 4460 clientid.lval[1] = *tl++; 4461 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 4462 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 4463 /* Persistent sessions and RDMA are not supported. */ 4464 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 4465 4466 /* Fore channel attributes. */ 4467 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4468 tl++; /* Header pad always 0. */ 4469 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 4470 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) { 4471 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR; 4472 if (do_printf) 4473 printf("Consider increasing kern.ipc.maxsockbuf\n"); 4474 do_printf = false; 4475 } 4476 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 4477 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) { 4478 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR; 4479 if (do_printf) 4480 printf("Consider increasing kern.ipc.maxsockbuf\n"); 4481 do_printf = false; 4482 } 4483 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 4484 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 4485 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 4486 if (sep->sess_maxslots > NFSV4_SLOTS) 4487 sep->sess_maxslots = NFSV4_SLOTS; 4488 rdmacnt = fxdr_unsigned(uint32_t, *tl); 4489 if (rdmacnt > 1) { 4490 nd->nd_repstat = NFSERR_BADXDR; 4491 goto nfsmout; 4492 } else if (rdmacnt == 1) 4493 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4494 4495 /* Back channel attributes. */ 4496 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4497 tl++; /* Header pad always 0. */ 4498 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 4499 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 4500 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 4501 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 4502 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 4503 rdmacnt = fxdr_unsigned(uint32_t, *tl); 4504 if (rdmacnt > 1) { 4505 nd->nd_repstat = NFSERR_BADXDR; 4506 goto nfsmout; 4507 } else if (rdmacnt == 1) 4508 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4509 4510 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4511 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 4512 4513 /* 4514 * nfsrv_getclient() searches the client list for a match and 4515 * returns the appropriate NFSERR status. 4516 */ 4517 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 4518 NULL, sep, confirm, sep->sess_cbprogram, nd, p); 4519 if (nd->nd_repstat == 0) { 4520 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4521 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 4522 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 4523 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 4524 *tl++ = txdr_unsigned(sep->sess_crflags); 4525 4526 /* Fore channel attributes. */ 4527 *tl++ = 0; 4528 *tl++ = txdr_unsigned(sep->sess_maxreq); 4529 *tl++ = txdr_unsigned(sep->sess_maxresp); 4530 *tl++ = txdr_unsigned(sep->sess_maxrespcached); 4531 *tl++ = txdr_unsigned(sep->sess_maxops); 4532 *tl++ = txdr_unsigned(sep->sess_maxslots); 4533 *tl++ = txdr_unsigned(1); 4534 *tl++ = txdr_unsigned(0); /* No RDMA. */ 4535 4536 /* Back channel attributes. */ 4537 *tl++ = 0; 4538 *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 4539 *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 4540 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 4541 *tl++ = txdr_unsigned(sep->sess_cbmaxops); 4542 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 4543 *tl++ = txdr_unsigned(1); 4544 *tl = txdr_unsigned(0); /* No RDMA. */ 4545 } 4546 nfsmout: 4547 if (nd->nd_repstat != 0 && sep != NULL) 4548 free(sep, M_NFSDSESSION); 4549 NFSEXITCODE2(error, nd); 4550 return (error); 4551 } 4552 4553 /* 4554 * nfsv4 sequence service 4555 */ 4556 int 4557 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 4558 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4559 { 4560 uint32_t *tl; 4561 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 4562 int cache_this, error = 0; 4563 struct thread *p = curthread; 4564 4565 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4566 goto nfsmout; 4567 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 4568 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 4569 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4570 sequenceid = fxdr_unsigned(uint32_t, *tl++); 4571 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 4572 highest_slotid = fxdr_unsigned(uint32_t, *tl++); 4573 if (*tl == newnfs_true) 4574 cache_this = 1; 4575 else 4576 cache_this = 0; 4577 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 4578 &target_highest_slotid, cache_this, &sflags, p); 4579 if (nd->nd_repstat != NFSERR_BADSLOT) 4580 nd->nd_flag |= ND_HASSEQUENCE; 4581 if (nd->nd_repstat == 0) { 4582 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4583 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 4584 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 4585 *tl++ = txdr_unsigned(sequenceid); 4586 *tl++ = txdr_unsigned(nd->nd_slotid); 4587 *tl++ = txdr_unsigned(highest_slotid); 4588 *tl++ = txdr_unsigned(target_highest_slotid); 4589 *tl = txdr_unsigned(sflags); 4590 } 4591 nfsmout: 4592 NFSEXITCODE2(error, nd); 4593 return (error); 4594 } 4595 4596 /* 4597 * nfsv4 reclaim complete service 4598 */ 4599 int 4600 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 4601 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4602 { 4603 uint32_t *tl; 4604 int error = 0, onefs; 4605 4606 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4607 /* 4608 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only 4609 * to be used after a file system has been transferred to a different 4610 * file server. However, RFC5661 is somewhat vague w.r.t. this and 4611 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs 4612 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE. 4613 * Therefore, just ignore the rca_one_fs == TRUE operation and return 4614 * NFS_OK without doing anything. 4615 */ 4616 onefs = 0; 4617 if (*tl == newnfs_true) 4618 onefs = 1; 4619 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs); 4620 nfsmout: 4621 NFSEXITCODE2(error, nd); 4622 return (error); 4623 } 4624 4625 /* 4626 * nfsv4 destroy clientid service 4627 */ 4628 int 4629 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4630 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4631 { 4632 uint32_t *tl; 4633 nfsquad_t clientid; 4634 int error = 0; 4635 struct thread *p = curthread; 4636 4637 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4638 goto nfsmout; 4639 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4640 clientid.lval[0] = *tl++; 4641 clientid.lval[1] = *tl; 4642 nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4643 nfsmout: 4644 NFSEXITCODE2(error, nd); 4645 return (error); 4646 } 4647 4648 /* 4649 * nfsv4 bind connection to session service 4650 */ 4651 int 4652 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram, 4653 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4654 { 4655 uint32_t *tl; 4656 uint8_t sessid[NFSX_V4SESSIONID]; 4657 int error = 0, foreaft; 4658 4659 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4660 goto nfsmout; 4661 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 4662 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID); 4663 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4664 foreaft = fxdr_unsigned(int, *tl++); 4665 if (*tl == newnfs_true) { 4666 /* RDMA is not supported. */ 4667 nd->nd_repstat = NFSERR_NOTSUPP; 4668 goto nfsmout; 4669 } 4670 4671 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft); 4672 if (nd->nd_repstat == 0) { 4673 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * 4674 NFSX_UNSIGNED); 4675 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID); 4676 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4677 *tl++ = txdr_unsigned(foreaft); 4678 *tl = newnfs_false; 4679 } 4680 nfsmout: 4681 NFSEXITCODE2(error, nd); 4682 return (error); 4683 } 4684 4685 /* 4686 * nfsv4 destroy session service 4687 */ 4688 int 4689 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4690 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4691 { 4692 uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4693 int error = 0; 4694 4695 if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0) 4696 goto nfsmout; 4697 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4698 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4699 nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4700 nfsmout: 4701 NFSEXITCODE2(error, nd); 4702 return (error); 4703 } 4704 4705 /* 4706 * nfsv4 free stateid service 4707 */ 4708 int 4709 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4710 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4711 { 4712 uint32_t *tl; 4713 nfsv4stateid_t stateid; 4714 int error = 0; 4715 struct thread *p = curthread; 4716 4717 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4718 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4719 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4720 4721 /* 4722 * For the special stateid of other all 0s and seqid == 1, set the 4723 * stateid to the current stateid, if it is set. 4724 */ 4725 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4726 stateid.other[1] == 0 && stateid.other[2] == 0) { 4727 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4728 stateid = nd->nd_curstateid; 4729 stateid.seqid = 0; 4730 } else { 4731 nd->nd_repstat = NFSERR_BADSTATEID; 4732 goto nfsmout; 4733 } 4734 } 4735 4736 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 4737 4738 /* If the current stateid has been free'd, unset it. */ 4739 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 && 4740 stateid.other[0] == nd->nd_curstateid.other[0] && 4741 stateid.other[1] == nd->nd_curstateid.other[1] && 4742 stateid.other[2] == nd->nd_curstateid.other[2]) 4743 nd->nd_flag &= ~ND_CURSTATEID; 4744 nfsmout: 4745 NFSEXITCODE2(error, nd); 4746 return (error); 4747 } 4748 4749 /* 4750 * nfsv4 layoutget service 4751 */ 4752 int 4753 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram, 4754 vnode_t vp, struct nfsexstuff *exp) 4755 { 4756 uint32_t *tl; 4757 nfsv4stateid_t stateid; 4758 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose; 4759 uint64_t offset, len, minlen; 4760 char *layp; 4761 struct thread *p = curthread; 4762 4763 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 4764 NFSX_STATEID); 4765 tl++; /* Signal layout available. Ignore for now. */ 4766 layouttype = fxdr_unsigned(int, *tl++); 4767 iomode = fxdr_unsigned(int, *tl++); 4768 offset = fxdr_hyper(tl); tl += 2; 4769 len = fxdr_hyper(tl); tl += 2; 4770 minlen = fxdr_hyper(tl); tl += 2; 4771 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4772 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4773 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4774 maxcnt = fxdr_unsigned(int, *tl); 4775 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n", 4776 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len, 4777 (uintmax_t)minlen); 4778 if (len < minlen || 4779 (minlen != UINT64_MAX && offset + minlen < offset) || 4780 (len != UINT64_MAX && offset + len < offset)) { 4781 nd->nd_repstat = NFSERR_INVAL; 4782 goto nfsmout; 4783 } 4784 4785 /* 4786 * For the special stateid of other all 0s and seqid == 1, set the 4787 * stateid to the current stateid, if it is set. 4788 */ 4789 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4790 stateid.other[1] == 0 && stateid.other[2] == 0) { 4791 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4792 stateid = nd->nd_curstateid; 4793 stateid.seqid = 0; 4794 } else { 4795 nd->nd_repstat = NFSERR_BADSTATEID; 4796 goto nfsmout; 4797 } 4798 } 4799 4800 layp = NULL; 4801 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1) 4802 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK); 4803 else if (layouttype == NFSLAYOUT_FLEXFILE) 4804 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP, 4805 M_WAITOK); 4806 else 4807 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE; 4808 if (layp != NULL) 4809 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype, 4810 &iomode, &offset, &len, minlen, &stateid, maxcnt, 4811 &retonclose, &layoutlen, layp, nd->nd_cred, p); 4812 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat, 4813 layoutlen); 4814 if (nd->nd_repstat == 0) { 4815 /* For NFSv4.1, set the Current StateID. */ 4816 if ((nd->nd_flag & ND_NFSV41) != 0) { 4817 nd->nd_curstateid = stateid; 4818 nd->nd_flag |= ND_CURSTATEID; 4819 } 4820 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID + 4821 2 * NFSX_HYPER); 4822 *tl++ = txdr_unsigned(retonclose); 4823 *tl++ = txdr_unsigned(stateid.seqid); 4824 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 4825 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4826 *tl++ = txdr_unsigned(1); /* Only returns one layout. */ 4827 txdr_hyper(offset, tl); tl += 2; 4828 txdr_hyper(len, tl); tl += 2; 4829 *tl++ = txdr_unsigned(iomode); 4830 *tl = txdr_unsigned(layouttype); 4831 nfsm_strtom(nd, layp, layoutlen); 4832 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) { 4833 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4834 *tl = newnfs_false; 4835 } 4836 free(layp, M_TEMP); 4837 nfsmout: 4838 vput(vp); 4839 NFSEXITCODE2(error, nd); 4840 return (error); 4841 } 4842 4843 /* 4844 * nfsv4 layoutcommit service 4845 */ 4846 int 4847 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram, 4848 vnode_t vp, struct nfsexstuff *exp) 4849 { 4850 uint32_t *tl; 4851 nfsv4stateid_t stateid; 4852 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim; 4853 int hasnewsize; 4854 uint64_t offset, len, newoff = 0, newsize; 4855 struct timespec newmtime; 4856 char *layp; 4857 struct thread *p = curthread; 4858 4859 layp = NULL; 4860 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER + 4861 NFSX_STATEID); 4862 offset = fxdr_hyper(tl); tl += 2; 4863 len = fxdr_hyper(tl); tl += 2; 4864 reclaim = fxdr_unsigned(int, *tl++); 4865 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4866 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4867 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4868 /* 4869 * For the special stateid of other all 0s and seqid == 1, set the 4870 * stateid to the current stateid, if it is set. 4871 */ 4872 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4873 stateid.other[1] == 0 && stateid.other[2] == 0) { 4874 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4875 stateid = nd->nd_curstateid; 4876 stateid.seqid = 0; 4877 } else { 4878 nd->nd_repstat = NFSERR_BADSTATEID; 4879 goto nfsmout; 4880 } 4881 } 4882 4883 hasnewoff = fxdr_unsigned(int, *tl); 4884 if (hasnewoff != 0) { 4885 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 4886 newoff = fxdr_hyper(tl); tl += 2; 4887 } else 4888 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4889 hasnewmtime = fxdr_unsigned(int, *tl); 4890 if (hasnewmtime != 0) { 4891 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED); 4892 fxdr_nfsv4time(tl, &newmtime); 4893 tl += (NFSX_V4TIME / NFSX_UNSIGNED); 4894 } else 4895 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4896 layouttype = fxdr_unsigned(int, *tl++); 4897 maxcnt = fxdr_unsigned(int, *tl); 4898 if (maxcnt > 0) { 4899 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 4900 error = nfsrv_mtostr(nd, layp, maxcnt); 4901 if (error != 0) 4902 goto nfsmout; 4903 } 4904 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff, 4905 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid, 4906 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p); 4907 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat); 4908 if (nd->nd_repstat == 0) { 4909 if (hasnewsize != 0) { 4910 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 4911 *tl++ = newnfs_true; 4912 txdr_hyper(newsize, tl); 4913 } else { 4914 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4915 *tl = newnfs_false; 4916 } 4917 } 4918 nfsmout: 4919 free(layp, M_TEMP); 4920 vput(vp); 4921 NFSEXITCODE2(error, nd); 4922 return (error); 4923 } 4924 4925 /* 4926 * nfsv4 layoutreturn service 4927 */ 4928 int 4929 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram, 4930 vnode_t vp, struct nfsexstuff *exp) 4931 { 4932 uint32_t *tl, *layp; 4933 nfsv4stateid_t stateid; 4934 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim; 4935 uint64_t offset, len; 4936 struct thread *p = curthread; 4937 4938 layp = NULL; 4939 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4940 reclaim = *tl++; 4941 layouttype = fxdr_unsigned(int, *tl++); 4942 iomode = fxdr_unsigned(int, *tl++); 4943 kind = fxdr_unsigned(int, *tl); 4944 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim, 4945 layouttype, iomode, kind); 4946 if (kind == NFSV4LAYOUTRET_FILE) { 4947 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 4948 NFSX_UNSIGNED); 4949 offset = fxdr_hyper(tl); tl += 2; 4950 len = fxdr_hyper(tl); tl += 2; 4951 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4952 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4953 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4954 4955 /* 4956 * For the special stateid of other all 0s and seqid == 1, set 4957 * the stateid to the current stateid, if it is set. 4958 */ 4959 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4960 stateid.other[1] == 0 && stateid.other[2] == 0) { 4961 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4962 stateid = nd->nd_curstateid; 4963 stateid.seqid = 0; 4964 } else { 4965 nd->nd_repstat = NFSERR_BADSTATEID; 4966 goto nfsmout; 4967 } 4968 } 4969 4970 maxcnt = fxdr_unsigned(int, *tl); 4971 /* 4972 * There is no fixed upper bound defined in the RFCs, 4973 * but 128Kbytes should be more than sufficient. 4974 */ 4975 if (maxcnt < 0 || maxcnt > 131072) 4976 maxcnt = 0; 4977 if (maxcnt > 0) { 4978 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 4979 error = nfsrv_mtostr(nd, (char *)layp, maxcnt); 4980 if (error != 0) 4981 goto nfsmout; 4982 } 4983 } else { 4984 if (reclaim == newnfs_true) { 4985 nd->nd_repstat = NFSERR_INVAL; 4986 goto nfsmout; 4987 } 4988 offset = len = 0; 4989 maxcnt = 0; 4990 } 4991 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode, 4992 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd, 4993 nd->nd_cred, p); 4994 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat, 4995 fnd); 4996 if (nd->nd_repstat == 0) { 4997 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4998 if (fnd != 0) { 4999 *tl = newnfs_true; 5000 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID); 5001 *tl++ = txdr_unsigned(stateid.seqid); 5002 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 5003 } else 5004 *tl = newnfs_false; 5005 } 5006 nfsmout: 5007 free(layp, M_TEMP); 5008 vput(vp); 5009 NFSEXITCODE2(error, nd); 5010 return (error); 5011 } 5012 5013 /* 5014 * nfsv4 layout error service 5015 */ 5016 int 5017 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram, 5018 vnode_t vp, struct nfsexstuff *exp) 5019 { 5020 uint32_t *tl; 5021 nfsv4stateid_t stateid; 5022 int cnt, error = 0, i, stat; 5023 int opnum __unused; 5024 char devid[NFSX_V4DEVICEID]; 5025 uint64_t offset, len; 5026 5027 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5028 NFSX_UNSIGNED); 5029 offset = fxdr_hyper(tl); tl += 2; 5030 len = fxdr_hyper(tl); tl += 2; 5031 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5032 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5033 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5034 cnt = fxdr_unsigned(int, *tl); 5035 NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset, 5036 (uintmax_t)len, cnt); 5037 /* 5038 * For the special stateid of other all 0s and seqid == 1, set 5039 * the stateid to the current stateid, if it is set. 5040 */ 5041 if (stateid.seqid == 1 && stateid.other[0] == 0 && 5042 stateid.other[1] == 0 && stateid.other[2] == 0) { 5043 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5044 stateid = nd->nd_curstateid; 5045 stateid.seqid = 0; 5046 } else { 5047 nd->nd_repstat = NFSERR_BADSTATEID; 5048 goto nfsmout; 5049 } 5050 } 5051 5052 /* 5053 * Ignore offset, len and stateid for now. 5054 */ 5055 for (i = 0; i < cnt; i++) { 5056 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 * 5057 NFSX_UNSIGNED); 5058 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5059 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5060 stat = fxdr_unsigned(int, *tl++); 5061 opnum = fxdr_unsigned(int, *tl); 5062 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat); 5063 /* 5064 * Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC 5065 * errors, disable the mirror. 5066 */ 5067 if (stat != NFSERR_ACCES && stat != NFSERR_STALE && 5068 stat != NFSERR_NOSPC) 5069 nfsrv_delds(devid, curthread); 5070 5071 /* For NFSERR_NOSPC, mark all deviceids and layouts. */ 5072 if (stat == NFSERR_NOSPC) 5073 nfsrv_marknospc(devid, true); 5074 } 5075 nfsmout: 5076 vput(vp); 5077 NFSEXITCODE2(error, nd); 5078 return (error); 5079 } 5080 5081 /* 5082 * nfsv4 layout stats service 5083 */ 5084 int 5085 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram, 5086 vnode_t vp, struct nfsexstuff *exp) 5087 { 5088 uint32_t *tl; 5089 nfsv4stateid_t stateid; 5090 int cnt, error = 0; 5091 int layouttype __unused; 5092 char devid[NFSX_V4DEVICEID] __unused; 5093 uint64_t offset __unused, len __unused, readcount __unused; 5094 uint64_t readbytes __unused, writecount __unused, writebytes __unused; 5095 5096 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID + 5097 NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED); 5098 offset = fxdr_hyper(tl); tl += 2; 5099 len = fxdr_hyper(tl); tl += 2; 5100 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5101 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5102 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5103 readcount = fxdr_hyper(tl); tl += 2; 5104 readbytes = fxdr_hyper(tl); tl += 2; 5105 writecount = fxdr_hyper(tl); tl += 2; 5106 writebytes = fxdr_hyper(tl); tl += 2; 5107 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5108 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5109 layouttype = fxdr_unsigned(int, *tl++); 5110 cnt = fxdr_unsigned(int, *tl); 5111 error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1); 5112 if (error != 0) 5113 goto nfsmout; 5114 NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt); 5115 /* 5116 * For the special stateid of other all 0s and seqid == 1, set 5117 * the stateid to the current stateid, if it is set. 5118 */ 5119 if (stateid.seqid == 1 && stateid.other[0] == 0 && 5120 stateid.other[1] == 0 && stateid.other[2] == 0) { 5121 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5122 stateid = nd->nd_curstateid; 5123 stateid.seqid = 0; 5124 } else { 5125 nd->nd_repstat = NFSERR_BADSTATEID; 5126 goto nfsmout; 5127 } 5128 } 5129 5130 /* 5131 * No use for the stats for now. 5132 */ 5133 nfsmout: 5134 vput(vp); 5135 NFSEXITCODE2(error, nd); 5136 return (error); 5137 } 5138 5139 /* 5140 * nfsv4 io_advise service 5141 */ 5142 int 5143 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram, 5144 vnode_t vp, struct nfsexstuff *exp) 5145 { 5146 uint32_t *tl; 5147 nfsv4stateid_t stateid; 5148 nfsattrbit_t hints; 5149 int error = 0, ret; 5150 off_t offset, len; 5151 5152 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5153 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5154 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5155 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5156 offset = fxdr_hyper(tl); tl += 2; 5157 len = fxdr_hyper(tl); 5158 error = nfsrv_getattrbits(nd, &hints, NULL, NULL); 5159 if (error != 0) 5160 goto nfsmout; 5161 /* 5162 * For the special stateid of other all 0s and seqid == 1, set 5163 * the stateid to the current stateid, if it is set. 5164 */ 5165 if (stateid.seqid == 1 && stateid.other[0] == 0 && 5166 stateid.other[1] == 0 && stateid.other[2] == 0) { 5167 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5168 stateid = nd->nd_curstateid; 5169 stateid.seqid = 0; 5170 } else { 5171 nd->nd_repstat = NFSERR_BADSTATEID; 5172 goto nfsmout; 5173 } 5174 } 5175 5176 if (offset < 0) { 5177 nd->nd_repstat = NFSERR_INVAL; 5178 goto nfsmout; 5179 } 5180 if (len < 0) 5181 len = 0; 5182 if (vp->v_type != VREG) { 5183 if (vp->v_type == VDIR) 5184 nd->nd_repstat = NFSERR_ISDIR; 5185 else 5186 nd->nd_repstat = NFSERR_WRONGTYPE; 5187 goto nfsmout; 5188 } 5189 5190 /* 5191 * For now, we can only handle WILLNEED and DONTNEED and don't use 5192 * the stateid. 5193 */ 5194 if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) && 5195 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) || 5196 (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) && 5197 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) { 5198 NFSVOPUNLOCK(vp); 5199 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) { 5200 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED); 5201 NFSZERO_ATTRBIT(&hints); 5202 if (ret == 0) 5203 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 5204 else 5205 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5206 } else { 5207 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED); 5208 NFSZERO_ATTRBIT(&hints); 5209 if (ret == 0) 5210 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 5211 else 5212 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5213 } 5214 vrele(vp); 5215 } else { 5216 NFSZERO_ATTRBIT(&hints); 5217 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5218 vput(vp); 5219 } 5220 nfsrv_putattrbit(nd, &hints); 5221 NFSEXITCODE2(error, nd); 5222 return (error); 5223 nfsmout: 5224 vput(vp); 5225 NFSEXITCODE2(error, nd); 5226 return (error); 5227 } 5228 5229 /* 5230 * nfsv4 getdeviceinfo service 5231 */ 5232 int 5233 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram, 5234 __unused vnode_t vp, __unused struct nfsexstuff *exp) 5235 { 5236 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP]; 5237 int cnt, devaddrlen, error = 0, i, layouttype; 5238 char devid[NFSX_V4DEVICEID], *devaddr; 5239 time_t dev_time; 5240 5241 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID); 5242 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5243 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5244 layouttype = fxdr_unsigned(int, *tl++); 5245 maxcnt = fxdr_unsigned(uint32_t, *tl++); 5246 cnt = fxdr_unsigned(int, *tl); 5247 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype, 5248 maxcnt, cnt); 5249 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) { 5250 nd->nd_repstat = NFSERR_INVAL; 5251 goto nfsmout; 5252 } 5253 if (cnt > 0) { 5254 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED); 5255 for (i = 0; i < cnt; i++) 5256 notify[i] = fxdr_unsigned(uint32_t, *tl++); 5257 } 5258 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++) 5259 notify[i] = 0; 5260 5261 /* 5262 * Check that the device id is not stale. Device ids are recreated 5263 * each time the nfsd threads are restarted. 5264 */ 5265 NFSBCOPY(devid, &dev_time, sizeof(dev_time)); 5266 if (dev_time != nfsdev_time) { 5267 nd->nd_repstat = NFSERR_NOENT; 5268 goto nfsmout; 5269 } 5270 5271 /* Look for the device id. */ 5272 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt, 5273 notify, &devaddrlen, &devaddr); 5274 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat); 5275 if (nd->nd_repstat == 0) { 5276 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5277 *tl = txdr_unsigned(layouttype); 5278 nfsm_strtom(nd, devaddr, devaddrlen); 5279 cnt = 0; 5280 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) { 5281 if (notify[i] != 0) 5282 cnt = i + 1; 5283 } 5284 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED); 5285 *tl++ = txdr_unsigned(cnt); 5286 for (i = 0; i < cnt; i++) 5287 *tl++ = txdr_unsigned(notify[i]); 5288 } else if (nd->nd_repstat == NFSERR_TOOSMALL) { 5289 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5290 *tl = txdr_unsigned(maxcnt); 5291 } 5292 nfsmout: 5293 NFSEXITCODE2(error, nd); 5294 return (error); 5295 } 5296 5297 /* 5298 * nfsv4 test stateid service 5299 */ 5300 int 5301 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, 5302 __unused vnode_t vp, __unused struct nfsexstuff *exp) 5303 { 5304 uint32_t *tl; 5305 nfsv4stateid_t *stateidp = NULL, *tstateidp; 5306 int cnt, error = 0, i, ret; 5307 struct thread *p = curthread; 5308 5309 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5310 cnt = fxdr_unsigned(int, *tl); 5311 if (cnt <= 0 || cnt > 1024) { 5312 nd->nd_repstat = NFSERR_BADXDR; 5313 goto nfsmout; 5314 } 5315 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); 5316 tstateidp = stateidp; 5317 for (i = 0; i < cnt; i++) { 5318 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5319 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5320 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); 5321 tstateidp++; 5322 } 5323 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5324 *tl = txdr_unsigned(cnt); 5325 tstateidp = stateidp; 5326 for (i = 0; i < cnt; i++) { 5327 ret = nfsrv_teststateid(nd, tstateidp, p); 5328 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5329 *tl = txdr_unsigned(ret); 5330 tstateidp++; 5331 } 5332 nfsmout: 5333 free(stateidp, M_TEMP); 5334 NFSEXITCODE2(error, nd); 5335 return (error); 5336 } 5337 5338 /* 5339 * nfs allocate service 5340 */ 5341 int 5342 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram, 5343 vnode_t vp, struct nfsexstuff *exp) 5344 { 5345 uint32_t *tl; 5346 struct nfsvattr forat; 5347 int error = 0, forat_ret = 1, gotproxystateid; 5348 off_t off, len; 5349 struct nfsstate st, *stp = &st; 5350 struct nfslock lo, *lop = &lo; 5351 nfsv4stateid_t stateid; 5352 nfsquad_t clientid; 5353 nfsattrbit_t attrbits; 5354 5355 if (!nfsrv_doallocate) { 5356 /* 5357 * If any exported file system, such as a ZFS one, cannot 5358 * do VOP_ALLOCATE(), this operation cannot be supported 5359 * for NFSv4.2. This cannot be done 'per filesystem', but 5360 * must be for the entire nfsd NFSv4.2 service. 5361 */ 5362 nd->nd_repstat = NFSERR_NOTSUPP; 5363 goto nfsmout; 5364 } 5365 gotproxystateid = 0; 5366 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5367 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5368 lop->lo_flags = NFSLCK_WRITE; 5369 stp->ls_ownerlen = 0; 5370 stp->ls_op = NULL; 5371 stp->ls_uid = nd->nd_cred->cr_uid; 5372 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 5373 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 5374 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 5375 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 5376 if ((nd->nd_flag & ND_NFSV41) != 0) 5377 clientid.qval = nd->nd_clientid.qval; 5378 else if (nd->nd_clientid.qval != clientid.qval) 5379 printf("EEK2 multiple clids\n"); 5380 } else { 5381 if ((nd->nd_flag & ND_NFSV41) != 0) 5382 printf("EEK! no clientid from session\n"); 5383 nd->nd_flag |= ND_IMPLIEDCLID; 5384 nd->nd_clientid.qval = clientid.qval; 5385 } 5386 stp->ls_stateid.other[2] = *tl++; 5387 /* 5388 * Don't allow this to be done for a DS. 5389 */ 5390 if ((nd->nd_flag & ND_DSSERVER) != 0) 5391 nd->nd_repstat = NFSERR_NOTSUPP; 5392 /* However, allow the proxy stateid. */ 5393 if (stp->ls_stateid.seqid == 0xffffffff && 5394 stp->ls_stateid.other[0] == 0x55555555 && 5395 stp->ls_stateid.other[1] == 0x55555555 && 5396 stp->ls_stateid.other[2] == 0x55555555) 5397 gotproxystateid = 1; 5398 off = fxdr_hyper(tl); tl += 2; 5399 lop->lo_first = off; 5400 len = fxdr_hyper(tl); 5401 lop->lo_end = lop->lo_first + len; 5402 /* 5403 * Sanity check the offset and length. 5404 * off and len are off_t (signed int64_t) whereas 5405 * lo_first and lo_end are uint64_t and, as such, 5406 * if off >= 0 && len > 0, lo_end cannot overflow 5407 * unless off_t is changed to something other than 5408 * int64_t. Check lo_end < lo_first in case that 5409 * is someday the case. 5410 */ 5411 if (nd->nd_repstat == 0 && (len <= 0 || off < 0 || lop->lo_end > 5412 OFF_MAX || lop->lo_end < lop->lo_first)) 5413 nd->nd_repstat = NFSERR_INVAL; 5414 5415 if (nd->nd_repstat == 0 && vp->v_type != VREG) 5416 nd->nd_repstat = NFSERR_WRONGTYPE; 5417 NFSZERO_ATTRBIT(&attrbits); 5418 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5419 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); 5420 if (nd->nd_repstat == 0) 5421 nd->nd_repstat = forat_ret; 5422 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || 5423 NFSVNO_EXSTRICTACCESS(exp))) 5424 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, 5425 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5426 NULL); 5427 if (nd->nd_repstat == 0 && gotproxystateid == 0) 5428 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 5429 &stateid, exp, nd, curthread); 5430 5431 NFSD_DEBUG(4, "nfsrvd_allocate: off=%jd len=%jd stat=%d\n", 5432 (intmax_t)off, (intmax_t)len, nd->nd_repstat); 5433 if (nd->nd_repstat == 0) 5434 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred, 5435 curthread); 5436 NFSD_DEBUG(4, "nfsrvd_allocate: aft nfsvno_allocate=%d\n", 5437 nd->nd_repstat); 5438 vput(vp); 5439 NFSEXITCODE2(0, nd); 5440 return (0); 5441 nfsmout: 5442 vput(vp); 5443 NFSEXITCODE2(error, nd); 5444 return (error); 5445 } 5446 5447 /* 5448 * nfs deallocate service 5449 */ 5450 int 5451 nfsrvd_deallocate(struct nfsrv_descript *nd, __unused int isdgram, 5452 vnode_t vp, struct nfsexstuff *exp) 5453 { 5454 uint32_t *tl; 5455 struct nfsvattr forat; 5456 int error = 0, forat_ret = 1, gotproxystateid; 5457 off_t off, len; 5458 struct nfsstate st, *stp = &st; 5459 struct nfslock lo, *lop = &lo; 5460 nfsv4stateid_t stateid; 5461 nfsquad_t clientid; 5462 nfsattrbit_t attrbits; 5463 5464 gotproxystateid = 0; 5465 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5466 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5467 lop->lo_flags = NFSLCK_WRITE; 5468 stp->ls_ownerlen = 0; 5469 stp->ls_op = NULL; 5470 stp->ls_uid = nd->nd_cred->cr_uid; 5471 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 5472 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 5473 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 5474 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 5475 if ((nd->nd_flag & ND_NFSV41) != 0) 5476 clientid.qval = nd->nd_clientid.qval; 5477 else if (nd->nd_clientid.qval != clientid.qval) 5478 printf("EEK2 multiple clids\n"); 5479 } else { 5480 if ((nd->nd_flag & ND_NFSV41) != 0) 5481 printf("EEK! no clientid from session\n"); 5482 nd->nd_flag |= ND_IMPLIEDCLID; 5483 nd->nd_clientid.qval = clientid.qval; 5484 } 5485 stp->ls_stateid.other[2] = *tl++; 5486 /* 5487 * Don't allow this to be done for a DS. 5488 */ 5489 if ((nd->nd_flag & ND_DSSERVER) != 0) 5490 nd->nd_repstat = NFSERR_NOTSUPP; 5491 /* However, allow the proxy stateid. */ 5492 if (stp->ls_stateid.seqid == 0xffffffff && 5493 stp->ls_stateid.other[0] == 0x55555555 && 5494 stp->ls_stateid.other[1] == 0x55555555 && 5495 stp->ls_stateid.other[2] == 0x55555555) 5496 gotproxystateid = 1; 5497 off = fxdr_hyper(tl); tl += 2; 5498 lop->lo_first = off; 5499 len = fxdr_hyper(tl); 5500 if (len < 0) 5501 len = OFF_MAX; 5502 NFSD_DEBUG(4, "dealloc: off=%jd len=%jd\n", (intmax_t)off, 5503 (intmax_t)len); 5504 lop->lo_end = lop->lo_first + len; 5505 /* 5506 * Sanity check the offset and length. 5507 * off and len are off_t (signed int64_t) whereas 5508 * lo_first and lo_end are uint64_t and, as such, 5509 * if off >= 0 && len > 0, lo_end cannot overflow 5510 * unless off_t is changed to something other than 5511 * int64_t. Check lo_end < lo_first in case that 5512 * is someday the case. 5513 * The error to return is not specified by RFC 7862 so I 5514 * made this compatible with the Linux knfsd. 5515 */ 5516 if (nd->nd_repstat == 0) { 5517 if (off < 0 || lop->lo_end > NFSRV_MAXFILESIZE) 5518 nd->nd_repstat = NFSERR_FBIG; 5519 else if (len == 0 || lop->lo_end < lop->lo_first) 5520 nd->nd_repstat = NFSERR_INVAL; 5521 } 5522 5523 if (nd->nd_repstat == 0 && vp->v_type != VREG) 5524 nd->nd_repstat = NFSERR_WRONGTYPE; 5525 NFSZERO_ATTRBIT(&attrbits); 5526 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5527 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); 5528 if (nd->nd_repstat == 0) 5529 nd->nd_repstat = forat_ret; 5530 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || 5531 NFSVNO_EXSTRICTACCESS(exp))) 5532 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, 5533 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5534 NULL); 5535 if (nd->nd_repstat == 0 && gotproxystateid == 0) 5536 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 5537 &stateid, exp, nd, curthread); 5538 5539 if (nd->nd_repstat == 0) 5540 nd->nd_repstat = nfsvno_deallocate(vp, off, len, nd->nd_cred, 5541 curthread); 5542 vput(vp); 5543 NFSD_DEBUG(4, "eo deallocate=%d\n", nd->nd_repstat); 5544 NFSEXITCODE2(0, nd); 5545 return (0); 5546 nfsmout: 5547 vput(vp); 5548 NFSEXITCODE2(error, nd); 5549 return (error); 5550 } 5551 5552 /* 5553 * nfs copy service 5554 */ 5555 int 5556 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram, 5557 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 5558 { 5559 uint32_t *tl; 5560 struct nfsvattr at; 5561 int cnt, error = 0, ret; 5562 off_t inoff, outoff; 5563 uint64_t len; 5564 size_t xfer; 5565 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst; 5566 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo; 5567 nfsquad_t clientid; 5568 nfsv4stateid_t stateid; 5569 nfsattrbit_t attrbits; 5570 void *rl_rcookie, *rl_wcookie; 5571 5572 rl_rcookie = rl_wcookie = NULL; 5573 if (nfsrv_devidcnt > 0) { 5574 /* 5575 * For a pNFS server, reply NFSERR_NOTSUPP so that the client 5576 * will do the copy via I/O on the DS(s). 5577 */ 5578 nd->nd_repstat = NFSERR_NOTSUPP; 5579 goto nfsmout; 5580 } 5581 if (vp == tovp) { 5582 /* Copying a byte range within the same file is not allowed. */ 5583 nd->nd_repstat = NFSERR_INVAL; 5584 goto nfsmout; 5585 } 5586 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER + 5587 3 * NFSX_UNSIGNED); 5588 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 5589 inlop->lo_flags = NFSLCK_READ; 5590 instp->ls_ownerlen = 0; 5591 instp->ls_op = NULL; 5592 instp->ls_uid = nd->nd_cred->cr_uid; 5593 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5594 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++; 5595 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++; 5596 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) 5597 clientid.qval = nd->nd_clientid.qval; 5598 instp->ls_stateid.other[2] = *tl++; 5599 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5600 outlop->lo_flags = NFSLCK_WRITE; 5601 outstp->ls_ownerlen = 0; 5602 outstp->ls_op = NULL; 5603 outstp->ls_uid = nd->nd_cred->cr_uid; 5604 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5605 outstp->ls_stateid.other[0] = *tl++; 5606 outstp->ls_stateid.other[1] = *tl++; 5607 outstp->ls_stateid.other[2] = *tl++; 5608 inoff = fxdr_hyper(tl); tl += 2; 5609 inlop->lo_first = inoff; 5610 outoff = fxdr_hyper(tl); tl += 2; 5611 outlop->lo_first = outoff; 5612 len = fxdr_hyper(tl); tl += 2; 5613 if (len == 0) { 5614 /* len == 0 means to EOF. */ 5615 inlop->lo_end = OFF_MAX; 5616 outlop->lo_end = OFF_MAX; 5617 } else { 5618 inlop->lo_end = inlop->lo_first + len; 5619 outlop->lo_end = outlop->lo_first + len; 5620 } 5621 5622 /* 5623 * At this time only consecutive, synchronous copy is supported, 5624 * so ca_consecutive and ca_synchronous can be ignored. 5625 */ 5626 tl += 2; 5627 5628 cnt = fxdr_unsigned(int, *tl); 5629 if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0) 5630 nd->nd_repstat = NFSERR_NOTSUPP; 5631 if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX || 5632 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX || 5633 inlop->lo_end < inlop->lo_first || outlop->lo_end < 5634 outlop->lo_first)) 5635 nd->nd_repstat = NFSERR_INVAL; 5636 5637 if (nd->nd_repstat == 0 && vp->v_type != VREG) 5638 nd->nd_repstat = NFSERR_WRONGTYPE; 5639 5640 /* Check permissions for the input file. */ 5641 NFSZERO_ATTRBIT(&attrbits); 5642 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5643 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits); 5644 if (nd->nd_repstat == 0) 5645 nd->nd_repstat = ret; 5646 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5647 NFSVNO_EXSTRICTACCESS(exp))) 5648 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5649 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5650 NULL); 5651 if (nd->nd_repstat == 0) 5652 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL, 5653 clientid, &stateid, exp, nd, curthread); 5654 NFSVOPUNLOCK(vp); 5655 if (nd->nd_repstat != 0) 5656 goto out; 5657 5658 error = NFSVOPLOCK(tovp, LK_SHARED); 5659 if (error != 0) 5660 goto out; 5661 if (tovp->v_type != VREG) 5662 nd->nd_repstat = NFSERR_WRONGTYPE; 5663 5664 /* For the output file, we only need the Owner attribute. */ 5665 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits); 5666 if (nd->nd_repstat == 0) 5667 nd->nd_repstat = ret; 5668 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5669 NFSVNO_EXSTRICTACCESS(exp))) 5670 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp, 5671 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5672 NULL); 5673 if (nd->nd_repstat == 0) 5674 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL, 5675 clientid, &stateid, toexp, nd, curthread); 5676 NFSVOPUNLOCK(tovp); 5677 5678 /* Range lock the byte ranges for both invp and outvp. */ 5679 if (nd->nd_repstat == 0) { 5680 for (;;) { 5681 if (len == 0) { 5682 rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5683 OFF_MAX); 5684 rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5685 OFF_MAX); 5686 } else { 5687 rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5688 outoff + len); 5689 rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5690 inoff + len); 5691 } 5692 if (rl_rcookie != NULL) 5693 break; 5694 vn_rangelock_unlock(tovp, rl_wcookie); 5695 if (len == 0) 5696 rl_rcookie = vn_rangelock_rlock(vp, inoff, 5697 OFF_MAX); 5698 else 5699 rl_rcookie = vn_rangelock_rlock(vp, inoff, 5700 inoff + len); 5701 vn_rangelock_unlock(vp, rl_rcookie); 5702 } 5703 5704 error = NFSVOPLOCK(vp, LK_SHARED); 5705 if (error == 0) { 5706 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL); 5707 if (ret == 0) { 5708 /* 5709 * Since invp is range locked, na_size should 5710 * not change. 5711 */ 5712 if (len == 0 && at.na_size > inoff) { 5713 /* 5714 * If len == 0, set it based on invp's 5715 * size. If offset is past EOF, just 5716 * leave len == 0. 5717 */ 5718 len = at.na_size - inoff; 5719 } else if (nfsrv_linux42server == 0 && 5720 inoff + len > at.na_size) { 5721 /* 5722 * RFC-7862 says that NFSERR_INVAL must 5723 * be returned when inoff + len exceeds 5724 * the file size, however the NFSv4.2 5725 * Linux client likes to do this, so 5726 * only check if nfsrv_linux42server 5727 * is not set. 5728 */ 5729 nd->nd_repstat = NFSERR_INVAL; 5730 } 5731 } 5732 NFSVOPUNLOCK(vp); 5733 if (ret != 0 && nd->nd_repstat == 0) 5734 nd->nd_repstat = ret; 5735 } else if (nd->nd_repstat == 0) 5736 nd->nd_repstat = error; 5737 } 5738 5739 xfer = len; 5740 if (nd->nd_repstat == 0) { 5741 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff, 5742 &xfer, COPY_FILE_RANGE_TIMEO1SEC, nd->nd_cred, nd->nd_cred, 5743 NULL); 5744 if (nd->nd_repstat == 0) 5745 len = xfer; 5746 } 5747 5748 /* Unlock the ranges. */ 5749 if (rl_rcookie != NULL) 5750 vn_rangelock_unlock(vp, rl_rcookie); 5751 if (rl_wcookie != NULL) 5752 vn_rangelock_unlock(tovp, rl_wcookie); 5753 5754 if (nd->nd_repstat == 0) { 5755 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER + 5756 NFSX_VERF); 5757 *tl++ = txdr_unsigned(0); /* No callback ids. */ 5758 txdr_hyper(len, tl); tl += 2; 5759 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE); 5760 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 5761 *tl++ = txdr_unsigned(nfsboottime.tv_usec); 5762 *tl++ = newnfs_true; 5763 *tl = newnfs_true; 5764 } 5765 out: 5766 vrele(vp); 5767 vrele(tovp); 5768 NFSEXITCODE2(error, nd); 5769 return (error); 5770 nfsmout: 5771 vput(vp); 5772 vrele(tovp); 5773 NFSEXITCODE2(error, nd); 5774 return (error); 5775 } 5776 5777 /* 5778 * nfs seek service 5779 */ 5780 int 5781 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram, 5782 vnode_t vp, struct nfsexstuff *exp) 5783 { 5784 uint32_t *tl; 5785 struct nfsvattr at; 5786 int content, error = 0; 5787 off_t off; 5788 u_long cmd; 5789 nfsattrbit_t attrbits; 5790 bool eof; 5791 5792 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED); 5793 /* Ignore the stateid for now. */ 5794 tl += (NFSX_STATEID / NFSX_UNSIGNED); 5795 off = fxdr_hyper(tl); tl += 2; 5796 content = fxdr_unsigned(int, *tl); 5797 if (content == NFSV4CONTENT_DATA) 5798 cmd = FIOSEEKDATA; 5799 else if (content == NFSV4CONTENT_HOLE) 5800 cmd = FIOSEEKHOLE; 5801 else 5802 nd->nd_repstat = NFSERR_BADXDR; 5803 if (nd->nd_repstat == 0 && vp->v_type == VDIR) 5804 nd->nd_repstat = NFSERR_ISDIR; 5805 if (nd->nd_repstat == 0 && vp->v_type != VREG) 5806 nd->nd_repstat = NFSERR_WRONGTYPE; 5807 if (nd->nd_repstat == 0 && off < 0) 5808 nd->nd_repstat = NFSERR_NXIO; 5809 if (nd->nd_repstat == 0) { 5810 /* Check permissions for the input file. */ 5811 NFSZERO_ATTRBIT(&attrbits); 5812 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5813 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1, 5814 &attrbits); 5815 } 5816 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5817 NFSVNO_EXSTRICTACCESS(exp))) 5818 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5819 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5820 NULL); 5821 if (nd->nd_repstat != 0) 5822 goto nfsmout; 5823 5824 /* nfsvno_seek() unlocks and vrele()s the vp. */ 5825 nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof, 5826 nd->nd_cred, curthread); 5827 if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA && 5828 nfsrv_linux42server != 0) 5829 nd->nd_repstat = NFSERR_NXIO; 5830 if (nd->nd_repstat == 0) { 5831 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 5832 if (eof) 5833 *tl++ = newnfs_true; 5834 else 5835 *tl++ = newnfs_false; 5836 txdr_hyper(off, tl); 5837 } 5838 NFSEXITCODE2(error, nd); 5839 return (error); 5840 nfsmout: 5841 vput(vp); 5842 NFSEXITCODE2(error, nd); 5843 return (error); 5844 } 5845 5846 /* 5847 * nfs get extended attribute service 5848 */ 5849 int 5850 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram, 5851 vnode_t vp, __unused struct nfsexstuff *exp) 5852 { 5853 uint32_t *tl; 5854 struct mbuf *mp = NULL, *mpend = NULL; 5855 int error, len; 5856 char *name; 5857 struct thread *p = curthread; 5858 uint16_t off; 5859 5860 error = 0; 5861 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5862 len = fxdr_unsigned(int, *tl); 5863 if (len <= 0) { 5864 nd->nd_repstat = NFSERR_BADXDR; 5865 goto nfsmout; 5866 } 5867 if (len > EXTATTR_MAXNAMELEN) { 5868 nd->nd_repstat = NFSERR_NOXATTR; 5869 goto nfsmout; 5870 } 5871 name = malloc(len + 1, M_TEMP, M_WAITOK); 5872 nd->nd_repstat = nfsrv_mtostr(nd, name, len); 5873 if (nd->nd_repstat == 0) 5874 nd->nd_repstat = nfsvno_getxattr(vp, name, 5875 nd->nd_maxresp, nd->nd_cred, nd->nd_flag, 5876 nd->nd_maxextsiz, p, &mp, &mpend, &len); 5877 if (nd->nd_repstat == ENOATTR) 5878 nd->nd_repstat = NFSERR_NOXATTR; 5879 else if (nd->nd_repstat == EOPNOTSUPP) 5880 nd->nd_repstat = NFSERR_NOTSUPP; 5881 if (nd->nd_repstat == 0) { 5882 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5883 *tl = txdr_unsigned(len); 5884 if (len > 0) { 5885 nd->nd_mb->m_next = mp; 5886 nd->nd_mb = mpend; 5887 if ((mpend->m_flags & M_EXTPG) != 0) { 5888 nd->nd_flag |= ND_EXTPG; 5889 nd->nd_bextpg = mpend->m_epg_npgs - 1; 5890 nd->nd_bpos = (char *)(void *) 5891 PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]); 5892 off = (nd->nd_bextpg == 0) ? 5893 mpend->m_epg_1st_off : 0; 5894 nd->nd_bpos += off + mpend->m_epg_last_len; 5895 nd->nd_bextpgsiz = PAGE_SIZE - 5896 mpend->m_epg_last_len - off; 5897 } else 5898 nd->nd_bpos = mtod(mpend, char *) + 5899 mpend->m_len; 5900 } 5901 } 5902 free(name, M_TEMP); 5903 5904 nfsmout: 5905 if (nd->nd_repstat == 0) 5906 nd->nd_repstat = error; 5907 vput(vp); 5908 NFSEXITCODE2(0, nd); 5909 return (0); 5910 } 5911 5912 /* 5913 * nfs set extended attribute service 5914 */ 5915 int 5916 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram, 5917 vnode_t vp, __unused struct nfsexstuff *exp) 5918 { 5919 uint32_t *tl; 5920 struct nfsvattr ova, nva; 5921 nfsattrbit_t attrbits; 5922 int error, len, opt; 5923 char *name; 5924 size_t siz; 5925 struct thread *p = curthread; 5926 5927 error = 0; 5928 name = NULL; 5929 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5930 opt = fxdr_unsigned(int, *tl++); 5931 len = fxdr_unsigned(int, *tl); 5932 if (len <= 0) { 5933 nd->nd_repstat = NFSERR_BADXDR; 5934 goto nfsmout; 5935 } 5936 if (len > EXTATTR_MAXNAMELEN) { 5937 nd->nd_repstat = NFSERR_NOXATTR; 5938 goto nfsmout; 5939 } 5940 name = malloc(len + 1, M_TEMP, M_WAITOK); 5941 error = nfsrv_mtostr(nd, name, len); 5942 if (error != 0) 5943 goto nfsmout; 5944 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5945 len = fxdr_unsigned(int, *tl); 5946 if (len < 0 || len > IOSIZE_MAX) { 5947 nd->nd_repstat = NFSERR_XATTR2BIG; 5948 goto nfsmout; 5949 } 5950 switch (opt) { 5951 case NFSV4SXATTR_CREATE: 5952 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 5953 &siz, nd->nd_cred, p); 5954 if (error != ENOATTR) 5955 nd->nd_repstat = NFSERR_EXIST; 5956 error = 0; 5957 break; 5958 case NFSV4SXATTR_REPLACE: 5959 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 5960 &siz, nd->nd_cred, p); 5961 if (error != 0) 5962 nd->nd_repstat = NFSERR_NOXATTR; 5963 break; 5964 case NFSV4SXATTR_EITHER: 5965 break; 5966 default: 5967 nd->nd_repstat = NFSERR_BADXDR; 5968 } 5969 if (nd->nd_repstat != 0) 5970 goto nfsmout; 5971 5972 /* Now, do the Set Extended attribute, with Change before and after. */ 5973 NFSZERO_ATTRBIT(&attrbits); 5974 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 5975 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 5976 if (nd->nd_repstat == 0) { 5977 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md, 5978 nd->nd_dpos, nd->nd_cred, p); 5979 if (nd->nd_repstat == ENXIO) 5980 nd->nd_repstat = NFSERR_XATTR2BIG; 5981 } 5982 if (nd->nd_repstat == 0 && len > 0) 5983 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1); 5984 if (nd->nd_repstat == 0) 5985 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 5986 if (nd->nd_repstat == 0) { 5987 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 5988 *tl++ = newnfs_true; 5989 txdr_hyper(ova.na_filerev, tl); tl += 2; 5990 txdr_hyper(nva.na_filerev, tl); 5991 } 5992 5993 nfsmout: 5994 free(name, M_TEMP); 5995 if (nd->nd_repstat == 0) 5996 nd->nd_repstat = error; 5997 vput(vp); 5998 NFSEXITCODE2(0, nd); 5999 return (0); 6000 } 6001 6002 /* 6003 * nfs remove extended attribute service 6004 */ 6005 int 6006 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram, 6007 vnode_t vp, __unused struct nfsexstuff *exp) 6008 { 6009 uint32_t *tl; 6010 struct nfsvattr ova, nva; 6011 nfsattrbit_t attrbits; 6012 int error, len; 6013 char *name; 6014 struct thread *p = curthread; 6015 6016 error = 0; 6017 name = NULL; 6018 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6019 len = fxdr_unsigned(int, *tl); 6020 if (len <= 0) { 6021 nd->nd_repstat = NFSERR_BADXDR; 6022 goto nfsmout; 6023 } 6024 if (len > EXTATTR_MAXNAMELEN) { 6025 nd->nd_repstat = NFSERR_NOXATTR; 6026 goto nfsmout; 6027 } 6028 name = malloc(len + 1, M_TEMP, M_WAITOK); 6029 error = nfsrv_mtostr(nd, name, len); 6030 if (error != 0) 6031 goto nfsmout; 6032 6033 if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) { 6034 printf("EEK! nfsrvd_rmxattr: no implied clientid\n"); 6035 error = NFSERR_NOXATTR; 6036 goto nfsmout; 6037 } 6038 /* 6039 * Now, do the Remove Extended attribute, with Change before and 6040 * after. 6041 */ 6042 NFSZERO_ATTRBIT(&attrbits); 6043 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 6044 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 6045 if (nd->nd_repstat == 0) { 6046 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p); 6047 if (nd->nd_repstat == ENOATTR) 6048 nd->nd_repstat = NFSERR_NOXATTR; 6049 } 6050 if (nd->nd_repstat == 0) 6051 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 6052 if (nd->nd_repstat == 0) { 6053 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 6054 *tl++ = newnfs_true; 6055 txdr_hyper(ova.na_filerev, tl); tl += 2; 6056 txdr_hyper(nva.na_filerev, tl); 6057 } 6058 6059 nfsmout: 6060 free(name, M_TEMP); 6061 if (nd->nd_repstat == 0) 6062 nd->nd_repstat = error; 6063 vput(vp); 6064 NFSEXITCODE2(0, nd); 6065 return (0); 6066 } 6067 6068 /* 6069 * nfs list extended attribute service 6070 */ 6071 int 6072 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram, 6073 vnode_t vp, __unused struct nfsexstuff *exp) 6074 { 6075 uint32_t cnt, *tl, len, len2, i, pos, retlen; 6076 int error; 6077 uint64_t cookie, cookie2; 6078 u_char *buf; 6079 bool eof; 6080 struct thread *p = curthread; 6081 6082 error = 0; 6083 buf = NULL; 6084 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 6085 /* 6086 * The cookie doesn't need to be in net byte order, but FreeBSD 6087 * does so to make it more readable in packet traces. 6088 */ 6089 cookie = fxdr_hyper(tl); tl += 2; 6090 len = fxdr_unsigned(uint32_t, *tl); 6091 if (len == 0 || cookie >= IOSIZE_MAX) { 6092 nd->nd_repstat = NFSERR_BADXDR; 6093 goto nfsmout; 6094 } 6095 if (len > nd->nd_maxresp - NFS_MAXXDR) 6096 len = nd->nd_maxresp - NFS_MAXXDR; 6097 len2 = len; 6098 nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf, 6099 &len, &eof); 6100 if (nd->nd_repstat == EOPNOTSUPP) 6101 nd->nd_repstat = NFSERR_NOTSUPP; 6102 if (nd->nd_repstat == 0) { 6103 cookie2 = cookie + len; 6104 if (cookie2 < cookie) 6105 nd->nd_repstat = NFSERR_BADXDR; 6106 } 6107 retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED; 6108 if (nd->nd_repstat == 0 && len2 < retlen) 6109 nd->nd_repstat = NFSERR_TOOSMALL; 6110 if (nd->nd_repstat == 0) { 6111 /* Now copy the entries out. */ 6112 if (len == 0) { 6113 /* The cookie was at eof. */ 6114 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * 6115 NFSX_UNSIGNED); 6116 txdr_hyper(cookie2, tl); tl += 2; 6117 *tl++ = txdr_unsigned(0); 6118 *tl = newnfs_true; 6119 goto nfsmout; 6120 } 6121 6122 /* Sanity check the cookie. */ 6123 for (pos = 0; pos < len; pos += (i + 1)) { 6124 if (pos == cookie) 6125 break; 6126 i = buf[pos]; 6127 } 6128 if (pos != cookie) { 6129 nd->nd_repstat = NFSERR_INVAL; 6130 goto nfsmout; 6131 } 6132 6133 /* Loop around copying the entrie(s) out. */ 6134 cnt = 0; 6135 len -= cookie; 6136 i = buf[pos]; 6137 while (i < len && len2 >= retlen + NFSM_RNDUP(i) + 6138 NFSX_UNSIGNED) { 6139 if (cnt == 0) { 6140 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 6141 NFSX_UNSIGNED); 6142 txdr_hyper(cookie2, tl); tl += 2; 6143 } 6144 retlen += nfsm_strtom(nd, &buf[pos + 1], i); 6145 len -= (i + 1); 6146 pos += (i + 1); 6147 i = buf[pos]; 6148 cnt++; 6149 } 6150 /* 6151 * eof is set true/false by nfsvno_listxattr(), but if we 6152 * can't copy all entries returned by nfsvno_listxattr(), 6153 * we are not at eof. 6154 */ 6155 if (len > 0) 6156 eof = false; 6157 if (cnt > 0) { 6158 /* *tl is set above. */ 6159 *tl = txdr_unsigned(cnt); 6160 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 6161 if (eof) 6162 *tl = newnfs_true; 6163 else 6164 *tl = newnfs_false; 6165 } else 6166 nd->nd_repstat = NFSERR_TOOSMALL; 6167 } 6168 6169 nfsmout: 6170 free(buf, M_TEMP); 6171 if (nd->nd_repstat == 0) 6172 nd->nd_repstat = error; 6173 vput(vp); 6174 NFSEXITCODE2(0, nd); 6175 return (0); 6176 } 6177 6178 /* 6179 * nfsv4 service not supported 6180 */ 6181 int 6182 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 6183 __unused vnode_t vp, __unused struct nfsexstuff *exp) 6184 { 6185 6186 nd->nd_repstat = NFSERR_NOTSUPP; 6187 NFSEXITCODE2(0, nd); 6188 return (0); 6189 } 6190