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