1 /* $NetBSD: nfs_nfsdserv.c,v 1.6 2024/07/05 04:31:52 rin Exp $ */ 2 /*- 3 * Copyright (c) 1989, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Rick Macklem at The University of Guelph. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 */ 34 35 #include <sys/cdefs.h> 36 /* __FBSDID("FreeBSD: head/sys/fs/nfsserver/nfs_nfsdserv.c 299514 2016-05-12 05:03:12Z cem "); */ 37 __RCSID("$NetBSD: nfs_nfsdserv.c,v 1.6 2024/07/05 04:31:52 rin Exp $"); 38 39 /* 40 * nfs version 2, 3 and 4 server calls to vnode ops 41 * - these routines generally have 3 phases 42 * 1 - break down and validate rpc request in mbuf list 43 * 2 - do the vnode ops for the request, usually by calling a nfsvno_XXX() 44 * function in nfsd_port.c 45 * 3 - build the rpc reply in an mbuf list 46 * For nfsv4, these functions are called for each Op within the Compound RPC. 47 */ 48 49 #ifndef APPLEKEXT 50 #include <fs/nfs/common/nfsport.h> 51 52 /* Global vars */ 53 extern u_int32_t newnfs_false, newnfs_true; 54 extern enum vtype nv34tov_type[8]; 55 extern struct timeval nfsboottime; 56 extern int nfs_rootfhset; 57 extern int nfsrv_enable_crossmntpt; 58 extern int nfsrv_statehashsize; 59 #endif /* !APPLEKEXT */ 60 61 static int nfs_async = 0; 62 SYSCTL_DECL(_vfs_nfsd); 63 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0, 64 "Tell client that writes were synced even though they were not"); 65 66 /* 67 * This list defines the GSS mechanisms supported. 68 * (Don't ask me how you get these strings from the RFC stuff like 69 * iso(1), org(3)... but someone did it, so I don't need to know.) 70 */ 71 static struct nfsgss_mechlist nfsgss_mechlist[] = { 72 { 9, "\052\206\110\206\367\022\001\002\002", 11 }, 73 { 0, "", 0 }, 74 }; 75 76 /* local functions */ 77 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 78 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 79 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 80 int *diraft_retp, nfsattrbit_t *attrbitp, 81 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 82 int pathlen); 83 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 84 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 85 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 86 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 87 NFSPROC_T *p, struct nfsexstuff *exp); 88 89 /* 90 * nfs access service (not a part of NFS V2) 91 */ 92 APPLESTATIC int 93 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram, 94 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 95 { 96 u_int32_t *tl; 97 int getret, error = 0; 98 struct nfsvattr nva; 99 u_int32_t testmode, nfsmode, supported = 0; 100 accmode_t deletebit; 101 102 if (nd->nd_repstat) { 103 nfsrv_postopattr(nd, 1, &nva); 104 goto out; 105 } 106 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 107 nfsmode = fxdr_unsigned(u_int32_t, *tl); 108 if ((nd->nd_flag & ND_NFSV4) && 109 (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP | 110 NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE | 111 NFSACCESS_EXECUTE))) { 112 nd->nd_repstat = NFSERR_INVAL; 113 vput(vp); 114 goto out; 115 } 116 if (nfsmode & NFSACCESS_READ) { 117 supported |= NFSACCESS_READ; 118 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p, 119 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 120 nfsmode &= ~NFSACCESS_READ; 121 } 122 if (nfsmode & NFSACCESS_MODIFY) { 123 supported |= NFSACCESS_MODIFY; 124 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p, 125 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 126 nfsmode &= ~NFSACCESS_MODIFY; 127 } 128 if (nfsmode & NFSACCESS_EXTEND) { 129 supported |= NFSACCESS_EXTEND; 130 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p, 131 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 132 nfsmode &= ~NFSACCESS_EXTEND; 133 } 134 if (nfsmode & NFSACCESS_DELETE) { 135 supported |= NFSACCESS_DELETE; 136 if (vp->v_type == VDIR) 137 deletebit = VDELETE_CHILD; 138 else 139 deletebit = VDELETE; 140 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p, 141 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 142 nfsmode &= ~NFSACCESS_DELETE; 143 } 144 if (vnode_vtype(vp) == VDIR) 145 testmode = NFSACCESS_LOOKUP; 146 else 147 testmode = NFSACCESS_EXECUTE; 148 if (nfsmode & testmode) { 149 supported |= (nfsmode & testmode); 150 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p, 151 NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported)) 152 nfsmode &= ~testmode; 153 } 154 nfsmode &= supported; 155 if (nd->nd_flag & ND_NFSV3) { 156 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 157 nfsrv_postopattr(nd, getret, &nva); 158 } 159 vput(vp); 160 if (nd->nd_flag & ND_NFSV4) { 161 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 162 *tl++ = txdr_unsigned(supported); 163 } else 164 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 165 *tl = txdr_unsigned(nfsmode); 166 167 out: 168 NFSEXITCODE2(0, nd); 169 return (0); 170 nfsmout: 171 vput(vp); 172 NFSEXITCODE2(error, nd); 173 return (error); 174 } 175 176 /* 177 * nfs getattr service 178 */ 179 APPLESTATIC int 180 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram, 181 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 182 { 183 struct nfsvattr nva; 184 fhandle_t fh; 185 int at_root = 0, error = 0, supports_nfsv4acls; 186 struct nfsreferral *refp; 187 nfsattrbit_t attrbits, tmpbits; 188 struct mount *mp; 189 struct vnode *tvp = NULL; 190 struct vattr va; 191 uint64_t mounted_on_fileno = 0; 192 accmode_t accmode; 193 194 if (nd->nd_repstat) 195 goto out; 196 if (nd->nd_flag & ND_NFSV4) { 197 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 198 if (error) { 199 vput(vp); 200 goto out; 201 } 202 203 /* 204 * Check for a referral. 205 */ 206 refp = nfsv4root_getreferral(vp, NULL, 0); 207 if (refp != NULL) { 208 (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1, 209 &nd->nd_repstat); 210 vput(vp); 211 goto out; 212 } 213 if (nd->nd_repstat == 0) { 214 accmode = 0; 215 NFSSET_ATTRBIT(&tmpbits, &attrbits); 216 217 /* 218 * GETATTR with write-only attr time_access_set and time_modify_set 219 * should return NFS4ERR_INVAL. 220 */ 221 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) || 222 NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){ 223 error = NFSERR_INVAL; 224 vput(vp); 225 goto out; 226 } 227 if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) { 228 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL); 229 accmode |= VREAD_ACL; 230 } 231 if (NFSNONZERO_ATTRBIT(&tmpbits)) 232 accmode |= VREAD_ATTRIBUTES; 233 if (accmode != 0) 234 nd->nd_repstat = nfsvno_accchk(vp, accmode, 235 nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE, 236 NFSACCCHK_VPISLOCKED, NULL); 237 } 238 } 239 if (!nd->nd_repstat) 240 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 241 if (!nd->nd_repstat) { 242 if (nd->nd_flag & ND_NFSV4) { 243 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE)) 244 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 245 if (!nd->nd_repstat) 246 nd->nd_repstat = nfsrv_checkgetattr(nd, vp, 247 &nva, &attrbits, nd->nd_cred, p); 248 if (nd->nd_repstat == 0) { 249 supports_nfsv4acls = nfs_supportsnfsv4acls(vp); 250 mp = vp->v_mount; 251 if (nfsrv_enable_crossmntpt != 0 && 252 vp->v_type == VDIR && 253 (vp->v_vflag & VV_ROOT) != 0 && 254 vp != rootvnode) { 255 tvp = mp->mnt_vnodecovered; 256 VREF(tvp); 257 at_root = 1; 258 } else 259 at_root = 0; 260 vfs_ref(mp); 261 NFSVOPUNLOCK(vp, 0); 262 if (at_root != 0) { 263 if ((nd->nd_repstat = 264 NFSVOPLOCK(tvp, LK_SHARED)) == 0) { 265 nd->nd_repstat = VOP_GETATTR( 266 tvp, &va, nd->nd_cred); 267 vput(tvp); 268 } else 269 vrele(tvp); 270 if (nd->nd_repstat == 0) 271 mounted_on_fileno = (uint64_t) 272 va.va_fileid; 273 else 274 at_root = 0; 275 } 276 if (nd->nd_repstat == 0) 277 nd->nd_repstat = vfs_busy(mp, 0); 278 vfs_rel(mp); 279 if (nd->nd_repstat == 0) { 280 (void)nfsvno_fillattr(nd, mp, vp, &nva, 281 &fh, 0, &attrbits, nd->nd_cred, p, 282 isdgram, 1, supports_nfsv4acls, 283 at_root, mounted_on_fileno); 284 vfs_unbusy(mp); 285 } 286 vrele(vp); 287 } else 288 vput(vp); 289 } else { 290 nfsrv_fillattr(nd, &nva); 291 vput(vp); 292 } 293 } else { 294 vput(vp); 295 } 296 297 out: 298 NFSEXITCODE2(error, nd); 299 return (error); 300 } 301 302 /* 303 * nfs setattr service 304 */ 305 APPLESTATIC int 306 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram, 307 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 308 { 309 struct nfsvattr nva, nva2; 310 u_int32_t *tl; 311 int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0; 312 struct timespec guard = { 0, 0 }; 313 nfsattrbit_t attrbits, retbits; 314 nfsv4stateid_t stateid; 315 NFSACL_T *aclp = NULL; 316 317 if (nd->nd_repstat) { 318 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 319 goto out; 320 } 321 #ifdef NFS4_ACL_EXTATTR_NAME 322 aclp = acl_alloc(M_WAITOK); 323 aclp->acl_cnt = 0; 324 #endif 325 NFSVNO_ATTRINIT(&nva); 326 NFSZERO_ATTRBIT(&retbits); 327 if (nd->nd_flag & ND_NFSV4) { 328 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 329 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 330 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 331 } 332 error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p); 333 if (error) 334 goto nfsmout; 335 preat_ret = nfsvno_getattr(vp, &nva2, nd->nd_cred, p, 1); 336 if (!nd->nd_repstat) 337 nd->nd_repstat = preat_ret; 338 if (nd->nd_flag & ND_NFSV3) { 339 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 340 gcheck = fxdr_unsigned(int, *tl); 341 if (gcheck) { 342 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 343 fxdr_nfsv3time(tl, &guard); 344 } 345 if (!nd->nd_repstat && gcheck && 346 (nva2.na_ctime.tv_sec != guard.tv_sec || 347 nva2.na_ctime.tv_nsec != guard.tv_nsec)) 348 nd->nd_repstat = NFSERR_NOT_SYNC; 349 if (nd->nd_repstat) { 350 vput(vp); 351 #ifdef NFS4_ACL_EXTATTR_NAME 352 acl_free(aclp); 353 #endif 354 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 355 goto out; 356 } 357 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 358 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 359 360 /* 361 * Now that we have all the fields, lets do it. 362 * If the size is being changed write access is required, otherwise 363 * just check for a read only file system. 364 */ 365 if (!nd->nd_repstat) { 366 if (NFSVNO_NOTSETSIZE(&nva)) { 367 if (NFSVNO_EXRDONLY(exp) || 368 (vfs_flags(vnode_mount(vp)) & MNT_RDONLY)) 369 nd->nd_repstat = EROFS; 370 } else { 371 if (vnode_vtype(vp) != VREG) 372 nd->nd_repstat = EINVAL; 373 else if (nva2.na_uid != nd->nd_cred->cr_uid || 374 NFSVNO_EXSTRICTACCESS(exp)) 375 nd->nd_repstat = nfsvno_accchk(vp, 376 VWRITE, nd->nd_cred, exp, p, 377 NFSACCCHK_NOOVERRIDE, 378 NFSACCCHK_VPISLOCKED, NULL); 379 } 380 } 381 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) 382 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid, 383 &nva, &attrbits, exp, p); 384 385 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 386 /* 387 * For V4, try setting the attributes in sets, so that the 388 * reply bitmap will be correct for an error case. 389 */ 390 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) || 391 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) { 392 NFSVNO_ATTRINIT(&nva2); 393 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid); 394 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid); 395 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 396 exp); 397 if (!nd->nd_repstat) { 398 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER)) 399 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER); 400 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) 401 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP); 402 } 403 } 404 if (!nd->nd_repstat && 405 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) { 406 NFSVNO_ATTRINIT(&nva2); 407 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size); 408 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 409 exp); 410 if (!nd->nd_repstat) 411 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE); 412 } 413 if (!nd->nd_repstat && 414 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) || 415 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) { 416 NFSVNO_ATTRINIT(&nva2); 417 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime); 418 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime); 419 if (nva.na_vaflags & VA_UTIMES_NULL) { 420 nva2.na_vaflags |= VA_UTIMES_NULL; 421 NFSVNO_SETACTIVE(&nva2, vaflags); 422 } 423 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 424 exp); 425 if (!nd->nd_repstat) { 426 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET)) 427 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET); 428 if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET)) 429 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET); 430 } 431 } 432 if (!nd->nd_repstat && 433 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE)) { 434 NFSVNO_ATTRINIT(&nva2); 435 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode); 436 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p, 437 exp); 438 if (!nd->nd_repstat) 439 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE); 440 } 441 442 #ifdef NFS4_ACL_EXTATTR_NAME 443 if (!nd->nd_repstat && aclp->acl_cnt > 0 && 444 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) { 445 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p); 446 if (!nd->nd_repstat) 447 NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL); 448 } 449 #endif 450 } else if (!nd->nd_repstat) { 451 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p, 452 exp); 453 } 454 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) { 455 postat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 456 if (!nd->nd_repstat) 457 nd->nd_repstat = postat_ret; 458 } 459 vput(vp); 460 #ifdef NFS4_ACL_EXTATTR_NAME 461 acl_free(aclp); 462 #endif 463 if (nd->nd_flag & ND_NFSV3) 464 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva); 465 else if (nd->nd_flag & ND_NFSV4) 466 (void) nfsrv_putattrbit(nd, &retbits); 467 else if (!nd->nd_repstat) 468 nfsrv_fillattr(nd, &nva); 469 470 out: 471 NFSEXITCODE2(0, nd); 472 return (0); 473 nfsmout: 474 vput(vp); 475 #ifdef NFS4_ACL_EXTATTR_NAME 476 acl_free(aclp); 477 #endif 478 if (nd->nd_flag & ND_NFSV4) { 479 /* 480 * For all nd_repstat, the V4 reply includes a bitmap, 481 * even NFSERR_BADXDR, which is what this will end up 482 * returning. 483 */ 484 (void) nfsrv_putattrbit(nd, &retbits); 485 } 486 NFSEXITCODE2(error, nd); 487 return (error); 488 } 489 490 /* 491 * nfs lookup rpc 492 * (Also performs lookup parent for v4) 493 */ 494 APPLESTATIC int 495 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram, 496 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 497 struct nfsexstuff *exp) 498 { 499 struct nameidata named; 500 vnode_t vp, dirp = NULL; 501 int error = 0, dattr_ret = 1; 502 struct nfsvattr nva, dattr; 503 char *bufp; 504 u_long *hashp; 505 506 if (nd->nd_repstat) { 507 nfsrv_postopattr(nd, dattr_ret, &dattr); 508 goto out; 509 } 510 511 /* 512 * For some reason, if dp is a symlink, the error 513 * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR. 514 */ 515 if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) { 516 nd->nd_repstat = NFSERR_SYMLINK; 517 vrele(dp); 518 goto out; 519 } 520 521 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 522 LOCKLEAF | SAVESTART); 523 nfsvno_setpathbuf(&named, &bufp, &hashp); 524 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 525 if (error) { 526 vrele(dp); 527 nfsvno_relpathbuf(&named); 528 goto out; 529 } 530 if (!nd->nd_repstat) { 531 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 532 } else { 533 vrele(dp); 534 nfsvno_relpathbuf(&named); 535 } 536 if (nd->nd_repstat) { 537 if (dirp) { 538 if (nd->nd_flag & ND_NFSV3) 539 dattr_ret = nfsvno_getattr(dirp, &dattr, 540 nd->nd_cred, p, 0); 541 vrele(dirp); 542 } 543 if (nd->nd_flag & ND_NFSV3) 544 nfsrv_postopattr(nd, dattr_ret, &dattr); 545 goto out; 546 } 547 if (named.ni_startdir) 548 vrele(named.ni_startdir); 549 nfsvno_relpathbuf(&named); 550 vp = named.ni_vp; 551 if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) && 552 vp->v_type != VDIR && vp->v_type != VLNK) 553 /* 554 * Only allow lookup of VDIR and VLNK for traversal of 555 * non-exported volumes during NFSv4 mounting. 556 */ 557 nd->nd_repstat = ENOENT; 558 if (nd->nd_repstat == 0) 559 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 560 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 561 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 562 if (vpp != NULL && nd->nd_repstat == 0) 563 *vpp = vp; 564 else 565 vput(vp); 566 if (dirp) { 567 if (nd->nd_flag & ND_NFSV3) 568 dattr_ret = nfsvno_getattr(dirp, &dattr, nd->nd_cred, 569 p, 0); 570 vrele(dirp); 571 } 572 if (nd->nd_repstat) { 573 if (nd->nd_flag & ND_NFSV3) 574 nfsrv_postopattr(nd, dattr_ret, &dattr); 575 goto out; 576 } 577 if (nd->nd_flag & ND_NFSV2) { 578 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 579 nfsrv_fillattr(nd, &nva); 580 } else if (nd->nd_flag & ND_NFSV3) { 581 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 582 nfsrv_postopattr(nd, 0, &nva); 583 nfsrv_postopattr(nd, dattr_ret, &dattr); 584 } 585 586 out: 587 NFSEXITCODE2(error, nd); 588 return (error); 589 } 590 591 /* 592 * nfs readlink service 593 */ 594 APPLESTATIC int 595 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram, 596 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 597 { 598 u_int32_t *tl; 599 mbuf_t mp = NULL, mpend = NULL; 600 int getret = 1, len; 601 struct nfsvattr nva; 602 603 if (nd->nd_repstat) { 604 nfsrv_postopattr(nd, getret, &nva); 605 goto out; 606 } 607 if (vnode_vtype(vp) != VLNK) { 608 if (nd->nd_flag & ND_NFSV2) 609 nd->nd_repstat = ENXIO; 610 else 611 nd->nd_repstat = EINVAL; 612 } 613 if (!nd->nd_repstat) 614 nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred, p, 615 &mp, &mpend, &len); 616 if (nd->nd_flag & ND_NFSV3) 617 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 618 vput(vp); 619 if (nd->nd_flag & ND_NFSV3) 620 nfsrv_postopattr(nd, getret, &nva); 621 if (nd->nd_repstat) 622 goto out; 623 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 624 *tl = txdr_unsigned(len); 625 mbuf_setnext(nd->nd_mb, mp); 626 nd->nd_mb = mpend; 627 nd->nd_bpos = NFSMTOD(mpend, caddr_t) + mbuf_len(mpend); 628 629 out: 630 NFSEXITCODE2(0, nd); 631 return (0); 632 } 633 634 /* 635 * nfs read service 636 */ 637 APPLESTATIC int 638 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram, 639 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 640 { 641 u_int32_t *tl; 642 int error = 0, cnt, getret = 1, reqlen, eof = 0; 643 mbuf_t m2, m3; 644 struct nfsvattr nva; 645 off_t off = 0x0; 646 struct nfsstate st, *stp = &st; 647 struct nfslock lo, *lop = &lo; 648 nfsv4stateid_t stateid; 649 nfsquad_t clientid; 650 651 if (nd->nd_repstat) { 652 nfsrv_postopattr(nd, getret, &nva); 653 goto out; 654 } 655 if (nd->nd_flag & ND_NFSV2) { 656 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 657 off = (off_t)fxdr_unsigned(u_int32_t, *tl++); 658 reqlen = fxdr_unsigned(int, *tl); 659 } else if (nd->nd_flag & ND_NFSV3) { 660 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 661 off = fxdr_hyper(tl); 662 tl += 2; 663 reqlen = fxdr_unsigned(int, *tl); 664 } else { 665 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED); 666 reqlen = fxdr_unsigned(int, *(tl + 6)); 667 } 668 if (reqlen > NFS_SRVMAXDATA(nd)) { 669 reqlen = NFS_SRVMAXDATA(nd); 670 } else if (reqlen < 0) { 671 error = EBADRPC; 672 goto nfsmout; 673 } 674 if (nd->nd_flag & ND_NFSV4) { 675 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS); 676 lop->lo_flags = NFSLCK_READ; 677 stp->ls_ownerlen = 0; 678 stp->ls_op = NULL; 679 stp->ls_uid = nd->nd_cred->cr_uid; 680 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 681 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 682 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 683 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 684 if ((nd->nd_flag & ND_NFSV41) != 0) 685 clientid.qval = nd->nd_clientid.qval; 686 else if (nd->nd_clientid.qval != clientid.qval) 687 printf("EEK1 multiple clids\n"); 688 } else { 689 if ((nd->nd_flag & ND_NFSV41) != 0) 690 printf("EEK! no clientid from session\n"); 691 nd->nd_flag |= ND_IMPLIEDCLID; 692 nd->nd_clientid.qval = clientid.qval; 693 } 694 stp->ls_stateid.other[2] = *tl++; 695 off = fxdr_hyper(tl); 696 lop->lo_first = off; 697 tl += 2; 698 lop->lo_end = off + reqlen; 699 /* 700 * Paranoia, just in case it wraps around. 701 */ 702 if (lop->lo_end < off) 703 lop->lo_end = NFS64BITSSET; 704 } 705 if (vnode_vtype(vp) != VREG) { 706 if (nd->nd_flag & ND_NFSV3) 707 nd->nd_repstat = EINVAL; 708 else 709 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 710 EINVAL; 711 } 712 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 713 if (!nd->nd_repstat) 714 nd->nd_repstat = getret; 715 if (!nd->nd_repstat && 716 (nva.na_uid != nd->nd_cred->cr_uid || 717 NFSVNO_EXSTRICTACCESS(exp))) { 718 nd->nd_repstat = nfsvno_accchk(vp, VREAD, 719 nd->nd_cred, exp, p, 720 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 721 if (nd->nd_repstat) 722 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 723 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 724 NFSACCCHK_VPISLOCKED, NULL); 725 } 726 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 727 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 728 &stateid, exp, nd, p); 729 if (nd->nd_repstat) { 730 vput(vp); 731 if (nd->nd_flag & ND_NFSV3) 732 nfsrv_postopattr(nd, getret, &nva); 733 goto out; 734 } 735 if (off >= nva.na_size) { 736 cnt = 0; 737 eof = 1; 738 } else if (reqlen == 0) 739 cnt = 0; 740 else if ((off + reqlen) >= nva.na_size) { 741 cnt = nva.na_size - off; 742 eof = 1; 743 } else 744 cnt = reqlen; 745 m3 = NULL; 746 if (cnt > 0) { 747 nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred, p, 748 &m3, &m2); 749 if (!(nd->nd_flag & ND_NFSV4)) { 750 getret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 751 if (!nd->nd_repstat) 752 nd->nd_repstat = getret; 753 } 754 if (nd->nd_repstat) { 755 vput(vp); 756 mbuf_freem(m3); 757 if (nd->nd_flag & ND_NFSV3) 758 nfsrv_postopattr(nd, getret, &nva); 759 goto out; 760 } 761 } 762 vput(vp); 763 if (nd->nd_flag & ND_NFSV2) { 764 nfsrv_fillattr(nd, &nva); 765 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 766 } else { 767 if (nd->nd_flag & ND_NFSV3) { 768 nfsrv_postopattr(nd, getret, &nva); 769 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 770 *tl++ = txdr_unsigned(cnt); 771 } else 772 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 773 if (eof) 774 *tl++ = newnfs_true; 775 else 776 *tl++ = newnfs_false; 777 } 778 *tl = txdr_unsigned(cnt); 779 if (m3) { 780 mbuf_setnext(nd->nd_mb, m3); 781 nd->nd_mb = m2; 782 nd->nd_bpos = NFSMTOD(m2, caddr_t) + mbuf_len(m2); 783 } 784 785 out: 786 NFSEXITCODE2(0, nd); 787 return (0); 788 nfsmout: 789 vput(vp); 790 NFSEXITCODE2(error, nd); 791 return (error); 792 } 793 794 /* 795 * nfs write service 796 */ 797 APPLESTATIC int 798 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram, 799 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 800 { 801 int i, cnt; 802 u_int32_t *tl; 803 mbuf_t mp; 804 struct nfsvattr nva, forat; 805 int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1; 806 int stable = NFSWRITE_FILESYNC; 807 off_t off; 808 struct nfsstate st, *stp = &st; 809 struct nfslock lo, *lop = &lo; 810 nfsv4stateid_t stateid; 811 nfsquad_t clientid; 812 813 if (nd->nd_repstat) { 814 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 815 goto out; 816 } 817 if (nd->nd_flag & ND_NFSV2) { 818 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 819 off = (off_t)fxdr_unsigned(u_int32_t, *++tl); 820 tl += 2; 821 retlen = len = fxdr_unsigned(int32_t, *tl); 822 } else if (nd->nd_flag & ND_NFSV3) { 823 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 824 off = fxdr_hyper(tl); 825 tl += 3; 826 stable = fxdr_unsigned(int, *tl++); 827 retlen = len = fxdr_unsigned(int32_t, *tl); 828 } else { 829 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED); 830 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS); 831 lop->lo_flags = NFSLCK_WRITE; 832 stp->ls_ownerlen = 0; 833 stp->ls_op = NULL; 834 stp->ls_uid = nd->nd_cred->cr_uid; 835 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 836 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++; 837 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++; 838 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 839 if ((nd->nd_flag & ND_NFSV41) != 0) 840 clientid.qval = nd->nd_clientid.qval; 841 else if (nd->nd_clientid.qval != clientid.qval) 842 printf("EEK2 multiple clids\n"); 843 } else { 844 if ((nd->nd_flag & ND_NFSV41) != 0) 845 printf("EEK! no clientid from session\n"); 846 nd->nd_flag |= ND_IMPLIEDCLID; 847 nd->nd_clientid.qval = clientid.qval; 848 } 849 stp->ls_stateid.other[2] = *tl++; 850 off = fxdr_hyper(tl); 851 lop->lo_first = off; 852 tl += 2; 853 stable = fxdr_unsigned(int, *tl++); 854 retlen = len = fxdr_unsigned(int32_t, *tl); 855 lop->lo_end = off + len; 856 /* 857 * Paranoia, just in case it wraps around, which shouldn't 858 * ever happen anyhow. 859 */ 860 if (lop->lo_end < lop->lo_first) 861 lop->lo_end = NFS64BITSSET; 862 } 863 864 /* 865 * Loop through the mbuf chain, counting how many mbufs are a 866 * part of this write operation, so the iovec size is known. 867 */ 868 cnt = 0; 869 mp = nd->nd_md; 870 i = NFSMTOD(mp, caddr_t) + mbuf_len(mp) - nd->nd_dpos; 871 while (len > 0) { 872 if (i > 0) { 873 len -= i; 874 cnt++; 875 } 876 mp = mbuf_next(mp); 877 if (!mp) { 878 if (len > 0) { 879 error = EBADRPC; 880 goto nfsmout; 881 } 882 } else 883 i = mbuf_len(mp); 884 } 885 886 if (retlen > NFS_SRVMAXIO || retlen < 0) 887 nd->nd_repstat = EIO; 888 if (vnode_vtype(vp) != VREG && !nd->nd_repstat) { 889 if (nd->nd_flag & ND_NFSV3) 890 nd->nd_repstat = EINVAL; 891 else 892 nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR : 893 EINVAL; 894 } 895 forat_ret = nfsvno_getattr(vp, &forat, nd->nd_cred, p, 1); 896 if (!nd->nd_repstat) 897 nd->nd_repstat = forat_ret; 898 if (!nd->nd_repstat && 899 (forat.na_uid != nd->nd_cred->cr_uid || 900 NFSVNO_EXSTRICTACCESS(exp))) 901 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 902 nd->nd_cred, exp, p, 903 NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 904 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 905 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 906 &stateid, exp, nd, p); 907 } 908 if (nd->nd_repstat) { 909 vput(vp); 910 if (nd->nd_flag & ND_NFSV3) 911 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 912 goto out; 913 } 914 915 /* 916 * For NFS Version 2, it is not obvious what a write of zero length 917 * should do, but I might as well be consistent with Version 3, 918 * which is to return ok so long as there are no permission problems. 919 */ 920 if (retlen > 0) { 921 nd->nd_repstat = nfsvno_write(vp, off, retlen, cnt, stable, 922 nd->nd_md, nd->nd_dpos, nd->nd_cred, p); 923 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1); 924 if (error) 925 panic("nfsrv_write mbuf"); 926 } 927 if (nd->nd_flag & ND_NFSV4) 928 aftat_ret = 0; 929 else 930 aftat_ret = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 931 vput(vp); 932 if (!nd->nd_repstat) 933 nd->nd_repstat = aftat_ret; 934 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 935 if (nd->nd_flag & ND_NFSV3) 936 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva); 937 if (nd->nd_repstat) 938 goto out; 939 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 940 *tl++ = txdr_unsigned(retlen); 941 /* 942 * If nfs_async is set, then pretend the write was FILESYNC. 943 * Warning: Doing this violates RFC1813 and runs a risk 944 * of data written by a client being lost when the server 945 * crashes/reboots. 946 */ 947 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0) 948 *tl++ = txdr_unsigned(stable); 949 else 950 *tl++ = txdr_unsigned(NFSWRITE_FILESYNC); 951 /* 952 * Actually, there is no need to txdr these fields, 953 * but it may make the values more human readable, 954 * for debugging purposes. 955 */ 956 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 957 *tl = txdr_unsigned(nfsboottime.tv_usec); 958 } else if (!nd->nd_repstat) 959 nfsrv_fillattr(nd, &nva); 960 961 out: 962 NFSEXITCODE2(0, nd); 963 return (0); 964 nfsmout: 965 vput(vp); 966 NFSEXITCODE2(error, nd); 967 return (error); 968 } 969 970 /* 971 * nfs create service (creates regular files for V2 and V3. Spec. files for V2.) 972 * now does a truncate to 0 length via. setattr if it already exists 973 * The core creation routine has been extracted out into nfsrv_creatsub(), 974 * so it can also be used by nfsrv_open() for V4. 975 */ 976 APPLESTATIC int 977 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram, 978 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 979 { 980 struct nfsvattr nva, dirfor, diraft; 981 struct nfsv2_sattr *sp; 982 struct nameidata named; 983 u_int32_t *tl; 984 int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1; 985 int how = NFSCREATE_UNCHECKED, exclusive_flag = 0; 986 NFSDEV_T rdev = 0; 987 vnode_t vp = NULL, dirp = NULL; 988 fhandle_t fh; 989 char *bufp; 990 u_long *hashp; 991 enum vtype vtyp; 992 int32_t cverf[2], tverf[2] = { 0, 0 }; 993 994 if (nd->nd_repstat) { 995 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 996 goto out; 997 } 998 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 999 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 1000 nfsvno_setpathbuf(&named, &bufp, &hashp); 1001 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1002 if (error) 1003 goto nfsmout; 1004 if (!nd->nd_repstat) { 1005 NFSVNO_ATTRINIT(&nva); 1006 if (nd->nd_flag & ND_NFSV2) { 1007 NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR); 1008 vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); 1009 if (vtyp == VNON) 1010 vtyp = VREG; 1011 NFSVNO_SETATTRVAL(&nva, type, vtyp); 1012 NFSVNO_SETATTRVAL(&nva, mode, 1013 nfstov_mode(sp->sa_mode)); 1014 switch (nva.na_type) { 1015 case VREG: 1016 tsize = fxdr_unsigned(int32_t, sp->sa_size); 1017 if (tsize != -1) 1018 NFSVNO_SETATTRVAL(&nva, size, 1019 (u_quad_t)tsize); 1020 break; 1021 case VCHR: 1022 case VBLK: 1023 case VFIFO: 1024 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size); 1025 break; 1026 default: 1027 break; 1028 } 1029 } else { 1030 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1031 how = fxdr_unsigned(int, *tl); 1032 switch (how) { 1033 case NFSCREATE_GUARDED: 1034 case NFSCREATE_UNCHECKED: 1035 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 1036 if (error) 1037 goto nfsmout; 1038 break; 1039 case NFSCREATE_EXCLUSIVE: 1040 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 1041 cverf[0] = *tl++; 1042 cverf[1] = *tl; 1043 exclusive_flag = 1; 1044 break; 1045 } 1046 NFSVNO_SETATTRVAL(&nva, type, VREG); 1047 } 1048 } 1049 if (nd->nd_repstat) { 1050 nfsvno_relpathbuf(&named); 1051 if (nd->nd_flag & ND_NFSV3) { 1052 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, 1053 p, 1); 1054 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1055 &diraft); 1056 } 1057 vput(dp); 1058 goto out; 1059 } 1060 1061 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 1062 if (dirp) { 1063 if (nd->nd_flag & ND_NFSV2) { 1064 vrele(dirp); 1065 dirp = NULL; 1066 } else { 1067 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1068 p, 0); 1069 } 1070 } 1071 if (nd->nd_repstat) { 1072 if (nd->nd_flag & ND_NFSV3) 1073 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1074 &diraft); 1075 if (dirp) 1076 vrele(dirp); 1077 goto out; 1078 } 1079 1080 if (!(nd->nd_flag & ND_NFSV2)) { 1081 switch (how) { 1082 case NFSCREATE_GUARDED: 1083 if (named.ni_vp) 1084 nd->nd_repstat = EEXIST; 1085 break; 1086 case NFSCREATE_UNCHECKED: 1087 break; 1088 case NFSCREATE_EXCLUSIVE: 1089 if (named.ni_vp == NULL) 1090 NFSVNO_SETATTRVAL(&nva, mode, 0); 1091 break; 1092 } 1093 } 1094 1095 /* 1096 * Iff doesn't exist, create it 1097 * otherwise just truncate to 0 length 1098 * should I set the mode too ? 1099 */ 1100 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, 1101 &exclusive_flag, cverf, rdev, p, exp); 1102 1103 if (!nd->nd_repstat) { 1104 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 1105 if (!nd->nd_repstat) 1106 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 1107 p, 1); 1108 vput(vp); 1109 if (!nd->nd_repstat) { 1110 tverf[0] = nva.na_atime.tv_sec; 1111 tverf[1] = nva.na_atime.tv_nsec; 1112 } 1113 } 1114 if (nd->nd_flag & ND_NFSV2) { 1115 if (!nd->nd_repstat) { 1116 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 1117 nfsrv_fillattr(nd, &nva); 1118 } 1119 } else { 1120 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0] 1121 || cverf[1] != tverf[1])) 1122 nd->nd_repstat = EEXIST; 1123 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 1124 vrele(dirp); 1125 if (!nd->nd_repstat) { 1126 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1); 1127 nfsrv_postopattr(nd, 0, &nva); 1128 } 1129 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1130 } 1131 1132 out: 1133 NFSEXITCODE2(0, nd); 1134 return (0); 1135 nfsmout: 1136 vput(dp); 1137 nfsvno_relpathbuf(&named); 1138 NFSEXITCODE2(error, nd); 1139 return (error); 1140 } 1141 1142 /* 1143 * nfs v3 mknod service (and v4 create) 1144 */ 1145 APPLESTATIC int 1146 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, 1147 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1148 struct nfsexstuff *exp) 1149 { 1150 struct nfsvattr nva, dirfor, diraft; 1151 u_int32_t *tl; 1152 struct nameidata named; 1153 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 1154 u_int32_t major, minor; 1155 enum vtype vtyp = VNON; 1156 nfstype nfs4type = NFNON; 1157 vnode_t vp, dirp = NULL; 1158 nfsattrbit_t attrbits; 1159 char *bufp = NULL, *pathcp = NULL; 1160 u_long *hashp, cnflags; 1161 NFSACL_T *aclp = NULL; 1162 1163 NFSVNO_ATTRINIT(&nva); 1164 cnflags = (LOCKPARENT | SAVESTART); 1165 if (nd->nd_repstat) { 1166 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1167 goto out; 1168 } 1169 #ifdef NFS4_ACL_EXTATTR_NAME 1170 aclp = acl_alloc(M_WAITOK); 1171 aclp->acl_cnt = 0; 1172 #endif 1173 1174 /* 1175 * For V4, the creation stuff is here, Yuck! 1176 */ 1177 if (nd->nd_flag & ND_NFSV4) { 1178 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1179 vtyp = nfsv34tov_type(*tl); 1180 nfs4type = fxdr_unsigned(nfstype, *tl); 1181 switch (nfs4type) { 1182 case NFLNK: 1183 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, 1184 &pathlen); 1185 if (error) 1186 goto nfsmout; 1187 break; 1188 case NFCHR: 1189 case NFBLK: 1190 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1191 major = fxdr_unsigned(u_int32_t, *tl++); 1192 minor = fxdr_unsigned(u_int32_t, *tl); 1193 nva.na_rdev = NFSMAKEDEV(major, minor); 1194 break; 1195 case NFSOCK: 1196 case NFFIFO: 1197 break; 1198 case NFDIR: 1199 cnflags = (LOCKPARENT | SAVENAME); 1200 break; 1201 default: 1202 nd->nd_repstat = NFSERR_BADTYPE; 1203 vrele(dp); 1204 #ifdef NFS4_ACL_EXTATTR_NAME 1205 acl_free(aclp); 1206 #endif 1207 goto out; 1208 } 1209 } 1210 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE); 1211 nfsvno_setpathbuf(&named, &bufp, &hashp); 1212 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1213 if (error) 1214 goto nfsmout; 1215 if (!nd->nd_repstat) { 1216 if (nd->nd_flag & ND_NFSV3) { 1217 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1218 vtyp = nfsv34tov_type(*tl); 1219 } 1220 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p); 1221 if (error) 1222 goto nfsmout; 1223 nva.na_type = vtyp; 1224 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 1225 (vtyp == VCHR || vtyp == VBLK)) { 1226 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1227 major = fxdr_unsigned(u_int32_t, *tl++); 1228 minor = fxdr_unsigned(u_int32_t, *tl); 1229 nva.na_rdev = NFSMAKEDEV(major, minor); 1230 } 1231 } 1232 1233 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 1234 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 1235 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && 1236 dirfor.na_gid == nva.na_gid) 1237 NFSVNO_UNSET(&nva, gid); 1238 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 1239 } 1240 if (nd->nd_repstat) { 1241 vrele(dp); 1242 #ifdef NFS4_ACL_EXTATTR_NAME 1243 acl_free(aclp); 1244 #endif 1245 nfsvno_relpathbuf(&named); 1246 if (pathcp) 1247 FREE(pathcp, M_TEMP); 1248 if (nd->nd_flag & ND_NFSV3) 1249 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1250 &diraft); 1251 goto out; 1252 } 1253 1254 /* 1255 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill 1256 * in va_mode, so we'll have to set a default here. 1257 */ 1258 if (NFSVNO_NOTSETMODE(&nva)) { 1259 if (vtyp == VLNK) 1260 nva.na_mode = 0755; 1261 else 1262 nva.na_mode = 0400; 1263 } 1264 1265 if (vtyp == VDIR) 1266 named.ni_cnd.cn_flags |= WILLBEDIR; 1267 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1268 if (nd->nd_repstat) { 1269 if (dirp) { 1270 if (nd->nd_flag & ND_NFSV3) 1271 dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1272 nd->nd_cred, p, 0); 1273 vrele(dirp); 1274 } 1275 #ifdef NFS4_ACL_EXTATTR_NAME 1276 acl_free(aclp); 1277 #endif 1278 if (nd->nd_flag & ND_NFSV3) 1279 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1280 &diraft); 1281 goto out; 1282 } 1283 if (dirp) 1284 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 1285 1286 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { 1287 if (vtyp == VDIR) { 1288 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, 1289 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, 1290 exp); 1291 #ifdef NFS4_ACL_EXTATTR_NAME 1292 acl_free(aclp); 1293 #endif 1294 goto out; 1295 } else if (vtyp == VLNK) { 1296 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1297 &dirfor, &diraft, &diraft_ret, &attrbits, 1298 aclp, p, exp, pathcp, pathlen); 1299 #ifdef NFS4_ACL_EXTATTR_NAME 1300 acl_free(aclp); 1301 #endif 1302 FREE(pathcp, M_TEMP); 1303 goto out; 1304 } 1305 } 1306 1307 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); 1308 if (!nd->nd_repstat) { 1309 vp = named.ni_vp; 1310 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); 1311 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 1312 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) 1313 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 1314 p, 1); 1315 if (vpp != NULL && nd->nd_repstat == 0) { 1316 NFSVOPUNLOCK(vp, 0); 1317 *vpp = vp; 1318 } else 1319 vput(vp); 1320 } 1321 1322 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 1323 vrele(dirp); 1324 if (!nd->nd_repstat) { 1325 if (nd->nd_flag & ND_NFSV3) { 1326 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1327 nfsrv_postopattr(nd, 0, &nva); 1328 } else { 1329 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1330 *tl++ = newnfs_false; 1331 txdr_hyper(dirfor.na_filerev, tl); 1332 tl += 2; 1333 txdr_hyper(diraft.na_filerev, tl); 1334 (void) nfsrv_putattrbit(nd, &attrbits); 1335 } 1336 } 1337 if (nd->nd_flag & ND_NFSV3) 1338 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1339 #ifdef NFS4_ACL_EXTATTR_NAME 1340 acl_free(aclp); 1341 #endif 1342 1343 out: 1344 NFSEXITCODE2(0, nd); 1345 return (0); 1346 nfsmout: 1347 vrele(dp); 1348 #ifdef NFS4_ACL_EXTATTR_NAME 1349 acl_free(aclp); 1350 #endif 1351 if (bufp) 1352 nfsvno_relpathbuf(&named); 1353 if (pathcp) 1354 FREE(pathcp, M_TEMP); 1355 1356 NFSEXITCODE2(error, nd); 1357 return (error); 1358 } 1359 1360 /* 1361 * nfs remove service 1362 */ 1363 APPLESTATIC int 1364 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, 1365 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 1366 { 1367 struct nameidata named; 1368 u_int32_t *tl; 1369 int error = 0, dirfor_ret = 1, diraft_ret = 1; 1370 vnode_t dirp = NULL; 1371 struct nfsvattr dirfor, diraft; 1372 char *bufp; 1373 u_long *hashp; 1374 1375 if (nd->nd_repstat) { 1376 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1377 goto out; 1378 } 1379 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, 1380 LOCKPARENT | LOCKLEAF); 1381 nfsvno_setpathbuf(&named, &bufp, &hashp); 1382 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1383 if (error) { 1384 vput(dp); 1385 nfsvno_relpathbuf(&named); 1386 goto out; 1387 } 1388 if (!nd->nd_repstat) { 1389 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 1390 } else { 1391 vput(dp); 1392 nfsvno_relpathbuf(&named); 1393 } 1394 if (dirp) { 1395 if (!(nd->nd_flag & ND_NFSV2)) { 1396 dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1397 nd->nd_cred, p, 0); 1398 } else { 1399 vrele(dirp); 1400 dirp = NULL; 1401 } 1402 } 1403 if (!nd->nd_repstat) { 1404 if (nd->nd_flag & ND_NFSV4) { 1405 if (vnode_vtype(named.ni_vp) == VDIR) 1406 nd->nd_repstat = nfsvno_rmdirsub(&named, 1, 1407 nd->nd_cred, p, exp); 1408 else 1409 nd->nd_repstat = nfsvno_removesub(&named, 1, 1410 nd->nd_cred, p, exp); 1411 } else if (nd->nd_procnum == NFSPROC_RMDIR) { 1412 nd->nd_repstat = nfsvno_rmdirsub(&named, 0, 1413 nd->nd_cred, p, exp); 1414 } else { 1415 nd->nd_repstat = nfsvno_removesub(&named, 0, 1416 nd->nd_cred, p, exp); 1417 } 1418 } 1419 if (!(nd->nd_flag & ND_NFSV2)) { 1420 if (dirp) { 1421 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, 1422 p, 0); 1423 vrele(dirp); 1424 } 1425 if (nd->nd_flag & ND_NFSV3) { 1426 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1427 &diraft); 1428 } else if (!nd->nd_repstat) { 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 } 1435 } 1436 1437 out: 1438 NFSEXITCODE2(error, nd); 1439 return (error); 1440 } 1441 1442 /* 1443 * nfs rename service 1444 */ 1445 APPLESTATIC int 1446 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, 1447 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp, 1448 struct nfsexstuff *toexp) 1449 { 1450 u_int32_t *tl; 1451 int error = 0, fdirfor_ret = 1, fdiraft_ret = 1; 1452 int tdirfor_ret = 1, tdiraft_ret = 1; 1453 struct nameidata fromnd, tond; 1454 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; 1455 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; 1456 struct nfsexstuff tnes; 1457 struct nfsrvfh tfh; 1458 char *bufp, *tbufp = NULL; 1459 u_long *hashp; 1460 fhandle_t fh; 1461 1462 if (nd->nd_repstat) { 1463 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1464 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1465 goto out; 1466 } 1467 if (!(nd->nd_flag & ND_NFSV2)) 1468 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p, 1); 1469 tond.ni_cnd.cn_nameiop = 0; 1470 tond.ni_startdir = NULL; 1471 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART); 1472 nfsvno_setpathbuf(&fromnd, &bufp, &hashp); 1473 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); 1474 if (error) { 1475 vput(dp); 1476 if (todp) 1477 vrele(todp); 1478 nfsvno_relpathbuf(&fromnd); 1479 goto out; 1480 } 1481 /* 1482 * Unlock dp in this code section, so it is unlocked before 1483 * tdp gets locked. This avoids a potential LOR if tdp is the 1484 * parent directory of dp. 1485 */ 1486 if (nd->nd_flag & ND_NFSV4) { 1487 tdp = todp; 1488 tnes = *toexp; 1489 if (dp != tdp) { 1490 NFSVOPUNLOCK(dp, 0); 1491 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 1492 p, 0); /* Might lock tdp. */ 1493 } else { 1494 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 1495 p, 1); 1496 NFSVOPUNLOCK(dp, 0); 1497 } 1498 } else { 1499 tfh.nfsrvfh_len = 0; 1500 error = nfsrv_mtofh(nd, &tfh); 1501 if (error == 0) 1502 error = nfsvno_getfh(dp, &fh, p); 1503 if (error) { 1504 vput(dp); 1505 /* todp is always NULL except NFSv4 */ 1506 nfsvno_relpathbuf(&fromnd); 1507 goto out; 1508 } 1509 1510 /* If this is the same file handle, just VREF() the vnode. */ 1511 if (tfh.nfsrvfh_len == NFSX_MYFH && 1512 !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) { 1513 VREF(dp); 1514 tdp = dp; 1515 tnes = *exp; 1516 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 1517 p, 1); 1518 NFSVOPUNLOCK(dp, 0); 1519 } else { 1520 NFSVOPUNLOCK(dp, 0); 1521 nd->nd_cred->cr_uid = nd->nd_saveduid; 1522 nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL, 1523 0, p); /* Locks tdp. */ 1524 if (tdp) { 1525 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, 1526 nd->nd_cred, p, 1); 1527 NFSVOPUNLOCK(tdp, 0); 1528 } 1529 } 1530 } 1531 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART); 1532 nfsvno_setpathbuf(&tond, &tbufp, &hashp); 1533 if (!nd->nd_repstat) { 1534 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); 1535 if (error) { 1536 if (tdp) 1537 vrele(tdp); 1538 vrele(dp); 1539 nfsvno_relpathbuf(&fromnd); 1540 nfsvno_relpathbuf(&tond); 1541 goto out; 1542 } 1543 } 1544 if (nd->nd_repstat) { 1545 if (nd->nd_flag & ND_NFSV3) { 1546 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 1547 &fdiraft); 1548 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 1549 &tdiraft); 1550 } 1551 if (tdp) 1552 vrele(tdp); 1553 vrele(dp); 1554 nfsvno_relpathbuf(&fromnd); 1555 nfsvno_relpathbuf(&tond); 1556 goto out; 1557 } 1558 1559 /* 1560 * Done parsing, now down to business. 1561 */ 1562 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp); 1563 if (nd->nd_repstat) { 1564 if (nd->nd_flag & ND_NFSV3) { 1565 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 1566 &fdiraft); 1567 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 1568 &tdiraft); 1569 } 1570 if (fdirp) 1571 vrele(fdirp); 1572 if (tdp) 1573 vrele(tdp); 1574 nfsvno_relpathbuf(&tond); 1575 goto out; 1576 } 1577 if (vnode_vtype(fromnd.ni_vp) == VDIR) 1578 tond.ni_cnd.cn_flags |= WILLBEDIR; 1579 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp); 1580 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat, 1581 nd->nd_flag, nd->nd_cred, p); 1582 if (fdirp) 1583 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p, 1584 0); 1585 if (tdirp) 1586 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p, 1587 0); 1588 if (fdirp) 1589 vrele(fdirp); 1590 if (tdirp) 1591 vrele(tdirp); 1592 if (nd->nd_flag & ND_NFSV3) { 1593 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1594 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1595 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1596 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 1597 *tl++ = newnfs_false; 1598 txdr_hyper(fdirfor.na_filerev, tl); 1599 tl += 2; 1600 txdr_hyper(fdiraft.na_filerev, tl); 1601 tl += 2; 1602 *tl++ = newnfs_false; 1603 txdr_hyper(tdirfor.na_filerev, tl); 1604 tl += 2; 1605 txdr_hyper(tdiraft.na_filerev, tl); 1606 } 1607 1608 out: 1609 NFSEXITCODE2(error, nd); 1610 return (error); 1611 } 1612 1613 /* 1614 * nfs link service 1615 */ 1616 APPLESTATIC int 1617 nfsrvd_link(struct nfsrv_descript *nd, int isdgram, 1618 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp, 1619 struct nfsexstuff *toexp) 1620 { 1621 struct nameidata named; 1622 u_int32_t *tl; 1623 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; 1624 vnode_t dirp = NULL, dp = NULL; 1625 struct nfsvattr dirfor, diraft, at; 1626 struct nfsexstuff tnes; 1627 struct nfsrvfh dfh; 1628 char *bufp; 1629 u_long *hashp; 1630 1631 if (nd->nd_repstat) { 1632 nfsrv_postopattr(nd, getret, &at); 1633 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1634 goto out; 1635 } 1636 NFSVOPUNLOCK(vp, 0); 1637 if (vnode_vtype(vp) == VDIR) { 1638 if (nd->nd_flag & ND_NFSV4) 1639 nd->nd_repstat = NFSERR_ISDIR; 1640 else 1641 nd->nd_repstat = NFSERR_INVAL; 1642 if (tovp) 1643 vrele(tovp); 1644 } 1645 if (!nd->nd_repstat) { 1646 if (nd->nd_flag & ND_NFSV4) { 1647 dp = tovp; 1648 tnes = *toexp; 1649 } else { 1650 error = nfsrv_mtofh(nd, &dfh); 1651 if (error) { 1652 vrele(vp); 1653 /* tovp is always NULL unless NFSv4 */ 1654 goto out; 1655 } 1656 nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL, 0, 1657 p); 1658 if (dp) 1659 NFSVOPUNLOCK(dp, 0); 1660 } 1661 } 1662 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1663 LOCKPARENT | SAVENAME | NOCACHE); 1664 if (!nd->nd_repstat) { 1665 nfsvno_setpathbuf(&named, &bufp, &hashp); 1666 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1667 if (error) { 1668 vrele(vp); 1669 if (dp) 1670 vrele(dp); 1671 nfsvno_relpathbuf(&named); 1672 goto out; 1673 } 1674 if (!nd->nd_repstat) { 1675 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 1676 p, &dirp); 1677 } else { 1678 if (dp) 1679 vrele(dp); 1680 nfsvno_relpathbuf(&named); 1681 } 1682 } 1683 if (dirp) { 1684 if (nd->nd_flag & ND_NFSV2) { 1685 vrele(dirp); 1686 dirp = NULL; 1687 } else { 1688 dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1689 nd->nd_cred, p, 0); 1690 } 1691 } 1692 if (!nd->nd_repstat) 1693 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 1694 if (nd->nd_flag & ND_NFSV3) 1695 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 0); 1696 if (dirp) { 1697 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 0); 1698 vrele(dirp); 1699 } 1700 vrele(vp); 1701 if (nd->nd_flag & ND_NFSV3) { 1702 nfsrv_postopattr(nd, getret, &at); 1703 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1704 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1705 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1706 *tl++ = newnfs_false; 1707 txdr_hyper(dirfor.na_filerev, tl); 1708 tl += 2; 1709 txdr_hyper(diraft.na_filerev, tl); 1710 } 1711 1712 out: 1713 NFSEXITCODE2(error, nd); 1714 return (error); 1715 } 1716 1717 /* 1718 * nfs symbolic link service 1719 */ 1720 APPLESTATIC int 1721 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1722 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1723 struct nfsexstuff *exp) 1724 { 1725 struct nfsvattr nva, dirfor, diraft; 1726 struct nameidata named; 1727 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 1728 vnode_t dirp = NULL; 1729 char *bufp, *pathcp = NULL; 1730 u_long *hashp; 1731 1732 if (nd->nd_repstat) { 1733 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1734 goto out; 1735 } 1736 if (vpp) 1737 *vpp = NULL; 1738 NFSVNO_ATTRINIT(&nva); 1739 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1740 LOCKPARENT | SAVESTART | NOCACHE); 1741 nfsvno_setpathbuf(&named, &bufp, &hashp); 1742 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1743 if (!error && !nd->nd_repstat) 1744 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 1745 if (error) { 1746 vrele(dp); 1747 nfsvno_relpathbuf(&named); 1748 goto out; 1749 } 1750 if (!nd->nd_repstat) { 1751 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1752 } else { 1753 vrele(dp); 1754 nfsvno_relpathbuf(&named); 1755 } 1756 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1757 vrele(dirp); 1758 dirp = NULL; 1759 } 1760 1761 /* 1762 * And call nfsrvd_symlinksub() to do the common code. It will 1763 * return EBADRPC upon a parsing error, 0 otherwise. 1764 */ 1765 if (!nd->nd_repstat) { 1766 if (dirp != NULL) 1767 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1768 p, 0); 1769 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1770 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 1771 pathcp, pathlen); 1772 } else if (dirp != NULL) { 1773 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 1774 vrele(dirp); 1775 } 1776 if (pathcp) 1777 FREE(pathcp, M_TEMP); 1778 1779 if (nd->nd_flag & ND_NFSV3) { 1780 if (!nd->nd_repstat) { 1781 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1782 nfsrv_postopattr(nd, 0, &nva); 1783 } 1784 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1785 } 1786 1787 out: 1788 NFSEXITCODE2(error, nd); 1789 return (error); 1790 } 1791 1792 /* 1793 * Common code for creating a symbolic link. 1794 */ 1795 static void 1796 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 1797 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1798 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1799 int *diraft_retp, nfsattrbit_t *attrbitp, 1800 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 1801 int pathlen) 1802 { 1803 u_int32_t *tl; 1804 1805 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 1806 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 1807 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 1808 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 1809 if (nd->nd_flag & ND_NFSV3) { 1810 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 1811 if (!nd->nd_repstat) 1812 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 1813 nvap, nd->nd_cred, p, 1); 1814 } 1815 if (vpp != NULL && nd->nd_repstat == 0) { 1816 NFSVOPUNLOCK(ndp->ni_vp, 0); 1817 *vpp = ndp->ni_vp; 1818 } else 1819 vput(ndp->ni_vp); 1820 } 1821 if (dirp) { 1822 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 1823 vrele(dirp); 1824 } 1825 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1826 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1827 *tl++ = newnfs_false; 1828 txdr_hyper(dirforp->na_filerev, tl); 1829 tl += 2; 1830 txdr_hyper(diraftp->na_filerev, tl); 1831 (void) nfsrv_putattrbit(nd, attrbitp); 1832 } 1833 1834 NFSEXITCODE2(0, nd); 1835 } 1836 1837 /* 1838 * nfs mkdir service 1839 */ 1840 APPLESTATIC int 1841 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 1842 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1843 struct nfsexstuff *exp) 1844 { 1845 struct nfsvattr nva, dirfor, diraft; 1846 struct nameidata named; 1847 u_int32_t *tl; 1848 int error = 0, dirfor_ret = 1, diraft_ret = 1; 1849 vnode_t dirp = NULL; 1850 char *bufp; 1851 u_long *hashp; 1852 1853 if (nd->nd_repstat) { 1854 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1855 goto out; 1856 } 1857 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1858 LOCKPARENT | SAVENAME | NOCACHE); 1859 nfsvno_setpathbuf(&named, &bufp, &hashp); 1860 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1861 if (error) 1862 goto nfsmout; 1863 if (!nd->nd_repstat) { 1864 NFSVNO_ATTRINIT(&nva); 1865 if (nd->nd_flag & ND_NFSV3) { 1866 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p); 1867 if (error) 1868 goto nfsmout; 1869 } else { 1870 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1871 nva.na_mode = nfstov_mode(*tl++); 1872 } 1873 } 1874 if (!nd->nd_repstat) { 1875 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1876 } else { 1877 vrele(dp); 1878 nfsvno_relpathbuf(&named); 1879 } 1880 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1881 vrele(dirp); 1882 dirp = NULL; 1883 } 1884 if (nd->nd_repstat) { 1885 if (dirp != NULL) { 1886 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1887 p, 0); 1888 vrele(dirp); 1889 } 1890 if (nd->nd_flag & ND_NFSV3) 1891 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1892 &diraft); 1893 goto out; 1894 } 1895 if (dirp != NULL) 1896 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p, 0); 1897 1898 /* 1899 * Call nfsrvd_mkdirsub() for the code common to V4 as well. 1900 */ 1901 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 1902 &diraft_ret, NULL, NULL, p, exp); 1903 1904 if (nd->nd_flag & ND_NFSV3) { 1905 if (!nd->nd_repstat) { 1906 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1907 nfsrv_postopattr(nd, 0, &nva); 1908 } 1909 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1910 } else if (!nd->nd_repstat) { 1911 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 1912 nfsrv_fillattr(nd, &nva); 1913 } 1914 1915 out: 1916 NFSEXITCODE2(0, nd); 1917 return (0); 1918 nfsmout: 1919 vrele(dp); 1920 nfsvno_relpathbuf(&named); 1921 NFSEXITCODE2(error, nd); 1922 return (error); 1923 } 1924 1925 /* 1926 * Code common to mkdir for V2,3 and 4. 1927 */ 1928 static void 1929 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 1930 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1931 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1932 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 1933 NFSPROC_T *p, struct nfsexstuff *exp) 1934 { 1935 vnode_t vp; 1936 u_int32_t *tl; 1937 1938 NFSVNO_SETATTRVAL(nvap, type, VDIR); 1939 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 1940 nd->nd_cred, p, exp); 1941 if (!nd->nd_repstat) { 1942 vp = ndp->ni_vp; 1943 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 1944 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 1945 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 1946 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred, 1947 p, 1); 1948 if (vpp && !nd->nd_repstat) { 1949 NFSVOPUNLOCK(vp, 0); 1950 *vpp = vp; 1951 } else { 1952 vput(vp); 1953 } 1954 } 1955 if (dirp) { 1956 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p, 0); 1957 vrele(dirp); 1958 } 1959 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1960 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1961 *tl++ = newnfs_false; 1962 txdr_hyper(dirforp->na_filerev, tl); 1963 tl += 2; 1964 txdr_hyper(diraftp->na_filerev, tl); 1965 (void) nfsrv_putattrbit(nd, attrbitp); 1966 } 1967 1968 NFSEXITCODE2(0, nd); 1969 } 1970 1971 /* 1972 * nfs commit service 1973 */ 1974 APPLESTATIC int 1975 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 1976 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1977 { 1978 struct nfsvattr bfor, aft; 1979 u_int32_t *tl; 1980 int error = 0, for_ret = 1, aft_ret = 1, cnt; 1981 u_int64_t off; 1982 1983 if (nd->nd_repstat) { 1984 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1985 goto out; 1986 } 1987 1988 /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */ 1989 if (vp->v_type != VREG) { 1990 if (nd->nd_flag & ND_NFSV3) 1991 error = NFSERR_NOTSUPP; 1992 else 1993 error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL; 1994 goto nfsmout; 1995 } 1996 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1997 1998 /* 1999 * XXX At this time VOP_FSYNC() does not accept offset and byte 2000 * count parameters, so these arguments are useless (someday maybe). 2001 */ 2002 off = fxdr_hyper(tl); 2003 tl += 2; 2004 cnt = fxdr_unsigned(int, *tl); 2005 if (nd->nd_flag & ND_NFSV3) 2006 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p, 1); 2007 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 2008 if (nd->nd_flag & ND_NFSV3) { 2009 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p, 1); 2010 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 2011 } 2012 vput(vp); 2013 if (!nd->nd_repstat) { 2014 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2015 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 2016 *tl = txdr_unsigned(nfsboottime.tv_usec); 2017 } 2018 2019 out: 2020 NFSEXITCODE2(0, nd); 2021 return (0); 2022 nfsmout: 2023 vput(vp); 2024 NFSEXITCODE2(error, nd); 2025 return (error); 2026 } 2027 2028 /* 2029 * nfs statfs service 2030 */ 2031 APPLESTATIC int 2032 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 2033 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2034 { 2035 struct statfs *sf; 2036 u_int32_t *tl; 2037 int getret = 1; 2038 struct nfsvattr at; 2039 struct statfs sfs; 2040 u_quad_t tval; 2041 2042 if (nd->nd_repstat) { 2043 nfsrv_postopattr(nd, getret, &at); 2044 goto out; 2045 } 2046 sf = &sfs; 2047 nd->nd_repstat = nfsvno_statfs(vp, sf); 2048 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2049 vput(vp); 2050 if (nd->nd_flag & ND_NFSV3) 2051 nfsrv_postopattr(nd, getret, &at); 2052 if (nd->nd_repstat) 2053 goto out; 2054 if (nd->nd_flag & ND_NFSV2) { 2055 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 2056 *tl++ = txdr_unsigned(NFS_V2MAXDATA); 2057 *tl++ = txdr_unsigned(sf->f_bsize); 2058 *tl++ = txdr_unsigned(sf->f_blocks); 2059 *tl++ = txdr_unsigned(sf->f_bfree); 2060 *tl = txdr_unsigned(sf->f_bavail); 2061 } else { 2062 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 2063 tval = (u_quad_t)sf->f_blocks; 2064 tval *= (u_quad_t)sf->f_bsize; 2065 txdr_hyper(tval, tl); tl += 2; 2066 tval = (u_quad_t)sf->f_bfree; 2067 tval *= (u_quad_t)sf->f_bsize; 2068 txdr_hyper(tval, tl); tl += 2; 2069 tval = (u_quad_t)sf->f_bavail; 2070 tval *= (u_quad_t)sf->f_bsize; 2071 txdr_hyper(tval, tl); tl += 2; 2072 tval = (u_quad_t)sf->f_files; 2073 txdr_hyper(tval, tl); tl += 2; 2074 tval = (u_quad_t)sf->f_ffree; 2075 txdr_hyper(tval, tl); tl += 2; 2076 tval = (u_quad_t)sf->f_ffree; 2077 txdr_hyper(tval, tl); tl += 2; 2078 *tl = 0; 2079 } 2080 2081 out: 2082 NFSEXITCODE2(0, nd); 2083 return (0); 2084 } 2085 2086 /* 2087 * nfs fsinfo service 2088 */ 2089 APPLESTATIC int 2090 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 2091 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2092 { 2093 u_int32_t *tl; 2094 struct nfsfsinfo fs; 2095 int getret = 1; 2096 struct nfsvattr at; 2097 2098 if (nd->nd_repstat) { 2099 nfsrv_postopattr(nd, getret, &at); 2100 goto out; 2101 } 2102 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2103 nfsvno_getfs(&fs, isdgram); 2104 vput(vp); 2105 nfsrv_postopattr(nd, getret, &at); 2106 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 2107 *tl++ = txdr_unsigned(fs.fs_rtmax); 2108 *tl++ = txdr_unsigned(fs.fs_rtpref); 2109 *tl++ = txdr_unsigned(fs.fs_rtmult); 2110 *tl++ = txdr_unsigned(fs.fs_wtmax); 2111 *tl++ = txdr_unsigned(fs.fs_wtpref); 2112 *tl++ = txdr_unsigned(fs.fs_wtmult); 2113 *tl++ = txdr_unsigned(fs.fs_dtpref); 2114 txdr_hyper(fs.fs_maxfilesize, tl); 2115 tl += 2; 2116 txdr_nfsv3time(&fs.fs_timedelta, tl); 2117 tl += 2; 2118 *tl = txdr_unsigned(fs.fs_properties); 2119 2120 out: 2121 NFSEXITCODE2(0, nd); 2122 return (0); 2123 } 2124 2125 /* 2126 * nfs pathconf service 2127 */ 2128 APPLESTATIC int 2129 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 2130 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2131 { 2132 struct nfsv3_pathconf *pc; 2133 int getret = 1; 2134 register_t linkmax, namemax, chownres, notrunc; 2135 struct nfsvattr at; 2136 2137 if (nd->nd_repstat) { 2138 nfsrv_postopattr(nd, getret, &at); 2139 goto out; 2140 } 2141 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 2142 nd->nd_cred, p); 2143 if (!nd->nd_repstat) 2144 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 2145 nd->nd_cred, p); 2146 if (!nd->nd_repstat) 2147 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 2148 &chownres, nd->nd_cred, p); 2149 if (!nd->nd_repstat) 2150 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 2151 nd->nd_cred, p); 2152 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p, 1); 2153 vput(vp); 2154 nfsrv_postopattr(nd, getret, &at); 2155 if (!nd->nd_repstat) { 2156 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 2157 pc->pc_linkmax = txdr_unsigned(linkmax); 2158 pc->pc_namemax = txdr_unsigned(namemax); 2159 pc->pc_notrunc = txdr_unsigned(notrunc); 2160 pc->pc_chownrestricted = txdr_unsigned(chownres); 2161 2162 /* 2163 * These should probably be supported by VOP_PATHCONF(), but 2164 * until msdosfs is exportable (why would you want to?), the 2165 * Unix defaults should be ok. 2166 */ 2167 pc->pc_caseinsensitive = newnfs_false; 2168 pc->pc_casepreserving = newnfs_true; 2169 } 2170 2171 out: 2172 NFSEXITCODE2(0, nd); 2173 return (0); 2174 } 2175 2176 /* 2177 * nfsv4 lock service 2178 */ 2179 APPLESTATIC int 2180 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2181 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2182 { 2183 u_int32_t *tl; 2184 int i; 2185 struct nfsstate *stp = NULL; 2186 struct nfslock *lop; 2187 struct nfslockconflict cf; 2188 int error = 0; 2189 u_short flags = NFSLCK_LOCK, lflags; 2190 u_int64_t offset, len; 2191 nfsv4stateid_t stateid; 2192 nfsquad_t clientid; 2193 2194 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2195 i = fxdr_unsigned(int, *tl++); 2196 switch (i) { 2197 case NFSV4LOCKT_READW: 2198 flags |= NFSLCK_BLOCKING; 2199 case NFSV4LOCKT_READ: 2200 lflags = NFSLCK_READ; 2201 break; 2202 case NFSV4LOCKT_WRITEW: 2203 flags |= NFSLCK_BLOCKING; 2204 case NFSV4LOCKT_WRITE: 2205 lflags = NFSLCK_WRITE; 2206 break; 2207 default: 2208 nd->nd_repstat = NFSERR_BADXDR; 2209 goto nfsmout; 2210 } 2211 if (*tl++ == newnfs_true) 2212 flags |= NFSLCK_RECLAIM; 2213 offset = fxdr_hyper(tl); 2214 tl += 2; 2215 len = fxdr_hyper(tl); 2216 tl += 2; 2217 if (*tl == newnfs_true) 2218 flags |= NFSLCK_OPENTOLOCK; 2219 if (flags & NFSLCK_OPENTOLOCK) { 2220 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 2221 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 2222 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2223 nd->nd_repstat = NFSERR_BADXDR; 2224 goto nfsmout; 2225 } 2226 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2227 M_NFSDSTATE, M_WAITOK); 2228 stp->ls_ownerlen = i; 2229 stp->ls_op = nd->nd_rp; 2230 stp->ls_seq = fxdr_unsigned(int, *tl++); 2231 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2232 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2233 NFSX_STATEIDOTHER); 2234 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2235 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 2236 clientid.lval[0] = *tl++; 2237 clientid.lval[1] = *tl++; 2238 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2239 if ((nd->nd_flag & ND_NFSV41) != 0) 2240 clientid.qval = nd->nd_clientid.qval; 2241 else if (nd->nd_clientid.qval != clientid.qval) 2242 printf("EEK3 multiple clids\n"); 2243 } else { 2244 if ((nd->nd_flag & ND_NFSV41) != 0) 2245 printf("EEK! no clientid from session\n"); 2246 nd->nd_flag |= ND_IMPLIEDCLID; 2247 nd->nd_clientid.qval = clientid.qval; 2248 } 2249 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2250 if (error) 2251 goto nfsmout; 2252 } else { 2253 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2254 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2255 M_NFSDSTATE, M_WAITOK); 2256 stp->ls_ownerlen = 0; 2257 stp->ls_op = nd->nd_rp; 2258 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2259 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2260 NFSX_STATEIDOTHER); 2261 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2262 stp->ls_seq = fxdr_unsigned(int, *tl); 2263 clientid.lval[0] = stp->ls_stateid.other[0]; 2264 clientid.lval[1] = stp->ls_stateid.other[1]; 2265 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2266 if ((nd->nd_flag & ND_NFSV41) != 0) 2267 clientid.qval = nd->nd_clientid.qval; 2268 else if (nd->nd_clientid.qval != clientid.qval) 2269 printf("EEK4 multiple clids\n"); 2270 } else { 2271 if ((nd->nd_flag & ND_NFSV41) != 0) 2272 printf("EEK! no clientid from session\n"); 2273 nd->nd_flag |= ND_IMPLIEDCLID; 2274 nd->nd_clientid.qval = clientid.qval; 2275 } 2276 } 2277 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2278 M_NFSDLOCK, M_WAITOK); 2279 lop->lo_first = offset; 2280 if (len == NFS64BITSSET) { 2281 lop->lo_end = NFS64BITSSET; 2282 } else { 2283 lop->lo_end = offset + len; 2284 if (lop->lo_end <= lop->lo_first) 2285 nd->nd_repstat = NFSERR_INVAL; 2286 } 2287 lop->lo_flags = lflags; 2288 stp->ls_flags = flags; 2289 stp->ls_uid = nd->nd_cred->cr_uid; 2290 2291 /* 2292 * Do basic access checking. 2293 */ 2294 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2295 if (vnode_vtype(vp) == VDIR) 2296 nd->nd_repstat = NFSERR_ISDIR; 2297 else 2298 nd->nd_repstat = NFSERR_INVAL; 2299 } 2300 if (!nd->nd_repstat) { 2301 if (lflags & NFSLCK_WRITE) { 2302 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 2303 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2304 NFSACCCHK_VPISLOCKED, NULL); 2305 } else { 2306 nd->nd_repstat = nfsvno_accchk(vp, VREAD, 2307 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2308 NFSACCCHK_VPISLOCKED, NULL); 2309 if (nd->nd_repstat) 2310 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2311 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2312 NFSACCCHK_VPISLOCKED, NULL); 2313 } 2314 } 2315 2316 /* 2317 * We call nfsrv_lockctrl() even if nd_repstat set, so that the 2318 * seqid# gets updated. nfsrv_lockctrl() will return the value 2319 * of nd_repstat, if it gets that far. 2320 */ 2321 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2322 &stateid, exp, nd, p); 2323 if (lop) 2324 FREE((caddr_t)lop, M_NFSDLOCK); 2325 if (stp) 2326 FREE((caddr_t)stp, M_NFSDSTATE); 2327 if (!nd->nd_repstat) { 2328 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2329 *tl++ = txdr_unsigned(stateid.seqid); 2330 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2331 } else if (nd->nd_repstat == NFSERR_DENIED) { 2332 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2333 txdr_hyper(cf.cl_first, tl); 2334 tl += 2; 2335 if (cf.cl_end == NFS64BITSSET) 2336 len = NFS64BITSSET; 2337 else 2338 len = cf.cl_end - cf.cl_first; 2339 txdr_hyper(len, tl); 2340 tl += 2; 2341 if (cf.cl_flags == NFSLCK_WRITE) 2342 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2343 else 2344 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2345 *tl++ = stateid.other[0]; 2346 *tl = stateid.other[1]; 2347 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2348 } 2349 vput(vp); 2350 NFSEXITCODE2(0, nd); 2351 return (0); 2352 nfsmout: 2353 vput(vp); 2354 if (stp) 2355 free((caddr_t)stp, M_NFSDSTATE); 2356 NFSEXITCODE2(error, nd); 2357 return (error); 2358 } 2359 2360 /* 2361 * nfsv4 lock test service 2362 */ 2363 APPLESTATIC int 2364 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2365 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2366 { 2367 u_int32_t *tl; 2368 int i; 2369 struct nfsstate *stp = NULL; 2370 struct nfslock lo, *lop = &lo; 2371 struct nfslockconflict cf; 2372 int error = 0; 2373 nfsv4stateid_t stateid; 2374 nfsquad_t clientid; 2375 u_int64_t len; 2376 2377 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 2378 i = fxdr_unsigned(int, *(tl + 7)); 2379 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2380 nd->nd_repstat = NFSERR_BADXDR; 2381 goto nfsmout; 2382 } 2383 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2384 M_NFSDSTATE, M_WAITOK); 2385 stp->ls_ownerlen = i; 2386 stp->ls_op = NULL; 2387 stp->ls_flags = NFSLCK_TEST; 2388 stp->ls_uid = nd->nd_cred->cr_uid; 2389 i = fxdr_unsigned(int, *tl++); 2390 switch (i) { 2391 case NFSV4LOCKT_READW: 2392 stp->ls_flags |= NFSLCK_BLOCKING; 2393 case NFSV4LOCKT_READ: 2394 lo.lo_flags = NFSLCK_READ; 2395 break; 2396 case NFSV4LOCKT_WRITEW: 2397 stp->ls_flags |= NFSLCK_BLOCKING; 2398 case NFSV4LOCKT_WRITE: 2399 lo.lo_flags = NFSLCK_WRITE; 2400 break; 2401 default: 2402 nd->nd_repstat = NFSERR_BADXDR; 2403 goto nfsmout; 2404 } 2405 lo.lo_first = fxdr_hyper(tl); 2406 tl += 2; 2407 len = fxdr_hyper(tl); 2408 if (len == NFS64BITSSET) { 2409 lo.lo_end = NFS64BITSSET; 2410 } else { 2411 lo.lo_end = lo.lo_first + len; 2412 if (lo.lo_end <= lo.lo_first) 2413 nd->nd_repstat = NFSERR_INVAL; 2414 } 2415 tl += 2; 2416 clientid.lval[0] = *tl++; 2417 clientid.lval[1] = *tl; 2418 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2419 if ((nd->nd_flag & ND_NFSV41) != 0) 2420 clientid.qval = nd->nd_clientid.qval; 2421 else if (nd->nd_clientid.qval != clientid.qval) 2422 printf("EEK5 multiple clids\n"); 2423 } else { 2424 if ((nd->nd_flag & ND_NFSV41) != 0) 2425 printf("EEK! no clientid from session\n"); 2426 nd->nd_flag |= ND_IMPLIEDCLID; 2427 nd->nd_clientid.qval = clientid.qval; 2428 } 2429 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2430 if (error) 2431 goto nfsmout; 2432 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2433 if (vnode_vtype(vp) == VDIR) 2434 nd->nd_repstat = NFSERR_ISDIR; 2435 else 2436 nd->nd_repstat = NFSERR_INVAL; 2437 } 2438 if (!nd->nd_repstat) 2439 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2440 &stateid, exp, nd, p); 2441 if (nd->nd_repstat) { 2442 if (nd->nd_repstat == NFSERR_DENIED) { 2443 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2444 txdr_hyper(cf.cl_first, tl); 2445 tl += 2; 2446 if (cf.cl_end == NFS64BITSSET) 2447 len = NFS64BITSSET; 2448 else 2449 len = cf.cl_end - cf.cl_first; 2450 txdr_hyper(len, tl); 2451 tl += 2; 2452 if (cf.cl_flags == NFSLCK_WRITE) 2453 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2454 else 2455 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2456 *tl++ = stp->ls_stateid.other[0]; 2457 *tl = stp->ls_stateid.other[1]; 2458 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2459 } 2460 } 2461 vput(vp); 2462 if (stp) 2463 FREE((caddr_t)stp, M_NFSDSTATE); 2464 NFSEXITCODE2(0, nd); 2465 return (0); 2466 nfsmout: 2467 vput(vp); 2468 if (stp) 2469 free((caddr_t)stp, M_NFSDSTATE); 2470 NFSEXITCODE2(error, nd); 2471 return (error); 2472 } 2473 2474 /* 2475 * nfsv4 unlock service 2476 */ 2477 APPLESTATIC int 2478 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2479 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2480 { 2481 u_int32_t *tl; 2482 int i; 2483 struct nfsstate *stp; 2484 struct nfslock *lop; 2485 int error = 0; 2486 nfsv4stateid_t stateid; 2487 nfsquad_t clientid; 2488 u_int64_t len; 2489 2490 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2491 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2492 M_NFSDSTATE, M_WAITOK); 2493 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2494 M_NFSDLOCK, M_WAITOK); 2495 stp->ls_flags = NFSLCK_UNLOCK; 2496 lop->lo_flags = NFSLCK_UNLOCK; 2497 stp->ls_op = nd->nd_rp; 2498 i = fxdr_unsigned(int, *tl++); 2499 switch (i) { 2500 case NFSV4LOCKT_READW: 2501 stp->ls_flags |= NFSLCK_BLOCKING; 2502 case NFSV4LOCKT_READ: 2503 break; 2504 case NFSV4LOCKT_WRITEW: 2505 stp->ls_flags |= NFSLCK_BLOCKING; 2506 case NFSV4LOCKT_WRITE: 2507 break; 2508 default: 2509 nd->nd_repstat = NFSERR_BADXDR; 2510 free(stp, M_NFSDSTATE); 2511 free(lop, M_NFSDLOCK); 2512 goto nfsmout; 2513 } 2514 stp->ls_ownerlen = 0; 2515 stp->ls_uid = nd->nd_cred->cr_uid; 2516 stp->ls_seq = fxdr_unsigned(int, *tl++); 2517 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2518 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2519 NFSX_STATEIDOTHER); 2520 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2521 lop->lo_first = fxdr_hyper(tl); 2522 tl += 2; 2523 len = fxdr_hyper(tl); 2524 if (len == NFS64BITSSET) { 2525 lop->lo_end = NFS64BITSSET; 2526 } else { 2527 lop->lo_end = lop->lo_first + len; 2528 if (lop->lo_end <= lop->lo_first) 2529 nd->nd_repstat = NFSERR_INVAL; 2530 } 2531 clientid.lval[0] = stp->ls_stateid.other[0]; 2532 clientid.lval[1] = stp->ls_stateid.other[1]; 2533 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2534 if ((nd->nd_flag & ND_NFSV41) != 0) 2535 clientid.qval = nd->nd_clientid.qval; 2536 else if (nd->nd_clientid.qval != clientid.qval) 2537 printf("EEK6 multiple clids\n"); 2538 } else { 2539 if ((nd->nd_flag & ND_NFSV41) != 0) 2540 printf("EEK! no clientid from session\n"); 2541 nd->nd_flag |= ND_IMPLIEDCLID; 2542 nd->nd_clientid.qval = clientid.qval; 2543 } 2544 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2545 if (vnode_vtype(vp) == VDIR) 2546 nd->nd_repstat = NFSERR_ISDIR; 2547 else 2548 nd->nd_repstat = NFSERR_INVAL; 2549 } 2550 /* 2551 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 2552 * seqid# gets incremented. nfsrv_lockctrl() will return the 2553 * value of nd_repstat, if it gets that far. 2554 */ 2555 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 2556 &stateid, exp, nd, p); 2557 if (stp) 2558 FREE((caddr_t)stp, M_NFSDSTATE); 2559 if (lop) 2560 free((caddr_t)lop, M_NFSDLOCK); 2561 if (!nd->nd_repstat) { 2562 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2563 *tl++ = txdr_unsigned(stateid.seqid); 2564 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2565 } 2566 nfsmout: 2567 vput(vp); 2568 NFSEXITCODE2(error, nd); 2569 return (error); 2570 } 2571 2572 /* 2573 * nfsv4 open service 2574 */ 2575 APPLESTATIC int 2576 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2577 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p, 2578 struct nfsexstuff *exp) 2579 { 2580 u_int32_t *tl; 2581 int i, retext; 2582 struct nfsstate *stp = NULL; 2583 int error = 0, create, claim, exclusive_flag = 0; 2584 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 2585 int how = NFSCREATE_UNCHECKED; 2586 int32_t cverf[2], tverf[2] = { 0, 0 }; 2587 vnode_t vp = NULL, dirp = NULL; 2588 struct nfsvattr nva, dirfor, diraft; 2589 struct nameidata named; 2590 nfsv4stateid_t stateid, delegstateid; 2591 nfsattrbit_t attrbits; 2592 nfsquad_t clientid; 2593 char *bufp = NULL; 2594 u_long *hashp; 2595 NFSACL_T *aclp = NULL; 2596 2597 #ifdef NFS4_ACL_EXTATTR_NAME 2598 aclp = acl_alloc(M_WAITOK); 2599 aclp->acl_cnt = 0; 2600 #endif 2601 NFSZERO_ATTRBIT(&attrbits); 2602 named.ni_startdir = NULL; 2603 named.ni_cnd.cn_nameiop = 0; 2604 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2605 i = fxdr_unsigned(int, *(tl + 5)); 2606 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2607 nd->nd_repstat = NFSERR_BADXDR; 2608 goto nfsmout; 2609 } 2610 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2611 M_NFSDSTATE, M_WAITOK); 2612 stp->ls_ownerlen = i; 2613 stp->ls_op = nd->nd_rp; 2614 stp->ls_flags = NFSLCK_OPEN; 2615 stp->ls_uid = nd->nd_cred->cr_uid; 2616 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2617 i = fxdr_unsigned(int, *tl++); 2618 retext = 0; 2619 if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG | 2620 NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) { 2621 retext = 1; 2622 /* For now, ignore these. */ 2623 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG); 2624 switch (i & NFSV4OPEN_WANTDELEGMASK) { 2625 case NFSV4OPEN_WANTANYDELEG: 2626 stp->ls_flags |= (NFSLCK_WANTRDELEG | 2627 NFSLCK_WANTWDELEG); 2628 i &= ~NFSV4OPEN_WANTDELEGMASK; 2629 break; 2630 case NFSV4OPEN_WANTREADDELEG: 2631 stp->ls_flags |= NFSLCK_WANTRDELEG; 2632 i &= ~NFSV4OPEN_WANTDELEGMASK; 2633 break; 2634 case NFSV4OPEN_WANTWRITEDELEG: 2635 stp->ls_flags |= NFSLCK_WANTWDELEG; 2636 i &= ~NFSV4OPEN_WANTDELEGMASK; 2637 break; 2638 case NFSV4OPEN_WANTNODELEG: 2639 stp->ls_flags |= NFSLCK_WANTNODELEG; 2640 i &= ~NFSV4OPEN_WANTDELEGMASK; 2641 break; 2642 case NFSV4OPEN_WANTCANCEL: 2643 printf("NFSv4: ignore Open WantCancel\n"); 2644 i &= ~NFSV4OPEN_WANTDELEGMASK; 2645 break; 2646 default: 2647 /* nd_repstat will be set to NFSERR_INVAL below. */ 2648 break; 2649 } 2650 } 2651 switch (i) { 2652 case NFSV4OPEN_ACCESSREAD: 2653 stp->ls_flags |= NFSLCK_READACCESS; 2654 break; 2655 case NFSV4OPEN_ACCESSWRITE: 2656 stp->ls_flags |= NFSLCK_WRITEACCESS; 2657 break; 2658 case NFSV4OPEN_ACCESSBOTH: 2659 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2660 break; 2661 default: 2662 nd->nd_repstat = NFSERR_INVAL; 2663 } 2664 i = fxdr_unsigned(int, *tl++); 2665 switch (i) { 2666 case NFSV4OPEN_DENYNONE: 2667 break; 2668 case NFSV4OPEN_DENYREAD: 2669 stp->ls_flags |= NFSLCK_READDENY; 2670 break; 2671 case NFSV4OPEN_DENYWRITE: 2672 stp->ls_flags |= NFSLCK_WRITEDENY; 2673 break; 2674 case NFSV4OPEN_DENYBOTH: 2675 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 2676 break; 2677 default: 2678 nd->nd_repstat = NFSERR_INVAL; 2679 } 2680 clientid.lval[0] = *tl++; 2681 clientid.lval[1] = *tl; 2682 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 2683 if ((nd->nd_flag & ND_NFSV41) != 0) 2684 clientid.qval = nd->nd_clientid.qval; 2685 else if (nd->nd_clientid.qval != clientid.qval) 2686 printf("EEK7 multiple clids\n"); 2687 } else { 2688 if ((nd->nd_flag & ND_NFSV41) != 0) 2689 printf("EEK! no clientid from session\n"); 2690 nd->nd_flag |= ND_IMPLIEDCLID; 2691 nd->nd_clientid.qval = clientid.qval; 2692 } 2693 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2694 if (error) 2695 goto nfsmout; 2696 NFSVNO_ATTRINIT(&nva); 2697 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2698 create = fxdr_unsigned(int, *tl); 2699 if (!nd->nd_repstat) 2700 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p, 0); 2701 if (create == NFSV4OPEN_CREATE) { 2702 nva.na_type = VREG; 2703 nva.na_mode = 0; 2704 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2705 how = fxdr_unsigned(int, *tl); 2706 switch (how) { 2707 case NFSCREATE_UNCHECKED: 2708 case NFSCREATE_GUARDED: 2709 error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p); 2710 if (error) 2711 goto nfsmout; 2712 /* 2713 * If the na_gid being set is the same as that of 2714 * the directory it is going in, clear it, since 2715 * that is what will be set by default. This allows 2716 * a user that isn't in that group to do the create. 2717 */ 2718 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 2719 nva.na_gid == dirfor.na_gid) 2720 NFSVNO_UNSET(&nva, gid); 2721 if (!nd->nd_repstat) 2722 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2723 break; 2724 case NFSCREATE_EXCLUSIVE: 2725 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2726 cverf[0] = *tl++; 2727 cverf[1] = *tl; 2728 break; 2729 case NFSCREATE_EXCLUSIVE41: 2730 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2731 cverf[0] = *tl++; 2732 cverf[1] = *tl; 2733 error = nfsv4_sattr(nd, vp, &nva, &attrbits, aclp, p); 2734 if (error != 0) 2735 goto nfsmout; 2736 if (NFSISSET_ATTRBIT(&attrbits, 2737 NFSATTRBIT_TIMEACCESSSET)) 2738 nd->nd_repstat = NFSERR_INVAL; 2739 /* 2740 * If the na_gid being set is the same as that of 2741 * the directory it is going in, clear it, since 2742 * that is what will be set by default. This allows 2743 * a user that isn't in that group to do the create. 2744 */ 2745 if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) && 2746 nva.na_gid == dirfor.na_gid) 2747 NFSVNO_UNSET(&nva, gid); 2748 if (nd->nd_repstat == 0) 2749 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2750 break; 2751 default: 2752 nd->nd_repstat = NFSERR_BADXDR; 2753 goto nfsmout; 2754 } 2755 } else if (create != NFSV4OPEN_NOCREATE) { 2756 nd->nd_repstat = NFSERR_BADXDR; 2757 goto nfsmout; 2758 } 2759 2760 /* 2761 * Now, handle the claim, which usually includes looking up a 2762 * name in the directory referenced by dp. The exception is 2763 * NFSV4OPEN_CLAIMPREVIOUS. 2764 */ 2765 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2766 claim = fxdr_unsigned(int, *tl); 2767 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 2768 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2769 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2770 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 2771 stp->ls_flags |= NFSLCK_DELEGCUR; 2772 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2773 stp->ls_flags |= NFSLCK_DELEGPREV; 2774 } 2775 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 2776 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2777 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 2778 claim != NFSV4OPEN_CLAIMNULL) 2779 nd->nd_repstat = NFSERR_INVAL; 2780 if (nd->nd_repstat) { 2781 nd->nd_repstat = nfsrv_opencheck(clientid, 2782 &stateid, stp, NULL, nd, p, nd->nd_repstat); 2783 goto nfsmout; 2784 } 2785 if (create == NFSV4OPEN_CREATE) 2786 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 2787 LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE); 2788 else 2789 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 2790 LOCKLEAF | SAVESTART); 2791 nfsvno_setpathbuf(&named, &bufp, &hashp); 2792 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2793 if (error) { 2794 vrele(dp); 2795 #ifdef NFS4_ACL_EXTATTR_NAME 2796 acl_free(aclp); 2797 #endif 2798 FREE((caddr_t)stp, M_NFSDSTATE); 2799 nfsvno_relpathbuf(&named); 2800 NFSEXITCODE2(error, nd); 2801 return (error); 2802 } 2803 if (!nd->nd_repstat) { 2804 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 2805 p, &dirp); 2806 } else { 2807 vrele(dp); 2808 nfsvno_relpathbuf(&named); 2809 } 2810 if (create == NFSV4OPEN_CREATE) { 2811 switch (how) { 2812 case NFSCREATE_UNCHECKED: 2813 if (named.ni_vp) { 2814 /* 2815 * Clear the setable attribute bits, except 2816 * for Size, if it is being truncated. 2817 */ 2818 NFSZERO_ATTRBIT(&attrbits); 2819 if (NFSVNO_ISSETSIZE(&nva)) 2820 NFSSETBIT_ATTRBIT(&attrbits, 2821 NFSATTRBIT_SIZE); 2822 } 2823 break; 2824 case NFSCREATE_GUARDED: 2825 if (named.ni_vp && !nd->nd_repstat) 2826 nd->nd_repstat = EEXIST; 2827 break; 2828 case NFSCREATE_EXCLUSIVE: 2829 exclusive_flag = 1; 2830 if (!named.ni_vp) 2831 nva.na_mode = 0; 2832 break; 2833 case NFSCREATE_EXCLUSIVE41: 2834 exclusive_flag = 1; 2835 break; 2836 } 2837 } 2838 nfsvno_open(nd, &named, clientid, &stateid, stp, 2839 &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 2840 nd->nd_cred, p, exp, &vp); 2841 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim == 2842 NFSV4OPEN_CLAIMFH) { 2843 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2844 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2845 i = fxdr_unsigned(int, *tl); 2846 switch (i) { 2847 case NFSV4OPEN_DELEGATEREAD: 2848 stp->ls_flags |= NFSLCK_DELEGREAD; 2849 break; 2850 case NFSV4OPEN_DELEGATEWRITE: 2851 stp->ls_flags |= NFSLCK_DELEGWRITE; 2852 case NFSV4OPEN_DELEGATENONE: 2853 break; 2854 default: 2855 nd->nd_repstat = NFSERR_BADXDR; 2856 goto nfsmout; 2857 } 2858 stp->ls_flags |= NFSLCK_RECLAIM; 2859 } else { 2860 /* CLAIM_NULL_FH */ 2861 if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE) 2862 nd->nd_repstat = NFSERR_INVAL; 2863 } 2864 vp = dp; 2865 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY); 2866 if ((vp->v_iflag & VI_DOOMED) == 0) 2867 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, 2868 stp, vp, nd, p, nd->nd_repstat); 2869 else 2870 nd->nd_repstat = NFSERR_PERM; 2871 } else { 2872 nd->nd_repstat = NFSERR_BADXDR; 2873 goto nfsmout; 2874 } 2875 2876 /* 2877 * Do basic access checking. 2878 */ 2879 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2880 /* 2881 * The IETF working group decided that this is the correct 2882 * error return for all non-regular files. 2883 */ 2884 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK; 2885 } 2886 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 2887 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 2888 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2889 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 2890 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 2891 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2892 if (nd->nd_repstat) 2893 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2894 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2895 NFSACCCHK_VPISLOCKED, NULL); 2896 } 2897 2898 if (!nd->nd_repstat) { 2899 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 2900 if (!nd->nd_repstat) { 2901 tverf[0] = nva.na_atime.tv_sec; 2902 tverf[1] = nva.na_atime.tv_nsec; 2903 } 2904 } 2905 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 2906 cverf[1] != tverf[1])) 2907 nd->nd_repstat = EEXIST; 2908 /* 2909 * Do the open locking/delegation stuff. 2910 */ 2911 if (!nd->nd_repstat) 2912 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 2913 &delegstateid, &rflags, exp, p, nva.na_filerev); 2914 2915 /* 2916 * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 2917 * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 2918 * (ie: Leave the NFSVOPUNLOCK() about here.) 2919 */ 2920 if (vp) 2921 NFSVOPUNLOCK(vp, 0); 2922 if (stp) 2923 FREE((caddr_t)stp, M_NFSDSTATE); 2924 if (!nd->nd_repstat && dirp) 2925 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p, 2926 0); 2927 if (!nd->nd_repstat) { 2928 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 2929 *tl++ = txdr_unsigned(stateid.seqid); 2930 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2931 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2932 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2933 *tl++ = newnfs_true; 2934 *tl++ = 0; 2935 *tl++ = 0; 2936 *tl++ = 0; 2937 *tl++ = 0; 2938 } else { 2939 *tl++ = newnfs_false; /* Since dirp is not locked */ 2940 txdr_hyper(dirfor.na_filerev, tl); 2941 tl += 2; 2942 txdr_hyper(diraft.na_filerev, tl); 2943 tl += 2; 2944 } 2945 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 2946 (void) nfsrv_putattrbit(nd, &attrbits); 2947 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2948 if (rflags & NFSV4OPEN_READDELEGATE) 2949 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 2950 else if (rflags & NFSV4OPEN_WRITEDELEGATE) 2951 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 2952 else if (retext != 0) { 2953 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT); 2954 if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) { 2955 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2956 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION); 2957 *tl = newnfs_false; 2958 } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) { 2959 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2960 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE); 2961 *tl = newnfs_false; 2962 } else { 2963 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2964 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED); 2965 } 2966 } else 2967 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 2968 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 2969 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 2970 *tl++ = txdr_unsigned(delegstateid.seqid); 2971 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 2972 NFSX_STATEIDOTHER); 2973 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2974 if (rflags & NFSV4OPEN_RECALL) 2975 *tl = newnfs_true; 2976 else 2977 *tl = newnfs_false; 2978 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 2979 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2980 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 2981 txdr_hyper(nva.na_size, tl); 2982 } 2983 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2984 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 2985 *tl++ = txdr_unsigned(0x0); 2986 acemask = NFSV4ACE_ALLFILESMASK; 2987 if (nva.na_mode & S_IRUSR) 2988 acemask |= NFSV4ACE_READMASK; 2989 if (nva.na_mode & S_IWUSR) 2990 acemask |= NFSV4ACE_WRITEMASK; 2991 if (nva.na_mode & S_IXUSR) 2992 acemask |= NFSV4ACE_EXECUTEMASK; 2993 *tl = txdr_unsigned(acemask); 2994 (void) nfsm_strtom(nd, "OWNER@", 6); 2995 } 2996 *vpp = vp; 2997 } else if (vp) { 2998 vrele(vp); 2999 } 3000 if (dirp) 3001 vrele(dirp); 3002 #ifdef NFS4_ACL_EXTATTR_NAME 3003 acl_free(aclp); 3004 #endif 3005 NFSEXITCODE2(0, nd); 3006 return (0); 3007 nfsmout: 3008 vrele(dp); 3009 #ifdef NFS4_ACL_EXTATTR_NAME 3010 acl_free(aclp); 3011 #endif 3012 if (stp) 3013 FREE((caddr_t)stp, M_NFSDSTATE); 3014 NFSEXITCODE2(error, nd); 3015 return (error); 3016 } 3017 3018 /* 3019 * nfsv4 close service 3020 */ 3021 APPLESTATIC int 3022 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 3023 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3024 { 3025 u_int32_t *tl; 3026 struct nfsstate st, *stp = &st; 3027 int error = 0; 3028 nfsv4stateid_t stateid; 3029 nfsquad_t clientid; 3030 3031 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 3032 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3033 stp->ls_ownerlen = 0; 3034 stp->ls_op = nd->nd_rp; 3035 stp->ls_uid = nd->nd_cred->cr_uid; 3036 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3037 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3038 NFSX_STATEIDOTHER); 3039 stp->ls_flags = NFSLCK_CLOSE; 3040 clientid.lval[0] = stp->ls_stateid.other[0]; 3041 clientid.lval[1] = stp->ls_stateid.other[1]; 3042 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3043 if ((nd->nd_flag & ND_NFSV41) != 0) 3044 clientid.qval = nd->nd_clientid.qval; 3045 else if (nd->nd_clientid.qval != clientid.qval) 3046 printf("EEK8 multiple clids\n"); 3047 } else { 3048 if ((nd->nd_flag & ND_NFSV41) != 0) 3049 printf("EEK! no clientid from session\n"); 3050 nd->nd_flag |= ND_IMPLIEDCLID; 3051 nd->nd_clientid.qval = clientid.qval; 3052 } 3053 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 3054 vput(vp); 3055 if (!nd->nd_repstat) { 3056 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3057 *tl++ = txdr_unsigned(stateid.seqid); 3058 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3059 } 3060 NFSEXITCODE2(0, nd); 3061 return (0); 3062 nfsmout: 3063 vput(vp); 3064 NFSEXITCODE2(error, nd); 3065 return (error); 3066 } 3067 3068 /* 3069 * nfsv4 delegpurge service 3070 */ 3071 APPLESTATIC int 3072 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 3073 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3074 { 3075 u_int32_t *tl; 3076 int error = 0; 3077 nfsquad_t clientid; 3078 3079 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3080 nd->nd_repstat = NFSERR_WRONGSEC; 3081 goto nfsmout; 3082 } 3083 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3084 clientid.lval[0] = *tl++; 3085 clientid.lval[1] = *tl; 3086 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3087 if ((nd->nd_flag & ND_NFSV41) != 0) 3088 clientid.qval = nd->nd_clientid.qval; 3089 else if (nd->nd_clientid.qval != clientid.qval) 3090 printf("EEK9 multiple clids\n"); 3091 } else { 3092 if ((nd->nd_flag & ND_NFSV41) != 0) 3093 printf("EEK! no clientid from session\n"); 3094 nd->nd_flag |= ND_IMPLIEDCLID; 3095 nd->nd_clientid.qval = clientid.qval; 3096 } 3097 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL, 3098 NFSV4OP_DELEGPURGE, nd->nd_cred, p); 3099 nfsmout: 3100 NFSEXITCODE2(error, nd); 3101 return (error); 3102 } 3103 3104 /* 3105 * nfsv4 delegreturn service 3106 */ 3107 APPLESTATIC int 3108 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 3109 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3110 { 3111 u_int32_t *tl; 3112 int error = 0; 3113 nfsv4stateid_t stateid; 3114 nfsquad_t clientid; 3115 3116 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3117 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3118 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 3119 clientid.lval[0] = stateid.other[0]; 3120 clientid.lval[1] = stateid.other[1]; 3121 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3122 if ((nd->nd_flag & ND_NFSV41) != 0) 3123 clientid.qval = nd->nd_clientid.qval; 3124 else if (nd->nd_clientid.qval != clientid.qval) 3125 printf("EEK10 multiple clids\n"); 3126 } else { 3127 if ((nd->nd_flag & ND_NFSV41) != 0) 3128 printf("EEK! no clientid from session\n"); 3129 nd->nd_flag |= ND_IMPLIEDCLID; 3130 nd->nd_clientid.qval = clientid.qval; 3131 } 3132 nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp, 3133 NFSV4OP_DELEGRETURN, nd->nd_cred, p); 3134 nfsmout: 3135 vput(vp); 3136 NFSEXITCODE2(error, nd); 3137 return (error); 3138 } 3139 3140 /* 3141 * nfsv4 get file handle service 3142 */ 3143 APPLESTATIC int 3144 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 3145 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3146 { 3147 fhandle_t fh; 3148 3149 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3150 vput(vp); 3151 if (!nd->nd_repstat) 3152 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 3153 NFSEXITCODE2(0, nd); 3154 return (0); 3155 } 3156 3157 /* 3158 * nfsv4 open confirm service 3159 */ 3160 APPLESTATIC int 3161 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 3162 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3163 { 3164 u_int32_t *tl; 3165 struct nfsstate st, *stp = &st; 3166 int error = 0; 3167 nfsv4stateid_t stateid; 3168 nfsquad_t clientid; 3169 3170 if ((nd->nd_flag & ND_NFSV41) != 0) { 3171 nd->nd_repstat = NFSERR_NOTSUPP; 3172 goto nfsmout; 3173 } 3174 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3175 stp->ls_ownerlen = 0; 3176 stp->ls_op = nd->nd_rp; 3177 stp->ls_uid = nd->nd_cred->cr_uid; 3178 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3179 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3180 NFSX_STATEIDOTHER); 3181 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3182 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 3183 stp->ls_flags = NFSLCK_CONFIRM; 3184 clientid.lval[0] = stp->ls_stateid.other[0]; 3185 clientid.lval[1] = stp->ls_stateid.other[1]; 3186 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3187 if ((nd->nd_flag & ND_NFSV41) != 0) 3188 clientid.qval = nd->nd_clientid.qval; 3189 else if (nd->nd_clientid.qval != clientid.qval) 3190 printf("EEK11 multiple clids\n"); 3191 } else { 3192 if ((nd->nd_flag & ND_NFSV41) != 0) 3193 printf("EEK! no clientid from session\n"); 3194 nd->nd_flag |= ND_IMPLIEDCLID; 3195 nd->nd_clientid.qval = clientid.qval; 3196 } 3197 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 3198 if (!nd->nd_repstat) { 3199 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3200 *tl++ = txdr_unsigned(stateid.seqid); 3201 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3202 } 3203 nfsmout: 3204 vput(vp); 3205 NFSEXITCODE2(error, nd); 3206 return (error); 3207 } 3208 3209 /* 3210 * nfsv4 open downgrade service 3211 */ 3212 APPLESTATIC int 3213 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 3214 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3215 { 3216 u_int32_t *tl; 3217 int i; 3218 struct nfsstate st, *stp = &st; 3219 int error = 0; 3220 nfsv4stateid_t stateid; 3221 nfsquad_t clientid; 3222 3223 /* opendowngrade can only work on a file object.*/ 3224 if (vp->v_type != VREG) { 3225 error = NFSERR_INVAL; 3226 goto nfsmout; 3227 } 3228 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 3229 stp->ls_ownerlen = 0; 3230 stp->ls_op = nd->nd_rp; 3231 stp->ls_uid = nd->nd_cred->cr_uid; 3232 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3233 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3234 NFSX_STATEIDOTHER); 3235 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3236 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3237 i = fxdr_unsigned(int, *tl++); 3238 switch (i) { 3239 case NFSV4OPEN_ACCESSREAD: 3240 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3241 break; 3242 case NFSV4OPEN_ACCESSWRITE: 3243 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3244 break; 3245 case NFSV4OPEN_ACCESSBOTH: 3246 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3247 NFSLCK_DOWNGRADE); 3248 break; 3249 default: 3250 nd->nd_repstat = NFSERR_BADXDR; 3251 } 3252 i = fxdr_unsigned(int, *tl); 3253 switch (i) { 3254 case NFSV4OPEN_DENYNONE: 3255 break; 3256 case NFSV4OPEN_DENYREAD: 3257 stp->ls_flags |= NFSLCK_READDENY; 3258 break; 3259 case NFSV4OPEN_DENYWRITE: 3260 stp->ls_flags |= NFSLCK_WRITEDENY; 3261 break; 3262 case NFSV4OPEN_DENYBOTH: 3263 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3264 break; 3265 default: 3266 nd->nd_repstat = NFSERR_BADXDR; 3267 } 3268 3269 clientid.lval[0] = stp->ls_stateid.other[0]; 3270 clientid.lval[1] = stp->ls_stateid.other[1]; 3271 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3272 if ((nd->nd_flag & ND_NFSV41) != 0) 3273 clientid.qval = nd->nd_clientid.qval; 3274 else if (nd->nd_clientid.qval != clientid.qval) 3275 printf("EEK12 multiple clids\n"); 3276 } else { 3277 if ((nd->nd_flag & ND_NFSV41) != 0) 3278 printf("EEK! no clientid from session\n"); 3279 nd->nd_flag |= ND_IMPLIEDCLID; 3280 nd->nd_clientid.qval = clientid.qval; 3281 } 3282 if (!nd->nd_repstat) 3283 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3284 nd, p); 3285 if (!nd->nd_repstat) { 3286 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3287 *tl++ = txdr_unsigned(stateid.seqid); 3288 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3289 } 3290 nfsmout: 3291 vput(vp); 3292 NFSEXITCODE2(error, nd); 3293 return (error); 3294 } 3295 3296 /* 3297 * nfsv4 renew lease service 3298 */ 3299 APPLESTATIC int 3300 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3301 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3302 { 3303 u_int32_t *tl; 3304 int error = 0; 3305 nfsquad_t clientid; 3306 3307 if ((nd->nd_flag & ND_NFSV41) != 0) { 3308 nd->nd_repstat = NFSERR_NOTSUPP; 3309 goto nfsmout; 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 *, NFSX_HYPER); 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("EEK13 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_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3330 NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p); 3331 nfsmout: 3332 NFSEXITCODE2(error, nd); 3333 return (error); 3334 } 3335 3336 /* 3337 * nfsv4 security info service 3338 */ 3339 APPLESTATIC int 3340 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3341 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 3342 { 3343 u_int32_t *tl; 3344 int len; 3345 struct nameidata named; 3346 vnode_t dirp = NULL, vp; 3347 struct nfsrvfh fh; 3348 struct nfsexstuff retnes; 3349 u_int32_t *sizp; 3350 int error = 0, savflag, i; 3351 char *bufp; 3352 u_long *hashp; 3353 3354 /* 3355 * All this just to get the export flags for the name. 3356 */ 3357 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3358 LOCKLEAF | SAVESTART); 3359 nfsvno_setpathbuf(&named, &bufp, &hashp); 3360 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3361 if (error) { 3362 vput(dp); 3363 nfsvno_relpathbuf(&named); 3364 goto out; 3365 } 3366 if (!nd->nd_repstat) { 3367 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3368 } else { 3369 vput(dp); 3370 nfsvno_relpathbuf(&named); 3371 } 3372 if (dirp) 3373 vrele(dirp); 3374 if (nd->nd_repstat) 3375 goto out; 3376 vrele(named.ni_startdir); 3377 nfsvno_relpathbuf(&named); 3378 fh.nfsrvfh_len = NFSX_MYFH; 3379 vp = named.ni_vp; 3380 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3381 vput(vp); 3382 savflag = nd->nd_flag; 3383 if (!nd->nd_repstat) { 3384 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0, p); 3385 if (vp) 3386 vput(vp); 3387 } 3388 nd->nd_flag = savflag; 3389 if (nd->nd_repstat) 3390 goto out; 3391 3392 /* 3393 * Finally have the export flags for name, so we can create 3394 * the security info. 3395 */ 3396 len = 0; 3397 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3398 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3399 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3400 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3401 *tl = txdr_unsigned(RPCAUTH_UNIX); 3402 len++; 3403 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3404 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3405 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3406 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3407 nfsgss_mechlist[KERBV_MECH].len); 3408 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3409 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3410 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3411 len++; 3412 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3413 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3414 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3415 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3416 nfsgss_mechlist[KERBV_MECH].len); 3417 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3418 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3419 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3420 len++; 3421 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3422 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3423 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3424 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3425 nfsgss_mechlist[KERBV_MECH].len); 3426 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3427 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3428 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3429 len++; 3430 } 3431 } 3432 *sizp = txdr_unsigned(len); 3433 3434 out: 3435 NFSEXITCODE2(error, nd); 3436 return (error); 3437 } 3438 3439 /* 3440 * nfsv4 set client id service 3441 */ 3442 APPLESTATIC int 3443 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3444 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3445 { 3446 u_int32_t *tl; 3447 int i; 3448 int error = 0, idlen; 3449 struct nfsclient *clp = NULL; 3450 struct sockaddr_in *rad; 3451 u_char *verf, *ucp, *ucp2, addrbuf[24]; 3452 nfsquad_t clientid, confirm; 3453 3454 if ((nd->nd_flag & ND_NFSV41) != 0) { 3455 nd->nd_repstat = NFSERR_NOTSUPP; 3456 goto nfsmout; 3457 } 3458 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3459 nd->nd_repstat = NFSERR_WRONGSEC; 3460 goto out; 3461 } 3462 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3463 verf = (u_char *)tl; 3464 tl += (NFSX_VERF / NFSX_UNSIGNED); 3465 i = fxdr_unsigned(int, *tl); 3466 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3467 nd->nd_repstat = NFSERR_BADXDR; 3468 goto nfsmout; 3469 } 3470 idlen = i; 3471 if (nd->nd_flag & ND_GSS) 3472 i += nd->nd_princlen; 3473 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3474 M_ZERO); 3475 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3476 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3477 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3478 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3479 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3480 clp->lc_req.nr_cred = NULL; 3481 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3482 clp->lc_idlen = idlen; 3483 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3484 if (error) 3485 goto nfsmout; 3486 if (nd->nd_flag & ND_GSS) { 3487 clp->lc_flags = LCL_GSS; 3488 if (nd->nd_flag & ND_GSSINTEGRITY) 3489 clp->lc_flags |= LCL_GSSINTEGRITY; 3490 else if (nd->nd_flag & ND_GSSPRIVACY) 3491 clp->lc_flags |= LCL_GSSPRIVACY; 3492 } else { 3493 clp->lc_flags = 0; 3494 } 3495 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 3496 clp->lc_flags |= LCL_NAME; 3497 clp->lc_namelen = nd->nd_princlen; 3498 clp->lc_name = &clp->lc_id[idlen]; 3499 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3500 } else { 3501 clp->lc_uid = nd->nd_cred->cr_uid; 3502 clp->lc_gid = nd->nd_cred->cr_gid; 3503 } 3504 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3505 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 3506 error = nfsrv_getclientipaddr(nd, clp); 3507 if (error) 3508 goto nfsmout; 3509 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3510 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 3511 3512 /* 3513 * nfsrv_setclient() does the actual work of adding it to the 3514 * client list. If there is no error, the structure has been 3515 * linked into the client list and clp should no longer be used 3516 * here. When an error is returned, it has not been linked in, 3517 * so it should be free'd. 3518 */ 3519 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3520 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3521 if (clp->lc_flags & LCL_TCPCALLBACK) 3522 (void) nfsm_strtom(nd, "tcp", 3); 3523 else 3524 (void) nfsm_strtom(nd, "udp", 3); 3525 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3526 ucp = (u_char *)&rad->sin_addr.s_addr; 3527 ucp2 = (u_char *)&rad->sin_port; 3528 snprintf(addrbuf, sizeof(addrbuf), "%d.%d.%d.%d.%d.%d", 3529 ucp[0] & 0xff, ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 3530 ucp2[0] & 0xff, ucp2[1] & 0xff); 3531 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3532 } 3533 if (clp) { 3534 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3535 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3536 free(clp->lc_stateid, M_NFSDCLIENT); 3537 free(clp, M_NFSDCLIENT); 3538 } 3539 if (!nd->nd_repstat) { 3540 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 3541 *tl++ = clientid.lval[0]; 3542 *tl++ = clientid.lval[1]; 3543 *tl++ = confirm.lval[0]; 3544 *tl = confirm.lval[1]; 3545 } 3546 3547 out: 3548 NFSEXITCODE2(0, nd); 3549 return (0); 3550 nfsmout: 3551 if (clp) { 3552 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3553 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3554 free(clp->lc_stateid, M_NFSDCLIENT); 3555 free(clp, M_NFSDCLIENT); 3556 } 3557 NFSEXITCODE2(error, nd); 3558 return (error); 3559 } 3560 3561 /* 3562 * nfsv4 set client id confirm service 3563 */ 3564 APPLESTATIC int 3565 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3566 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p, 3567 __unused struct nfsexstuff *exp) 3568 { 3569 u_int32_t *tl; 3570 int error = 0; 3571 nfsquad_t clientid, confirm; 3572 3573 if ((nd->nd_flag & ND_NFSV41) != 0) { 3574 nd->nd_repstat = NFSERR_NOTSUPP; 3575 goto nfsmout; 3576 } 3577 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3578 nd->nd_repstat = NFSERR_WRONGSEC; 3579 goto nfsmout; 3580 } 3581 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 3582 clientid.lval[0] = *tl++; 3583 clientid.lval[1] = *tl++; 3584 confirm.lval[0] = *tl++; 3585 confirm.lval[1] = *tl; 3586 3587 /* 3588 * nfsrv_getclient() searches the client list for a match and 3589 * returns the appropriate NFSERR status. 3590 */ 3591 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3592 NULL, NULL, confirm, 0, nd, p); 3593 nfsmout: 3594 NFSEXITCODE2(error, nd); 3595 return (error); 3596 } 3597 3598 /* 3599 * nfsv4 verify service 3600 */ 3601 APPLESTATIC int 3602 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3603 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3604 { 3605 int error = 0, ret, fhsize = NFSX_MYFH; 3606 struct nfsvattr nva; 3607 struct statfs sf; 3608 struct nfsfsinfo fs; 3609 fhandle_t fh; 3610 3611 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p, 1); 3612 if (!nd->nd_repstat) 3613 nd->nd_repstat = nfsvno_statfs(vp, &sf); 3614 if (!nd->nd_repstat) 3615 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3616 if (!nd->nd_repstat) { 3617 nfsvno_getfs(&fs, isdgram); 3618 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 3619 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 3620 if (!error) { 3621 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 3622 if (ret == 0) 3623 nd->nd_repstat = NFSERR_SAME; 3624 else if (ret != NFSERR_NOTSAME) 3625 nd->nd_repstat = ret; 3626 } else if (ret) 3627 nd->nd_repstat = ret; 3628 } 3629 } 3630 vput(vp); 3631 NFSEXITCODE2(error, nd); 3632 return (error); 3633 } 3634 3635 /* 3636 * nfs openattr rpc 3637 */ 3638 APPLESTATIC int 3639 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 3640 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3641 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3642 { 3643 u_int32_t *tl; 3644 int error = 0, createdir; 3645 3646 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3647 createdir = fxdr_unsigned(int, *tl); 3648 nd->nd_repstat = NFSERR_NOTSUPP; 3649 nfsmout: 3650 vrele(dp); 3651 NFSEXITCODE2(error, nd); 3652 return (error); 3653 } 3654 3655 /* 3656 * nfsv4 release lock owner service 3657 */ 3658 APPLESTATIC int 3659 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 3660 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3661 { 3662 u_int32_t *tl; 3663 struct nfsstate *stp = NULL; 3664 int error = 0, len; 3665 nfsquad_t clientid; 3666 3667 if ((nd->nd_flag & ND_NFSV41) != 0) { 3668 nd->nd_repstat = NFSERR_NOTSUPP; 3669 goto nfsmout; 3670 } 3671 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3672 nd->nd_repstat = NFSERR_WRONGSEC; 3673 goto nfsmout; 3674 } 3675 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3676 len = fxdr_unsigned(int, *(tl + 2)); 3677 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 3678 nd->nd_repstat = NFSERR_BADXDR; 3679 goto nfsmout; 3680 } 3681 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len, 3682 M_NFSDSTATE, M_WAITOK); 3683 stp->ls_ownerlen = len; 3684 stp->ls_op = NULL; 3685 stp->ls_flags = NFSLCK_RELEASE; 3686 stp->ls_uid = nd->nd_cred->cr_uid; 3687 clientid.lval[0] = *tl++; 3688 clientid.lval[1] = *tl; 3689 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) { 3690 if ((nd->nd_flag & ND_NFSV41) != 0) 3691 clientid.qval = nd->nd_clientid.qval; 3692 else if (nd->nd_clientid.qval != clientid.qval) 3693 printf("EEK14 multiple clids\n"); 3694 } else { 3695 if ((nd->nd_flag & ND_NFSV41) != 0) 3696 printf("EEK! no clientid from session\n"); 3697 nd->nd_flag |= ND_IMPLIEDCLID; 3698 nd->nd_clientid.qval = clientid.qval; 3699 } 3700 error = nfsrv_mtostr(nd, stp->ls_owner, len); 3701 if (error) 3702 goto nfsmout; 3703 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 3704 FREE((caddr_t)stp, M_NFSDSTATE); 3705 3706 NFSEXITCODE2(0, nd); 3707 return (0); 3708 nfsmout: 3709 if (stp) 3710 free((caddr_t)stp, M_NFSDSTATE); 3711 NFSEXITCODE2(error, nd); 3712 return (error); 3713 } 3714 3715 /* 3716 * nfsv4 exchange_id service 3717 */ 3718 APPLESTATIC int 3719 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram, 3720 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3721 { 3722 uint32_t *tl; 3723 int error = 0, i, idlen; 3724 struct nfsclient *clp = NULL; 3725 nfsquad_t clientid, confirm; 3726 uint8_t *verf; 3727 uint32_t sp4type, v41flags; 3728 uint64_t owner_minor; 3729 struct timespec verstime; 3730 3731 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3732 nd->nd_repstat = NFSERR_WRONGSEC; 3733 goto nfsmout; 3734 } 3735 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3736 verf = (uint8_t *)tl; 3737 tl += (NFSX_VERF / NFSX_UNSIGNED); 3738 i = fxdr_unsigned(int, *tl); 3739 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3740 nd->nd_repstat = NFSERR_BADXDR; 3741 goto nfsmout; 3742 } 3743 idlen = i; 3744 if (nd->nd_flag & ND_GSS) 3745 i += nd->nd_princlen; 3746 clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK | 3747 M_ZERO); 3748 clp->lc_stateid = malloc(sizeof(struct nfsstatehead) * 3749 nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK); 3750 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3751 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3752 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3753 clp->lc_req.nr_cred = NULL; 3754 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3755 clp->lc_idlen = idlen; 3756 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3757 if (error != 0) 3758 goto nfsmout; 3759 if ((nd->nd_flag & ND_GSS) != 0) { 3760 clp->lc_flags = LCL_GSS | LCL_NFSV41; 3761 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0) 3762 clp->lc_flags |= LCL_GSSINTEGRITY; 3763 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0) 3764 clp->lc_flags |= LCL_GSSPRIVACY; 3765 } else 3766 clp->lc_flags = LCL_NFSV41; 3767 if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) { 3768 clp->lc_flags |= LCL_NAME; 3769 clp->lc_namelen = nd->nd_princlen; 3770 clp->lc_name = &clp->lc_id[idlen]; 3771 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3772 } else { 3773 clp->lc_uid = nd->nd_cred->cr_uid; 3774 clp->lc_gid = nd->nd_cred->cr_gid; 3775 } 3776 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3777 v41flags = fxdr_unsigned(uint32_t, *tl++); 3778 if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR | 3779 NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS | 3780 NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) { 3781 nd->nd_repstat = NFSERR_INVAL; 3782 goto nfsmout; 3783 } 3784 if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0) 3785 confirm.lval[1] = 1; 3786 else 3787 confirm.lval[1] = 0; 3788 v41flags = NFSV4EXCH_USENONPNFS; 3789 sp4type = fxdr_unsigned(uint32_t, *tl); 3790 if (sp4type != NFSV4EXCH_SP4NONE) { 3791 nd->nd_repstat = NFSERR_NOTSUPP; 3792 goto nfsmout; 3793 } 3794 3795 /* 3796 * nfsrv_setclient() does the actual work of adding it to the 3797 * client list. If there is no error, the structure has been 3798 * linked into the client list and clp should no longer be used 3799 * here. When an error is returned, it has not been linked in, 3800 * so it should be free'd. 3801 */ 3802 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3803 if (clp != NULL) { 3804 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3805 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3806 free(clp->lc_stateid, M_NFSDCLIENT); 3807 free(clp, M_NFSDCLIENT); 3808 } 3809 if (nd->nd_repstat == 0) { 3810 if (confirm.lval[1] != 0) 3811 v41flags |= NFSV4EXCH_CONFIRMEDR; 3812 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED); 3813 *tl++ = clientid.lval[0]; /* ClientID */ 3814 *tl++ = clientid.lval[1]; 3815 *tl++ = txdr_unsigned(confirm.lval[0]); /* SequenceID */ 3816 *tl++ = txdr_unsigned(v41flags); /* Exch flags */ 3817 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); /* No SSV */ 3818 owner_minor = 0; /* Owner */ 3819 txdr_hyper(owner_minor, tl); /* Minor */ 3820 (void)nfsm_strtom(nd, nd->nd_cred->cr_prison->pr_hostuuid, 3821 strlen(nd->nd_cred->cr_prison->pr_hostuuid)); /* Major */ 3822 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 3823 *tl++ = txdr_unsigned(NFSX_UNSIGNED); 3824 *tl++ = time_uptime; /* Make scope a unique value. */ 3825 *tl = txdr_unsigned(1); 3826 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 3827 (void)nfsm_strtom(nd, version, strlen(version)); 3828 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 3829 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 3830 verstime.tv_nsec = 0; 3831 txdr_nfsv4time(&verstime, tl); 3832 } 3833 NFSEXITCODE2(0, nd); 3834 return (0); 3835 nfsmout: 3836 if (clp != NULL) { 3837 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3838 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3839 free(clp->lc_stateid, M_NFSDCLIENT); 3840 free(clp, M_NFSDCLIENT); 3841 } 3842 NFSEXITCODE2(error, nd); 3843 return (error); 3844 } 3845 3846 /* 3847 * nfsv4 create session service 3848 */ 3849 APPLESTATIC int 3850 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram, 3851 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3852 { 3853 uint32_t *tl; 3854 int error = 0; 3855 nfsquad_t clientid, confirm; 3856 struct nfsdsession *sep = NULL; 3857 uint32_t rdmacnt; 3858 3859 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3860 nd->nd_repstat = NFSERR_WRONGSEC; 3861 goto nfsmout; 3862 } 3863 sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession), 3864 M_NFSDSESSION, M_WAITOK | M_ZERO); 3865 sep->sess_refcnt = 1; 3866 mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF); 3867 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 3868 clientid.lval[0] = *tl++; 3869 clientid.lval[1] = *tl++; 3870 confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++); 3871 sep->sess_crflags = fxdr_unsigned(uint32_t, *tl); 3872 /* Persistent sessions and RDMA are not supported. */ 3873 sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN; 3874 3875 /* Fore channel attributes. */ 3876 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3877 tl++; /* Header pad always 0. */ 3878 sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++); 3879 sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++); 3880 sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++); 3881 sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++); 3882 sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++); 3883 if (sep->sess_maxslots > NFSV4_SLOTS) 3884 sep->sess_maxslots = NFSV4_SLOTS; 3885 rdmacnt = fxdr_unsigned(uint32_t, *tl); 3886 if (rdmacnt > 1) { 3887 nd->nd_repstat = NFSERR_BADXDR; 3888 goto nfsmout; 3889 } else if (rdmacnt == 1) 3890 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3891 3892 /* Back channel attributes. */ 3893 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 3894 tl++; /* Header pad always 0. */ 3895 sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++); 3896 sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++); 3897 sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++); 3898 sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++); 3899 sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++); 3900 rdmacnt = fxdr_unsigned(uint32_t, *tl); 3901 if (rdmacnt > 1) { 3902 nd->nd_repstat = NFSERR_BADXDR; 3903 goto nfsmout; 3904 } else if (rdmacnt == 1) 3905 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3906 3907 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 3908 sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl); 3909 3910 /* 3911 * nfsrv_getclient() searches the client list for a match and 3912 * returns the appropriate NFSERR status. 3913 */ 3914 nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW, 3915 NULL, sep, confirm, sep->sess_cbprogram, nd, p); 3916 if (nd->nd_repstat == 0) { 3917 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3918 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID); 3919 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED); 3920 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */ 3921 *tl++ = txdr_unsigned(sep->sess_crflags); 3922 3923 /* Fore channel attributes. */ 3924 *tl++ = 0; 3925 *tl++ = txdr_unsigned(sep->sess_maxreq); 3926 *tl++ = txdr_unsigned(sep->sess_maxresp); 3927 *tl++ = txdr_unsigned(sep->sess_maxrespcached); 3928 *tl++ = txdr_unsigned(sep->sess_maxops); 3929 *tl++ = txdr_unsigned(sep->sess_maxslots); 3930 *tl++ = txdr_unsigned(1); 3931 *tl++ = txdr_unsigned(0); /* No RDMA. */ 3932 3933 /* Back channel attributes. */ 3934 *tl++ = 0; 3935 *tl++ = txdr_unsigned(sep->sess_cbmaxreq); 3936 *tl++ = txdr_unsigned(sep->sess_cbmaxresp); 3937 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached); 3938 *tl++ = txdr_unsigned(sep->sess_cbmaxops); 3939 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots); 3940 *tl++ = txdr_unsigned(1); 3941 *tl = txdr_unsigned(0); /* No RDMA. */ 3942 } 3943 nfsmout: 3944 if (nd->nd_repstat != 0 && sep != NULL) 3945 free(sep, M_NFSDSESSION); 3946 NFSEXITCODE2(error, nd); 3947 return (error); 3948 } 3949 3950 /* 3951 * nfsv4 sequence service 3952 */ 3953 APPLESTATIC int 3954 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram, 3955 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3956 { 3957 uint32_t *tl; 3958 uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid; 3959 int cache_this, error = 0; 3960 3961 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 3962 nd->nd_repstat = NFSERR_WRONGSEC; 3963 goto nfsmout; 3964 } 3965 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID); 3966 NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID); 3967 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 3968 sequenceid = fxdr_unsigned(uint32_t, *tl++); 3969 nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++); 3970 highest_slotid = fxdr_unsigned(uint32_t, *tl++); 3971 if (*tl == newnfs_true) 3972 cache_this = 1; 3973 else 3974 cache_this = 0; 3975 nd->nd_flag |= ND_HASSEQUENCE; 3976 nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid, 3977 &target_highest_slotid, cache_this, &sflags, p); 3978 if (nd->nd_repstat == 0) { 3979 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 3980 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID); 3981 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 3982 *tl++ = txdr_unsigned(sequenceid); 3983 *tl++ = txdr_unsigned(nd->nd_slotid); 3984 *tl++ = txdr_unsigned(highest_slotid); 3985 *tl++ = txdr_unsigned(target_highest_slotid); 3986 *tl = txdr_unsigned(sflags); 3987 } 3988 nfsmout: 3989 NFSEXITCODE2(error, nd); 3990 return (error); 3991 } 3992 3993 /* 3994 * nfsv4 reclaim complete service 3995 */ 3996 APPLESTATIC int 3997 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram, 3998 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3999 { 4000 uint32_t *tl; 4001 int error = 0; 4002 4003 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4004 nd->nd_repstat = NFSERR_WRONGSEC; 4005 goto nfsmout; 4006 } 4007 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4008 if (*tl == newnfs_true) 4009 nd->nd_repstat = NFSERR_NOTSUPP; 4010 else 4011 nd->nd_repstat = nfsrv_checkreclaimcomplete(nd); 4012 nfsmout: 4013 NFSEXITCODE2(error, nd); 4014 return (error); 4015 } 4016 4017 /* 4018 * nfsv4 destroy clientid service 4019 */ 4020 APPLESTATIC int 4021 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram, 4022 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4023 { 4024 uint32_t *tl; 4025 nfsquad_t clientid; 4026 int error = 0; 4027 4028 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4029 nd->nd_repstat = NFSERR_WRONGSEC; 4030 goto nfsmout; 4031 } 4032 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4033 clientid.lval[0] = *tl++; 4034 clientid.lval[1] = *tl; 4035 nd->nd_repstat = nfsrv_destroyclient(clientid, p); 4036 nfsmout: 4037 NFSEXITCODE2(error, nd); 4038 return (error); 4039 } 4040 4041 /* 4042 * nfsv4 destroy session service 4043 */ 4044 APPLESTATIC int 4045 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram, 4046 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4047 { 4048 uint8_t *cp, sessid[NFSX_V4SESSIONID]; 4049 int error = 0; 4050 4051 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4052 nd->nd_repstat = NFSERR_WRONGSEC; 4053 goto nfsmout; 4054 } 4055 NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID); 4056 NFSBCOPY(cp, sessid, NFSX_V4SESSIONID); 4057 nd->nd_repstat = nfsrv_destroysession(nd, sessid); 4058 nfsmout: 4059 NFSEXITCODE2(error, nd); 4060 return (error); 4061 } 4062 4063 /* 4064 * nfsv4 free stateid service 4065 */ 4066 APPLESTATIC int 4067 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram, 4068 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 4069 { 4070 uint32_t *tl; 4071 nfsv4stateid_t stateid; 4072 int error = 0; 4073 4074 if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) { 4075 nd->nd_repstat = NFSERR_WRONGSEC; 4076 goto nfsmout; 4077 } 4078 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 4079 stateid.seqid = fxdr_unsigned(uint32_t, *tl++); 4080 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER); 4081 nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p); 4082 nfsmout: 4083 NFSEXITCODE2(error, nd); 4084 return (error); 4085 } 4086 4087 /* 4088 * nfsv4 service not supported 4089 */ 4090 APPLESTATIC int 4091 nfsrvd_notsupp(struct nfsrv_descript *nd, __unused int isdgram, 4092 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 4093 { 4094 4095 nd->nd_repstat = NFSERR_NOTSUPP; 4096 NFSEXITCODE2(0, nd); 4097 return (0); 4098 } 4099 4100