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