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 goto nfsmout; 2724 } 2725 } 2726 2727 lop->lo_first = fxdr_hyper(tl); 2728 tl += 2; 2729 len = fxdr_hyper(tl); 2730 if (len == NFS64BITSSET) { 2731 lop->lo_end = NFS64BITSSET; 2732 } else { 2733 lop->lo_end = lop->lo_first + len; 2734 if (lop->lo_end <= lop->lo_first) 2735 nd->nd_repstat = NFSERR_INVAL; 2736 } 2737 clientid.lval[0] = stp->ls_stateid.other[0]; 2738 clientid.lval[1] = stp->ls_stateid.other[1]; 2739 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2740 if ((nd->nd_flag & ND_NFSV41) != 0) 2741 clientid.qval = nd->nd_clientid.qval; 2742 else if (nd->nd_clientid.qval != clientid.qval) 2743 printf("EEK6 multiple clids\n"); 2744 } else { 2745 if ((nd->nd_flag & ND_NFSV41) != 0) 2746 printf("EEK! no clientid from session\n"); 2747 nd->nd_flag |= ND_IMPLIEDCLID; 2748 nd->nd_clientid.qval = clientid.qval; 2749 } 2750 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2751 if (vnode_vtype(vp) == VDIR) 2752 nd->nd_repstat = NFSERR_ISDIR; 2753 else 2754 nd->nd_repstat = NFSERR_INVAL; 2755 } 2756 /* 2757 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 2758 * seqid# gets incremented. nfsrv_lockctrl() will return the 2759 * value of nd_repstat, if it gets that far. 2760 */ 2761 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 2762 &stateid, exp, nd, p); 2763 if (stp) 2764 free(stp, M_NFSDSTATE); 2765 if (lop) 2766 free(lop, M_NFSDLOCK); 2767 if (!nd->nd_repstat) { 2768 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2769 *tl++ = txdr_unsigned(stateid.seqid); 2770 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2771 } 2772 nfsmout: 2773 vput(vp); 2774 NFSEXITCODE2(error, nd); 2775 return (error); 2776 } 2777 2778 /* 2779 * nfsv4 open service 2780 */ 2781 int 2782 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2783 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp) 2784 { 2785 u_int32_t *tl; 2786 int i, retext; 2787 struct nfsstate *stp = NULL; 2788 int error = 0, create, claim, exclusive_flag = 0, override; 2789 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 2790 int how = NFSCREATE_UNCHECKED; 2791 int32_t cverf[2], tverf[2] = { 0, 0 }; 2792 vnode_t vp = NULL, dirp = NULL; 2793 struct nfsvattr nva, dirfor, diraft; 2794 struct nameidata named; 2795 nfsv4stateid_t stateid, delegstateid; 2796 nfsattrbit_t attrbits; 2797 nfsquad_t clientid; 2798 char *bufp = NULL; 2799 u_long *hashp; 2800 NFSACL_T *aclp = NULL; 2801 struct thread *p = curthread; 2802 2803 #ifdef NFS4_ACL_EXTATTR_NAME 2804 aclp = acl_alloc(M_WAITOK); 2805 aclp->acl_cnt = 0; 2806 #endif 2807 NFSZERO_ATTRBIT(&attrbits); 2808 named.ni_startdir = NULL; 2809 named.ni_cnd.cn_nameiop = 0; 2810 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2811 i = fxdr_unsigned(int, *(tl + 5)); 2812 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2813 nd->nd_repstat = NFSERR_BADXDR; 2814 goto nfsmout; 2815 } 2816 stp = malloc(sizeof (struct nfsstate) + i, 2817 M_NFSDSTATE, M_WAITOK); 2818 stp->ls_ownerlen = i; 2819 stp->ls_op = nd->nd_rp; 2820 stp->ls_flags = NFSLCK_OPEN; 2821 stp->ls_uid = nd->nd_cred->cr_uid; 2822 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2823 i = fxdr_unsigned(int, *tl++); 2824 retext = 0; 2825 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2826 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2827 retext = 1; 2828 /* For now, ignore these. */ 2829 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2830 switch (i & NFSV4OPEN_WANTDELEGMASK) { 2831 case NFSV4OPEN_WANTANYDELEG: 2832 stp->ls_flags |= (NFSLCK_WANTRDELEG | 2833 NFSLCK_WANTWDELEG); 2834 i &= ~NFSV4OPEN_WANTDELEGMASK; 2835 break; 2836 case NFSV4OPEN_WANTREADDELEG: 2837 stp->ls_flags |= NFSLCK_WANTRDELEG; 2838 i &= ~NFSV4OPEN_WANTDELEGMASK; 2839 break; 2840 case NFSV4OPEN_WANTWRITEDELEG: 2841 stp->ls_flags |= NFSLCK_WANTWDELEG; 2842 i &= ~NFSV4OPEN_WANTDELEGMASK; 2843 break; 2844 case NFSV4OPEN_WANTNODELEG: 2845 stp->ls_flags |= NFSLCK_WANTNODELEG; 2846 i &= ~NFSV4OPEN_WANTDELEGMASK; 2847 break; 2848 case NFSV4OPEN_WANTCANCEL: 2849 printf("NFSv4: ignore Open WantCancel\n"); 2850 i &= ~NFSV4OPEN_WANTDELEGMASK; 2851 break; 2852 default: 2853 /* nd_repstat will be set to NFSERR_INVAL below. */ 2854 break; 2855 } 2856 } 2857 switch (i) { 2858 case NFSV4OPEN_ACCESSREAD: 2859 stp->ls_flags |= NFSLCK_READACCESS; 2860 break; 2861 case NFSV4OPEN_ACCESSWRITE: 2862 stp->ls_flags |= NFSLCK_WRITEACCESS; 2863 break; 2864 case NFSV4OPEN_ACCESSBOTH: 2865 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2866 break; 2867 default: 2868 nd->nd_repstat = NFSERR_INVAL; 2869 } 2870 i = fxdr_unsigned(int, *tl++); 2871 switch (i) { 2872 case NFSV4OPEN_DENYNONE: 2873 break; 2874 case NFSV4OPEN_DENYREAD: 2875 stp->ls_flags |= NFSLCK_READDENY; 2876 break; 2877 case NFSV4OPEN_DENYWRITE: 2878 stp->ls_flags |= NFSLCK_WRITEDENY; 2879 break; 2880 case NFSV4OPEN_DENYBOTH: 2881 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 2882 break; 2883 default: 2884 nd->nd_repstat = NFSERR_INVAL; 2885 } 2886 clientid.lval[0] = *tl++; 2887 clientid.lval[1] = *tl; 2888 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2889 if ((nd->nd_flag & ND_NFSV41) != 0) 2890 clientid.qval = nd->nd_clientid.qval; 2891 else if (nd->nd_clientid.qval != clientid.qval) 2892 printf("EEK7 multiple clids\n"); 2893 } else { 2894 if ((nd->nd_flag & ND_NFSV41) != 0) 2895 printf("EEK! no clientid from session\n"); 2896 nd->nd_flag |= ND_IMPLIEDCLID; 2897 nd->nd_clientid.qval = clientid.qval; 2898 } 2899 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2900 if (error) 2901 goto nfsmout; 2902 NFSVNO_ATTRINIT(&nva); 2903 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2904 create = fxdr_unsigned(int, *tl); 2905 if (!nd->nd_repstat) 2906 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL); 2907 if (create == NFSV4OPEN_CREATE) { 2908 nva.na_type = VREG; 2909 nva.na_mode = 0; 2910 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2911 how = fxdr_unsigned(int, *tl); 2912 switch (how) { 2913 case NFSCREATE_UNCHECKED: 2914 case NFSCREATE_GUARDED: 2915 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2916 if (error) 2917 goto nfsmout; 2918 /* 2919 * If the na_gid being set is the same as that of 2920 * the directory it is going in, clear it, since 2921 * that is what will be set by default. This allows 2922 * a user that isn't in that group to do the create. 2923 */ 2924 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 2925 nva.na_gid == dirfor.na_gid) 2926 NFSVNO_UNSET(&nva, gid); 2927 if (!nd->nd_repstat) 2928 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2929 break; 2930 case NFSCREATE_EXCLUSIVE: 2931 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2932 cverf[0] = *tl++; 2933 cverf[1] = *tl; 2934 break; 2935 case NFSCREATE_EXCLUSIVE41: 2936 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2937 cverf[0] = *tl++; 2938 cverf[1] = *tl; 2939 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2940 if (error != 0) 2941 goto nfsmout; 2942 if (NFSISSET_ATTRBIT(&attrbits, 2943 NFSATTRBIT_TIMEACCESSSET)) 2944 nd->nd_repstat = NFSERR_INVAL; 2945 /* 2946 * If the na_gid being set is the same as that of 2947 * the directory it is going in, clear it, since 2948 * that is what will be set by default. This allows 2949 * a user that isn't in that group to do the create. 2950 */ 2951 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2952 nva.na_gid == dirfor.na_gid) 2953 NFSVNO_UNSET(&nva, gid); 2954 if (nd->nd_repstat == 0) 2955 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2956 break; 2957 default: 2958 nd->nd_repstat = NFSERR_BADXDR; 2959 goto nfsmout; 2960 } 2961 } else if (create != NFSV4OPEN_NOCREATE) { 2962 nd->nd_repstat = NFSERR_BADXDR; 2963 goto nfsmout; 2964 } 2965 2966 /* 2967 * Now, handle the claim, which usually includes looking up a 2968 * name in the directory referenced by dp. The exception is 2969 * NFSV4OPEN_CLAIMPREVIOUS. 2970 */ 2971 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2972 claim = fxdr_unsigned(int, *tl); 2973 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 2974 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2975 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2976 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 2977 stp->ls_flags |= NFSLCK_DELEGCUR; 2978 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2979 stp->ls_flags |= NFSLCK_DELEGPREV; 2980 } 2981 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 2982 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2983 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 2984 claim != NFSV4OPEN_CLAIMNULL) 2985 nd->nd_repstat = NFSERR_INVAL; 2986 if (nd->nd_repstat) { 2987 nd->nd_repstat = nfsrv_opencheck(clientid, 2988 &stateid, stp, NULL, nd, p, nd->nd_repstat); 2989 goto nfsmout; 2990 } 2991 if (create == NFSV4OPEN_CREATE) 2992 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 2993 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 2994 else 2995 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 2996 LOCKLEAF | SAVESTART); 2997 nfsvno_setpathbuf(&named, &bufp, &hashp); 2998 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2999 if (error) { 3000 vrele(dp); 3001 #ifdef NFS4_ACL_EXTATTR_NAME 3002 acl_free(aclp); 3003 #endif 3004 free(stp, M_NFSDSTATE); 3005 nfsvno_relpathbuf(&named); 3006 NFSEXITCODE2(error, nd); 3007 return (error); 3008 } 3009 if (!nd->nd_repstat) { 3010 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 3011 p, &dirp); 3012 } else { 3013 vrele(dp); 3014 nfsvno_relpathbuf(&named); 3015 } 3016 if (create == NFSV4OPEN_CREATE) { 3017 switch (how) { 3018 case NFSCREATE_UNCHECKED: 3019 if (named.ni_vp) { 3020 /* 3021 * Clear the setable attribute bits, except 3022 * for Size, if it is being truncated. 3023 */ 3024 NFSZERO_ATTRBIT(&attrbits); 3025 if (NFSVNO_ISSETSIZE(&nva)) 3026 NFSSETBIT_ATTRBIT(&attrbits, 3027 NFSATTRBIT_SIZE); 3028 } 3029 break; 3030 case NFSCREATE_GUARDED: 3031 if (named.ni_vp && !nd->nd_repstat) 3032 nd->nd_repstat = EEXIST; 3033 break; 3034 case NFSCREATE_EXCLUSIVE: 3035 exclusive_flag = 1; 3036 if (!named.ni_vp) 3037 nva.na_mode = 0; 3038 break; 3039 case NFSCREATE_EXCLUSIVE41: 3040 exclusive_flag = 1; 3041 break; 3042 } 3043 } 3044 nfsvno_open(nd, &named, clientid, &stateid, stp, 3045 &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 3046 nd->nd_cred, exp, &vp); 3047 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 3048 NFSV4OPEN_CLAIMFH) { 3049 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 3050 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3051 i = fxdr_unsigned(int, *tl); 3052 switch (i) { 3053 case NFSV4OPEN_DELEGATEREAD: 3054 stp->ls_flags |= NFSLCK_DELEGREAD; 3055 break; 3056 case NFSV4OPEN_DELEGATEWRITE: 3057 stp->ls_flags |= NFSLCK_DELEGWRITE; 3058 case NFSV4OPEN_DELEGATENONE: 3059 break; 3060 default: 3061 nd->nd_repstat = NFSERR_BADXDR; 3062 goto nfsmout; 3063 } 3064 stp->ls_flags |= NFSLCK_RECLAIM; 3065 } else { 3066 /* CLAIM_NULL_FH */ 3067 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 3068 nd->nd_repstat = NFSERR_INVAL; 3069 } 3070 vp = dp; 3071 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 3072 if (!VN_IS_DOOMED(vp)) 3073 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 3074 stp, vp, nd, p, nd->nd_repstat); 3075 else 3076 nd->nd_repstat = NFSERR_PERM; 3077 } else { 3078 nd->nd_repstat = NFSERR_BADXDR; 3079 goto nfsmout; 3080 } 3081 3082 /* 3083 * Do basic access checking. 3084 */ 3085 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 3086 /* 3087 * The IETF working group decided that this is the correct 3088 * error return for all non-regular files. 3089 */ 3090 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK; 3091 } 3092 3093 /* 3094 * If the Open is being done for a file that already exists, apply 3095 * normal permission checking including for the file owner, if 3096 * vfs.nfsd.v4openaccess is set. 3097 * Previously, the owner was always allowed to open the file to 3098 * be consistent with the NFS tradition of always allowing the 3099 * owner of the file to write to the file regardless of permissions. 3100 * It now appears that the Linux client expects the owner 3101 * permissions to be checked for opens that are not creating the 3102 * file. I believe the correct approach is to use the Access 3103 * operation's results to be consistent with NFSv3, but that is 3104 * not what the current Linux client appears to be doing. 3105 * Since both the Linux and OpenSolaris NFSv4 servers do this check, 3106 * I have enabled it by default. 3107 * If this semantic change causes a problem, it can be disabled by 3108 * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the 3109 * previous semantics. 3110 */ 3111 if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE) 3112 override = NFSACCCHK_NOOVERRIDE; 3113 else 3114 override = NFSACCCHK_ALLOWOWNER; 3115 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 3116 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 3117 exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 3118 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 3119 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 3120 exp, p, override, NFSACCCHK_VPISLOCKED, NULL); 3121 if (nd->nd_repstat) 3122 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 3123 nd->nd_cred, exp, p, override, 3124 NFSACCCHK_VPISLOCKED, NULL); 3125 } 3126 3127 if (!nd->nd_repstat) { 3128 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 3129 if (!nd->nd_repstat) { 3130 tverf[0] = nva.na_atime.tv_sec; 3131 tverf[1] = nva.na_atime.tv_nsec; 3132 } 3133 } 3134 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 3135 cverf[1] != tverf[1])) 3136 nd->nd_repstat = EEXIST; 3137 /* 3138 * Do the open locking/delegation stuff. 3139 */ 3140 if (!nd->nd_repstat) 3141 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 3142 &delegstateid, &rflags, exp, p, nva.na_filerev); 3143 3144 /* 3145 * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 3146 * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 3147 * (ie: Leave the NFSVOPUNLOCK() about here.) 3148 */ 3149 if (vp) 3150 NFSVOPUNLOCK(vp); 3151 if (stp) 3152 free(stp, M_NFSDSTATE); 3153 if (!nd->nd_repstat && dirp) 3154 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL); 3155 if (!nd->nd_repstat) { 3156 /* For NFSv4.1, set the Current StateID. */ 3157 if ((nd->nd_flag & ND_NFSV41) != 0) { 3158 nd->nd_curstateid = stateid; 3159 nd->nd_flag |= ND_CURSTATEID; 3160 } 3161 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 3162 *tl++ = txdr_unsigned(stateid.seqid); 3163 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3164 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3165 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 3166 *tl++ = newnfs_true; 3167 *tl++ = 0; 3168 *tl++ = 0; 3169 *tl++ = 0; 3170 *tl++ = 0; 3171 } else { 3172 *tl++ = newnfs_false; /* Since dirp is not locked */ 3173 txdr_hyper(dirfor.na_filerev, tl); 3174 tl += 2; 3175 txdr_hyper(diraft.na_filerev, tl); 3176 tl += 2; 3177 } 3178 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 3179 (void) nfsrv_putattrbit(nd, &attrbits); 3180 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3181 if (rflags & NFSV4OPEN_READDELEGATE) 3182 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 3183 else if (rflags & NFSV4OPEN_WRITEDELEGATE) 3184 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 3185 else if (retext != 0) { 3186 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 3187 if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) { 3188 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3189 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3190 } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) { 3191 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3192 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE); 3193 } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 3194 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3195 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 3196 *tl = newnfs_false; 3197 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 3198 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3199 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 3200 *tl = newnfs_false; 3201 } else { 3202 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3203 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 3204 } 3205 } else 3206 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 3207 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 3208 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 3209 *tl++ = txdr_unsigned(delegstateid.seqid); 3210 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 3211 NFSX_STATEIDOTHER); 3212 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3213 if (rflags & NFSV4OPEN_RECALL) 3214 *tl = newnfs_true; 3215 else 3216 *tl = newnfs_false; 3217 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 3218 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3219 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 3220 txdr_hyper(nva.na_size, tl); 3221 } 3222 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3223 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 3224 *tl++ = txdr_unsigned(0x0); 3225 acemask = NFSV4ACE_ALLFILESMASK; 3226 if (nva.na_mode & S_IRUSR) 3227 acemask |= NFSV4ACE_READMASK; 3228 if (nva.na_mode & S_IWUSR) 3229 acemask |= NFSV4ACE_WRITEMASK; 3230 if (nva.na_mode & S_IXUSR) 3231 acemask |= NFSV4ACE_EXECUTEMASK; 3232 *tl = txdr_unsigned(acemask); 3233 (void) nfsm_strtom(nd, "OWNER@", 6); 3234 } 3235 *vpp = vp; 3236 } else if (vp) { 3237 vrele(vp); 3238 } 3239 if (dirp) 3240 vrele(dirp); 3241 #ifdef NFS4_ACL_EXTATTR_NAME 3242 acl_free(aclp); 3243 #endif 3244 NFSEXITCODE2(0, nd); 3245 return (0); 3246 nfsmout: 3247 vrele(dp); 3248 #ifdef NFS4_ACL_EXTATTR_NAME 3249 acl_free(aclp); 3250 #endif 3251 if (stp) 3252 free(stp, M_NFSDSTATE); 3253 NFSEXITCODE2(error, nd); 3254 return (error); 3255 } 3256 3257 /* 3258 * nfsv4 close service 3259 */ 3260 int 3261 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3262 vnode_t vp, __unused struct nfsexstuff *exp) 3263 { 3264 u_int32_t *tl; 3265 struct nfsstate st, *stp = &st; 3266 int error = 0, writeacc; 3267 nfsv4stateid_t stateid; 3268 nfsquad_t clientid; 3269 struct nfsvattr na; 3270 struct thread *p = curthread; 3271 3272 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 3273 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3274 stp->ls_ownerlen = 0; 3275 stp->ls_op = nd->nd_rp; 3276 stp->ls_uid = nd->nd_cred->cr_uid; 3277 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3278 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3279 NFSX_STATEIDOTHER); 3280 3281 /* 3282 * For the special stateid of other all 0s and seqid == 1, set the 3283 * stateid to the current stateid, if it is set. 3284 */ 3285 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 3286 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 3287 stp->ls_stateid.other[2] == 0) { 3288 if ((nd->nd_flag & ND_CURSTATEID) != 0) 3289 stp->ls_stateid = nd->nd_curstateid; 3290 else { 3291 nd->nd_repstat = NFSERR_BADSTATEID; 3292 goto nfsmout; 3293 } 3294 } 3295 3296 stp->ls_flags = NFSLCK_CLOSE; 3297 clientid.lval[0] = stp->ls_stateid.other[0]; 3298 clientid.lval[1] = stp->ls_stateid.other[1]; 3299 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3300 if ((nd->nd_flag & ND_NFSV41) != 0) 3301 clientid.qval = nd->nd_clientid.qval; 3302 else if (nd->nd_clientid.qval != clientid.qval) 3303 printf("EEK8 multiple clids\n"); 3304 } else { 3305 if ((nd->nd_flag & ND_NFSV41) != 0) 3306 printf("EEK! no clientid from session\n"); 3307 nd->nd_flag |= ND_IMPLIEDCLID; 3308 nd->nd_clientid.qval = clientid.qval; 3309 } 3310 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 3311 &writeacc); 3312 /* For pNFS, update the attributes. */ 3313 if (writeacc != 0 || nfsrv_pnfsatime != 0) 3314 nfsrv_updatemdsattr(vp, &na, p); 3315 vput(vp); 3316 if (!nd->nd_repstat) { 3317 /* 3318 * If the stateid that has been closed is the current stateid, 3319 * unset it. 3320 */ 3321 if ((nd->nd_flag & ND_CURSTATEID) != 0 && 3322 stateid.other[0] == nd->nd_curstateid.other[0] && 3323 stateid.other[1] == nd->nd_curstateid.other[1] && 3324 stateid.other[2] == nd->nd_curstateid.other[2]) 3325 nd->nd_flag &= ~ND_CURSTATEID; 3326 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3327 *tl++ = txdr_unsigned(stateid.seqid); 3328 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3329 } 3330 NFSEXITCODE2(0, nd); 3331 return (0); 3332 nfsmout: 3333 vput(vp); 3334 NFSEXITCODE2(error, nd); 3335 return (error); 3336 } 3337 3338 /* 3339 * nfsv4 delegpurge service 3340 */ 3341 int 3342 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3343 __unused vnode_t vp, __unused struct nfsexstuff *exp) 3344 { 3345 u_int32_t *tl; 3346 int error = 0; 3347 nfsquad_t clientid; 3348 struct thread *p = curthread; 3349 3350 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3351 nd->nd_repstat = NFSERR_WRONGSEC; 3352 goto nfsmout; 3353 } 3354 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3355 clientid.lval[0] = *tl++; 3356 clientid.lval[1] = *tl; 3357 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3358 if ((nd->nd_flag & ND_NFSV41) != 0) 3359 clientid.qval = nd->nd_clientid.qval; 3360 else if (nd->nd_clientid.qval != clientid.qval) 3361 printf("EEK9 multiple clids\n"); 3362 } else { 3363 if ((nd->nd_flag & ND_NFSV41) != 0) 3364 printf("EEK! no clientid from session\n"); 3365 nd->nd_flag |= ND_IMPLIEDCLID; 3366 nd->nd_clientid.qval = clientid.qval; 3367 } 3368 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 3369 NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL); 3370 nfsmout: 3371 NFSEXITCODE2(error, nd); 3372 return (error); 3373 } 3374 3375 /* 3376 * nfsv4 delegreturn service 3377 */ 3378 int 3379 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3380 vnode_t vp, __unused struct nfsexstuff *exp) 3381 { 3382 u_int32_t *tl; 3383 int error = 0, writeacc; 3384 nfsv4stateid_t stateid; 3385 nfsquad_t clientid; 3386 struct nfsvattr na; 3387 struct thread *p = curthread; 3388 3389 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3390 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3391 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 3392 clientid.lval[0] = stateid.other[0]; 3393 clientid.lval[1] = stateid.other[1]; 3394 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3395 if ((nd->nd_flag & ND_NFSV41) != 0) 3396 clientid.qval = nd->nd_clientid.qval; 3397 else if (nd->nd_clientid.qval != clientid.qval) 3398 printf("EEK10 multiple clids\n"); 3399 } else { 3400 if ((nd->nd_flag & ND_NFSV41) != 0) 3401 printf("EEK! no clientid from session\n"); 3402 nd->nd_flag |= ND_IMPLIEDCLID; 3403 nd->nd_clientid.qval = clientid.qval; 3404 } 3405 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 3406 NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc); 3407 /* For pNFS, update the attributes. */ 3408 if (writeacc != 0 || nfsrv_pnfsatime != 0) 3409 nfsrv_updatemdsattr(vp, &na, p); 3410 nfsmout: 3411 vput(vp); 3412 NFSEXITCODE2(error, nd); 3413 return (error); 3414 } 3415 3416 /* 3417 * nfsv4 get file handle service 3418 */ 3419 int 3420 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3421 vnode_t vp, __unused struct nfsexstuff *exp) 3422 { 3423 fhandle_t fh; 3424 struct thread *p = curthread; 3425 3426 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3427 vput(vp); 3428 if (!nd->nd_repstat) 3429 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3430 NFSEXITCODE2(0, nd); 3431 return (0); 3432 } 3433 3434 /* 3435 * nfsv4 open confirm service 3436 */ 3437 int 3438 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3439 vnode_t vp, __unused struct nfsexstuff *exp) 3440 { 3441 u_int32_t *tl; 3442 struct nfsstate st, *stp = &st; 3443 int error = 0; 3444 nfsv4stateid_t stateid; 3445 nfsquad_t clientid; 3446 struct thread *p = curthread; 3447 3448 if ((nd->nd_flag & ND_NFSV41) != 0) { 3449 nd->nd_repstat = NFSERR_NOTSUPP; 3450 goto nfsmout; 3451 } 3452 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3453 stp->ls_ownerlen = 0; 3454 stp->ls_op = nd->nd_rp; 3455 stp->ls_uid = nd->nd_cred->cr_uid; 3456 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3457 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3458 NFSX_STATEIDOTHER); 3459 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3460 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 3461 stp->ls_flags = NFSLCK_CONFIRM; 3462 clientid.lval[0] = stp->ls_stateid.other[0]; 3463 clientid.lval[1] = stp->ls_stateid.other[1]; 3464 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3465 if ((nd->nd_flag & ND_NFSV41) != 0) 3466 clientid.qval = nd->nd_clientid.qval; 3467 else if (nd->nd_clientid.qval != clientid.qval) 3468 printf("EEK11 multiple clids\n"); 3469 } else { 3470 if ((nd->nd_flag & ND_NFSV41) != 0) 3471 printf("EEK! no clientid from session\n"); 3472 nd->nd_flag |= ND_IMPLIEDCLID; 3473 nd->nd_clientid.qval = clientid.qval; 3474 } 3475 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p, 3476 NULL); 3477 if (!nd->nd_repstat) { 3478 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3479 *tl++ = txdr_unsigned(stateid.seqid); 3480 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3481 } 3482 nfsmout: 3483 vput(vp); 3484 NFSEXITCODE2(error, nd); 3485 return (error); 3486 } 3487 3488 /* 3489 * nfsv4 open downgrade service 3490 */ 3491 int 3492 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3493 vnode_t vp, __unused struct nfsexstuff *exp) 3494 { 3495 u_int32_t *tl; 3496 int i; 3497 struct nfsstate st, *stp = &st; 3498 int error = 0; 3499 nfsv4stateid_t stateid; 3500 nfsquad_t clientid; 3501 struct thread *p = curthread; 3502 3503 /* opendowngrade can only work on a file object.*/ 3504 if (vp->v_type != VREG) { 3505 error = NFSERR_INVAL; 3506 goto nfsmout; 3507 } 3508 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 3509 stp->ls_ownerlen = 0; 3510 stp->ls_op = nd->nd_rp; 3511 stp->ls_uid = nd->nd_cred->cr_uid; 3512 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3513 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3514 NFSX_STATEIDOTHER); 3515 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3516 3517 /* 3518 * For the special stateid of other all 0s and seqid == 1, set the 3519 * stateid to the current stateid, if it is set. 3520 */ 3521 if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 && 3522 stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 && 3523 stp->ls_stateid.other[2] == 0) { 3524 if ((nd->nd_flag & ND_CURSTATEID) != 0) 3525 stp->ls_stateid = nd->nd_curstateid; 3526 else { 3527 nd->nd_repstat = NFSERR_BADSTATEID; 3528 goto nfsmout; 3529 } 3530 } 3531 3532 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3533 i = fxdr_unsigned(int, *tl++); 3534 if ((nd->nd_flag & ND_NFSV41) != 0) 3535 i &= ~NFSV4OPEN_WANTDELEGMASK; 3536 switch (i) { 3537 case NFSV4OPEN_ACCESSREAD: 3538 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3539 break; 3540 case NFSV4OPEN_ACCESSWRITE: 3541 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3542 break; 3543 case NFSV4OPEN_ACCESSBOTH: 3544 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3545 NFSLCK_DOWNGRADE); 3546 break; 3547 default: 3548 nd->nd_repstat = NFSERR_INVAL; 3549 } 3550 i = fxdr_unsigned(int, *tl); 3551 switch (i) { 3552 case NFSV4OPEN_DENYNONE: 3553 break; 3554 case NFSV4OPEN_DENYREAD: 3555 stp->ls_flags |= NFSLCK_READDENY; 3556 break; 3557 case NFSV4OPEN_DENYWRITE: 3558 stp->ls_flags |= NFSLCK_WRITEDENY; 3559 break; 3560 case NFSV4OPEN_DENYBOTH: 3561 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3562 break; 3563 default: 3564 nd->nd_repstat = NFSERR_INVAL; 3565 } 3566 3567 clientid.lval[0] = stp->ls_stateid.other[0]; 3568 clientid.lval[1] = stp->ls_stateid.other[1]; 3569 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3570 if ((nd->nd_flag & ND_NFSV41) != 0) 3571 clientid.qval = nd->nd_clientid.qval; 3572 else if (nd->nd_clientid.qval != clientid.qval) 3573 printf("EEK12 multiple clids\n"); 3574 } else { 3575 if ((nd->nd_flag & ND_NFSV41) != 0) 3576 printf("EEK! no clientid from session\n"); 3577 nd->nd_flag |= ND_IMPLIEDCLID; 3578 nd->nd_clientid.qval = clientid.qval; 3579 } 3580 if (!nd->nd_repstat) 3581 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3582 nd, p, NULL); 3583 if (!nd->nd_repstat) { 3584 /* For NFSv4.1, set the Current StateID. */ 3585 if ((nd->nd_flag & ND_NFSV41) != 0) { 3586 nd->nd_curstateid = stateid; 3587 nd->nd_flag |= ND_CURSTATEID; 3588 } 3589 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3590 *tl++ = txdr_unsigned(stateid.seqid); 3591 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3592 } 3593 nfsmout: 3594 vput(vp); 3595 NFSEXITCODE2(error, nd); 3596 return (error); 3597 } 3598 3599 /* 3600 * nfsv4 renew lease service 3601 */ 3602 int 3603 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3604 __unused vnode_t vp, __unused struct nfsexstuff *exp) 3605 { 3606 u_int32_t *tl; 3607 int error = 0; 3608 nfsquad_t clientid; 3609 struct thread *p = curthread; 3610 3611 if ((nd->nd_flag & ND_NFSV41) != 0) { 3612 nd->nd_repstat = NFSERR_NOTSUPP; 3613 goto nfsmout; 3614 } 3615 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3616 nd->nd_repstat = NFSERR_WRONGSEC; 3617 goto nfsmout; 3618 } 3619 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3620 clientid.lval[0] = *tl++; 3621 clientid.lval[1] = *tl; 3622 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3623 if ((nd->nd_flag & ND_NFSV41) != 0) 3624 clientid.qval = nd->nd_clientid.qval; 3625 else if (nd->nd_clientid.qval != clientid.qval) 3626 printf("EEK13 multiple clids\n"); 3627 } else { 3628 if ((nd->nd_flag & ND_NFSV41) != 0) 3629 printf("EEK! no clientid from session\n"); 3630 nd->nd_flag |= ND_IMPLIEDCLID; 3631 nd->nd_clientid.qval = clientid.qval; 3632 } 3633 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3634 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 3635 nfsmout: 3636 NFSEXITCODE2(error, nd); 3637 return (error); 3638 } 3639 3640 /* 3641 * nfsv4 security info service 3642 */ 3643 int 3644 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3645 vnode_t dp, struct nfsexstuff *exp) 3646 { 3647 u_int32_t *tl; 3648 int len; 3649 struct nameidata named; 3650 vnode_t dirp = NULL, vp; 3651 struct nfsrvfh fh; 3652 struct nfsexstuff retnes; 3653 u_int32_t *sizp; 3654 int error = 0, savflag, i; 3655 char *bufp; 3656 u_long *hashp; 3657 struct thread *p = curthread; 3658 3659 /* 3660 * All this just to get the export flags for the name. 3661 */ 3662 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3663 LOCKLEAF | SAVESTART); 3664 nfsvno_setpathbuf(&named, &bufp, &hashp); 3665 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3666 if (error) { 3667 vput(dp); 3668 nfsvno_relpathbuf(&named); 3669 goto out; 3670 } 3671 if (!nd->nd_repstat) { 3672 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3673 } else { 3674 vput(dp); 3675 nfsvno_relpathbuf(&named); 3676 } 3677 if (dirp) 3678 vrele(dirp); 3679 if (nd->nd_repstat) 3680 goto out; 3681 vrele(named.ni_startdir); 3682 nfsvno_relpathbuf(&named); 3683 fh.nfsrvfh_len = NFSX_MYFH; 3684 vp = named.ni_vp; 3685 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3686 vput(vp); 3687 savflag = nd->nd_flag; 3688 if (!nd->nd_repstat) { 3689 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0); 3690 if (vp) 3691 vput(vp); 3692 } 3693 nd->nd_flag = savflag; 3694 if (nd->nd_repstat) 3695 goto out; 3696 3697 /* 3698 * Finally have the export flags for name, so we can create 3699 * the security info. 3700 */ 3701 len = 0; 3702 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3703 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3704 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3705 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3706 *tl = txdr_unsigned(RPCAUTH_UNIX); 3707 len++; 3708 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3709 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3710 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3711 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3712 nfsgss_mechlist[KERBV_MECH].len); 3713 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3714 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3715 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3716 len++; 3717 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3718 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3719 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3720 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3721 nfsgss_mechlist[KERBV_MECH].len); 3722 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3723 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3724 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3725 len++; 3726 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3727 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3728 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3729 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3730 nfsgss_mechlist[KERBV_MECH].len); 3731 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3732 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3733 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3734 len++; 3735 } 3736 } 3737 *sizp = txdr_unsigned(len); 3738 3739 out: 3740 NFSEXITCODE2(error, nd); 3741 return (error); 3742 } 3743 3744 /* 3745 * nfsv4 set client id service 3746 */ 3747 int 3748 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3749 __unused vnode_t vp, __unused struct nfsexstuff *exp) 3750 { 3751 u_int32_t *tl; 3752 int i; 3753 int error = 0, idlen; 3754 struct nfsclient *clp = NULL; 3755 #ifdef INET 3756 struct sockaddr_in *rin; 3757 #endif 3758 #ifdef INET6 3759 struct sockaddr_in6 *rin6; 3760 #endif 3761 #if defined(INET) || defined(INET6) 3762 u_char *ucp, *ucp2; 3763 #endif 3764 u_char *verf, *addrbuf; 3765 nfsquad_t clientid, confirm; 3766 struct thread *p = curthread; 3767 3768 if ((nd->nd_flag & ND_NFSV41) != 0) { 3769 nd->nd_repstat = NFSERR_NOTSUPP; 3770 goto nfsmout; 3771 } 3772 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3773 nd->nd_repstat = NFSERR_WRONGSEC; 3774 goto out; 3775 } 3776 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3777 verf = (u_char *)tl; 3778 tl += (NFSX_VERF / NFSX_UNSIGNED); 3779 i = fxdr_unsigned(int, *tl); 3780 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3781 nd->nd_repstat = NFSERR_BADXDR; 3782 goto nfsmout; 3783 } 3784 idlen = i; 3785 if (nd->nd_flag & ND_GSS) 3786 i += nd->nd_princlen; 3787 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3788 M_ZERO); 3789 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3790 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3791 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3792 /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 3793 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 3794 M_WAITOK | M_ZERO); 3795 clp->lc_req.nr_cred = NULL; 3796 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3797 clp->lc_idlen = idlen; 3798 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3799 if (error) 3800 goto nfsmout; 3801 if (nd->nd_flag & ND_GSS) { 3802 clp->lc_flags = LCL_GSS; 3803 if (nd->nd_flag & ND_GSSINTEGRITY) 3804 clp->lc_flags |= LCL_GSSINTEGRITY; 3805 else if (nd->nd_flag & ND_GSSPRIVACY) 3806 clp->lc_flags |= LCL_GSSPRIVACY; 3807 } else { 3808 clp->lc_flags = 0; 3809 } 3810 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 3811 clp->lc_flags |= LCL_NAME; 3812 clp->lc_namelen = nd->nd_princlen; 3813 clp->lc_name = &clp->lc_id[idlen]; 3814 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3815 } else { 3816 clp->lc_uid = nd->nd_cred->cr_uid; 3817 clp->lc_gid = nd->nd_cred->cr_gid; 3818 } 3819 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3820 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 3821 error = nfsrv_getclientipaddr(nd, clp); 3822 if (error) 3823 goto nfsmout; 3824 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3825 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 3826 3827 /* 3828 * nfsrv_setclient() does the actual work of adding it to the 3829 * client list. If there is no error, the structure has been 3830 * linked into the client list and clp should no longer be used 3831 * here. When an error is returned, it has not been linked in, 3832 * so it should be free'd. 3833 */ 3834 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3835 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3836 /* 3837 * 8 is the maximum length of the port# string. 3838 */ 3839 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK); 3840 switch (clp->lc_req.nr_nam->sa_family) { 3841 #ifdef INET 3842 case AF_INET: 3843 if (clp->lc_flags & LCL_TCPCALLBACK) 3844 (void) nfsm_strtom(nd, "tcp", 3); 3845 else 3846 (void) nfsm_strtom(nd, "udp", 3); 3847 rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 3848 ucp = (u_char *)&rin->sin_addr.s_addr; 3849 ucp2 = (u_char *)&rin->sin_port; 3850 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 3851 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 3852 ucp2[0] & 0xff, ucp2[1] & 0xff); 3853 break; 3854 #endif 3855 #ifdef INET6 3856 case AF_INET6: 3857 if (clp->lc_flags & LCL_TCPCALLBACK) 3858 (void) nfsm_strtom(nd, "tcp6", 4); 3859 else 3860 (void) nfsm_strtom(nd, "udp6", 4); 3861 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 3862 ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf, 3863 INET6_ADDRSTRLEN); 3864 if (ucp != NULL) 3865 i = strlen(ucp); 3866 else 3867 i = 0; 3868 ucp2 = (u_char *)&rin6->sin6_port; 3869 sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff, 3870 ucp2[1] & 0xff); 3871 break; 3872 #endif 3873 } 3874 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3875 free(addrbuf, M_TEMP); 3876 } 3877 if (clp) { 3878 free(clp->lc_req.nr_nam, M_SONAME); 3879 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3880 free(clp->lc_stateid, M_NFSDCLIENT); 3881 free(clp, M_NFSDCLIENT); 3882 } 3883 if (!nd->nd_repstat) { 3884 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 3885 *tl++ = clientid.lval[0]; 3886 *tl++ = clientid.lval[1]; 3887 *tl++ = confirm.lval[0]; 3888 *tl = confirm.lval[1]; 3889 } 3890 3891 out: 3892 NFSEXITCODE2(0, nd); 3893 return (0); 3894 nfsmout: 3895 if (clp) { 3896 free(clp->lc_req.nr_nam, M_SONAME); 3897 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3898 free(clp->lc_stateid, M_NFSDCLIENT); 3899 free(clp, M_NFSDCLIENT); 3900 } 3901 NFSEXITCODE2(error, nd); 3902 return (error); 3903 } 3904 3905 /* 3906 * nfsv4 set client id confirm service 3907 */ 3908 int 3909 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3910 __unused int isdgram, __unused vnode_t vp, 3911 __unused struct nfsexstuff *exp) 3912 { 3913 u_int32_t *tl; 3914 int error = 0; 3915 nfsquad_t clientid, confirm; 3916 struct thread *p = curthread; 3917 3918 if ((nd->nd_flag & ND_NFSV41) != 0) { 3919 nd->nd_repstat = NFSERR_NOTSUPP; 3920 goto nfsmout; 3921 } 3922 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3923 nd->nd_repstat = NFSERR_WRONGSEC; 3924 goto nfsmout; 3925 } 3926 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 3927 clientid.lval[0] = *tl++; 3928 clientid.lval[1] = *tl++; 3929 confirm.lval[0] = *tl++; 3930 confirm.lval[1] = *tl; 3931 3932 /* 3933 * nfsrv_getclient() searches the client list for a match and 3934 * returns the appropriate NFSERR status. 3935 */ 3936 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3937 NULL, NULL, confirm, 0, nd, p); 3938 nfsmout: 3939 NFSEXITCODE2(error, nd); 3940 return (error); 3941 } 3942 3943 /* 3944 * nfsv4 verify service 3945 */ 3946 int 3947 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3948 vnode_t vp, __unused struct nfsexstuff *exp) 3949 { 3950 int error = 0, ret, fhsize = NFSX_MYFH; 3951 struct nfsvattr nva; 3952 struct statfs *sf; 3953 struct nfsfsinfo fs; 3954 fhandle_t fh; 3955 struct thread *p = curthread; 3956 3957 sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK); 3958 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL); 3959 if (!nd->nd_repstat) 3960 nd->nd_repstat = nfsvno_statfs(vp, sf); 3961 if (!nd->nd_repstat) 3962 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3963 if (!nd->nd_repstat) { 3964 nfsvno_getfs(&fs, isdgram); 3965 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 3966 sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 3967 if (!error) { 3968 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 3969 if (ret == 0) 3970 nd->nd_repstat = NFSERR_SAME; 3971 else if (ret != NFSERR_NOTSAME) 3972 nd->nd_repstat = ret; 3973 } else if (ret) 3974 nd->nd_repstat = ret; 3975 } 3976 } 3977 vput(vp); 3978 free(sf, M_STATFS); 3979 NFSEXITCODE2(error, nd); 3980 return (error); 3981 } 3982 3983 /* 3984 * nfs openattr rpc 3985 */ 3986 int 3987 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 3988 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3989 __unused struct nfsexstuff *exp) 3990 { 3991 u_int32_t *tl; 3992 int error = 0, createdir __unused; 3993 3994 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3995 createdir = fxdr_unsigned(int, *tl); 3996 nd->nd_repstat = NFSERR_NOTSUPP; 3997 nfsmout: 3998 vrele(dp); 3999 NFSEXITCODE2(error, nd); 4000 return (error); 4001 } 4002 4003 /* 4004 * nfsv4 release lock owner service 4005 */ 4006 int 4007 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 4008 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4009 { 4010 u_int32_t *tl; 4011 struct nfsstate *stp = NULL; 4012 int error = 0, len; 4013 nfsquad_t clientid; 4014 struct thread *p = curthread; 4015 4016 if ((nd->nd_flag & ND_NFSV41) != 0) { 4017 nd->nd_repstat = NFSERR_NOTSUPP; 4018 goto nfsmout; 4019 } 4020 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4021 nd->nd_repstat = NFSERR_WRONGSEC; 4022 goto nfsmout; 4023 } 4024 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 4025 len = fxdr_unsigned(int, *(tl + 2)); 4026 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 4027 nd->nd_repstat = NFSERR_BADXDR; 4028 goto nfsmout; 4029 } 4030 stp = malloc(sizeof (struct nfsstate) + len, 4031 M_NFSDSTATE, M_WAITOK); 4032 stp->ls_ownerlen = len; 4033 stp->ls_op = NULL; 4034 stp->ls_flags = NFSLCK_RELEASE; 4035 stp->ls_uid = nd->nd_cred->cr_uid; 4036 clientid.lval[0] = *tl++; 4037 clientid.lval[1] = *tl; 4038 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 4039 if ((nd->nd_flag & ND_NFSV41) != 0) 4040 clientid.qval = nd->nd_clientid.qval; 4041 else if (nd->nd_clientid.qval != clientid.qval) 4042 printf("EEK14 multiple clids\n"); 4043 } else { 4044 if ((nd->nd_flag & ND_NFSV41) != 0) 4045 printf("EEK! no clientid from session\n"); 4046 nd->nd_flag |= ND_IMPLIEDCLID; 4047 nd->nd_clientid.qval = clientid.qval; 4048 } 4049 error = nfsrv_mtostr(nd, stp->ls_owner, len); 4050 if (error) 4051 goto nfsmout; 4052 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 4053 free(stp, M_NFSDSTATE); 4054 4055 NFSEXITCODE2(0, nd); 4056 return (0); 4057 nfsmout: 4058 if (stp) 4059 free(stp, M_NFSDSTATE); 4060 NFSEXITCODE2(error, nd); 4061 return (error); 4062 } 4063 4064 /* 4065 * nfsv4 exchange_id service 4066 */ 4067 int 4068 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 4069 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4070 { 4071 uint32_t *tl; 4072 int error = 0, i, idlen; 4073 struct nfsclient *clp = NULL; 4074 nfsquad_t clientid, confirm; 4075 uint8_t *verf; 4076 uint32_t sp4type, v41flags; 4077 uint64_t owner_minor; 4078 struct timespec verstime; 4079 #ifdef INET 4080 struct sockaddr_in *sin, *rin; 4081 #endif 4082 #ifdef INET6 4083 struct sockaddr_in6 *sin6, *rin6; 4084 #endif 4085 struct thread *p = curthread; 4086 4087 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4088 nd->nd_repstat = NFSERR_WRONGSEC; 4089 goto nfsmout; 4090 } 4091 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 4092 verf = (uint8_t *)tl; 4093 tl += (NFSX_VERF / NFSX_UNSIGNED); 4094 i = fxdr_unsigned(int, *tl); 4095 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 4096 nd->nd_repstat = NFSERR_BADXDR; 4097 goto nfsmout; 4098 } 4099 idlen = i; 4100 if (nd->nd_flag & ND_GSS) 4101 i += nd->nd_princlen; 4102 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 4103 M_ZERO); 4104 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 4105 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 4106 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 4107 /* Allocated large enough for an AF_INET or AF_INET6 socket. */ 4108 clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME, 4109 M_WAITOK | M_ZERO); 4110 switch (nd->nd_nam->sa_family) { 4111 #ifdef INET 4112 case AF_INET: 4113 rin = (struct sockaddr_in *)clp->lc_req.nr_nam; 4114 sin = (struct sockaddr_in *)nd->nd_nam; 4115 rin->sin_family = AF_INET; 4116 rin->sin_len = sizeof(struct sockaddr_in); 4117 rin->sin_port = 0; 4118 rin->sin_addr.s_addr = sin->sin_addr.s_addr; 4119 break; 4120 #endif 4121 #ifdef INET6 4122 case AF_INET6: 4123 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam; 4124 sin6 = (struct sockaddr_in6 *)nd->nd_nam; 4125 rin6->sin6_family = AF_INET6; 4126 rin6->sin6_len = sizeof(struct sockaddr_in6); 4127 rin6->sin6_port = 0; 4128 rin6->sin6_addr = sin6->sin6_addr; 4129 break; 4130 #endif 4131 } 4132 clp->lc_req.nr_cred = NULL; 4133 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 4134 clp->lc_idlen = idlen; 4135 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 4136 if (error != 0) 4137 goto nfsmout; 4138 if ((nd->nd_flag & ND_GSS) != 0) { 4139 clp->lc_flags = LCL_GSS | LCL_NFSV41; 4140 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 4141 clp->lc_flags |= LCL_GSSINTEGRITY; 4142 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 4143 clp->lc_flags |= LCL_GSSPRIVACY; 4144 } else 4145 clp->lc_flags = LCL_NFSV41; 4146 if ((nd->nd_flag & ND_NFSV42) != 0) 4147 clp->lc_flags |= LCL_NFSV42; 4148 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 4149 clp->lc_flags |= LCL_NAME; 4150 clp->lc_namelen = nd->nd_princlen; 4151 clp->lc_name = &clp->lc_id[idlen]; 4152 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 4153 } else { 4154 clp->lc_uid = nd->nd_cred->cr_uid; 4155 clp->lc_gid = nd->nd_cred->cr_gid; 4156 } 4157 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4158 v41flags = fxdr_unsigned(uint32_t, *tl++); 4159 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 4160 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 4161 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 4162 nd->nd_repstat = NFSERR_INVAL; 4163 goto nfsmout; 4164 } 4165 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 4166 confirm.lval[1] = 1; 4167 else 4168 confirm.lval[1] = 0; 4169 if (nfsrv_devidcnt == 0) 4170 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS; 4171 else 4172 v41flags = NFSV4EXCH_USEPNFSMDS; 4173 sp4type = fxdr_unsigned(uint32_t, *tl); 4174 if (sp4type != NFSV4EXCH_SP4NONE) { 4175 nd->nd_repstat = NFSERR_NOTSUPP; 4176 goto nfsmout; 4177 } 4178 4179 /* 4180 * nfsrv_setclient() does the actual work of adding it to the 4181 * client list. If there is no error, the structure has been 4182 * linked into the client list and clp should no longer be used 4183 * here. When an error is returned, it has not been linked in, 4184 * so it should be free'd. 4185 */ 4186 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 4187 if (clp != NULL) { 4188 free(clp->lc_req.nr_nam, M_SONAME); 4189 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4190 free(clp->lc_stateid, M_NFSDCLIENT); 4191 free(clp, M_NFSDCLIENT); 4192 } 4193 if (nd->nd_repstat == 0) { 4194 if (confirm.lval[1] != 0) 4195 v41flags |= NFSV4EXCH_CONFIRMEDR; 4196 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 4197 *tl++ = clientid.lval[0]; /* ClientID */ 4198 *tl++ = clientid.lval[1]; 4199 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 4200 *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 4201 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 4202 owner_minor = 0; /* Owner */ 4203 txdr_hyper(owner_minor, tl); /* Minor */ 4204 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 4205 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 4206 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 4207 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Scope */ 4208 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4209 *tl = txdr_unsigned(1); 4210 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4211 (void)nfsm_strtom(nd, version, strlen(version)); 4212 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4213 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4214 verstime.tv_nsec = 0; 4215 txdr_nfsv4time(&verstime, tl); 4216 } 4217 NFSEXITCODE2(0, nd); 4218 return (0); 4219 nfsmout: 4220 if (clp != NULL) { 4221 free(clp->lc_req.nr_nam, M_SONAME); 4222 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 4223 free(clp->lc_stateid, M_NFSDCLIENT); 4224 free(clp, M_NFSDCLIENT); 4225 } 4226 NFSEXITCODE2(error, nd); 4227 return (error); 4228 } 4229 4230 /* 4231 * nfsv4 create session service 4232 */ 4233 int 4234 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 4235 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4236 { 4237 uint32_t *tl; 4238 int error = 0; 4239 nfsquad_t clientid, confirm; 4240 struct nfsdsession *sep = NULL; 4241 uint32_t rdmacnt; 4242 struct thread *p = curthread; 4243 4244 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4245 nd->nd_repstat = NFSERR_WRONGSEC; 4246 goto nfsmout; 4247 } 4248 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 4249 M_NFSDSESSION, M_WAITOK | M_ZERO); 4250 sep->sess_refcnt = 1; 4251 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 4252 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 4253 clientid.lval[0] = *tl++; 4254 clientid.lval[1] = *tl++; 4255 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 4256 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 4257 /* Persistent sessions and RDMA are not supported. */ 4258 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 4259 4260 /* Fore channel attributes. */ 4261 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4262 tl++; /* Header pad always 0. */ 4263 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 4264 if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) { 4265 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR; 4266 printf("Consider increasing kern.ipc.maxsockbuf\n"); 4267 } 4268 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 4269 if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) { 4270 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR; 4271 printf("Consider increasing kern.ipc.maxsockbuf\n"); 4272 } 4273 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 4274 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 4275 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 4276 if (sep->sess_maxslots > NFSV4_SLOTS) 4277 sep->sess_maxslots = NFSV4_SLOTS; 4278 rdmacnt = fxdr_unsigned(uint32_t, *tl); 4279 if (rdmacnt > 1) { 4280 nd->nd_repstat = NFSERR_BADXDR; 4281 goto nfsmout; 4282 } else if (rdmacnt == 1) 4283 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4284 4285 /* Back channel attributes. */ 4286 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4287 tl++; /* Header pad always 0. */ 4288 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 4289 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 4290 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 4291 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 4292 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 4293 rdmacnt = fxdr_unsigned(uint32_t, *tl); 4294 if (rdmacnt > 1) { 4295 nd->nd_repstat = NFSERR_BADXDR; 4296 goto nfsmout; 4297 } else if (rdmacnt == 1) 4298 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4299 4300 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4301 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 4302 4303 /* 4304 * nfsrv_getclient() searches the client list for a match and 4305 * returns the appropriate NFSERR status. 4306 */ 4307 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 4308 NULL, sep, confirm, sep->sess_cbprogram, nd, p); 4309 if (nd->nd_repstat == 0) { 4310 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4311 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 4312 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 4313 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 4314 *tl++ = txdr_unsigned(sep->sess_crflags); 4315 4316 /* Fore channel attributes. */ 4317 *tl++ = 0; 4318 *tl++ = txdr_unsigned(sep->sess_maxreq); 4319 *tl++ = txdr_unsigned(sep->sess_maxresp); 4320 *tl++ = txdr_unsigned(sep->sess_maxrespcached); 4321 *tl++ = txdr_unsigned(sep->sess_maxops); 4322 *tl++ = txdr_unsigned(sep->sess_maxslots); 4323 *tl++ = txdr_unsigned(1); 4324 *tl++ = txdr_unsigned(0); /* No RDMA. */ 4325 4326 /* Back channel attributes. */ 4327 *tl++ = 0; 4328 *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 4329 *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 4330 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 4331 *tl++ = txdr_unsigned(sep->sess_cbmaxops); 4332 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 4333 *tl++ = txdr_unsigned(1); 4334 *tl = txdr_unsigned(0); /* No RDMA. */ 4335 } 4336 nfsmout: 4337 if (nd->nd_repstat != 0 && sep != NULL) 4338 free(sep, M_NFSDSESSION); 4339 NFSEXITCODE2(error, nd); 4340 return (error); 4341 } 4342 4343 /* 4344 * nfsv4 sequence service 4345 */ 4346 int 4347 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 4348 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4349 { 4350 uint32_t *tl; 4351 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 4352 int cache_this, error = 0; 4353 struct thread *p = curthread; 4354 4355 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4356 nd->nd_repstat = NFSERR_WRONGSEC; 4357 goto nfsmout; 4358 } 4359 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 4360 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 4361 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4362 sequenceid = fxdr_unsigned(uint32_t, *tl++); 4363 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 4364 highest_slotid = fxdr_unsigned(uint32_t, *tl++); 4365 if (*tl == newnfs_true) 4366 cache_this = 1; 4367 else 4368 cache_this = 0; 4369 nd->nd_flag |= ND_HASSEQUENCE; 4370 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 4371 &target_highest_slotid, cache_this, &sflags, p); 4372 if (nd->nd_repstat == 0) { 4373 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4374 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 4375 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 4376 *tl++ = txdr_unsigned(sequenceid); 4377 *tl++ = txdr_unsigned(nd->nd_slotid); 4378 *tl++ = txdr_unsigned(highest_slotid); 4379 *tl++ = txdr_unsigned(target_highest_slotid); 4380 *tl = txdr_unsigned(sflags); 4381 } 4382 nfsmout: 4383 NFSEXITCODE2(error, nd); 4384 return (error); 4385 } 4386 4387 /* 4388 * nfsv4 reclaim complete service 4389 */ 4390 int 4391 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 4392 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4393 { 4394 uint32_t *tl; 4395 int error = 0, onefs; 4396 4397 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4398 nd->nd_repstat = NFSERR_WRONGSEC; 4399 goto nfsmout; 4400 } 4401 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4402 /* 4403 * I believe that a ReclaimComplete with rca_one_fs == TRUE is only 4404 * to be used after a file system has been transferred to a different 4405 * file server. However, RFC5661 is somewhat vague w.r.t. this and 4406 * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs 4407 * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE. 4408 * Therefore, just ignore the rca_one_fs == TRUE operation and return 4409 * NFS_OK without doing anything. 4410 */ 4411 onefs = 0; 4412 if (*tl == newnfs_true) 4413 onefs = 1; 4414 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs); 4415 nfsmout: 4416 NFSEXITCODE2(error, nd); 4417 return (error); 4418 } 4419 4420 /* 4421 * nfsv4 destroy clientid service 4422 */ 4423 int 4424 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4425 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4426 { 4427 uint32_t *tl; 4428 nfsquad_t clientid; 4429 int error = 0; 4430 struct thread *p = curthread; 4431 4432 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4433 nd->nd_repstat = NFSERR_WRONGSEC; 4434 goto nfsmout; 4435 } 4436 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4437 clientid.lval[0] = *tl++; 4438 clientid.lval[1] = *tl; 4439 nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4440 nfsmout: 4441 NFSEXITCODE2(error, nd); 4442 return (error); 4443 } 4444 4445 /* 4446 * nfsv4 bind connection to session service 4447 */ 4448 int 4449 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram, 4450 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4451 { 4452 uint32_t *tl; 4453 uint8_t sessid[NFSX_V4SESSIONID]; 4454 int error = 0, foreaft; 4455 4456 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4457 nd->nd_repstat = NFSERR_WRONGSEC; 4458 goto nfsmout; 4459 } 4460 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 4461 NFSBCOPY(tl, sessid, NFSX_V4SESSIONID); 4462 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4463 foreaft = fxdr_unsigned(int, *tl++); 4464 if (*tl == newnfs_true) { 4465 /* RDMA is not supported. */ 4466 nd->nd_repstat = NFSERR_NOTSUPP; 4467 goto nfsmout; 4468 } 4469 4470 nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft); 4471 if (nd->nd_repstat == 0) { 4472 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * 4473 NFSX_UNSIGNED); 4474 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID); 4475 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED); 4476 *tl++ = txdr_unsigned(foreaft); 4477 *tl = newnfs_false; 4478 } 4479 nfsmout: 4480 NFSEXITCODE2(error, nd); 4481 return (error); 4482 } 4483 4484 /* 4485 * nfsv4 destroy session service 4486 */ 4487 int 4488 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4489 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4490 { 4491 uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4492 int error = 0; 4493 4494 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4495 nd->nd_repstat = NFSERR_WRONGSEC; 4496 goto nfsmout; 4497 } 4498 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4499 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4500 nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4501 nfsmout: 4502 NFSEXITCODE2(error, nd); 4503 return (error); 4504 } 4505 4506 /* 4507 * nfsv4 free stateid service 4508 */ 4509 int 4510 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4511 __unused vnode_t vp, __unused struct nfsexstuff *exp) 4512 { 4513 uint32_t *tl; 4514 nfsv4stateid_t stateid; 4515 int error = 0; 4516 struct thread *p = curthread; 4517 4518 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4519 nd->nd_repstat = NFSERR_WRONGSEC; 4520 goto nfsmout; 4521 } 4522 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4523 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4524 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4525 4526 /* 4527 * For the special stateid of other all 0s and seqid == 1, set the 4528 * stateid to the current stateid, if it is set. 4529 */ 4530 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4531 stateid.other[1] == 0 && stateid.other[2] == 0) { 4532 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4533 stateid = nd->nd_curstateid; 4534 stateid.seqid = 0; 4535 } else { 4536 nd->nd_repstat = NFSERR_BADSTATEID; 4537 goto nfsmout; 4538 } 4539 } 4540 4541 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 4542 4543 /* If the current stateid has been free'd, unset it. */ 4544 if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 && 4545 stateid.other[0] == nd->nd_curstateid.other[0] && 4546 stateid.other[1] == nd->nd_curstateid.other[1] && 4547 stateid.other[2] == nd->nd_curstateid.other[2]) 4548 nd->nd_flag &= ~ND_CURSTATEID; 4549 nfsmout: 4550 NFSEXITCODE2(error, nd); 4551 return (error); 4552 } 4553 4554 /* 4555 * nfsv4 layoutget service 4556 */ 4557 int 4558 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram, 4559 vnode_t vp, struct nfsexstuff *exp) 4560 { 4561 uint32_t *tl; 4562 nfsv4stateid_t stateid; 4563 int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose; 4564 uint64_t offset, len, minlen; 4565 char *layp; 4566 struct thread *p = curthread; 4567 4568 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4569 nd->nd_repstat = NFSERR_WRONGSEC; 4570 goto nfsmout; 4571 } 4572 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 4573 NFSX_STATEID); 4574 tl++; /* Signal layout available. Ignore for now. */ 4575 layouttype = fxdr_unsigned(int, *tl++); 4576 iomode = fxdr_unsigned(int, *tl++); 4577 offset = fxdr_hyper(tl); tl += 2; 4578 len = fxdr_hyper(tl); tl += 2; 4579 minlen = fxdr_hyper(tl); tl += 2; 4580 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4581 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4582 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4583 maxcnt = fxdr_unsigned(int, *tl); 4584 NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n", 4585 layouttype, iomode, (uintmax_t)offset, (uintmax_t)len, 4586 (uintmax_t)minlen); 4587 if (len < minlen || 4588 (minlen != UINT64_MAX && offset + minlen < offset) || 4589 (len != UINT64_MAX && offset + len < offset)) { 4590 nd->nd_repstat = NFSERR_INVAL; 4591 goto nfsmout; 4592 } 4593 4594 /* 4595 * For the special stateid of other all 0s and seqid == 1, set the 4596 * stateid to the current stateid, if it is set. 4597 */ 4598 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4599 stateid.other[1] == 0 && stateid.other[2] == 0) { 4600 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4601 stateid = nd->nd_curstateid; 4602 stateid.seqid = 0; 4603 } else { 4604 nd->nd_repstat = NFSERR_BADSTATEID; 4605 goto nfsmout; 4606 } 4607 } 4608 4609 layp = NULL; 4610 if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1) 4611 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK); 4612 else if (layouttype == NFSLAYOUT_FLEXFILE) 4613 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP, 4614 M_WAITOK); 4615 else 4616 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE; 4617 if (layp != NULL) 4618 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype, 4619 &iomode, &offset, &len, minlen, &stateid, maxcnt, 4620 &retonclose, &layoutlen, layp, nd->nd_cred, p); 4621 NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat, 4622 layoutlen); 4623 if (nd->nd_repstat == 0) { 4624 /* For NFSv4.1, set the Current StateID. */ 4625 if ((nd->nd_flag & ND_NFSV41) != 0) { 4626 nd->nd_curstateid = stateid; 4627 nd->nd_flag |= ND_CURSTATEID; 4628 } 4629 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID + 4630 2 * NFSX_HYPER); 4631 *tl++ = txdr_unsigned(retonclose); 4632 *tl++ = txdr_unsigned(stateid.seqid); 4633 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 4634 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4635 *tl++ = txdr_unsigned(1); /* Only returns one layout. */ 4636 txdr_hyper(offset, tl); tl += 2; 4637 txdr_hyper(len, tl); tl += 2; 4638 *tl++ = txdr_unsigned(iomode); 4639 *tl = txdr_unsigned(layouttype); 4640 nfsm_strtom(nd, layp, layoutlen); 4641 } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) { 4642 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4643 *tl = newnfs_false; 4644 } 4645 free(layp, M_TEMP); 4646 nfsmout: 4647 vput(vp); 4648 NFSEXITCODE2(error, nd); 4649 return (error); 4650 } 4651 4652 /* 4653 * nfsv4 layoutcommit service 4654 */ 4655 int 4656 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram, 4657 vnode_t vp, struct nfsexstuff *exp) 4658 { 4659 uint32_t *tl; 4660 nfsv4stateid_t stateid; 4661 int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim; 4662 int hasnewsize; 4663 uint64_t offset, len, newoff = 0, newsize; 4664 struct timespec newmtime; 4665 char *layp; 4666 struct thread *p = curthread; 4667 4668 layp = NULL; 4669 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4670 nd->nd_repstat = NFSERR_WRONGSEC; 4671 goto nfsmout; 4672 } 4673 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER + 4674 NFSX_STATEID); 4675 offset = fxdr_hyper(tl); tl += 2; 4676 len = fxdr_hyper(tl); tl += 2; 4677 reclaim = fxdr_unsigned(int, *tl++); 4678 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4679 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4680 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4681 /* 4682 * For the special stateid of other all 0s and seqid == 1, set the 4683 * stateid to the current stateid, if it is set. 4684 */ 4685 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4686 stateid.other[1] == 0 && stateid.other[2] == 0) { 4687 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4688 stateid = nd->nd_curstateid; 4689 stateid.seqid = 0; 4690 } else { 4691 nd->nd_repstat = NFSERR_BADSTATEID; 4692 goto nfsmout; 4693 } 4694 } 4695 4696 hasnewoff = fxdr_unsigned(int, *tl); 4697 if (hasnewoff != 0) { 4698 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 4699 newoff = fxdr_hyper(tl); tl += 2; 4700 } else 4701 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4702 hasnewmtime = fxdr_unsigned(int, *tl); 4703 if (hasnewmtime != 0) { 4704 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED); 4705 fxdr_nfsv4time(tl, &newmtime); 4706 tl += (NFSX_V4TIME / NFSX_UNSIGNED); 4707 } else 4708 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4709 layouttype = fxdr_unsigned(int, *tl++); 4710 maxcnt = fxdr_unsigned(int, *tl); 4711 if (maxcnt > 0) { 4712 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 4713 error = nfsrv_mtostr(nd, layp, maxcnt); 4714 if (error != 0) 4715 goto nfsmout; 4716 } 4717 nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff, 4718 newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid, 4719 maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p); 4720 NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat); 4721 if (nd->nd_repstat == 0) { 4722 if (hasnewsize != 0) { 4723 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 4724 *tl++ = newnfs_true; 4725 txdr_hyper(newsize, tl); 4726 } else { 4727 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4728 *tl = newnfs_false; 4729 } 4730 } 4731 nfsmout: 4732 free(layp, M_TEMP); 4733 vput(vp); 4734 NFSEXITCODE2(error, nd); 4735 return (error); 4736 } 4737 4738 /* 4739 * nfsv4 layoutreturn service 4740 */ 4741 int 4742 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram, 4743 vnode_t vp, struct nfsexstuff *exp) 4744 { 4745 uint32_t *tl, *layp; 4746 nfsv4stateid_t stateid; 4747 int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim; 4748 uint64_t offset, len; 4749 struct thread *p = curthread; 4750 4751 layp = NULL; 4752 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4753 nd->nd_repstat = NFSERR_WRONGSEC; 4754 goto nfsmout; 4755 } 4756 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4757 reclaim = *tl++; 4758 layouttype = fxdr_unsigned(int, *tl++); 4759 iomode = fxdr_unsigned(int, *tl++); 4760 kind = fxdr_unsigned(int, *tl); 4761 NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim, 4762 layouttype, iomode, kind); 4763 if (kind == NFSV4LAYOUTRET_FILE) { 4764 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 4765 NFSX_UNSIGNED); 4766 offset = fxdr_hyper(tl); tl += 2; 4767 len = fxdr_hyper(tl); tl += 2; 4768 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4769 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4770 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4771 4772 /* 4773 * For the special stateid of other all 0s and seqid == 1, set 4774 * the stateid to the current stateid, if it is set. 4775 */ 4776 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4777 stateid.other[1] == 0 && stateid.other[2] == 0) { 4778 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4779 stateid = nd->nd_curstateid; 4780 stateid.seqid = 0; 4781 } else { 4782 nd->nd_repstat = NFSERR_BADSTATEID; 4783 goto nfsmout; 4784 } 4785 } 4786 4787 maxcnt = fxdr_unsigned(int, *tl); 4788 if (maxcnt > 0) { 4789 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK); 4790 error = nfsrv_mtostr(nd, (char *)layp, maxcnt); 4791 if (error != 0) 4792 goto nfsmout; 4793 } 4794 } else { 4795 if (reclaim == newnfs_true) { 4796 nd->nd_repstat = NFSERR_INVAL; 4797 goto nfsmout; 4798 } 4799 offset = len = 0; 4800 maxcnt = 0; 4801 } 4802 nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode, 4803 offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd, 4804 nd->nd_cred, p); 4805 NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat, 4806 fnd); 4807 if (nd->nd_repstat == 0) { 4808 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4809 if (fnd != 0) { 4810 *tl = newnfs_true; 4811 NFSM_BUILD(tl, uint32_t *, NFSX_STATEID); 4812 *tl++ = txdr_unsigned(stateid.seqid); 4813 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER); 4814 } else 4815 *tl = newnfs_false; 4816 } 4817 nfsmout: 4818 free(layp, M_TEMP); 4819 vput(vp); 4820 NFSEXITCODE2(error, nd); 4821 return (error); 4822 } 4823 4824 /* 4825 * nfsv4 layout error service 4826 */ 4827 int 4828 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram, 4829 vnode_t vp, struct nfsexstuff *exp) 4830 { 4831 uint32_t *tl; 4832 nfsv4stateid_t stateid; 4833 int cnt, error = 0, i, stat; 4834 int opnum __unused; 4835 char devid[NFSX_V4DEVICEID]; 4836 uint64_t offset, len; 4837 4838 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4839 nd->nd_repstat = NFSERR_WRONGSEC; 4840 goto nfsmout; 4841 } 4842 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 4843 NFSX_UNSIGNED); 4844 offset = fxdr_hyper(tl); tl += 2; 4845 len = fxdr_hyper(tl); tl += 2; 4846 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4847 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4848 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4849 cnt = fxdr_unsigned(int, *tl); 4850 NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset, 4851 (uintmax_t)len, cnt); 4852 /* 4853 * For the special stateid of other all 0s and seqid == 1, set 4854 * the stateid to the current stateid, if it is set. 4855 */ 4856 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4857 stateid.other[1] == 0 && stateid.other[2] == 0) { 4858 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4859 stateid = nd->nd_curstateid; 4860 stateid.seqid = 0; 4861 } else { 4862 nd->nd_repstat = NFSERR_BADSTATEID; 4863 goto nfsmout; 4864 } 4865 } 4866 4867 /* 4868 * Ignore offset, len and stateid for now. 4869 */ 4870 for (i = 0; i < cnt; i++) { 4871 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 * 4872 NFSX_UNSIGNED); 4873 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 4874 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 4875 stat = fxdr_unsigned(int, *tl++); 4876 opnum = fxdr_unsigned(int, *tl); 4877 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat); 4878 /* 4879 * Except for NFSERR_ACCES and NFSERR_STALE errors, 4880 * disable the mirror. 4881 */ 4882 if (stat != NFSERR_ACCES && stat != NFSERR_STALE) 4883 nfsrv_delds(devid, curthread); 4884 } 4885 nfsmout: 4886 vput(vp); 4887 NFSEXITCODE2(error, nd); 4888 return (error); 4889 } 4890 4891 /* 4892 * nfsv4 layout stats service 4893 */ 4894 int 4895 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram, 4896 vnode_t vp, struct nfsexstuff *exp) 4897 { 4898 uint32_t *tl; 4899 nfsv4stateid_t stateid; 4900 int cnt, error = 0; 4901 int layouttype __unused; 4902 char devid[NFSX_V4DEVICEID] __unused; 4903 uint64_t offset, len, readcount, readbytes, writecount, writebytes 4904 __unused; 4905 4906 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4907 nd->nd_repstat = NFSERR_WRONGSEC; 4908 goto nfsmout; 4909 } 4910 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID + 4911 NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED); 4912 offset = fxdr_hyper(tl); tl += 2; 4913 len = fxdr_hyper(tl); tl += 2; 4914 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4915 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4916 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4917 readcount = fxdr_hyper(tl); tl += 2; 4918 readbytes = fxdr_hyper(tl); tl += 2; 4919 writecount = fxdr_hyper(tl); tl += 2; 4920 writebytes = fxdr_hyper(tl); tl += 2; 4921 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 4922 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 4923 layouttype = fxdr_unsigned(int, *tl++); 4924 cnt = fxdr_unsigned(int, *tl); 4925 error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1); 4926 if (error != 0) 4927 goto nfsmout; 4928 NFSD_DEBUG(4, "layoutstats cnt=%d\n", cnt); 4929 /* 4930 * For the special stateid of other all 0s and seqid == 1, set 4931 * the stateid to the current stateid, if it is set. 4932 */ 4933 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4934 stateid.other[1] == 0 && stateid.other[2] == 0) { 4935 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4936 stateid = nd->nd_curstateid; 4937 stateid.seqid = 0; 4938 } else { 4939 nd->nd_repstat = NFSERR_BADSTATEID; 4940 goto nfsmout; 4941 } 4942 } 4943 4944 /* 4945 * No use for the stats for now. 4946 */ 4947 nfsmout: 4948 vput(vp); 4949 NFSEXITCODE2(error, nd); 4950 return (error); 4951 } 4952 4953 /* 4954 * nfsv4 io_advise service 4955 */ 4956 int 4957 nfsrvd_ioadvise(struct nfsrv_descript *nd, __unused int isdgram, 4958 vnode_t vp, struct nfsexstuff *exp) 4959 { 4960 uint32_t *tl; 4961 nfsv4stateid_t stateid; 4962 nfsattrbit_t hints; 4963 int error = 0, ret; 4964 off_t offset, len; 4965 4966 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4967 nd->nd_repstat = NFSERR_WRONGSEC; 4968 goto nfsmout; 4969 } 4970 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 4971 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4972 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4973 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 4974 offset = fxdr_hyper(tl); tl += 2; 4975 len = fxdr_hyper(tl); 4976 error = nfsrv_getattrbits(nd, &hints, NULL, NULL); 4977 if (error != 0) 4978 goto nfsmout; 4979 /* 4980 * For the special stateid of other all 0s and seqid == 1, set 4981 * the stateid to the current stateid, if it is set. 4982 */ 4983 if (stateid.seqid == 1 && stateid.other[0] == 0 && 4984 stateid.other[1] == 0 && stateid.other[2] == 0) { 4985 if ((nd->nd_flag & ND_CURSTATEID) != 0) { 4986 stateid = nd->nd_curstateid; 4987 stateid.seqid = 0; 4988 } else { 4989 nd->nd_repstat = NFSERR_BADSTATEID; 4990 goto nfsmout; 4991 } 4992 } 4993 4994 if (offset < 0) { 4995 nd->nd_repstat = NFSERR_INVAL; 4996 goto nfsmout; 4997 } 4998 if (len < 0) 4999 len = 0; 5000 if (vp->v_type != VREG) { 5001 if (vp->v_type == VDIR) 5002 nd->nd_repstat = NFSERR_ISDIR; 5003 else 5004 nd->nd_repstat = NFSERR_WRONGTYPE; 5005 goto nfsmout; 5006 } 5007 5008 /* 5009 * For now, we can only handle WILLNEED and DONTNEED and don't use 5010 * the stateid. 5011 */ 5012 if ((NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED) && 5013 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED)) || 5014 (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED) && 5015 !NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED))) { 5016 NFSVOPUNLOCK(vp); 5017 if (NFSISSET_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED)) { 5018 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_WILLNEED); 5019 NFSZERO_ATTRBIT(&hints); 5020 if (ret == 0) 5021 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 5022 else 5023 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5024 } else { 5025 ret = VOP_ADVISE(vp, offset, len, POSIX_FADV_DONTNEED); 5026 NFSZERO_ATTRBIT(&hints); 5027 if (ret == 0) 5028 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 5029 else 5030 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5031 } 5032 vrele(vp); 5033 } else { 5034 NFSZERO_ATTRBIT(&hints); 5035 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_NORMAL); 5036 vput(vp); 5037 } 5038 nfsrv_putattrbit(nd, &hints); 5039 NFSEXITCODE2(error, nd); 5040 return (error); 5041 nfsmout: 5042 vput(vp); 5043 NFSEXITCODE2(error, nd); 5044 return (error); 5045 } 5046 5047 /* 5048 * nfsv4 getdeviceinfo service 5049 */ 5050 int 5051 nfsrvd_getdevinfo(struct nfsrv_descript *nd, __unused int isdgram, 5052 __unused vnode_t vp, __unused struct nfsexstuff *exp) 5053 { 5054 uint32_t *tl, maxcnt, notify[NFSV4_NOTIFYBITMAP]; 5055 int cnt, devaddrlen, error = 0, i, layouttype; 5056 char devid[NFSX_V4DEVICEID], *devaddr; 5057 time_t dev_time; 5058 5059 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5060 nd->nd_repstat = NFSERR_WRONGSEC; 5061 goto nfsmout; 5062 } 5063 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_V4DEVICEID); 5064 NFSBCOPY(tl, devid, NFSX_V4DEVICEID); 5065 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5066 layouttype = fxdr_unsigned(int, *tl++); 5067 maxcnt = fxdr_unsigned(uint32_t, *tl++); 5068 cnt = fxdr_unsigned(int, *tl); 5069 NFSD_DEBUG(4, "getdevinfo ltyp=%d maxcnt=%u bitcnt=%d\n", layouttype, 5070 maxcnt, cnt); 5071 if (cnt > NFSV4_NOTIFYBITMAP || cnt < 0) { 5072 nd->nd_repstat = NFSERR_INVAL; 5073 goto nfsmout; 5074 } 5075 if (cnt > 0) { 5076 NFSM_DISSECT(tl, uint32_t *, cnt * NFSX_UNSIGNED); 5077 for (i = 0; i < cnt; i++) 5078 notify[i] = fxdr_unsigned(uint32_t, *tl++); 5079 } 5080 for (i = cnt; i < NFSV4_NOTIFYBITMAP; i++) 5081 notify[i] = 0; 5082 5083 /* 5084 * Check that the device id is not stale. Device ids are recreated 5085 * each time the nfsd threads are restarted. 5086 */ 5087 NFSBCOPY(devid, &dev_time, sizeof(dev_time)); 5088 if (dev_time != nfsdev_time) { 5089 nd->nd_repstat = NFSERR_NOENT; 5090 goto nfsmout; 5091 } 5092 5093 /* Look for the device id. */ 5094 nd->nd_repstat = nfsrv_getdevinfo(devid, layouttype, &maxcnt, 5095 notify, &devaddrlen, &devaddr); 5096 NFSD_DEBUG(4, "nfsrv_getdevinfo stat=%u\n", nd->nd_repstat); 5097 if (nd->nd_repstat == 0) { 5098 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5099 *tl = txdr_unsigned(layouttype); 5100 nfsm_strtom(nd, devaddr, devaddrlen); 5101 cnt = 0; 5102 for (i = 0; i < NFSV4_NOTIFYBITMAP; i++) { 5103 if (notify[i] != 0) 5104 cnt = i + 1; 5105 } 5106 NFSM_BUILD(tl, uint32_t *, (cnt + 1) * NFSX_UNSIGNED); 5107 *tl++ = txdr_unsigned(cnt); 5108 for (i = 0; i < cnt; i++) 5109 *tl++ = txdr_unsigned(notify[i]); 5110 } else if (nd->nd_repstat == NFSERR_TOOSMALL) { 5111 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5112 *tl = txdr_unsigned(maxcnt); 5113 } 5114 nfsmout: 5115 NFSEXITCODE2(error, nd); 5116 return (error); 5117 } 5118 5119 /* 5120 * nfsv4 test stateid service 5121 */ 5122 int 5123 nfsrvd_teststateid(struct nfsrv_descript *nd, __unused int isdgram, 5124 __unused vnode_t vp, __unused struct nfsexstuff *exp) 5125 { 5126 uint32_t *tl; 5127 nfsv4stateid_t *stateidp = NULL, *tstateidp; 5128 int cnt, error = 0, i, ret; 5129 struct thread *p = curthread; 5130 5131 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5132 nd->nd_repstat = NFSERR_WRONGSEC; 5133 goto nfsmout; 5134 } 5135 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5136 cnt = fxdr_unsigned(int, *tl); 5137 if (cnt <= 0 || cnt > 1024) { 5138 nd->nd_repstat = NFSERR_BADXDR; 5139 goto nfsmout; 5140 } 5141 stateidp = mallocarray(cnt, sizeof(nfsv4stateid_t), M_TEMP, M_WAITOK); 5142 tstateidp = stateidp; 5143 for (i = 0; i < cnt; i++) { 5144 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5145 tstateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5146 NFSBCOPY(tl, tstateidp->other, NFSX_STATEIDOTHER); 5147 tstateidp++; 5148 } 5149 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5150 *tl = txdr_unsigned(cnt); 5151 tstateidp = stateidp; 5152 for (i = 0; i < cnt; i++) { 5153 ret = nfsrv_teststateid(nd, tstateidp, p); 5154 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5155 *tl = txdr_unsigned(ret); 5156 tstateidp++; 5157 } 5158 nfsmout: 5159 free(stateidp, M_TEMP); 5160 NFSEXITCODE2(error, nd); 5161 return (error); 5162 } 5163 5164 /* 5165 * nfs allocate service 5166 */ 5167 int 5168 nfsrvd_allocate(struct nfsrv_descript *nd, __unused int isdgram, 5169 vnode_t vp, struct nfsexstuff *exp) 5170 { 5171 uint32_t *tl; 5172 struct nfsvattr forat; 5173 int error = 0, forat_ret = 1, gotproxystateid; 5174 off_t off, len; 5175 struct nfsstate st, *stp = &st; 5176 struct nfslock lo, *lop = &lo; 5177 nfsv4stateid_t stateid; 5178 nfsquad_t clientid; 5179 nfsattrbit_t attrbits; 5180 5181 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5182 nd->nd_repstat = NFSERR_WRONGSEC; 5183 goto nfsmout; 5184 } 5185 gotproxystateid = 0; 5186 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + 2 * NFSX_HYPER); 5187 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5188 lop->lo_flags = NFSLCK_WRITE; 5189 stp->ls_ownerlen = 0; 5190 stp->ls_op = NULL; 5191 stp->ls_uid = nd->nd_cred->cr_uid; 5192 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 5193 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 5194 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 5195 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 5196 if ((nd->nd_flag & ND_NFSV41) != 0) 5197 clientid.qval = nd->nd_clientid.qval; 5198 else if (nd->nd_clientid.qval != clientid.qval) 5199 printf("EEK2 multiple clids\n"); 5200 } else { 5201 if ((nd->nd_flag & ND_NFSV41) != 0) 5202 printf("EEK! no clientid from session\n"); 5203 nd->nd_flag |= ND_IMPLIEDCLID; 5204 nd->nd_clientid.qval = clientid.qval; 5205 } 5206 stp->ls_stateid.other[2] = *tl++; 5207 /* 5208 * Don't allow this to be done for a DS. 5209 */ 5210 if ((nd->nd_flag & ND_DSSERVER) != 0) 5211 nd->nd_repstat = NFSERR_NOTSUPP; 5212 /* However, allow the proxy stateid. */ 5213 if (stp->ls_stateid.seqid == 0xffffffff && 5214 stp->ls_stateid.other[0] == 0x55555555 && 5215 stp->ls_stateid.other[1] == 0x55555555 && 5216 stp->ls_stateid.other[2] == 0x55555555) 5217 gotproxystateid = 1; 5218 off = fxdr_hyper(tl); tl += 2; 5219 lop->lo_first = off; 5220 len = fxdr_hyper(tl); 5221 lop->lo_end = off + len; 5222 /* 5223 * Paranoia, just in case it wraps around, which shouldn't 5224 * ever happen anyhow. 5225 */ 5226 if (nd->nd_repstat == 0 && (lop->lo_end < lop->lo_first || len <= 0)) 5227 nd->nd_repstat = NFSERR_INVAL; 5228 5229 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5230 nd->nd_repstat = NFSERR_WRONGTYPE; 5231 NFSZERO_ATTRBIT(&attrbits); 5232 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5233 forat_ret = nfsvno_getattr(vp, &forat, nd, curthread, 1, &attrbits); 5234 if (nd->nd_repstat == 0) 5235 nd->nd_repstat = forat_ret; 5236 if (nd->nd_repstat == 0 && (forat.na_uid != nd->nd_cred->cr_uid || 5237 NFSVNO_EXSTRICTACCESS(exp))) 5238 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, 5239 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5240 NULL); 5241 if (nd->nd_repstat == 0 && gotproxystateid == 0) 5242 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 5243 &stateid, exp, nd, curthread); 5244 5245 if (nd->nd_repstat == 0) 5246 nd->nd_repstat = nfsvno_allocate(vp, off, len, nd->nd_cred, 5247 curthread); 5248 vput(vp); 5249 NFSEXITCODE2(0, nd); 5250 return (0); 5251 nfsmout: 5252 vput(vp); 5253 NFSEXITCODE2(error, nd); 5254 return (error); 5255 } 5256 5257 /* 5258 * nfs copy service 5259 */ 5260 int 5261 nfsrvd_copy_file_range(struct nfsrv_descript *nd, __unused int isdgram, 5262 vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp) 5263 { 5264 uint32_t *tl; 5265 struct nfsvattr at; 5266 int cnt, error = 0, ret; 5267 off_t inoff, outoff; 5268 uint64_t len; 5269 size_t xfer; 5270 struct nfsstate inst, outst, *instp = &inst, *outstp = &outst; 5271 struct nfslock inlo, outlo, *inlop = &inlo, *outlop = &outlo; 5272 nfsquad_t clientid; 5273 nfsv4stateid_t stateid; 5274 nfsattrbit_t attrbits; 5275 void *rl_rcookie, *rl_wcookie; 5276 5277 rl_rcookie = rl_wcookie = NULL; 5278 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5279 nd->nd_repstat = NFSERR_WRONGSEC; 5280 goto nfsmout; 5281 } 5282 if (nfsrv_devidcnt > 0) { 5283 /* 5284 * For a pNFS server, reply NFSERR_NOTSUPP so that the client 5285 * will do the copy via I/O on the DS(s). 5286 */ 5287 nd->nd_repstat = NFSERR_NOTSUPP; 5288 goto nfsmout; 5289 } 5290 if (vp == tovp) { 5291 /* Copying a byte range within the same file is not allowed. */ 5292 nd->nd_repstat = NFSERR_INVAL; 5293 goto nfsmout; 5294 } 5295 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_STATEID + 3 * NFSX_HYPER + 5296 3 * NFSX_UNSIGNED); 5297 instp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 5298 inlop->lo_flags = NFSLCK_READ; 5299 instp->ls_ownerlen = 0; 5300 instp->ls_op = NULL; 5301 instp->ls_uid = nd->nd_cred->cr_uid; 5302 instp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5303 clientid.lval[0] = instp->ls_stateid.other[0] = *tl++; 5304 clientid.lval[1] = instp->ls_stateid.other[1] = *tl++; 5305 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) 5306 clientid.qval = nd->nd_clientid.qval; 5307 instp->ls_stateid.other[2] = *tl++; 5308 outstp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 5309 outlop->lo_flags = NFSLCK_WRITE; 5310 outstp->ls_ownerlen = 0; 5311 outstp->ls_op = NULL; 5312 outstp->ls_uid = nd->nd_cred->cr_uid; 5313 outstp->ls_stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 5314 outstp->ls_stateid.other[0] = *tl++; 5315 outstp->ls_stateid.other[1] = *tl++; 5316 outstp->ls_stateid.other[2] = *tl++; 5317 inoff = fxdr_hyper(tl); tl += 2; 5318 inlop->lo_first = inoff; 5319 outoff = fxdr_hyper(tl); tl += 2; 5320 outlop->lo_first = outoff; 5321 len = fxdr_hyper(tl); tl += 2; 5322 if (len == 0) { 5323 /* len == 0 means to EOF. */ 5324 inlop->lo_end = OFF_MAX; 5325 outlop->lo_end = OFF_MAX; 5326 } else { 5327 inlop->lo_end = inlop->lo_first + len; 5328 outlop->lo_end = outlop->lo_first + len; 5329 } 5330 5331 /* 5332 * At this time only consecutive, synchronous copy is supported, 5333 * so ca_consecutive and ca_synchronous can be ignored. 5334 */ 5335 tl += 2; 5336 5337 cnt = fxdr_unsigned(int, *tl); 5338 if ((nd->nd_flag & ND_DSSERVER) != 0 || cnt != 0) 5339 nd->nd_repstat = NFSERR_NOTSUPP; 5340 if (nd->nd_repstat == 0 && (inoff > OFF_MAX || outoff > OFF_MAX || 5341 inlop->lo_end > OFF_MAX || outlop->lo_end > OFF_MAX || 5342 inlop->lo_end < inlop->lo_first || outlop->lo_end < 5343 outlop->lo_first)) 5344 nd->nd_repstat = NFSERR_INVAL; 5345 5346 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5347 nd->nd_repstat = NFSERR_WRONGTYPE; 5348 5349 /* Check permissions for the input file. */ 5350 NFSZERO_ATTRBIT(&attrbits); 5351 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5352 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, &attrbits); 5353 if (nd->nd_repstat == 0) 5354 nd->nd_repstat = ret; 5355 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5356 NFSVNO_EXSTRICTACCESS(exp))) 5357 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5358 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5359 NULL); 5360 if (nd->nd_repstat == 0) 5361 nd->nd_repstat = nfsrv_lockctrl(vp, &instp, &inlop, NULL, 5362 clientid, &stateid, exp, nd, curthread); 5363 NFSVOPUNLOCK(vp); 5364 if (nd->nd_repstat != 0) 5365 goto out; 5366 5367 error = NFSVOPLOCK(tovp, LK_SHARED); 5368 if (error != 0) 5369 goto out; 5370 if (vnode_vtype(tovp) != VREG) 5371 nd->nd_repstat = NFSERR_WRONGTYPE; 5372 5373 /* For the output file, we only need the Owner attribute. */ 5374 ret = nfsvno_getattr(tovp, &at, nd, curthread, 1, &attrbits); 5375 if (nd->nd_repstat == 0) 5376 nd->nd_repstat = ret; 5377 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5378 NFSVNO_EXSTRICTACCESS(exp))) 5379 nd->nd_repstat = nfsvno_accchk(tovp, VWRITE, nd->nd_cred, toexp, 5380 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5381 NULL); 5382 if (nd->nd_repstat == 0) 5383 nd->nd_repstat = nfsrv_lockctrl(tovp, &outstp, &outlop, NULL, 5384 clientid, &stateid, toexp, nd, curthread); 5385 NFSVOPUNLOCK(tovp); 5386 5387 /* Range lock the byte ranges for both invp and outvp. */ 5388 if (nd->nd_repstat == 0) { 5389 for (;;) { 5390 if (len == 0) { 5391 rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5392 OFF_MAX); 5393 rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5394 OFF_MAX); 5395 } else { 5396 rl_wcookie = vn_rangelock_wlock(tovp, outoff, 5397 outoff + len); 5398 rl_rcookie = vn_rangelock_tryrlock(vp, inoff, 5399 inoff + len); 5400 } 5401 if (rl_rcookie != NULL) 5402 break; 5403 vn_rangelock_unlock(tovp, rl_wcookie); 5404 if (len == 0) 5405 rl_rcookie = vn_rangelock_rlock(vp, inoff, 5406 OFF_MAX); 5407 else 5408 rl_rcookie = vn_rangelock_rlock(vp, inoff, 5409 inoff + len); 5410 vn_rangelock_unlock(vp, rl_rcookie); 5411 } 5412 5413 error = NFSVOPLOCK(vp, LK_SHARED); 5414 if (error == 0) { 5415 ret = nfsvno_getattr(vp, &at, nd, curthread, 1, NULL); 5416 if (ret == 0) { 5417 /* 5418 * Since invp is range locked, na_size should 5419 * not change. 5420 */ 5421 if (len == 0 && at.na_size > inoff) { 5422 /* 5423 * If len == 0, set it based on invp's 5424 * size. If offset is past EOF, just 5425 * leave len == 0. 5426 */ 5427 len = at.na_size - inoff; 5428 } else if (nfsrv_linux42server == 0 && 5429 inoff + len > at.na_size) { 5430 /* 5431 * RFC-7862 says that NFSERR_INVAL must 5432 * be returned when inoff + len exceeds 5433 * the file size, however the NFSv4.2 5434 * Linux client likes to do this, so 5435 * only check if nfsrv_linux42server 5436 * is not set. 5437 */ 5438 nd->nd_repstat = NFSERR_INVAL; 5439 } 5440 } 5441 NFSVOPUNLOCK(vp); 5442 if (ret != 0 && nd->nd_repstat == 0) 5443 nd->nd_repstat = ret; 5444 } else if (nd->nd_repstat == 0) 5445 nd->nd_repstat = error; 5446 } 5447 5448 /* 5449 * Do the actual copy to an upper limit of vfs.nfs.maxcopyrange. 5450 * This limit is applied to ensure that the RPC replies in a 5451 * reasonable time. 5452 */ 5453 if (len > nfs_maxcopyrange) 5454 xfer = nfs_maxcopyrange; 5455 else 5456 xfer = len; 5457 if (nd->nd_repstat == 0) { 5458 nd->nd_repstat = vn_copy_file_range(vp, &inoff, tovp, &outoff, 5459 &xfer, 0, nd->nd_cred, nd->nd_cred, NULL); 5460 if (nd->nd_repstat == 0) 5461 len = xfer; 5462 } 5463 5464 /* Unlock the ranges. */ 5465 if (rl_rcookie != NULL) 5466 vn_rangelock_unlock(vp, rl_rcookie); 5467 if (rl_wcookie != NULL) 5468 vn_rangelock_unlock(tovp, rl_wcookie); 5469 5470 if (nd->nd_repstat == 0) { 5471 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_HYPER + 5472 NFSX_VERF); 5473 *tl++ = txdr_unsigned(0); /* No callback ids. */ 5474 txdr_hyper(len, tl); tl += 2; 5475 *tl++ = txdr_unsigned(NFSWRITE_UNSTABLE); 5476 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 5477 *tl++ = txdr_unsigned(nfsboottime.tv_usec); 5478 *tl++ = newnfs_true; 5479 *tl = newnfs_true; 5480 } 5481 out: 5482 vrele(vp); 5483 vrele(tovp); 5484 NFSEXITCODE2(error, nd); 5485 return (error); 5486 nfsmout: 5487 vput(vp); 5488 vrele(tovp); 5489 NFSEXITCODE2(error, nd); 5490 return (error); 5491 } 5492 5493 /* 5494 * nfs seek service 5495 */ 5496 int 5497 nfsrvd_seek(struct nfsrv_descript *nd, __unused int isdgram, 5498 vnode_t vp, struct nfsexstuff *exp) 5499 { 5500 uint32_t *tl; 5501 struct nfsvattr at; 5502 int content, error = 0; 5503 off_t off; 5504 u_long cmd; 5505 nfsattrbit_t attrbits; 5506 bool eof; 5507 5508 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5509 nd->nd_repstat = NFSERR_WRONGSEC; 5510 goto nfsmout; 5511 } 5512 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID + NFSX_HYPER + NFSX_UNSIGNED); 5513 /* Ignore the stateid for now. */ 5514 tl += (NFSX_STATEID / NFSX_UNSIGNED); 5515 off = fxdr_hyper(tl); tl += 2; 5516 content = fxdr_unsigned(int, *tl); 5517 if (content == NFSV4CONTENT_DATA) 5518 cmd = FIOSEEKDATA; 5519 else if (content == NFSV4CONTENT_HOLE) 5520 cmd = FIOSEEKHOLE; 5521 else 5522 nd->nd_repstat = NFSERR_BADXDR; 5523 if (nd->nd_repstat == 0 && vnode_vtype(vp) == VDIR) 5524 nd->nd_repstat = NFSERR_ISDIR; 5525 if (nd->nd_repstat == 0 && vnode_vtype(vp) != VREG) 5526 nd->nd_repstat = NFSERR_WRONGTYPE; 5527 if (nd->nd_repstat == 0 && off < 0) 5528 nd->nd_repstat = NFSERR_NXIO; 5529 if (nd->nd_repstat == 0) { 5530 /* Check permissions for the input file. */ 5531 NFSZERO_ATTRBIT(&attrbits); 5532 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER); 5533 nd->nd_repstat = nfsvno_getattr(vp, &at, nd, curthread, 1, 5534 &attrbits); 5535 } 5536 if (nd->nd_repstat == 0 && (at.na_uid != nd->nd_cred->cr_uid || 5537 NFSVNO_EXSTRICTACCESS(exp))) 5538 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, 5539 curthread, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, 5540 NULL); 5541 if (nd->nd_repstat != 0) 5542 goto nfsmout; 5543 5544 /* nfsvno_seek() unlocks and vrele()s the vp. */ 5545 nd->nd_repstat = nfsvno_seek(nd, vp, cmd, &off, content, &eof, 5546 nd->nd_cred, curthread); 5547 if (nd->nd_repstat == 0 && eof && content == NFSV4CONTENT_DATA && 5548 nfsrv_linux42server != 0) 5549 nd->nd_repstat = NFSERR_NXIO; 5550 if (nd->nd_repstat == 0) { 5551 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER); 5552 if (eof) 5553 *tl++ = newnfs_true; 5554 else 5555 *tl++ = newnfs_false; 5556 txdr_hyper(off, tl); 5557 } 5558 NFSEXITCODE2(error, nd); 5559 return (error); 5560 nfsmout: 5561 vput(vp); 5562 NFSEXITCODE2(error, nd); 5563 return (error); 5564 } 5565 5566 /* 5567 * nfs get extended attribute service 5568 */ 5569 int 5570 nfsrvd_getxattr(struct nfsrv_descript *nd, __unused int isdgram, 5571 vnode_t vp, __unused struct nfsexstuff *exp) 5572 { 5573 uint32_t *tl; 5574 struct mbuf *mp = NULL, *mpend = NULL; 5575 int error, len; 5576 char *name; 5577 struct thread *p = curthread; 5578 uint16_t off; 5579 5580 error = 0; 5581 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5582 nd->nd_repstat = NFSERR_WRONGSEC; 5583 goto nfsmout; 5584 } 5585 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5586 len = fxdr_unsigned(int, *tl); 5587 if (len <= 0) { 5588 nd->nd_repstat = NFSERR_BADXDR; 5589 goto nfsmout; 5590 } 5591 if (len > EXTATTR_MAXNAMELEN) { 5592 nd->nd_repstat = NFSERR_NOXATTR; 5593 goto nfsmout; 5594 } 5595 name = malloc(len + 1, M_TEMP, M_WAITOK); 5596 nd->nd_repstat = nfsrv_mtostr(nd, name, len); 5597 if (nd->nd_repstat == 0) 5598 nd->nd_repstat = nfsvno_getxattr(vp, name, 5599 nd->nd_maxresp, nd->nd_cred, nd->nd_flag, 5600 nd->nd_maxextsiz, p, &mp, &mpend, &len); 5601 if (nd->nd_repstat == ENOATTR) 5602 nd->nd_repstat = NFSERR_NOXATTR; 5603 else if (nd->nd_repstat == EOPNOTSUPP) 5604 nd->nd_repstat = NFSERR_NOTSUPP; 5605 if (nd->nd_repstat == 0) { 5606 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5607 *tl = txdr_unsigned(len); 5608 if (len > 0) { 5609 nd->nd_mb->m_next = mp; 5610 nd->nd_mb = mpend; 5611 if ((mpend->m_flags & M_EXTPG) != 0) { 5612 nd->nd_flag |= ND_EXTPG; 5613 nd->nd_bextpg = mpend->m_epg_npgs - 1; 5614 nd->nd_bpos = (char *)(void *) 5615 PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]); 5616 off = (nd->nd_bextpg == 0) ? 5617 mpend->m_epg_1st_off : 0; 5618 nd->nd_bpos += off + mpend->m_epg_last_len; 5619 nd->nd_bextpgsiz = PAGE_SIZE - 5620 mpend->m_epg_last_len - off; 5621 } else 5622 nd->nd_bpos = mtod(mpend, char *) + 5623 mpend->m_len; 5624 } 5625 } 5626 free(name, M_TEMP); 5627 5628 nfsmout: 5629 if (nd->nd_repstat == 0) 5630 nd->nd_repstat = error; 5631 vput(vp); 5632 NFSEXITCODE2(0, nd); 5633 return (0); 5634 } 5635 5636 /* 5637 * nfs set extended attribute service 5638 */ 5639 int 5640 nfsrvd_setxattr(struct nfsrv_descript *nd, __unused int isdgram, 5641 vnode_t vp, __unused struct nfsexstuff *exp) 5642 { 5643 uint32_t *tl; 5644 struct nfsvattr ova, nva; 5645 nfsattrbit_t attrbits; 5646 int error, len, opt; 5647 char *name; 5648 size_t siz; 5649 struct thread *p = curthread; 5650 5651 error = 0; 5652 name = NULL; 5653 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5654 nd->nd_repstat = NFSERR_WRONGSEC; 5655 goto nfsmout; 5656 } 5657 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5658 opt = fxdr_unsigned(int, *tl++); 5659 len = fxdr_unsigned(int, *tl); 5660 if (len <= 0) { 5661 nd->nd_repstat = NFSERR_BADXDR; 5662 goto nfsmout; 5663 } 5664 if (len > EXTATTR_MAXNAMELEN) { 5665 nd->nd_repstat = NFSERR_NOXATTR; 5666 goto nfsmout; 5667 } 5668 name = malloc(len + 1, M_TEMP, M_WAITOK); 5669 error = nfsrv_mtostr(nd, name, len); 5670 if (error != 0) 5671 goto nfsmout; 5672 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5673 len = fxdr_unsigned(int, *tl); 5674 if (len < 0 || len > IOSIZE_MAX) { 5675 nd->nd_repstat = NFSERR_XATTR2BIG; 5676 goto nfsmout; 5677 } 5678 switch (opt) { 5679 case NFSV4SXATTR_CREATE: 5680 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 5681 &siz, nd->nd_cred, p); 5682 if (error != ENOATTR) 5683 nd->nd_repstat = NFSERR_EXIST; 5684 error = 0; 5685 break; 5686 case NFSV4SXATTR_REPLACE: 5687 error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER, name, NULL, 5688 &siz, nd->nd_cred, p); 5689 if (error != 0) 5690 nd->nd_repstat = NFSERR_NOXATTR; 5691 break; 5692 case NFSV4SXATTR_EITHER: 5693 break; 5694 default: 5695 nd->nd_repstat = NFSERR_BADXDR; 5696 } 5697 if (nd->nd_repstat != 0) 5698 goto nfsmout; 5699 5700 /* Now, do the Set Extended attribute, with Change before and after. */ 5701 NFSZERO_ATTRBIT(&attrbits); 5702 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 5703 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 5704 if (nd->nd_repstat == 0) { 5705 nd->nd_repstat = nfsvno_setxattr(vp, name, len, nd->nd_md, 5706 nd->nd_dpos, nd->nd_cred, p); 5707 if (nd->nd_repstat == ENXIO) 5708 nd->nd_repstat = NFSERR_XATTR2BIG; 5709 } 5710 if (nd->nd_repstat == 0 && len > 0) 5711 nd->nd_repstat = nfsm_advance(nd, NFSM_RNDUP(len), -1); 5712 if (nd->nd_repstat == 0) 5713 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 5714 if (nd->nd_repstat == 0) { 5715 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 5716 *tl++ = newnfs_true; 5717 txdr_hyper(ova.na_filerev, tl); tl += 2; 5718 txdr_hyper(nva.na_filerev, tl); 5719 } 5720 5721 nfsmout: 5722 free(name, M_TEMP); 5723 if (nd->nd_repstat == 0) 5724 nd->nd_repstat = error; 5725 vput(vp); 5726 NFSEXITCODE2(0, nd); 5727 return (0); 5728 } 5729 5730 /* 5731 * nfs remove extended attribute service 5732 */ 5733 int 5734 nfsrvd_rmxattr(struct nfsrv_descript *nd, __unused int isdgram, 5735 vnode_t vp, __unused struct nfsexstuff *exp) 5736 { 5737 uint32_t *tl; 5738 struct nfsvattr ova, nva; 5739 nfsattrbit_t attrbits; 5740 int error, len; 5741 char *name; 5742 struct thread *p = curthread; 5743 5744 error = 0; 5745 name = NULL; 5746 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5747 nd->nd_repstat = NFSERR_WRONGSEC; 5748 goto nfsmout; 5749 } 5750 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5751 len = fxdr_unsigned(int, *tl); 5752 if (len <= 0) { 5753 nd->nd_repstat = NFSERR_BADXDR; 5754 goto nfsmout; 5755 } 5756 if (len > EXTATTR_MAXNAMELEN) { 5757 nd->nd_repstat = NFSERR_NOXATTR; 5758 goto nfsmout; 5759 } 5760 name = malloc(len + 1, M_TEMP, M_WAITOK); 5761 error = nfsrv_mtostr(nd, name, len); 5762 if (error != 0) 5763 goto nfsmout; 5764 5765 if ((nd->nd_flag & ND_IMPLIEDCLID) == 0) { 5766 printf("EEK! nfsrvd_rmxattr: no implied clientid\n"); 5767 error = NFSERR_NOXATTR; 5768 goto nfsmout; 5769 } 5770 /* 5771 * Now, do the Remove Extended attribute, with Change before and 5772 * after. 5773 */ 5774 NFSZERO_ATTRBIT(&attrbits); 5775 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 5776 nd->nd_repstat = nfsvno_getattr(vp, &ova, nd, p, 1, &attrbits); 5777 if (nd->nd_repstat == 0) { 5778 nd->nd_repstat = nfsvno_rmxattr(nd, vp, name, nd->nd_cred, p); 5779 if (nd->nd_repstat == ENOATTR) 5780 nd->nd_repstat = NFSERR_NOXATTR; 5781 } 5782 if (nd->nd_repstat == 0) 5783 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits); 5784 if (nd->nd_repstat == 0) { 5785 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 5786 *tl++ = newnfs_true; 5787 txdr_hyper(ova.na_filerev, tl); tl += 2; 5788 txdr_hyper(nva.na_filerev, tl); 5789 } 5790 5791 nfsmout: 5792 free(name, M_TEMP); 5793 if (nd->nd_repstat == 0) 5794 nd->nd_repstat = error; 5795 vput(vp); 5796 NFSEXITCODE2(0, nd); 5797 return (0); 5798 } 5799 5800 /* 5801 * nfs list extended attribute service 5802 */ 5803 int 5804 nfsrvd_listxattr(struct nfsrv_descript *nd, __unused int isdgram, 5805 vnode_t vp, __unused struct nfsexstuff *exp) 5806 { 5807 uint32_t cnt, *tl, len, len2, i, pos, retlen; 5808 int error; 5809 uint64_t cookie, cookie2; 5810 u_char *buf; 5811 bool eof; 5812 struct thread *p = curthread; 5813 5814 error = 0; 5815 buf = NULL; 5816 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 5817 nd->nd_repstat = NFSERR_WRONGSEC; 5818 goto nfsmout; 5819 } 5820 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 5821 /* 5822 * The cookie doesn't need to be in net byte order, but FreeBSD 5823 * does so to make it more readable in packet traces. 5824 */ 5825 cookie = fxdr_hyper(tl); tl += 2; 5826 len = fxdr_unsigned(uint32_t, *tl); 5827 if (len == 0 || cookie >= IOSIZE_MAX) { 5828 nd->nd_repstat = NFSERR_BADXDR; 5829 goto nfsmout; 5830 } 5831 if (len > nd->nd_maxresp - NFS_MAXXDR) 5832 len = nd->nd_maxresp - NFS_MAXXDR; 5833 len2 = len; 5834 nd->nd_repstat = nfsvno_listxattr(vp, cookie, nd->nd_cred, p, &buf, 5835 &len, &eof); 5836 if (nd->nd_repstat == EOPNOTSUPP) 5837 nd->nd_repstat = NFSERR_NOTSUPP; 5838 if (nd->nd_repstat == 0) { 5839 cookie2 = cookie + len; 5840 if (cookie2 < cookie) 5841 nd->nd_repstat = NFSERR_BADXDR; 5842 } 5843 if (nd->nd_repstat == 0) { 5844 /* Now copy the entries out. */ 5845 retlen = NFSX_HYPER + 2 * NFSX_UNSIGNED; 5846 if (len == 0 && retlen <= len2) { 5847 /* The cookie was at eof. */ 5848 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * 5849 NFSX_UNSIGNED); 5850 txdr_hyper(cookie2, tl); tl += 2; 5851 *tl++ = txdr_unsigned(0); 5852 *tl = newnfs_true; 5853 goto nfsmout; 5854 } 5855 5856 /* Sanity check the cookie. */ 5857 for (pos = 0; pos < len; pos += (i + 1)) { 5858 if (pos == cookie) 5859 break; 5860 i = buf[pos]; 5861 } 5862 if (pos != cookie) { 5863 nd->nd_repstat = NFSERR_INVAL; 5864 goto nfsmout; 5865 } 5866 5867 /* Loop around copying the entrie(s) out. */ 5868 cnt = 0; 5869 len -= cookie; 5870 i = buf[pos]; 5871 while (i < len && len2 >= retlen + NFSM_RNDUP(i) + 5872 NFSX_UNSIGNED) { 5873 if (cnt == 0) { 5874 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 5875 NFSX_UNSIGNED); 5876 txdr_hyper(cookie2, tl); tl += 2; 5877 } 5878 retlen += nfsm_strtom(nd, &buf[pos + 1], i); 5879 len -= (i + 1); 5880 pos += (i + 1); 5881 i = buf[pos]; 5882 cnt++; 5883 } 5884 /* 5885 * eof is set true/false by nfsvno_listxattr(), but if we 5886 * can't copy all entries returned by nfsvno_listxattr(), 5887 * we are not at eof. 5888 */ 5889 if (len > 0) 5890 eof = false; 5891 if (cnt > 0) { 5892 /* *tl is set above. */ 5893 *tl = txdr_unsigned(cnt); 5894 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5895 if (eof) 5896 *tl = newnfs_true; 5897 else 5898 *tl = newnfs_false; 5899 } else 5900 nd->nd_repstat = NFSERR_TOOSMALL; 5901 } 5902 5903 nfsmout: 5904 free(buf, M_TEMP); 5905 if (nd->nd_repstat == 0) 5906 nd->nd_repstat = error; 5907 vput(vp); 5908 NFSEXITCODE2(0, nd); 5909 return (0); 5910 } 5911 5912 /* 5913 * nfsv4 service not supported 5914 */ 5915 int 5916 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 5917 __unused vnode_t vp, __unused struct nfsexstuff *exp) 5918 { 5919 5920 nd->nd_repstat = NFSERR_NOTSUPP; 5921 NFSEXITCODE2(0, nd); 5922 return (0); 5923 } 5924 5925