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