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 | SAVENAME); 1090 break; 1091 default: 1092 nd->nd_repstat = NFSERR_BADTYPE; 1093 vrele(dp); 1094 #ifdef NFS4_ACL_EXTATTR_NAME 1095 acl_free(aclp); 1096 #endif 1097 return (0); 1098 }; 1099 } 1100 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags); 1101 nfsvno_setpathbuf(&named, &bufp, &hashp); 1102 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1103 if (error) { 1104 vrele(dp); 1105 #ifdef NFS4_ACL_EXTATTR_NAME 1106 acl_free(aclp); 1107 #endif 1108 nfsvno_relpathbuf(&named); 1109 if (pathcp) 1110 FREE(pathcp, M_TEMP); 1111 return (error); 1112 } 1113 if (!nd->nd_repstat) { 1114 if (nd->nd_flag & ND_NFSV3) { 1115 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1116 vtyp = nfsv34tov_type(*tl); 1117 } 1118 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p); 1119 if (error) { 1120 vrele(dp); 1121 #ifdef NFS4_ACL_EXTATTR_NAME 1122 acl_free(aclp); 1123 #endif 1124 nfsvno_relpathbuf(&named); 1125 if (pathcp) 1126 FREE(pathcp, M_TEMP); 1127 return (error); 1128 } 1129 nva.na_type = vtyp; 1130 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 1131 (vtyp == VCHR || vtyp == VBLK)) { 1132 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1133 major = fxdr_unsigned(u_int32_t, *tl++); 1134 minor = fxdr_unsigned(u_int32_t, *tl); 1135 nva.na_rdev = NFSMAKEDEV(major, minor); 1136 } 1137 } 1138 1139 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p); 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, 1553 LOCKPARENT | SAVENAME); 1554 if (!nd->nd_repstat) { 1555 nfsvno_setpathbuf(&named, &bufp, &hashp); 1556 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1557 if (error) { 1558 vrele(vp); 1559 if (dp) { 1560 if (tnes.nes_vfslocked && !exp->nes_vfslocked && 1561 !(nd->nd_flag & ND_NFSV4)) 1562 nfsvno_unlockvfs(mp); 1563 vrele(dp); 1564 } 1565 nfsvno_relpathbuf(&named); 1566 return (error); 1567 } 1568 if (!nd->nd_repstat) { 1569 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 1570 p, &dirp); 1571 } else { 1572 if (dp) 1573 vrele(dp); 1574 nfsvno_relpathbuf(&named); 1575 } 1576 } 1577 if (dirp) { 1578 if (nd->nd_flag & ND_NFSV2) { 1579 vrele(dirp); 1580 dirp = NULL; 1581 } else { 1582 dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1583 nd->nd_cred, p); 1584 } 1585 } 1586 if (!nd->nd_repstat) 1587 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 1588 if (nd->nd_flag & ND_NFSV3) 1589 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p); 1590 if (dirp) { 1591 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p); 1592 vrele(dirp); 1593 } 1594 if (tnes.nes_vfslocked && !exp->nes_vfslocked && 1595 !(nd->nd_flag & ND_NFSV4)) 1596 nfsvno_unlockvfs(mp); 1597 vrele(vp); 1598 if (nd->nd_flag & ND_NFSV3) { 1599 nfsrv_postopattr(nd, getret, &at); 1600 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1601 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1602 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1603 *tl++ = newnfs_false; 1604 txdr_hyper(dirfor.na_filerev, tl); 1605 tl += 2; 1606 txdr_hyper(diraft.na_filerev, tl); 1607 } 1608 return (0); 1609 } 1610 1611 /* 1612 * nfs symbolic link service 1613 */ 1614 APPLESTATIC int 1615 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1616 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1617 struct nfsexstuff *exp) 1618 { 1619 struct nfsvattr nva, dirfor, diraft; 1620 struct nameidata named; 1621 int error, dirfor_ret = 1, diraft_ret = 1, pathlen; 1622 vnode_t dirp = NULL; 1623 char *bufp, *pathcp = NULL; 1624 u_long *hashp; 1625 1626 if (nd->nd_repstat) { 1627 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1628 return (0); 1629 } 1630 if (vpp) 1631 *vpp = NULL; 1632 NFSVNO_ATTRINIT(&nva); 1633 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1634 LOCKPARENT | SAVESTART); 1635 nfsvno_setpathbuf(&named, &bufp, &hashp); 1636 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1637 if (!error && !nd->nd_repstat) 1638 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 1639 if (error) { 1640 vrele(dp); 1641 nfsvno_relpathbuf(&named); 1642 return (error); 1643 } 1644 if (!nd->nd_repstat) { 1645 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1646 } else { 1647 vrele(dp); 1648 nfsvno_relpathbuf(&named); 1649 } 1650 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1651 vrele(dirp); 1652 dirp = NULL; 1653 } 1654 1655 /* 1656 * And call nfsrvd_symlinksub() to do the common code. It will 1657 * return EBADRPC upon a parsing error, 0 otherwise. 1658 */ 1659 if (!nd->nd_repstat) { 1660 if (dirp != NULL) 1661 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1662 p); 1663 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1664 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 1665 pathcp, pathlen); 1666 } else if (dirp != NULL) { 1667 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p); 1668 vrele(dirp); 1669 } 1670 if (pathcp) 1671 FREE(pathcp, M_TEMP); 1672 1673 if (nd->nd_flag & ND_NFSV3) { 1674 if (!nd->nd_repstat) { 1675 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1676 nfsrv_postopattr(nd, 0, &nva); 1677 } 1678 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1679 } 1680 return (0); 1681 } 1682 1683 /* 1684 * Common code for creating a symbolic link. 1685 */ 1686 static void 1687 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 1688 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1689 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1690 int *diraft_retp, nfsattrbit_t *attrbitp, 1691 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 1692 int pathlen) 1693 { 1694 u_int32_t *tl; 1695 1696 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 1697 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 1698 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 1699 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 1700 if (nd->nd_flag & ND_NFSV3) { 1701 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 1702 if (!nd->nd_repstat) 1703 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 1704 nvap, nd->nd_cred, p); 1705 } 1706 if (vpp) { 1707 NFSVOPUNLOCK(ndp->ni_vp, 0, p); 1708 *vpp = ndp->ni_vp; 1709 } else { 1710 vput(ndp->ni_vp); 1711 } 1712 } 1713 if (dirp) { 1714 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p); 1715 vrele(dirp); 1716 } 1717 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1718 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1719 *tl++ = newnfs_false; 1720 txdr_hyper(dirforp->na_filerev, tl); 1721 tl += 2; 1722 txdr_hyper(diraftp->na_filerev, tl); 1723 (void) nfsrv_putattrbit(nd, attrbitp); 1724 } 1725 } 1726 1727 /* 1728 * nfs mkdir service 1729 */ 1730 APPLESTATIC int 1731 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 1732 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1733 struct nfsexstuff *exp) 1734 { 1735 struct nfsvattr nva, dirfor, diraft; 1736 struct nameidata named; 1737 u_int32_t *tl; 1738 int error, dirfor_ret = 1, diraft_ret = 1; 1739 vnode_t dirp = NULL; 1740 char *bufp; 1741 u_long *hashp; 1742 1743 if (nd->nd_repstat) { 1744 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1745 return (0); 1746 } 1747 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1748 LOCKPARENT | SAVENAME); 1749 nfsvno_setpathbuf(&named, &bufp, &hashp); 1750 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1751 if (error) { 1752 vrele(dp); 1753 nfsvno_relpathbuf(&named); 1754 return (error); 1755 } 1756 if (!nd->nd_repstat) { 1757 NFSVNO_ATTRINIT(&nva); 1758 if (nd->nd_flag & ND_NFSV3) { 1759 error = nfsrv_sattr(nd, &nva, NULL, NULL, p); 1760 if (error) { 1761 vrele(dp); 1762 nfsvno_relpathbuf(&named); 1763 return (error); 1764 } 1765 } else { 1766 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1767 nva.na_mode = nfstov_mode(*tl++); 1768 } 1769 } 1770 if (!nd->nd_repstat) { 1771 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1772 } else { 1773 vrele(dp); 1774 nfsvno_relpathbuf(&named); 1775 } 1776 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1777 vrele(dirp); 1778 dirp = NULL; 1779 } 1780 if (nd->nd_repstat) { 1781 if (dirp != NULL) { 1782 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1783 p); 1784 vrele(dirp); 1785 } 1786 if (nd->nd_flag & ND_NFSV3) 1787 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1788 &diraft); 1789 return (0); 1790 } 1791 if (dirp != NULL) 1792 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p); 1793 1794 /* 1795 * Call nfsrvd_mkdirsub() for the code common to V4 as well. 1796 */ 1797 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 1798 &diraft_ret, NULL, NULL, p, exp); 1799 1800 if (nd->nd_flag & ND_NFSV3) { 1801 if (!nd->nd_repstat) { 1802 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1803 nfsrv_postopattr(nd, 0, &nva); 1804 } 1805 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1806 } else if (!nd->nd_repstat) { 1807 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 1808 nfsrv_fillattr(nd, &nva); 1809 } 1810 return (0); 1811 nfsmout: 1812 vrele(dp); 1813 nfsvno_relpathbuf(&named); 1814 return (error); 1815 } 1816 1817 /* 1818 * Code common to mkdir for V2,3 and 4. 1819 */ 1820 static void 1821 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 1822 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1823 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1824 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 1825 NFSPROC_T *p, struct nfsexstuff *exp) 1826 { 1827 vnode_t vp; 1828 u_int32_t *tl; 1829 1830 NFSVNO_SETATTRVAL(nvap, type, VDIR); 1831 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 1832 nd->nd_cred, p, exp); 1833 if (!nd->nd_repstat) { 1834 vp = ndp->ni_vp; 1835 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 1836 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 1837 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 1838 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred, 1839 p); 1840 if (vpp && !nd->nd_repstat) { 1841 NFSVOPUNLOCK(vp, 0, p); 1842 *vpp = vp; 1843 } else { 1844 vput(vp); 1845 } 1846 } 1847 if (dirp) { 1848 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p); 1849 vrele(dirp); 1850 } 1851 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1852 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1853 *tl++ = newnfs_false; 1854 txdr_hyper(dirforp->na_filerev, tl); 1855 tl += 2; 1856 txdr_hyper(diraftp->na_filerev, tl); 1857 (void) nfsrv_putattrbit(nd, attrbitp); 1858 } 1859 } 1860 1861 /* 1862 * nfs commit service 1863 */ 1864 APPLESTATIC int 1865 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 1866 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1867 { 1868 struct nfsvattr bfor, aft; 1869 u_int32_t *tl; 1870 int error = 0, for_ret = 1, aft_ret = 1, cnt; 1871 u_int64_t off; 1872 1873 if (nd->nd_repstat) { 1874 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1875 return (0); 1876 } 1877 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1878 /* 1879 * XXX At this time VOP_FSYNC() does not accept offset and byte 1880 * count parameters, so these arguments are useless (someday maybe). 1881 */ 1882 off = fxdr_hyper(tl); 1883 tl += 2; 1884 cnt = fxdr_unsigned(int, *tl); 1885 if (nd->nd_flag & ND_NFSV3) 1886 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p); 1887 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 1888 if (nd->nd_flag & ND_NFSV3) { 1889 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p); 1890 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1891 } 1892 vput(vp); 1893 if (!nd->nd_repstat) { 1894 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1895 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 1896 *tl = txdr_unsigned(nfsboottime.tv_usec); 1897 } 1898 return (0); 1899 nfsmout: 1900 vput(vp); 1901 return (error); 1902 } 1903 1904 /* 1905 * nfs statfs service 1906 */ 1907 APPLESTATIC int 1908 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 1909 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1910 { 1911 struct statfs *sf; 1912 u_int32_t *tl; 1913 int getret = 1; 1914 struct nfsvattr at; 1915 struct statfs sfs; 1916 u_quad_t tval; 1917 1918 if (nd->nd_repstat) { 1919 nfsrv_postopattr(nd, getret, &at); 1920 return (0); 1921 } 1922 sf = &sfs; 1923 nd->nd_repstat = nfsvno_statfs(vp, sf); 1924 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p); 1925 vput(vp); 1926 if (nd->nd_flag & ND_NFSV3) 1927 nfsrv_postopattr(nd, getret, &at); 1928 if (nd->nd_repstat) 1929 return (0); 1930 if (nd->nd_flag & ND_NFSV2) { 1931 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 1932 *tl++ = txdr_unsigned(NFS_V2MAXDATA); 1933 *tl++ = txdr_unsigned(sf->f_bsize); 1934 *tl++ = txdr_unsigned(sf->f_blocks); 1935 *tl++ = txdr_unsigned(sf->f_bfree); 1936 *tl = txdr_unsigned(sf->f_bavail); 1937 } else { 1938 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 1939 tval = (u_quad_t)sf->f_blocks; 1940 tval *= (u_quad_t)sf->f_bsize; 1941 txdr_hyper(tval, tl); tl += 2; 1942 tval = (u_quad_t)sf->f_bfree; 1943 tval *= (u_quad_t)sf->f_bsize; 1944 txdr_hyper(tval, tl); tl += 2; 1945 tval = (u_quad_t)sf->f_bavail; 1946 tval *= (u_quad_t)sf->f_bsize; 1947 txdr_hyper(tval, tl); tl += 2; 1948 tval = (u_quad_t)sf->f_files; 1949 txdr_hyper(tval, tl); tl += 2; 1950 tval = (u_quad_t)sf->f_ffree; 1951 txdr_hyper(tval, tl); tl += 2; 1952 tval = (u_quad_t)sf->f_ffree; 1953 txdr_hyper(tval, tl); tl += 2; 1954 *tl = 0; 1955 } 1956 return (0); 1957 } 1958 1959 /* 1960 * nfs fsinfo service 1961 */ 1962 APPLESTATIC int 1963 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 1964 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1965 { 1966 u_int32_t *tl; 1967 struct nfsfsinfo fs; 1968 int getret = 1; 1969 struct nfsvattr at; 1970 1971 if (nd->nd_repstat) { 1972 nfsrv_postopattr(nd, getret, &at); 1973 return (0); 1974 } 1975 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p); 1976 nfsvno_getfs(&fs, isdgram); 1977 vput(vp); 1978 nfsrv_postopattr(nd, getret, &at); 1979 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 1980 *tl++ = txdr_unsigned(fs.fs_rtmax); 1981 *tl++ = txdr_unsigned(fs.fs_rtpref); 1982 *tl++ = txdr_unsigned(fs.fs_rtmult); 1983 *tl++ = txdr_unsigned(fs.fs_wtmax); 1984 *tl++ = txdr_unsigned(fs.fs_wtpref); 1985 *tl++ = txdr_unsigned(fs.fs_wtmult); 1986 *tl++ = txdr_unsigned(fs.fs_dtpref); 1987 txdr_hyper(fs.fs_maxfilesize, tl); 1988 tl += 2; 1989 txdr_nfsv3time(&fs.fs_timedelta, tl); 1990 tl += 2; 1991 *tl = txdr_unsigned(fs.fs_properties); 1992 return (0); 1993 } 1994 1995 /* 1996 * nfs pathconf service 1997 */ 1998 APPLESTATIC int 1999 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 2000 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2001 { 2002 struct nfsv3_pathconf *pc; 2003 int getret = 1; 2004 register_t linkmax, namemax, chownres, notrunc; 2005 struct nfsvattr at; 2006 2007 if (nd->nd_repstat) { 2008 nfsrv_postopattr(nd, getret, &at); 2009 return (0); 2010 } 2011 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 2012 nd->nd_cred, p); 2013 if (!nd->nd_repstat) 2014 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 2015 nd->nd_cred, p); 2016 if (!nd->nd_repstat) 2017 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 2018 &chownres, nd->nd_cred, p); 2019 if (!nd->nd_repstat) 2020 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 2021 nd->nd_cred, p); 2022 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p); 2023 vput(vp); 2024 nfsrv_postopattr(nd, getret, &at); 2025 if (!nd->nd_repstat) { 2026 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 2027 pc->pc_linkmax = txdr_unsigned(linkmax); 2028 pc->pc_namemax = txdr_unsigned(namemax); 2029 pc->pc_notrunc = txdr_unsigned(notrunc); 2030 pc->pc_chownrestricted = txdr_unsigned(chownres); 2031 2032 /* 2033 * These should probably be supported by VOP_PATHCONF(), but 2034 * until msdosfs is exportable (why would you want to?), the 2035 * Unix defaults should be ok. 2036 */ 2037 pc->pc_caseinsensitive = newnfs_false; 2038 pc->pc_casepreserving = newnfs_true; 2039 } 2040 return (0); 2041 } 2042 2043 /* 2044 * nfsv4 lock service 2045 */ 2046 APPLESTATIC int 2047 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2048 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2049 { 2050 u_int32_t *tl; 2051 int i; 2052 struct nfsstate *stp = NULL; 2053 struct nfslock *lop; 2054 struct nfslockconflict cf; 2055 int error = 0; 2056 u_short flags = NFSLCK_LOCK, lflags; 2057 u_int64_t offset, len; 2058 nfsv4stateid_t stateid; 2059 nfsquad_t clientid; 2060 2061 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2062 i = fxdr_unsigned(int, *tl++); 2063 switch (i) { 2064 case NFSV4LOCKT_READW: 2065 flags |= NFSLCK_BLOCKING; 2066 case NFSV4LOCKT_READ: 2067 lflags = NFSLCK_READ; 2068 break; 2069 case NFSV4LOCKT_WRITEW: 2070 flags |= NFSLCK_BLOCKING; 2071 case NFSV4LOCKT_WRITE: 2072 lflags = NFSLCK_WRITE; 2073 break; 2074 default: 2075 nd->nd_repstat = NFSERR_BADXDR; 2076 goto nfsmout; 2077 }; 2078 if (*tl++ == newnfs_true) 2079 flags |= NFSLCK_RECLAIM; 2080 offset = fxdr_hyper(tl); 2081 tl += 2; 2082 len = fxdr_hyper(tl); 2083 tl += 2; 2084 if (*tl == newnfs_true) 2085 flags |= NFSLCK_OPENTOLOCK; 2086 if (flags & NFSLCK_OPENTOLOCK) { 2087 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 2088 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 2089 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2090 nd->nd_repstat = NFSERR_BADXDR; 2091 goto nfsmout; 2092 } 2093 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2094 M_NFSDSTATE, M_WAITOK); 2095 stp->ls_ownerlen = i; 2096 stp->ls_op = nd->nd_rp; 2097 stp->ls_seq = fxdr_unsigned(int, *tl++); 2098 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2099 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2100 NFSX_STATEIDOTHER); 2101 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2102 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 2103 clientid.lval[0] = *tl++; 2104 clientid.lval[1] = *tl++; 2105 if (nd->nd_flag & ND_IMPLIEDCLID) { 2106 if (nd->nd_clientid.qval != clientid.qval) 2107 printf("EEK! multiple clids\n"); 2108 } else { 2109 nd->nd_flag |= ND_IMPLIEDCLID; 2110 nd->nd_clientid.qval = clientid.qval; 2111 } 2112 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2113 if (error) 2114 goto nfsmout; 2115 } else { 2116 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2117 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2118 M_NFSDSTATE, M_WAITOK); 2119 stp->ls_ownerlen = 0; 2120 stp->ls_op = nd->nd_rp; 2121 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2122 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2123 NFSX_STATEIDOTHER); 2124 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2125 stp->ls_seq = fxdr_unsigned(int, *tl); 2126 clientid.lval[0] = stp->ls_stateid.other[0]; 2127 clientid.lval[1] = stp->ls_stateid.other[1]; 2128 if (nd->nd_flag & ND_IMPLIEDCLID) { 2129 if (nd->nd_clientid.qval != clientid.qval) 2130 printf("EEK! multiple clids\n"); 2131 } else { 2132 nd->nd_flag |= ND_IMPLIEDCLID; 2133 nd->nd_clientid.qval = clientid.qval; 2134 } 2135 } 2136 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2137 M_NFSDLOCK, M_WAITOK); 2138 lop->lo_first = offset; 2139 if (len == NFS64BITSSET) { 2140 lop->lo_end = NFS64BITSSET; 2141 } else { 2142 lop->lo_end = offset + len; 2143 if (lop->lo_end <= lop->lo_first) 2144 nd->nd_repstat = NFSERR_INVAL; 2145 } 2146 lop->lo_flags = lflags; 2147 stp->ls_flags = flags; 2148 stp->ls_uid = nd->nd_cred->cr_uid; 2149 2150 /* 2151 * Do basic access checking. 2152 */ 2153 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2154 if (vnode_vtype(vp) == VDIR) 2155 nd->nd_repstat = NFSERR_ISDIR; 2156 else 2157 nd->nd_repstat = NFSERR_INVAL; 2158 } 2159 if (!nd->nd_repstat) { 2160 if (lflags & NFSLCK_WRITE) { 2161 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, 2162 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2163 NFSACCCHK_VPISLOCKED, NULL); 2164 } else { 2165 nd->nd_repstat = nfsvno_accchk(vp, VREAD, 2166 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2167 NFSACCCHK_VPISLOCKED, NULL); 2168 if (nd->nd_repstat) 2169 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2170 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2171 NFSACCCHK_VPISLOCKED, NULL); 2172 } 2173 } 2174 2175 /* 2176 * We call nfsrv_lockctrl() even if nd_repstat set, so that the 2177 * seqid# gets updated. nfsrv_lockctrl() will return the value 2178 * of nd_repstat, if it gets that far. 2179 */ 2180 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2181 &stateid, exp, nd, p); 2182 if (lop) 2183 FREE((caddr_t)lop, M_NFSDLOCK); 2184 if (stp) 2185 FREE((caddr_t)stp, M_NFSDSTATE); 2186 if (!nd->nd_repstat) { 2187 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2188 *tl++ = txdr_unsigned(stateid.seqid); 2189 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2190 } else if (nd->nd_repstat == NFSERR_DENIED) { 2191 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2192 txdr_hyper(cf.cl_first, tl); 2193 tl += 2; 2194 if (cf.cl_end == NFS64BITSSET) 2195 len = NFS64BITSSET; 2196 else 2197 len = cf.cl_end - cf.cl_first; 2198 txdr_hyper(len, tl); 2199 tl += 2; 2200 if (cf.cl_flags == NFSLCK_WRITE) 2201 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2202 else 2203 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2204 *tl++ = stateid.other[0]; 2205 *tl = stateid.other[1]; 2206 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2207 } 2208 vput(vp); 2209 return (0); 2210 nfsmout: 2211 vput(vp); 2212 if (stp) 2213 free((caddr_t)stp, M_NFSDSTATE); 2214 return (error); 2215 } 2216 2217 /* 2218 * nfsv4 lock test service 2219 */ 2220 APPLESTATIC int 2221 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2222 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2223 { 2224 u_int32_t *tl; 2225 int i; 2226 struct nfsstate *stp = NULL; 2227 struct nfslock lo, *lop = &lo; 2228 struct nfslockconflict cf; 2229 int error = 0; 2230 nfsv4stateid_t stateid; 2231 nfsquad_t clientid; 2232 u_int64_t len; 2233 2234 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 2235 i = fxdr_unsigned(int, *(tl + 7)); 2236 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2237 nd->nd_repstat = NFSERR_BADXDR; 2238 goto nfsmout; 2239 } 2240 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2241 M_NFSDSTATE, M_WAITOK); 2242 stp->ls_ownerlen = i; 2243 stp->ls_op = NULL; 2244 stp->ls_flags = NFSLCK_TEST; 2245 stp->ls_uid = nd->nd_cred->cr_uid; 2246 i = fxdr_unsigned(int, *tl++); 2247 switch (i) { 2248 case NFSV4LOCKT_READW: 2249 stp->ls_flags |= NFSLCK_BLOCKING; 2250 case NFSV4LOCKT_READ: 2251 lo.lo_flags = NFSLCK_READ; 2252 break; 2253 case NFSV4LOCKT_WRITEW: 2254 stp->ls_flags |= NFSLCK_BLOCKING; 2255 case NFSV4LOCKT_WRITE: 2256 lo.lo_flags = NFSLCK_WRITE; 2257 break; 2258 default: 2259 nd->nd_repstat = NFSERR_BADXDR; 2260 goto nfsmout; 2261 }; 2262 lo.lo_first = fxdr_hyper(tl); 2263 tl += 2; 2264 len = fxdr_hyper(tl); 2265 if (len == NFS64BITSSET) { 2266 lo.lo_end = NFS64BITSSET; 2267 } else { 2268 lo.lo_end = lo.lo_first + len; 2269 if (lo.lo_end <= lo.lo_first) 2270 nd->nd_repstat = NFSERR_INVAL; 2271 } 2272 tl += 2; 2273 clientid.lval[0] = *tl++; 2274 clientid.lval[1] = *tl; 2275 if (nd->nd_flag & ND_IMPLIEDCLID) { 2276 if (nd->nd_clientid.qval != clientid.qval) 2277 printf("EEK! multiple clids\n"); 2278 } else { 2279 nd->nd_flag |= ND_IMPLIEDCLID; 2280 nd->nd_clientid.qval = clientid.qval; 2281 } 2282 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2283 if (error) 2284 goto nfsmout; 2285 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2286 if (vnode_vtype(vp) == VDIR) 2287 nd->nd_repstat = NFSERR_ISDIR; 2288 else 2289 nd->nd_repstat = NFSERR_INVAL; 2290 } 2291 if (!nd->nd_repstat) 2292 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2293 &stateid, exp, nd, p); 2294 if (stp) 2295 FREE((caddr_t)stp, M_NFSDSTATE); 2296 if (nd->nd_repstat) { 2297 if (nd->nd_repstat == NFSERR_DENIED) { 2298 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2299 txdr_hyper(cf.cl_first, tl); 2300 tl += 2; 2301 if (cf.cl_end == NFS64BITSSET) 2302 len = NFS64BITSSET; 2303 else 2304 len = cf.cl_end - cf.cl_first; 2305 txdr_hyper(len, tl); 2306 tl += 2; 2307 if (cf.cl_flags == NFSLCK_WRITE) 2308 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2309 else 2310 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2311 *tl++ = stp->ls_stateid.other[0]; 2312 *tl = stp->ls_stateid.other[1]; 2313 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2314 } 2315 } 2316 vput(vp); 2317 return (0); 2318 nfsmout: 2319 vput(vp); 2320 if (stp) 2321 free((caddr_t)stp, M_NFSDSTATE); 2322 return (error); 2323 } 2324 2325 /* 2326 * nfsv4 unlock service 2327 */ 2328 APPLESTATIC int 2329 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2330 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2331 { 2332 u_int32_t *tl; 2333 int i; 2334 struct nfsstate *stp; 2335 struct nfslock *lop; 2336 int error = 0; 2337 nfsv4stateid_t stateid; 2338 nfsquad_t clientid; 2339 u_int64_t len; 2340 2341 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2342 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2343 M_NFSDSTATE, M_WAITOK); 2344 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2345 M_NFSDLOCK, M_WAITOK); 2346 stp->ls_flags = NFSLCK_UNLOCK; 2347 lop->lo_flags = NFSLCK_UNLOCK; 2348 stp->ls_op = nd->nd_rp; 2349 i = fxdr_unsigned(int, *tl++); 2350 switch (i) { 2351 case NFSV4LOCKT_READW: 2352 stp->ls_flags |= NFSLCK_BLOCKING; 2353 case NFSV4LOCKT_READ: 2354 break; 2355 case NFSV4LOCKT_WRITEW: 2356 stp->ls_flags |= NFSLCK_BLOCKING; 2357 case NFSV4LOCKT_WRITE: 2358 break; 2359 default: 2360 nd->nd_repstat = NFSERR_BADXDR; 2361 free(stp, M_NFSDSTATE); 2362 free(lop, M_NFSDLOCK); 2363 goto nfsmout; 2364 }; 2365 stp->ls_ownerlen = 0; 2366 stp->ls_uid = nd->nd_cred->cr_uid; 2367 stp->ls_seq = fxdr_unsigned(int, *tl++); 2368 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2369 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2370 NFSX_STATEIDOTHER); 2371 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2372 lop->lo_first = fxdr_hyper(tl); 2373 tl += 2; 2374 len = fxdr_hyper(tl); 2375 if (len == NFS64BITSSET) { 2376 lop->lo_end = NFS64BITSSET; 2377 } else { 2378 lop->lo_end = lop->lo_first + len; 2379 if (lop->lo_end <= lop->lo_first) 2380 nd->nd_repstat = NFSERR_INVAL; 2381 } 2382 clientid.lval[0] = stp->ls_stateid.other[0]; 2383 clientid.lval[1] = stp->ls_stateid.other[1]; 2384 if (nd->nd_flag & ND_IMPLIEDCLID) { 2385 if (nd->nd_clientid.qval != clientid.qval) 2386 printf("EEK! multiple clids\n"); 2387 } else { 2388 nd->nd_flag |= ND_IMPLIEDCLID; 2389 nd->nd_clientid.qval = clientid.qval; 2390 } 2391 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2392 if (vnode_vtype(vp) == VDIR) 2393 nd->nd_repstat = NFSERR_ISDIR; 2394 else 2395 nd->nd_repstat = NFSERR_INVAL; 2396 } 2397 /* 2398 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 2399 * seqid# gets incremented. nfsrv_lockctrl() will return the 2400 * value of nd_repstat, if it gets that far. 2401 */ 2402 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 2403 &stateid, exp, nd, p); 2404 if (stp) 2405 FREE((caddr_t)stp, M_NFSDSTATE); 2406 if (lop) 2407 free((caddr_t)lop, M_NFSDLOCK); 2408 if (!nd->nd_repstat) { 2409 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2410 *tl++ = txdr_unsigned(stateid.seqid); 2411 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2412 } 2413 nfsmout: 2414 vput(vp); 2415 return (error); 2416 } 2417 2418 /* 2419 * nfsv4 open service 2420 */ 2421 APPLESTATIC int 2422 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2423 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p, 2424 struct nfsexstuff *exp) 2425 { 2426 u_int32_t *tl; 2427 int i; 2428 struct nfsstate *stp = NULL; 2429 int error = 0, create, claim, exclusive_flag = 0; 2430 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 2431 int how = NFSCREATE_UNCHECKED; 2432 int32_t cverf[2], tverf[2] = { 0, 0 }; 2433 vnode_t vp = NULL, dirp = NULL; 2434 struct nfsvattr nva, dirfor, diraft; 2435 struct nameidata named; 2436 nfsv4stateid_t stateid, delegstateid; 2437 nfsattrbit_t attrbits; 2438 nfsquad_t clientid; 2439 char *bufp = NULL; 2440 u_long *hashp; 2441 NFSACL_T *aclp = NULL; 2442 2443 #ifdef NFS4_ACL_EXTATTR_NAME 2444 aclp = acl_alloc(M_WAITOK); 2445 aclp->acl_cnt = 0; 2446 #endif 2447 NFSZERO_ATTRBIT(&attrbits); 2448 named.ni_startdir = NULL; 2449 named.ni_cnd.cn_nameiop = 0; 2450 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2451 i = fxdr_unsigned(int, *(tl + 5)); 2452 if (i <= 0 || i > NFSV4_OPAQUELIMIT) { 2453 nd->nd_repstat = NFSERR_BADXDR; 2454 vrele(dp); 2455 #ifdef NFS4_ACL_EXTATTR_NAME 2456 acl_free(aclp); 2457 #endif 2458 return (0); 2459 } 2460 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2461 M_NFSDSTATE, M_WAITOK); 2462 stp->ls_ownerlen = i; 2463 stp->ls_op = nd->nd_rp; 2464 stp->ls_flags = NFSLCK_OPEN; 2465 stp->ls_uid = nd->nd_cred->cr_uid; 2466 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2467 i = fxdr_unsigned(int, *tl++); 2468 switch (i) { 2469 case NFSV4OPEN_ACCESSREAD: 2470 stp->ls_flags |= NFSLCK_READACCESS; 2471 break; 2472 case NFSV4OPEN_ACCESSWRITE: 2473 stp->ls_flags |= NFSLCK_WRITEACCESS; 2474 break; 2475 case NFSV4OPEN_ACCESSBOTH: 2476 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2477 break; 2478 default: 2479 nd->nd_repstat = NFSERR_INVAL; 2480 }; 2481 i = fxdr_unsigned(int, *tl++); 2482 switch (i) { 2483 case NFSV4OPEN_DENYNONE: 2484 break; 2485 case NFSV4OPEN_DENYREAD: 2486 stp->ls_flags |= NFSLCK_READDENY; 2487 break; 2488 case NFSV4OPEN_DENYWRITE: 2489 stp->ls_flags |= NFSLCK_WRITEDENY; 2490 break; 2491 case NFSV4OPEN_DENYBOTH: 2492 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 2493 break; 2494 default: 2495 nd->nd_repstat = NFSERR_INVAL; 2496 }; 2497 clientid.lval[0] = *tl++; 2498 clientid.lval[1] = *tl; 2499 if (nd->nd_flag & ND_IMPLIEDCLID) { 2500 if (nd->nd_clientid.qval != clientid.qval) 2501 printf("EEK! multiple clids\n"); 2502 } else { 2503 nd->nd_flag |= ND_IMPLIEDCLID; 2504 nd->nd_clientid.qval = clientid.qval; 2505 } 2506 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2507 if (error) { 2508 vrele(dp); 2509 #ifdef NFS4_ACL_EXTATTR_NAME 2510 acl_free(aclp); 2511 #endif 2512 FREE((caddr_t)stp, M_NFSDSTATE); 2513 return (error); 2514 } 2515 NFSVNO_ATTRINIT(&nva); 2516 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2517 create = fxdr_unsigned(int, *tl); 2518 if (!nd->nd_repstat) 2519 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p); 2520 if (create == NFSV4OPEN_CREATE) { 2521 nva.na_type = VREG; 2522 nva.na_mode = 0; 2523 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2524 how = fxdr_unsigned(int, *tl); 2525 switch (how) { 2526 case NFSCREATE_UNCHECKED: 2527 case NFSCREATE_GUARDED: 2528 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p); 2529 if (error) { 2530 vrele(dp); 2531 #ifdef NFS4_ACL_EXTATTR_NAME 2532 acl_free(aclp); 2533 #endif 2534 FREE((caddr_t)stp, M_NFSDSTATE); 2535 return (error); 2536 } 2537 /* 2538 * If the na_gid being set is the same as that of 2539 * the directory it is going in, clear it, since 2540 * that is what will be set by default. This allows 2541 * a user that isn't in that group to do the create. 2542 */ 2543 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 2544 nva.na_gid == dirfor.na_gid) 2545 NFSVNO_UNSET(&nva, gid); 2546 if (!nd->nd_repstat) 2547 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2548 break; 2549 case NFSCREATE_EXCLUSIVE: 2550 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2551 cverf[0] = *tl++; 2552 cverf[1] = *tl; 2553 break; 2554 default: 2555 nd->nd_repstat = NFSERR_BADXDR; 2556 vrele(dp); 2557 #ifdef NFS4_ACL_EXTATTR_NAME 2558 acl_free(aclp); 2559 #endif 2560 FREE((caddr_t)stp, M_NFSDSTATE); 2561 return (0); 2562 }; 2563 } else if (create != NFSV4OPEN_NOCREATE) { 2564 nd->nd_repstat = NFSERR_BADXDR; 2565 vrele(dp); 2566 #ifdef NFS4_ACL_EXTATTR_NAME 2567 acl_free(aclp); 2568 #endif 2569 FREE((caddr_t)stp, M_NFSDSTATE); 2570 return (0); 2571 } 2572 2573 /* 2574 * Now, handle the claim, which usually includes looking up a 2575 * name in the directory referenced by dp. The exception is 2576 * NFSV4OPEN_CLAIMPREVIOUS. 2577 */ 2578 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2579 claim = fxdr_unsigned(int, *tl); 2580 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 2581 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2582 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2583 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 2584 stp->ls_flags |= NFSLCK_DELEGCUR; 2585 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2586 stp->ls_flags |= NFSLCK_DELEGPREV; 2587 } 2588 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 2589 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2590 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 2591 claim != NFSV4OPEN_CLAIMNULL) 2592 nd->nd_repstat = NFSERR_INVAL; 2593 if (nd->nd_repstat) { 2594 nd->nd_repstat = nfsrv_opencheck(clientid, 2595 &stateid, stp, NULL, nd, p, nd->nd_repstat); 2596 vrele(dp); 2597 #ifdef NFS4_ACL_EXTATTR_NAME 2598 acl_free(aclp); 2599 #endif 2600 FREE((caddr_t)stp, M_NFSDSTATE); 2601 return (0); 2602 } 2603 if (create == NFSV4OPEN_CREATE) 2604 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 2605 LOCKPARENT | LOCKLEAF | SAVESTART); 2606 else 2607 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 2608 LOCKLEAF | SAVESTART); 2609 nfsvno_setpathbuf(&named, &bufp, &hashp); 2610 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2611 if (error) { 2612 vrele(dp); 2613 #ifdef NFS4_ACL_EXTATTR_NAME 2614 acl_free(aclp); 2615 #endif 2616 FREE((caddr_t)stp, M_NFSDSTATE); 2617 nfsvno_relpathbuf(&named); 2618 return (error); 2619 } 2620 if (!nd->nd_repstat) { 2621 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 2622 p, &dirp); 2623 } else { 2624 vrele(dp); 2625 nfsvno_relpathbuf(&named); 2626 } 2627 if (create == NFSV4OPEN_CREATE) { 2628 switch (how) { 2629 case NFSCREATE_UNCHECKED: 2630 if (named.ni_vp) { 2631 /* 2632 * Clear the setable attribute bits, except 2633 * for Size, if it is being truncated. 2634 */ 2635 NFSZERO_ATTRBIT(&attrbits); 2636 if (NFSVNO_ISSETSIZE(&nva)) 2637 NFSSETBIT_ATTRBIT(&attrbits, 2638 NFSATTRBIT_SIZE); 2639 } 2640 break; 2641 case NFSCREATE_GUARDED: 2642 if (named.ni_vp && !nd->nd_repstat) 2643 nd->nd_repstat = EEXIST; 2644 break; 2645 case NFSCREATE_EXCLUSIVE: 2646 exclusive_flag = 1; 2647 if (!named.ni_vp) 2648 nva.na_mode = 0; 2649 }; 2650 } 2651 nfsvno_open(nd, &named, clientid, &stateid, stp, 2652 &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 2653 nd->nd_cred, p, exp, &vp); 2654 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2655 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2656 i = fxdr_unsigned(int, *tl); 2657 switch (i) { 2658 case NFSV4OPEN_DELEGATEREAD: 2659 stp->ls_flags |= NFSLCK_DELEGREAD; 2660 break; 2661 case NFSV4OPEN_DELEGATEWRITE: 2662 stp->ls_flags |= NFSLCK_DELEGWRITE; 2663 case NFSV4OPEN_DELEGATENONE: 2664 break; 2665 default: 2666 nd->nd_repstat = NFSERR_BADXDR; 2667 vrele(dp); 2668 #ifdef NFS4_ACL_EXTATTR_NAME 2669 acl_free(aclp); 2670 #endif 2671 FREE((caddr_t)stp, M_NFSDSTATE); 2672 return (0); 2673 }; 2674 stp->ls_flags |= NFSLCK_RECLAIM; 2675 vp = dp; 2676 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p); 2677 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, stp, vp, 2678 nd, p, nd->nd_repstat); 2679 } else { 2680 nd->nd_repstat = NFSERR_BADXDR; 2681 vrele(dp); 2682 #ifdef NFS4_ACL_EXTATTR_NAME 2683 acl_free(aclp); 2684 #endif 2685 FREE((caddr_t)stp, M_NFSDSTATE); 2686 return (0); 2687 } 2688 2689 /* 2690 * Do basic access checking. 2691 */ 2692 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2693 if (vnode_vtype(vp) == VDIR) 2694 nd->nd_repstat = NFSERR_ISDIR; 2695 else if (vnode_vtype(vp) == VLNK) 2696 nd->nd_repstat = NFSERR_SYMLINK; 2697 else 2698 nd->nd_repstat = NFSERR_INVAL; 2699 } 2700 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 2701 nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred, 2702 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2703 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 2704 nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred, 2705 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL); 2706 if (nd->nd_repstat) 2707 nd->nd_repstat = nfsvno_accchk(vp, VEXEC, 2708 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2709 NFSACCCHK_VPISLOCKED, NULL); 2710 } 2711 2712 if (!nd->nd_repstat) { 2713 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p); 2714 if (!nd->nd_repstat) { 2715 tverf[0] = nva.na_atime.tv_sec; 2716 tverf[1] = nva.na_atime.tv_nsec; 2717 } 2718 } 2719 if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] || 2720 cverf[1] != tverf[1])) 2721 nd->nd_repstat = EEXIST; 2722 /* 2723 * Do the open locking/delegation stuff. 2724 */ 2725 if (!nd->nd_repstat) 2726 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 2727 &delegstateid, &rflags, exp, p, nva.na_filerev); 2728 2729 /* 2730 * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 2731 * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 2732 * (ie: Leave the NFSVOPUNLOCK() about here.) 2733 */ 2734 if (vp) 2735 NFSVOPUNLOCK(vp, 0, p); 2736 if (stp) 2737 FREE((caddr_t)stp, M_NFSDSTATE); 2738 if (!nd->nd_repstat && dirp) 2739 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p); 2740 if (!nd->nd_repstat) { 2741 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 2742 *tl++ = txdr_unsigned(stateid.seqid); 2743 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2744 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2745 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2746 *tl++ = newnfs_true; 2747 *tl++ = 0; 2748 *tl++ = 0; 2749 *tl++ = 0; 2750 *tl++ = 0; 2751 } else { 2752 *tl++ = newnfs_false; /* Since dirp is not locked */ 2753 txdr_hyper(dirfor.na_filerev, tl); 2754 tl += 2; 2755 txdr_hyper(diraft.na_filerev, tl); 2756 tl += 2; 2757 } 2758 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 2759 (void) nfsrv_putattrbit(nd, &attrbits); 2760 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2761 if (rflags & NFSV4OPEN_READDELEGATE) 2762 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 2763 else if (rflags & NFSV4OPEN_WRITEDELEGATE) 2764 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 2765 else 2766 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 2767 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 2768 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 2769 *tl++ = txdr_unsigned(delegstateid.seqid); 2770 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 2771 NFSX_STATEIDOTHER); 2772 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2773 if (rflags & NFSV4OPEN_RECALL) 2774 *tl = newnfs_true; 2775 else 2776 *tl = newnfs_false; 2777 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 2778 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2779 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 2780 txdr_hyper(nva.na_size, tl); 2781 } 2782 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2783 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 2784 *tl++ = txdr_unsigned(0x0); 2785 acemask = NFSV4ACE_ALLFILESMASK; 2786 if (nva.na_mode & S_IRUSR) 2787 acemask |= NFSV4ACE_READMASK; 2788 if (nva.na_mode & S_IWUSR) 2789 acemask |= NFSV4ACE_WRITEMASK; 2790 if (nva.na_mode & S_IXUSR) 2791 acemask |= NFSV4ACE_EXECUTEMASK; 2792 *tl = txdr_unsigned(acemask); 2793 (void) nfsm_strtom(nd, "OWNER@", 6); 2794 } 2795 *vpp = vp; 2796 } else if (vp) { 2797 vrele(vp); 2798 } 2799 if (dirp) 2800 vrele(dirp); 2801 #ifdef NFS4_ACL_EXTATTR_NAME 2802 acl_free(aclp); 2803 #endif 2804 return (0); 2805 nfsmout: 2806 vrele(dp); 2807 #ifdef NFS4_ACL_EXTATTR_NAME 2808 acl_free(aclp); 2809 #endif 2810 if (stp) 2811 FREE((caddr_t)stp, M_NFSDSTATE); 2812 return (error); 2813 } 2814 2815 /* 2816 * nfsv4 close service 2817 */ 2818 APPLESTATIC int 2819 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 2820 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2821 { 2822 u_int32_t *tl; 2823 struct nfsstate st, *stp = &st; 2824 int error = 0; 2825 nfsv4stateid_t stateid; 2826 nfsquad_t clientid; 2827 2828 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 2829 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2830 stp->ls_ownerlen = 0; 2831 stp->ls_op = nd->nd_rp; 2832 stp->ls_uid = nd->nd_cred->cr_uid; 2833 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2834 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2835 NFSX_STATEIDOTHER); 2836 stp->ls_flags = NFSLCK_CLOSE; 2837 clientid.lval[0] = stp->ls_stateid.other[0]; 2838 clientid.lval[1] = stp->ls_stateid.other[1]; 2839 if (nd->nd_flag & ND_IMPLIEDCLID) { 2840 if (nd->nd_clientid.qval != clientid.qval) 2841 printf("EEK! multiple clids\n"); 2842 } else { 2843 nd->nd_flag |= ND_IMPLIEDCLID; 2844 nd->nd_clientid.qval = clientid.qval; 2845 } 2846 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 2847 vput(vp); 2848 if (!nd->nd_repstat) { 2849 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2850 *tl++ = txdr_unsigned(stateid.seqid); 2851 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2852 } 2853 return (0); 2854 nfsmout: 2855 vput(vp); 2856 return (error); 2857 } 2858 2859 /* 2860 * nfsv4 delegpurge service 2861 */ 2862 APPLESTATIC int 2863 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 2864 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 2865 { 2866 u_int32_t *tl; 2867 int error = 0; 2868 nfsquad_t clientid; 2869 2870 if ((!nfs_rootfhset && !nfsv4root_set) || 2871 nfsd_checkrootexp(nd)) { 2872 nd->nd_repstat = NFSERR_WRONGSEC; 2873 return (0); 2874 } 2875 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2876 clientid.lval[0] = *tl++; 2877 clientid.lval[1] = *tl; 2878 if (nd->nd_flag & ND_IMPLIEDCLID) { 2879 if (nd->nd_clientid.qval != clientid.qval) 2880 printf("EEK! multiple clids\n"); 2881 } else { 2882 nd->nd_flag |= ND_IMPLIEDCLID; 2883 nd->nd_clientid.qval = clientid.qval; 2884 } 2885 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL, 2886 NFSV4OP_DELEGPURGE, nd->nd_cred, p); 2887 nfsmout: 2888 return (error); 2889 } 2890 2891 /* 2892 * nfsv4 delegreturn service 2893 */ 2894 APPLESTATIC int 2895 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 2896 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2897 { 2898 u_int32_t *tl; 2899 int error = 0; 2900 nfsv4stateid_t stateid; 2901 nfsquad_t clientid; 2902 2903 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2904 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2905 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 2906 clientid.lval[0] = stateid.other[0]; 2907 clientid.lval[1] = stateid.other[1]; 2908 if (nd->nd_flag & ND_IMPLIEDCLID) { 2909 if (nd->nd_clientid.qval != clientid.qval) 2910 printf("EEK! multiple clids\n"); 2911 } else { 2912 nd->nd_flag |= ND_IMPLIEDCLID; 2913 nd->nd_clientid.qval = clientid.qval; 2914 } 2915 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp, 2916 NFSV4OP_DELEGRETURN, nd->nd_cred, p); 2917 nfsmout: 2918 vput(vp); 2919 return (error); 2920 } 2921 2922 /* 2923 * nfsv4 get file handle service 2924 */ 2925 APPLESTATIC int 2926 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 2927 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2928 { 2929 fhandle_t fh; 2930 2931 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 2932 vput(vp); 2933 if (!nd->nd_repstat) 2934 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 2935 return (0); 2936 } 2937 2938 /* 2939 * nfsv4 open confirm service 2940 */ 2941 APPLESTATIC int 2942 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 2943 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2944 { 2945 u_int32_t *tl; 2946 struct nfsstate st, *stp = &st; 2947 int error = 0; 2948 nfsv4stateid_t stateid; 2949 nfsquad_t clientid; 2950 2951 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2952 stp->ls_ownerlen = 0; 2953 stp->ls_op = nd->nd_rp; 2954 stp->ls_uid = nd->nd_cred->cr_uid; 2955 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2956 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2957 NFSX_STATEIDOTHER); 2958 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2959 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 2960 stp->ls_flags = NFSLCK_CONFIRM; 2961 clientid.lval[0] = stp->ls_stateid.other[0]; 2962 clientid.lval[1] = stp->ls_stateid.other[1]; 2963 if (nd->nd_flag & ND_IMPLIEDCLID) { 2964 if (nd->nd_clientid.qval != clientid.qval) 2965 printf("EEK! multiple clids\n"); 2966 } else { 2967 nd->nd_flag |= ND_IMPLIEDCLID; 2968 nd->nd_clientid.qval = clientid.qval; 2969 } 2970 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 2971 if (!nd->nd_repstat) { 2972 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2973 *tl++ = txdr_unsigned(stateid.seqid); 2974 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2975 } 2976 nfsmout: 2977 vput(vp); 2978 return (error); 2979 } 2980 2981 /* 2982 * nfsv4 open downgrade service 2983 */ 2984 APPLESTATIC int 2985 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 2986 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2987 { 2988 u_int32_t *tl; 2989 int i; 2990 struct nfsstate st, *stp = &st; 2991 int error = 0; 2992 nfsv4stateid_t stateid; 2993 nfsquad_t clientid; 2994 2995 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 2996 stp->ls_ownerlen = 0; 2997 stp->ls_op = nd->nd_rp; 2998 stp->ls_uid = nd->nd_cred->cr_uid; 2999 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 3000 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 3001 NFSX_STATEIDOTHER); 3002 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 3003 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 3004 i = fxdr_unsigned(int, *tl++); 3005 switch (i) { 3006 case NFSV4OPEN_ACCESSREAD: 3007 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 3008 break; 3009 case NFSV4OPEN_ACCESSWRITE: 3010 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 3011 break; 3012 case NFSV4OPEN_ACCESSBOTH: 3013 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 3014 NFSLCK_DOWNGRADE); 3015 break; 3016 default: 3017 nd->nd_repstat = NFSERR_BADXDR; 3018 }; 3019 i = fxdr_unsigned(int, *tl); 3020 switch (i) { 3021 case NFSV4OPEN_DENYNONE: 3022 break; 3023 case NFSV4OPEN_DENYREAD: 3024 stp->ls_flags |= NFSLCK_READDENY; 3025 break; 3026 case NFSV4OPEN_DENYWRITE: 3027 stp->ls_flags |= NFSLCK_WRITEDENY; 3028 break; 3029 case NFSV4OPEN_DENYBOTH: 3030 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 3031 break; 3032 default: 3033 nd->nd_repstat = NFSERR_BADXDR; 3034 }; 3035 3036 clientid.lval[0] = stp->ls_stateid.other[0]; 3037 clientid.lval[1] = stp->ls_stateid.other[1]; 3038 if (nd->nd_flag & ND_IMPLIEDCLID) { 3039 if (nd->nd_clientid.qval != clientid.qval) 3040 printf("EEK! multiple clids\n"); 3041 } else { 3042 nd->nd_flag |= ND_IMPLIEDCLID; 3043 nd->nd_clientid.qval = clientid.qval; 3044 } 3045 if (!nd->nd_repstat) 3046 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3047 nd, p); 3048 if (!nd->nd_repstat) { 3049 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3050 *tl++ = txdr_unsigned(stateid.seqid); 3051 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3052 } 3053 nfsmout: 3054 vput(vp); 3055 return (error); 3056 } 3057 3058 /* 3059 * nfsv4 renew lease service 3060 */ 3061 APPLESTATIC int 3062 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3063 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3064 { 3065 u_int32_t *tl; 3066 int error = 0; 3067 nfsquad_t clientid; 3068 3069 if ((!nfs_rootfhset && !nfsv4root_set) || 3070 nfsd_checkrootexp(nd)) { 3071 nd->nd_repstat = NFSERR_WRONGSEC; 3072 return (0); 3073 } 3074 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3075 clientid.lval[0] = *tl++; 3076 clientid.lval[1] = *tl; 3077 if (nd->nd_flag & ND_IMPLIEDCLID) { 3078 if (nd->nd_clientid.qval != clientid.qval) 3079 printf("EEK! multiple clids\n"); 3080 } else { 3081 nd->nd_flag |= ND_IMPLIEDCLID; 3082 nd->nd_clientid.qval = clientid.qval; 3083 } 3084 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3085 NULL, (nfsquad_t)((u_quad_t)0), nd, p); 3086 nfsmout: 3087 return (error); 3088 } 3089 3090 /* 3091 * nfsv4 security info service 3092 */ 3093 APPLESTATIC int 3094 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3095 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 3096 { 3097 u_int32_t *tl; 3098 int len; 3099 struct nameidata named; 3100 vnode_t dirp = NULL, vp; 3101 struct nfsrvfh fh; 3102 struct nfsexstuff retnes; 3103 mount_t mp; 3104 u_int32_t *sizp; 3105 int error, savflag, i; 3106 char *bufp; 3107 u_long *hashp; 3108 3109 /* 3110 * All this just to get the export flags for the name. 3111 */ 3112 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3113 LOCKLEAF | SAVESTART); 3114 nfsvno_setpathbuf(&named, &bufp, &hashp); 3115 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3116 if (error) { 3117 vput(dp); 3118 nfsvno_relpathbuf(&named); 3119 return (error); 3120 } 3121 if (!nd->nd_repstat) { 3122 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3123 } else { 3124 vput(dp); 3125 nfsvno_relpathbuf(&named); 3126 } 3127 if (dirp) 3128 vrele(dirp); 3129 if (nd->nd_repstat) 3130 return (0); 3131 vrele(named.ni_startdir); 3132 nfsvno_relpathbuf(&named); 3133 fh.nfsrvfh_len = NFSX_MYFH; 3134 vp = named.ni_vp; 3135 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3136 mp = vnode_mount(vp); /* so it won't try to re-lock filesys */ 3137 retnes.nes_vfslocked = exp->nes_vfslocked; 3138 vput(vp); 3139 savflag = nd->nd_flag; 3140 if (!nd->nd_repstat) { 3141 nfsd_fhtovp(nd, &fh, &vp, &retnes, &mp, 0, p); 3142 if (vp) 3143 vput(vp); 3144 } 3145 nd->nd_flag = savflag; 3146 if (nd->nd_repstat) 3147 return (0); 3148 3149 /* 3150 * Finally have the export flags for name, so we can create 3151 * the security info. 3152 */ 3153 len = 0; 3154 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3155 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3156 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3157 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3158 *tl = txdr_unsigned(RPCAUTH_UNIX); 3159 len++; 3160 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3161 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3162 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3163 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3164 nfsgss_mechlist[KERBV_MECH].len); 3165 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3166 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3167 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3168 len++; 3169 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3170 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3171 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3172 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3173 nfsgss_mechlist[KERBV_MECH].len); 3174 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3175 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3176 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3177 len++; 3178 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3179 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3180 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3181 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3182 nfsgss_mechlist[KERBV_MECH].len); 3183 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3184 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3185 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3186 len++; 3187 } 3188 } 3189 *sizp = txdr_unsigned(len); 3190 return (0); 3191 } 3192 3193 /* 3194 * nfsv4 set client id service 3195 */ 3196 APPLESTATIC int 3197 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3198 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3199 { 3200 u_int32_t *tl; 3201 int i; 3202 int error = 0, idlen; 3203 struct nfsclient *clp = NULL; 3204 struct sockaddr_in *rad; 3205 u_char *verf, *ucp, *ucp2, addrbuf[24]; 3206 nfsquad_t clientid, confirm; 3207 3208 if ((!nfs_rootfhset && !nfsv4root_set) || 3209 nfsd_checkrootexp(nd)) { 3210 nd->nd_repstat = NFSERR_WRONGSEC; 3211 return (0); 3212 } 3213 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3214 verf = (u_char *)tl; 3215 tl += (NFSX_VERF / NFSX_UNSIGNED); 3216 i = fxdr_unsigned(int, *tl); 3217 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3218 nd->nd_repstat = NFSERR_BADXDR; 3219 return (error); 3220 } 3221 idlen = i; 3222 if (nd->nd_flag & ND_GSS) 3223 i += nd->nd_princlen; 3224 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i, 3225 M_NFSDCLIENT, M_WAITOK); 3226 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i); 3227 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3228 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3229 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3230 clp->lc_req.nr_cred = NULL; 3231 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3232 clp->lc_idlen = idlen; 3233 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3234 if (error) 3235 goto nfsmout; 3236 if (nd->nd_flag & ND_GSS) { 3237 clp->lc_flags = LCL_GSS; 3238 if (nd->nd_flag & ND_GSSINTEGRITY) 3239 clp->lc_flags |= LCL_GSSINTEGRITY; 3240 else if (nd->nd_flag & ND_GSSPRIVACY) 3241 clp->lc_flags |= LCL_GSSPRIVACY; 3242 } else { 3243 clp->lc_flags = 0; 3244 } 3245 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 3246 clp->lc_flags |= LCL_NAME; 3247 clp->lc_namelen = nd->nd_princlen; 3248 clp->lc_name = &clp->lc_id[idlen]; 3249 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3250 } else { 3251 clp->lc_uid = nd->nd_cred->cr_uid; 3252 clp->lc_gid = nd->nd_cred->cr_gid; 3253 } 3254 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3255 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 3256 error = nfsrv_getclientipaddr(nd, clp); 3257 if (error) 3258 goto nfsmout; 3259 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3260 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 3261 3262 /* 3263 * nfsrv_setclient() does the actual work of adding it to the 3264 * client list. If there is no error, the structure has been 3265 * linked into the client list and clp should no longer be used 3266 * here. When an error is returned, it has not been linked in, 3267 * so it should be free'd. 3268 */ 3269 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3270 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3271 if (clp->lc_flags & LCL_TCPCALLBACK) 3272 (void) nfsm_strtom(nd, "tcp", 3); 3273 else 3274 (void) nfsm_strtom(nd, "udp", 3); 3275 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3276 ucp = (u_char *)&rad->sin_addr.s_addr; 3277 ucp2 = (u_char *)&rad->sin_port; 3278 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 3279 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 3280 ucp2[0] & 0xff, ucp2[1] & 0xff); 3281 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3282 } 3283 if (clp) { 3284 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3285 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3286 free((caddr_t)clp, M_NFSDCLIENT); 3287 } 3288 if (!nd->nd_repstat) { 3289 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 3290 *tl++ = clientid.lval[0]; 3291 *tl++ = clientid.lval[1]; 3292 *tl++ = confirm.lval[0]; 3293 *tl = confirm.lval[1]; 3294 } 3295 return (0); 3296 nfsmout: 3297 if (clp) { 3298 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3299 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3300 free((caddr_t)clp, M_NFSDCLIENT); 3301 } 3302 return (error); 3303 } 3304 3305 /* 3306 * nfsv4 set client id confirm service 3307 */ 3308 APPLESTATIC int 3309 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3310 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p, 3311 __unused struct nfsexstuff *exp) 3312 { 3313 u_int32_t *tl; 3314 int error = 0; 3315 nfsquad_t clientid, confirm; 3316 3317 if ((!nfs_rootfhset && !nfsv4root_set) || 3318 nfsd_checkrootexp(nd)) { 3319 nd->nd_repstat = NFSERR_WRONGSEC; 3320 return (0); 3321 } 3322 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 3323 clientid.lval[0] = *tl++; 3324 clientid.lval[1] = *tl++; 3325 confirm.lval[0] = *tl++; 3326 confirm.lval[1] = *tl; 3327 3328 /* 3329 * nfsrv_getclient() searches the client list for a match and 3330 * returns the appropriate NFSERR status. 3331 */ 3332 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3333 NULL, confirm, nd, p); 3334 nfsmout: 3335 return (error); 3336 } 3337 3338 /* 3339 * nfsv4 verify service 3340 */ 3341 APPLESTATIC int 3342 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3343 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3344 { 3345 int error = 0, ret, fhsize = NFSX_MYFH; 3346 struct nfsvattr nva; 3347 struct statfs sf; 3348 struct nfsfsinfo fs; 3349 fhandle_t fh; 3350 3351 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p); 3352 if (!nd->nd_repstat) 3353 nd->nd_repstat = nfsvno_statfs(vp, &sf); 3354 if (!nd->nd_repstat) 3355 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3356 if (!nd->nd_repstat) { 3357 nfsvno_getfs(&fs, isdgram); 3358 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 3359 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 3360 if (!error) { 3361 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 3362 if (ret == 0) 3363 nd->nd_repstat = NFSERR_SAME; 3364 else if (ret != NFSERR_NOTSAME) 3365 nd->nd_repstat = ret; 3366 } else if (ret) 3367 nd->nd_repstat = ret; 3368 } 3369 } 3370 vput(vp); 3371 return (error); 3372 } 3373 3374 /* 3375 * nfs openattr rpc 3376 */ 3377 APPLESTATIC int 3378 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 3379 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3380 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3381 { 3382 u_int32_t *tl; 3383 int error = 0, createdir; 3384 3385 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3386 createdir = fxdr_unsigned(int, *tl); 3387 nd->nd_repstat = NFSERR_NOTSUPP; 3388 nfsmout: 3389 vrele(dp); 3390 return (error); 3391 } 3392 3393 /* 3394 * nfsv4 release lock owner service 3395 */ 3396 APPLESTATIC int 3397 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 3398 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3399 { 3400 u_int32_t *tl; 3401 struct nfsstate *stp = NULL; 3402 int error = 0, len; 3403 nfsquad_t clientid; 3404 3405 if ((!nfs_rootfhset && !nfsv4root_set) || 3406 nfsd_checkrootexp(nd)) { 3407 nd->nd_repstat = NFSERR_WRONGSEC; 3408 return (0); 3409 } 3410 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3411 len = fxdr_unsigned(int, *(tl + 2)); 3412 if (len <= 0 || len > NFSV4_OPAQUELIMIT) { 3413 nd->nd_repstat = NFSERR_BADXDR; 3414 return (0); 3415 } 3416 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len, 3417 M_NFSDSTATE, M_WAITOK); 3418 stp->ls_ownerlen = len; 3419 stp->ls_op = NULL; 3420 stp->ls_flags = NFSLCK_RELEASE; 3421 stp->ls_uid = nd->nd_cred->cr_uid; 3422 clientid.lval[0] = *tl++; 3423 clientid.lval[1] = *tl; 3424 if (nd->nd_flag & ND_IMPLIEDCLID) { 3425 if (nd->nd_clientid.qval != clientid.qval) 3426 printf("EEK! multiple clids\n"); 3427 } else { 3428 nd->nd_flag |= ND_IMPLIEDCLID; 3429 nd->nd_clientid.qval = clientid.qval; 3430 } 3431 error = nfsrv_mtostr(nd, stp->ls_owner, len); 3432 if (error) 3433 goto nfsmout; 3434 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 3435 FREE((caddr_t)stp, M_NFSDSTATE); 3436 return (0); 3437 nfsmout: 3438 if (stp) 3439 free((caddr_t)stp, M_NFSDSTATE); 3440 return (error); 3441 } 3442