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