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