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