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