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