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