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