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