1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T. 29 * All rights reserved. 30 */ 31 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 35 #include <sys/types.h> 36 #include <sys/param.h> 37 #include <sys/time.h> 38 #include <sys/vfs.h> 39 #include <sys/vnode.h> 40 #include <sys/socket.h> 41 #include <sys/errno.h> 42 #include <sys/uio.h> 43 #include <sys/proc.h> 44 #include <sys/user.h> 45 #include <sys/file.h> 46 #include <sys/tiuser.h> 47 #include <sys/kmem.h> 48 #include <sys/pathname.h> 49 #include <sys/debug.h> 50 #include <sys/vtrace.h> 51 #include <sys/cmn_err.h> 52 #include <sys/acl.h> 53 #include <sys/utsname.h> 54 #include <netinet/in.h> 55 56 #include <rpc/types.h> 57 #include <rpc/auth.h> 58 #include <rpc/svc.h> 59 60 #include <nfs/nfs.h> 61 #include <nfs/export.h> 62 #include <nfs/nfssys.h> 63 #include <nfs/nfs_clnt.h> 64 #include <nfs/nfs_acl.h> 65 #include <nfs/nfs_log.h> 66 #include <nfs/lm.h> 67 68 #define EXPTABLESIZE 16 69 70 struct exportinfo *exptable[EXPTABLESIZE]; 71 72 static int unexport(fsid_t *, fid_t *, vnode_t *); 73 static void exportfree(struct exportinfo *); 74 static int loadindex(struct exportdata *); 75 76 extern void nfsauth_cache_free(struct exportinfo *); 77 extern int sec_svc_loadrootnames(int, int, caddr_t **, model_t); 78 extern void sec_svc_freerootnames(int, int, caddr_t *); 79 80 #ifdef VOLATILE_FH_TEST 81 static struct ex_vol_rename *find_volrnm_fh(struct exportinfo *, nfs_fh4 *); 82 static uint32_t find_volrnm_fh_id(struct exportinfo *, nfs_fh4 *); 83 static void free_volrnm_list(struct exportinfo *); 84 #endif /* VOLATILE_FH_TEST */ 85 86 /* 87 * exported_lock Read/Write lock that protects the exportinfo list. 88 * This lock must be held when searching or modifiying 89 * the exportinfo list. 90 */ 91 krwlock_t exported_lock; 92 93 /* 94 * "public" and default (root) location for public filehandle 95 */ 96 struct exportinfo *exi_public, *exi_root; 97 98 fid_t exi_rootfid; /* for checking the default public file handle */ 99 100 fhandle_t nullfh2; /* for comparing V2 filehandles */ 101 102 #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1)) 103 104 /* 105 * File handle hash function, good for producing hash values 16 bits wide. 106 */ 107 int 108 nfs_fhhash(fsid_t *fsid, fid_t *fid) 109 { 110 short *data; 111 int i, len; 112 short h; 113 114 ASSERT(fid != NULL); 115 116 data = (short *)fid->fid_data; 117 118 /* fid_data must be aligned on a short */ 119 ASSERT((((uintptr_t)data) & (sizeof (short) - 1)) == 0); 120 121 if (fid->fid_len == 10) { 122 /* 123 * probably ufs: hash on bytes 4,5 and 8,9 124 */ 125 return (fsid->val[0] ^ data[2] ^ data[4]); 126 } 127 128 if (fid->fid_len == 6) { 129 /* 130 * probably hsfs: hash on bytes 0,1 and 4,5 131 */ 132 return ((fsid->val[0] ^ data[0] ^ data[2])); 133 } 134 135 /* 136 * Some other file system. Assume that every byte is 137 * worth hashing. 138 */ 139 h = (short)fsid->val[0]; 140 141 /* 142 * Sanity check the length before using it 143 * blindly in case the client trashed it. 144 */ 145 if (fid->fid_len > NFS_FHMAXDATA) 146 len = 0; 147 else 148 len = fid->fid_len / sizeof (short); 149 150 /* 151 * This will ignore one byte if len is not a multiple of 152 * of sizeof (short). No big deal since we at least get some 153 * variation with fsid->val[0]; 154 */ 155 for (i = 0; i < len; i++) 156 h ^= data[i]; 157 158 return ((int)h); 159 } 160 161 /* 162 * Counted byte string compare routine, optimized for file ids. 163 */ 164 int 165 nfs_fhbcmp(char *d1, char *d2, int l) 166 { 167 int k; 168 169 if (l > NFS_FHMAXDATA) 170 return (1); 171 172 /* 173 * We are always passed pointers to the data portions of 174 * two fids, where pointers are always 2 bytes from 32 bit 175 * alignment. If the length is also 2 bytes off word alignment, 176 * we can do word compares, because the two bytes before the fid 177 * data are always the length packed into a 16 bit short, so we 178 * can safely start our comparisons at d1-2 and d2-2. 179 * If the length is 2 bytes off word alignment, that probably 180 * means that first two bytes are zeroes. This means that 181 * first word in each fid, including the length are going to be 182 * equal (we wouldn't call fhbcmp if the lengths weren't the 183 * same). Thus it makes the most sense to start comparing the 184 * last words of each data portion. 185 */ 186 187 if ((l & 0x3) == 2) { 188 /* 189 * We are going move the data pointers to the 190 * last word. Adding just the length, puts us to the 191 * word past end of the data. So reduce length by one 192 * word length. 193 */ 194 k = l - 4; 195 /* 196 * Both adjusted length and the data pointer are offset two 197 * bytes from word alignment. Adding them together gives 198 * us word alignment. 199 */ 200 d1 += k; 201 d2 += k; 202 l += 2; 203 while (l -= 4) { 204 if (*(int *)d1 != *(int *)d2) 205 return (1); 206 d1 -= 4; 207 d2 -= 4; 208 } 209 } else { 210 while (l--) { 211 if (*d1++ != *d2++) 212 return (1); 213 } 214 } 215 return (0); 216 } 217 218 /* 219 * Free the memory allocated within a secinfo entry. 220 */ 221 void 222 srv_secinfo_entry_free(struct secinfo *secp) 223 { 224 if (secp->s_rootcnt > 0 && secp->s_rootnames != NULL) { 225 sec_svc_freerootnames(secp->s_secinfo.sc_rpcnum, 226 secp->s_rootcnt, secp->s_rootnames); 227 secp->s_rootcnt = 0; 228 } 229 230 if ((secp->s_secinfo.sc_rpcnum == RPCSEC_GSS) && 231 (secp->s_secinfo.sc_gss_mech_type)) { 232 kmem_free(secp->s_secinfo.sc_gss_mech_type->elements, 233 secp->s_secinfo.sc_gss_mech_type->length); 234 kmem_free(secp->s_secinfo.sc_gss_mech_type, 235 sizeof (rpc_gss_OID_desc)); 236 secp->s_secinfo.sc_gss_mech_type = NULL; 237 } 238 239 } 240 241 /* 242 * Free a list of secinfo allocated in the exportdata structure. 243 */ 244 void 245 srv_secinfo_list_free(struct secinfo *secinfo, int cnt) 246 { 247 int i; 248 249 if (cnt == 0) 250 return; 251 252 for (i = 0; i < cnt; i++) 253 srv_secinfo_entry_free(&secinfo[i]); 254 255 kmem_free(secinfo, cnt * sizeof (struct secinfo)); 256 } 257 258 /* 259 * Allocate and copy a secinfo data from "from" to "to". 260 * 261 * This routine is used by srv_secinfo_add() to add a new flavor to an 262 * ancestor's export node. The rootnames are not copied because the 263 * allowable rootname access only applies to the explicit exported node, 264 * not its ancestor's. 265 * 266 * "to" should have already been allocated and zeroed before calling 267 * this routine. 268 * 269 * This routine is used under the protection of exported_lock (RW_WRITER). 270 */ 271 void 272 srv_secinfo_copy(struct secinfo *from, struct secinfo *to) 273 { 274 to->s_secinfo.sc_nfsnum = from->s_secinfo.sc_nfsnum; 275 to->s_secinfo.sc_rpcnum = from->s_secinfo.sc_rpcnum; 276 277 if (from->s_secinfo.sc_rpcnum == RPCSEC_GSS) { 278 to->s_secinfo.sc_service = from->s_secinfo.sc_service; 279 bcopy(from->s_secinfo.sc_name, to->s_secinfo.sc_name, 280 strlen(from->s_secinfo.sc_name)); 281 bcopy(from->s_secinfo.sc_gss_mech, to->s_secinfo.sc_gss_mech, 282 strlen(from->s_secinfo.sc_gss_mech)); 283 284 /* copy mechanism oid */ 285 to->s_secinfo.sc_gss_mech_type = 286 kmem_alloc(sizeof (rpc_gss_OID_desc), KM_SLEEP); 287 to->s_secinfo.sc_gss_mech_type->length = 288 from->s_secinfo.sc_gss_mech_type->length; 289 to->s_secinfo.sc_gss_mech_type->elements = 290 kmem_alloc(from->s_secinfo.sc_gss_mech_type->length, 291 KM_SLEEP); 292 bcopy(from->s_secinfo.sc_gss_mech_type->elements, 293 to->s_secinfo.sc_gss_mech_type->elements, 294 from->s_secinfo.sc_gss_mech_type->length); 295 } 296 297 to->s_refcnt = from->s_refcnt; 298 to->s_window = from->s_window; 299 /* no need to copy the mode bits - s_flags */ 300 } 301 302 /* 303 * Add the new security flavors from newdata to the current list, curdata. 304 * Upon return, curdata has the newly merged secinfo list. 305 * 306 * There should be at least 1 secinfo entry in newdata. 307 * 308 * This routine is used under the protection of exported_lock (RW_WRITER). 309 */ 310 void 311 srv_secinfo_add(struct exportdata *curdata, struct exportdata *newdata) 312 { 313 int ccnt, c; /* sec count in current data - curdata */ 314 int ncnt, n; /* sec count in new data - newdata */ 315 int tcnt, mcnt; /* total sec count after merge */ 316 struct secinfo *msec; /* merged secinfo list */ 317 318 ccnt = curdata->ex_seccnt; 319 ncnt = newdata->ex_seccnt; 320 321 ASSERT(ncnt > 0); 322 tcnt = ccnt + ncnt; 323 324 for (n = 0; n < ncnt; n++) { 325 for (c = 0; c < ccnt; c++) { 326 if (newdata->ex_secinfo[n].s_secinfo.sc_nfsnum == 327 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) { 328 329 /* 330 * add the reference count of the newdata 331 * to the curdata for this nfs flavor. 332 */ 333 curdata->ex_secinfo[c].s_refcnt += 334 newdata->ex_secinfo[n].s_refcnt; 335 336 tcnt--; 337 break; 338 } 339 } 340 } 341 342 if (tcnt == ccnt) 343 return; /* no change; no new flavors */ 344 345 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP); 346 347 /* move current secinfo list data to the new list */ 348 for (c = 0; c < ccnt; c++) { 349 350 bcopy(&curdata->ex_secinfo[c], &msec[c], 351 sizeof (struct secinfo)); 352 } 353 354 /* Add the flavor that's not in the current data */ 355 mcnt = ccnt; 356 for (n = 0; n < ncnt; n++) { 357 for (c = 0; c < ccnt; c++) { 358 if (newdata->ex_secinfo[n].s_secinfo.sc_nfsnum == 359 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) 360 break; 361 } 362 363 /* This is the one. Add it. */ 364 if (c == ccnt) { 365 srv_secinfo_copy(&newdata->ex_secinfo[n], &msec[mcnt]); 366 if (curdata->ex_flags & EX_PSEUDO) 367 msec[mcnt].s_flags = M_RO; 368 mcnt++; 369 } 370 } 371 372 ASSERT(mcnt == tcnt); 373 /* 374 * Done. Update curdata. 375 * Free up the existing secinfo list in curdata and 376 * set the new value. 377 */ 378 if (ccnt > 0) 379 kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo)); 380 curdata->ex_seccnt = tcnt; 381 curdata->ex_secinfo = msec; 382 } 383 384 /* 385 * For NFS V4. 386 * Remove the security data of the unexported node from its ancestors. 387 * Assume there is at least one flavor entry in the current data, curdata. 388 * 389 * This routine is used under the protection of exported_lock (RW_WRITER). 390 */ 391 void 392 srv_secinfo_remove(struct exportdata *curdata, struct exportdata *remdata) 393 { 394 int ccnt, c; /* sec count in current data - curdata */ 395 int rcnt, r; /* sec count in removal data - remdata */ 396 int tcnt, mcnt; /* total sec count after removing */ 397 struct secinfo *msec; /* final secinfo list after removing */ 398 399 ASSERT(curdata->ex_seccnt > 0); 400 ccnt = curdata->ex_seccnt; 401 rcnt = remdata->ex_seccnt; 402 tcnt = ccnt; 403 404 for (r = 0; r < rcnt; r++) { 405 406 if (SEC_REF_EXPORTED(&remdata->ex_secinfo[r])) { 407 /* 408 * Remove a flavor only if the flavor was a shared flavor for 409 * the remdata exported node that's being unshared. Otherwise, 410 * this flavor is for the children of remdata, need to keep it. 411 */ 412 for (c = 0; c < ccnt; c++) { 413 if (remdata->ex_secinfo[r].s_secinfo.sc_nfsnum == 414 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) { 415 416 /* 417 * Decrement secinfo reference count by 1. 418 * If this entry is invalid after decrementing 419 * the count (i.e. count < 1), this entry will 420 * be removed. 421 */ 422 curdata->ex_secinfo[c].s_refcnt--; 423 if (SEC_REF_INVALID(&curdata->ex_secinfo[c])) 424 tcnt--; 425 426 break; 427 } 428 } 429 } 430 } 431 432 ASSERT(tcnt >= 0); 433 if (tcnt == ccnt) 434 return; /* no change; no flavors to remove */ 435 436 if (tcnt == 0) { 437 srv_secinfo_list_free(curdata->ex_secinfo, ccnt); 438 curdata->ex_seccnt = 0; 439 curdata->ex_secinfo = NULL; 440 return; 441 } 442 443 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP); 444 445 /* walk thru the given secinfo list to remove the flavors */ 446 mcnt = 0; 447 for (c = 0; c < ccnt; c++) { 448 449 if (SEC_REF_INVALID(&curdata->ex_secinfo[c])) { 450 srv_secinfo_entry_free(&curdata->ex_secinfo[c]); 451 } else { 452 bcopy(&curdata->ex_secinfo[c], &msec[mcnt], 453 sizeof (struct secinfo)); 454 mcnt++; 455 } 456 } 457 458 ASSERT(mcnt == tcnt); 459 /* 460 * Done. Update curdata. 461 * Free the existing secinfo list in curdata. All pointers 462 * within the list have either been moved to msec or freed 463 * if it's invalid. 464 */ 465 kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo)); 466 curdata->ex_seccnt = tcnt; 467 curdata->ex_secinfo = msec; 468 } 469 470 /* 471 * Upon re-sharing an export node, if there is more than 1 export reference 472 * to an old flavor (i.e. some of its children shared with this flavor), this 473 * flavor information needs to be transfered to the new shared node. 474 * 475 * Expect at least 1 secinfo entry in the old shared node - olddata. 476 * Expect both curdata and olddata are not pseudo nodes. 477 * 478 * This routine is used under the protection of exported_lock (RW_WRITER). 479 */ 480 void 481 srv_secinfo_exp2exp(struct exportdata *curdata, struct exportdata *olddata) 482 { 483 int ccnt, c; /* sec count in current data - curdata */ 484 int ocnt, o; /* sec count in old data - olddata */ 485 int tcnt, mcnt; /* total sec count after the transfer */ 486 struct secinfo *msec; /* merged secinfo list */ 487 488 ccnt = curdata->ex_seccnt; 489 ocnt = olddata->ex_seccnt; 490 491 ASSERT(ocnt > 0); 492 ASSERT(!(olddata->ex_flags & EX_PSEUDO)); 493 ASSERT(!(curdata->ex_flags & EX_PSEUDO)); 494 495 /* 496 * If the olddata has flavors with more than 1 reference count, 497 * transfer the information to the curdata. 498 */ 499 tcnt = ccnt + ocnt; 500 501 for (o = 0; o < ocnt; o++) { 502 503 if (SEC_REF_SELF(&olddata->ex_secinfo[o])) { 504 tcnt--; 505 } else { 506 for (c = 0; c < ccnt; c++) { 507 if (olddata->ex_secinfo[o].s_secinfo.sc_nfsnum == 508 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) { 509 510 /* add old reference to the current secinfo count */ 511 curdata->ex_secinfo[c].s_refcnt += 512 olddata->ex_secinfo[o].s_refcnt; 513 514 /* delete the old export flavor reference */ 515 if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o])) 516 curdata->ex_secinfo[c].s_refcnt--; 517 tcnt--; 518 break; 519 } 520 } 521 } 522 } 523 524 if (tcnt == ccnt) 525 return; /* no more transfer to do */ 526 527 /* 528 * olddata has flavors refered by its children that are not 529 * in the current (new) export flavor list. Add these flavors. 530 */ 531 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP); 532 533 /* move current secinfo list data to the new list */ 534 for (c = 0; c < ccnt; c++) { 535 bcopy(&curdata->ex_secinfo[c], &msec[c], 536 sizeof (struct secinfo)); 537 } 538 539 /* 540 * Add the flavor that's not in the new export, but still 541 * referred by its children. 542 */ 543 mcnt = ccnt; 544 for (o = 0; o < ocnt; o++) { 545 if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) { 546 for (c = 0; c < ccnt; c++) { 547 if (olddata->ex_secinfo[o].s_secinfo.sc_nfsnum == 548 curdata->ex_secinfo[c].s_secinfo.sc_nfsnum) 549 break; 550 } 551 552 /* 553 * This is the one. Add it. Decrement the reference count 554 * by 1 if the flavor is an explicitly shared flavor for 555 * the olddata export node. 556 */ 557 if (c == ccnt) { 558 srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]); 559 if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o])) 560 msec[mcnt].s_refcnt--; 561 mcnt++; 562 } 563 } 564 } 565 566 ASSERT(mcnt == tcnt); 567 /* 568 * Done. Update curdata. 569 * Free up the existing secinfo list in curdata and 570 * set the new value. 571 */ 572 if (ccnt > 0) 573 kmem_free(curdata->ex_secinfo, ccnt * sizeof (struct secinfo)); 574 curdata->ex_seccnt = tcnt; 575 curdata->ex_secinfo = msec; 576 } 577 578 /* 579 * When unsharing an old export node and the old node becomes a pseudo node, 580 * if there is more than 1 export reference to an old flavor (i.e. some of 581 * its children shared with this flavor), this flavor information needs to 582 * be transfered to the new shared node. 583 * 584 * This routine is used under the protection of exported_lock (RW_WRITER). 585 */ 586 void 587 srv_secinfo_exp2pseu(struct exportdata *curdata, struct exportdata *olddata) 588 { 589 int ocnt, o; /* sec count in transfer data - trandata */ 590 int tcnt, mcnt; /* total sec count after transfer */ 591 struct secinfo *msec; /* merged secinfo list */ 592 593 ASSERT(curdata->ex_flags & EX_PSEUDO); 594 ASSERT(curdata->ex_seccnt == 0); 595 596 ocnt = olddata->ex_seccnt; 597 598 /* 599 * If the olddata has flavors with more than 1 reference count, 600 * transfer the information to the curdata. 601 */ 602 tcnt = ocnt; 603 604 for (o = 0; o < ocnt; o++) { 605 if (SEC_REF_SELF(&olddata->ex_secinfo[o])) 606 tcnt--; 607 } 608 609 if (tcnt == 0) 610 return; /* no transfer to do */ 611 612 msec = kmem_zalloc(tcnt * sizeof (struct secinfo), KM_SLEEP); 613 614 mcnt = 0; 615 for (o = 0; o < ocnt; o++) { 616 if (! SEC_REF_SELF(&olddata->ex_secinfo[o])) { 617 618 /* 619 * Decrement the reference count by 1 if the flavor is 620 * an explicitly shared flavor for the olddata export node. 621 */ 622 srv_secinfo_copy(&olddata->ex_secinfo[o], &msec[mcnt]); 623 msec[mcnt].s_flags = M_RO; /* for a pseudo node */ 624 if (SEC_REF_EXPORTED(&olddata->ex_secinfo[o])) 625 msec[mcnt].s_refcnt--; 626 mcnt++; 627 } 628 } 629 630 ASSERT(mcnt == tcnt); 631 /* 632 * Done. Update curdata. 633 * Free up the existing secinfo list in curdata and 634 * set the new value. 635 */ 636 curdata->ex_seccnt = tcnt; 637 curdata->ex_secinfo = msec; 638 } 639 640 /* 641 * For NFS V4. 642 * Add or remove the newly exported or unexported security flavors of the 643 * given exportinfo from its ancestors upto the system root. 644 */ 645 int 646 srv_secinfo_treeclimb(struct exportinfo *exip, bool_t isadd) 647 { 648 vnode_t *dvp, *vp; 649 fid_t fid; 650 int error = 0; 651 int exportdir; 652 struct exportinfo *exi; 653 struct exportdata *exdata; 654 655 ASSERT(RW_WRITE_HELD(&exported_lock)); 656 657 exdata = &exip->exi_export; 658 if (exdata->ex_seccnt == 0) 659 return (0); 660 661 vp = exip->exi_vp; 662 VN_HOLD(vp); 663 exportdir = 1; 664 665 for (;;) { 666 667 bzero(&fid, sizeof (fid)); 668 fid.fid_len = MAXFIDSZ; 669 error = vop_fid_pseudo(vp, &fid); 670 if (error) 671 break; 672 673 if (! exportdir) { 674 675 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 676 677 if (exi != NULL) { 678 679 if (isadd) { 680 /* 681 * Add the new security flavors to the 682 * export entry of the current directory. 683 */ 684 srv_secinfo_add(&exi->exi_export, exdata); 685 } else { 686 /* 687 * Remove the unexported secinfo entries. 688 */ 689 srv_secinfo_remove(&exi->exi_export, exdata); 690 } 691 } 692 } 693 694 /* 695 * If at the root of the filesystem, need 696 * to traverse across the mountpoint 697 * and continue the climb on the mounted-on 698 * filesystem. 699 */ 700 if (vp->v_flag & VROOT) { 701 702 if (VN_CMP(vp, rootdir)) { 703 /* at system root */ 704 break; 705 } 706 707 vp = untraverse(vp); 708 exportdir = 0; 709 continue; 710 } 711 712 /* 713 * Now, do a ".." to find parent dir of vp. 714 */ 715 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED()); 716 717 if (error == ENOTDIR && exportdir) { 718 dvp = exip->exi_dvp; 719 ASSERT(dvp != NULL); 720 VN_HOLD(dvp); 721 error = 0; 722 } 723 724 if (error) 725 break; 726 727 exportdir = 0; 728 VN_RELE(vp); 729 vp = dvp; 730 } 731 732 VN_RELE(vp); 733 return (error); 734 } 735 736 void 737 export_link(struct exportinfo *exi) { 738 int exporthash; 739 740 exporthash = exptablehash(&exi->exi_fsid, &exi->exi_fid); 741 exi->exi_hash = exptable[exporthash]; 742 exptable[exporthash] = exi; 743 } 744 745 /* 746 * Initialization routine for export routines. Should only be called once. 747 */ 748 int 749 nfs_exportinit(void) 750 { 751 int error; 752 753 rw_init(&exported_lock, NULL, RW_DEFAULT, NULL); 754 755 /* 756 * Allocate the place holder for the public file handle, which 757 * is all zeroes. It is initially set to the root filesystem. 758 */ 759 exi_root = kmem_zalloc(sizeof (*exi_root), KM_SLEEP); 760 exi_public = exi_root; 761 762 exi_root->exi_export.ex_flags = EX_PUBLIC; 763 exi_root->exi_export.ex_pathlen = 2; /* length of "/" */ 764 exi_root->exi_export.ex_path = 765 kmem_alloc(exi_root->exi_export.ex_pathlen, KM_SLEEP); 766 exi_root->exi_export.ex_path[0] = '/'; 767 exi_root->exi_export.ex_path[1] = '\0'; 768 769 exi_root->exi_count = 1; 770 mutex_init(&exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL); 771 772 exi_root->exi_vp = rootdir; 773 exi_rootfid.fid_len = MAXFIDSZ; 774 error = vop_fid_pseudo(exi_root->exi_vp, &exi_rootfid); 775 if (error) { 776 mutex_destroy(&exi_root->exi_lock); 777 kmem_free(exi_root, sizeof (*exi_root)); 778 return (error); 779 } 780 781 /* setup the fhandle template */ 782 exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid; 783 exi_root->exi_fh.fh_xlen = exi_rootfid.fid_len; 784 bcopy(exi_rootfid.fid_data, exi_root->exi_fh.fh_xdata, 785 exi_rootfid.fid_len); 786 exi_root->exi_fh.fh_len = sizeof (exi_root->exi_fh.fh_data); 787 788 /* 789 * Publish the exportinfo in the hash table 790 */ 791 export_link(exi_root); 792 793 nfslog_init(); 794 795 return (0); 796 } 797 798 /* 799 * Finalization routine for export routines. Called to cleanup previoulsy 800 * initializtion work when the NFS server module could not be loaded correctly. 801 */ 802 void 803 nfs_exportfini(void) 804 { 805 /* 806 * Deallocate the place holder for the public file handle. 807 */ 808 srv_secinfo_list_free(exi_root->exi_export.ex_secinfo, 809 exi_root->exi_export.ex_seccnt); 810 mutex_destroy(&exi_root->exi_lock); 811 kmem_free(exi_root, sizeof (*exi_root)); 812 813 rw_destroy(&exported_lock); 814 } 815 816 /* 817 * Check if 2 gss mechanism identifiers are the same. 818 * 819 * return FALSE if not the same. 820 * return TRUE if the same. 821 */ 822 static bool_t 823 nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2) 824 { 825 if ((mech1->length == 0) && (mech2->length == 0)) 826 return (TRUE); 827 828 if (mech1->length != mech2->length) 829 return (FALSE); 830 831 return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0); 832 } 833 834 /* 835 * This routine is used by rpc to map rpc security number 836 * to nfs specific security flavor number. 837 * 838 * The gss callback prototype is 839 * callback(struct svc_req *, gss_cred_id_t *, gss_ctx_id_t *, 840 * rpc_gss_lock_t *, void **), 841 * since nfs does not use the gss_cred_id_t/gss_ctx_id_t arguments 842 * we cast them to void. 843 */ 844 /*ARGSUSED*/ 845 bool_t 846 rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context, 847 rpc_gss_lock_t *lock, void **cookie) 848 { 849 int i, j; 850 rpc_gss_rawcred_t *raw_cred; 851 struct exportinfo *exi; 852 853 /* 854 * We don't deal with delegated credentials. 855 */ 856 if (deleg != GSS_C_NO_CREDENTIAL) 857 return (FALSE); 858 859 raw_cred = lock->raw_cred; 860 *cookie = NULL; 861 862 rw_enter(&exported_lock, RW_READER); 863 for (i = 0; i < EXPTABLESIZE; i++) { 864 exi = exptable[i]; 865 while (exi) { 866 if (exi->exi_export.ex_seccnt > 0) { 867 struct secinfo *secp; 868 869 secp = exi->exi_export.ex_secinfo; 870 for (j = 0; j < exi->exi_export.ex_seccnt; j++) { 871 /* 872 * If there is a map of the triplet 873 * (mechanism, service, qop) between raw_cred and 874 * the exported flavor, get the psudo flavor number. 875 * Also qop should not be NULL, it should be "default" 876 * or something else. 877 */ 878 if ((secp[j].s_secinfo.sc_rpcnum == RPCSEC_GSS) && 879 (nfs_mech_equal(secp[j].s_secinfo.sc_gss_mech_type, 880 raw_cred->mechanism)) && 881 (secp[j].s_secinfo.sc_service == raw_cred->service) && 882 (raw_cred->qop == secp[j].s_secinfo.sc_qop)) { 883 *cookie = (void *)(uintptr_t) 884 secp[j].s_secinfo.sc_nfsnum; 885 goto done; 886 } 887 } 888 } 889 exi = exi->exi_hash; 890 } 891 } 892 done: 893 rw_exit(&exported_lock); 894 895 /* 896 * If no nfs pseudo number mapping can be found in the export 897 * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may 898 * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC). 899 * 900 * For example: 901 * server first shares with krb5i; 902 * client mounts with krb5i; 903 * server re-shares with krb5p; 904 * client tries with krb5i, but no mapping can be found; 905 * rpcsec_gss module calls this routine to do the mapping, 906 * if this routine fails, request is rejected from 907 * the rpc layer. 908 * What we need is to let the nfs layer rejects the request. 909 * For V4, we can reject with NFS4ERR_WRONGSEC and the client 910 * may recover from it by getting the new flavor via SECINFO. 911 * 912 * nfs pseudo number for RPCSEC_GSS mapping (see nfssec.conf) 913 * is owned by IANA (see RFC 2623). 914 * 915 * XXX NFS_FLAVOR_NOMAP is defined in Solaris to work around 916 * the implementation issue. This number should not overlap with 917 * any new IANA defined pseudo flavor numbers. 918 */ 919 if (*cookie == NULL) 920 *cookie = (void *)NFS_FLAVOR_NOMAP; 921 922 lock->locked = TRUE; 923 924 return (TRUE); 925 } 926 927 928 /* 929 * Exportfs system call; credentials should be checked before 930 * calling this function. 931 */ 932 int 933 exportfs(struct exportfs_args *args, model_t model, cred_t *cr) 934 { 935 vnode_t *vp; 936 vnode_t *dvp; 937 struct exportdata *kex; 938 struct exportinfo *exi; 939 struct exportinfo *ex, *prev; 940 fid_t fid; 941 fsid_t fsid; 942 int error; 943 size_t allocsize; 944 struct secinfo *sp; 945 struct secinfo *exs; 946 rpc_gss_callback_t cb; 947 char *pathbuf; 948 char *log_buffer; 949 char *tagbuf; 950 int callback; 951 int allocd_seccnt; 952 STRUCT_HANDLE(exportfs_args, uap); 953 STRUCT_DECL(exportdata, uexi); 954 int i; 955 956 STRUCT_SET_HANDLE(uap, model, args); 957 958 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE, 959 FOLLOW, &dvp, &vp); 960 if (error == EINVAL) { 961 /* 962 * if fname resolves to / we get EINVAL error 963 * since we wanted the parent vnode. Try again 964 * with NULL dvp. 965 */ 966 error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE, 967 FOLLOW, NULL, &vp); 968 dvp = NULL; 969 } 970 if (!error && vp == NULL) { 971 /* 972 * Last component of fname not found 973 */ 974 if (dvp != NULL) { 975 VN_RELE(dvp); 976 } 977 error = ENOENT; 978 } 979 if (error) 980 return (error); 981 982 /* 983 * 'vp' may be an AUTOFS node, so we perform a 984 * VOP_ACCESS() to trigger the mount of the 985 * intended filesystem, so we can share the intended 986 * filesystem instead of the AUTOFS filesystem. 987 */ 988 (void) VOP_ACCESS(vp, 0, 0, cr); 989 990 /* 991 * We're interested in the top most filesystem. 992 * This is specially important when uap->dname is a trigger 993 * AUTOFS node, since we're really interested in sharing the 994 * filesystem AUTOFS mounted as result of the VOP_ACCESS() 995 * call not the AUTOFS node itself. 996 */ 997 if (vn_mountedvfs(vp) != NULL) { 998 if (error = traverse(&vp)) { 999 VN_RELE(vp); 1000 if (dvp != NULL) 1001 VN_RELE(dvp); 1002 return (error); 1003 } 1004 } 1005 1006 /* 1007 * Get the vfs id 1008 */ 1009 bzero(&fid, sizeof (fid)); 1010 fid.fid_len = MAXFIDSZ; 1011 error = VOP_FID(vp, &fid); 1012 fsid = vp->v_vfsp->vfs_fsid; 1013 if (error) { 1014 VN_RELE(vp); 1015 if (dvp != NULL) 1016 VN_RELE(dvp); 1017 /* 1018 * If VOP_FID returns ENOSPC then the fid supplied 1019 * is too small. For now we simply return EREMOTE. 1020 */ 1021 if (error == ENOSPC) 1022 error = EREMOTE; 1023 return (error); 1024 } 1025 1026 if (STRUCT_FGETP(uap, uex) == NULL) { 1027 error = unexport(&fsid, &fid, vp); 1028 VN_RELE(vp); 1029 if (dvp != NULL) 1030 VN_RELE(dvp); 1031 return (error); 1032 } 1033 exi = kmem_zalloc(sizeof (*exi), KM_SLEEP); 1034 exi->exi_fsid = fsid; 1035 exi->exi_fid = fid; 1036 exi->exi_vp = vp; 1037 exi->exi_count = 1; 1038 exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag & 1039 VSW_VOLATILEDEV) ? 1 : 0; 1040 mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL); 1041 exi->exi_dvp = dvp; 1042 1043 /* 1044 * Initialize auth cache lock 1045 */ 1046 rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL); 1047 1048 /* 1049 * Build up the template fhandle 1050 */ 1051 exi->exi_fh.fh_fsid = fsid; 1052 if (exi->exi_fid.fid_len > sizeof (exi->exi_fh.fh_xdata)) { 1053 error = EREMOTE; 1054 goto out1; 1055 } 1056 exi->exi_fh.fh_xlen = exi->exi_fid.fid_len; 1057 bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata, 1058 exi->exi_fid.fid_len); 1059 1060 exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data); 1061 1062 kex = &exi->exi_export; 1063 1064 /* 1065 * Load in everything, and do sanity checking 1066 */ 1067 STRUCT_INIT(uexi, model); 1068 if (copyin(STRUCT_FGETP(uap, uex), STRUCT_BUF(uexi), 1069 STRUCT_SIZE(uexi))) { 1070 error = EFAULT; 1071 goto out1; 1072 } 1073 1074 kex->ex_version = STRUCT_FGET(uexi, ex_version); 1075 if (kex->ex_version != EX_CURRENT_VERSION) { 1076 error = EINVAL; 1077 cmn_err(CE_WARN, 1078 "NFS: exportfs requires export struct version 2 - got %d\n", 1079 kex->ex_version); 1080 goto out1; 1081 } 1082 1083 /* 1084 * Must have at least one security entry 1085 */ 1086 kex->ex_seccnt = STRUCT_FGET(uexi, ex_seccnt); 1087 if (kex->ex_seccnt < 1) { 1088 error = EINVAL; 1089 goto out1; 1090 } 1091 1092 kex->ex_path = STRUCT_FGETP(uexi, ex_path); 1093 kex->ex_pathlen = STRUCT_FGET(uexi, ex_pathlen); 1094 kex->ex_flags = STRUCT_FGET(uexi, ex_flags); 1095 kex->ex_anon = STRUCT_FGET(uexi, ex_anon); 1096 kex->ex_secinfo = STRUCT_FGETP(uexi, ex_secinfo); 1097 kex->ex_index = STRUCT_FGETP(uexi, ex_index); 1098 kex->ex_log_buffer = STRUCT_FGETP(uexi, ex_log_buffer); 1099 kex->ex_log_bufferlen = STRUCT_FGET(uexi, ex_log_bufferlen); 1100 kex->ex_tag = STRUCT_FGETP(uexi, ex_tag); 1101 kex->ex_taglen = STRUCT_FGET(uexi, ex_taglen); 1102 1103 /* 1104 * Copy the exported pathname into 1105 * an appropriately sized buffer. 1106 */ 1107 pathbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1108 if (copyinstr(kex->ex_path, pathbuf, MAXPATHLEN, &kex->ex_pathlen)) { 1109 kmem_free(pathbuf, MAXPATHLEN); 1110 error = EFAULT; 1111 goto out1; 1112 } 1113 kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP); 1114 bcopy(pathbuf, kex->ex_path, kex->ex_pathlen); 1115 kex->ex_path[kex->ex_pathlen] = '\0'; 1116 kmem_free(pathbuf, MAXPATHLEN); 1117 1118 /* 1119 * Get the path to the logging buffer and the tag 1120 */ 1121 if (kex->ex_flags & EX_LOG) { 1122 log_buffer = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1123 if (copyinstr(kex->ex_log_buffer, log_buffer, MAXPATHLEN, 1124 &kex->ex_log_bufferlen)) { 1125 kmem_free(log_buffer, MAXPATHLEN); 1126 error = EFAULT; 1127 goto out2; 1128 } 1129 kex->ex_log_buffer = 1130 kmem_alloc(kex->ex_log_bufferlen + 1, KM_SLEEP); 1131 bcopy(log_buffer, kex->ex_log_buffer, kex->ex_log_bufferlen); 1132 kex->ex_log_buffer[kex->ex_log_bufferlen] = '\0'; 1133 kmem_free(log_buffer, MAXPATHLEN); 1134 1135 tagbuf = kmem_alloc(MAXPATHLEN, KM_SLEEP); 1136 if (copyinstr(kex->ex_tag, tagbuf, MAXPATHLEN, 1137 &kex->ex_taglen)) { 1138 kmem_free(tagbuf, MAXPATHLEN); 1139 error = EFAULT; 1140 goto out3; 1141 } 1142 kex->ex_tag = kmem_alloc(kex->ex_taglen + 1, KM_SLEEP); 1143 bcopy(tagbuf, kex->ex_tag, kex->ex_taglen); 1144 kex->ex_tag[kex->ex_taglen] = '\0'; 1145 kmem_free(tagbuf, MAXPATHLEN); 1146 } 1147 1148 /* 1149 * Load the security information for each flavor 1150 */ 1151 allocsize = kex->ex_seccnt * SIZEOF_STRUCT(secinfo, model); 1152 sp = kmem_zalloc(allocsize, KM_SLEEP); 1153 if (copyin(kex->ex_secinfo, sp, allocsize)) { 1154 kmem_free(sp, allocsize); 1155 error = EFAULT; 1156 goto out4; 1157 } 1158 1159 /* 1160 * All of these nested structures need to be converted to 1161 * the kernel native format. 1162 */ 1163 if (model != DATAMODEL_NATIVE) { 1164 size_t allocsize2; 1165 struct secinfo *sp2; 1166 1167 allocsize2 = kex->ex_seccnt * sizeof (struct secinfo); 1168 sp2 = kmem_zalloc(allocsize2, KM_SLEEP); 1169 1170 for (i = 0; i < kex->ex_seccnt; i++) { 1171 STRUCT_HANDLE(secinfo, usi); 1172 1173 STRUCT_SET_HANDLE(usi, model, 1174 (struct secinfo *)((caddr_t)sp + 1175 (i * SIZEOF_STRUCT(secinfo, model)))); 1176 bcopy(STRUCT_FGET(usi, s_secinfo.sc_name), 1177 sp2[i].s_secinfo.sc_name, MAX_NAME_LEN); 1178 sp2[i].s_secinfo.sc_nfsnum = 1179 STRUCT_FGET(usi, s_secinfo.sc_nfsnum); 1180 sp2[i].s_secinfo.sc_rpcnum = 1181 STRUCT_FGET(usi, s_secinfo.sc_rpcnum); 1182 bcopy(STRUCT_FGET(usi, s_secinfo.sc_gss_mech), 1183 sp2[i].s_secinfo.sc_gss_mech, MAX_NAME_LEN); 1184 sp2[i].s_secinfo.sc_gss_mech_type = 1185 STRUCT_FGETP(usi, s_secinfo.sc_gss_mech_type); 1186 sp2[i].s_secinfo.sc_qop = 1187 STRUCT_FGET(usi, s_secinfo.sc_qop); 1188 sp2[i].s_secinfo.sc_service = 1189 STRUCT_FGET(usi, s_secinfo.sc_service); 1190 1191 sp2[i].s_flags = STRUCT_FGET(usi, s_flags); 1192 sp2[i].s_window = STRUCT_FGET(usi, s_window); 1193 sp2[i].s_rootcnt = STRUCT_FGET(usi, s_rootcnt); 1194 sp2[i].s_rootnames = STRUCT_FGETP(usi, s_rootnames); 1195 } 1196 kmem_free(sp, allocsize); 1197 sp = sp2; 1198 allocsize = allocsize2; 1199 } 1200 1201 kex->ex_secinfo = sp; 1202 1203 /* 1204 * And now copy rootnames for each individual secinfo. 1205 */ 1206 callback = 0; 1207 allocd_seccnt = 0; 1208 while (allocd_seccnt < kex->ex_seccnt) { 1209 1210 exs = &sp[allocd_seccnt]; 1211 if (exs->s_rootcnt > 0) { 1212 if (!sec_svc_loadrootnames(exs->s_secinfo.sc_rpcnum, 1213 exs->s_rootcnt, &exs->s_rootnames, model)) { 1214 error = EFAULT; 1215 goto out5; 1216 } 1217 } 1218 1219 if (exs->s_secinfo.sc_rpcnum == RPCSEC_GSS) { 1220 rpc_gss_OID mech_tmp; 1221 STRUCT_DECL(rpc_gss_OID_s, umech_tmp); 1222 caddr_t elements_tmp; 1223 1224 /* Copyin mechanism type */ 1225 STRUCT_INIT(umech_tmp, model); 1226 mech_tmp = kmem_alloc(sizeof (*mech_tmp), KM_SLEEP); 1227 if (copyin(exs->s_secinfo.sc_gss_mech_type, 1228 STRUCT_BUF(umech_tmp), STRUCT_SIZE(umech_tmp))) { 1229 kmem_free(mech_tmp, sizeof (*mech_tmp)); 1230 error = EFAULT; 1231 goto out5; 1232 } 1233 mech_tmp->length = STRUCT_FGET(umech_tmp, length); 1234 mech_tmp->elements = STRUCT_FGETP(umech_tmp, elements); 1235 1236 elements_tmp = kmem_alloc(mech_tmp->length, KM_SLEEP); 1237 if (copyin(mech_tmp->elements, elements_tmp, 1238 mech_tmp->length)) { 1239 kmem_free(elements_tmp, mech_tmp->length); 1240 kmem_free(mech_tmp, sizeof (*mech_tmp)); 1241 error = EFAULT; 1242 goto out5; 1243 } 1244 mech_tmp->elements = elements_tmp; 1245 exs->s_secinfo.sc_gss_mech_type = mech_tmp; 1246 allocd_seccnt++; 1247 1248 callback = 1; 1249 } else 1250 allocd_seccnt++; 1251 } 1252 1253 /* 1254 * Init the secinfo reference count and mark these flavors 1255 * explicitly exported flavors. 1256 */ 1257 for (i = 0; i < kex->ex_seccnt; i++) { 1258 kex->ex_secinfo[i].s_flags |= M_4SEC_EXPORTED; 1259 kex->ex_secinfo[i].s_refcnt++; /* 1 reference count */ 1260 } 1261 1262 /* 1263 * Set up rpcsec_gss callback routine entry if any. 1264 */ 1265 if (callback) { 1266 cb.callback = rfs_gsscallback; 1267 cb.program = NFS_ACL_PROGRAM; 1268 for (cb.version = NFS_ACL_VERSMIN; 1269 cb.version <= NFS_ACL_VERSMAX; cb.version++) { 1270 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK, 1271 (void *)&cb); 1272 } 1273 1274 cb.program = NFS_PROGRAM; 1275 for (cb.version = NFS_VERSMIN; 1276 cb.version <= NFS_VERSMAX; cb.version++) { 1277 (void) sec_svc_control(RPC_SVC_SET_GSS_CALLBACK, 1278 (void *)&cb); 1279 } 1280 } 1281 1282 /* 1283 * Check the index flag. Do this here to avoid holding the 1284 * lock while dealing with the index option (as we do with 1285 * the public option). 1286 */ 1287 if (kex->ex_flags & EX_INDEX) { 1288 if (!kex->ex_index) { /* sanity check */ 1289 error = EINVAL; 1290 goto out5; 1291 } 1292 if (error = loadindex(kex)) 1293 goto out5; 1294 } 1295 1296 if (kex->ex_flags & EX_LOG) { 1297 if (error = nfslog_setup(exi)) 1298 goto out6; 1299 } 1300 1301 /* 1302 * Insert the new entry at the front of the export list 1303 */ 1304 rw_enter(&exported_lock, RW_WRITER); 1305 1306 export_link(exi); 1307 1308 /* 1309 * Check the rest of the list for an old entry for the fs. 1310 * If one is found then unlink it, wait until this is the 1311 * only reference and then free it. 1312 */ 1313 prev = exi; 1314 for (ex = prev->exi_hash; ex != NULL; prev = ex, ex = ex->exi_hash) { 1315 if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) { 1316 prev->exi_hash = ex->exi_hash; 1317 break; 1318 } 1319 } 1320 1321 /* 1322 * If the public filehandle is pointing at the 1323 * old entry, then point it back at the root. 1324 */ 1325 if (ex != NULL && ex == exi_public) 1326 exi_public = exi_root; 1327 1328 /* 1329 * If the public flag is on, make the global exi_public 1330 * point to this entry and turn off the public bit so that 1331 * we can distinguish it from the place holder export. 1332 */ 1333 if (kex->ex_flags & EX_PUBLIC) { 1334 exi_public = exi; 1335 kex->ex_flags &= ~EX_PUBLIC; 1336 } 1337 1338 #ifdef VOLATILE_FH_TEST 1339 /* 1340 * Set up the volatile_id value if volatile on share. 1341 * The list of volatile renamed filehandles is always destroyed, 1342 * if the fs was reshared. 1343 */ 1344 if (kex->ex_flags & EX_VOLFH) 1345 exi->exi_volatile_id = gethrestime_sec(); 1346 1347 mutex_init(&exi->exi_vol_rename_lock, NULL, MUTEX_DEFAULT, NULL); 1348 #endif /* VOLATILE_FH_TEST */ 1349 1350 /* 1351 * If this is a new export, then climb up 1352 * the tree and check if any pseudo exports 1353 * need to be created to provide a path for 1354 * NFS v4 clients. 1355 */ 1356 if (ex == NULL) 1357 error = treeclimb_export(exi); 1358 1359 if (!error) 1360 error = srv_secinfo_treeclimb(exi, TRUE); 1361 1362 /* 1363 * If re-sharing an old export entry, update the secinfo data 1364 * depending on if the old entry is a pseudo node or not. 1365 */ 1366 if (!error && ex != NULL) { 1367 if (PSEUDO(ex)) { 1368 srv_secinfo_add(&exi->exi_export, &ex->exi_export); 1369 } else { 1370 srv_secinfo_exp2exp(&exi->exi_export, &ex->exi_export); 1371 error = srv_secinfo_treeclimb(ex, FALSE); 1372 } 1373 } 1374 1375 if (error) 1376 goto out7; 1377 1378 /* 1379 * If it's a re-export and the old entry has a visible list, 1380 * then transfer its visible list to the new export. 1381 * Note: only VROOT node may have a visible list either 1382 * it is a PSEUDO node or a real export node. 1383 */ 1384 if (ex != NULL && (ex->exi_visible != NULL)) { 1385 exi->exi_visible = ex->exi_visible; 1386 ex->exi_visible = NULL; 1387 } 1388 1389 rw_exit(&exported_lock); 1390 1391 if (exi_public == exi || kex->ex_flags & EX_LOG) { 1392 /* 1393 * Log share operation to this buffer only. 1394 */ 1395 nfslog_share_record(exi, cr); 1396 } 1397 1398 if (ex != NULL) 1399 exi_rele(ex); 1400 1401 return (0); 1402 1403 out7: 1404 /* 1405 * Cleaning up the tree. Assuming *treeclimb* routines 1406 * will fail at the same place in the tree. 1407 */ 1408 (void) treeclimb_unexport(exi); 1409 (void) srv_secinfo_treeclimb(exi, FALSE); 1410 1411 /* 1412 * Unlink and re-link the new and old export in exptable. 1413 */ 1414 (void) export_unlink(&exi->exi_fsid, &exi->exi_fid, exi->exi_vp, NULL); 1415 if (ex != NULL) 1416 export_link(ex); 1417 1418 rw_exit(&exported_lock); 1419 out6: 1420 if (kex->ex_flags & EX_INDEX) 1421 kmem_free(kex->ex_index, strlen(kex->ex_index) + 1); 1422 out5: 1423 /* free partially completed allocation */ 1424 while (--allocd_seccnt >= 0) { 1425 exs = &kex->ex_secinfo[allocd_seccnt]; 1426 srv_secinfo_entry_free(exs); 1427 } 1428 1429 if (kex->ex_secinfo) { 1430 kmem_free(kex->ex_secinfo, 1431 kex->ex_seccnt * sizeof (struct secinfo)); 1432 } 1433 1434 out4: 1435 if ((kex->ex_flags & EX_LOG) && kex->ex_tag != NULL) 1436 kmem_free(kex->ex_tag, kex->ex_taglen + 1); 1437 out3: 1438 if ((kex->ex_flags & EX_LOG) && kex->ex_log_buffer != NULL) 1439 kmem_free(kex->ex_log_buffer, kex->ex_log_bufferlen + 1); 1440 out2: 1441 kmem_free(kex->ex_path, kex->ex_pathlen + 1); 1442 out1: 1443 VN_RELE(vp); 1444 if (dvp != NULL) 1445 VN_RELE(dvp); 1446 mutex_destroy(&exi->exi_lock); 1447 rw_destroy(&exi->exi_cache_lock); 1448 kmem_free(exi, sizeof (*exi)); 1449 return (error); 1450 } 1451 1452 /* 1453 * Remove the exportinfo from the export list 1454 */ 1455 int 1456 export_unlink(fsid_t *fsid, fid_t *fid, vnode_t *vp, struct exportinfo **exip) 1457 { 1458 struct exportinfo **tail; 1459 1460 ASSERT(RW_WRITE_HELD(&exported_lock)); 1461 1462 tail = &exptable[exptablehash(fsid, fid)]; 1463 while (*tail != NULL) { 1464 if (exportmatch(*tail, fsid, fid)) { 1465 /* 1466 * If vp is given, check if vp is the 1467 * same vnode as the exported node. 1468 * 1469 * Since VOP_FID of a lofs node returns the 1470 * fid of its real node (ufs), the exported 1471 * node for lofs and (pseudo) ufs may have 1472 * the same fsid and fid. 1473 */ 1474 if (vp == NULL || vp == (*tail)->exi_vp) { 1475 1476 if (exip != NULL) 1477 *exip = *tail; 1478 *tail = (*tail)->exi_hash; 1479 1480 return (0); 1481 } 1482 } 1483 tail = &(*tail)->exi_hash; 1484 } 1485 1486 return (EINVAL); 1487 } 1488 1489 /* 1490 * Unexport an exported filesystem 1491 */ 1492 int 1493 unexport(fsid_t *fsid, fid_t *fid, vnode_t *vp) 1494 { 1495 struct exportinfo *exi = NULL; 1496 int error; 1497 1498 rw_enter(&exported_lock, RW_WRITER); 1499 1500 error = export_unlink(fsid, fid, vp, &exi); 1501 1502 if (error) { 1503 rw_exit(&exported_lock); 1504 return (error); 1505 } 1506 1507 /* pseudo node is not a real exported filesystem */ 1508 if (PSEUDO(exi)) { 1509 /* 1510 * Put the pseudo node back into the export table 1511 * before erroring out. 1512 */ 1513 export_link(exi); 1514 rw_exit(&exported_lock); 1515 return (EINVAL); 1516 } 1517 1518 /* 1519 * If there's a visible list, then need to leave 1520 * a pseudo export here to retain the visible list 1521 * for paths to exports below. 1522 */ 1523 if (exi->exi_visible) { 1524 error = pseudo_exportfs(exi->exi_vp, exi->exi_visible, 1525 &exi->exi_export); 1526 if (error) 1527 goto done; 1528 1529 exi->exi_visible = NULL; 1530 } else { 1531 error = treeclimb_unexport(exi); 1532 if (error) 1533 goto done; 1534 } 1535 1536 error = srv_secinfo_treeclimb(exi, FALSE); 1537 if (error) 1538 goto done; 1539 1540 rw_exit(&exported_lock); 1541 1542 /* 1543 * Need to call into the NFSv4 server and release all data 1544 * held on this particular export. This is important since 1545 * the v4 server may be holding file locks or vnodes under 1546 * this export. 1547 */ 1548 rfs4_clean_state_exi(exi); 1549 1550 /* 1551 * Notify the lock manager that the filesystem is being 1552 * unexported. 1553 */ 1554 lm_unexport(exi); 1555 1556 /* 1557 * If this was a public export, restore 1558 * the public filehandle to the root. 1559 */ 1560 if (exi == exi_public) { 1561 exi_public = exi_root; 1562 1563 nfslog_share_record(exi_public, CRED()); 1564 } 1565 1566 if (exi->exi_export.ex_flags & EX_LOG) { 1567 nfslog_unshare_record(exi, CRED()); 1568 } 1569 1570 exi_rele(exi); 1571 return (error); 1572 1573 done: 1574 rw_exit(&exported_lock); 1575 exi_rele(exi); 1576 return (error); 1577 } 1578 1579 /* 1580 * Get file handle system call. 1581 * Takes file name and returns a file handle for it. 1582 * Credentials must be verified before calling. 1583 */ 1584 int 1585 nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr) 1586 { 1587 fhandle_t fh; 1588 vnode_t *vp; 1589 vnode_t *dvp; 1590 struct exportinfo *exi; 1591 int error; 1592 STRUCT_HANDLE(nfs_getfh_args, uap); 1593 1594 #ifdef lint 1595 model = model; /* STRUCT macros don't always use it */ 1596 #endif 1597 1598 STRUCT_SET_HANDLE(uap, model, args); 1599 1600 error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE, 1601 FOLLOW, &dvp, &vp); 1602 if (error == EINVAL) { 1603 /* 1604 * if fname resolves to / we get EINVAL error 1605 * since we wanted the parent vnode. Try again 1606 * with NULL dvp. 1607 */ 1608 error = lookupname(STRUCT_FGETP(uap, fname), UIO_USERSPACE, 1609 FOLLOW, NULL, &vp); 1610 dvp = NULL; 1611 } 1612 if (!error && vp == NULL) { 1613 /* 1614 * Last component of fname not found 1615 */ 1616 if (dvp != NULL) { 1617 VN_RELE(dvp); 1618 } 1619 error = ENOENT; 1620 } 1621 if (error) 1622 return (error); 1623 1624 /* 1625 * 'vp' may be an AUTOFS node, so we perform a 1626 * VOP_ACCESS() to trigger the mount of the 1627 * intended filesystem, so we can share the intended 1628 * filesystem instead of the AUTOFS filesystem. 1629 */ 1630 (void) VOP_ACCESS(vp, 0, 0, cr); 1631 1632 /* 1633 * We're interested in the top most filesystem. 1634 * This is specially important when uap->dname is a trigger 1635 * AUTOFS node, since we're really interested in sharing the 1636 * filesystem AUTOFS mounted as result of the VOP_ACCESS() 1637 * call not the AUTOFS node itself. 1638 */ 1639 if (vn_mountedvfs(vp) != NULL) { 1640 if (error = traverse(&vp)) { 1641 VN_RELE(vp); 1642 if (dvp != NULL) 1643 VN_RELE(dvp); 1644 return (error); 1645 } 1646 } 1647 1648 exi = nfs_vptoexi(dvp, vp, cr, NULL, &error, FALSE); 1649 if (!error) { 1650 error = makefh(&fh, vp, exi); 1651 if (!error && exi->exi_export.ex_flags & EX_LOG) { 1652 nfslog_getfh(exi, &fh, STRUCT_FGETP(uap, fname), 1653 UIO_USERSPACE, cr); 1654 } 1655 exi_rele(exi); 1656 if (!error) { 1657 if (copyout(&fh, STRUCT_FGETP(uap, fhp), sizeof (fh))) 1658 error = EFAULT; 1659 } 1660 } 1661 VN_RELE(vp); 1662 if (dvp != NULL) { 1663 VN_RELE(dvp); 1664 } 1665 return (error); 1666 } 1667 1668 /* 1669 * Strategy: if vp is in the export list, then 1670 * return the associated file handle. Otherwise, ".." 1671 * once up the vp and try again, until the root of the 1672 * filesystem is reached. 1673 */ 1674 struct exportinfo * 1675 nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk, 1676 int *err, bool_t v4srv) 1677 { 1678 fid_t fid; 1679 int error; 1680 struct exportinfo *exi; 1681 1682 ASSERT(vp); 1683 VN_HOLD(vp); 1684 if (dvp != NULL) { 1685 VN_HOLD(dvp); 1686 } 1687 if (walk != NULL) 1688 *walk = 0; 1689 1690 for (;;) { 1691 bzero(&fid, sizeof (fid)); 1692 fid.fid_len = MAXFIDSZ; 1693 error = vop_fid_pseudo(vp, &fid); 1694 if (error) { 1695 /* 1696 * If vop_fid_pseudo returns ENOSPC then the fid 1697 * supplied is too small. For now we simply 1698 * return EREMOTE. 1699 */ 1700 if (error == ENOSPC) 1701 error = EREMOTE; 1702 break; 1703 } 1704 1705 if (v4srv) 1706 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 1707 else 1708 exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid); 1709 1710 if (exi != NULL) { 1711 /* 1712 * Found the export info 1713 */ 1714 break; 1715 } 1716 1717 /* 1718 * We have just failed finding a matching export. 1719 * If we're at the root of this filesystem, then 1720 * it's time to stop (with failure). 1721 */ 1722 if (vp->v_flag & VROOT) { 1723 error = EINVAL; 1724 break; 1725 } 1726 1727 if (walk != NULL) 1728 (*walk)++; 1729 1730 /* 1731 * Now, do a ".." up vp. If dvp is supplied, use it, 1732 * otherwise, look it up. 1733 */ 1734 if (dvp == NULL) { 1735 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr); 1736 if (error) 1737 break; 1738 } 1739 VN_RELE(vp); 1740 vp = dvp; 1741 dvp = NULL; 1742 } 1743 VN_RELE(vp); 1744 if (dvp != NULL) { 1745 VN_RELE(dvp); 1746 } 1747 if (error != 0) { 1748 if (err != NULL) 1749 *err = error; 1750 return (NULL); 1751 } 1752 return (exi); 1753 } 1754 1755 bool_t 1756 chk_clnt_sec(struct exportinfo *exi, struct svc_req *req) 1757 { 1758 int i, nfsflavor; 1759 struct secinfo *sp; 1760 bool_t sec_found = FALSE; 1761 1762 /* 1763 * Get the nfs flavor number from xprt. 1764 */ 1765 nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie; 1766 1767 sp = exi->exi_export.ex_secinfo; 1768 for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 1769 if (nfsflavor == sp[i].s_secinfo.sc_nfsnum) { 1770 sec_found = TRUE; 1771 break; 1772 } 1773 } 1774 return (sec_found); 1775 } 1776 1777 /* 1778 * Make an fhandle from a vnode 1779 */ 1780 int 1781 makefh(fhandle_t *fh, vnode_t *vp, struct exportinfo *exi) 1782 { 1783 int error; 1784 1785 *fh = exi->exi_fh; /* struct copy */ 1786 1787 error = VOP_FID(vp, (fid_t *)&fh->fh_len); 1788 if (error) { 1789 /* 1790 * Should be something other than EREMOTE 1791 */ 1792 return (EREMOTE); 1793 } 1794 return (0); 1795 } 1796 1797 /* 1798 * This routine makes an overloaded V2 fhandle which contains 1799 * sec modes. 1800 * 1801 * Note that the first four octets contain the length octet, 1802 * the status octet, and two padded octets to make them XDR 1803 * four-octet aligned. 1804 * 1805 * 1 2 3 4 32 1806 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ 1807 * | l | s | | | sec_1 |...| sec_n |...| | 1808 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ 1809 * 1810 * where 1811 * 1812 * the status octet s indicates whether there are more security 1813 * flavors (1 means yes, 0 means no) that require the client to 1814 * perform another 0x81 LOOKUP to get them, 1815 * 1816 * the length octet l is the length describing the number of 1817 * valid octets that follow. (l = 4 * n, where n is the number 1818 * of security flavors sent in the current overloaded filehandle.) 1819 */ 1820 int 1821 makefh_ol(fhandle_t *fh, struct exportinfo *exi, uint_t sec_index) 1822 { 1823 static int max_cnt = (NFS_FHSIZE/sizeof (int)) - 1; 1824 int totalcnt, i, *ipt, cnt; 1825 char *c; 1826 1827 if (fh == (fhandle_t *)NULL || 1828 exi == (struct exportinfo *)NULL || 1829 sec_index > exi->exi_export.ex_seccnt || 1830 sec_index < 1) 1831 return (EREMOTE); 1832 1833 totalcnt = exi->exi_export.ex_seccnt-sec_index+1; 1834 cnt = totalcnt > max_cnt? max_cnt : totalcnt; 1835 1836 c = (char *)fh; 1837 /* 1838 * Encode the length octet representing the number of 1839 * security flavors (in bytes) in this overloaded fh. 1840 */ 1841 *c = cnt * sizeof (int); 1842 1843 /* 1844 * Encode the status octet that indicates whether there 1845 * are more security flavors the client needs to get. 1846 */ 1847 *(c+1) = totalcnt > max_cnt; 1848 1849 /* 1850 * put security flavors in the overloaded fh 1851 */ 1852 ipt = (int *)(c + sizeof (int32_t)); 1853 for (i = 0; i < cnt; i++) { 1854 *ipt++ = htonl(exi->exi_export.ex_secinfo[i+sec_index-1]. 1855 s_secinfo.sc_nfsnum); 1856 } 1857 return (0); 1858 } 1859 1860 /* 1861 * Make an nfs_fh3 from a vnode 1862 */ 1863 int 1864 makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi) 1865 { 1866 int error; 1867 1868 fh->fh3_length = sizeof (fh->fh3_u.nfs_fh3_i); 1869 fh->fh3_u.nfs_fh3_i.fh3_i = exi->exi_fh; /* struct copy */ 1870 1871 error = VOP_FID(vp, (fid_t *)&fh->fh3_len); 1872 1873 if (error) { 1874 /* 1875 * Should be something other than EREMOTE 1876 */ 1877 return (EREMOTE); 1878 } 1879 return (0); 1880 } 1881 1882 /* 1883 * This routine makes an overloaded V3 fhandle which contains 1884 * sec modes. 1885 * 1886 * 1 4 1887 * +--+--+--+--+ 1888 * | len | 1889 * +--+--+--+--+ 1890 * up to 64 1891 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ 1892 * |s | | | | sec_1 | sec_2 | ... | sec_n | 1893 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ 1894 * 1895 * len = 4 * (n+1), where n is the number of security flavors 1896 * sent in the current overloaded filehandle. 1897 * 1898 * the status octet s indicates whether there are more security 1899 * mechanisms (1 means yes, 0 means no) that require the client 1900 * to perform another 0x81 LOOKUP to get them. 1901 * 1902 * Three octets are padded after the status octet. 1903 */ 1904 int 1905 makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index) 1906 { 1907 static int max_cnt = NFS3_FHSIZE/sizeof (int) - 1; 1908 int totalcnt, cnt, *ipt, i; 1909 char *c; 1910 1911 if (fh == (nfs_fh3 *)NULL || 1912 exi == (struct exportinfo *)NULL || 1913 sec_index > exi->exi_export.ex_seccnt || 1914 sec_index < 1) { 1915 return (EREMOTE); 1916 } 1917 1918 totalcnt = exi->exi_export.ex_seccnt-sec_index+1; 1919 cnt = totalcnt > max_cnt? max_cnt : totalcnt; 1920 1921 /* 1922 * Place the length in fh3_length representing the number 1923 * of security flavors (in bytes) in this overloaded fh. 1924 */ 1925 fh->fh3_length = (cnt+1) * sizeof (int32_t); 1926 1927 c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i; 1928 /* 1929 * Encode the status octet that indicates whether there 1930 * are more security flavors the client needs to get. 1931 */ 1932 *c = totalcnt > max_cnt; 1933 1934 /* 1935 * put security flavors in the overloaded fh 1936 */ 1937 ipt = (int *)(c + sizeof (int32_t)); 1938 for (i = 0; i < cnt; i++) { 1939 *(ipt+i) = htonl( 1940 exi->exi_export.ex_secinfo[i+sec_index-1].s_secinfo.sc_nfsnum); 1941 } 1942 return (0); 1943 } 1944 1945 /* 1946 * Make an nfs_fh4 from a vnode 1947 */ 1948 int 1949 makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi) 1950 { 1951 int error; 1952 nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val; 1953 fid_t fid; 1954 1955 bzero(&fid, sizeof (fid)); 1956 fid.fid_len = MAXFIDSZ; 1957 /* 1958 * vop_fid_pseudo() is used to set up NFSv4 namespace, so 1959 * use vop_fid_pseudo() here to get the fid instead of VOP_FID. 1960 */ 1961 error = vop_fid_pseudo(vp, &fid); 1962 if (error) 1963 return (error); 1964 1965 fh->nfs_fh4_len = NFS_FH4_LEN; 1966 1967 fh_fmtp->fh4_i = exi->exi_fh; /* copy the fhandle template */ 1968 fh_fmtp->fh4_len = fid.fid_len; 1969 ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data)); 1970 bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len); 1971 fh_fmtp->fh4_flag = 0; 1972 1973 #ifdef VOLATILE_FH_TEST 1974 /* 1975 * XXX (temporary?) 1976 * Use the rnode volatile_id value to add volatility to the fh. 1977 * 1978 * For testing purposes there are currently two scenarios, based 1979 * on whether the filesystem was shared with "volatile_fh" 1980 * or "expire_on_rename". In the first case, use the value of 1981 * export struct share_time as the volatile_id. In the second 1982 * case use the vnode volatile_id value (which is set to the 1983 * time in which the file was renamed). 1984 * 1985 * Note that the above are temporary constructs for testing only 1986 * XXX 1987 */ 1988 if (exi->exi_export.ex_flags & EX_VOLRNM) { 1989 fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh); 1990 } else if (exi->exi_export.ex_flags & EX_VOLFH) { 1991 fh_fmtp->fh4_volatile_id = exi->exi_volatile_id; 1992 } else { 1993 fh_fmtp->fh4_volatile_id = 0; 1994 } 1995 #endif /* VOLATILE_FH_TEST */ 1996 1997 return (0); 1998 } 1999 2000 /* 2001 * Convert an fhandle into a vnode. 2002 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode. 2003 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2004 * are done with it. 2005 */ 2006 vnode_t * 2007 nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi) 2008 { 2009 vfs_t *vfsp; 2010 vnode_t *vp; 2011 int error; 2012 fid_t *fidp; 2013 2014 TRACE_0(TR_FAC_NFS, TR_FHTOVP_START, 2015 "fhtovp_start"); 2016 2017 if (exi == NULL) { 2018 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2019 "fhtovp_end:(%S)", "exi NULL"); 2020 return (NULL); /* not exported */ 2021 } 2022 2023 ASSERT(exi->exi_vp != NULL); 2024 2025 if (PUBLIC_FH2(fh)) { 2026 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2027 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2028 "fhtovp_end:(%S)", "root not exported"); 2029 return (NULL); 2030 } 2031 vp = exi->exi_vp; 2032 VN_HOLD(vp); 2033 return (vp); 2034 } 2035 2036 vfsp = exi->exi_vp->v_vfsp; 2037 ASSERT(vfsp != NULL); 2038 fidp = (fid_t *)&fh->fh_len; 2039 2040 error = VFS_VGET(vfsp, &vp, fidp); 2041 if (error || vp == NULL) { 2042 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2043 "fhtovp_end:(%S)", "VFS_GET failed or vp NULL"); 2044 return (NULL); 2045 } 2046 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2047 "fhtovp_end:(%S)", "end"); 2048 return (vp); 2049 } 2050 2051 /* 2052 * Convert an fhandle into a vnode. 2053 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode. 2054 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2055 * are done with it. 2056 * This is just like nfs_fhtovp() but without the exportinfo argument. 2057 */ 2058 2059 vnode_t * 2060 lm_fhtovp(fhandle_t *fh) 2061 { 2062 register vfs_t *vfsp; 2063 vnode_t *vp; 2064 int error; 2065 2066 vfsp = getvfs(&fh->fh_fsid); 2067 if (vfsp == NULL) 2068 return (NULL); 2069 2070 error = VFS_VGET(vfsp, &vp, (fid_t *)&(fh->fh_len)); 2071 VFS_RELE(vfsp); 2072 if (error || vp == NULL) 2073 return (NULL); 2074 2075 return (vp); 2076 } 2077 2078 /* 2079 * Convert an nfs_fh3 into a vnode. 2080 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2081 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2082 * are done with it. 2083 */ 2084 vnode_t * 2085 nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi) 2086 { 2087 vfs_t *vfsp; 2088 vnode_t *vp; 2089 int error; 2090 fid_t *fidp; 2091 2092 if (exi == NULL) 2093 return (NULL); /* not exported */ 2094 2095 ASSERT(exi->exi_vp != NULL); 2096 2097 if (PUBLIC_FH3(fh)) { 2098 if (exi->exi_export.ex_flags & EX_PUBLIC) 2099 return (NULL); 2100 vp = exi->exi_vp; 2101 VN_HOLD(vp); 2102 return (vp); 2103 } 2104 2105 if (fh->fh3_length != NFS3_CURFHSIZE) 2106 return (NULL); 2107 2108 vfsp = exi->exi_vp->v_vfsp; 2109 ASSERT(vfsp != NULL); 2110 fidp = (fid_t *)&fh->fh3_len; 2111 2112 error = VFS_VGET(vfsp, &vp, fidp); 2113 if (error || vp == NULL) 2114 return (NULL); 2115 2116 return (vp); 2117 } 2118 2119 /* 2120 * Convert an nfs_fh3 into a vnode. 2121 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2122 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2123 * are done with it. 2124 * BTW: This is just like nfs3_fhtovp() but without the exportinfo arg. 2125 * Also, vfsp is accessed through getvfs() rather using exportinfo !! 2126 */ 2127 2128 vnode_t * 2129 lm_nfs3_fhtovp(nfs_fh3 *fh) 2130 { 2131 vfs_t *vfsp; 2132 vnode_t *vp; 2133 int error; 2134 2135 if (fh->fh3_length != NFS3_CURFHSIZE) 2136 return (NULL); 2137 2138 vfsp = getvfs(&fh->fh3_fsid); 2139 if (vfsp == NULL) 2140 return (NULL); 2141 2142 error = VFS_VGET(vfsp, &vp, (fid_t *)&(fh->fh3_len)); 2143 VFS_RELE(vfsp); 2144 if (error || vp == NULL) 2145 return (NULL); 2146 2147 return (vp); 2148 } 2149 2150 /* 2151 * Convert an nfs_fh4 into a vnode. 2152 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2153 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2154 * are done with it. 2155 */ 2156 vnode_t * 2157 nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp) 2158 { 2159 vfs_t *vfsp; 2160 vnode_t *vp = NULL; 2161 int error; 2162 fid_t *fidp; 2163 nfs_fh4_fmt_t *fh_fmtp; 2164 #ifdef VOLATILE_FH_TEST 2165 uint32_t volatile_id = 0; 2166 #endif /* VOLATILE_FH_TEST */ 2167 2168 if (exi == NULL) { 2169 *statp = NFS4ERR_STALE; 2170 return (NULL); /* not exported */ 2171 } 2172 ASSERT(exi->exi_vp != NULL); 2173 2174 /* caller should have checked this */ 2175 ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN); 2176 2177 fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val; 2178 vfsp = exi->exi_vp->v_vfsp; 2179 ASSERT(vfsp != NULL); 2180 fidp = (fid_t *)&fh_fmtp->fh4_len; 2181 2182 #ifdef VOLATILE_FH_TEST 2183 /* XXX check if volatile - should be changed later */ 2184 if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) { 2185 /* 2186 * Filesystem is shared with volatile filehandles 2187 */ 2188 if (exi->exi_export.ex_flags & EX_VOLRNM) 2189 volatile_id = find_volrnm_fh_id(exi, fh); 2190 else 2191 volatile_id = exi->exi_volatile_id; 2192 2193 if (fh_fmtp->fh4_volatile_id != volatile_id) { 2194 *statp = NFS4ERR_FHEXPIRED; 2195 return (NULL); 2196 } 2197 } 2198 /* 2199 * XXX even if test_volatile_fh false, the fh may contain a 2200 * volatile id if obtained when the test was set. 2201 */ 2202 fh_fmtp->fh4_volatile_id = (uchar_t)0; 2203 #endif /* VOLATILE_FH_TEST */ 2204 2205 error = VFS_VGET(vfsp, &vp, fidp); 2206 /* 2207 * If we can not get vp from VFS_VGET, perhaps this is 2208 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem. 2209 * Check it out. 2210 */ 2211 if (error && PSEUDO(exi)) 2212 error = nfs4_vget_pseudo(exi, &vp, fidp); 2213 2214 if (error || vp == NULL) { 2215 *statp = NFS4ERR_STALE; 2216 return (NULL); 2217 } 2218 /* XXX - disgusting hack */ 2219 if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR) 2220 vp->v_type = VDIR; 2221 *statp = NFS4_OK; 2222 return (vp); 2223 } 2224 2225 /* 2226 * Find the export structure associated with the given filesystem. 2227 * If found, then increment the ref count (exi_count). 2228 */ 2229 struct exportinfo * 2230 checkexport(fsid_t *fsid, fid_t *fid) 2231 { 2232 struct exportinfo *exi; 2233 2234 rw_enter(&exported_lock, RW_READER); 2235 for (exi = exptable[exptablehash(fsid, fid)]; 2236 exi != NULL; 2237 exi = exi->exi_hash) { 2238 if (exportmatch(exi, fsid, fid)) { 2239 /* 2240 * If this is the place holder for the 2241 * public file handle, then return the 2242 * real export entry for the public file 2243 * handle. 2244 */ 2245 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2246 exi = exi_public; 2247 } 2248 mutex_enter(&exi->exi_lock); 2249 exi->exi_count++; 2250 mutex_exit(&exi->exi_lock); 2251 rw_exit(&exported_lock); 2252 return (exi); 2253 } 2254 } 2255 rw_exit(&exported_lock); 2256 return (NULL); 2257 } 2258 2259 2260 /* 2261 * "old school" version of checkexport() for NFS4. NFS4 2262 * rfs4_compound holds exported_lock for duration of compound 2263 * processing. This version doesn't manipulate exi_count 2264 * since NFS4 breaks fundamental assumptions in the exi_count 2265 * design. 2266 */ 2267 struct exportinfo * 2268 checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp) 2269 { 2270 struct exportinfo *exi; 2271 2272 ASSERT(RW_LOCK_HELD(&exported_lock)); 2273 2274 for (exi = exptable[exptablehash(fsid, fid)]; 2275 exi != NULL; 2276 exi = exi->exi_hash) { 2277 if (exportmatch(exi, fsid, fid)) { 2278 /* 2279 * If this is the place holder for the 2280 * public file handle, then return the 2281 * real export entry for the public file 2282 * handle. 2283 */ 2284 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2285 exi = exi_public; 2286 } 2287 2288 /* 2289 * If vp is given, check if vp is the 2290 * same vnode as the exported node. 2291 * 2292 * Since VOP_FID of a lofs node returns the 2293 * fid of its real node (ufs), the exported 2294 * node for lofs and (pseudo) ufs may have 2295 * the same fsid and fid. 2296 */ 2297 if (vp == NULL || vp == exi->exi_vp) 2298 return (exi); 2299 } 2300 } 2301 2302 return (NULL); 2303 } 2304 2305 /* 2306 * Free an entire export list node 2307 */ 2308 void 2309 exportfree(struct exportinfo *exi) 2310 { 2311 struct exportdata *ex; 2312 2313 ex = &exi->exi_export; 2314 2315 ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC)); 2316 VN_RELE(exi->exi_vp); 2317 if (exi->exi_dvp != NULL) 2318 VN_RELE(exi->exi_dvp); 2319 2320 if (ex->ex_flags & EX_INDEX) 2321 kmem_free(ex->ex_index, strlen(ex->ex_index) + 1); 2322 2323 kmem_free(ex->ex_path, ex->ex_pathlen + 1); 2324 nfsauth_cache_free(exi); 2325 2326 if (exi->exi_logbuffer != NULL) 2327 nfslog_disable(exi); 2328 2329 if (ex->ex_flags & EX_LOG) { 2330 kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1); 2331 kmem_free(ex->ex_tag, ex->ex_taglen + 1); 2332 } 2333 2334 if (exi->exi_visible) 2335 free_visible(exi->exi_visible); 2336 2337 srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt); 2338 2339 #ifdef VOLATILE_FH_TEST 2340 free_volrnm_list(exi); 2341 mutex_destroy(&exi->exi_vol_rename_lock); 2342 #endif /* VOLATILE_FH_TEST */ 2343 2344 mutex_destroy(&exi->exi_lock); 2345 rw_destroy(&exi->exi_cache_lock); 2346 2347 kmem_free(exi, sizeof (*exi)); 2348 } 2349 2350 /* 2351 * load the index file from user space into kernel space. 2352 */ 2353 static int 2354 loadindex(struct exportdata *kex) 2355 { 2356 int error; 2357 char index[MAXNAMELEN+1]; 2358 size_t len; 2359 2360 /* 2361 * copyinstr copies the complete string including the NULL and 2362 * returns the len with the NULL byte included in the calculation 2363 * as long as the max length is not exceeded. 2364 */ 2365 if (error = copyinstr(kex->ex_index, index, sizeof (index), &len)) 2366 return (error); 2367 2368 kex->ex_index = kmem_alloc(len, KM_SLEEP); 2369 bcopy(index, kex->ex_index, len); 2370 2371 return (0); 2372 } 2373 2374 /* 2375 * When a thread completes using exi, it should call exi_rele(). 2376 * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e. 2377 * if this is the last user of exi and exi is not on exportinfo list anymore 2378 */ 2379 void 2380 exi_rele(struct exportinfo *exi) 2381 { 2382 mutex_enter(&exi->exi_lock); 2383 exi->exi_count--; 2384 if (exi->exi_count == 0) { 2385 mutex_exit(&exi->exi_lock); 2386 exportfree(exi); 2387 } else 2388 mutex_exit(&exi->exi_lock); 2389 } 2390 2391 #ifdef VOLATILE_FH_TEST 2392 /* 2393 * Test for volatile fh's - add file handle to list and set its volatile id 2394 * to time it was renamed. If EX_VOLFH is also on and the fs is reshared, 2395 * the vol_rename queue is purged. 2396 * 2397 * XXX This code is for unit testing purposes only... To correctly use it, it 2398 * needs to tie a rename list to the export struct and (more 2399 * important), protect access to the exi rename list using a write lock. 2400 */ 2401 2402 /* 2403 * get the fh vol record if it's in the volatile on rename list. Don't check 2404 * volatile_id in the file handle - compare only the file handles. 2405 */ 2406 static struct ex_vol_rename * 2407 find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p) 2408 { 2409 struct ex_vol_rename *p = NULL; 2410 fhandle_t *fhp; 2411 2412 /* XXX shouldn't we assert &exported_lock held? */ 2413 ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock)); 2414 2415 if (fh4p->nfs_fh4_len != NFS_FH4_LEN) { 2416 return (NULL); 2417 } 2418 fhp = &((struct nfs_fh4_fmt *)fh4p->nfs_fh4_val)->fh4_i; 2419 for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) { 2420 if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i, sizeof (fhandle_t)) == 0) 2421 break; 2422 } 2423 return (p); 2424 } 2425 2426 /* 2427 * get the volatile id for the fh (if there is - else return 0). Ignore the 2428 * volatile_id in the file handle - compare only the file handles. 2429 */ 2430 static uint32_t 2431 find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p) 2432 { 2433 struct ex_vol_rename *p; 2434 uint32_t volatile_id; 2435 2436 mutex_enter(&exi->exi_vol_rename_lock); 2437 p = find_volrnm_fh(exi, fh4p); 2438 volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id : 2439 exi->exi_volatile_id); 2440 mutex_exit(&exi->exi_vol_rename_lock); 2441 return (volatile_id); 2442 } 2443 2444 /* 2445 * Free the volatile on rename list - will be called if a filesystem is 2446 * unshared or reshared without EX_VOLRNM 2447 */ 2448 static void 2449 free_volrnm_list(struct exportinfo *exi) 2450 { 2451 struct ex_vol_rename *p, *pnext; 2452 2453 /* no need to hold mutex lock - this one is called from exportfree */ 2454 for (p = exi->exi_vol_rename; p != NULL; p = pnext) { 2455 pnext = p->vrn_next; 2456 kmem_free(p, sizeof (*p)); 2457 } 2458 exi->exi_vol_rename = NULL; 2459 } 2460 2461 /* 2462 * Add a file handle to the volatile on rename list. 2463 */ 2464 void 2465 add_volrnm_fh(struct exportinfo *exi, vnode_t *vp) 2466 { 2467 struct ex_vol_rename *p; 2468 char fhbuf[NFS4_FHSIZE]; 2469 nfs_fh4 fh4; 2470 int error; 2471 2472 fh4.nfs_fh4_val = fhbuf; 2473 error = makefh4(&fh4, vp, exi); 2474 if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) { 2475 return; 2476 } 2477 2478 mutex_enter(&exi->exi_vol_rename_lock); 2479 2480 p = find_volrnm_fh(exi, &fh4); 2481 2482 if (p == NULL) { 2483 p = kmem_alloc(sizeof (*p), KM_SLEEP); 2484 bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt)); 2485 p->vrn_next = exi->exi_vol_rename; 2486 exi->exi_vol_rename = p; 2487 } 2488 2489 p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec(); 2490 mutex_exit(&exi->exi_vol_rename_lock); 2491 } 2492 2493 #endif /* VOLATILE_FH_TEST */ 2494