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