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