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 u_char cverf[NFSX_VERF], *cp; 869 fhandle_t fh; 870 char *bufp; 871 u_long *hashp; 872 enum vtype vtyp; 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(cp, u_char *, NFSX_VERF); 924 NFSBCOPY(cp, cverf, NFSX_VERF); 925 exclusive_flag = 1; 926 break; 927 }; 928 NFSVNO_SETATTRVAL(&nva, type, VREG); 929 } 930 } 931 if (nd->nd_repstat) { 932 nfsvno_relpathbuf(&named); 933 if (nd->nd_flag & ND_NFSV3) { 934 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, 935 p); 936 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 937 &diraft); 938 } 939 vput(dp); 940 return (0); 941 } 942 943 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 944 if (dirp) { 945 if (nd->nd_flag & ND_NFSV2) { 946 vrele(dirp); 947 dirp = NULL; 948 } else { 949 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 950 p); 951 } 952 } 953 if (nd->nd_repstat) { 954 if (nd->nd_flag & ND_NFSV3) 955 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 956 &diraft); 957 if (dirp) 958 vrele(dirp); 959 return (0); 960 } 961 962 if (!(nd->nd_flag & ND_NFSV2)) { 963 switch (how) { 964 case NFSCREATE_GUARDED: 965 if (named.ni_vp) 966 nd->nd_repstat = EEXIST; 967 break; 968 case NFSCREATE_UNCHECKED: 969 break; 970 case NFSCREATE_EXCLUSIVE: 971 if (named.ni_vp == NULL) 972 NFSVNO_SETATTRVAL(&nva, mode, 0); 973 break; 974 }; 975 } 976 977 /* 978 * Iff doesn't exist, create it 979 * otherwise just truncate to 0 length 980 * should I set the mode too ? 981 */ 982 nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva, 983 &exclusive_flag, cverf, rdev, p, exp); 984 985 if (!nd->nd_repstat) { 986 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 987 if (!nd->nd_repstat) 988 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 989 p); 990 vput(vp); 991 } 992 if (nd->nd_flag & ND_NFSV2) { 993 if (!nd->nd_repstat) { 994 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 995 nfsrv_fillattr(nd, &nva); 996 } 997 } else { 998 if (exclusive_flag && !nd->nd_repstat && 999 NFSBCMP(cverf, (caddr_t)&nva.na_atime, NFSX_VERF)) 1000 nd->nd_repstat = EEXIST; 1001 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p); 1002 vrele(dirp); 1003 if (!nd->nd_repstat) { 1004 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1); 1005 nfsrv_postopattr(nd, 0, &nva); 1006 } 1007 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1008 } 1009 return (0); 1010 nfsmout: 1011 vput(dp); 1012 nfsvno_relpathbuf(&named); 1013 return (error); 1014 } 1015 1016 /* 1017 * nfs v3 mknod service (and v4 create) 1018 */ 1019 APPLESTATIC int 1020 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram, 1021 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1022 struct nfsexstuff *exp) 1023 { 1024 struct nfsvattr nva, dirfor, diraft; 1025 u_int32_t *tl; 1026 struct nameidata named; 1027 int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen; 1028 u_int32_t major, minor; 1029 enum vtype vtyp = VNON; 1030 nfstype nfs4type = NFNON; 1031 vnode_t vp, dirp = NULL; 1032 nfsattrbit_t attrbits; 1033 char *bufp = NULL, *pathcp = NULL; 1034 u_long *hashp, cnflags; 1035 NFSACL_T *aclp = NULL; 1036 1037 NFSVNO_ATTRINIT(&nva); 1038 cnflags = (LOCKPARENT | SAVESTART); 1039 if (nd->nd_repstat) { 1040 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1041 return (0); 1042 } 1043 #ifdef NFS4_ACL_EXTATTR_NAME 1044 aclp = acl_alloc(M_WAITOK); 1045 aclp->acl_cnt = 0; 1046 #endif 1047 1048 /* 1049 * For V4, the creation stuff is here, Yuck! 1050 */ 1051 if (nd->nd_flag & ND_NFSV4) { 1052 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1053 vtyp = nfsv34tov_type(*tl); 1054 nfs4type = fxdr_unsigned(nfstype, *tl); 1055 switch (nfs4type) { 1056 case NFLNK: 1057 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, 1058 &pathlen); 1059 if (error) { 1060 vrele(dp); 1061 #ifdef NFS4_ACL_EXTATTR_NAME 1062 acl_free(aclp); 1063 #endif 1064 return (error); 1065 } 1066 break; 1067 case NFCHR: 1068 case NFBLK: 1069 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1070 major = fxdr_unsigned(u_int32_t, *tl++); 1071 minor = fxdr_unsigned(u_int32_t, *tl); 1072 nva.na_rdev = NFSMAKEDEV(major, minor); 1073 break; 1074 case NFSOCK: 1075 case NFFIFO: 1076 break; 1077 case NFDIR: 1078 cnflags = LOCKPARENT; 1079 break; 1080 default: 1081 nd->nd_repstat = NFSERR_BADTYPE; 1082 vrele(dp); 1083 #ifdef NFS4_ACL_EXTATTR_NAME 1084 acl_free(aclp); 1085 #endif 1086 return (0); 1087 }; 1088 } 1089 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags); 1090 nfsvno_setpathbuf(&named, &bufp, &hashp); 1091 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1092 if (error) { 1093 vrele(dp); 1094 #ifdef NFS4_ACL_EXTATTR_NAME 1095 acl_free(aclp); 1096 #endif 1097 nfsvno_relpathbuf(&named); 1098 if (pathcp) 1099 FREE(pathcp, M_TEMP); 1100 return (error); 1101 } 1102 if (!nd->nd_repstat) { 1103 if (nd->nd_flag & ND_NFSV3) { 1104 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1105 vtyp = nfsv34tov_type(*tl); 1106 } 1107 error = nfsrv_sattr(nd, &nva, &attrbits, aclp, p); 1108 if (error) { 1109 vrele(dp); 1110 #ifdef NFS4_ACL_EXTATTR_NAME 1111 acl_free(aclp); 1112 #endif 1113 nfsvno_relpathbuf(&named); 1114 if (pathcp) 1115 FREE(pathcp, M_TEMP); 1116 return (error); 1117 } 1118 nva.na_type = vtyp; 1119 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) && 1120 (vtyp == VCHR || vtyp == VBLK)) { 1121 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1122 major = fxdr_unsigned(u_int32_t, *tl++); 1123 minor = fxdr_unsigned(u_int32_t, *tl); 1124 nva.na_rdev = NFSMAKEDEV(major, minor); 1125 } 1126 } 1127 1128 dirfor_ret = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p); 1129 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) { 1130 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) && 1131 dirfor.na_gid == nva.na_gid) 1132 NFSVNO_UNSET(&nva, gid); 1133 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 1134 } 1135 if (nd->nd_repstat) { 1136 vrele(dp); 1137 #ifdef NFS4_ACL_EXTATTR_NAME 1138 acl_free(aclp); 1139 #endif 1140 nfsvno_relpathbuf(&named); 1141 if (pathcp) 1142 FREE(pathcp, M_TEMP); 1143 if (nd->nd_flag & ND_NFSV3) 1144 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1145 &diraft); 1146 return (0); 1147 } 1148 1149 /* 1150 * Yuck! For V4, mkdir and link are here and some V4 clients don't fill 1151 * in va_mode, so we'll have to set a default here. 1152 */ 1153 if (NFSVNO_NOTSETMODE(&nva)) { 1154 if (vtyp == VLNK) 1155 nva.na_mode = 0755; 1156 else 1157 nva.na_mode = 0400; 1158 } 1159 1160 if (vtyp == VDIR) 1161 named.ni_cnd.cn_flags |= WILLBEDIR; 1162 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1163 if (nd->nd_repstat) { 1164 if (dirp) { 1165 if (nd->nd_flag & ND_NFSV3) 1166 dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1167 nd->nd_cred, p); 1168 vrele(dirp); 1169 } 1170 #ifdef NFS4_ACL_EXTATTR_NAME 1171 acl_free(aclp); 1172 #endif 1173 if (nd->nd_flag & ND_NFSV3) 1174 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1175 &diraft); 1176 return (0); 1177 } 1178 if (dirp) 1179 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p); 1180 1181 if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) { 1182 if (vtyp == VDIR) { 1183 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, 1184 &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p, 1185 exp); 1186 #ifdef NFS4_ACL_EXTATTR_NAME 1187 acl_free(aclp); 1188 #endif 1189 return (0); 1190 } else if (vtyp == VLNK) { 1191 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1192 &dirfor, &diraft, &diraft_ret, &attrbits, 1193 aclp, p, exp, pathcp, pathlen); 1194 #ifdef NFS4_ACL_EXTATTR_NAME 1195 acl_free(aclp); 1196 #endif 1197 FREE(pathcp, M_TEMP); 1198 return (0); 1199 } 1200 } 1201 1202 nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p); 1203 if (!nd->nd_repstat) { 1204 vp = named.ni_vp; 1205 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp); 1206 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 1207 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat) 1208 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, 1209 p); 1210 if (vpp) { 1211 NFSVOPUNLOCK(vp, 0, p); 1212 *vpp = vp; 1213 } else { 1214 vput(vp); 1215 } 1216 } 1217 1218 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p); 1219 vrele(dirp); 1220 if (!nd->nd_repstat) { 1221 if (nd->nd_flag & ND_NFSV3) { 1222 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1223 nfsrv_postopattr(nd, 0, &nva); 1224 } else { 1225 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1226 *tl++ = newnfs_false; 1227 txdr_hyper(dirfor.na_filerev, tl); 1228 tl += 2; 1229 txdr_hyper(diraft.na_filerev, tl); 1230 (void) nfsrv_putattrbit(nd, &attrbits); 1231 } 1232 } 1233 if (nd->nd_flag & ND_NFSV3) 1234 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1235 #ifdef NFS4_ACL_EXTATTR_NAME 1236 acl_free(aclp); 1237 #endif 1238 return (0); 1239 nfsmout: 1240 vrele(dp); 1241 #ifdef NFS4_ACL_EXTATTR_NAME 1242 acl_free(aclp); 1243 #endif 1244 if (bufp) 1245 nfsvno_relpathbuf(&named); 1246 if (pathcp) 1247 FREE(pathcp, M_TEMP); 1248 return (error); 1249 } 1250 1251 /* 1252 * nfs remove service 1253 */ 1254 APPLESTATIC int 1255 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram, 1256 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 1257 { 1258 struct nameidata named; 1259 u_int32_t *tl; 1260 int error, dirfor_ret = 1, diraft_ret = 1; 1261 vnode_t dirp = NULL; 1262 struct nfsvattr dirfor, diraft; 1263 char *bufp; 1264 u_long *hashp; 1265 1266 if (nd->nd_repstat) { 1267 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1268 return (0); 1269 } 1270 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE, 1271 LOCKPARENT | LOCKLEAF); 1272 nfsvno_setpathbuf(&named, &bufp, &hashp); 1273 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1274 if (error) { 1275 vput(dp); 1276 nfsvno_relpathbuf(&named); 1277 return (error); 1278 } 1279 if (!nd->nd_repstat) { 1280 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 1281 } else { 1282 vput(dp); 1283 nfsvno_relpathbuf(&named); 1284 } 1285 if (dirp) { 1286 if (!(nd->nd_flag & ND_NFSV2)) { 1287 dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1288 nd->nd_cred, p); 1289 } else { 1290 vrele(dirp); 1291 dirp = NULL; 1292 } 1293 } 1294 if (!nd->nd_repstat) { 1295 if (nd->nd_flag & ND_NFSV4) { 1296 if (vnode_vtype(named.ni_vp) == VDIR) 1297 nd->nd_repstat = nfsvno_rmdirsub(&named, 1, 1298 nd->nd_cred, p, exp); 1299 else 1300 nd->nd_repstat = nfsvno_removesub(&named, 1, 1301 nd->nd_cred, p, exp); 1302 } else if (nd->nd_procnum == NFSPROC_RMDIR) { 1303 nd->nd_repstat = nfsvno_rmdirsub(&named, 0, 1304 nd->nd_cred, p, exp); 1305 } else { 1306 nd->nd_repstat = nfsvno_removesub(&named, 0, 1307 nd->nd_cred, p, exp); 1308 } 1309 } 1310 if (!(nd->nd_flag & ND_NFSV2)) { 1311 if (dirp) { 1312 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, 1313 p); 1314 vrele(dirp); 1315 } 1316 if (nd->nd_flag & ND_NFSV3) { 1317 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1318 &diraft); 1319 } else if (!nd->nd_repstat) { 1320 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1321 *tl++ = newnfs_false; 1322 txdr_hyper(dirfor.na_filerev, tl); 1323 tl += 2; 1324 txdr_hyper(diraft.na_filerev, tl); 1325 } 1326 } 1327 return (0); 1328 } 1329 1330 /* 1331 * nfs rename service 1332 */ 1333 APPLESTATIC int 1334 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram, 1335 vnode_t dp, vnode_t todp, NFSPROC_T *p, struct nfsexstuff *exp, 1336 struct nfsexstuff *toexp) 1337 { 1338 u_int32_t *tl; 1339 int error, fdirfor_ret = 1, fdiraft_ret = 1; 1340 int tdirfor_ret = 1, tdiraft_ret = 1; 1341 struct nameidata fromnd, tond; 1342 vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL; 1343 struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft; 1344 struct nfsexstuff tnes; 1345 struct nfsrvfh tfh; 1346 mount_t mp = NULL; 1347 char *bufp, *tbufp = NULL; 1348 u_long *hashp; 1349 1350 if (nd->nd_repstat) { 1351 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1352 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1353 return (0); 1354 } 1355 if (!(nd->nd_flag & ND_NFSV2)) 1356 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd->nd_cred, p); 1357 tond.ni_cnd.cn_nameiop = 0; 1358 tond.ni_startdir = NULL; 1359 NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART); 1360 nfsvno_setpathbuf(&fromnd, &bufp, &hashp); 1361 error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen); 1362 if (error) { 1363 vput(dp); 1364 if (todp) 1365 vrele(todp); 1366 nfsvno_relpathbuf(&fromnd); 1367 return (error); 1368 } 1369 if (nd->nd_flag & ND_NFSV4) { 1370 tdp = todp; 1371 tnes = *toexp; 1372 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, p); 1373 } else { 1374 error = nfsrv_mtofh(nd, &tfh); 1375 if (error) { 1376 vput(dp); 1377 /* todp is always NULL except NFSv4 */ 1378 nfsvno_relpathbuf(&fromnd); 1379 return (error); 1380 } 1381 nd->nd_cred->cr_uid = nd->nd_saveduid; 1382 /* Won't lock vfs if already locked, mp == NULL */ 1383 tnes.nes_vfslocked = exp->nes_vfslocked; 1384 nfsd_fhtovp(nd, &tfh, &tdp, &tnes, &mp, 0, p); 1385 if (tdp) { 1386 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd->nd_cred, 1387 p); 1388 NFSVOPUNLOCK(tdp, 0, p); 1389 } 1390 } 1391 NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART); 1392 nfsvno_setpathbuf(&tond, &tbufp, &hashp); 1393 if (!nd->nd_repstat) { 1394 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen); 1395 if (error) { 1396 if (tdp) { 1397 if (tnes.nes_vfslocked && !exp->nes_vfslocked && 1398 !(nd->nd_flag & ND_NFSV4)) 1399 nfsvno_unlockvfs(mp); 1400 vrele(tdp); 1401 } 1402 vput(dp); 1403 nfsvno_relpathbuf(&fromnd); 1404 nfsvno_relpathbuf(&tond); 1405 return (error); 1406 } 1407 } 1408 if (nd->nd_repstat) { 1409 if (nd->nd_flag & ND_NFSV3) { 1410 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 1411 &fdiraft); 1412 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 1413 &tdiraft); 1414 } 1415 if (tdp) { 1416 if (tnes.nes_vfslocked && !exp->nes_vfslocked && 1417 !(nd->nd_flag & ND_NFSV4)) 1418 nfsvno_unlockvfs(mp); 1419 vrele(tdp); 1420 } 1421 vput(dp); 1422 nfsvno_relpathbuf(&fromnd); 1423 nfsvno_relpathbuf(&tond); 1424 return (0); 1425 } 1426 1427 /* 1428 * Done parsing, now down to business. 1429 */ 1430 nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 1, exp, p, &fdirp); 1431 if (nd->nd_repstat) { 1432 if (nd->nd_flag & ND_NFSV3) { 1433 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, 1434 &fdiraft); 1435 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, 1436 &tdiraft); 1437 } 1438 if (fdirp) 1439 vrele(fdirp); 1440 if (tdp) { 1441 if (tnes.nes_vfslocked && !exp->nes_vfslocked && 1442 !(nd->nd_flag & ND_NFSV4)) 1443 nfsvno_unlockvfs(mp); 1444 vrele(tdp); 1445 } 1446 nfsvno_relpathbuf(&tond); 1447 return (0); 1448 } 1449 if (vnode_vtype(fromnd.ni_vp) == VDIR) 1450 tond.ni_cnd.cn_flags |= WILLBEDIR; 1451 nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp); 1452 nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat, 1453 nd->nd_flag, nd->nd_cred, p); 1454 if (fdirp) 1455 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd->nd_cred, p); 1456 if (tdirp) 1457 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd->nd_cred, p); 1458 if (tnes.nes_vfslocked && !exp->nes_vfslocked && 1459 !(nd->nd_flag & ND_NFSV4)) 1460 nfsvno_unlockvfs(mp); 1461 if (fdirp) 1462 vrele(fdirp); 1463 if (tdirp) 1464 vrele(tdirp); 1465 if (nd->nd_flag & ND_NFSV3) { 1466 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft); 1467 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft); 1468 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1469 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED); 1470 *tl++ = newnfs_false; 1471 txdr_hyper(fdirfor.na_filerev, tl); 1472 tl += 2; 1473 txdr_hyper(fdiraft.na_filerev, tl); 1474 tl += 2; 1475 *tl++ = newnfs_false; 1476 txdr_hyper(tdirfor.na_filerev, tl); 1477 tl += 2; 1478 txdr_hyper(tdiraft.na_filerev, tl); 1479 } 1480 return (0); 1481 } 1482 1483 /* 1484 * nfs link service 1485 */ 1486 APPLESTATIC int 1487 nfsrvd_link(struct nfsrv_descript *nd, int isdgram, 1488 vnode_t vp, vnode_t tovp, NFSPROC_T *p, struct nfsexstuff *exp, 1489 struct nfsexstuff *toexp) 1490 { 1491 struct nameidata named; 1492 u_int32_t *tl; 1493 int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1; 1494 vnode_t dirp = NULL, dp = NULL; 1495 struct nfsvattr dirfor, diraft, at; 1496 struct nfsexstuff tnes; 1497 struct nfsrvfh dfh; 1498 mount_t mp = NULL; 1499 char *bufp; 1500 u_long *hashp; 1501 1502 if (nd->nd_repstat) { 1503 nfsrv_postopattr(nd, getret, &at); 1504 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1505 return (0); 1506 } 1507 NFSVOPUNLOCK(vp, 0, p); 1508 if (vnode_vtype(vp) == VDIR) { 1509 if (nd->nd_flag & ND_NFSV4) 1510 nd->nd_repstat = NFSERR_ISDIR; 1511 else 1512 nd->nd_repstat = NFSERR_INVAL; 1513 if (tovp) 1514 vrele(tovp); 1515 } else if (vnode_vtype(vp) == VLNK) { 1516 if (nd->nd_flag & ND_NFSV2) 1517 nd->nd_repstat = NFSERR_INVAL; 1518 else 1519 nd->nd_repstat = NFSERR_NOTSUPP; 1520 if (tovp) 1521 vrele(tovp); 1522 } 1523 if (!nd->nd_repstat) { 1524 if (nd->nd_flag & ND_NFSV4) { 1525 dp = tovp; 1526 tnes = *toexp; 1527 } else { 1528 error = nfsrv_mtofh(nd, &dfh); 1529 if (error) { 1530 vrele(vp); 1531 /* tovp is always NULL unless NFSv4 */ 1532 return (error); 1533 } 1534 /* Won't lock vfs if already locked, mp == NULL */ 1535 tnes.nes_vfslocked = exp->nes_vfslocked; 1536 nfsd_fhtovp(nd, &dfh, &dp, &tnes, &mp, 0, p); 1537 if (dp) 1538 NFSVOPUNLOCK(dp, 0, p); 1539 } 1540 } 1541 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT); 1542 if (!nd->nd_repstat) { 1543 nfsvno_setpathbuf(&named, &bufp, &hashp); 1544 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1545 if (error) { 1546 vrele(vp); 1547 if (dp) { 1548 if (tnes.nes_vfslocked && !exp->nes_vfslocked && 1549 !(nd->nd_flag & ND_NFSV4)) 1550 nfsvno_unlockvfs(mp); 1551 vrele(dp); 1552 } 1553 nfsvno_relpathbuf(&named); 1554 return (error); 1555 } 1556 if (!nd->nd_repstat) { 1557 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes, 1558 p, &dirp); 1559 } else { 1560 if (dp) 1561 vrele(dp); 1562 nfsvno_relpathbuf(&named); 1563 } 1564 } 1565 if (dirp) { 1566 if (nd->nd_flag & ND_NFSV2) { 1567 vrele(dirp); 1568 dirp = NULL; 1569 } else { 1570 dirfor_ret = nfsvno_getattr(dirp, &dirfor, 1571 nd->nd_cred, p); 1572 } 1573 } 1574 if (!nd->nd_repstat) 1575 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp); 1576 if (nd->nd_flag & ND_NFSV3) 1577 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p); 1578 if (dirp) { 1579 diraft_ret = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p); 1580 vrele(dirp); 1581 } 1582 if (tnes.nes_vfslocked && !exp->nes_vfslocked && 1583 !(nd->nd_flag & ND_NFSV4)) 1584 nfsvno_unlockvfs(mp); 1585 vrele(vp); 1586 if (nd->nd_flag & ND_NFSV3) { 1587 nfsrv_postopattr(nd, getret, &at); 1588 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1589 } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1590 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1591 *tl++ = newnfs_false; 1592 txdr_hyper(dirfor.na_filerev, tl); 1593 tl += 2; 1594 txdr_hyper(diraft.na_filerev, tl); 1595 } 1596 return (0); 1597 } 1598 1599 /* 1600 * nfs symbolic link service 1601 */ 1602 APPLESTATIC int 1603 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram, 1604 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1605 struct nfsexstuff *exp) 1606 { 1607 struct nfsvattr nva, dirfor, diraft; 1608 struct nameidata named; 1609 int error, dirfor_ret = 1, diraft_ret = 1, pathlen; 1610 vnode_t dirp = NULL; 1611 char *bufp, *pathcp = NULL; 1612 u_long *hashp; 1613 1614 if (nd->nd_repstat) { 1615 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1616 return (0); 1617 } 1618 if (vpp) 1619 *vpp = NULL; 1620 NFSVNO_ATTRINIT(&nva); 1621 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 1622 LOCKPARENT | SAVESTART); 1623 nfsvno_setpathbuf(&named, &bufp, &hashp); 1624 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1625 if (!error && !nd->nd_repstat) 1626 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen); 1627 if (error) { 1628 vrele(dp); 1629 nfsvno_relpathbuf(&named); 1630 return (error); 1631 } 1632 if (!nd->nd_repstat) { 1633 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1634 } else { 1635 vrele(dp); 1636 nfsvno_relpathbuf(&named); 1637 } 1638 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1639 vrele(dirp); 1640 dirp = NULL; 1641 } 1642 1643 /* 1644 * And call nfsrvd_symlinksub() to do the common code. It will 1645 * return EBADRPC upon a parsing error, 0 otherwise. 1646 */ 1647 if (!nd->nd_repstat) { 1648 if (dirp != NULL) 1649 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1650 p); 1651 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp, 1652 &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp, 1653 pathcp, pathlen); 1654 } else if (dirp != NULL) { 1655 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p); 1656 vrele(dirp); 1657 } 1658 if (pathcp) 1659 FREE(pathcp, M_TEMP); 1660 1661 if (nd->nd_flag & ND_NFSV3) { 1662 if (!nd->nd_repstat) { 1663 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1664 nfsrv_postopattr(nd, 0, &nva); 1665 } 1666 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1667 } 1668 return (0); 1669 } 1670 1671 /* 1672 * Common code for creating a symbolic link. 1673 */ 1674 static void 1675 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp, 1676 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1677 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1678 int *diraft_retp, nfsattrbit_t *attrbitp, 1679 NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp, 1680 int pathlen) 1681 { 1682 u_int32_t *tl; 1683 1684 nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen, 1685 !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp); 1686 if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) { 1687 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp); 1688 if (nd->nd_flag & ND_NFSV3) { 1689 nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p); 1690 if (!nd->nd_repstat) 1691 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp, 1692 nvap, nd->nd_cred, p); 1693 } 1694 if (vpp) { 1695 NFSVOPUNLOCK(ndp->ni_vp, 0, p); 1696 *vpp = ndp->ni_vp; 1697 } else { 1698 vput(ndp->ni_vp); 1699 } 1700 } 1701 if (dirp) { 1702 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p); 1703 vrele(dirp); 1704 } 1705 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1706 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1707 *tl++ = newnfs_false; 1708 txdr_hyper(dirforp->na_filerev, tl); 1709 tl += 2; 1710 txdr_hyper(diraftp->na_filerev, tl); 1711 (void) nfsrv_putattrbit(nd, attrbitp); 1712 } 1713 } 1714 1715 /* 1716 * nfs mkdir service 1717 */ 1718 APPLESTATIC int 1719 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram, 1720 vnode_t dp, vnode_t *vpp, fhandle_t *fhp, NFSPROC_T *p, 1721 struct nfsexstuff *exp) 1722 { 1723 struct nfsvattr nva, dirfor, diraft; 1724 struct nameidata named; 1725 u_int32_t *tl; 1726 int error, dirfor_ret = 1, diraft_ret = 1; 1727 vnode_t dirp = NULL; 1728 char *bufp; 1729 u_long *hashp; 1730 1731 if (nd->nd_repstat) { 1732 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1733 return (0); 1734 } 1735 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, LOCKPARENT); 1736 nfsvno_setpathbuf(&named, &bufp, &hashp); 1737 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 1738 if (error) { 1739 vrele(dp); 1740 nfsvno_relpathbuf(&named); 1741 return (error); 1742 } 1743 if (!nd->nd_repstat) { 1744 NFSVNO_ATTRINIT(&nva); 1745 if (nd->nd_flag & ND_NFSV3) { 1746 error = nfsrv_sattr(nd, &nva, NULL, NULL, p); 1747 if (error) { 1748 vrele(dp); 1749 nfsvno_relpathbuf(&named); 1750 return (error); 1751 } 1752 } else { 1753 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1754 nva.na_mode = nfstov_mode(*tl++); 1755 } 1756 } 1757 if (!nd->nd_repstat) { 1758 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp); 1759 } else { 1760 vrele(dp); 1761 nfsvno_relpathbuf(&named); 1762 } 1763 if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) { 1764 vrele(dirp); 1765 dirp = NULL; 1766 } 1767 if (nd->nd_repstat) { 1768 if (dirp != NULL) { 1769 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, 1770 p); 1771 vrele(dirp); 1772 } 1773 if (nd->nd_flag & ND_NFSV3) 1774 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, 1775 &diraft); 1776 return (0); 1777 } 1778 if (dirp != NULL) 1779 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd->nd_cred, p); 1780 1781 /* 1782 * Call nfsrvd_mkdirsub() for the code common to V4 as well. 1783 */ 1784 nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft, 1785 &diraft_ret, NULL, NULL, p, exp); 1786 1787 if (nd->nd_flag & ND_NFSV3) { 1788 if (!nd->nd_repstat) { 1789 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1); 1790 nfsrv_postopattr(nd, 0, &nva); 1791 } 1792 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft); 1793 } else if (!nd->nd_repstat) { 1794 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0); 1795 nfsrv_fillattr(nd, &nva); 1796 } 1797 return (0); 1798 nfsmout: 1799 vrele(dp); 1800 nfsvno_relpathbuf(&named); 1801 return (error); 1802 } 1803 1804 /* 1805 * Code common to mkdir for V2,3 and 4. 1806 */ 1807 static void 1808 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp, 1809 struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp, 1810 vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp, 1811 int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp, 1812 NFSPROC_T *p, struct nfsexstuff *exp) 1813 { 1814 vnode_t vp; 1815 u_int32_t *tl; 1816 1817 NFSVNO_SETATTRVAL(nvap, type, VDIR); 1818 nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid, 1819 nd->nd_cred, p, exp); 1820 if (!nd->nd_repstat) { 1821 vp = ndp->ni_vp; 1822 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp); 1823 nd->nd_repstat = nfsvno_getfh(vp, fhp, p); 1824 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) 1825 nd->nd_repstat = nfsvno_getattr(vp, nvap, nd->nd_cred, 1826 p); 1827 if (vpp && !nd->nd_repstat) { 1828 NFSVOPUNLOCK(vp, 0, p); 1829 *vpp = vp; 1830 } else { 1831 vput(vp); 1832 } 1833 } 1834 if (dirp) { 1835 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd->nd_cred, p); 1836 vrele(dirp); 1837 } 1838 if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) { 1839 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1840 *tl++ = newnfs_false; 1841 txdr_hyper(dirforp->na_filerev, tl); 1842 tl += 2; 1843 txdr_hyper(diraftp->na_filerev, tl); 1844 (void) nfsrv_putattrbit(nd, attrbitp); 1845 } 1846 } 1847 1848 /* 1849 * nfs commit service 1850 */ 1851 APPLESTATIC int 1852 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram, 1853 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1854 { 1855 struct nfsvattr bfor, aft; 1856 u_int32_t *tl; 1857 int error = 0, for_ret = 1, aft_ret = 1, cnt; 1858 u_int64_t off; 1859 1860 if (nd->nd_repstat) { 1861 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1862 return (0); 1863 } 1864 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1865 /* 1866 * XXX At this time VOP_FSYNC() does not accept offset and byte 1867 * count parameters, so these arguments are useless (someday maybe). 1868 */ 1869 off = fxdr_hyper(tl); 1870 tl += 2; 1871 cnt = fxdr_unsigned(int, *tl); 1872 if (nd->nd_flag & ND_NFSV3) 1873 for_ret = nfsvno_getattr(vp, &bfor, nd->nd_cred, p); 1874 nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p); 1875 if (nd->nd_flag & ND_NFSV3) { 1876 aft_ret = nfsvno_getattr(vp, &aft, nd->nd_cred, p); 1877 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft); 1878 } 1879 vput(vp); 1880 if (!nd->nd_repstat) { 1881 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1882 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 1883 *tl = txdr_unsigned(nfsboottime.tv_usec); 1884 } 1885 return (0); 1886 nfsmout: 1887 vput(vp); 1888 return (error); 1889 } 1890 1891 /* 1892 * nfs statfs service 1893 */ 1894 APPLESTATIC int 1895 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram, 1896 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1897 { 1898 struct statfs *sf; 1899 u_int32_t *tl; 1900 int getret = 1; 1901 struct nfsvattr at; 1902 struct statfs sfs; 1903 u_quad_t tval; 1904 1905 if (nd->nd_repstat) { 1906 nfsrv_postopattr(nd, getret, &at); 1907 return (0); 1908 } 1909 sf = &sfs; 1910 nd->nd_repstat = nfsvno_statfs(vp, sf); 1911 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p); 1912 vput(vp); 1913 if (nd->nd_flag & ND_NFSV3) 1914 nfsrv_postopattr(nd, getret, &at); 1915 if (nd->nd_repstat) 1916 return (0); 1917 if (nd->nd_flag & ND_NFSV2) { 1918 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS); 1919 *tl++ = txdr_unsigned(NFS_V2MAXDATA); 1920 *tl++ = txdr_unsigned(sf->f_bsize); 1921 *tl++ = txdr_unsigned(sf->f_blocks); 1922 *tl++ = txdr_unsigned(sf->f_bfree); 1923 *tl = txdr_unsigned(sf->f_bavail); 1924 } else { 1925 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS); 1926 tval = (u_quad_t)sf->f_blocks; 1927 tval *= (u_quad_t)sf->f_bsize; 1928 txdr_hyper(tval, tl); tl += 2; 1929 tval = (u_quad_t)sf->f_bfree; 1930 tval *= (u_quad_t)sf->f_bsize; 1931 txdr_hyper(tval, tl); tl += 2; 1932 tval = (u_quad_t)sf->f_bavail; 1933 tval *= (u_quad_t)sf->f_bsize; 1934 txdr_hyper(tval, tl); tl += 2; 1935 tval = (u_quad_t)sf->f_files; 1936 txdr_hyper(tval, tl); tl += 2; 1937 tval = (u_quad_t)sf->f_ffree; 1938 txdr_hyper(tval, tl); tl += 2; 1939 tval = (u_quad_t)sf->f_ffree; 1940 txdr_hyper(tval, tl); tl += 2; 1941 *tl = 0; 1942 } 1943 return (0); 1944 } 1945 1946 /* 1947 * nfs fsinfo service 1948 */ 1949 APPLESTATIC int 1950 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram, 1951 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1952 { 1953 u_int32_t *tl; 1954 struct nfsfsinfo fs; 1955 int getret = 1; 1956 struct nfsvattr at; 1957 1958 if (nd->nd_repstat) { 1959 nfsrv_postopattr(nd, getret, &at); 1960 return (0); 1961 } 1962 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p); 1963 nfsvno_getfs(&fs, isdgram); 1964 vput(vp); 1965 nfsrv_postopattr(nd, getret, &at); 1966 NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO); 1967 *tl++ = txdr_unsigned(fs.fs_rtmax); 1968 *tl++ = txdr_unsigned(fs.fs_rtpref); 1969 *tl++ = txdr_unsigned(fs.fs_rtmult); 1970 *tl++ = txdr_unsigned(fs.fs_wtmax); 1971 *tl++ = txdr_unsigned(fs.fs_wtpref); 1972 *tl++ = txdr_unsigned(fs.fs_wtmult); 1973 *tl++ = txdr_unsigned(fs.fs_dtpref); 1974 txdr_hyper(fs.fs_maxfilesize, tl); 1975 tl += 2; 1976 txdr_nfsv3time(&fs.fs_timedelta, tl); 1977 tl += 2; 1978 *tl = txdr_unsigned(fs.fs_properties); 1979 return (0); 1980 } 1981 1982 /* 1983 * nfs pathconf service 1984 */ 1985 APPLESTATIC int 1986 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram, 1987 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 1988 { 1989 struct nfsv3_pathconf *pc; 1990 int getret = 1; 1991 register_t linkmax, namemax, chownres, notrunc; 1992 struct nfsvattr at; 1993 1994 if (nd->nd_repstat) { 1995 nfsrv_postopattr(nd, getret, &at); 1996 return (0); 1997 } 1998 nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax, 1999 nd->nd_cred, p); 2000 if (!nd->nd_repstat) 2001 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax, 2002 nd->nd_cred, p); 2003 if (!nd->nd_repstat) 2004 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED, 2005 &chownres, nd->nd_cred, p); 2006 if (!nd->nd_repstat) 2007 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, ¬runc, 2008 nd->nd_cred, p); 2009 getret = nfsvno_getattr(vp, &at, nd->nd_cred, p); 2010 vput(vp); 2011 nfsrv_postopattr(nd, getret, &at); 2012 if (!nd->nd_repstat) { 2013 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF); 2014 pc->pc_linkmax = txdr_unsigned(linkmax); 2015 pc->pc_namemax = txdr_unsigned(namemax); 2016 pc->pc_notrunc = txdr_unsigned(notrunc); 2017 pc->pc_chownrestricted = txdr_unsigned(chownres); 2018 2019 /* 2020 * These should probably be supported by VOP_PATHCONF(), but 2021 * until msdosfs is exportable (why would you want to?), the 2022 * Unix defaults should be ok. 2023 */ 2024 pc->pc_caseinsensitive = newnfs_false; 2025 pc->pc_casepreserving = newnfs_true; 2026 } 2027 return (0); 2028 } 2029 2030 /* 2031 * nfsv4 lock service 2032 */ 2033 APPLESTATIC int 2034 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram, 2035 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2036 { 2037 u_int32_t *tl; 2038 int i; 2039 struct nfsstate *stp = NULL; 2040 struct nfslock *lop; 2041 struct nfslockconflict cf; 2042 int error = 0; 2043 u_short flags = NFSLCK_LOCK, lflags; 2044 u_int64_t offset, len; 2045 nfsv4stateid_t stateid; 2046 nfsquad_t clientid; 2047 2048 NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2049 i = fxdr_unsigned(int, *tl++); 2050 switch (i) { 2051 case NFSV4LOCKT_READW: 2052 flags |= NFSLCK_BLOCKING; 2053 case NFSV4LOCKT_READ: 2054 lflags = NFSLCK_READ; 2055 break; 2056 case NFSV4LOCKT_WRITEW: 2057 flags |= NFSLCK_BLOCKING; 2058 case NFSV4LOCKT_WRITE: 2059 lflags = NFSLCK_WRITE; 2060 break; 2061 default: 2062 nd->nd_repstat = NFSERR_BADXDR; 2063 goto nfsmout; 2064 }; 2065 if (*tl++ == newnfs_true) 2066 flags |= NFSLCK_RECLAIM; 2067 offset = fxdr_hyper(tl); 2068 tl += 2; 2069 len = fxdr_hyper(tl); 2070 tl += 2; 2071 if (*tl == newnfs_true) 2072 flags |= NFSLCK_OPENTOLOCK; 2073 if (flags & NFSLCK_OPENTOLOCK) { 2074 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID); 2075 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED))); 2076 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2077 M_NFSDSTATE, M_WAITOK); 2078 stp->ls_ownerlen = i; 2079 stp->ls_op = nd->nd_rp; 2080 stp->ls_seq = fxdr_unsigned(int, *tl++); 2081 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2082 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2083 NFSX_STATEIDOTHER); 2084 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2085 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++); 2086 clientid.lval[0] = *tl++; 2087 clientid.lval[1] = *tl++; 2088 if (nd->nd_flag & ND_IMPLIEDCLID) { 2089 if (nd->nd_clientid.qval != clientid.qval) 2090 printf("EEK! multiple clids\n"); 2091 } else { 2092 nd->nd_flag |= ND_IMPLIEDCLID; 2093 nd->nd_clientid.qval = clientid.qval; 2094 } 2095 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2096 if (error) 2097 goto nfsmout; 2098 } else { 2099 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2100 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2101 M_NFSDSTATE, M_WAITOK); 2102 stp->ls_ownerlen = 0; 2103 stp->ls_op = nd->nd_rp; 2104 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2105 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2106 NFSX_STATEIDOTHER); 2107 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2108 stp->ls_seq = fxdr_unsigned(int, *tl); 2109 clientid.lval[0] = stp->ls_stateid.other[0]; 2110 clientid.lval[1] = stp->ls_stateid.other[1]; 2111 if (nd->nd_flag & ND_IMPLIEDCLID) { 2112 if (nd->nd_clientid.qval != clientid.qval) 2113 printf("EEK! multiple clids\n"); 2114 } else { 2115 nd->nd_flag |= ND_IMPLIEDCLID; 2116 nd->nd_clientid.qval = clientid.qval; 2117 } 2118 } 2119 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2120 M_NFSDLOCK, M_WAITOK); 2121 lop->lo_first = offset; 2122 if (len == NFS64BITSSET) { 2123 lop->lo_end = NFS64BITSSET; 2124 } else { 2125 lop->lo_end = offset + len; 2126 if (lop->lo_end <= lop->lo_first) 2127 nd->nd_repstat = NFSERR_INVAL; 2128 } 2129 lop->lo_flags = lflags; 2130 stp->ls_flags = flags; 2131 stp->ls_uid = nd->nd_cred->cr_uid; 2132 2133 /* 2134 * Do basic access checking. 2135 */ 2136 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2137 if (vnode_vtype(vp) == VDIR) 2138 nd->nd_repstat = NFSERR_ISDIR; 2139 else 2140 nd->nd_repstat = NFSERR_INVAL; 2141 } 2142 if (!nd->nd_repstat) { 2143 if (lflags & NFSLCK_WRITE) { 2144 nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_WRITEDATA, 2145 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2146 NFSACCCHK_VPISLOCKED); 2147 } else { 2148 nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_READDATA, 2149 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2150 NFSACCCHK_VPISLOCKED); 2151 if (nd->nd_repstat) 2152 nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_EXECUTE, 2153 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2154 NFSACCCHK_VPISLOCKED); 2155 } 2156 } 2157 2158 /* 2159 * We call nfsrv_lockctrl() even if nd_repstat set, so that the 2160 * seqid# gets updated. nfsrv_lockctrl() will return the value 2161 * of nd_repstat, if it gets that far. 2162 */ 2163 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2164 &stateid, exp, nd, p); 2165 if (lop) 2166 FREE((caddr_t)lop, M_NFSDLOCK); 2167 if (stp) 2168 FREE((caddr_t)stp, M_NFSDSTATE); 2169 if (!nd->nd_repstat) { 2170 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2171 *tl++ = txdr_unsigned(stateid.seqid); 2172 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2173 } else if (nd->nd_repstat == NFSERR_DENIED) { 2174 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2175 txdr_hyper(cf.cl_first, tl); 2176 tl += 2; 2177 if (cf.cl_end == NFS64BITSSET) 2178 len = NFS64BITSSET; 2179 else 2180 len = cf.cl_end - cf.cl_first; 2181 txdr_hyper(len, tl); 2182 tl += 2; 2183 if (cf.cl_flags == NFSLCK_WRITE) 2184 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2185 else 2186 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2187 *tl++ = stateid.other[0]; 2188 *tl = stateid.other[1]; 2189 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2190 } 2191 vput(vp); 2192 return (0); 2193 nfsmout: 2194 vput(vp); 2195 if (stp) 2196 free((caddr_t)stp, M_NFSDSTATE); 2197 return (error); 2198 } 2199 2200 /* 2201 * nfsv4 lock test service 2202 */ 2203 APPLESTATIC int 2204 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram, 2205 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2206 { 2207 u_int32_t *tl; 2208 int i; 2209 struct nfsstate *stp = NULL; 2210 struct nfslock lo, *lop = &lo; 2211 struct nfslockconflict cf; 2212 int error = 0; 2213 nfsv4stateid_t stateid; 2214 nfsquad_t clientid; 2215 u_int64_t len; 2216 2217 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 2218 i = fxdr_unsigned(int, *(tl + 7)); 2219 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2220 M_NFSDSTATE, M_WAITOK); 2221 stp->ls_ownerlen = i; 2222 stp->ls_op = NULL; 2223 stp->ls_flags = NFSLCK_TEST; 2224 stp->ls_uid = nd->nd_cred->cr_uid; 2225 i = fxdr_unsigned(int, *tl++); 2226 switch (i) { 2227 case NFSV4LOCKT_READW: 2228 stp->ls_flags |= NFSLCK_BLOCKING; 2229 case NFSV4LOCKT_READ: 2230 lo.lo_flags = NFSLCK_READ; 2231 break; 2232 case NFSV4LOCKT_WRITEW: 2233 stp->ls_flags |= NFSLCK_BLOCKING; 2234 case NFSV4LOCKT_WRITE: 2235 lo.lo_flags = NFSLCK_WRITE; 2236 break; 2237 default: 2238 nd->nd_repstat = NFSERR_BADXDR; 2239 goto nfsmout; 2240 }; 2241 lo.lo_first = fxdr_hyper(tl); 2242 tl += 2; 2243 len = fxdr_hyper(tl); 2244 if (len == NFS64BITSSET) { 2245 lo.lo_end = NFS64BITSSET; 2246 } else { 2247 lo.lo_end = lo.lo_first + len; 2248 if (lo.lo_end <= lo.lo_first) 2249 nd->nd_repstat = NFSERR_INVAL; 2250 } 2251 tl += 2; 2252 clientid.lval[0] = *tl++; 2253 clientid.lval[1] = *tl; 2254 if (nd->nd_flag & ND_IMPLIEDCLID) { 2255 if (nd->nd_clientid.qval != clientid.qval) 2256 printf("EEK! multiple clids\n"); 2257 } else { 2258 nd->nd_flag |= ND_IMPLIEDCLID; 2259 nd->nd_clientid.qval = clientid.qval; 2260 } 2261 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2262 if (error) 2263 goto nfsmout; 2264 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2265 if (vnode_vtype(vp) == VDIR) 2266 nd->nd_repstat = NFSERR_ISDIR; 2267 else 2268 nd->nd_repstat = NFSERR_INVAL; 2269 } 2270 if (!nd->nd_repstat) 2271 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 2272 &stateid, exp, nd, p); 2273 if (stp) 2274 FREE((caddr_t)stp, M_NFSDSTATE); 2275 if (nd->nd_repstat) { 2276 if (nd->nd_repstat == NFSERR_DENIED) { 2277 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 2278 txdr_hyper(cf.cl_first, tl); 2279 tl += 2; 2280 if (cf.cl_end == NFS64BITSSET) 2281 len = NFS64BITSSET; 2282 else 2283 len = cf.cl_end - cf.cl_first; 2284 txdr_hyper(len, tl); 2285 tl += 2; 2286 if (cf.cl_flags == NFSLCK_WRITE) 2287 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 2288 else 2289 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 2290 *tl++ = stp->ls_stateid.other[0]; 2291 *tl = stp->ls_stateid.other[1]; 2292 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen); 2293 } 2294 } 2295 vput(vp); 2296 return (0); 2297 nfsmout: 2298 vput(vp); 2299 if (stp) 2300 free((caddr_t)stp, M_NFSDSTATE); 2301 return (error); 2302 } 2303 2304 /* 2305 * nfsv4 unlock service 2306 */ 2307 APPLESTATIC int 2308 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram, 2309 vnode_t vp, NFSPROC_T *p, struct nfsexstuff *exp) 2310 { 2311 u_int32_t *tl; 2312 int i; 2313 struct nfsstate *stp; 2314 struct nfslock *lop; 2315 int error = 0; 2316 nfsv4stateid_t stateid; 2317 nfsquad_t clientid; 2318 u_int64_t len; 2319 2320 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID); 2321 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate), 2322 M_NFSDSTATE, M_WAITOK); 2323 MALLOC(lop, struct nfslock *, sizeof (struct nfslock), 2324 M_NFSDLOCK, M_WAITOK); 2325 stp->ls_flags = NFSLCK_UNLOCK; 2326 lop->lo_flags = NFSLCK_UNLOCK; 2327 stp->ls_op = nd->nd_rp; 2328 i = fxdr_unsigned(int, *tl++); 2329 switch (i) { 2330 case NFSV4LOCKT_READW: 2331 stp->ls_flags |= NFSLCK_BLOCKING; 2332 case NFSV4LOCKT_READ: 2333 break; 2334 case NFSV4LOCKT_WRITEW: 2335 stp->ls_flags |= NFSLCK_BLOCKING; 2336 case NFSV4LOCKT_WRITE: 2337 break; 2338 default: 2339 nd->nd_repstat = NFSERR_BADXDR; 2340 goto nfsmout; 2341 }; 2342 stp->ls_ownerlen = 0; 2343 stp->ls_uid = nd->nd_cred->cr_uid; 2344 stp->ls_seq = fxdr_unsigned(int, *tl++); 2345 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2346 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2347 NFSX_STATEIDOTHER); 2348 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2349 lop->lo_first = fxdr_hyper(tl); 2350 tl += 2; 2351 len = fxdr_hyper(tl); 2352 if (len == NFS64BITSSET) { 2353 lop->lo_end = NFS64BITSSET; 2354 } else { 2355 lop->lo_end = lop->lo_first + len; 2356 if (lop->lo_end <= lop->lo_first) 2357 nd->nd_repstat = NFSERR_INVAL; 2358 } 2359 clientid.lval[0] = stp->ls_stateid.other[0]; 2360 clientid.lval[1] = stp->ls_stateid.other[1]; 2361 if (nd->nd_flag & ND_IMPLIEDCLID) { 2362 if (nd->nd_clientid.qval != clientid.qval) 2363 printf("EEK! multiple clids\n"); 2364 } else { 2365 nd->nd_flag |= ND_IMPLIEDCLID; 2366 nd->nd_clientid.qval = clientid.qval; 2367 } 2368 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2369 if (vnode_vtype(vp) == VDIR) 2370 nd->nd_repstat = NFSERR_ISDIR; 2371 else 2372 nd->nd_repstat = NFSERR_INVAL; 2373 } 2374 /* 2375 * Call nfsrv_lockctrl() even if nd_repstat is set, so that the 2376 * seqid# gets incremented. nfsrv_lockctrl() will return the 2377 * value of nd_repstat, if it gets that far. 2378 */ 2379 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid, 2380 &stateid, exp, nd, p); 2381 if (stp) 2382 FREE((caddr_t)stp, M_NFSDSTATE); 2383 if (lop) 2384 free((caddr_t)lop, M_NFSDLOCK); 2385 if (!nd->nd_repstat) { 2386 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2387 *tl++ = txdr_unsigned(stateid.seqid); 2388 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2389 } 2390 nfsmout: 2391 vput(vp); 2392 return (error); 2393 } 2394 2395 /* 2396 * nfsv4 open service 2397 */ 2398 APPLESTATIC int 2399 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram, 2400 vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, NFSPROC_T *p, 2401 struct nfsexstuff *exp) 2402 { 2403 u_int32_t *tl; 2404 int i; 2405 struct nfsstate *stp = NULL; 2406 int error = 0, create, claim, exclusive_flag = 0; 2407 u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask; 2408 int how = NFSCREATE_UNCHECKED; 2409 u_char cverf[NFSX_VERF]; 2410 vnode_t vp = NULL, dirp = NULL; 2411 struct nfsvattr nva, dirfor, diraft; 2412 struct nameidata named; 2413 nfsv4stateid_t stateid, delegstateid; 2414 nfsattrbit_t attrbits; 2415 nfsquad_t clientid; 2416 char *bufp = NULL; 2417 u_long *hashp; 2418 NFSACL_T *aclp = NULL; 2419 2420 #ifdef NFS4_ACL_EXTATTR_NAME 2421 aclp = acl_alloc(M_WAITOK); 2422 aclp->acl_cnt = 0; 2423 #endif 2424 NFSZERO_ATTRBIT(&attrbits); 2425 named.ni_startdir = NULL; 2426 named.ni_cnd.cn_nameiop = 0; 2427 NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 2428 i = fxdr_unsigned(int, *(tl + 5)); 2429 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + i, 2430 M_NFSDSTATE, M_WAITOK); 2431 stp->ls_ownerlen = i; 2432 stp->ls_op = nd->nd_rp; 2433 stp->ls_flags = NFSLCK_OPEN; 2434 stp->ls_uid = nd->nd_cred->cr_uid; 2435 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2436 i = fxdr_unsigned(int, *tl++); 2437 switch (i) { 2438 case NFSV4OPEN_ACCESSREAD: 2439 stp->ls_flags |= NFSLCK_READACCESS; 2440 break; 2441 case NFSV4OPEN_ACCESSWRITE: 2442 stp->ls_flags |= NFSLCK_WRITEACCESS; 2443 break; 2444 case NFSV4OPEN_ACCESSBOTH: 2445 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS); 2446 break; 2447 default: 2448 nd->nd_repstat = NFSERR_INVAL; 2449 }; 2450 i = fxdr_unsigned(int, *tl++); 2451 switch (i) { 2452 case NFSV4OPEN_DENYNONE: 2453 break; 2454 case NFSV4OPEN_DENYREAD: 2455 stp->ls_flags |= NFSLCK_READDENY; 2456 break; 2457 case NFSV4OPEN_DENYWRITE: 2458 stp->ls_flags |= NFSLCK_WRITEDENY; 2459 break; 2460 case NFSV4OPEN_DENYBOTH: 2461 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 2462 break; 2463 default: 2464 nd->nd_repstat = NFSERR_INVAL; 2465 }; 2466 clientid.lval[0] = *tl++; 2467 clientid.lval[1] = *tl; 2468 if (nd->nd_flag & ND_IMPLIEDCLID) { 2469 if (nd->nd_clientid.qval != clientid.qval) 2470 printf("EEK! multiple clids\n"); 2471 } else { 2472 nd->nd_flag |= ND_IMPLIEDCLID; 2473 nd->nd_clientid.qval = clientid.qval; 2474 } 2475 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen); 2476 if (error) { 2477 vrele(dp); 2478 #ifdef NFS4_ACL_EXTATTR_NAME 2479 acl_free(aclp); 2480 #endif 2481 FREE((caddr_t)stp, M_NFSDSTATE); 2482 return (error); 2483 } 2484 NFSVNO_ATTRINIT(&nva); 2485 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2486 create = fxdr_unsigned(int, *tl); 2487 if (!nd->nd_repstat) 2488 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd->nd_cred, p); 2489 if (create == NFSV4OPEN_CREATE) { 2490 nva.na_type = VREG; 2491 nva.na_mode = 0; 2492 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2493 how = fxdr_unsigned(int, *tl); 2494 switch (how) { 2495 case NFSCREATE_UNCHECKED: 2496 case NFSCREATE_GUARDED: 2497 error = nfsv4_sattr(nd, &nva, &attrbits, aclp, p); 2498 if (error) { 2499 vrele(dp); 2500 #ifdef NFS4_ACL_EXTATTR_NAME 2501 acl_free(aclp); 2502 #endif 2503 FREE((caddr_t)stp, M_NFSDSTATE); 2504 return (error); 2505 } 2506 /* 2507 * If the na_gid being set is the same as that of 2508 * the directory it is going in, clear it, since 2509 * that is what will be set by default. This allows 2510 * a user that isn't in that group to do the create. 2511 */ 2512 if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) && 2513 nva.na_gid == dirfor.na_gid) 2514 NFSVNO_UNSET(&nva, gid); 2515 if (!nd->nd_repstat) 2516 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva); 2517 break; 2518 case NFSCREATE_EXCLUSIVE: 2519 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 2520 NFSBCOPY((caddr_t)tl, cverf, NFSX_VERF); 2521 break; 2522 default: 2523 nd->nd_repstat = NFSERR_BADXDR; 2524 vrele(dp); 2525 #ifdef NFS4_ACL_EXTATTR_NAME 2526 acl_free(aclp); 2527 #endif 2528 FREE((caddr_t)stp, M_NFSDSTATE); 2529 return (0); 2530 }; 2531 } else if (create != NFSV4OPEN_NOCREATE) { 2532 nd->nd_repstat = NFSERR_BADXDR; 2533 vrele(dp); 2534 #ifdef NFS4_ACL_EXTATTR_NAME 2535 acl_free(aclp); 2536 #endif 2537 FREE((caddr_t)stp, M_NFSDSTATE); 2538 return (0); 2539 } 2540 2541 /* 2542 * Now, handle the claim, which usually includes looking up a 2543 * name in the directory referenced by dp. The exception is 2544 * NFSV4OPEN_CLAIMPREVIOUS. 2545 */ 2546 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2547 claim = fxdr_unsigned(int, *tl); 2548 if (claim == NFSV4OPEN_CLAIMDELEGATECUR) { 2549 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2550 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2551 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER); 2552 stp->ls_flags |= NFSLCK_DELEGCUR; 2553 } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2554 stp->ls_flags |= NFSLCK_DELEGPREV; 2555 } 2556 if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR 2557 || claim == NFSV4OPEN_CLAIMDELEGATEPREV) { 2558 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE && 2559 claim != NFSV4OPEN_CLAIMNULL) 2560 nd->nd_repstat = NFSERR_INVAL; 2561 if (nd->nd_repstat) { 2562 nd->nd_repstat = nfsrv_opencheck(clientid, 2563 &stateid, stp, NULL, nd, p, nd->nd_repstat); 2564 vrele(dp); 2565 #ifdef NFS4_ACL_EXTATTR_NAME 2566 acl_free(aclp); 2567 #endif 2568 FREE((caddr_t)stp, M_NFSDSTATE); 2569 return (0); 2570 } 2571 if (create == NFSV4OPEN_CREATE) 2572 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, 2573 LOCKPARENT | LOCKLEAF | SAVESTART); 2574 else 2575 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 2576 LOCKLEAF | SAVESTART); 2577 nfsvno_setpathbuf(&named, &bufp, &hashp); 2578 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 2579 if (error) { 2580 vrele(dp); 2581 #ifdef NFS4_ACL_EXTATTR_NAME 2582 acl_free(aclp); 2583 #endif 2584 FREE((caddr_t)stp, M_NFSDSTATE); 2585 nfsvno_relpathbuf(&named); 2586 return (error); 2587 } 2588 if (!nd->nd_repstat) { 2589 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, 2590 p, &dirp); 2591 } else { 2592 vrele(dp); 2593 nfsvno_relpathbuf(&named); 2594 } 2595 if (create == NFSV4OPEN_CREATE) { 2596 switch (how) { 2597 case NFSCREATE_UNCHECKED: 2598 if (named.ni_vp) { 2599 /* 2600 * Clear the setable attribute bits, except 2601 * for Size, if it is being truncated. 2602 */ 2603 NFSZERO_ATTRBIT(&attrbits); 2604 if (NFSVNO_ISSETSIZE(&nva)) 2605 NFSSETBIT_ATTRBIT(&attrbits, 2606 NFSATTRBIT_SIZE); 2607 } 2608 break; 2609 case NFSCREATE_GUARDED: 2610 if (named.ni_vp && !nd->nd_repstat) 2611 nd->nd_repstat = EEXIST; 2612 break; 2613 case NFSCREATE_EXCLUSIVE: 2614 exclusive_flag = 1; 2615 if (!named.ni_vp) 2616 nva.na_mode = 0; 2617 }; 2618 } 2619 nfsvno_open(nd, &named, clientid, &stateid, stp, 2620 &exclusive_flag, &nva, cverf, create, aclp, &attrbits, 2621 nd->nd_cred, p, exp, &vp); 2622 } else if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2623 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2624 i = fxdr_unsigned(int, *tl); 2625 switch (i) { 2626 case NFSV4OPEN_DELEGATEREAD: 2627 stp->ls_flags |= NFSLCK_DELEGREAD; 2628 break; 2629 case NFSV4OPEN_DELEGATEWRITE: 2630 stp->ls_flags |= NFSLCK_DELEGWRITE; 2631 case NFSV4OPEN_DELEGATENONE: 2632 break; 2633 default: 2634 nd->nd_repstat = NFSERR_BADXDR; 2635 vrele(dp); 2636 #ifdef NFS4_ACL_EXTATTR_NAME 2637 acl_free(aclp); 2638 #endif 2639 FREE((caddr_t)stp, M_NFSDSTATE); 2640 return (0); 2641 }; 2642 stp->ls_flags |= NFSLCK_RECLAIM; 2643 vp = dp; 2644 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY, p); 2645 nd->nd_repstat = nfsrv_opencheck(clientid, &stateid, stp, vp, 2646 nd, p, nd->nd_repstat); 2647 } else { 2648 nd->nd_repstat = NFSERR_BADXDR; 2649 vrele(dp); 2650 #ifdef NFS4_ACL_EXTATTR_NAME 2651 acl_free(aclp); 2652 #endif 2653 FREE((caddr_t)stp, M_NFSDSTATE); 2654 return (0); 2655 } 2656 2657 /* 2658 * Do basic access checking. 2659 */ 2660 if (!nd->nd_repstat && vnode_vtype(vp) != VREG) { 2661 if (vnode_vtype(vp) == VDIR) 2662 nd->nd_repstat = NFSERR_ISDIR; 2663 else if (vnode_vtype(vp) == VLNK) 2664 nd->nd_repstat = NFSERR_SYMLINK; 2665 else 2666 nd->nd_repstat = NFSERR_INVAL; 2667 } 2668 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS)) 2669 nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_WRITEDATA, nd->nd_cred, 2670 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED); 2671 if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) { 2672 nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_READDATA, nd->nd_cred, 2673 exp, p, NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED); 2674 if (nd->nd_repstat) 2675 nd->nd_repstat = nfsvno_accchk(vp, NFSV4ACE_EXECUTE, 2676 nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER, 2677 NFSACCCHK_VPISLOCKED); 2678 } 2679 2680 if (!nd->nd_repstat) 2681 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p); 2682 if (!nd->nd_repstat && exclusive_flag && 2683 NFSBCMP(cverf, (caddr_t)&nva.na_atime, NFSX_VERF)) 2684 nd->nd_repstat = EEXIST; 2685 /* 2686 * Do the open locking/delegation stuff. 2687 */ 2688 if (!nd->nd_repstat) 2689 nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid, 2690 &delegstateid, &rflags, exp, p, nva.na_filerev); 2691 2692 /* 2693 * vp must be unlocked before the call to nfsvno_getattr(dirp,...) 2694 * below, to avoid a deadlock with the lookup in nfsvno_namei() above. 2695 * (ie: Leave the NFSVOPUNLOCK() about here.) 2696 */ 2697 if (vp) 2698 NFSVOPUNLOCK(vp, 0, p); 2699 if (stp) 2700 FREE((caddr_t)stp, M_NFSDSTATE); 2701 if (!nd->nd_repstat && dirp) 2702 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd->nd_cred, p); 2703 if (!nd->nd_repstat) { 2704 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 2705 *tl++ = txdr_unsigned(stateid.seqid); 2706 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2707 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2708 if (claim == NFSV4OPEN_CLAIMPREVIOUS) { 2709 *tl++ = newnfs_true; 2710 *tl++ = 0; 2711 *tl++ = 0; 2712 *tl++ = 0; 2713 *tl++ = 0; 2714 } else { 2715 *tl++ = newnfs_false; /* Since dirp is not locked */ 2716 txdr_hyper(dirfor.na_filerev, tl); 2717 tl += 2; 2718 txdr_hyper(diraft.na_filerev, tl); 2719 tl += 2; 2720 } 2721 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS); 2722 (void) nfsrv_putattrbit(nd, &attrbits); 2723 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2724 if (rflags & NFSV4OPEN_READDELEGATE) 2725 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD); 2726 else if (rflags & NFSV4OPEN_WRITEDELEGATE) 2727 *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE); 2728 else 2729 *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE); 2730 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) { 2731 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED); 2732 *tl++ = txdr_unsigned(delegstateid.seqid); 2733 NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl, 2734 NFSX_STATEIDOTHER); 2735 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2736 if (rflags & NFSV4OPEN_RECALL) 2737 *tl = newnfs_true; 2738 else 2739 *tl = newnfs_false; 2740 if (rflags & NFSV4OPEN_WRITEDELEGATE) { 2741 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2742 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE); 2743 txdr_hyper(nva.na_size, tl); 2744 } 2745 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2746 *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE); 2747 *tl++ = txdr_unsigned(0x0); 2748 acemask = NFSV4ACE_ALLFILESMASK; 2749 if (nva.na_mode & S_IRUSR) 2750 acemask |= NFSV4ACE_READMASK; 2751 if (nva.na_mode & S_IWUSR) 2752 acemask |= NFSV4ACE_WRITEMASK; 2753 if (nva.na_mode & S_IXUSR) 2754 acemask |= NFSV4ACE_EXECUTEMASK; 2755 *tl = txdr_unsigned(acemask); 2756 (void) nfsm_strtom(nd, "OWNER@", 6); 2757 } 2758 *vpp = vp; 2759 } else if (vp) { 2760 vrele(vp); 2761 } 2762 if (dirp) 2763 vrele(dirp); 2764 #ifdef NFS4_ACL_EXTATTR_NAME 2765 acl_free(aclp); 2766 #endif 2767 return (0); 2768 nfsmout: 2769 vrele(dp); 2770 #ifdef NFS4_ACL_EXTATTR_NAME 2771 acl_free(aclp); 2772 #endif 2773 if (stp) 2774 FREE((caddr_t)stp, M_NFSDSTATE); 2775 return (error); 2776 } 2777 2778 /* 2779 * nfsv4 close service 2780 */ 2781 APPLESTATIC int 2782 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram, 2783 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2784 { 2785 u_int32_t *tl; 2786 struct nfsstate st, *stp = &st; 2787 int error = 0; 2788 nfsv4stateid_t stateid; 2789 nfsquad_t clientid; 2790 2791 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 2792 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2793 stp->ls_ownerlen = 0; 2794 stp->ls_op = nd->nd_rp; 2795 stp->ls_uid = nd->nd_cred->cr_uid; 2796 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2797 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2798 NFSX_STATEIDOTHER); 2799 stp->ls_flags = NFSLCK_CLOSE; 2800 clientid.lval[0] = stp->ls_stateid.other[0]; 2801 clientid.lval[1] = stp->ls_stateid.other[1]; 2802 if (nd->nd_flag & ND_IMPLIEDCLID) { 2803 if (nd->nd_clientid.qval != clientid.qval) 2804 printf("EEK! multiple clids\n"); 2805 } else { 2806 nd->nd_flag |= ND_IMPLIEDCLID; 2807 nd->nd_clientid.qval = clientid.qval; 2808 } 2809 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 2810 vput(vp); 2811 if (!nd->nd_repstat) { 2812 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2813 *tl++ = txdr_unsigned(stateid.seqid); 2814 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2815 } 2816 return (0); 2817 nfsmout: 2818 vput(vp); 2819 return (error); 2820 } 2821 2822 /* 2823 * nfsv4 delegpurge service 2824 */ 2825 APPLESTATIC int 2826 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram, 2827 __unused vnode_t vp, __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 2828 { 2829 u_int32_t *tl; 2830 int error = 0; 2831 nfsquad_t clientid; 2832 2833 if ((!nfs_rootfhset && !nfsv4root_set) || 2834 nfsd_checkrootexp(nd)) { 2835 nd->nd_repstat = NFSERR_WRONGSEC; 2836 return (0); 2837 } 2838 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2839 clientid.lval[0] = *tl++; 2840 clientid.lval[1] = *tl; 2841 if (nd->nd_flag & ND_IMPLIEDCLID) { 2842 if (nd->nd_clientid.qval != clientid.qval) 2843 printf("EEK! multiple clids\n"); 2844 } else { 2845 nd->nd_flag |= ND_IMPLIEDCLID; 2846 nd->nd_clientid.qval = clientid.qval; 2847 } 2848 nd->nd_repstat = nfsrv_delegupdate(clientid, NULL, NULL, 2849 NFSV4OP_DELEGPURGE, nd->nd_cred, p); 2850 nfsmout: 2851 return (error); 2852 } 2853 2854 /* 2855 * nfsv4 delegreturn service 2856 */ 2857 APPLESTATIC int 2858 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram, 2859 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2860 { 2861 u_int32_t *tl; 2862 int error = 0; 2863 nfsv4stateid_t stateid; 2864 nfsquad_t clientid; 2865 2866 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 2867 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2868 NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER); 2869 clientid.lval[0] = stateid.other[0]; 2870 clientid.lval[1] = stateid.other[1]; 2871 if (nd->nd_flag & ND_IMPLIEDCLID) { 2872 if (nd->nd_clientid.qval != clientid.qval) 2873 printf("EEK! multiple clids\n"); 2874 } else { 2875 nd->nd_flag |= ND_IMPLIEDCLID; 2876 nd->nd_clientid.qval = clientid.qval; 2877 } 2878 nd->nd_repstat = nfsrv_delegupdate(clientid, &stateid, vp, 2879 NFSV4OP_DELEGRETURN, nd->nd_cred, p); 2880 nfsmout: 2881 vput(vp); 2882 return (error); 2883 } 2884 2885 /* 2886 * nfsv4 get file handle service 2887 */ 2888 APPLESTATIC int 2889 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram, 2890 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2891 { 2892 fhandle_t fh; 2893 2894 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 2895 vput(vp); 2896 if (!nd->nd_repstat) 2897 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0); 2898 return (0); 2899 } 2900 2901 /* 2902 * nfsv4 open confirm service 2903 */ 2904 APPLESTATIC int 2905 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram, 2906 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2907 { 2908 u_int32_t *tl; 2909 struct nfsstate st, *stp = &st; 2910 int error = 0; 2911 nfsv4stateid_t stateid; 2912 nfsquad_t clientid; 2913 2914 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 2915 stp->ls_ownerlen = 0; 2916 stp->ls_op = nd->nd_rp; 2917 stp->ls_uid = nd->nd_cred->cr_uid; 2918 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2919 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2920 NFSX_STATEIDOTHER); 2921 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2922 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl); 2923 stp->ls_flags = NFSLCK_CONFIRM; 2924 clientid.lval[0] = stp->ls_stateid.other[0]; 2925 clientid.lval[1] = stp->ls_stateid.other[1]; 2926 if (nd->nd_flag & ND_IMPLIEDCLID) { 2927 if (nd->nd_clientid.qval != clientid.qval) 2928 printf("EEK! multiple clids\n"); 2929 } else { 2930 nd->nd_flag |= ND_IMPLIEDCLID; 2931 nd->nd_clientid.qval = clientid.qval; 2932 } 2933 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p); 2934 if (!nd->nd_repstat) { 2935 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2936 *tl++ = txdr_unsigned(stateid.seqid); 2937 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 2938 } 2939 nfsmout: 2940 vput(vp); 2941 return (error); 2942 } 2943 2944 /* 2945 * nfsv4 open downgrade service 2946 */ 2947 APPLESTATIC int 2948 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram, 2949 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 2950 { 2951 u_int32_t *tl; 2952 int i; 2953 struct nfsstate st, *stp = &st; 2954 int error = 0; 2955 nfsv4stateid_t stateid; 2956 nfsquad_t clientid; 2957 2958 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 2959 stp->ls_ownerlen = 0; 2960 stp->ls_op = nd->nd_rp; 2961 stp->ls_uid = nd->nd_cred->cr_uid; 2962 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++); 2963 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other, 2964 NFSX_STATEIDOTHER); 2965 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED); 2966 stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++); 2967 i = fxdr_unsigned(int, *tl++); 2968 switch (i) { 2969 case NFSV4OPEN_ACCESSREAD: 2970 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE); 2971 break; 2972 case NFSV4OPEN_ACCESSWRITE: 2973 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE); 2974 break; 2975 case NFSV4OPEN_ACCESSBOTH: 2976 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS | 2977 NFSLCK_DOWNGRADE); 2978 break; 2979 default: 2980 nd->nd_repstat = NFSERR_BADXDR; 2981 }; 2982 i = fxdr_unsigned(int, *tl); 2983 switch (i) { 2984 case NFSV4OPEN_DENYNONE: 2985 break; 2986 case NFSV4OPEN_DENYREAD: 2987 stp->ls_flags |= NFSLCK_READDENY; 2988 break; 2989 case NFSV4OPEN_DENYWRITE: 2990 stp->ls_flags |= NFSLCK_WRITEDENY; 2991 break; 2992 case NFSV4OPEN_DENYBOTH: 2993 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY); 2994 break; 2995 default: 2996 nd->nd_repstat = NFSERR_BADXDR; 2997 }; 2998 2999 clientid.lval[0] = stp->ls_stateid.other[0]; 3000 clientid.lval[1] = stp->ls_stateid.other[1]; 3001 if (nd->nd_flag & ND_IMPLIEDCLID) { 3002 if (nd->nd_clientid.qval != clientid.qval) 3003 printf("EEK! multiple clids\n"); 3004 } else { 3005 nd->nd_flag |= ND_IMPLIEDCLID; 3006 nd->nd_clientid.qval = clientid.qval; 3007 } 3008 if (!nd->nd_repstat) 3009 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, 3010 nd, p); 3011 if (!nd->nd_repstat) { 3012 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 3013 *tl++ = txdr_unsigned(stateid.seqid); 3014 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER); 3015 } 3016 nfsmout: 3017 vput(vp); 3018 return (error); 3019 } 3020 3021 /* 3022 * nfsv4 renew lease service 3023 */ 3024 APPLESTATIC int 3025 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram, 3026 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3027 { 3028 u_int32_t *tl; 3029 int error = 0; 3030 nfsquad_t clientid; 3031 3032 if ((!nfs_rootfhset && !nfsv4root_set) || 3033 nfsd_checkrootexp(nd)) { 3034 nd->nd_repstat = NFSERR_WRONGSEC; 3035 return (0); 3036 } 3037 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3038 clientid.lval[0] = *tl++; 3039 clientid.lval[1] = *tl; 3040 if (nd->nd_flag & ND_IMPLIEDCLID) { 3041 if (nd->nd_clientid.qval != clientid.qval) 3042 printf("EEK! multiple clids\n"); 3043 } else { 3044 nd->nd_flag |= ND_IMPLIEDCLID; 3045 nd->nd_clientid.qval = clientid.qval; 3046 } 3047 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW), 3048 NULL, (nfsquad_t)((u_quad_t)0), nd, p); 3049 nfsmout: 3050 return (error); 3051 } 3052 3053 /* 3054 * nfsv4 security info service 3055 */ 3056 APPLESTATIC int 3057 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram, 3058 vnode_t dp, NFSPROC_T *p, struct nfsexstuff *exp) 3059 { 3060 u_int32_t *tl; 3061 int len; 3062 struct nameidata named; 3063 vnode_t dirp = NULL, vp; 3064 struct nfsrvfh fh; 3065 struct nfsexstuff retnes; 3066 mount_t mp; 3067 u_int32_t *sizp; 3068 int error, savflag, i; 3069 char *bufp; 3070 u_long *hashp; 3071 3072 /* 3073 * All this just to get the export flags for the name. 3074 */ 3075 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP, 3076 LOCKLEAF | SAVESTART); 3077 nfsvno_setpathbuf(&named, &bufp, &hashp); 3078 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen); 3079 if (error) { 3080 vput(dp); 3081 nfsvno_relpathbuf(&named); 3082 return (error); 3083 } 3084 if (!nd->nd_repstat) { 3085 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp); 3086 } else { 3087 vput(dp); 3088 nfsvno_relpathbuf(&named); 3089 } 3090 if (dirp) 3091 vrele(dirp); 3092 if (nd->nd_repstat) 3093 return (0); 3094 vrele(named.ni_startdir); 3095 nfsvno_relpathbuf(&named); 3096 fh.nfsrvfh_len = NFSX_MYFH; 3097 vp = named.ni_vp; 3098 nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p); 3099 mp = vnode_mount(vp); /* so it won't try to re-lock filesys */ 3100 retnes.nes_vfslocked = exp->nes_vfslocked; 3101 vput(vp); 3102 savflag = nd->nd_flag; 3103 if (!nd->nd_repstat) { 3104 nfsd_fhtovp(nd, &fh, &vp, &retnes, &mp, 0, p); 3105 if (vp) 3106 vput(vp); 3107 } 3108 nd->nd_flag = savflag; 3109 if (nd->nd_repstat) 3110 return (0); 3111 3112 /* 3113 * Finally have the export flags for name, so we can create 3114 * the security info. 3115 */ 3116 len = 0; 3117 NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED); 3118 for (i = 0; i < retnes.nes_numsecflavor; i++) { 3119 if (retnes.nes_secflavors[i] == AUTH_SYS) { 3120 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3121 *tl = txdr_unsigned(RPCAUTH_UNIX); 3122 len++; 3123 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) { 3124 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3125 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3126 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3127 nfsgss_mechlist[KERBV_MECH].len); 3128 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3129 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3130 *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE); 3131 len++; 3132 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) { 3133 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3134 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3135 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3136 nfsgss_mechlist[KERBV_MECH].len); 3137 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3138 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3139 *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY); 3140 len++; 3141 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) { 3142 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3143 *tl++ = txdr_unsigned(RPCAUTH_GSS); 3144 (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str, 3145 nfsgss_mechlist[KERBV_MECH].len); 3146 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3147 *tl++ = txdr_unsigned(GSS_KERBV_QOP); 3148 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY); 3149 len++; 3150 } 3151 } 3152 *sizp = txdr_unsigned(len); 3153 return (0); 3154 } 3155 3156 /* 3157 * nfsv4 set client id service 3158 */ 3159 APPLESTATIC int 3160 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram, 3161 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3162 { 3163 u_int32_t *tl; 3164 int i; 3165 int error = 0, idlen; 3166 struct nfsclient *clp = NULL; 3167 struct sockaddr_in *rad; 3168 u_char *verf, *ucp, *ucp2, addrbuf[24]; 3169 nfsquad_t clientid, confirm; 3170 3171 if ((!nfs_rootfhset && !nfsv4root_set) || 3172 nfsd_checkrootexp(nd)) { 3173 nd->nd_repstat = NFSERR_WRONGSEC; 3174 return (0); 3175 } 3176 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED); 3177 verf = (u_char *)tl; 3178 tl += (NFSX_VERF / NFSX_UNSIGNED); 3179 i = fxdr_unsigned(int, *tl); 3180 if (i > NFSV4_OPAQUELIMIT || i <= 0) { 3181 nd->nd_repstat = NFSERR_BADXDR; 3182 return (error); 3183 } 3184 idlen = i; 3185 if (nd->nd_flag & ND_GSS) 3186 i += nd->nd_princlen; 3187 MALLOC(clp, struct nfsclient *, sizeof (struct nfsclient) + i, 3188 M_NFSDCLIENT, M_WAITOK); 3189 NFSBZERO((caddr_t)clp, sizeof (struct nfsclient) + i); 3190 NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx); 3191 NFSSOCKADDRALLOC(clp->lc_req.nr_nam); 3192 NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in)); 3193 clp->lc_req.nr_cred = NULL; 3194 NFSBCOPY(verf, clp->lc_verf, NFSX_VERF); 3195 clp->lc_idlen = idlen; 3196 error = nfsrv_mtostr(nd, clp->lc_id, idlen); 3197 if (error) 3198 goto nfsmout; 3199 if (nd->nd_flag & ND_GSS) { 3200 clp->lc_flags = LCL_GSS; 3201 if (nd->nd_flag & ND_GSSINTEGRITY) 3202 clp->lc_flags |= LCL_GSSINTEGRITY; 3203 else if (nd->nd_flag & ND_GSSPRIVACY) 3204 clp->lc_flags |= LCL_GSSPRIVACY; 3205 } else { 3206 clp->lc_flags = 0; 3207 } 3208 if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) { 3209 clp->lc_flags |= LCL_NAME; 3210 clp->lc_namelen = nd->nd_princlen; 3211 clp->lc_name = &clp->lc_id[idlen]; 3212 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen); 3213 } else { 3214 clp->lc_uid = nd->nd_cred->cr_uid; 3215 clp->lc_gid = nd->nd_cred->cr_gid; 3216 } 3217 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3218 clp->lc_program = fxdr_unsigned(u_int32_t, *tl); 3219 error = nfsrv_getclientipaddr(nd, clp); 3220 if (error) 3221 goto nfsmout; 3222 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3223 clp->lc_callback = fxdr_unsigned(u_int32_t, *tl); 3224 3225 /* 3226 * nfsrv_setclient() does the actual work of adding it to the 3227 * client list. If there is no error, the structure has been 3228 * linked into the client list and clp should no longer be used 3229 * here. When an error is returned, it has not been linked in, 3230 * so it should be free'd. 3231 */ 3232 nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p); 3233 if (nd->nd_repstat == NFSERR_CLIDINUSE) { 3234 if (clp->lc_flags & LCL_TCPCALLBACK) 3235 (void) nfsm_strtom(nd, "tcp", 3); 3236 else 3237 (void) nfsm_strtom(nd, "udp", 3); 3238 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *); 3239 ucp = (u_char *)&rad->sin_addr.s_addr; 3240 ucp2 = (u_char *)&rad->sin_port; 3241 sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff, 3242 ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff, 3243 ucp2[0] & 0xff, ucp2[1] & 0xff); 3244 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf)); 3245 } 3246 if (clp) { 3247 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3248 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3249 free((caddr_t)clp, M_NFSDCLIENT); 3250 } 3251 if (!nd->nd_repstat) { 3252 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER); 3253 *tl++ = clientid.lval[0]; 3254 *tl++ = clientid.lval[1]; 3255 *tl++ = confirm.lval[0]; 3256 *tl = confirm.lval[1]; 3257 } 3258 return (0); 3259 nfsmout: 3260 if (clp) { 3261 NFSSOCKADDRFREE(clp->lc_req.nr_nam); 3262 NFSFREEMUTEX(&clp->lc_req.nr_mtx); 3263 free((caddr_t)clp, M_NFSDCLIENT); 3264 } 3265 return (error); 3266 } 3267 3268 /* 3269 * nfsv4 set client id confirm service 3270 */ 3271 APPLESTATIC int 3272 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd, 3273 __unused int isdgram, __unused vnode_t vp, NFSPROC_T *p, 3274 __unused struct nfsexstuff *exp) 3275 { 3276 u_int32_t *tl; 3277 int error = 0; 3278 nfsquad_t clientid, confirm; 3279 3280 if ((!nfs_rootfhset && !nfsv4root_set) || 3281 nfsd_checkrootexp(nd)) { 3282 nd->nd_repstat = NFSERR_WRONGSEC; 3283 return (0); 3284 } 3285 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER); 3286 clientid.lval[0] = *tl++; 3287 clientid.lval[1] = *tl++; 3288 confirm.lval[0] = *tl++; 3289 confirm.lval[1] = *tl; 3290 3291 /* 3292 * nfsrv_getclient() searches the client list for a match and 3293 * returns the appropriate NFSERR status. 3294 */ 3295 nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW), 3296 NULL, confirm, nd, p); 3297 nfsmout: 3298 return (error); 3299 } 3300 3301 /* 3302 * nfsv4 verify service 3303 */ 3304 APPLESTATIC int 3305 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram, 3306 vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3307 { 3308 int error = 0, ret, fhsize = NFSX_MYFH; 3309 struct nfsvattr nva; 3310 struct statfs sf; 3311 struct nfsfsinfo fs; 3312 fhandle_t fh; 3313 3314 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd->nd_cred, p); 3315 if (!nd->nd_repstat) 3316 nd->nd_repstat = nfsvno_statfs(vp, &sf); 3317 if (!nd->nd_repstat) 3318 nd->nd_repstat = nfsvno_getfh(vp, &fh, p); 3319 if (!nd->nd_repstat) { 3320 nfsvno_getfs(&fs, isdgram); 3321 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL, 3322 &sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred); 3323 if (!error) { 3324 if (nd->nd_procnum == NFSV4OP_NVERIFY) { 3325 if (ret == 0) 3326 nd->nd_repstat = NFSERR_SAME; 3327 else if (ret != NFSERR_NOTSAME) 3328 nd->nd_repstat = ret; 3329 } else if (ret) 3330 nd->nd_repstat = ret; 3331 } 3332 } 3333 vput(vp); 3334 return (error); 3335 } 3336 3337 /* 3338 * nfs openattr rpc 3339 */ 3340 APPLESTATIC int 3341 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram, 3342 vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp, 3343 __unused NFSPROC_T *p, __unused struct nfsexstuff *exp) 3344 { 3345 u_int32_t *tl; 3346 int error = 0, createdir; 3347 3348 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3349 createdir = fxdr_unsigned(int, *tl); 3350 nd->nd_repstat = NFSERR_NOTSUPP; 3351 nfsmout: 3352 vrele(dp); 3353 return (error); 3354 } 3355 3356 /* 3357 * nfsv4 release lock owner service 3358 */ 3359 APPLESTATIC int 3360 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram, 3361 __unused vnode_t vp, NFSPROC_T *p, __unused struct nfsexstuff *exp) 3362 { 3363 u_int32_t *tl; 3364 struct nfsstate *stp = NULL; 3365 int error = 0, len; 3366 nfsquad_t clientid; 3367 3368 if ((!nfs_rootfhset && !nfsv4root_set) || 3369 nfsd_checkrootexp(nd)) { 3370 nd->nd_repstat = NFSERR_WRONGSEC; 3371 return (0); 3372 } 3373 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3374 len = fxdr_unsigned(int, *(tl + 2)); 3375 MALLOC(stp, struct nfsstate *, sizeof (struct nfsstate) + len, 3376 M_NFSDSTATE, M_WAITOK); 3377 stp->ls_ownerlen = len; 3378 stp->ls_op = NULL; 3379 stp->ls_flags = NFSLCK_RELEASE; 3380 stp->ls_uid = nd->nd_cred->cr_uid; 3381 clientid.lval[0] = *tl++; 3382 clientid.lval[1] = *tl; 3383 if (nd->nd_flag & ND_IMPLIEDCLID) { 3384 if (nd->nd_clientid.qval != clientid.qval) 3385 printf("EEK! multiple clids\n"); 3386 } else { 3387 nd->nd_flag |= ND_IMPLIEDCLID; 3388 nd->nd_clientid.qval = clientid.qval; 3389 } 3390 error = nfsrv_mtostr(nd, stp->ls_owner, len); 3391 if (error) 3392 goto nfsmout; 3393 nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p); 3394 FREE((caddr_t)stp, M_NFSDSTATE); 3395 return (0); 3396 nfsmout: 3397 if (stp) 3398 free((caddr_t)stp, M_NFSDSTATE); 3399 return (error); 3400 } 3401