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, pad; 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 1671 /* 1672 * For backwards compatability, the 1673 * fid length may be less than 1674 * NFS_FHMAXDATA, but it was always 1675 * encoded as NFS_FHMAXDATA bytes. 1676 */ 1677 1678 sz = sizeof (ushort_t); 1679 bcopy(&fh.fh3_len, &buf[i], sz); 1680 i += sz; 1681 bcopy(fh.fh3_data, &buf[i], fh.fh3_len); 1682 i += fh.fh3_len; 1683 pad = (NFS_FHMAXDATA - fh.fh3_len); 1684 if (pad > 0) { 1685 bzero(&buf[i], pad); 1686 i += pad; 1687 l += pad; 1688 } 1689 1690 sz = sizeof (ushort_t); 1691 bcopy(&fh.fh3_xlen, &buf[i], sz); 1692 i += sz; 1693 bcopy(fh.fh3_xdata, &buf[i], fh.fh3_xlen); 1694 i += fh.fh3_xlen; 1695 pad = (NFS_FHMAXDATA - fh.fh3_xlen); 1696 if (pad > 0) { 1697 bzero(&buf[i], pad); 1698 i += pad; 1699 l += pad; 1700 } 1701 } 1702 /* 1703 * If we need to do NFS logging, the filehandle 1704 * must be downsized to 32 bytes. 1705 */ 1706 if (!error && exi->exi_export.ex_flags & EX_LOG) { 1707 i = 0; 1708 sz = sizeof (fsid_t); 1709 bcopy(&fh.fh3_fsid, &logbuf[i], sz); 1710 i += sz; 1711 sz = sizeof (ushort_t); 1712 bcopy(&fh.fh3_len, &logbuf[i], sz); 1713 i += sz; 1714 sz = NFS_FHMAXDATA; 1715 bcopy(fh.fh3_data, &logbuf[i], sz); 1716 i += sz; 1717 sz = sizeof (ushort_t); 1718 bcopy(&fh.fh3_xlen, &logbuf[i], sz); 1719 i += sz; 1720 sz = NFS_FHMAXDATA; 1721 bcopy(fh.fh3_xdata, &logbuf[i], sz); 1722 i += sz; 1723 } 1724 } 1725 if (!error && exi->exi_export.ex_flags & EX_LOG) { 1726 nfslog_getfh(exi, (fhandle_t *)logptr, 1727 STRUCT_FGETP(uap, fname), UIO_USERSPACE, cr); 1728 } 1729 exi_rele(exi); 1730 if (!error) { 1731 if (copyout(&l, STRUCT_FGETP(uap, lenp), sizeof (int))) 1732 error = EFAULT; 1733 if (copyout(buf, STRUCT_FGETP(uap, fhp), l)) 1734 error = EFAULT; 1735 } 1736 } 1737 VN_RELE(vp); 1738 if (dvp != NULL) { 1739 VN_RELE(dvp); 1740 } 1741 return (error); 1742 } 1743 1744 /* 1745 * Strategy: if vp is in the export list, then 1746 * return the associated file handle. Otherwise, ".." 1747 * once up the vp and try again, until the root of the 1748 * filesystem is reached. 1749 */ 1750 struct exportinfo * 1751 nfs_vptoexi(vnode_t *dvp, vnode_t *vp, cred_t *cr, int *walk, 1752 int *err, bool_t v4srv) 1753 { 1754 fid_t fid; 1755 int error; 1756 struct exportinfo *exi; 1757 1758 ASSERT(vp); 1759 VN_HOLD(vp); 1760 if (dvp != NULL) { 1761 VN_HOLD(dvp); 1762 } 1763 if (walk != NULL) 1764 *walk = 0; 1765 1766 for (;;) { 1767 bzero(&fid, sizeof (fid)); 1768 fid.fid_len = MAXFIDSZ; 1769 error = vop_fid_pseudo(vp, &fid); 1770 if (error) { 1771 /* 1772 * If vop_fid_pseudo returns ENOSPC then the fid 1773 * supplied is too small. For now we simply 1774 * return EREMOTE. 1775 */ 1776 if (error == ENOSPC) 1777 error = EREMOTE; 1778 break; 1779 } 1780 1781 if (v4srv) 1782 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp); 1783 else 1784 exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid); 1785 1786 if (exi != NULL) { 1787 /* 1788 * Found the export info 1789 */ 1790 break; 1791 } 1792 1793 /* 1794 * We have just failed finding a matching export. 1795 * If we're at the root of this filesystem, then 1796 * it's time to stop (with failure). 1797 */ 1798 if (vp->v_flag & VROOT) { 1799 error = EINVAL; 1800 break; 1801 } 1802 1803 if (walk != NULL) 1804 (*walk)++; 1805 1806 /* 1807 * Now, do a ".." up vp. If dvp is supplied, use it, 1808 * otherwise, look it up. 1809 */ 1810 if (dvp == NULL) { 1811 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr); 1812 if (error) 1813 break; 1814 } 1815 VN_RELE(vp); 1816 vp = dvp; 1817 dvp = NULL; 1818 } 1819 VN_RELE(vp); 1820 if (dvp != NULL) { 1821 VN_RELE(dvp); 1822 } 1823 if (error != 0) { 1824 if (err != NULL) 1825 *err = error; 1826 return (NULL); 1827 } 1828 return (exi); 1829 } 1830 1831 bool_t 1832 chk_clnt_sec(struct exportinfo *exi, struct svc_req *req) 1833 { 1834 int i, nfsflavor; 1835 struct secinfo *sp; 1836 bool_t sec_found = FALSE; 1837 1838 /* 1839 * Get the nfs flavor number from xprt. 1840 */ 1841 nfsflavor = (int)(uintptr_t)req->rq_xprt->xp_cookie; 1842 1843 sp = exi->exi_export.ex_secinfo; 1844 for (i = 0; i < exi->exi_export.ex_seccnt; i++) { 1845 if (nfsflavor == sp[i].s_secinfo.sc_nfsnum) { 1846 sec_found = TRUE; 1847 break; 1848 } 1849 } 1850 return (sec_found); 1851 } 1852 1853 /* 1854 * Make an fhandle from a vnode 1855 */ 1856 int 1857 makefh(fhandle_t *fh, vnode_t *vp, struct exportinfo *exi) 1858 { 1859 int error; 1860 1861 *fh = exi->exi_fh; /* struct copy */ 1862 1863 error = VOP_FID(vp, (fid_t *)&fh->fh_len); 1864 if (error) { 1865 /* 1866 * Should be something other than EREMOTE 1867 */ 1868 return (EREMOTE); 1869 } 1870 return (0); 1871 } 1872 1873 /* 1874 * This routine makes an overloaded V2 fhandle which contains 1875 * sec modes. 1876 * 1877 * Note that the first four octets contain the length octet, 1878 * the status octet, and two padded octets to make them XDR 1879 * four-octet aligned. 1880 * 1881 * 1 2 3 4 32 1882 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ 1883 * | l | s | | | sec_1 |...| sec_n |...| | 1884 * +---+---+---+---+---+---+---+---+ +---+---+---+---+ +---+ 1885 * 1886 * where 1887 * 1888 * the status octet s indicates whether there are more security 1889 * flavors (1 means yes, 0 means no) that require the client to 1890 * perform another 0x81 LOOKUP to get them, 1891 * 1892 * the length octet l is the length describing the number of 1893 * valid octets that follow. (l = 4 * n, where n is the number 1894 * of security flavors sent in the current overloaded filehandle.) 1895 */ 1896 int 1897 makefh_ol(fhandle_t *fh, struct exportinfo *exi, uint_t sec_index) 1898 { 1899 static int max_cnt = (NFS_FHSIZE/sizeof (int)) - 1; 1900 int totalcnt, i, *ipt, cnt; 1901 char *c; 1902 1903 if (fh == (fhandle_t *)NULL || 1904 exi == (struct exportinfo *)NULL || 1905 sec_index > exi->exi_export.ex_seccnt || 1906 sec_index < 1) 1907 return (EREMOTE); 1908 1909 totalcnt = exi->exi_export.ex_seccnt-sec_index+1; 1910 cnt = totalcnt > max_cnt? max_cnt : totalcnt; 1911 1912 c = (char *)fh; 1913 /* 1914 * Encode the length octet representing the number of 1915 * security flavors (in bytes) in this overloaded fh. 1916 */ 1917 *c = cnt * sizeof (int); 1918 1919 /* 1920 * Encode the status octet that indicates whether there 1921 * are more security flavors the client needs to get. 1922 */ 1923 *(c+1) = totalcnt > max_cnt; 1924 1925 /* 1926 * put security flavors in the overloaded fh 1927 */ 1928 ipt = (int *)(c + sizeof (int32_t)); 1929 for (i = 0; i < cnt; i++) { 1930 *ipt++ = htonl(exi->exi_export.ex_secinfo[i+sec_index-1]. 1931 s_secinfo.sc_nfsnum); 1932 } 1933 return (0); 1934 } 1935 1936 /* 1937 * Make an nfs_fh3 from a vnode 1938 */ 1939 int 1940 makefh3(nfs_fh3 *fh, vnode_t *vp, struct exportinfo *exi) 1941 { 1942 int error; 1943 fid_t fid; 1944 1945 bzero(&fid, sizeof (fid)); 1946 fid.fid_len = MAXFIDSZ; 1947 error = VOP_FID(vp, &fid); 1948 if (error) 1949 return (EREMOTE); 1950 1951 bzero(fh, sizeof (nfs_fh3)); 1952 fh->fh3_fsid = exi->exi_fsid; 1953 fh->fh3_len = fid.fid_len; 1954 bcopy(fid.fid_data, fh->fh3_data, fh->fh3_len); 1955 fh->fh3_xlen = exi->exi_fid.fid_len; 1956 bcopy(exi->exi_fid.fid_data, fh->fh3_xdata, fh->fh3_xlen); 1957 fh->fh3_length = sizeof (fsid_t) 1958 + sizeof (ushort_t) + fh->fh3_len 1959 + sizeof (ushort_t) + fh->fh3_xlen; 1960 fh->fh3_flags = 0; 1961 return (0); 1962 } 1963 1964 /* 1965 * This routine makes an overloaded V3 fhandle which contains 1966 * sec modes. 1967 * 1968 * 1 4 1969 * +--+--+--+--+ 1970 * | len | 1971 * +--+--+--+--+ 1972 * up to 64 1973 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ 1974 * |s | | | | sec_1 | sec_2 | ... | sec_n | 1975 * +--+--+--+--+--+--+--+--+--+--+--+--+ +--+--+--+--+ 1976 * 1977 * len = 4 * (n+1), where n is the number of security flavors 1978 * sent in the current overloaded filehandle. 1979 * 1980 * the status octet s indicates whether there are more security 1981 * mechanisms (1 means yes, 0 means no) that require the client 1982 * to perform another 0x81 LOOKUP to get them. 1983 * 1984 * Three octets are padded after the status octet. 1985 */ 1986 int 1987 makefh3_ol(nfs_fh3 *fh, struct exportinfo *exi, uint_t sec_index) 1988 { 1989 static int max_cnt = NFS3_FHSIZE/sizeof (int) - 1; 1990 int totalcnt, cnt, *ipt, i; 1991 char *c; 1992 1993 if (fh == (nfs_fh3 *)NULL || 1994 exi == (struct exportinfo *)NULL || 1995 sec_index > exi->exi_export.ex_seccnt || 1996 sec_index < 1) { 1997 return (EREMOTE); 1998 } 1999 2000 totalcnt = exi->exi_export.ex_seccnt-sec_index+1; 2001 cnt = totalcnt > max_cnt? max_cnt : totalcnt; 2002 2003 /* 2004 * Place the length in fh3_length representing the number 2005 * of security flavors (in bytes) in this overloaded fh. 2006 */ 2007 fh->fh3_flags = FH_WEBNFS; 2008 fh->fh3_length = (cnt+1) * sizeof (int32_t); 2009 2010 c = (char *)&fh->fh3_u.nfs_fh3_i.fh3_i; 2011 /* 2012 * Encode the status octet that indicates whether there 2013 * are more security flavors the client needs to get. 2014 */ 2015 *c = totalcnt > max_cnt; 2016 2017 /* 2018 * put security flavors in the overloaded fh 2019 */ 2020 ipt = (int *)(c + sizeof (int32_t)); 2021 for (i = 0; i < cnt; i++) { 2022 *(ipt+i) = htonl( 2023 exi->exi_export.ex_secinfo[i+sec_index-1].s_secinfo.sc_nfsnum); 2024 } 2025 return (0); 2026 } 2027 2028 /* 2029 * Make an nfs_fh4 from a vnode 2030 */ 2031 int 2032 makefh4(nfs_fh4 *fh, vnode_t *vp, struct exportinfo *exi) 2033 { 2034 int error; 2035 nfs_fh4_fmt_t *fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val; 2036 fid_t fid; 2037 2038 bzero(&fid, sizeof (fid)); 2039 fid.fid_len = MAXFIDSZ; 2040 /* 2041 * vop_fid_pseudo() is used to set up NFSv4 namespace, so 2042 * use vop_fid_pseudo() here to get the fid instead of VOP_FID. 2043 */ 2044 error = vop_fid_pseudo(vp, &fid); 2045 if (error) 2046 return (error); 2047 2048 fh->nfs_fh4_len = NFS_FH4_LEN; 2049 2050 fh_fmtp->fh4_i.fhx_fsid = exi->exi_fh.fh_fsid; 2051 fh_fmtp->fh4_i.fhx_xlen = exi->exi_fh.fh_xlen; 2052 2053 bzero(fh_fmtp->fh4_i.fhx_data, sizeof (fh_fmtp->fh4_i.fhx_data)); 2054 bzero(fh_fmtp->fh4_i.fhx_xdata, sizeof (fh_fmtp->fh4_i.fhx_xdata)); 2055 bcopy(exi->exi_fh.fh_xdata, fh_fmtp->fh4_i.fhx_xdata, 2056 exi->exi_fh.fh_xlen); 2057 2058 fh_fmtp->fh4_len = fid.fid_len; 2059 ASSERT(fid.fid_len <= sizeof (fh_fmtp->fh4_data)); 2060 bcopy(fid.fid_data, fh_fmtp->fh4_data, fid.fid_len); 2061 fh_fmtp->fh4_flag = 0; 2062 2063 #ifdef VOLATILE_FH_TEST 2064 /* 2065 * XXX (temporary?) 2066 * Use the rnode volatile_id value to add volatility to the fh. 2067 * 2068 * For testing purposes there are currently two scenarios, based 2069 * on whether the filesystem was shared with "volatile_fh" 2070 * or "expire_on_rename". In the first case, use the value of 2071 * export struct share_time as the volatile_id. In the second 2072 * case use the vnode volatile_id value (which is set to the 2073 * time in which the file was renamed). 2074 * 2075 * Note that the above are temporary constructs for testing only 2076 * XXX 2077 */ 2078 if (exi->exi_export.ex_flags & EX_VOLRNM) { 2079 fh_fmtp->fh4_volatile_id = find_volrnm_fh_id(exi, fh); 2080 } else if (exi->exi_export.ex_flags & EX_VOLFH) { 2081 fh_fmtp->fh4_volatile_id = exi->exi_volatile_id; 2082 } else { 2083 fh_fmtp->fh4_volatile_id = 0; 2084 } 2085 #endif /* VOLATILE_FH_TEST */ 2086 2087 return (0); 2088 } 2089 2090 /* 2091 * Convert an fhandle into a vnode. 2092 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode. 2093 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2094 * are done with it. 2095 */ 2096 vnode_t * 2097 nfs_fhtovp(fhandle_t *fh, struct exportinfo *exi) 2098 { 2099 vfs_t *vfsp; 2100 vnode_t *vp; 2101 int error; 2102 fid_t *fidp; 2103 2104 TRACE_0(TR_FAC_NFS, TR_FHTOVP_START, 2105 "fhtovp_start"); 2106 2107 if (exi == NULL) { 2108 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2109 "fhtovp_end:(%S)", "exi NULL"); 2110 return (NULL); /* not exported */ 2111 } 2112 2113 ASSERT(exi->exi_vp != NULL); 2114 2115 if (PUBLIC_FH2(fh)) { 2116 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2117 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2118 "fhtovp_end:(%S)", "root not exported"); 2119 return (NULL); 2120 } 2121 vp = exi->exi_vp; 2122 VN_HOLD(vp); 2123 return (vp); 2124 } 2125 2126 vfsp = exi->exi_vp->v_vfsp; 2127 ASSERT(vfsp != NULL); 2128 fidp = (fid_t *)&fh->fh_len; 2129 2130 error = VFS_VGET(vfsp, &vp, fidp); 2131 if (error || vp == NULL) { 2132 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2133 "fhtovp_end:(%S)", "VFS_GET failed or vp NULL"); 2134 return (NULL); 2135 } 2136 TRACE_1(TR_FAC_NFS, TR_FHTOVP_END, 2137 "fhtovp_end:(%S)", "end"); 2138 return (vp); 2139 } 2140 2141 /* 2142 * Convert an fhandle into a vnode. 2143 * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode. 2144 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2145 * are done with it. 2146 * This is just like nfs_fhtovp() but without the exportinfo argument. 2147 */ 2148 2149 vnode_t * 2150 lm_fhtovp(fhandle_t *fh) 2151 { 2152 register vfs_t *vfsp; 2153 vnode_t *vp; 2154 int error; 2155 2156 vfsp = getvfs(&fh->fh_fsid); 2157 if (vfsp == NULL) 2158 return (NULL); 2159 2160 error = VFS_VGET(vfsp, &vp, (fid_t *)&(fh->fh_len)); 2161 VFS_RELE(vfsp); 2162 if (error || vp == NULL) 2163 return (NULL); 2164 2165 return (vp); 2166 } 2167 2168 /* 2169 * Convert an nfs_fh3 into a vnode. 2170 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2171 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2172 * are done with it. 2173 */ 2174 vnode_t * 2175 nfs3_fhtovp(nfs_fh3 *fh, struct exportinfo *exi) 2176 { 2177 vfs_t *vfsp; 2178 vnode_t *vp; 2179 int error; 2180 fid_t *fidp; 2181 2182 if (exi == NULL) 2183 return (NULL); /* not exported */ 2184 2185 ASSERT(exi->exi_vp != NULL); 2186 2187 if (PUBLIC_FH3(fh)) { 2188 if (exi->exi_export.ex_flags & EX_PUBLIC) 2189 return (NULL); 2190 vp = exi->exi_vp; 2191 VN_HOLD(vp); 2192 return (vp); 2193 } 2194 2195 if (fh->fh3_length < NFS3_OLDFHSIZE || 2196 fh->fh3_length > NFS3_MAXFHSIZE) 2197 return (NULL); 2198 2199 vfsp = exi->exi_vp->v_vfsp; 2200 ASSERT(vfsp != NULL); 2201 fidp = FH3TOFIDP(fh); 2202 2203 error = VFS_VGET(vfsp, &vp, fidp); 2204 if (error || vp == NULL) 2205 return (NULL); 2206 2207 return (vp); 2208 } 2209 2210 /* 2211 * Convert an nfs_fh3 into a vnode. 2212 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2213 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2214 * are done with it. 2215 * BTW: This is just like nfs3_fhtovp() but without the exportinfo arg. 2216 * Also, vfsp is accessed through getvfs() rather using exportinfo !! 2217 */ 2218 2219 vnode_t * 2220 lm_nfs3_fhtovp(nfs_fh3 *fh) 2221 { 2222 vfs_t *vfsp; 2223 vnode_t *vp; 2224 int error; 2225 fid_t *fidp; 2226 2227 if (fh->fh3_length < NFS3_OLDFHSIZE || 2228 fh->fh3_length > NFS3_MAXFHSIZE) 2229 return (NULL); 2230 2231 vfsp = getvfs(&fh->fh3_fsid); 2232 if (vfsp == NULL) 2233 return (NULL); 2234 fidp = FH3TOFIDP(fh); 2235 2236 error = VFS_VGET(vfsp, &vp, fidp); 2237 VFS_RELE(vfsp); 2238 if (error || vp == NULL) 2239 return (NULL); 2240 2241 return (vp); 2242 } 2243 2244 /* 2245 * Convert an nfs_fh4 into a vnode. 2246 * Uses the file id (fh_len + fh_data) in the file handle to get the vnode. 2247 * WARNING: users of this routine must do a VN_RELE on the vnode when they 2248 * are done with it. 2249 */ 2250 vnode_t * 2251 nfs4_fhtovp(nfs_fh4 *fh, struct exportinfo *exi, nfsstat4 *statp) 2252 { 2253 vfs_t *vfsp; 2254 vnode_t *vp = NULL; 2255 int error; 2256 fid_t *fidp; 2257 nfs_fh4_fmt_t *fh_fmtp; 2258 #ifdef VOLATILE_FH_TEST 2259 uint32_t volatile_id = 0; 2260 #endif /* VOLATILE_FH_TEST */ 2261 2262 if (exi == NULL) { 2263 *statp = NFS4ERR_STALE; 2264 return (NULL); /* not exported */ 2265 } 2266 ASSERT(exi->exi_vp != NULL); 2267 2268 /* caller should have checked this */ 2269 ASSERT(fh->nfs_fh4_len >= NFS_FH4_LEN); 2270 2271 fh_fmtp = (nfs_fh4_fmt_t *)fh->nfs_fh4_val; 2272 vfsp = exi->exi_vp->v_vfsp; 2273 ASSERT(vfsp != NULL); 2274 fidp = (fid_t *)&fh_fmtp->fh4_len; 2275 2276 #ifdef VOLATILE_FH_TEST 2277 /* XXX check if volatile - should be changed later */ 2278 if (exi->exi_export.ex_flags & (EX_VOLRNM | EX_VOLFH)) { 2279 /* 2280 * Filesystem is shared with volatile filehandles 2281 */ 2282 if (exi->exi_export.ex_flags & EX_VOLRNM) 2283 volatile_id = find_volrnm_fh_id(exi, fh); 2284 else 2285 volatile_id = exi->exi_volatile_id; 2286 2287 if (fh_fmtp->fh4_volatile_id != volatile_id) { 2288 *statp = NFS4ERR_FHEXPIRED; 2289 return (NULL); 2290 } 2291 } 2292 /* 2293 * XXX even if test_volatile_fh false, the fh may contain a 2294 * volatile id if obtained when the test was set. 2295 */ 2296 fh_fmtp->fh4_volatile_id = (uchar_t)0; 2297 #endif /* VOLATILE_FH_TEST */ 2298 2299 error = VFS_VGET(vfsp, &vp, fidp); 2300 /* 2301 * If we can not get vp from VFS_VGET, perhaps this is 2302 * an nfs v2/v3/v4 node in an nfsv4 pseudo filesystem. 2303 * Check it out. 2304 */ 2305 if (error && PSEUDO(exi)) 2306 error = nfs4_vget_pseudo(exi, &vp, fidp); 2307 2308 if (error || vp == NULL) { 2309 *statp = NFS4ERR_STALE; 2310 return (NULL); 2311 } 2312 /* XXX - disgusting hack */ 2313 if (vp->v_type == VNON && vp->v_flag & V_XATTRDIR) 2314 vp->v_type = VDIR; 2315 *statp = NFS4_OK; 2316 return (vp); 2317 } 2318 2319 /* 2320 * Find the export structure associated with the given filesystem. 2321 * If found, then increment the ref count (exi_count). 2322 */ 2323 struct exportinfo * 2324 checkexport(fsid_t *fsid, fid_t *fid) 2325 { 2326 struct exportinfo *exi; 2327 2328 rw_enter(&exported_lock, RW_READER); 2329 for (exi = exptable[exptablehash(fsid, fid)]; 2330 exi != NULL; 2331 exi = exi->exi_hash) { 2332 if (exportmatch(exi, fsid, fid)) { 2333 /* 2334 * If this is the place holder for the 2335 * public file handle, then return the 2336 * real export entry for the public file 2337 * handle. 2338 */ 2339 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2340 exi = exi_public; 2341 } 2342 mutex_enter(&exi->exi_lock); 2343 exi->exi_count++; 2344 mutex_exit(&exi->exi_lock); 2345 rw_exit(&exported_lock); 2346 return (exi); 2347 } 2348 } 2349 rw_exit(&exported_lock); 2350 return (NULL); 2351 } 2352 2353 2354 /* 2355 * "old school" version of checkexport() for NFS4. NFS4 2356 * rfs4_compound holds exported_lock for duration of compound 2357 * processing. This version doesn't manipulate exi_count 2358 * since NFS4 breaks fundamental assumptions in the exi_count 2359 * design. 2360 */ 2361 struct exportinfo * 2362 checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp) 2363 { 2364 struct exportinfo *exi; 2365 2366 ASSERT(RW_LOCK_HELD(&exported_lock)); 2367 2368 for (exi = exptable[exptablehash(fsid, fid)]; 2369 exi != NULL; 2370 exi = exi->exi_hash) { 2371 if (exportmatch(exi, fsid, fid)) { 2372 /* 2373 * If this is the place holder for the 2374 * public file handle, then return the 2375 * real export entry for the public file 2376 * handle. 2377 */ 2378 if (exi->exi_export.ex_flags & EX_PUBLIC) { 2379 exi = exi_public; 2380 } 2381 2382 /* 2383 * If vp is given, check if vp is the 2384 * same vnode as the exported node. 2385 * 2386 * Since VOP_FID of a lofs node returns the 2387 * fid of its real node (ufs), the exported 2388 * node for lofs and (pseudo) ufs may have 2389 * the same fsid and fid. 2390 */ 2391 if (vp == NULL || vp == exi->exi_vp) 2392 return (exi); 2393 } 2394 } 2395 2396 return (NULL); 2397 } 2398 2399 /* 2400 * Free an entire export list node 2401 */ 2402 void 2403 exportfree(struct exportinfo *exi) 2404 { 2405 struct exportdata *ex; 2406 2407 ex = &exi->exi_export; 2408 2409 ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC)); 2410 VN_RELE(exi->exi_vp); 2411 if (exi->exi_dvp != NULL) 2412 VN_RELE(exi->exi_dvp); 2413 2414 if (ex->ex_flags & EX_INDEX) 2415 kmem_free(ex->ex_index, strlen(ex->ex_index) + 1); 2416 2417 kmem_free(ex->ex_path, ex->ex_pathlen + 1); 2418 nfsauth_cache_free(exi); 2419 2420 if (exi->exi_logbuffer != NULL) 2421 nfslog_disable(exi); 2422 2423 if (ex->ex_flags & EX_LOG) { 2424 kmem_free(ex->ex_log_buffer, ex->ex_log_bufferlen + 1); 2425 kmem_free(ex->ex_tag, ex->ex_taglen + 1); 2426 } 2427 2428 if (exi->exi_visible) 2429 free_visible(exi->exi_visible); 2430 2431 srv_secinfo_list_free(ex->ex_secinfo, ex->ex_seccnt); 2432 2433 #ifdef VOLATILE_FH_TEST 2434 free_volrnm_list(exi); 2435 mutex_destroy(&exi->exi_vol_rename_lock); 2436 #endif /* VOLATILE_FH_TEST */ 2437 2438 mutex_destroy(&exi->exi_lock); 2439 rw_destroy(&exi->exi_cache_lock); 2440 2441 kmem_free(exi, sizeof (*exi)); 2442 } 2443 2444 /* 2445 * load the index file from user space into kernel space. 2446 */ 2447 static int 2448 loadindex(struct exportdata *kex) 2449 { 2450 int error; 2451 char index[MAXNAMELEN+1]; 2452 size_t len; 2453 2454 /* 2455 * copyinstr copies the complete string including the NULL and 2456 * returns the len with the NULL byte included in the calculation 2457 * as long as the max length is not exceeded. 2458 */ 2459 if (error = copyinstr(kex->ex_index, index, sizeof (index), &len)) 2460 return (error); 2461 2462 kex->ex_index = kmem_alloc(len, KM_SLEEP); 2463 bcopy(index, kex->ex_index, len); 2464 2465 return (0); 2466 } 2467 2468 /* 2469 * When a thread completes using exi, it should call exi_rele(). 2470 * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e. 2471 * if this is the last user of exi and exi is not on exportinfo list anymore 2472 */ 2473 void 2474 exi_rele(struct exportinfo *exi) 2475 { 2476 mutex_enter(&exi->exi_lock); 2477 exi->exi_count--; 2478 if (exi->exi_count == 0) { 2479 mutex_exit(&exi->exi_lock); 2480 exportfree(exi); 2481 } else 2482 mutex_exit(&exi->exi_lock); 2483 } 2484 2485 #ifdef VOLATILE_FH_TEST 2486 /* 2487 * Test for volatile fh's - add file handle to list and set its volatile id 2488 * to time it was renamed. If EX_VOLFH is also on and the fs is reshared, 2489 * the vol_rename queue is purged. 2490 * 2491 * XXX This code is for unit testing purposes only... To correctly use it, it 2492 * needs to tie a rename list to the export struct and (more 2493 * important), protect access to the exi rename list using a write lock. 2494 */ 2495 2496 /* 2497 * get the fh vol record if it's in the volatile on rename list. Don't check 2498 * volatile_id in the file handle - compare only the file handles. 2499 */ 2500 static struct ex_vol_rename * 2501 find_volrnm_fh(struct exportinfo *exi, nfs_fh4 *fh4p) 2502 { 2503 struct ex_vol_rename *p = NULL; 2504 fhandle4_t *fhp; 2505 2506 /* XXX shouldn't we assert &exported_lock held? */ 2507 ASSERT(MUTEX_HELD(&exi->exi_vol_rename_lock)); 2508 2509 if (fh4p->nfs_fh4_len != NFS_FH4_LEN) { 2510 return (NULL); 2511 } 2512 fhp = &((nfs_fh4_fmt_t *)fh4p->nfs_fh4_val)->fh4_i; 2513 for (p = exi->exi_vol_rename; p != NULL; p = p->vrn_next) { 2514 if (bcmp(fhp, &p->vrn_fh_fmt.fh4_i, 2515 sizeof (fhandle4_t)) == 0) 2516 break; 2517 } 2518 return (p); 2519 } 2520 2521 /* 2522 * get the volatile id for the fh (if there is - else return 0). Ignore the 2523 * volatile_id in the file handle - compare only the file handles. 2524 */ 2525 static uint32_t 2526 find_volrnm_fh_id(struct exportinfo *exi, nfs_fh4 *fh4p) 2527 { 2528 struct ex_vol_rename *p; 2529 uint32_t volatile_id; 2530 2531 mutex_enter(&exi->exi_vol_rename_lock); 2532 p = find_volrnm_fh(exi, fh4p); 2533 volatile_id = (p ? p->vrn_fh_fmt.fh4_volatile_id : 2534 exi->exi_volatile_id); 2535 mutex_exit(&exi->exi_vol_rename_lock); 2536 return (volatile_id); 2537 } 2538 2539 /* 2540 * Free the volatile on rename list - will be called if a filesystem is 2541 * unshared or reshared without EX_VOLRNM 2542 */ 2543 static void 2544 free_volrnm_list(struct exportinfo *exi) 2545 { 2546 struct ex_vol_rename *p, *pnext; 2547 2548 /* no need to hold mutex lock - this one is called from exportfree */ 2549 for (p = exi->exi_vol_rename; p != NULL; p = pnext) { 2550 pnext = p->vrn_next; 2551 kmem_free(p, sizeof (*p)); 2552 } 2553 exi->exi_vol_rename = NULL; 2554 } 2555 2556 /* 2557 * Add a file handle to the volatile on rename list. 2558 */ 2559 void 2560 add_volrnm_fh(struct exportinfo *exi, vnode_t *vp) 2561 { 2562 struct ex_vol_rename *p; 2563 char fhbuf[NFS4_FHSIZE]; 2564 nfs_fh4 fh4; 2565 int error; 2566 2567 fh4.nfs_fh4_val = fhbuf; 2568 error = makefh4(&fh4, vp, exi); 2569 if ((error) || (fh4.nfs_fh4_len != sizeof (p->vrn_fh_fmt))) { 2570 return; 2571 } 2572 2573 mutex_enter(&exi->exi_vol_rename_lock); 2574 2575 p = find_volrnm_fh(exi, &fh4); 2576 2577 if (p == NULL) { 2578 p = kmem_alloc(sizeof (*p), KM_SLEEP); 2579 bcopy(fh4.nfs_fh4_val, &p->vrn_fh_fmt, sizeof (p->vrn_fh_fmt)); 2580 p->vrn_next = exi->exi_vol_rename; 2581 exi->exi_vol_rename = p; 2582 } 2583 2584 p->vrn_fh_fmt.fh4_volatile_id = gethrestime_sec(); 2585 mutex_exit(&exi->exi_vol_rename_lock); 2586 } 2587 2588 #endif /* VOLATILE_FH_TEST */ 2589