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 nfs_rootfhset; 60 extern int nfsrv_enable_crossmntpt; 61 extern int nfsrv_statehashsize; 62 extern int nfsrv_layouthashsize; 63 extern time_t nfsdev_time; 64 extern volatile int nfsrv_devidcnt; 65 extern int nfsd_debuglevel; 66 extern u_long sb_max_adj; 67 extern int nfsrv_pnfsatime; 68 extern int nfsrv_maxpnfsmirror; 69 extern int nfs_maxcopyrange; 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); /* 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, 0); 1805 if (dp) 1806 NFSVOPUNLOCK(dp); 1807 } 1808 } 1809 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1810 LOCKPARENT | SAVENAME | NOCACHE); 1811 if (!nd->nd_repstat) { 1812 nfsvno_setpathbuf(&named, &bufp, &hashp); 1813 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1814 if (error) { 1815 vrele(vp); 1816 if (dp) 1817 vrele(dp); 1818 nfsvno_relpathbuf(&named); 1819 goto out; 1820 } 1821 if (!nd->nd_repstat) { 1822 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 1823 p, &dirp); 1824 } else { 1825 if (dp) 1826 vrele(dp); 1827 nfsvno_relpathbuf(&named); 1828 } 1829 } 1830 if (dirp) { 1831 if (nd->nd_flag & ND_NFSV2) { 1832 vrele(dirp); 1833 dirp = NULL; 1834 } else { 1835 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 1836 NULL); 1837 } 1838 } 1839 if (!nd->nd_repstat) 1840 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 1841 if (nd->nd_flag & ND_NFSV3) 1842 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL); 1843 if (dirp) { 1844 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 1845 vrele(dirp); 1846 } 1847 vrele(vp); 1848 if (nd->nd_flag & ND_NFSV3) { 1849 nfsrv_postopattr(nd, getret, &at); 1850 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1851 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1852 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1853 *tl++ = newnfs_false; 1854 txdr_hyper(dirfor.na_filerev, tl); 1855 tl += 2; 1856 txdr_hyper(diraft.na_filerev, tl); 1857 } 1858 1859 out: 1860 NFSEXITCODE2(error, nd); 1861 return (error); 1862 } 1863 1864 /* 1865 * nfs symbolic link service 1866 */ 1867 int 1868 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1869 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 1870 { 1871 struct nfsvattr nva, dirfor, diraft; 1872 struct nameidata named; 1873 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 1874 vnode_t dirp = NULL; 1875 char *bufp, *pathcp = NULL; 1876 u_long *hashp; 1877 struct thread *p = curthread; 1878 1879 if (nd->nd_repstat) { 1880 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1881 goto out; 1882 } 1883 if (vpp) 1884 *vpp = NULL; 1885 NFSVNO_ATTRINIT(&nva); 1886 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1887 LOCKPARENT | SAVESTART | NOCACHE); 1888 nfsvno_setpathbuf(&named, &bufp, &hashp); 1889 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1890 if (!error && !nd->nd_repstat) 1891 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 1892 if (error) { 1893 vrele(dp); 1894 nfsvno_relpathbuf(&named); 1895 goto out; 1896 } 1897 if (!nd->nd_repstat) { 1898 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1899 } else { 1900 vrele(dp); 1901 nfsvno_relpathbuf(&named); 1902 } 1903 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1904 vrele(dirp); 1905 dirp = NULL; 1906 } 1907 1908 /* 1909 * And call nfsrvd_symlinksub() to do the common code. It will 1910 * return EBADRPC upon a parsing error, 0 otherwise. 1911 */ 1912 if (!nd->nd_repstat) { 1913 if (dirp != NULL) 1914 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 1915 NULL); 1916 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1917 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 1918 pathcp, pathlen); 1919 } else if (dirp != NULL) { 1920 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 1921 vrele(dirp); 1922 } 1923 if (pathcp) 1924 free(pathcp, M_TEMP); 1925 1926 if (nd->nd_flag & ND_NFSV3) { 1927 if (!nd->nd_repstat) { 1928 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1929 nfsrv_postopattr(nd, 0, &nva); 1930 } 1931 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1932 } 1933 1934 out: 1935 NFSEXITCODE2(error, nd); 1936 return (error); 1937 } 1938 1939 /* 1940 * Common code for creating a symbolic link. 1941 */ 1942 static void 1943 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 1944 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1945 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1946 int *diraft_retp, nfsattrbit_t *attrbitp, 1947 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 1948 int pathlen) 1949 { 1950 u_int32_t *tl; 1951 1952 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 1953 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 1954 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 1955 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 1956 if (nd->nd_flag & ND_NFSV3) { 1957 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 1958 if (!nd->nd_repstat) 1959 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 1960 nvap, nd, p, 1, NULL); 1961 } 1962 if (vpp != NULL && nd->nd_repstat == 0) { 1963 NFSVOPUNLOCK(ndp->ni_vp); 1964 *vpp = ndp->ni_vp; 1965 } else 1966 vput(ndp->ni_vp); 1967 } 1968 if (dirp) { 1969 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 1970 vrele(dirp); 1971 } 1972 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1973 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1974 *tl++ = newnfs_false; 1975 txdr_hyper(dirforp->na_filerev, tl); 1976 tl += 2; 1977 txdr_hyper(diraftp->na_filerev, tl); 1978 (void) nfsrv_putattrbit(nd, attrbitp); 1979 } 1980 1981 NFSEXITCODE2(0, nd); 1982 } 1983 1984 /* 1985 * nfs mkdir service 1986 */ 1987 int 1988 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 1989 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp) 1990 { 1991 struct nfsvattr nva, dirfor, diraft; 1992 struct nameidata named; 1993 u_int32_t *tl; 1994 int error = 0, dirfor_ret = 1, diraft_ret = 1; 1995 vnode_t dirp = NULL; 1996 char *bufp; 1997 u_long *hashp; 1998 struct thread *p = curthread; 1999 2000 if (nd->nd_repstat) { 2001 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 2002 goto out; 2003 } 2004 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 2005 LOCKPARENT | SAVENAME | NOCACHE); 2006 nfsvno_setpathbuf(&named, &bufp, &hashp); 2007 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2008 if (error) 2009 goto nfsmout; 2010 if (!nd->nd_repstat) { 2011 NFSVNO_ATTRINIT(&nva); 2012 if (nd->nd_flag & ND_NFSV3) { 2013 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 2014 if (error) 2015 goto nfsmout; 2016 } else { 2017 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2018 nva.na_mode = nfstov_mode(*tl++); 2019 } 2020 } 2021 if (!nd->nd_repstat) { 2022 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 2023 } else { 2024 vrele(dp); 2025 nfsvno_relpathbuf(&named); 2026 } 2027 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 2028 vrele(dirp); 2029 dirp = NULL; 2030 } 2031 if (nd->nd_repstat) { 2032 if (dirp != NULL) { 2033 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, 2034 NULL); 2035 vrele(dirp); 2036 } 2037 if (nd->nd_flag & ND_NFSV3) 2038 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 2039 &diraft); 2040 goto out; 2041 } 2042 if (dirp != NULL) 2043 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL); 2044 2045 /* 2046 * Call nfsrvd_mkdirsub() for the code common to V4 as well. 2047 */ 2048 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 2049 &diraft_ret, NULL, NULL, p, exp); 2050 2051 if (nd->nd_flag & ND_NFSV3) { 2052 if (!nd->nd_repstat) { 2053 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 2054 nfsrv_postopattr(nd, 0, &nva); 2055 } 2056 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 2057 } else if (!nd->nd_repstat) { 2058 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 2059 nfsrv_fillattr(nd, &nva); 2060 } 2061 2062 out: 2063 NFSEXITCODE2(0, nd); 2064 return (0); 2065 nfsmout: 2066 vrele(dp); 2067 nfsvno_relpathbuf(&named); 2068 NFSEXITCODE2(error, nd); 2069 return (error); 2070 } 2071 2072 /* 2073 * Code common to mkdir for V2,3 and 4. 2074 */ 2075 static void 2076 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 2077 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 2078 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 2079 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 2080 NFSPROC_T *p, struct nfsexstuff *exp) 2081 { 2082 vnode_t vp; 2083 u_int32_t *tl; 2084 2085 NFSVNO_SETATTRVAL(nvap, type, VDIR); 2086 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 2087 nd->nd_cred, p, exp); 2088 if (!nd->nd_repstat) { 2089 vp = ndp->ni_vp; 2090 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 2091 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 2092 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 2093 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1, 2094 NULL); 2095 if (vpp && !nd->nd_repstat) { 2096 NFSVOPUNLOCK(vp); 2097 *vpp = vp; 2098 } else { 2099 vput(vp); 2100 } 2101 } 2102 if (dirp) { 2103 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL); 2104 vrele(dirp); 2105 } 2106 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 2107 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2108 *tl++ = newnfs_false; 2109 txdr_hyper(dirforp->na_filerev, tl); 2110 tl += 2; 2111 txdr_hyper(diraftp->na_filerev, tl); 2112 (void) nfsrv_putattrbit(nd, attrbitp); 2113 } 2114 2115 NFSEXITCODE2(0, nd); 2116 } 2117 2118 /* 2119 * nfs commit service 2120 */ 2121 int 2122 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 2123 vnode_t vp, __unused struct nfsexstuff *exp) 2124 { 2125 struct nfsvattr bfor, aft; 2126 u_int32_t *tl; 2127 int error = 0, for_ret = 1, aft_ret = 1, cnt; 2128 u_int64_t off; 2129 struct thread *p = curthread; 2130 2131 if (nd->nd_repstat) { 2132 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 2133 goto out; 2134 } 2135 2136 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */ 2137 if (vp->v_type != VREG) { 2138 if (nd->nd_flag & ND_NFSV3) 2139 error = NFSERR_NOTSUPP; 2140 else 2141 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL; 2142 goto nfsmout; 2143 } 2144 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2145 2146 /* 2147 * XXX At this time VOP_FSYNC() does not accept offset and byte 2148 * count parameters, so these arguments are useless (someday maybe). 2149 */ 2150 off = fxdr_hyper(tl); 2151 tl += 2; 2152 cnt = fxdr_unsigned(int, *tl); 2153 if (nd->nd_flag & ND_NFSV3) 2154 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL); 2155 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 2156 if (nd->nd_flag & ND_NFSV3) { 2157 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL); 2158 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 2159 } 2160 vput(vp); 2161 if (!nd->nd_repstat) { 2162 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2163 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 2164 *tl = txdr_unsigned(nfsboottime.tv_usec); 2165 } 2166 2167 out: 2168 NFSEXITCODE2(0, nd); 2169 return (0); 2170 nfsmout: 2171 vput(vp); 2172 NFSEXITCODE2(error, nd); 2173 return (error); 2174 } 2175 2176 /* 2177 * nfs statfs service 2178 */ 2179 int 2180 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 2181 vnode_t vp, __unused struct nfsexstuff *exp) 2182 { 2183 struct statfs *sf; 2184 u_int32_t *tl; 2185 int getret = 1; 2186 struct nfsvattr at; 2187 u_quad_t tval; 2188 struct thread *p = curthread; 2189 2190 sf = NULL; 2191 if (nd->nd_repstat) { 2192 nfsrv_postopattr(nd, getret, &at); 2193 goto out; 2194 } 2195 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 2196 nd->nd_repstat = nfsvno_statfs(vp, sf); 2197 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 2198 vput(vp); 2199 if (nd->nd_flag & ND_NFSV3) 2200 nfsrv_postopattr(nd, getret, &at); 2201 if (nd->nd_repstat) 2202 goto out; 2203 if (nd->nd_flag & ND_NFSV2) { 2204 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 2205 *tl++ = txdr_unsigned(NFS_V2MAXDATA); 2206 *tl++ = txdr_unsigned(sf->f_bsize); 2207 *tl++ = txdr_unsigned(sf->f_blocks); 2208 *tl++ = txdr_unsigned(sf->f_bfree); 2209 *tl = txdr_unsigned(sf->f_bavail); 2210 } else { 2211 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 2212 tval = (u_quad_t)sf->f_blocks; 2213 tval *= (u_quad_t)sf->f_bsize; 2214 txdr_hyper(tval, tl); tl += 2; 2215 tval = (u_quad_t)sf->f_bfree; 2216 tval *= (u_quad_t)sf->f_bsize; 2217 txdr_hyper(tval, tl); tl += 2; 2218 tval = (u_quad_t)sf->f_bavail; 2219 tval *= (u_quad_t)sf->f_bsize; 2220 txdr_hyper(tval, tl); tl += 2; 2221 tval = (u_quad_t)sf->f_files; 2222 txdr_hyper(tval, tl); tl += 2; 2223 tval = (u_quad_t)sf->f_ffree; 2224 txdr_hyper(tval, tl); tl += 2; 2225 tval = (u_quad_t)sf->f_ffree; 2226 txdr_hyper(tval, tl); tl += 2; 2227 *tl = 0; 2228 } 2229 2230 out: 2231 free(sf, M_STATFS); 2232 NFSEXITCODE2(0, nd); 2233 return (0); 2234 } 2235 2236 /* 2237 * nfs fsinfo service 2238 */ 2239 int 2240 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 2241 vnode_t vp, __unused struct nfsexstuff *exp) 2242 { 2243 u_int32_t *tl; 2244 struct nfsfsinfo fs; 2245 int getret = 1; 2246 struct nfsvattr at; 2247 struct thread *p = curthread; 2248 2249 if (nd->nd_repstat) { 2250 nfsrv_postopattr(nd, getret, &at); 2251 goto out; 2252 } 2253 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 2254 nfsvno_getfs(&fs, isdgram); 2255 vput(vp); 2256 nfsrv_postopattr(nd, getret, &at); 2257 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 2258 *tl++ = txdr_unsigned(fs.fs_rtmax); 2259 *tl++ = txdr_unsigned(fs.fs_rtpref); 2260 *tl++ = txdr_unsigned(fs.fs_rtmult); 2261 *tl++ = txdr_unsigned(fs.fs_wtmax); 2262 *tl++ = txdr_unsigned(fs.fs_wtpref); 2263 *tl++ = txdr_unsigned(fs.fs_wtmult); 2264 *tl++ = txdr_unsigned(fs.fs_dtpref); 2265 txdr_hyper(fs.fs_maxfilesize, tl); 2266 tl += 2; 2267 txdr_nfsv3time(&fs.fs_timedelta, tl); 2268 tl += 2; 2269 *tl = txdr_unsigned(fs.fs_properties); 2270 2271 out: 2272 NFSEXITCODE2(0, nd); 2273 return (0); 2274 } 2275 2276 /* 2277 * nfs pathconf service 2278 */ 2279 int 2280 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 2281 vnode_t vp, __unused struct nfsexstuff *exp) 2282 { 2283 struct nfsv3_pathconf *pc; 2284 int getret = 1; 2285 long linkmax, namemax, chownres, notrunc; 2286 struct nfsvattr at; 2287 struct thread *p = curthread; 2288 2289 if (nd->nd_repstat) { 2290 nfsrv_postopattr(nd, getret, &at); 2291 goto out; 2292 } 2293 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 2294 nd->nd_cred, p); 2295 if (!nd->nd_repstat) 2296 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 2297 nd->nd_cred, p); 2298 if (!nd->nd_repstat) 2299 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 2300 &chownres, nd->nd_cred, p); 2301 if (!nd->nd_repstat) 2302 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 2303 nd->nd_cred, p); 2304 getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL); 2305 vput(vp); 2306 nfsrv_postopattr(nd, getret, &at); 2307 if (!nd->nd_repstat) { 2308 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 2309 pc->pc_linkmax = txdr_unsigned(linkmax); 2310 pc->pc_namemax = txdr_unsigned(namemax); 2311 pc->pc_notrunc = txdr_unsigned(notrunc); 2312 pc->pc_chownrestricted = txdr_unsigned(chownres); 2313 2314 /* 2315 * These should probably be supported by VOP_PATHCONF(), but 2316 * until msdosfs is exportable (why would you want to?), the 2317 * Unix defaults should be ok. 2318 */ 2319 pc->pc_caseinsensitive = newnfs_false; 2320 pc->pc_casepreserving = newnfs_true; 2321 } 2322 2323 out: 2324 NFSEXITCODE2(0, nd); 2325 return (0); 2326 } 2327 2328 /* 2329 * nfsv4 lock service 2330 */ 2331 int 2332 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2333 vnode_t vp, struct nfsexstuff *exp) 2334 { 2335 u_int32_t *tl; 2336 int i; 2337 struct nfsstate *stp = NULL; 2338 struct nfslock *lop; 2339 struct nfslockconflict cf; 2340 int error = 0; 2341 u_short flags = NFSLCK_LOCK, lflags; 2342 u_int64_t offset, len; 2343 nfsv4stateid_t stateid; 2344 nfsquad_t clientid; 2345 struct thread *p = curthread; 2346 2347 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2348 i = fxdr_unsigned(int, *tl++); 2349 switch (i) { 2350 case NFSV4LOCKT_READW: 2351 flags |= NFSLCK_BLOCKING; 2352 case NFSV4LOCKT_READ: 2353 lflags = NFSLCK_READ; 2354 break; 2355 case NFSV4LOCKT_WRITEW: 2356 flags |= NFSLCK_BLOCKING; 2357 case NFSV4LOCKT_WRITE: 2358 lflags = NFSLCK_WRITE; 2359 break; 2360 default: 2361 nd->nd_repstat = NFSERR_BADXDR; 2362 goto nfsmout; 2363 } 2364 if (*tl++ == newnfs_true) 2365 flags |= NFSLCK_RECLAIM; 2366 offset = fxdr_hyper(tl); 2367 tl += 2; 2368 len = fxdr_hyper(tl); 2369 tl += 2; 2370 if (*tl == newnfs_true) 2371 flags |= NFSLCK_OPENTOLOCK; 2372 if (flags & NFSLCK_OPENTOLOCK) { 2373 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 2374 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 2375 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2376 nd->nd_repstat = NFSERR_BADXDR; 2377 goto nfsmout; 2378 } 2379 stp = malloc(sizeof (struct nfsstate) + i, 2380 M_NFSDSTATE, M_WAITOK); 2381 stp->ls_ownerlen = i; 2382 stp->ls_op = nd->nd_rp; 2383 stp->ls_seq = fxdr_unsigned(int, *tl++); 2384 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2385 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2386 NFSX_STATEIDOTHER); 2387 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2388 2389 /* 2390 * For the special stateid of other all 0s and seqid == 1, set 2391 * the stateid to the current stateid, if it is set. 2392 */ 2393 if ((nd->nd_flag & ND_NFSV41) != 0 && 2394 stp->ls_stateid.seqid == 1 && 2395 stp->ls_stateid.other[0] == 0 && 2396 stp->ls_stateid.other[1] == 0 && 2397 stp->ls_stateid.other[2] == 0) { 2398 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 2399 stp->ls_stateid = nd->nd_curstateid; 2400 stp->ls_stateid.seqid = 0; 2401 } else { 2402 nd->nd_repstat = NFSERR_BADSTATEID; 2403 goto nfsmout; 2404 } 2405 } 2406 2407 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 2408 clientid.lval[0] = *tl++; 2409 clientid.lval[1] = *tl++; 2410 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2411 if ((nd->nd_flag & ND_NFSV41) != 0) 2412 clientid.qval = nd->nd_clientid.qval; 2413 else if (nd->nd_clientid.qval != clientid.qval) 2414 printf("EEK3 multiple clids\n"); 2415 } else { 2416 if ((nd->nd_flag & ND_NFSV41) != 0) 2417 printf("EEK! no clientid from session\n"); 2418 nd->nd_flag |= ND_IMPLIEDCLID; 2419 nd->nd_clientid.qval = clientid.qval; 2420 } 2421 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2422 if (error) 2423 goto nfsmout; 2424 } else { 2425 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2426 stp = malloc(sizeof (struct nfsstate), 2427 M_NFSDSTATE, M_WAITOK); 2428 stp->ls_ownerlen = 0; 2429 stp->ls_op = nd->nd_rp; 2430 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2431 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2432 NFSX_STATEIDOTHER); 2433 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2434 2435 /* 2436 * For the special stateid of other all 0s and seqid == 1, set 2437 * the stateid to the current stateid, if it is set. 2438 */ 2439 if ((nd->nd_flag & ND_NFSV41) != 0 && 2440 stp->ls_stateid.seqid == 1 && 2441 stp->ls_stateid.other[0] == 0 && 2442 stp->ls_stateid.other[1] == 0 && 2443 stp->ls_stateid.other[2] == 0) { 2444 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 2445 stp->ls_stateid = nd->nd_curstateid; 2446 stp->ls_stateid.seqid = 0; 2447 } else { 2448 nd->nd_repstat = NFSERR_BADSTATEID; 2449 goto nfsmout; 2450 } 2451 } 2452 2453 stp->ls_seq = fxdr_unsigned(int, *tl); 2454 clientid.lval[0] = stp->ls_stateid.other[0]; 2455 clientid.lval[1] = stp->ls_stateid.other[1]; 2456 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2457 if ((nd->nd_flag & ND_NFSV41) != 0) 2458 clientid.qval = nd->nd_clientid.qval; 2459 else if (nd->nd_clientid.qval != clientid.qval) 2460 printf("EEK4 multiple clids\n"); 2461 } else { 2462 if ((nd->nd_flag & ND_NFSV41) != 0) 2463 printf("EEK! no clientid from session\n"); 2464 nd->nd_flag |= ND_IMPLIEDCLID; 2465 nd->nd_clientid.qval = clientid.qval; 2466 } 2467 } 2468 lop = malloc(sizeof (struct nfslock), 2469 M_NFSDLOCK, M_WAITOK); 2470 lop->lo_first = offset; 2471 if (len == NFS64BITSSET) { 2472 lop->lo_end = NFS64BITSSET; 2473 } else { 2474 lop->lo_end = offset + len; 2475 if (lop->lo_end <= lop->lo_first) 2476 nd->nd_repstat = NFSERR_INVAL; 2477 } 2478 lop->lo_flags = lflags; 2479 stp->ls_flags = flags; 2480 stp->ls_uid = nd->nd_cred->cr_uid; 2481 2482 /* 2483 * Do basic access checking. 2484 */ 2485 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2486 if (vnode_vtype(vp) == VDIR) 2487 nd->nd_repstat = NFSERR_ISDIR; 2488 else 2489 nd->nd_repstat = NFSERR_INVAL; 2490 } 2491 if (!nd->nd_repstat) { 2492 if (lflags & NFSLCK_WRITE) { 2493 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 2494 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2495 NFSACCCHK_VPISLOCKED, NULL); 2496 } else { 2497 nd->nd_repstat = nfsvno_accchk(vp, VREAD, 2498 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2499 NFSACCCHK_VPISLOCKED, NULL); 2500 if (nd->nd_repstat) 2501 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2502 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2503 NFSACCCHK_VPISLOCKED, NULL); 2504 } 2505 } 2506 2507 /* 2508 * We call nfsrv_lockctrl() even if nd_repstat set, so that the 2509 * seqid# gets updated. nfsrv_lockctrl() will return the value 2510 * of nd_repstat, if it gets that far. 2511 */ 2512 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2513 &stateid, exp, nd, p); 2514 if (lop) 2515 free(lop, M_NFSDLOCK); 2516 if (stp) 2517 free(stp, M_NFSDSTATE); 2518 if (!nd->nd_repstat) { 2519 /* For NFSv4.1, set the Current StateID. */ 2520 if ((nd->nd_flag & ND_NFSV41) != 0) { 2521 nd->nd_curstateid = stateid; 2522 nd->nd_flag |= ND_CURSTATEID; 2523 } 2524 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2525 *tl++ = txdr_unsigned(stateid.seqid); 2526 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2527 } else if (nd->nd_repstat == NFSERR_DENIED) { 2528 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2529 txdr_hyper(cf.cl_first, tl); 2530 tl += 2; 2531 if (cf.cl_end == NFS64BITSSET) 2532 len = NFS64BITSSET; 2533 else 2534 len = cf.cl_end - cf.cl_first; 2535 txdr_hyper(len, tl); 2536 tl += 2; 2537 if (cf.cl_flags == NFSLCK_WRITE) 2538 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2539 else 2540 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2541 *tl++ = stateid.other[0]; 2542 *tl = stateid.other[1]; 2543 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2544 } 2545 vput(vp); 2546 NFSEXITCODE2(0, nd); 2547 return (0); 2548 nfsmout: 2549 vput(vp); 2550 if (stp) 2551 free(stp, M_NFSDSTATE); 2552 NFSEXITCODE2(error, nd); 2553 return (error); 2554 } 2555 2556 /* 2557 * nfsv4 lock test service 2558 */ 2559 int 2560 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2561 vnode_t vp, struct nfsexstuff *exp) 2562 { 2563 u_int32_t *tl; 2564 int i; 2565 struct nfsstate *stp = NULL; 2566 struct nfslock lo, *lop = &lo; 2567 struct nfslockconflict cf; 2568 int error = 0; 2569 nfsv4stateid_t stateid; 2570 nfsquad_t clientid; 2571 u_int64_t len; 2572 struct thread *p = curthread; 2573 2574 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 2575 i = fxdr_unsigned(int, *(tl + 7)); 2576 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2577 nd->nd_repstat = NFSERR_BADXDR; 2578 goto nfsmout; 2579 } 2580 stp = malloc(sizeof (struct nfsstate) + i, 2581 M_NFSDSTATE, M_WAITOK); 2582 stp->ls_ownerlen = i; 2583 stp->ls_op = NULL; 2584 stp->ls_flags = NFSLCK_TEST; 2585 stp->ls_uid = nd->nd_cred->cr_uid; 2586 i = fxdr_unsigned(int, *tl++); 2587 switch (i) { 2588 case NFSV4LOCKT_READW: 2589 stp->ls_flags |= NFSLCK_BLOCKING; 2590 case NFSV4LOCKT_READ: 2591 lo.lo_flags = NFSLCK_READ; 2592 break; 2593 case NFSV4LOCKT_WRITEW: 2594 stp->ls_flags |= NFSLCK_BLOCKING; 2595 case NFSV4LOCKT_WRITE: 2596 lo.lo_flags = NFSLCK_WRITE; 2597 break; 2598 default: 2599 nd->nd_repstat = NFSERR_BADXDR; 2600 goto nfsmout; 2601 } 2602 lo.lo_first = fxdr_hyper(tl); 2603 tl += 2; 2604 len = fxdr_hyper(tl); 2605 if (len == NFS64BITSSET) { 2606 lo.lo_end = NFS64BITSSET; 2607 } else { 2608 lo.lo_end = lo.lo_first + len; 2609 if (lo.lo_end <= lo.lo_first) 2610 nd->nd_repstat = NFSERR_INVAL; 2611 } 2612 tl += 2; 2613 clientid.lval[0] = *tl++; 2614 clientid.lval[1] = *tl; 2615 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2616 if ((nd->nd_flag & ND_NFSV41) != 0) 2617 clientid.qval = nd->nd_clientid.qval; 2618 else if (nd->nd_clientid.qval != clientid.qval) 2619 printf("EEK5 multiple clids\n"); 2620 } else { 2621 if ((nd->nd_flag & ND_NFSV41) != 0) 2622 printf("EEK! no clientid from session\n"); 2623 nd->nd_flag |= ND_IMPLIEDCLID; 2624 nd->nd_clientid.qval = clientid.qval; 2625 } 2626 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2627 if (error) 2628 goto nfsmout; 2629 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2630 if (vnode_vtype(vp) == VDIR) 2631 nd->nd_repstat = NFSERR_ISDIR; 2632 else 2633 nd->nd_repstat = NFSERR_INVAL; 2634 } 2635 if (!nd->nd_repstat) 2636 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2637 &stateid, exp, nd, p); 2638 if (nd->nd_repstat) { 2639 if (nd->nd_repstat == NFSERR_DENIED) { 2640 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2641 txdr_hyper(cf.cl_first, tl); 2642 tl += 2; 2643 if (cf.cl_end == NFS64BITSSET) 2644 len = NFS64BITSSET; 2645 else 2646 len = cf.cl_end - cf.cl_first; 2647 txdr_hyper(len, tl); 2648 tl += 2; 2649 if (cf.cl_flags == NFSLCK_WRITE) 2650 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2651 else 2652 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2653 *tl++ = stp->ls_stateid.other[0]; 2654 *tl = stp->ls_stateid.other[1]; 2655 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2656 } 2657 } 2658 vput(vp); 2659 if (stp) 2660 free(stp, M_NFSDSTATE); 2661 NFSEXITCODE2(0, nd); 2662 return (0); 2663 nfsmout: 2664 vput(vp); 2665 if (stp) 2666 free(stp, M_NFSDSTATE); 2667 NFSEXITCODE2(error, nd); 2668 return (error); 2669 } 2670 2671 /* 2672 * nfsv4 unlock service 2673 */ 2674 int 2675 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2676 vnode_t vp, struct nfsexstuff *exp) 2677 { 2678 u_int32_t *tl; 2679 int i; 2680 struct nfsstate *stp; 2681 struct nfslock *lop; 2682 int error = 0; 2683 nfsv4stateid_t stateid; 2684 nfsquad_t clientid; 2685 u_int64_t len; 2686 struct thread *p = curthread; 2687 2688 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2689 stp = malloc(sizeof (struct nfsstate), 2690 M_NFSDSTATE, M_WAITOK); 2691 lop = malloc(sizeof (struct nfslock), 2692 M_NFSDLOCK, M_WAITOK); 2693 stp->ls_flags = NFSLCK_UNLOCK; 2694 lop->lo_flags = NFSLCK_UNLOCK; 2695 stp->ls_op = nd->nd_rp; 2696 i = fxdr_unsigned(int, *tl++); 2697 switch (i) { 2698 case NFSV4LOCKT_READW: 2699 stp->ls_flags |= NFSLCK_BLOCKING; 2700 case NFSV4LOCKT_READ: 2701 break; 2702 case NFSV4LOCKT_WRITEW: 2703 stp->ls_flags |= NFSLCK_BLOCKING; 2704 case NFSV4LOCKT_WRITE: 2705 break; 2706 default: 2707 nd->nd_repstat = NFSERR_BADXDR; 2708 free(stp, M_NFSDSTATE); 2709 free(lop, M_NFSDLOCK); 2710 goto nfsmout; 2711 } 2712 stp->ls_ownerlen = 0; 2713 stp->ls_uid = nd->nd_cred->cr_uid; 2714 stp->ls_seq = fxdr_unsigned(int, *tl++); 2715 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2716 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2717 NFSX_STATEIDOTHER); 2718 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2719 2720 /* 2721 * For the special stateid of other all 0s and seqid == 1, set the 2722 * stateid to the current stateid, if it is set. 2723 */ 2724 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 2725 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 2726 stp->ls_stateid.other[2] == 0) { 2727 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 2728 stp->ls_stateid = nd->nd_curstateid; 2729 stp->ls_stateid.seqid = 0; 2730 } else { 2731 nd->nd_repstat = NFSERR_BADSTATEID; 2732 free(stp, M_NFSDSTATE); 2733 free(lop, M_NFSDLOCK); 2734 goto nfsmout; 2735 } 2736 } 2737 2738 lop->lo_first = fxdr_hyper(tl); 2739 tl += 2; 2740 len = fxdr_hyper(tl); 2741 if (len == NFS64BITSSET) { 2742 lop->lo_end = NFS64BITSSET; 2743 } else { 2744 lop->lo_end = lop->lo_first + len; 2745 if (lop->lo_end <= lop->lo_first) 2746 nd->nd_repstat = NFSERR_INVAL; 2747 } 2748 clientid.lval[0] = stp->ls_stateid.other[0]; 2749 clientid.lval[1] = stp->ls_stateid.other[1]; 2750 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2751 if ((nd->nd_flag & ND_NFSV41) != 0) 2752 clientid.qval = nd->nd_clientid.qval; 2753 else if (nd->nd_clientid.qval != clientid.qval) 2754 printf("EEK6 multiple clids\n"); 2755 } else { 2756 if ((nd->nd_flag & ND_NFSV41) != 0) 2757 printf("EEK! no clientid from session\n"); 2758 nd->nd_flag |= ND_IMPLIEDCLID; 2759 nd->nd_clientid.qval = clientid.qval; 2760 } 2761 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2762 if (vnode_vtype(vp) == VDIR) 2763 nd->nd_repstat = NFSERR_ISDIR; 2764 else 2765 nd->nd_repstat = NFSERR_INVAL; 2766 } 2767 /* 2768 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 2769 * seqid# gets incremented. nfsrv_lockctrl() will return the 2770 * value of nd_repstat, if it gets that far. 2771 */ 2772 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 2773 &stateid, exp, nd, p); 2774 if (stp) 2775 free(stp, M_NFSDSTATE); 2776 if (lop) 2777 free(lop, M_NFSDLOCK); 2778 if (!nd->nd_repstat) { 2779 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2780 *tl++ = txdr_unsigned(stateid.seqid); 2781 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2782 } 2783 nfsmout: 2784 vput(vp); 2785 NFSEXITCODE2(error, nd); 2786 return (error); 2787 } 2788 2789 /* 2790 * nfsv4 open service 2791 */ 2792 int 2793 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2794 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp) 2795 { 2796 u_int32_t *tl; 2797 int i, retext; 2798 struct nfsstate *stp = NULL; 2799 int error = 0, create, claim, exclusive_flag = 0, override; 2800 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 2801 int how = NFSCREATE_UNCHECKED; 2802 int32_t cverf[2], tverf[2] = { 0, 0 }; 2803 vnode_t vp = NULL, dirp = NULL; 2804 struct nfsvattr nva, dirfor, diraft; 2805 struct nameidata named; 2806 nfsv4stateid_t stateid, delegstateid; 2807 nfsattrbit_t attrbits; 2808 nfsquad_t clientid; 2809 char *bufp = NULL; 2810 u_long *hashp; 2811 NFSACL_T *aclp = NULL; 2812 struct thread *p = curthread; 2813 2814 #ifdef NFS4_ACL_EXTATTR_NAME 2815 aclp = acl_alloc(M_WAITOK); 2816 aclp->acl_cnt = 0; 2817 #endif 2818 NFSZERO_ATTRBIT(&attrbits); 2819 named.ni_startdir = NULL; 2820 named.ni_cnd.cn_nameiop = 0; 2821 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2822 i = fxdr_unsigned(int, *(tl + 5)); 2823 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2824 nd->nd_repstat = NFSERR_BADXDR; 2825 goto nfsmout; 2826 } 2827 stp = malloc(sizeof (struct nfsstate) + i, 2828 M_NFSDSTATE, M_WAITOK); 2829 stp->ls_ownerlen = i; 2830 stp->ls_op = nd->nd_rp; 2831 stp->ls_flags = NFSLCK_OPEN; 2832 stp->ls_uid = nd->nd_cred->cr_uid; 2833 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2834 i = fxdr_unsigned(int, *tl++); 2835 retext = 0; 2836 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2837 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2838 retext = 1; 2839 /* For now, ignore these. */ 2840 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2841 switch (i & NFSV4OPEN_WANTDELEGMASK) { 2842 case NFSV4OPEN_WANTANYDELEG: 2843 stp->ls_flags |= (NFSLCK_WANTRDELEG | 2844 NFSLCK_WANTWDELEG); 2845 i &= ~NFSV4OPEN_WANTDELEGMASK; 2846 break; 2847 case NFSV4OPEN_WANTREADDELEG: 2848 stp->ls_flags |= NFSLCK_WANTRDELEG; 2849 i &= ~NFSV4OPEN_WANTDELEGMASK; 2850 break; 2851 case NFSV4OPEN_WANTWRITEDELEG: 2852 stp->ls_flags |= NFSLCK_WANTWDELEG; 2853 i &= ~NFSV4OPEN_WANTDELEGMASK; 2854 break; 2855 case NFSV4OPEN_WANTNODELEG: 2856 stp->ls_flags |= NFSLCK_WANTNODELEG; 2857 i &= ~NFSV4OPEN_WANTDELEGMASK; 2858 break; 2859 case NFSV4OPEN_WANTCANCEL: 2860 printf("NFSv4: ignore Open WantCancel\n"); 2861 i &= ~NFSV4OPEN_WANTDELEGMASK; 2862 break; 2863 default: 2864 /* nd_repstat will be set to NFSERR_INVAL below. */ 2865 break; 2866 } 2867 } 2868 switch (i) { 2869 case NFSV4OPEN_ACCESSREAD: 2870 stp->ls_flags |= NFSLCK_READACCESS; 2871 break; 2872 case NFSV4OPEN_ACCESSWRITE: 2873 stp->ls_flags |= NFSLCK_WRITEACCESS; 2874 break; 2875 case NFSV4OPEN_ACCESSBOTH: 2876 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2877 break; 2878 default: 2879 nd->nd_repstat = NFSERR_INVAL; 2880 } 2881 i = fxdr_unsigned(int, *tl++); 2882 switch (i) { 2883 case NFSV4OPEN_DENYNONE: 2884 break; 2885 case NFSV4OPEN_DENYREAD: 2886 stp->ls_flags |= NFSLCK_READDENY; 2887 break; 2888 case NFSV4OPEN_DENYWRITE: 2889 stp->ls_flags |= NFSLCK_WRITEDENY; 2890 break; 2891 case NFSV4OPEN_DENYBOTH: 2892 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 2893 break; 2894 default: 2895 nd->nd_repstat = NFSERR_INVAL; 2896 } 2897 clientid.lval[0] = *tl++; 2898 clientid.lval[1] = *tl; 2899 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2900 if ((nd->nd_flag & ND_NFSV41) != 0) 2901 clientid.qval = nd->nd_clientid.qval; 2902 else if (nd->nd_clientid.qval != clientid.qval) 2903 printf("EEK7 multiple clids\n"); 2904 } else { 2905 if ((nd->nd_flag & ND_NFSV41) != 0) 2906 printf("EEK! no clientid from session\n"); 2907 nd->nd_flag |= ND_IMPLIEDCLID; 2908 nd->nd_clientid.qval = clientid.qval; 2909 } 2910 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2911 if (error) 2912 goto nfsmout; 2913 NFSVNO_ATTRINIT(&nva); 2914 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2915 create = fxdr_unsigned(int, *tl); 2916 if (!nd->nd_repstat) 2917 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 2918 if (create == NFSV4OPEN_CREATE) { 2919 nva.na_type = VREG; 2920 nva.na_mode = 0; 2921 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2922 how = fxdr_unsigned(int, *tl); 2923 switch (how) { 2924 case NFSCREATE_UNCHECKED: 2925 case NFSCREATE_GUARDED: 2926 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2927 if (error) 2928 goto nfsmout; 2929 /* 2930 * If the na_gid being set is the same as that of 2931 * the directory it is going in, clear it, since 2932 * that is what will be set by default. This allows 2933 * a user that isn't in that group to do the create. 2934 */ 2935 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 2936 nva.na_gid == dirfor.na_gid) 2937 NFSVNO_UNSET(&nva, gid); 2938 if (!nd->nd_repstat) 2939 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2940 break; 2941 case NFSCREATE_EXCLUSIVE: 2942 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2943 cverf[0] = *tl++; 2944 cverf[1] = *tl; 2945 break; 2946 case NFSCREATE_EXCLUSIVE41: 2947 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2948 cverf[0] = *tl++; 2949 cverf[1] = *tl; 2950 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2951 if (error != 0) 2952 goto nfsmout; 2953 if (NFSISSET_ATTRBIT(&attrbits, 2954 NFSATTRBIT_TIMEACCESSSET)) 2955 nd->nd_repstat = NFSERR_INVAL; 2956 /* 2957 * If the na_gid being set is the same as that of 2958 * the directory it is going in, clear it, since 2959 * that is what will be set by default. This allows 2960 * a user that isn't in that group to do the create. 2961 */ 2962 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2963 nva.na_gid == dirfor.na_gid) 2964 NFSVNO_UNSET(&nva, gid); 2965 if (nd->nd_repstat == 0) 2966 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2967 break; 2968 default: 2969 nd->nd_repstat = NFSERR_BADXDR; 2970 goto nfsmout; 2971 } 2972 } else if (create != NFSV4OPEN_NOCREATE) { 2973 nd->nd_repstat = NFSERR_BADXDR; 2974 goto nfsmout; 2975 } 2976 2977 /* 2978 * Now, handle the claim, which usually includes looking up a 2979 * name in the directory referenced by dp. The exception is 2980 * NFSV4OPEN_CLAIMPREVIOUS. 2981 */ 2982 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2983 claim = fxdr_unsigned(int, *tl); 2984 if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim == 2985 NFSV4OPEN_CLAIMDELEGATECURFH) { 2986 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2987 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2988 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 2989 stp->ls_flags |= NFSLCK_DELEGCUR; 2990 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim == 2991 NFSV4OPEN_CLAIMDELEGATEPREVFH) { 2992 stp->ls_flags |= NFSLCK_DELEGPREV; 2993 } 2994 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 2995 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2996 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 2997 claim != NFSV4OPEN_CLAIMNULL) 2998 nd->nd_repstat = NFSERR_INVAL; 2999 if (nd->nd_repstat) { 3000 nd->nd_repstat = nfsrv_opencheck(clientid, 3001 &stateid, stp, NULL, nd, p, nd->nd_repstat); 3002 goto nfsmout; 3003 } 3004 if (create == NFSV4OPEN_CREATE) 3005 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 3006 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 3007 else 3008 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3009 LOCKLEAF | SAVESTART); 3010 nfsvno_setpathbuf(&named, &bufp, &hashp); 3011 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3012 if (error) { 3013 vrele(dp); 3014 #ifdef NFS4_ACL_EXTATTR_NAME 3015 acl_free(aclp); 3016 #endif 3017 free(stp, M_NFSDSTATE); 3018 nfsvno_relpathbuf(&named); 3019 NFSEXITCODE2(error, nd); 3020 return (error); 3021 } 3022 if (!nd->nd_repstat) { 3023 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 3024 p, &dirp); 3025 } else { 3026 vrele(dp); 3027 nfsvno_relpathbuf(&named); 3028 } 3029 if (create == NFSV4OPEN_CREATE) { 3030 switch (how) { 3031 case NFSCREATE_UNCHECKED: 3032 if (named.ni_vp) { 3033 /* 3034 * Clear the setable attribute bits, except 3035 * for Size, if it is being truncated. 3036 */ 3037 NFSZERO_ATTRBIT(&attrbits); 3038 if (NFSVNO_ISSETSIZE(&nva)) 3039 NFSSETBIT_ATTRBIT(&attrbits, 3040 NFSATTRBIT_SIZE); 3041 } 3042 break; 3043 case NFSCREATE_GUARDED: 3044 if (named.ni_vp && !nd->nd_repstat) 3045 nd->nd_repstat = EEXIST; 3046 break; 3047 case NFSCREATE_EXCLUSIVE: 3048 exclusive_flag = 1; 3049 if (!named.ni_vp) 3050 nva.na_mode = 0; 3051 break; 3052 case NFSCREATE_EXCLUSIVE41: 3053 exclusive_flag = 1; 3054 break; 3055 } 3056 } 3057 nfsvno_open(nd, &named, clientid, &stateid, stp, 3058 &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 3059 nd->nd_cred, exp, &vp); 3060 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 3061 NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH || 3062 claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) { 3063 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 3064 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3065 i = fxdr_unsigned(int, *tl); 3066 switch (i) { 3067 case NFSV4OPEN_DELEGATEREAD: 3068 stp->ls_flags |= NFSLCK_DELEGREAD; 3069 break; 3070 case NFSV4OPEN_DELEGATEWRITE: 3071 stp->ls_flags |= NFSLCK_DELEGWRITE; 3072 case NFSV4OPEN_DELEGATENONE: 3073 break; 3074 default: 3075 nd->nd_repstat = NFSERR_BADXDR; 3076 goto nfsmout; 3077 } 3078 stp->ls_flags |= NFSLCK_RECLAIM; 3079 } else { 3080 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 3081 nd->nd_repstat = NFSERR_INVAL; 3082 } 3083 vp = dp; 3084 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3085 if (!VN_IS_DOOMED(vp)) 3086 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 3087 stp, vp, nd, p, nd->nd_repstat); 3088 else 3089 nd->nd_repstat = NFSERR_PERM; 3090 } else { 3091 nd->nd_repstat = NFSERR_BADXDR; 3092 goto nfsmout; 3093 } 3094 3095 /* 3096 * Do basic access checking. 3097 */ 3098 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 3099 /* 3100 * The IETF working group decided that this is the correct 3101 * error return for all non-regular files. 3102 */ 3103 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK; 3104 } 3105 3106 /* 3107 * If the Open is being done for a file that already exists, apply 3108 * normal permission checking including for the file owner, if 3109 * vfs.nfsd.v4openaccess is set. 3110 * Previously, the owner was always allowed to open the file to 3111 * be consistent with the NFS tradition of always allowing the 3112 * owner of the file to write to the file regardless of permissions. 3113 * It now appears that the Linux client expects the owner 3114 * permissions to be checked for opens that are not creating the 3115 * file. I believe the correct approach is to use the Access 3116 * operation's results to be consistent with NFSv3, but that is 3117 * not what the current Linux client appears to be doing. 3118 * Since both the Linux and OpenSolaris NFSv4 servers do this check, 3119 * I have enabled it by default. 3120 * If this semantic change causes a problem, it can be disabled by 3121 * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the 3122 * previous semantics. 3123 */ 3124 if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE) 3125 override = NFSACCCHK_NOOVERRIDE; 3126 else 3127 override = NFSACCCHK_ALLOWOWNER; 3128 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 3129 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 3130 exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 3131 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 3132 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 3133 exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 3134 if (nd->nd_repstat) 3135 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 3136 nd->nd_cred, exp, p, override, 3137 NFSACCCHK_VPISLOCKED, NULL); 3138 } 3139 3140 if (!nd->nd_repstat) { 3141 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 3142 if (!nd->nd_repstat) { 3143 tverf[0] = nva.na_atime.tv_sec; 3144 tverf[1] = nva.na_atime.tv_nsec; 3145 } 3146 } 3147 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 3148 cverf[1] != tverf[1])) 3149 nd->nd_repstat = EEXIST; 3150 /* 3151 * Do the open locking/delegation stuff. 3152 */ 3153 if (!nd->nd_repstat) 3154 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 3155 &delegstateid, &rflags, exp, p, nva.na_filerev); 3156 3157 /* 3158 * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 3159 * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 3160 * (ie: Leave the NFSVOPUNLOCK() about here.) 3161 */ 3162 if (vp) 3163 NFSVOPUNLOCK(vp); 3164 if (stp) 3165 free(stp, M_NFSDSTATE); 3166 if (!nd->nd_repstat && dirp) 3167 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 3168 if (!nd->nd_repstat) { 3169 /* For NFSv4.1, set the Current StateID. */ 3170 if ((nd->nd_flag & ND_NFSV41) != 0) { 3171 nd->nd_curstateid = stateid; 3172 nd->nd_flag |= ND_CURSTATEID; 3173 } 3174 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 3175 *tl++ = txdr_unsigned(stateid.seqid); 3176 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3177 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3178 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 3179 *tl++ = newnfs_true; 3180 *tl++ = 0; 3181 *tl++ = 0; 3182 *tl++ = 0; 3183 *tl++ = 0; 3184 } else { 3185 *tl++ = newnfs_false; /* Since dirp is not locked */ 3186 txdr_hyper(dirfor.na_filerev, tl); 3187 tl += 2; 3188 txdr_hyper(diraft.na_filerev, tl); 3189 tl += 2; 3190 } 3191 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 3192 (void) nfsrv_putattrbit(nd, &attrbits); 3193 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3194 if (rflags & NFSV4OPEN_READDELEGATE) 3195 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 3196 else if (rflags & NFSV4OPEN_WRITEDELEGATE) 3197 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 3198 else if (retext != 0) { 3199 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 3200 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) { 3201 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3202 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3203 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) { 3204 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3205 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE); 3206 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 3207 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3208 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 3209 *tl = newnfs_false; 3210 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 3211 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3212 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 3213 *tl = newnfs_false; 3214 } else { 3215 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3216 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3217 } 3218 } else 3219 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 3220 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 3221 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 3222 *tl++ = txdr_unsigned(delegstateid.seqid); 3223 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 3224 NFSX_STATEIDOTHER); 3225 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3226 if (rflags & NFSV4OPEN_RECALL) 3227 *tl = newnfs_true; 3228 else 3229 *tl = newnfs_false; 3230 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 3231 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3232 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 3233 txdr_hyper(nva.na_size, tl); 3234 } 3235 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3236 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 3237 *tl++ = txdr_unsigned(0x0); 3238 acemask = NFSV4ACE_ALLFILESMASK; 3239 if (nva.na_mode & S_IRUSR) 3240 acemask |= NFSV4ACE_READMASK; 3241 if (nva.na_mode & S_IWUSR) 3242 acemask |= NFSV4ACE_WRITEMASK; 3243 if (nva.na_mode & S_IXUSR) 3244 acemask |= NFSV4ACE_EXECUTEMASK; 3245 *tl = txdr_unsigned(acemask); 3246 (void) nfsm_strtom(nd, "OWNER@", 6); 3247 } 3248 *vpp = vp; 3249 } else if (vp) { 3250 vrele(vp); 3251 } 3252 if (dirp) 3253 vrele(dirp); 3254 #ifdef NFS4_ACL_EXTATTR_NAME 3255 acl_free(aclp); 3256 #endif 3257 NFSEXITCODE2(0, nd); 3258 return (0); 3259 nfsmout: 3260 vrele(dp); 3261 #ifdef NFS4_ACL_EXTATTR_NAME 3262 acl_free(aclp); 3263 #endif 3264 if (stp) 3265 free(stp, M_NFSDSTATE); 3266 NFSEXITCODE2(error, nd); 3267 return (error); 3268 } 3269 3270 /* 3271 * nfsv4 close service 3272 */ 3273 int 3274 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3275 vnode_t vp, __unused struct nfsexstuff *exp) 3276 { 3277 u_int32_t *tl; 3278 struct nfsstate st, *stp = &st; 3279 int error = 0, writeacc; 3280 nfsv4stateid_t stateid; 3281 nfsquad_t clientid; 3282 struct nfsvattr na; 3283 struct thread *p = curthread; 3284 3285 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 3286 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3287 stp->ls_ownerlen = 0; 3288 stp->ls_op = nd->nd_rp; 3289 stp->ls_uid = nd->nd_cred->cr_uid; 3290 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3291 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3292 NFSX_STATEIDOTHER); 3293 3294 /* 3295 * For the special stateid of other all 0s and seqid == 1, set the 3296 * stateid to the current stateid, if it is set. 3297 */ 3298 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 3299 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 3300 stp->ls_stateid.other[2] == 0) { 3301 if ((nd->nd_flag & ND_CURSTATEID) != 0) 3302 stp->ls_stateid = nd->nd_curstateid; 3303 else { 3304 nd->nd_repstat = NFSERR_BADSTATEID; 3305 goto nfsmout; 3306 } 3307 } 3308 3309 stp->ls_flags = NFSLCK_CLOSE; 3310 clientid.lval[0] = stp->ls_stateid.other[0]; 3311 clientid.lval[1] = stp->ls_stateid.other[1]; 3312 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3313 if ((nd->nd_flag & ND_NFSV41) != 0) 3314 clientid.qval = nd->nd_clientid.qval; 3315 else if (nd->nd_clientid.qval != clientid.qval) 3316 printf("EEK8 multiple clids\n"); 3317 } else { 3318 if ((nd->nd_flag & ND_NFSV41) != 0) 3319 printf("EEK! no clientid from session\n"); 3320 nd->nd_flag |= ND_IMPLIEDCLID; 3321 nd->nd_clientid.qval = clientid.qval; 3322 } 3323 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 3324 &writeacc); 3325 /* For pNFS, update the attributes. */ 3326 if (writeacc != 0 || nfsrv_pnfsatime != 0) 3327 nfsrv_updatemdsattr(vp, &na, p); 3328 vput(vp); 3329 if (!nd->nd_repstat) { 3330 /* 3331 * If the stateid that has been closed is the current stateid, 3332 * unset it. 3333 */ 3334 if ((nd->nd_flag & ND_CURSTATEID) != 0 && 3335 stateid.other[0] == nd->nd_curstateid.other[0] && 3336 stateid.other[1] == nd->nd_curstateid.other[1] && 3337 stateid.other[2] == nd->nd_curstateid.other[2]) 3338 nd->nd_flag &= ~ND_CURSTATEID; 3339 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3340 *tl++ = txdr_unsigned(stateid.seqid); 3341 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3342 } 3343 NFSEXITCODE2(0, nd); 3344 return (0); 3345 nfsmout: 3346 vput(vp); 3347 NFSEXITCODE2(error, nd); 3348 return (error); 3349 } 3350 3351 /* 3352 * nfsv4 delegpurge service 3353 */ 3354 int 3355 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3356 __unused vnode_t vp, __unused struct nfsexstuff *exp) 3357 { 3358 u_int32_t *tl; 3359 int error = 0; 3360 nfsquad_t clientid; 3361 struct thread *p = curthread; 3362 3363 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3364 nd->nd_repstat = NFSERR_WRONGSEC; 3365 goto nfsmout; 3366 } 3367 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3368 clientid.lval[0] = *tl++; 3369 clientid.lval[1] = *tl; 3370 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3371 if ((nd->nd_flag & ND_NFSV41) != 0) 3372 clientid.qval = nd->nd_clientid.qval; 3373 else if (nd->nd_clientid.qval != clientid.qval) 3374 printf("EEK9 multiple clids\n"); 3375 } else { 3376 if ((nd->nd_flag & ND_NFSV41) != 0) 3377 printf("EEK! no clientid from session\n"); 3378 nd->nd_flag |= ND_IMPLIEDCLID; 3379 nd->nd_clientid.qval = clientid.qval; 3380 } 3381 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 3382 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL); 3383 nfsmout: 3384 NFSEXITCODE2(error, nd); 3385 return (error); 3386 } 3387 3388 /* 3389 * nfsv4 delegreturn service 3390 */ 3391 int 3392 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3393 vnode_t vp, __unused struct nfsexstuff *exp) 3394 { 3395 u_int32_t *tl; 3396 int error = 0, writeacc; 3397 nfsv4stateid_t stateid; 3398 nfsquad_t clientid; 3399 struct nfsvattr na; 3400 struct thread *p = curthread; 3401 3402 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3403 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3404 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 3405 clientid.lval[0] = stateid.other[0]; 3406 clientid.lval[1] = stateid.other[1]; 3407 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3408 if ((nd->nd_flag & ND_NFSV41) != 0) 3409 clientid.qval = nd->nd_clientid.qval; 3410 else if (nd->nd_clientid.qval != clientid.qval) 3411 printf("EEK10 multiple clids\n"); 3412 } else { 3413 if ((nd->nd_flag & ND_NFSV41) != 0) 3414 printf("EEK! no clientid from session\n"); 3415 nd->nd_flag |= ND_IMPLIEDCLID; 3416 nd->nd_clientid.qval = clientid.qval; 3417 } 3418 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 3419 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc); 3420 /* For pNFS, update the attributes. */ 3421 if (writeacc != 0 || nfsrv_pnfsatime != 0) 3422 nfsrv_updatemdsattr(vp, &na, p); 3423 nfsmout: 3424 vput(vp); 3425 NFSEXITCODE2(error, nd); 3426 return (error); 3427 } 3428 3429 /* 3430 * nfsv4 get file handle service 3431 */ 3432 int 3433 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3434 vnode_t vp, __unused struct nfsexstuff *exp) 3435 { 3436 fhandle_t fh; 3437 struct thread *p = curthread; 3438 3439 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3440 vput(vp); 3441 if (!nd->nd_repstat) 3442 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3443 NFSEXITCODE2(0, nd); 3444 return (0); 3445 } 3446 3447 /* 3448 * nfsv4 open confirm service 3449 */ 3450 int 3451 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3452 vnode_t vp, __unused struct nfsexstuff *exp) 3453 { 3454 u_int32_t *tl; 3455 struct nfsstate st, *stp = &st; 3456 int error = 0; 3457 nfsv4stateid_t stateid; 3458 nfsquad_t clientid; 3459 struct thread *p = curthread; 3460 3461 if ((nd->nd_flag & ND_NFSV41) != 0) { 3462 nd->nd_repstat = NFSERR_NOTSUPP; 3463 goto nfsmout; 3464 } 3465 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3466 stp->ls_ownerlen = 0; 3467 stp->ls_op = nd->nd_rp; 3468 stp->ls_uid = nd->nd_cred->cr_uid; 3469 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3470 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3471 NFSX_STATEIDOTHER); 3472 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3473 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 3474 stp->ls_flags = NFSLCK_CONFIRM; 3475 clientid.lval[0] = stp->ls_stateid.other[0]; 3476 clientid.lval[1] = stp->ls_stateid.other[1]; 3477 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3478 if ((nd->nd_flag & ND_NFSV41) != 0) 3479 clientid.qval = nd->nd_clientid.qval; 3480 else if (nd->nd_clientid.qval != clientid.qval) 3481 printf("EEK11 multiple clids\n"); 3482 } else { 3483 if ((nd->nd_flag & ND_NFSV41) != 0) 3484 printf("EEK! no clientid from session\n"); 3485 nd->nd_flag |= ND_IMPLIEDCLID; 3486 nd->nd_clientid.qval = clientid.qval; 3487 } 3488 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 3489 NULL); 3490 if (!nd->nd_repstat) { 3491 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3492 *tl++ = txdr_unsigned(stateid.seqid); 3493 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3494 } 3495 nfsmout: 3496 vput(vp); 3497 NFSEXITCODE2(error, nd); 3498 return (error); 3499 } 3500 3501 /* 3502 * nfsv4 open downgrade service 3503 */ 3504 int 3505 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3506 vnode_t vp, __unused struct nfsexstuff *exp) 3507 { 3508 u_int32_t *tl; 3509 int i; 3510 struct nfsstate st, *stp = &st; 3511 int error = 0; 3512 nfsv4stateid_t stateid; 3513 nfsquad_t clientid; 3514 struct thread *p = curthread; 3515 3516 /* opendowngrade can only work on a file object.*/ 3517 if (vp->v_type != VREG) { 3518 error = NFSERR_INVAL; 3519 goto nfsmout; 3520 } 3521 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 3522 stp->ls_ownerlen = 0; 3523 stp->ls_op = nd->nd_rp; 3524 stp->ls_uid = nd->nd_cred->cr_uid; 3525 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3526 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3527 NFSX_STATEIDOTHER); 3528 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3529 3530 /* 3531 * For the special stateid of other all 0s and seqid == 1, set the 3532 * stateid to the current stateid, if it is set. 3533 */ 3534 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 3535 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 3536 stp->ls_stateid.other[2] == 0) { 3537 if ((nd->nd_flag & ND_CURSTATEID) != 0) 3538 stp->ls_stateid = nd->nd_curstateid; 3539 else { 3540 nd->nd_repstat = NFSERR_BADSTATEID; 3541 goto nfsmout; 3542 } 3543 } 3544 3545 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3546 i = fxdr_unsigned(int, *tl++); 3547 if ((nd->nd_flag & ND_NFSV41) != 0) 3548 i &= ~NFSV4OPEN_WANTDELEGMASK; 3549 switch (i) { 3550 case NFSV4OPEN_ACCESSREAD: 3551 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3552 break; 3553 case NFSV4OPEN_ACCESSWRITE: 3554 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3555 break; 3556 case NFSV4OPEN_ACCESSBOTH: 3557 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3558 NFSLCK_DOWNGRADE); 3559 break; 3560 default: 3561 nd->nd_repstat = NFSERR_INVAL; 3562 } 3563 i = fxdr_unsigned(int, *tl); 3564 switch (i) { 3565 case NFSV4OPEN_DENYNONE: 3566 break; 3567 case NFSV4OPEN_DENYREAD: 3568 stp->ls_flags |= NFSLCK_READDENY; 3569 break; 3570 case NFSV4OPEN_DENYWRITE: 3571 stp->ls_flags |= NFSLCK_WRITEDENY; 3572 break; 3573 case NFSV4OPEN_DENYBOTH: 3574 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3575 break; 3576 default: 3577 nd->nd_repstat = NFSERR_INVAL; 3578 } 3579 3580 clientid.lval[0] = stp->ls_stateid.other[0]; 3581 clientid.lval[1] = stp->ls_stateid.other[1]; 3582 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3583 if ((nd->nd_flag & ND_NFSV41) != 0) 3584 clientid.qval = nd->nd_clientid.qval; 3585 else if (nd->nd_clientid.qval != clientid.qval) 3586 printf("EEK12 multiple clids\n"); 3587 } else { 3588 if ((nd->nd_flag & ND_NFSV41) != 0) 3589 printf("EEK! no clientid from session\n"); 3590 nd->nd_flag |= ND_IMPLIEDCLID; 3591 nd->nd_clientid.qval = clientid.qval; 3592 } 3593 if (!nd->nd_repstat) 3594 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3595 nd, p, NULL); 3596 if (!nd->nd_repstat) { 3597 /* For NFSv4.1, set the Current StateID. */ 3598 if ((nd->nd_flag & ND_NFSV41) != 0) { 3599 nd->nd_curstateid = stateid; 3600 nd->nd_flag |= ND_CURSTATEID; 3601 } 3602 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3603 *tl++ = txdr_unsigned(stateid.seqid); 3604 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3605 } 3606 nfsmout: 3607 vput(vp); 3608 NFSEXITCODE2(error, nd); 3609 return (error); 3610 } 3611 3612 /* 3613 * nfsv4 renew lease service 3614 */ 3615 int 3616 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3617 __unused vnode_t vp, __unused struct nfsexstuff *exp) 3618 { 3619 u_int32_t *tl; 3620 int error = 0; 3621 nfsquad_t clientid; 3622 struct thread *p = curthread; 3623 3624 if ((nd->nd_flag & ND_NFSV41) != 0) { 3625 nd->nd_repstat = NFSERR_NOTSUPP; 3626 goto nfsmout; 3627 } 3628 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3629 nd->nd_repstat = NFSERR_WRONGSEC; 3630 goto nfsmout; 3631 } 3632 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3633 clientid.lval[0] = *tl++; 3634 clientid.lval[1] = *tl; 3635 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3636 if ((nd->nd_flag & ND_NFSV41) != 0) 3637 clientid.qval = nd->nd_clientid.qval; 3638 else if (nd->nd_clientid.qval != clientid.qval) 3639 printf("EEK13 multiple clids\n"); 3640 } else { 3641 if ((nd->nd_flag & ND_NFSV41) != 0) 3642 printf("EEK! no clientid from session\n"); 3643 nd->nd_flag |= ND_IMPLIEDCLID; 3644 nd->nd_clientid.qval = clientid.qval; 3645 } 3646 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3647 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 3648 nfsmout: 3649 NFSEXITCODE2(error, nd); 3650 return (error); 3651 } 3652 3653 /* 3654 * nfsv4 security info service 3655 */ 3656 int 3657 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3658 vnode_t dp, struct nfsexstuff *exp) 3659 { 3660 u_int32_t *tl; 3661 int len; 3662 struct nameidata named; 3663 vnode_t dirp = NULL, vp; 3664 struct nfsrvfh fh; 3665 struct nfsexstuff retnes; 3666 u_int32_t *sizp; 3667 int error = 0, i; 3668 uint64_t savflag; 3669 char *bufp; 3670 u_long *hashp; 3671 struct thread *p = curthread; 3672 3673 /* 3674 * All this just to get the export flags for the name. 3675 */ 3676 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3677 LOCKLEAF | SAVESTART); 3678 nfsvno_setpathbuf(&named, &bufp, &hashp); 3679 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3680 if (error) { 3681 vput(dp); 3682 nfsvno_relpathbuf(&named); 3683 goto out; 3684 } 3685 if (!nd->nd_repstat) { 3686 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3687 } else { 3688 vput(dp); 3689 nfsvno_relpathbuf(&named); 3690 } 3691 if (dirp) 3692 vrele(dirp); 3693 if (nd->nd_repstat) 3694 goto out; 3695 vrele(named.ni_startdir); 3696 nfsvno_relpathbuf(&named); 3697 fh.nfsrvfh_len = NFSX_MYFH; 3698 vp = named.ni_vp; 3699 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3700 vput(vp); 3701 savflag = nd->nd_flag; 3702 if (!nd->nd_repstat) { 3703 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0); 3704 if (vp) 3705 vput(vp); 3706 } 3707 nd->nd_flag = savflag; 3708 if (nd->nd_repstat) 3709 goto out; 3710 3711 /* 3712 * Finally have the export flags for name, so we can create 3713 * the security info. 3714 */ 3715 len = 0; 3716 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3717 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3718 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3719 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3720 *tl = txdr_unsigned(RPCAUTH_UNIX); 3721 len++; 3722 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3723 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3724 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3725 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3726 nfsgss_mechlist[KERBV_MECH].len); 3727 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3728 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3729 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3730 len++; 3731 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3732 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3733 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3734 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3735 nfsgss_mechlist[KERBV_MECH].len); 3736 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3737 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3738 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3739 len++; 3740 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3741 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3742 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3743 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3744 nfsgss_mechlist[KERBV_MECH].len); 3745 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3746 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3747 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3748 len++; 3749 } 3750 } 3751 *sizp = txdr_unsigned(len); 3752 3753 out: 3754 NFSEXITCODE2(error, nd); 3755 return (error); 3756 } 3757 3758 /* 3759 * nfsv4 security info no name service 3760 */ 3761 int 3762 nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram, 3763 vnode_t dp, struct nfsexstuff *exp) 3764 { 3765 uint32_t *tl, *sizp; 3766 struct nameidata named; 3767 vnode_t dirp = NULL, vp; 3768 struct nfsrvfh fh; 3769 struct nfsexstuff retnes; 3770 int error = 0, fhstyle, i, len; 3771 uint64_t savflag; 3772 char *bufp; 3773 u_long *hashp; 3774 struct thread *p = curthread; 3775 3776 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3777 fhstyle = fxdr_unsigned(int, *tl); 3778 switch (fhstyle) { 3779 case NFSSECINFONONAME_PARENT: 3780 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3781 LOCKLEAF | SAVESTART); 3782 nfsvno_setpathbuf(&named, &bufp, &hashp); 3783 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3784 if (error != 0) { 3785 vput(dp); 3786 nfsvno_relpathbuf(&named); 3787 goto nfsmout; 3788 } 3789 if (nd->nd_repstat == 0) 3790 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3791 else 3792 vput(dp); 3793 if (dirp != NULL) 3794 vrele(dirp); 3795 vrele(named.ni_startdir); 3796 nfsvno_relpathbuf(&named); 3797 vp = named.ni_vp; 3798 break; 3799 case NFSSECINFONONAME_CURFH: 3800 vp = dp; 3801 break; 3802 default: 3803 nd->nd_repstat = NFSERR_INVAL; 3804 vput(dp); 3805 } 3806 if (nd->nd_repstat != 0) 3807 goto nfsmout; 3808 fh.nfsrvfh_len = NFSX_MYFH; 3809 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3810 vput(vp); 3811 savflag = nd->nd_flag; 3812 if (nd->nd_repstat == 0) { 3813 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0); 3814 if (vp != NULL) 3815 vput(vp); 3816 } 3817 nd->nd_flag = savflag; 3818 if (nd->nd_repstat != 0) 3819 goto nfsmout; 3820 3821 /* 3822 * Finally have the export flags for fh/parent, so we can create 3823 * the security info. 3824 */ 3825 len = 0; 3826 NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED); 3827 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3828 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3829 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3830 *tl = txdr_unsigned(RPCAUTH_UNIX); 3831 len++; 3832 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3833 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3834 *tl = txdr_unsigned(RPCAUTH_GSS); 3835 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3836 nfsgss_mechlist[KERBV_MECH].len); 3837 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3838 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3839 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3840 len++; 3841 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3842 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3843 *tl = txdr_unsigned(RPCAUTH_GSS); 3844 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3845 nfsgss_mechlist[KERBV_MECH].len); 3846 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3847 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3848 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3849 len++; 3850 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3851 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 3852 *tl = txdr_unsigned(RPCAUTH_GSS); 3853 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3854 nfsgss_mechlist[KERBV_MECH].len); 3855 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 3856 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3857 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3858 len++; 3859 } 3860 } 3861 *sizp = txdr_unsigned(len); 3862 3863 nfsmout: 3864 NFSEXITCODE2(error, nd); 3865 return (error); 3866 } 3867 3868 /* 3869 * nfsv4 set client id service 3870 */ 3871 int 3872 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3873 __unused vnode_t vp, __unused struct nfsexstuff *exp) 3874 { 3875 u_int32_t *tl; 3876 int i; 3877 int error = 0, idlen; 3878 struct nfsclient *clp = NULL; 3879 #ifdef INET 3880 struct sockaddr_in *rin; 3881 #endif 3882 #ifdef INET6 3883 struct sockaddr_in6 *rin6; 3884 #endif 3885 #if defined(INET) || defined(INET6) 3886 u_char *ucp, *ucp2; 3887 #endif 3888 u_char *verf, *addrbuf; 3889 nfsquad_t clientid, confirm; 3890 struct thread *p = curthread; 3891 3892 if ((nd->nd_flag & ND_NFSV41) != 0) { 3893 nd->nd_repstat = NFSERR_NOTSUPP; 3894 goto nfsmout; 3895 } 3896 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3897 nd->nd_repstat = NFSERR_WRONGSEC; 3898 goto out; 3899 } 3900 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3901 verf = (u_char *)tl; 3902 tl += (NFSX_VERF / NFSX_UNSIGNED); 3903 i = fxdr_unsigned(int, *tl); 3904 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3905 nd->nd_repstat = NFSERR_BADXDR; 3906 goto nfsmout; 3907 } 3908 idlen = i; 3909 if (nd->nd_flag & ND_GSS) 3910 i += nd->nd_princlen; 3911 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3912 M_ZERO); 3913 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3914 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3915 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3916 /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 3917 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 3918 M_WAITOK | M_ZERO); 3919 clp->lc_req.nr_cred = NULL; 3920 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3921 clp->lc_idlen = idlen; 3922 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3923 if (error) 3924 goto nfsmout; 3925 if (nd->nd_flag & ND_GSS) { 3926 clp->lc_flags = LCL_GSS; 3927 if (nd->nd_flag & ND_GSSINTEGRITY) 3928 clp->lc_flags |= LCL_GSSINTEGRITY; 3929 else if (nd->nd_flag & ND_GSSPRIVACY) 3930 clp->lc_flags |= LCL_GSSPRIVACY; 3931 } else { 3932 clp->lc_flags = 0; 3933 } 3934 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 3935 clp->lc_flags |= LCL_NAME; 3936 clp->lc_namelen = nd->nd_princlen; 3937 clp->lc_name = &clp->lc_id[idlen]; 3938 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3939 } else { 3940 clp->lc_uid = nd->nd_cred->cr_uid; 3941 clp->lc_gid = nd->nd_cred->cr_gid; 3942 } 3943 3944 /* If the client is using TLS, do so for the callback connection. */ 3945 if (nd->nd_flag & ND_TLS) 3946 clp->lc_flags |= LCL_TLSCB; 3947 3948 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3949 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 3950 error = nfsrv_getclientipaddr(nd, clp); 3951 if (error) 3952 goto nfsmout; 3953 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3954 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 3955 3956 /* 3957 * nfsrv_setclient() does the actual work of adding it to the 3958 * client list. If there is no error, the structure has been 3959 * linked into the client list and clp should no longer be used 3960 * here. When an error is returned, it has not been linked in, 3961 * so it should be free'd. 3962 */ 3963 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3964 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3965 /* 3966 * 8 is the maximum length of the port# string. 3967 */ 3968 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK); 3969 switch (clp->lc_req.nr_nam->sa_family) { 3970 #ifdef INET 3971 case AF_INET: 3972 if (clp->lc_flags & LCL_TCPCALLBACK) 3973 (void) nfsm_strtom(nd, "tcp", 3); 3974 else 3975 (void) nfsm_strtom(nd, "udp", 3); 3976 rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 3977 ucp = (u_char *)&rin->sin_addr.s_addr; 3978 ucp2 = (u_char *)&rin->sin_port; 3979 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 3980 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 3981 ucp2[0] & 0xff, ucp2[1] & 0xff); 3982 break; 3983 #endif 3984 #ifdef INET6 3985 case AF_INET6: 3986 if (clp->lc_flags & LCL_TCPCALLBACK) 3987 (void) nfsm_strtom(nd, "tcp6", 4); 3988 else 3989 (void) nfsm_strtom(nd, "udp6", 4); 3990 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 3991 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf, 3992 INET6_ADDRSTRLEN); 3993 if (ucp != NULL) 3994 i = strlen(ucp); 3995 else 3996 i = 0; 3997 ucp2 = (u_char *)&rin6->sin6_port; 3998 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff, 3999 ucp2[1] & 0xff); 4000 break; 4001 #endif 4002 } 4003 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 4004 free(addrbuf, M_TEMP); 4005 } 4006 if (clp) { 4007 free(clp->lc_req.nr_nam, M_SONAME); 4008 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4009 free(clp->lc_stateid, M_NFSDCLIENT); 4010 free(clp, M_NFSDCLIENT); 4011 } 4012 if (!nd->nd_repstat) { 4013 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 4014 *tl++ = clientid.lval[0]; 4015 *tl++ = clientid.lval[1]; 4016 *tl++ = confirm.lval[0]; 4017 *tl = confirm.lval[1]; 4018 } 4019 4020 out: 4021 NFSEXITCODE2(0, nd); 4022 return (0); 4023 nfsmout: 4024 if (clp) { 4025 free(clp->lc_req.nr_nam, M_SONAME); 4026 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4027 free(clp->lc_stateid, M_NFSDCLIENT); 4028 free(clp, M_NFSDCLIENT); 4029 } 4030 NFSEXITCODE2(error, nd); 4031 return (error); 4032 } 4033 4034 /* 4035 * nfsv4 set client id confirm service 4036 */ 4037 int 4038 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 4039 __unused int isdgram, __unused vnode_t vp, 4040 __unused struct nfsexstuff *exp) 4041 { 4042 u_int32_t *tl; 4043 int error = 0; 4044 nfsquad_t clientid, confirm; 4045 struct thread *p = curthread; 4046 4047 if ((nd->nd_flag & ND_NFSV41) != 0) { 4048 nd->nd_repstat = NFSERR_NOTSUPP; 4049 goto nfsmout; 4050 } 4051 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4052 nd->nd_repstat = NFSERR_WRONGSEC; 4053 goto nfsmout; 4054 } 4055 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 4056 clientid.lval[0] = *tl++; 4057 clientid.lval[1] = *tl++; 4058 confirm.lval[0] = *tl++; 4059 confirm.lval[1] = *tl; 4060 4061 /* 4062 * nfsrv_getclient() searches the client list for a match and 4063 * returns the appropriate NFSERR status. 4064 */ 4065 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 4066 NULL, NULL, confirm, 0, nd, p); 4067 nfsmout: 4068 NFSEXITCODE2(error, nd); 4069 return (error); 4070 } 4071 4072 /* 4073 * nfsv4 verify service 4074 */ 4075 int 4076 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 4077 vnode_t vp, __unused struct nfsexstuff *exp) 4078 { 4079 int error = 0, ret, fhsize = NFSX_MYFH; 4080 struct nfsvattr nva; 4081 struct statfs *sf; 4082 struct nfsfsinfo fs; 4083 fhandle_t fh; 4084 struct thread *p = curthread; 4085 4086 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 4087 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 4088 if (!nd->nd_repstat) 4089 nd->nd_repstat = nfsvno_statfs(vp, sf); 4090 if (!nd->nd_repstat) 4091 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 4092 if (!nd->nd_repstat) { 4093 nfsvno_getfs(&fs, isdgram); 4094 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 4095 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 4096 if (!error) { 4097 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 4098 if (ret == 0) 4099 nd->nd_repstat = NFSERR_SAME; 4100 else if (ret != NFSERR_NOTSAME) 4101 nd->nd_repstat = ret; 4102 } else if (ret) 4103 nd->nd_repstat = ret; 4104 } 4105 } 4106 vput(vp); 4107 free(sf, M_STATFS); 4108 NFSEXITCODE2(error, nd); 4109 return (error); 4110 } 4111 4112 /* 4113 * nfs openattr rpc 4114 */ 4115 int 4116 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 4117 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 4118 __unused struct nfsexstuff *exp) 4119 { 4120 u_int32_t *tl; 4121 int error = 0, createdir __unused; 4122 4123 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4124 createdir = fxdr_unsigned(int, *tl); 4125 nd->nd_repstat = NFSERR_NOTSUPP; 4126 nfsmout: 4127 vrele(dp); 4128 NFSEXITCODE2(error, nd); 4129 return (error); 4130 } 4131 4132 /* 4133 * nfsv4 release lock owner service 4134 */ 4135 int 4136 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 4137 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4138 { 4139 u_int32_t *tl; 4140 struct nfsstate *stp = NULL; 4141 int error = 0, len; 4142 nfsquad_t clientid; 4143 struct thread *p = curthread; 4144 4145 if ((nd->nd_flag & ND_NFSV41) != 0) { 4146 nd->nd_repstat = NFSERR_NOTSUPP; 4147 goto nfsmout; 4148 } 4149 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4150 nd->nd_repstat = NFSERR_WRONGSEC; 4151 goto nfsmout; 4152 } 4153 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 4154 len = fxdr_unsigned(int, *(tl + 2)); 4155 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 4156 nd->nd_repstat = NFSERR_BADXDR; 4157 goto nfsmout; 4158 } 4159 stp = malloc(sizeof (struct nfsstate) + len, 4160 M_NFSDSTATE, M_WAITOK); 4161 stp->ls_ownerlen = len; 4162 stp->ls_op = NULL; 4163 stp->ls_flags = NFSLCK_RELEASE; 4164 stp->ls_uid = nd->nd_cred->cr_uid; 4165 clientid.lval[0] = *tl++; 4166 clientid.lval[1] = *tl; 4167 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 4168 if ((nd->nd_flag & ND_NFSV41) != 0) 4169 clientid.qval = nd->nd_clientid.qval; 4170 else if (nd->nd_clientid.qval != clientid.qval) 4171 printf("EEK14 multiple clids\n"); 4172 } else { 4173 if ((nd->nd_flag & ND_NFSV41) != 0) 4174 printf("EEK! no clientid from session\n"); 4175 nd->nd_flag |= ND_IMPLIEDCLID; 4176 nd->nd_clientid.qval = clientid.qval; 4177 } 4178 error = nfsrv_mtostr(nd, stp->ls_owner, len); 4179 if (error) 4180 goto nfsmout; 4181 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 4182 free(stp, M_NFSDSTATE); 4183 4184 NFSEXITCODE2(0, nd); 4185 return (0); 4186 nfsmout: 4187 if (stp) 4188 free(stp, M_NFSDSTATE); 4189 NFSEXITCODE2(error, nd); 4190 return (error); 4191 } 4192 4193 /* 4194 * nfsv4 exchange_id service 4195 */ 4196 int 4197 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 4198 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4199 { 4200 uint32_t *tl; 4201 int error = 0, i, idlen; 4202 struct nfsclient *clp = NULL; 4203 nfsquad_t clientid, confirm; 4204 uint8_t *verf; 4205 uint32_t sp4type, v41flags; 4206 uint64_t owner_minor; 4207 struct timespec verstime; 4208 #ifdef INET 4209 struct sockaddr_in *sin, *rin; 4210 #endif 4211 #ifdef INET6 4212 struct sockaddr_in6 *sin6, *rin6; 4213 #endif 4214 struct thread *p = curthread; 4215 4216 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4217 nd->nd_repstat = NFSERR_WRONGSEC; 4218 goto nfsmout; 4219 } 4220 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 4221 verf = (uint8_t *)tl; 4222 tl += (NFSX_VERF / NFSX_UNSIGNED); 4223 i = fxdr_unsigned(int, *tl); 4224 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 4225 nd->nd_repstat = NFSERR_BADXDR; 4226 goto nfsmout; 4227 } 4228 idlen = i; 4229 if (nd->nd_flag & ND_GSS) 4230 i += nd->nd_princlen; 4231 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 4232 M_ZERO); 4233 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 4234 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 4235 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 4236 /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 4237 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 4238 M_WAITOK | M_ZERO); 4239 switch (nd->nd_nam->sa_family) { 4240 #ifdef INET 4241 case AF_INET: 4242 rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4243 sin = (struct sockaddr_in *)nd->nd_nam; 4244 rin->sin_family = AF_INET; 4245 rin->sin_len = sizeof(struct sockaddr_in); 4246 rin->sin_port = 0; 4247 rin->sin_addr.s_addr = sin->sin_addr.s_addr; 4248 break; 4249 #endif 4250 #ifdef INET6 4251 case AF_INET6: 4252 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4253 sin6 = (struct sockaddr_in6 *)nd->nd_nam; 4254 rin6->sin6_family = AF_INET6; 4255 rin6->sin6_len = sizeof(struct sockaddr_in6); 4256 rin6->sin6_port = 0; 4257 rin6->sin6_addr = sin6->sin6_addr; 4258 break; 4259 #endif 4260 } 4261 clp->lc_req.nr_cred = NULL; 4262 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 4263 clp->lc_idlen = idlen; 4264 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 4265 if (error != 0) 4266 goto nfsmout; 4267 if ((nd->nd_flag & ND_GSS) != 0) { 4268 clp->lc_flags = LCL_GSS | LCL_NFSV41; 4269 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 4270 clp->lc_flags |= LCL_GSSINTEGRITY; 4271 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 4272 clp->lc_flags |= LCL_GSSPRIVACY; 4273 } else 4274 clp->lc_flags = LCL_NFSV41; 4275 if ((nd->nd_flag & ND_NFSV42) != 0) 4276 clp->lc_flags |= LCL_NFSV42; 4277 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 4278 clp->lc_flags |= LCL_NAME; 4279 clp->lc_namelen = nd->nd_princlen; 4280 clp->lc_name = &clp->lc_id[idlen]; 4281 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 4282 } else { 4283 clp->lc_uid = nd->nd_cred->cr_uid; 4284 clp->lc_gid = nd->nd_cred->cr_gid; 4285 } 4286 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4287 v41flags = fxdr_unsigned(uint32_t, *tl++); 4288 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 4289 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 4290 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 4291 nd->nd_repstat = NFSERR_INVAL; 4292 goto nfsmout; 4293 } 4294 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 4295 confirm.lval[1] = 1; 4296 else 4297 confirm.lval[1] = 0; 4298 if (nfsrv_devidcnt == 0) 4299 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS; 4300 else 4301 v41flags = NFSV4EXCH_USEPNFSMDS; 4302 sp4type = fxdr_unsigned(uint32_t, *tl); 4303 if (sp4type != NFSV4EXCH_SP4NONE) { 4304 nd->nd_repstat = NFSERR_NOTSUPP; 4305 goto nfsmout; 4306 } 4307 4308 /* 4309 * nfsrv_setclient() does the actual work of adding it to the 4310 * client list. If there is no error, the structure has been 4311 * linked into the client list and clp should no longer be used 4312 * here. When an error is returned, it has not been linked in, 4313 * so it should be free'd. 4314 */ 4315 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 4316 if (clp != NULL) { 4317 free(clp->lc_req.nr_nam, M_SONAME); 4318 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4319 free(clp->lc_stateid, M_NFSDCLIENT); 4320 free(clp, M_NFSDCLIENT); 4321 } 4322 if (nd->nd_repstat == 0) { 4323 if (confirm.lval[1] != 0) 4324 v41flags |= NFSV4EXCH_CONFIRMEDR; 4325 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 4326 *tl++ = clientid.lval[0]; /* ClientID */ 4327 *tl++ = clientid.lval[1]; 4328 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 4329 *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 4330 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 4331 owner_minor = 0; /* Owner */ 4332 txdr_hyper(owner_minor, tl); /* Minor */ 4333 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 4334 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 4335 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 4336 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */ 4337 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4338 *tl = txdr_unsigned(1); 4339 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4340 (void)nfsm_strtom(nd, version, strlen(version)); 4341 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4342 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4343 verstime.tv_nsec = 0; 4344 txdr_nfsv4time(&verstime, tl); 4345 } 4346 NFSEXITCODE2(0, nd); 4347 return (0); 4348 nfsmout: 4349 if (clp != NULL) { 4350 free(clp->lc_req.nr_nam, M_SONAME); 4351 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4352 free(clp->lc_stateid, M_NFSDCLIENT); 4353 free(clp, M_NFSDCLIENT); 4354 } 4355 NFSEXITCODE2(error, nd); 4356 return (error); 4357 } 4358 4359 /* 4360 * nfsv4 create session service 4361 */ 4362 int 4363 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 4364 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4365 { 4366 uint32_t *tl; 4367 int error = 0; 4368 nfsquad_t clientid, confirm; 4369 struct nfsdsession *sep = NULL; 4370 uint32_t rdmacnt; 4371 struct thread *p = curthread; 4372 4373 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4374 nd->nd_repstat = NFSERR_WRONGSEC; 4375 goto nfsmout; 4376 } 4377 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 4378 M_NFSDSESSION, M_WAITOK | M_ZERO); 4379 sep->sess_refcnt = 1; 4380 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 4381 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 4382 clientid.lval[0] = *tl++; 4383 clientid.lval[1] = *tl++; 4384 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 4385 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 4386 /* Persistent sessions and RDMA are not supported. */ 4387 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 4388 4389 /* Fore channel attributes. */ 4390 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4391 tl++; /* Header pad always 0. */ 4392 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 4393 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) { 4394 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR; 4395 printf("Consider increasing kern.ipc.maxsockbuf\n"); 4396 } 4397 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 4398 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) { 4399 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR; 4400 printf("Consider increasing kern.ipc.maxsockbuf\n"); 4401 } 4402 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 4403 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 4404 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 4405 if (sep->sess_maxslots > NFSV4_SLOTS) 4406 sep->sess_maxslots = NFSV4_SLOTS; 4407 rdmacnt = fxdr_unsigned(uint32_t, *tl); 4408 if (rdmacnt > 1) { 4409 nd->nd_repstat = NFSERR_BADXDR; 4410 goto nfsmout; 4411 } else if (rdmacnt == 1) 4412 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4413 4414 /* Back channel attributes. */ 4415 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4416 tl++; /* Header pad always 0. */ 4417 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 4418 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 4419 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 4420 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 4421 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 4422 rdmacnt = fxdr_unsigned(uint32_t, *tl); 4423 if (rdmacnt > 1) { 4424 nd->nd_repstat = NFSERR_BADXDR; 4425 goto nfsmout; 4426 } else if (rdmacnt == 1) 4427 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4428 4429 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4430 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 4431 4432 /* 4433 * nfsrv_getclient() searches the client list for a match and 4434 * returns the appropriate NFSERR status. 4435 */ 4436 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 4437 NULL, sep, confirm, sep->sess_cbprogram, nd, p); 4438 if (nd->nd_repstat == 0) { 4439 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4440 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 4441 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 4442 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 4443 *tl++ = txdr_unsigned(sep->sess_crflags); 4444 4445 /* Fore channel attributes. */ 4446 *tl++ = 0; 4447 *tl++ = txdr_unsigned(sep->sess_maxreq); 4448 *tl++ = txdr_unsigned(sep->sess_maxresp); 4449 *tl++ = txdr_unsigned(sep->sess_maxrespcached); 4450 *tl++ = txdr_unsigned(sep->sess_maxops); 4451 *tl++ = txdr_unsigned(sep->sess_maxslots); 4452 *tl++ = txdr_unsigned(1); 4453 *tl++ = txdr_unsigned(0); /* No RDMA. */ 4454 4455 /* Back channel attributes. */ 4456 *tl++ = 0; 4457 *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 4458 *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 4459 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 4460 *tl++ = txdr_unsigned(sep->sess_cbmaxops); 4461 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 4462 *tl++ = txdr_unsigned(1); 4463 *tl = txdr_unsigned(0); /* No RDMA. */ 4464 } 4465 nfsmout: 4466 if (nd->nd_repstat != 0 && sep != NULL) 4467 free(sep, M_NFSDSESSION); 4468 NFSEXITCODE2(error, nd); 4469 return (error); 4470 } 4471 4472 /* 4473 * nfsv4 sequence service 4474 */ 4475 int 4476 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 4477 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4478 { 4479 uint32_t *tl; 4480 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 4481 int cache_this, error = 0; 4482 struct thread *p = curthread; 4483 4484 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4485 nd->nd_repstat = NFSERR_WRONGSEC; 4486 goto nfsmout; 4487 } 4488 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 4489 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 4490 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4491 sequenceid = fxdr_unsigned(uint32_t, *tl++); 4492 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 4493 highest_slotid = fxdr_unsigned(uint32_t, *tl++); 4494 if (*tl == newnfs_true) 4495 cache_this = 1; 4496 else 4497 cache_this = 0; 4498 nd->nd_flag |= ND_HASSEQUENCE; 4499 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 4500 &target_highest_slotid, cache_this, &sflags, p); 4501 if (nd->nd_repstat == 0) { 4502 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4503 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 4504 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 4505 *tl++ = txdr_unsigned(sequenceid); 4506 *tl++ = txdr_unsigned(nd->nd_slotid); 4507 *tl++ = txdr_unsigned(highest_slotid); 4508 *tl++ = txdr_unsigned(target_highest_slotid); 4509 *tl = txdr_unsigned(sflags); 4510 } 4511 nfsmout: 4512 NFSEXITCODE2(error, nd); 4513 return (error); 4514 } 4515 4516 /* 4517 * nfsv4 reclaim complete service 4518 */ 4519 int 4520 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 4521 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4522 { 4523 uint32_t *tl; 4524 int error = 0, onefs; 4525 4526 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4527 /* 4528 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only 4529 * to be used after a file system has been transferred to a different 4530 * file server. However, RFC5661 is somewhat vague w.r.t. this and 4531 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs 4532 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE. 4533 * Therefore, just ignore the rca_one_fs == TRUE operation and return 4534 * NFS_OK without doing anything. 4535 */ 4536 onefs = 0; 4537 if (*tl == newnfs_true) 4538 onefs = 1; 4539 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs); 4540 nfsmout: 4541 NFSEXITCODE2(error, nd); 4542 return (error); 4543 } 4544 4545 /* 4546 * nfsv4 destroy clientid service 4547 */ 4548 int 4549 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4550 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4551 { 4552 uint32_t *tl; 4553 nfsquad_t clientid; 4554 int error = 0; 4555 struct thread *p = curthread; 4556 4557 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4558 nd->nd_repstat = NFSERR_WRONGSEC; 4559 goto nfsmout; 4560 } 4561 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4562 clientid.lval[0] = *tl++; 4563 clientid.lval[1] = *tl; 4564 nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4565 nfsmout: 4566 NFSEXITCODE2(error, nd); 4567 return (error); 4568 } 4569 4570 /* 4571 * nfsv4 bind connection to session service 4572 */ 4573 int 4574 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram, 4575 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4576 { 4577 uint32_t *tl; 4578 uint8_t sessid[NFSX_V4SESSIONID]; 4579 int error = 0, foreaft; 4580 4581 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4582 nd->nd_repstat = NFSERR_WRONGSEC; 4583 goto nfsmout; 4584 } 4585 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 4586 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID); 4587 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4588 foreaft = fxdr_unsigned(int, *tl++); 4589 if (*tl == newnfs_true) { 4590 /* RDMA is not supported. */ 4591 nd->nd_repstat = NFSERR_NOTSUPP; 4592 goto nfsmout; 4593 } 4594 4595 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft); 4596 if (nd->nd_repstat == 0) { 4597 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * 4598 NFSX_UNSIGNED); 4599 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID); 4600 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4601 *tl++ = txdr_unsigned(foreaft); 4602 *tl = newnfs_false; 4603 } 4604 nfsmout: 4605 NFSEXITCODE2(error, nd); 4606 return (error); 4607 } 4608 4609 /* 4610 * nfsv4 destroy session service 4611 */ 4612 int 4613 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4614 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4615 { 4616 uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4617 int error = 0; 4618 4619 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4620 nd->nd_repstat = NFSERR_WRONGSEC; 4621 goto nfsmout; 4622 } 4623 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4624 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4625 nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4626 nfsmout: 4627 NFSEXITCODE2(error, nd); 4628 return (error); 4629 } 4630 4631 /* 4632 * nfsv4 free stateid service 4633 */ 4634 int 4635 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4636 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4637 { 4638 uint32_t *tl; 4639 nfsv4stateid_t stateid; 4640 int error = 0; 4641 struct thread *p = curthread; 4642 4643 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4644 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4645 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4646 4647 /* 4648 * For the special stateid of other all 0s and seqid == 1, set the 4649 * stateid to the current stateid, if it is set. 4650 */ 4651 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4652 stateid.other[1] == 0 && stateid.other[2] == 0) { 4653 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4654 stateid = nd->nd_curstateid; 4655 stateid.seqid = 0; 4656 } else { 4657 nd->nd_repstat = NFSERR_BADSTATEID; 4658 goto nfsmout; 4659 } 4660 } 4661 4662 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 4663 4664 /* If the current stateid has been free'd, unset it. */ 4665 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 && 4666 stateid.other[0] == nd->nd_curstateid.other[0] && 4667 stateid.other[1] == nd->nd_curstateid.other[1] && 4668 stateid.other[2] == nd->nd_curstateid.other[2]) 4669 nd->nd_flag &= ~ND_CURSTATEID; 4670 nfsmout: 4671 NFSEXITCODE2(error, nd); 4672 return (error); 4673 } 4674 4675 /* 4676 * nfsv4 layoutget service 4677 */ 4678 int 4679 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram, 4680 vnode_t vp, struct nfsexstuff *exp) 4681 { 4682 uint32_t *tl; 4683 nfsv4stateid_t stateid; 4684 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose; 4685 uint64_t offset, len, minlen; 4686 char *layp; 4687 struct thread *p = curthread; 4688 4689 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 4690 NFSX_STATEID); 4691 tl++; /* Signal layout available. Ignore for now. */ 4692 layouttype = fxdr_unsigned(int, *tl++); 4693 iomode = fxdr_unsigned(int, *tl++); 4694 offset = fxdr_hyper(tl); tl += 2; 4695 len = fxdr_hyper(tl); tl += 2; 4696 minlen = fxdr_hyper(tl); tl += 2; 4697 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4698 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4699 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4700 maxcnt = fxdr_unsigned(int, *tl); 4701 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n", 4702 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len, 4703 (uintmax_t)minlen); 4704 if (len < minlen || 4705 (minlen != UINT64_MAX && offset + minlen < offset) || 4706 (len != UINT64_MAX && offset + len < offset)) { 4707 nd->nd_repstat = NFSERR_INVAL; 4708 goto nfsmout; 4709 } 4710 4711 /* 4712 * For the special stateid of other all 0s and seqid == 1, set the 4713 * stateid to the current stateid, if it is set. 4714 */ 4715 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4716 stateid.other[1] == 0 && stateid.other[2] == 0) { 4717 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4718 stateid = nd->nd_curstateid; 4719 stateid.seqid = 0; 4720 } else { 4721 nd->nd_repstat = NFSERR_BADSTATEID; 4722 goto nfsmout; 4723 } 4724 } 4725 4726 layp = NULL; 4727 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1) 4728 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK); 4729 else if (layouttype == NFSLAYOUT_FLEXFILE) 4730 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP, 4731 M_WAITOK); 4732 else 4733 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE; 4734 if (layp != NULL) 4735 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype, 4736 &iomode, &offset, &len, minlen, &stateid, maxcnt, 4737 &retonclose, &layoutlen, layp, nd->nd_cred, p); 4738 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat, 4739 layoutlen); 4740 if (nd->nd_repstat == 0) { 4741 /* For NFSv4.1, set the Current StateID. */ 4742 if ((nd->nd_flag & ND_NFSV41) != 0) { 4743 nd->nd_curstateid = stateid; 4744 nd->nd_flag |= ND_CURSTATEID; 4745 } 4746 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID + 4747 2 * NFSX_HYPER); 4748 *tl++ = txdr_unsigned(retonclose); 4749 *tl++ = txdr_unsigned(stateid.seqid); 4750 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 4751 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4752 *tl++ = txdr_unsigned(1); /* Only returns one layout. */ 4753 txdr_hyper(offset, tl); tl += 2; 4754 txdr_hyper(len, tl); tl += 2; 4755 *tl++ = txdr_unsigned(iomode); 4756 *tl = txdr_unsigned(layouttype); 4757 nfsm_strtom(nd, layp, layoutlen); 4758 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) { 4759 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4760 *tl = newnfs_false; 4761 } 4762 free(layp, M_TEMP); 4763 nfsmout: 4764 vput(vp); 4765 NFSEXITCODE2(error, nd); 4766 return (error); 4767 } 4768 4769 /* 4770 * nfsv4 layoutcommit service 4771 */ 4772 int 4773 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram, 4774 vnode_t vp, struct nfsexstuff *exp) 4775 { 4776 uint32_t *tl; 4777 nfsv4stateid_t stateid; 4778 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim; 4779 int hasnewsize; 4780 uint64_t offset, len, newoff = 0, newsize; 4781 struct timespec newmtime; 4782 char *layp; 4783 struct thread *p = curthread; 4784 4785 layp = NULL; 4786 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER + 4787 NFSX_STATEID); 4788 offset = fxdr_hyper(tl); tl += 2; 4789 len = fxdr_hyper(tl); tl += 2; 4790 reclaim = fxdr_unsigned(int, *tl++); 4791 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4792 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4793 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4794 /* 4795 * For the special stateid of other all 0s and seqid == 1, set the 4796 * stateid to the current stateid, if it is set. 4797 */ 4798 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4799 stateid.other[1] == 0 && stateid.other[2] == 0) { 4800 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4801 stateid = nd->nd_curstateid; 4802 stateid.seqid = 0; 4803 } else { 4804 nd->nd_repstat = NFSERR_BADSTATEID; 4805 goto nfsmout; 4806 } 4807 } 4808 4809 hasnewoff = fxdr_unsigned(int, *tl); 4810 if (hasnewoff != 0) { 4811 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 4812 newoff = fxdr_hyper(tl); tl += 2; 4813 } else 4814 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4815 hasnewmtime = fxdr_unsigned(int, *tl); 4816 if (hasnewmtime != 0) { 4817 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED); 4818 fxdr_nfsv4time(tl, &newmtime); 4819 tl += (NFSX_V4TIME / NFSX_UNSIGNED); 4820 } else 4821 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4822 layouttype = fxdr_unsigned(int, *tl++); 4823 maxcnt = fxdr_unsigned(int, *tl); 4824 if (maxcnt > 0) { 4825 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 4826 error = nfsrv_mtostr(nd, layp, maxcnt); 4827 if (error != 0) 4828 goto nfsmout; 4829 } 4830 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff, 4831 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid, 4832 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p); 4833 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat); 4834 if (nd->nd_repstat == 0) { 4835 if (hasnewsize != 0) { 4836 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 4837 *tl++ = newnfs_true; 4838 txdr_hyper(newsize, tl); 4839 } else { 4840 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4841 *tl = newnfs_false; 4842 } 4843 } 4844 nfsmout: 4845 free(layp, M_TEMP); 4846 vput(vp); 4847 NFSEXITCODE2(error, nd); 4848 return (error); 4849 } 4850 4851 /* 4852 * nfsv4 layoutreturn service 4853 */ 4854 int 4855 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram, 4856 vnode_t vp, struct nfsexstuff *exp) 4857 { 4858 uint32_t *tl, *layp; 4859 nfsv4stateid_t stateid; 4860 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim; 4861 uint64_t offset, len; 4862 struct thread *p = curthread; 4863 4864 layp = NULL; 4865 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4866 reclaim = *tl++; 4867 layouttype = fxdr_unsigned(int, *tl++); 4868 iomode = fxdr_unsigned(int, *tl++); 4869 kind = fxdr_unsigned(int, *tl); 4870 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim, 4871 layouttype, iomode, kind); 4872 if (kind == NFSV4LAYOUTRET_FILE) { 4873 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 4874 NFSX_UNSIGNED); 4875 offset = fxdr_hyper(tl); tl += 2; 4876 len = fxdr_hyper(tl); tl += 2; 4877 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4878 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4879 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4880 4881 /* 4882 * For the special stateid of other all 0s and seqid == 1, set 4883 * the stateid to the current stateid, if it is set. 4884 */ 4885 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4886 stateid.other[1] == 0 && stateid.other[2] == 0) { 4887 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4888 stateid = nd->nd_curstateid; 4889 stateid.seqid = 0; 4890 } else { 4891 nd->nd_repstat = NFSERR_BADSTATEID; 4892 goto nfsmout; 4893 } 4894 } 4895 4896 maxcnt = fxdr_unsigned(int, *tl); 4897 if (maxcnt > 0) { 4898 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 4899 error = nfsrv_mtostr(nd, (char *)layp, maxcnt); 4900 if (error != 0) 4901 goto nfsmout; 4902 } 4903 } else { 4904 if (reclaim == newnfs_true) { 4905 nd->nd_repstat = NFSERR_INVAL; 4906 goto nfsmout; 4907 } 4908 offset = len = 0; 4909 maxcnt = 0; 4910 } 4911 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode, 4912 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd, 4913 nd->nd_cred, p); 4914 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat, 4915 fnd); 4916 if (nd->nd_repstat == 0) { 4917 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4918 if (fnd != 0) { 4919 *tl = newnfs_true; 4920 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID); 4921 *tl++ = txdr_unsigned(stateid.seqid); 4922 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 4923 } else 4924 *tl = newnfs_false; 4925 } 4926 nfsmout: 4927 free(layp, M_TEMP); 4928 vput(vp); 4929 NFSEXITCODE2(error, nd); 4930 return (error); 4931 } 4932 4933 /* 4934 * nfsv4 layout error service 4935 */ 4936 int 4937 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram, 4938 vnode_t vp, struct nfsexstuff *exp) 4939 { 4940 uint32_t *tl; 4941 nfsv4stateid_t stateid; 4942 int cnt, error = 0, i, stat; 4943 int opnum __unused; 4944 char devid[NFSX_V4DEVICEID]; 4945 uint64_t offset, len; 4946 4947 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 4948 NFSX_UNSIGNED); 4949 offset = fxdr_hyper(tl); tl += 2; 4950 len = fxdr_hyper(tl); tl += 2; 4951 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4952 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4953 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4954 cnt = fxdr_unsigned(int, *tl); 4955 NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset, 4956 (uintmax_t)len, cnt); 4957 /* 4958 * For the special stateid of other all 0s and seqid == 1, set 4959 * the stateid to the current stateid, if it is set. 4960 */ 4961 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4962 stateid.other[1] == 0 && stateid.other[2] == 0) { 4963 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4964 stateid = nd->nd_curstateid; 4965 stateid.seqid = 0; 4966 } else { 4967 nd->nd_repstat = NFSERR_BADSTATEID; 4968 goto nfsmout; 4969 } 4970 } 4971 4972 /* 4973 * Ignore offset, len and stateid for now. 4974 */ 4975 for (i = 0; i < cnt; i++) { 4976 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 * 4977 NFSX_UNSIGNED); 4978 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 4979 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 4980 stat = fxdr_unsigned(int, *tl++); 4981 opnum = fxdr_unsigned(int, *tl); 4982 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat); 4983 /* 4984 * Except for NFSERR_ACCES and NFSERR_STALE errors, 4985 * disable the mirror. 4986 */ 4987 if (stat != NFSERR_ACCES && stat != NFSERR_STALE) 4988 nfsrv_delds(devid, curthread); 4989 } 4990 nfsmout: 4991 vput(vp); 4992 NFSEXITCODE2(error, nd); 4993 return (error); 4994 } 4995 4996 /* 4997 * nfsv4 layout stats service 4998 */ 4999 int 5000 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram, 5001 vnode_t vp, struct nfsexstuff *exp) 5002 { 5003 uint32_t *tl; 5004 nfsv4stateid_t stateid; 5005 int cnt, error = 0; 5006 int layouttype __unused; 5007 char devid[NFSX_V4DEVICEID] __unused; 5008 uint64_t offset, len, readcount, readbytes, writecount, writebytes 5009 __unused; 5010 5011 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID + 5012 NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED); 5013 offset = fxdr_hyper(tl); tl += 2; 5014 len = fxdr_hyper(tl); tl += 2; 5015 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5016 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5017 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5018 readcount = fxdr_hyper(tl); tl += 2; 5019 readbytes = fxdr_hyper(tl); tl += 2; 5020 writecount = fxdr_hyper(tl); tl += 2; 5021 writebytes = fxdr_hyper(tl); tl += 2; 5022 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5023 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5024 layouttype = fxdr_unsigned(int, *tl++); 5025 cnt = fxdr_unsigned(int, *tl); 5026 error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1); 5027 if (error != 0) 5028 goto nfsmout; 5029 NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt); 5030 /* 5031 * For the special stateid of other all 0s and seqid == 1, set 5032 * the stateid to the current stateid, if it is set. 5033 */ 5034 if (stateid.seqid == 1 && stateid.other[0] == 0 && 5035 stateid.other[1] == 0 && stateid.other[2] == 0) { 5036 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5037 stateid = nd->nd_curstateid; 5038 stateid.seqid = 0; 5039 } else { 5040 nd->nd_repstat = NFSERR_BADSTATEID; 5041 goto nfsmout; 5042 } 5043 } 5044 5045 /* 5046 * No use for the stats for now. 5047 */ 5048 nfsmout: 5049 vput(vp); 5050 NFSEXITCODE2(error, nd); 5051 return (error); 5052 } 5053 5054 /* 5055 * nfsv4 io_advise service 5056 */ 5057 int 5058 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram, 5059 vnode_t vp, struct nfsexstuff *exp) 5060 { 5061 uint32_t *tl; 5062 nfsv4stateid_t stateid; 5063 nfsattrbit_t hints; 5064 int error = 0, ret; 5065 off_t offset, len; 5066 5067 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5068 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5069 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 5070 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 5071 offset = fxdr_hyper(tl); tl += 2; 5072 len = fxdr_hyper(tl); 5073 error = nfsrv_getattrbits(nd, &hints, NULL, NULL); 5074 if (error != 0) 5075 goto nfsmout; 5076 /* 5077 * For the special stateid of other all 0s and seqid == 1, set 5078 * the stateid to the current stateid, if it is set. 5079 */ 5080 if (stateid.seqid == 1 && stateid.other[0] == 0 && 5081 stateid.other[1] == 0 && stateid.other[2] == 0) { 5082 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 5083 stateid = nd->nd_curstateid; 5084 stateid.seqid = 0; 5085 } else { 5086 nd->nd_repstat = NFSERR_BADSTATEID; 5087 goto nfsmout; 5088 } 5089 } 5090 5091 if (offset < 0) { 5092 nd->nd_repstat = NFSERR_INVAL; 5093 goto nfsmout; 5094 } 5095 if (len < 0) 5096 len = 0; 5097 if (vp->v_type != VREG) { 5098 if (vp->v_type == VDIR) 5099 nd->nd_repstat = NFSERR_ISDIR; 5100 else 5101 nd->nd_repstat = NFSERR_WRONGTYPE; 5102 goto nfsmout; 5103 } 5104 5105 /* 5106 * For now, we can only handle WILLNEED and DONTNEED and don't use 5107 * the stateid. 5108 */ 5109 if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) && 5110 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) || 5111 (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) && 5112 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) { 5113 NFSVOPUNLOCK(vp); 5114 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) { 5115 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED); 5116 NFSZERO_ATTRBIT(&hints); 5117 if (ret == 0) 5118 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 5119 else 5120 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5121 } else { 5122 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED); 5123 NFSZERO_ATTRBIT(&hints); 5124 if (ret == 0) 5125 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 5126 else 5127 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5128 } 5129 vrele(vp); 5130 } else { 5131 NFSZERO_ATTRBIT(&hints); 5132 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5133 vput(vp); 5134 } 5135 nfsrv_putattrbit(nd, &hints); 5136 NFSEXITCODE2(error, nd); 5137 return (error); 5138 nfsmout: 5139 vput(vp); 5140 NFSEXITCODE2(error, nd); 5141 return (error); 5142 } 5143 5144 /* 5145 * nfsv4 getdeviceinfo service 5146 */ 5147 int 5148 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram, 5149 __unused vnode_t vp, __unused struct nfsexstuff *exp) 5150 { 5151 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP]; 5152 int cnt, devaddrlen, error = 0, i, layouttype; 5153 char devid[NFSX_V4DEVICEID], *devaddr; 5154 time_t dev_time; 5155 5156 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID); 5157 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5158 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5159 layouttype = fxdr_unsigned(int, *tl++); 5160 maxcnt = fxdr_unsigned(uint32_t, *tl++); 5161 cnt = fxdr_unsigned(int, *tl); 5162 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype, 5163 maxcnt, cnt); 5164 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) { 5165 nd->nd_repstat = NFSERR_INVAL; 5166 goto nfsmout; 5167 } 5168 if (cnt > 0) { 5169 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED); 5170 for (i = 0; i < cnt; i++) 5171 notify[i] = fxdr_unsigned(uint32_t, *tl++); 5172 } 5173 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++) 5174 notify[i] = 0; 5175 5176 /* 5177 * Check that the device id is not stale. Device ids are recreated 5178 * each time the nfsd threads are restarted. 5179 */ 5180 NFSBCOPY(devid, &dev_time, sizeof(dev_time)); 5181 if (dev_time != nfsdev_time) { 5182 nd->nd_repstat = NFSERR_NOENT; 5183 goto nfsmout; 5184 } 5185 5186 /* Look for the device id. */ 5187 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt, 5188 notify, &devaddrlen, &devaddr); 5189 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat); 5190 if (nd->nd_repstat == 0) { 5191 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5192 *tl = txdr_unsigned(layouttype); 5193 nfsm_strtom(nd, devaddr, devaddrlen); 5194 cnt = 0; 5195 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) { 5196 if (notify[i] != 0) 5197 cnt = i + 1; 5198 } 5199 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED); 5200 *tl++ = txdr_unsigned(cnt); 5201 for (i = 0; i < cnt; i++) 5202 *tl++ = txdr_unsigned(notify[i]); 5203 } else if (nd->nd_repstat == NFSERR_TOOSMALL) { 5204 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5205 *tl = txdr_unsigned(maxcnt); 5206 } 5207 nfsmout: 5208 NFSEXITCODE2(error, nd); 5209 return (error); 5210 } 5211 5212 /* 5213 * nfsv4 test stateid service 5214 */ 5215 int 5216 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, 5217 __unused vnode_t vp, __unused struct nfsexstuff *exp) 5218 { 5219 uint32_t *tl; 5220 nfsv4stateid_t *stateidp = NULL, *tstateidp; 5221 int cnt, error = 0, i, ret; 5222 struct thread *p = curthread; 5223 5224 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5225 cnt = fxdr_unsigned(int, *tl); 5226 if (cnt <= 0 || cnt > 1024) { 5227 nd->nd_repstat = NFSERR_BADXDR; 5228 goto nfsmout; 5229 } 5230 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); 5231 tstateidp = stateidp; 5232 for (i = 0; i < cnt; i++) { 5233 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5234 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5235 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); 5236 tstateidp++; 5237 } 5238 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5239 *tl = txdr_unsigned(cnt); 5240 tstateidp = stateidp; 5241 for (i = 0; i < cnt; i++) { 5242 ret = nfsrv_teststateid(nd, tstateidp, p); 5243 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5244 *tl = txdr_unsigned(ret); 5245 tstateidp++; 5246 } 5247 nfsmout: 5248 free(stateidp, M_TEMP); 5249 NFSEXITCODE2(error, nd); 5250 return (error); 5251 } 5252 5253 /* 5254 * nfs allocate service 5255 */ 5256 int 5257 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram, 5258 vnode_t vp, struct nfsexstuff *exp) 5259 { 5260 uint32_t *tl; 5261 struct nfsvattr forat; 5262 int error = 0, forat_ret = 1, gotproxystateid; 5263 off_t off, len; 5264 struct nfsstate st, *stp = &st; 5265 struct nfslock lo, *lop = &lo; 5266 nfsv4stateid_t stateid; 5267 nfsquad_t clientid; 5268 nfsattrbit_t attrbits; 5269 5270 gotproxystateid = 0; 5271 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5272 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5273 lop->lo_flags = NFSLCK_WRITE; 5274 stp->ls_ownerlen = 0; 5275 stp->ls_op = NULL; 5276 stp->ls_uid = nd->nd_cred->cr_uid; 5277 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 5278 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 5279 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 5280 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 5281 if ((nd->nd_flag & ND_NFSV41) != 0) 5282 clientid.qval = nd->nd_clientid.qval; 5283 else if (nd->nd_clientid.qval != clientid.qval) 5284 printf("EEK2 multiple clids\n"); 5285 } else { 5286 if ((nd->nd_flag & ND_NFSV41) != 0) 5287 printf("EEK! no clientid from session\n"); 5288 nd->nd_flag |= ND_IMPLIEDCLID; 5289 nd->nd_clientid.qval = clientid.qval; 5290 } 5291 stp->ls_stateid.other[2] = *tl++; 5292 /* 5293 * Don't allow this to be done for a DS. 5294 */ 5295 if ((nd->nd_flag & ND_DSSERVER) != 0) 5296 nd->nd_repstat = NFSERR_NOTSUPP; 5297 /* However, allow the proxy stateid. */ 5298 if (stp->ls_stateid.seqid == 0xffffffff && 5299 stp->ls_stateid.other[0] == 0x55555555 && 5300 stp->ls_stateid.other[1] == 0x55555555 && 5301 stp->ls_stateid.other[2] == 0x55555555) 5302 gotproxystateid = 1; 5303 off = fxdr_hyper(tl); tl += 2; 5304 lop->lo_first = off; 5305 len = fxdr_hyper(tl); 5306 lop->lo_end = off + len; 5307 /* 5308 * Paranoia, just in case it wraps around, which shouldn't 5309 * ever happen anyhow. 5310 */ 5311 if (nd->nd_repstat == 0 && (lop->lo_end < lop->lo_first || len <= 0)) 5312 nd->nd_repstat = NFSERR_INVAL; 5313 5314 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5315 nd->nd_repstat = NFSERR_WRONGTYPE; 5316 NFSZERO_ATTRBIT(&attrbits); 5317 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5318 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); 5319 if (nd->nd_repstat == 0) 5320 nd->nd_repstat = forat_ret; 5321 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || 5322 NFSVNO_EXSTRICTACCESS(exp))) 5323 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, 5324 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5325 NULL); 5326 if (nd->nd_repstat == 0 && gotproxystateid == 0) 5327 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 5328 &stateid, exp, nd, curthread); 5329 5330 if (nd->nd_repstat == 0) 5331 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred, 5332 curthread); 5333 vput(vp); 5334 NFSEXITCODE2(0, nd); 5335 return (0); 5336 nfsmout: 5337 vput(vp); 5338 NFSEXITCODE2(error, nd); 5339 return (error); 5340 } 5341 5342 /* 5343 * nfs copy service 5344 */ 5345 int 5346 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram, 5347 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 5348 { 5349 uint32_t *tl; 5350 struct nfsvattr at; 5351 int cnt, error = 0, ret; 5352 off_t inoff, outoff; 5353 uint64_t len; 5354 size_t xfer; 5355 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst; 5356 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo; 5357 nfsquad_t clientid; 5358 nfsv4stateid_t stateid; 5359 nfsattrbit_t attrbits; 5360 void *rl_rcookie, *rl_wcookie; 5361 5362 rl_rcookie = rl_wcookie = NULL; 5363 if (nfsrv_devidcnt > 0) { 5364 /* 5365 * For a pNFS server, reply NFSERR_NOTSUPP so that the client 5366 * will do the copy via I/O on the DS(s). 5367 */ 5368 nd->nd_repstat = NFSERR_NOTSUPP; 5369 goto nfsmout; 5370 } 5371 if (vp == tovp) { 5372 /* Copying a byte range within the same file is not allowed. */ 5373 nd->nd_repstat = NFSERR_INVAL; 5374 goto nfsmout; 5375 } 5376 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER + 5377 3 * NFSX_UNSIGNED); 5378 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 5379 inlop->lo_flags = NFSLCK_READ; 5380 instp->ls_ownerlen = 0; 5381 instp->ls_op = NULL; 5382 instp->ls_uid = nd->nd_cred->cr_uid; 5383 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5384 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++; 5385 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++; 5386 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) 5387 clientid.qval = nd->nd_clientid.qval; 5388 instp->ls_stateid.other[2] = *tl++; 5389 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5390 outlop->lo_flags = NFSLCK_WRITE; 5391 outstp->ls_ownerlen = 0; 5392 outstp->ls_op = NULL; 5393 outstp->ls_uid = nd->nd_cred->cr_uid; 5394 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5395 outstp->ls_stateid.other[0] = *tl++; 5396 outstp->ls_stateid.other[1] = *tl++; 5397 outstp->ls_stateid.other[2] = *tl++; 5398 inoff = fxdr_hyper(tl); tl += 2; 5399 inlop->lo_first = inoff; 5400 outoff = fxdr_hyper(tl); tl += 2; 5401 outlop->lo_first = outoff; 5402 len = fxdr_hyper(tl); tl += 2; 5403 if (len == 0) { 5404 /* len == 0 means to EOF. */ 5405 inlop->lo_end = OFF_MAX; 5406 outlop->lo_end = OFF_MAX; 5407 } else { 5408 inlop->lo_end = inlop->lo_first + len; 5409 outlop->lo_end = outlop->lo_first + len; 5410 } 5411 5412 /* 5413 * At this time only consecutive, synchronous copy is supported, 5414 * so ca_consecutive and ca_synchronous can be ignored. 5415 */ 5416 tl += 2; 5417 5418 cnt = fxdr_unsigned(int, *tl); 5419 if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0) 5420 nd->nd_repstat = NFSERR_NOTSUPP; 5421 if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX || 5422 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX || 5423 inlop->lo_end < inlop->lo_first || outlop->lo_end < 5424 outlop->lo_first)) 5425 nd->nd_repstat = NFSERR_INVAL; 5426 5427 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5428 nd->nd_repstat = NFSERR_WRONGTYPE; 5429 5430 /* Check permissions for the input file. */ 5431 NFSZERO_ATTRBIT(&attrbits); 5432 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5433 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits); 5434 if (nd->nd_repstat == 0) 5435 nd->nd_repstat = ret; 5436 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5437 NFSVNO_EXSTRICTACCESS(exp))) 5438 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5439 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5440 NULL); 5441 if (nd->nd_repstat == 0) 5442 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL, 5443 clientid, &stateid, exp, nd, curthread); 5444 NFSVOPUNLOCK(vp); 5445 if (nd->nd_repstat != 0) 5446 goto out; 5447 5448 error = NFSVOPLOCK(tovp, LK_SHARED); 5449 if (error != 0) 5450 goto out; 5451 if (vnode_vtype(tovp) != VREG) 5452 nd->nd_repstat = NFSERR_WRONGTYPE; 5453 5454 /* For the output file, we only need the Owner attribute. */ 5455 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits); 5456 if (nd->nd_repstat == 0) 5457 nd->nd_repstat = ret; 5458 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5459 NFSVNO_EXSTRICTACCESS(exp))) 5460 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp, 5461 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5462 NULL); 5463 if (nd->nd_repstat == 0) 5464 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL, 5465 clientid, &stateid, toexp, nd, curthread); 5466 NFSVOPUNLOCK(tovp); 5467 5468 /* Range lock the byte ranges for both invp and outvp. */ 5469 if (nd->nd_repstat == 0) { 5470 for (;;) { 5471 if (len == 0) { 5472 rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5473 OFF_MAX); 5474 rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5475 OFF_MAX); 5476 } else { 5477 rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5478 outoff + len); 5479 rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5480 inoff + len); 5481 } 5482 if (rl_rcookie != NULL) 5483 break; 5484 vn_rangelock_unlock(tovp, rl_wcookie); 5485 if (len == 0) 5486 rl_rcookie = vn_rangelock_rlock(vp, inoff, 5487 OFF_MAX); 5488 else 5489 rl_rcookie = vn_rangelock_rlock(vp, inoff, 5490 inoff + len); 5491 vn_rangelock_unlock(vp, rl_rcookie); 5492 } 5493 5494 error = NFSVOPLOCK(vp, LK_SHARED); 5495 if (error == 0) { 5496 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL); 5497 if (ret == 0) { 5498 /* 5499 * Since invp is range locked, na_size should 5500 * not change. 5501 */ 5502 if (len == 0 && at.na_size > inoff) { 5503 /* 5504 * If len == 0, set it based on invp's 5505 * size. If offset is past EOF, just 5506 * leave len == 0. 5507 */ 5508 len = at.na_size - inoff; 5509 } else if (nfsrv_linux42server == 0 && 5510 inoff + len > at.na_size) { 5511 /* 5512 * RFC-7862 says that NFSERR_INVAL must 5513 * be returned when inoff + len exceeds 5514 * the file size, however the NFSv4.2 5515 * Linux client likes to do this, so 5516 * only check if nfsrv_linux42server 5517 * is not set. 5518 */ 5519 nd->nd_repstat = NFSERR_INVAL; 5520 } 5521 } 5522 NFSVOPUNLOCK(vp); 5523 if (ret != 0 && nd->nd_repstat == 0) 5524 nd->nd_repstat = ret; 5525 } else if (nd->nd_repstat == 0) 5526 nd->nd_repstat = error; 5527 } 5528 5529 /* 5530 * Do the actual copy to an upper limit of vfs.nfs.maxcopyrange. 5531 * This limit is applied to ensure that the RPC replies in a 5532 * reasonable time. 5533 */ 5534 if (len > nfs_maxcopyrange) 5535 xfer = nfs_maxcopyrange; 5536 else 5537 xfer = len; 5538 if (nd->nd_repstat == 0) { 5539 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff, 5540 &xfer, 0, nd->nd_cred, nd->nd_cred, NULL); 5541 if (nd->nd_repstat == 0) 5542 len = xfer; 5543 } 5544 5545 /* Unlock the ranges. */ 5546 if (rl_rcookie != NULL) 5547 vn_rangelock_unlock(vp, rl_rcookie); 5548 if (rl_wcookie != NULL) 5549 vn_rangelock_unlock(tovp, rl_wcookie); 5550 5551 if (nd->nd_repstat == 0) { 5552 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER + 5553 NFSX_VERF); 5554 *tl++ = txdr_unsigned(0); /* No callback ids. */ 5555 txdr_hyper(len, tl); tl += 2; 5556 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE); 5557 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 5558 *tl++ = txdr_unsigned(nfsboottime.tv_usec); 5559 *tl++ = newnfs_true; 5560 *tl = newnfs_true; 5561 } 5562 out: 5563 vrele(vp); 5564 vrele(tovp); 5565 NFSEXITCODE2(error, nd); 5566 return (error); 5567 nfsmout: 5568 vput(vp); 5569 vrele(tovp); 5570 NFSEXITCODE2(error, nd); 5571 return (error); 5572 } 5573 5574 /* 5575 * nfs seek service 5576 */ 5577 int 5578 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram, 5579 vnode_t vp, struct nfsexstuff *exp) 5580 { 5581 uint32_t *tl; 5582 struct nfsvattr at; 5583 int content, error = 0; 5584 off_t off; 5585 u_long cmd; 5586 nfsattrbit_t attrbits; 5587 bool eof; 5588 5589 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED); 5590 /* Ignore the stateid for now. */ 5591 tl += (NFSX_STATEID / NFSX_UNSIGNED); 5592 off = fxdr_hyper(tl); tl += 2; 5593 content = fxdr_unsigned(int, *tl); 5594 if (content == NFSV4CONTENT_DATA) 5595 cmd = FIOSEEKDATA; 5596 else if (content == NFSV4CONTENT_HOLE) 5597 cmd = FIOSEEKHOLE; 5598 else 5599 nd->nd_repstat = NFSERR_BADXDR; 5600 if (nd->nd_repstat == 0 && vnode_vtype(vp) == VDIR) 5601 nd->nd_repstat = NFSERR_ISDIR; 5602 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5603 nd->nd_repstat = NFSERR_WRONGTYPE; 5604 if (nd->nd_repstat == 0 && off < 0) 5605 nd->nd_repstat = NFSERR_NXIO; 5606 if (nd->nd_repstat == 0) { 5607 /* Check permissions for the input file. */ 5608 NFSZERO_ATTRBIT(&attrbits); 5609 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5610 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1, 5611 &attrbits); 5612 } 5613 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5614 NFSVNO_EXSTRICTACCESS(exp))) 5615 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5616 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5617 NULL); 5618 if (nd->nd_repstat != 0) 5619 goto nfsmout; 5620 5621 /* nfsvno_seek() unlocks and vrele()s the vp. */ 5622 nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof, 5623 nd->nd_cred, curthread); 5624 if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA && 5625 nfsrv_linux42server != 0) 5626 nd->nd_repstat = NFSERR_NXIO; 5627 if (nd->nd_repstat == 0) { 5628 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 5629 if (eof) 5630 *tl++ = newnfs_true; 5631 else 5632 *tl++ = newnfs_false; 5633 txdr_hyper(off, tl); 5634 } 5635 NFSEXITCODE2(error, nd); 5636 return (error); 5637 nfsmout: 5638 vput(vp); 5639 NFSEXITCODE2(error, nd); 5640 return (error); 5641 } 5642 5643 /* 5644 * nfs get extended attribute service 5645 */ 5646 int 5647 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram, 5648 vnode_t vp, __unused struct nfsexstuff *exp) 5649 { 5650 uint32_t *tl; 5651 struct mbuf *mp = NULL, *mpend = NULL; 5652 int error, len; 5653 char *name; 5654 struct thread *p = curthread; 5655 uint16_t off; 5656 5657 error = 0; 5658 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5659 len = fxdr_unsigned(int, *tl); 5660 if (len <= 0) { 5661 nd->nd_repstat = NFSERR_BADXDR; 5662 goto nfsmout; 5663 } 5664 if (len > EXTATTR_MAXNAMELEN) { 5665 nd->nd_repstat = NFSERR_NOXATTR; 5666 goto nfsmout; 5667 } 5668 name = malloc(len + 1, M_TEMP, M_WAITOK); 5669 nd->nd_repstat = nfsrv_mtostr(nd, name, len); 5670 if (nd->nd_repstat == 0) 5671 nd->nd_repstat = nfsvno_getxattr(vp, name, 5672 nd->nd_maxresp, nd->nd_cred, nd->nd_flag, 5673 nd->nd_maxextsiz, p, &mp, &mpend, &len); 5674 if (nd->nd_repstat == ENOATTR) 5675 nd->nd_repstat = NFSERR_NOXATTR; 5676 else if (nd->nd_repstat == EOPNOTSUPP) 5677 nd->nd_repstat = NFSERR_NOTSUPP; 5678 if (nd->nd_repstat == 0) { 5679 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5680 *tl = txdr_unsigned(len); 5681 if (len > 0) { 5682 nd->nd_mb->m_next = mp; 5683 nd->nd_mb = mpend; 5684 if ((mpend->m_flags & M_EXTPG) != 0) { 5685 nd->nd_flag |= ND_EXTPG; 5686 nd->nd_bextpg = mpend->m_epg_npgs - 1; 5687 nd->nd_bpos = (char *)(void *) 5688 PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]); 5689 off = (nd->nd_bextpg == 0) ? 5690 mpend->m_epg_1st_off : 0; 5691 nd->nd_bpos += off + mpend->m_epg_last_len; 5692 nd->nd_bextpgsiz = PAGE_SIZE - 5693 mpend->m_epg_last_len - off; 5694 } else 5695 nd->nd_bpos = mtod(mpend, char *) + 5696 mpend->m_len; 5697 } 5698 } 5699 free(name, M_TEMP); 5700 5701 nfsmout: 5702 if (nd->nd_repstat == 0) 5703 nd->nd_repstat = error; 5704 vput(vp); 5705 NFSEXITCODE2(0, nd); 5706 return (0); 5707 } 5708 5709 /* 5710 * nfs set extended attribute service 5711 */ 5712 int 5713 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram, 5714 vnode_t vp, __unused struct nfsexstuff *exp) 5715 { 5716 uint32_t *tl; 5717 struct nfsvattr ova, nva; 5718 nfsattrbit_t attrbits; 5719 int error, len, opt; 5720 char *name; 5721 size_t siz; 5722 struct thread *p = curthread; 5723 5724 error = 0; 5725 name = NULL; 5726 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5727 opt = fxdr_unsigned(int, *tl++); 5728 len = fxdr_unsigned(int, *tl); 5729 if (len <= 0) { 5730 nd->nd_repstat = NFSERR_BADXDR; 5731 goto nfsmout; 5732 } 5733 if (len > EXTATTR_MAXNAMELEN) { 5734 nd->nd_repstat = NFSERR_NOXATTR; 5735 goto nfsmout; 5736 } 5737 name = malloc(len + 1, M_TEMP, M_WAITOK); 5738 error = nfsrv_mtostr(nd, name, len); 5739 if (error != 0) 5740 goto nfsmout; 5741 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5742 len = fxdr_unsigned(int, *tl); 5743 if (len < 0 || len > IOSIZE_MAX) { 5744 nd->nd_repstat = NFSERR_XATTR2BIG; 5745 goto nfsmout; 5746 } 5747 switch (opt) { 5748 case NFSV4SXATTR_CREATE: 5749 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 5750 &siz, nd->nd_cred, p); 5751 if (error != ENOATTR) 5752 nd->nd_repstat = NFSERR_EXIST; 5753 error = 0; 5754 break; 5755 case NFSV4SXATTR_REPLACE: 5756 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 5757 &siz, nd->nd_cred, p); 5758 if (error != 0) 5759 nd->nd_repstat = NFSERR_NOXATTR; 5760 break; 5761 case NFSV4SXATTR_EITHER: 5762 break; 5763 default: 5764 nd->nd_repstat = NFSERR_BADXDR; 5765 } 5766 if (nd->nd_repstat != 0) 5767 goto nfsmout; 5768 5769 /* Now, do the Set Extended attribute, with Change before and after. */ 5770 NFSZERO_ATTRBIT(&attrbits); 5771 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 5772 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 5773 if (nd->nd_repstat == 0) { 5774 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md, 5775 nd->nd_dpos, nd->nd_cred, p); 5776 if (nd->nd_repstat == ENXIO) 5777 nd->nd_repstat = NFSERR_XATTR2BIG; 5778 } 5779 if (nd->nd_repstat == 0 && len > 0) 5780 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1); 5781 if (nd->nd_repstat == 0) 5782 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 5783 if (nd->nd_repstat == 0) { 5784 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 5785 *tl++ = newnfs_true; 5786 txdr_hyper(ova.na_filerev, tl); tl += 2; 5787 txdr_hyper(nva.na_filerev, tl); 5788 } 5789 5790 nfsmout: 5791 free(name, M_TEMP); 5792 if (nd->nd_repstat == 0) 5793 nd->nd_repstat = error; 5794 vput(vp); 5795 NFSEXITCODE2(0, nd); 5796 return (0); 5797 } 5798 5799 /* 5800 * nfs remove extended attribute service 5801 */ 5802 int 5803 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram, 5804 vnode_t vp, __unused struct nfsexstuff *exp) 5805 { 5806 uint32_t *tl; 5807 struct nfsvattr ova, nva; 5808 nfsattrbit_t attrbits; 5809 int error, len; 5810 char *name; 5811 struct thread *p = curthread; 5812 5813 error = 0; 5814 name = NULL; 5815 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5816 len = fxdr_unsigned(int, *tl); 5817 if (len <= 0) { 5818 nd->nd_repstat = NFSERR_BADXDR; 5819 goto nfsmout; 5820 } 5821 if (len > EXTATTR_MAXNAMELEN) { 5822 nd->nd_repstat = NFSERR_NOXATTR; 5823 goto nfsmout; 5824 } 5825 name = malloc(len + 1, M_TEMP, M_WAITOK); 5826 error = nfsrv_mtostr(nd, name, len); 5827 if (error != 0) 5828 goto nfsmout; 5829 5830 if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) { 5831 printf("EEK! nfsrvd_rmxattr: no implied clientid\n"); 5832 error = NFSERR_NOXATTR; 5833 goto nfsmout; 5834 } 5835 /* 5836 * Now, do the Remove Extended attribute, with Change before and 5837 * after. 5838 */ 5839 NFSZERO_ATTRBIT(&attrbits); 5840 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 5841 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 5842 if (nd->nd_repstat == 0) { 5843 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p); 5844 if (nd->nd_repstat == ENOATTR) 5845 nd->nd_repstat = NFSERR_NOXATTR; 5846 } 5847 if (nd->nd_repstat == 0) 5848 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 5849 if (nd->nd_repstat == 0) { 5850 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 5851 *tl++ = newnfs_true; 5852 txdr_hyper(ova.na_filerev, tl); tl += 2; 5853 txdr_hyper(nva.na_filerev, tl); 5854 } 5855 5856 nfsmout: 5857 free(name, M_TEMP); 5858 if (nd->nd_repstat == 0) 5859 nd->nd_repstat = error; 5860 vput(vp); 5861 NFSEXITCODE2(0, nd); 5862 return (0); 5863 } 5864 5865 /* 5866 * nfs list extended attribute service 5867 */ 5868 int 5869 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram, 5870 vnode_t vp, __unused struct nfsexstuff *exp) 5871 { 5872 uint32_t cnt, *tl, len, len2, i, pos, retlen; 5873 int error; 5874 uint64_t cookie, cookie2; 5875 u_char *buf; 5876 bool eof; 5877 struct thread *p = curthread; 5878 5879 error = 0; 5880 buf = NULL; 5881 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 5882 /* 5883 * The cookie doesn't need to be in net byte order, but FreeBSD 5884 * does so to make it more readable in packet traces. 5885 */ 5886 cookie = fxdr_hyper(tl); tl += 2; 5887 len = fxdr_unsigned(uint32_t, *tl); 5888 if (len == 0 || cookie >= IOSIZE_MAX) { 5889 nd->nd_repstat = NFSERR_BADXDR; 5890 goto nfsmout; 5891 } 5892 if (len > nd->nd_maxresp - NFS_MAXXDR) 5893 len = nd->nd_maxresp - NFS_MAXXDR; 5894 len2 = len; 5895 nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf, 5896 &len, &eof); 5897 if (nd->nd_repstat == EOPNOTSUPP) 5898 nd->nd_repstat = NFSERR_NOTSUPP; 5899 if (nd->nd_repstat == 0) { 5900 cookie2 = cookie + len; 5901 if (cookie2 < cookie) 5902 nd->nd_repstat = NFSERR_BADXDR; 5903 } 5904 if (nd->nd_repstat == 0) { 5905 /* Now copy the entries out. */ 5906 retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED; 5907 if (len == 0 && retlen <= len2) { 5908 /* The cookie was at eof. */ 5909 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * 5910 NFSX_UNSIGNED); 5911 txdr_hyper(cookie2, tl); tl += 2; 5912 *tl++ = txdr_unsigned(0); 5913 *tl = newnfs_true; 5914 goto nfsmout; 5915 } 5916 5917 /* Sanity check the cookie. */ 5918 for (pos = 0; pos < len; pos += (i + 1)) { 5919 if (pos == cookie) 5920 break; 5921 i = buf[pos]; 5922 } 5923 if (pos != cookie) { 5924 nd->nd_repstat = NFSERR_INVAL; 5925 goto nfsmout; 5926 } 5927 5928 /* Loop around copying the entrie(s) out. */ 5929 cnt = 0; 5930 len -= cookie; 5931 i = buf[pos]; 5932 while (i < len && len2 >= retlen + NFSM_RNDUP(i) + 5933 NFSX_UNSIGNED) { 5934 if (cnt == 0) { 5935 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 5936 NFSX_UNSIGNED); 5937 txdr_hyper(cookie2, tl); tl += 2; 5938 } 5939 retlen += nfsm_strtom(nd, &buf[pos + 1], i); 5940 len -= (i + 1); 5941 pos += (i + 1); 5942 i = buf[pos]; 5943 cnt++; 5944 } 5945 /* 5946 * eof is set true/false by nfsvno_listxattr(), but if we 5947 * can't copy all entries returned by nfsvno_listxattr(), 5948 * we are not at eof. 5949 */ 5950 if (len > 0) 5951 eof = false; 5952 if (cnt > 0) { 5953 /* *tl is set above. */ 5954 *tl = txdr_unsigned(cnt); 5955 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5956 if (eof) 5957 *tl = newnfs_true; 5958 else 5959 *tl = newnfs_false; 5960 } else 5961 nd->nd_repstat = NFSERR_TOOSMALL; 5962 } 5963 5964 nfsmout: 5965 free(buf, M_TEMP); 5966 if (nd->nd_repstat == 0) 5967 nd->nd_repstat = error; 5968 vput(vp); 5969 NFSEXITCODE2(0, nd); 5970 return (0); 5971 } 5972 5973 /* 5974 * nfsv4 service not supported 5975 */ 5976 int 5977 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 5978 __unused vnode_t vp, __unused struct nfsexstuff *exp) 5979 { 5980 5981 nd->nd_repstat = NFSERR_NOTSUPP; 5982 NFSEXITCODE2(0, nd); 5983 return (0); 5984 } 5985