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