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