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