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