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