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