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