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