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