239 while ((c = getopt(argc, argv, "n")) != EOF) 240 switch (c) { 241 case 'n': 242 root_only = 0; 243 break; 244 default: 245 fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); 246 exit(1); 247 }; 248 argc -= optind; 249 argv += optind; 250 grphead = (struct grouplist *)NULL; 251 exphead = (struct exportlist *)NULL; 252 mlhead = (struct mountlist *)NULL; 253 if (argc == 1) { 254 strncpy(exname, *argv, MAXPATHLEN-1); 255 exname[MAXPATHLEN-1] = '\0'; 256 } else 257 strcpy(exname, _PATH_EXPORTS); 258 openlog("mountd", LOG_PID, LOG_DAEMON); 259 if (debug) 260 fprintf(stderr,"Getting export list.\n"); 261 get_exportlist(); 262 if (debug) 263 fprintf(stderr,"Getting mount list.\n"); 264 get_mountlist(); 265 if (debug) 266 fprintf(stderr,"Here we go.\n"); 267 if (debug == 0) { 268 daemon(0, 0); 269 signal(SIGINT, SIG_IGN); 270 signal(SIGQUIT, SIG_IGN); 271 } 272 signal(SIGHUP, (void (*) __P((int))) get_exportlist); 273 signal(SIGTERM, (void (*) __P((int))) send_umntall); 274 { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 275 if (pidfile != NULL) { 276 fprintf(pidfile, "%d\n", getpid()); 277 fclose(pidfile); 278 } 279 } 280 if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { 281 syslog(LOG_ERR, "Can't create socket"); 282 exit(1); 283 } 284 pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 285 if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 286 IPPROTO_UDP)) { 287 syslog(LOG_ERR, "Can't register mount"); 288 exit(1); 289 } 290 svc_run(); 291 syslog(LOG_ERR, "Mountd died"); 292 exit(1); 293} 294 295/* 296 * The mount rpc service 297 */ 298void 299mntsrv(rqstp, transp) 300 struct svc_req *rqstp; 301 SVCXPRT *transp; 302{ 303 struct exportlist *ep; 304 struct dirlist *dp; 305 nfsv2fh_t nfh; 306 struct authunix_parms *ucr; 307 struct stat stb; 308 struct statfs fsb; 309 struct hostent *hp; 310 u_long saddr; 311 char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; 312 int bad = ENOENT, omask, defset; 313 uid_t uid = -2; 314 315 /* Get authorization */ 316 switch (rqstp->rq_cred.oa_flavor) { 317 case AUTH_UNIX: 318 ucr = (struct authunix_parms *)rqstp->rq_clntcred; 319 uid = ucr->aup_uid; 320 break; 321 case AUTH_NULL: 322 default: 323 break; 324 } 325 326 saddr = transp->xp_raddr.sin_addr.s_addr; 327 hp = (struct hostent *)NULL; 328 switch (rqstp->rq_proc) { 329 case NULLPROC: 330 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 331 syslog(LOG_ERR, "Can't send reply"); 332 return; 333 case RPCMNT_MOUNT: 334 if ((uid != 0 && root_only) || uid == -2) { 335 svcerr_weakauth(transp); 336 return; 337 } 338 if (!svc_getargs(transp, xdr_dir, rpcpath)) { 339 svcerr_decode(transp); 340 return; 341 } 342 343 /* 344 * Get the real pathname and make sure it is a directory 345 * that exists. 346 */ 347 if (realpath(rpcpath, dirpath) == 0 || 348 stat(dirpath, &stb) < 0 || 349 (stb.st_mode & S_IFMT) != S_IFDIR || 350 statfs(dirpath, &fsb) < 0) { 351 chdir("/"); /* Just in case realpath doesn't */ 352 if (debug) 353 fprintf(stderr, "stat failed on %s\n", dirpath); 354 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 355 syslog(LOG_ERR, "Can't send reply"); 356 return; 357 } 358 359 /* Check in the exports list */ 360 omask = sigblock(sigmask(SIGHUP)); 361 ep = ex_search(&fsb.f_fsid); 362 defset = 0; 363 if (ep && (chk_host(ep->ex_defdir, saddr, &defset) || 364 ((dp = dirp_search(ep->ex_dirl, dirpath)) && 365 chk_host(dp, saddr, &defset)) || 366 (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 367 scan_tree(ep->ex_dirl, saddr) == 0))) { 368 /* Get the file handle */ 369 bzero((caddr_t)&nfh, sizeof(nfh)); 370 if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { 371 bad = errno; 372 syslog(LOG_ERR, "Can't get fh for %s", dirpath); 373 if (!svc_sendreply(transp, xdr_long, 374 (caddr_t)&bad)) 375 syslog(LOG_ERR, "Can't send reply"); 376 sigsetmask(omask); 377 return; 378 } 379 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) 380 syslog(LOG_ERR, "Can't send reply"); 381 if (hp == NULL) 382 hp = gethostbyaddr((caddr_t)&saddr, 383 sizeof(saddr), AF_INET); 384 if (hp) 385 add_mlist(hp->h_name, dirpath); 386 else 387 add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 388 dirpath); 389 if (debug) 390 fprintf(stderr,"Mount successfull.\n"); 391 } else { 392 bad = EACCES; 393 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 394 syslog(LOG_ERR, "Can't send reply"); 395 } 396 sigsetmask(omask); 397 return; 398 case RPCMNT_DUMP: 399 if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) 400 syslog(LOG_ERR, "Can't send reply"); 401 return; 402 case RPCMNT_UMOUNT: 403 if ((uid != 0 && root_only) || uid == -2) { 404 svcerr_weakauth(transp); 405 return; 406 } 407 if (!svc_getargs(transp, xdr_dir, dirpath)) { 408 svcerr_decode(transp); 409 return; 410 } 411 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 412 syslog(LOG_ERR, "Can't send reply"); 413 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 414 if (hp) 415 del_mlist(hp->h_name, dirpath); 416 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 417 return; 418 case RPCMNT_UMNTALL: 419 if ((uid != 0 && root_only) || uid == -2) { 420 svcerr_weakauth(transp); 421 return; 422 } 423 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 424 syslog(LOG_ERR, "Can't send reply"); 425 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 426 if (hp) 427 del_mlist(hp->h_name, (char *)NULL); 428 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL); 429 return; 430 case RPCMNT_EXPORT: 431 if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) 432 syslog(LOG_ERR, "Can't send reply"); 433 return; 434 default: 435 svcerr_noproc(transp); 436 return; 437 } 438} 439 440/* 441 * Xdr conversion for a dirpath string 442 */ 443int 444xdr_dir(xdrsp, dirp) 445 XDR *xdrsp; 446 char *dirp; 447{ 448 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 449} 450 451/* 452 * Xdr routine to generate fhstatus 453 */ 454int 455xdr_fhs(xdrsp, nfh) 456 XDR *xdrsp; 457 nfsv2fh_t *nfh; 458{ 459 int ok = 0; 460 461 if (!xdr_long(xdrsp, &ok)) 462 return (0); 463 return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); 464} 465 466int 467xdr_mlist(xdrsp, cp) 468 XDR *xdrsp; 469 caddr_t cp; 470{ 471 struct mountlist *mlp; 472 int true = 1; 473 int false = 0; 474 char *strp; 475 476 mlp = mlhead; 477 while (mlp) { 478 if (!xdr_bool(xdrsp, &true)) 479 return (0); 480 strp = &mlp->ml_host[0]; 481 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 482 return (0); 483 strp = &mlp->ml_dirp[0]; 484 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 485 return (0); 486 mlp = mlp->ml_next; 487 } 488 if (!xdr_bool(xdrsp, &false)) 489 return (0); 490 return (1); 491} 492 493/* 494 * Xdr conversion for export list 495 */ 496int 497xdr_explist(xdrsp, cp) 498 XDR *xdrsp; 499 caddr_t cp; 500{ 501 struct exportlist *ep; 502 int false = 0; 503 int omask, putdef; 504 505 omask = sigblock(sigmask(SIGHUP)); 506 ep = exphead; 507 while (ep) { 508 putdef = 0; 509 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 510 goto errout; 511 if (ep->ex_defdir && putdef == 0 && 512 put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 513 &putdef)) 514 goto errout; 515 ep = ep->ex_next; 516 } 517 sigsetmask(omask); 518 if (!xdr_bool(xdrsp, &false)) 519 return (0); 520 return (1); 521errout: 522 sigsetmask(omask); 523 return (0); 524} 525 526/* 527 * Called from xdr_explist() to traverse the tree and export the 528 * directory paths. 529 */ 530int 531put_exlist(dp, xdrsp, adp, putdefp) 532 struct dirlist *dp; 533 XDR *xdrsp; 534 struct dirlist *adp; 535 int *putdefp; 536{ 537 struct grouplist *grp; 538 struct hostlist *hp; 539 int true = 1; 540 int false = 0; 541 int gotalldir = 0; 542 char *strp; 543 544 if (dp) { 545 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 546 return (1); 547 if (!xdr_bool(xdrsp, &true)) 548 return (1); 549 strp = dp->dp_dirp; 550 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 551 return (1); 552 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 553 gotalldir = 1; 554 *putdefp = 1; 555 } 556 if ((dp->dp_flag & DP_DEFSET) == 0 && 557 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 558 hp = dp->dp_hosts; 559 while (hp) { 560 grp = hp->ht_grp; 561 if (grp->gr_type == GT_HOST) { 562 if (!xdr_bool(xdrsp, &true)) 563 return (1); 564 strp = grp->gr_ptr.gt_hostent->h_name; 565 if (!xdr_string(xdrsp, &strp, 566 RPCMNT_NAMELEN)) 567 return (1); 568 } else if (grp->gr_type == GT_NET) { 569 if (!xdr_bool(xdrsp, &true)) 570 return (1); 571 strp = grp->gr_ptr.gt_net.nt_name; 572 if (!xdr_string(xdrsp, &strp, 573 RPCMNT_NAMELEN)) 574 return (1); 575 } 576 hp = hp->ht_next; 577 if (gotalldir && hp == (struct hostlist *)NULL) { 578 hp = adp->dp_hosts; 579 gotalldir = 0; 580 } 581 } 582 } 583 if (!xdr_bool(xdrsp, &false)) 584 return (1); 585 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 586 return (1); 587 } 588 return (0); 589} 590 591#define LINESIZ 10240 592char line[LINESIZ]; 593FILE *exp_file; 594 595/* 596 * Get the export list 597 */ 598void 599get_exportlist() 600{ 601 struct exportlist *ep, *ep2; 602 struct grouplist *grp, *tgrp; 603 struct exportlist **epp; 604 struct dirlist *dirhead; 605 struct statfs fsb, *fsp; 606 struct hostent *hpe; 607 struct ucred anon; 608 char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 609 int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 610 611 /* 612 * First, get rid of the old list 613 */ 614 ep = exphead; 615 while (ep) { 616 ep2 = ep; 617 ep = ep->ex_next; 618 free_exp(ep2); 619 } 620 exphead = (struct exportlist *)NULL; 621 622 grp = grphead; 623 while (grp) { 624 tgrp = grp; 625 grp = grp->gr_next; 626 free_grp(tgrp); 627 } 628 grphead = (struct grouplist *)NULL; 629 630 /* 631 * And delete exports that are in the kernel for all local 632 * file systems. 633 * XXX: Should know how to handle all local exportable file systems 634 * instead of just MOUNT_UFS. 635 */ 636 num = getmntinfo(&fsp, MNT_NOWAIT); 637 for (i = 0; i < num; i++) { 638 union { 639 struct ufs_args ua; 640 struct iso_args ia; 641 struct mfs_args ma; 642 } targs; 643 644 switch (fsp->f_type) { 645 case MOUNT_MFS: 646 case MOUNT_UFS: 647 case MOUNT_CD9660: 648 case MOUNT_MSDOS: 649 targs.ua.fspec = NULL; 650 targs.ua.export.ex_flags = MNT_DELEXPORT; 651 if (mount(fsp->f_type, fsp->f_mntonname, 652 fsp->f_flags | MNT_UPDATE, 653 (caddr_t)&targs) < 0) 654 syslog(LOG_ERR, "Can't delete exports for %s", 655 fsp->f_mntonname); 656 } 657 fsp++; 658 } 659 660 /* 661 * Read in the exports file and build the list, calling 662 * mount() as we go along to push the export rules into the kernel. 663 */ 664 if ((exp_file = fopen(exname, "r")) == NULL) { 665 syslog(LOG_ERR, "Can't open %s", exname); 666 exit(2); 667 } 668 dirhead = (struct dirlist *)NULL; 669 while (get_line()) { 670 if (debug) 671 fprintf(stderr,"Got line %s\n",line); 672 cp = line; 673 nextfield(&cp, &endcp); 674 if (*cp == '#') 675 goto nextline; 676 677 /* 678 * Set defaults. 679 */ 680 has_host = FALSE; 681 anon = def_anon; 682 exflags = MNT_EXPORTED; 683 got_nondir = 0; 684 opt_flags = 0; 685 ep = (struct exportlist *)NULL; 686 687 /* 688 * Create new exports list entry 689 */ 690 len = endcp-cp; 691 tgrp = grp = get_grp(); 692 while (len > 0) { 693 if (len > RPCMNT_NAMELEN) { 694 getexp_err(ep, tgrp); 695 goto nextline; 696 } 697 if (*cp == '-') { 698 if (ep == (struct exportlist *)NULL) { 699 getexp_err(ep, tgrp); 700 goto nextline; 701 } 702 if (debug) 703 fprintf(stderr, "doing opt %s\n", cp); 704 got_nondir = 1; 705 if (do_opt(&cp, &endcp, ep, grp, &has_host, 706 &exflags, &anon)) { 707 getexp_err(ep, tgrp); 708 goto nextline; 709 } 710 } else if (*cp == '/') { 711 savedc = *endcp; 712 *endcp = '\0'; 713 if (check_dirpath(cp) && 714 statfs(cp, &fsb) >= 0) { 715 if (got_nondir) { 716 syslog(LOG_ERR, "Dirs must be first"); 717 getexp_err(ep, tgrp); 718 goto nextline; 719 } 720 if (ep) { 721 if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 722 ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 723 getexp_err(ep, tgrp); 724 goto nextline; 725 } 726 } else { 727 /* 728 * See if this directory is already 729 * in the list. 730 */ 731 ep = ex_search(&fsb.f_fsid); 732 if (ep == (struct exportlist *)NULL) { 733 ep = get_exp(); 734 ep->ex_fs = fsb.f_fsid; 735 ep->ex_fsdir = (char *) 736 malloc(strlen(fsb.f_mntonname) + 1); 737 if (ep->ex_fsdir) 738 strcpy(ep->ex_fsdir, 739 fsb.f_mntonname); 740 else 741 out_of_mem(); 742 if (debug) 743 fprintf(stderr, 744 "Making new ep fs=0x%x,0x%x\n", 745 fsb.f_fsid.val[0], 746 fsb.f_fsid.val[1]); 747 } else if (debug) 748 fprintf(stderr, 749 "Found ep fs=0x%x,0x%x\n", 750 fsb.f_fsid.val[0], 751 fsb.f_fsid.val[1]); 752 } 753 754 /* 755 * Add dirpath to export mount point. 756 */ 757 dirp = add_expdir(&dirhead, cp, len); 758 dirplen = len; 759 } else { 760 getexp_err(ep, tgrp); 761 goto nextline; 762 } 763 *endcp = savedc; 764 } else { 765 savedc = *endcp; 766 *endcp = '\0'; 767 got_nondir = 1; 768 if (ep == (struct exportlist *)NULL) { 769 getexp_err(ep, tgrp); 770 goto nextline; 771 } 772 773 /* 774 * Get the host or netgroup. 775 */ 776 setnetgrent(cp); 777 netgrp = getnetgrent(&hst, &usr, &dom); 778 do { 779 if (has_host) { 780 grp->gr_next = get_grp(); 781 grp = grp->gr_next; 782 } 783 if (netgrp) { 784 if (get_host(hst, grp)) { 785 syslog(LOG_ERR, "Bad netgroup %s", cp); 786 getexp_err(ep, tgrp); 787 goto nextline; 788 } 789 } else if (get_host(cp, grp)) { 790 getexp_err(ep, tgrp); 791 goto nextline; 792 } 793 has_host = TRUE; 794 } while (netgrp && getnetgrent(&hst, &usr, &dom)); 795 endnetgrent(); 796 *endcp = savedc; 797 } 798 cp = endcp; 799 nextfield(&cp, &endcp); 800 len = endcp - cp; 801 } 802 if (check_options(dirhead)) { 803 getexp_err(ep, tgrp); 804 goto nextline; 805 } 806 if (!has_host) { 807 grp->gr_type = GT_HOST; 808 if (debug) 809 fprintf(stderr,"Adding a default entry\n"); 810 /* add a default group and make the grp list NULL */ 811 hpe = (struct hostent *)malloc(sizeof(struct hostent)); 812 if (hpe == (struct hostent *)NULL) 813 out_of_mem(); 814 hpe->h_name = "Default"; 815 hpe->h_addrtype = AF_INET; 816 hpe->h_length = sizeof (u_long); 817 hpe->h_addr_list = (char **)NULL; 818 grp->gr_ptr.gt_hostent = hpe; 819 820 /* 821 * Don't allow a network export coincide with a list of 822 * host(s) on the same line. 823 */ 824 } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 825 getexp_err(ep, tgrp); 826 goto nextline; 827 } 828 829 /* 830 * Loop through hosts, pushing the exports into the kernel. 831 * After loop, tgrp points to the start of the list and 832 * grp points to the last entry in the list. 833 */ 834 grp = tgrp; 835 do { 836 if (do_mount(ep, grp, exflags, &anon, dirp, 837 dirplen, &fsb)) { 838 getexp_err(ep, tgrp); 839 goto nextline; 840 } 841 } while (grp->gr_next && (grp = grp->gr_next)); 842 843 /* 844 * Success. Update the data structures. 845 */ 846 if (has_host) { 847 hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS)); 848 grp->gr_next = grphead; 849 grphead = tgrp; 850 } else { 851 hang_dirp(dirhead, (struct grouplist *)NULL, ep, 852 (opt_flags & OP_ALLDIRS)); 853 free_grp(grp); 854 } 855 dirhead = (struct dirlist *)NULL; 856 if ((ep->ex_flag & EX_LINKED) == 0) { 857 ep2 = exphead; 858 epp = &exphead; 859 860 /* 861 * Insert in the list in alphabetical order. 862 */ 863 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 864 epp = &ep2->ex_next; 865 ep2 = ep2->ex_next; 866 } 867 if (ep2) 868 ep->ex_next = ep2; 869 *epp = ep; 870 ep->ex_flag |= EX_LINKED; 871 } 872nextline: 873 if (dirhead) { 874 free_dir(dirhead); 875 dirhead = (struct dirlist *)NULL; 876 } 877 } 878 fclose(exp_file); 879} 880 881/* 882 * Allocate an export list element 883 */ 884struct exportlist * 885get_exp() 886{ 887 struct exportlist *ep; 888 889 ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 890 if (ep == (struct exportlist *)NULL) 891 out_of_mem(); 892 bzero((caddr_t)ep, sizeof (struct exportlist)); 893 return (ep); 894} 895 896/* 897 * Allocate a group list element 898 */ 899struct grouplist * 900get_grp() 901{ 902 struct grouplist *gp; 903 904 gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 905 if (gp == (struct grouplist *)NULL) 906 out_of_mem(); 907 bzero((caddr_t)gp, sizeof (struct grouplist)); 908 return (gp); 909} 910 911/* 912 * Clean up upon an error in get_exportlist(). 913 */ 914void 915getexp_err(ep, grp) 916 struct exportlist *ep; 917 struct grouplist *grp; 918{ 919 struct grouplist *tgrp; 920 921 syslog(LOG_ERR, "Bad exports list line %s", line); 922 if (ep && (ep->ex_flag & EX_LINKED) == 0) 923 free_exp(ep); 924 while (grp) { 925 tgrp = grp; 926 grp = grp->gr_next; 927 free_grp(tgrp); 928 } 929} 930 931/* 932 * Search the export list for a matching fs. 933 */ 934struct exportlist * 935ex_search(fsid) 936 fsid_t *fsid; 937{ 938 struct exportlist *ep; 939 940 ep = exphead; 941 while (ep) { 942 if (ep->ex_fs.val[0] == fsid->val[0] && 943 ep->ex_fs.val[1] == fsid->val[1]) 944 return (ep); 945 ep = ep->ex_next; 946 } 947 return (ep); 948} 949 950/* 951 * Add a directory path to the list. 952 */ 953char * 954add_expdir(dpp, cp, len) 955 struct dirlist **dpp; 956 char *cp; 957 int len; 958{ 959 struct dirlist *dp; 960 961 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 962 dp->dp_left = *dpp; 963 dp->dp_right = (struct dirlist *)NULL; 964 dp->dp_flag = 0; 965 dp->dp_hosts = (struct hostlist *)NULL; 966 strcpy(dp->dp_dirp, cp); 967 *dpp = dp; 968 return (dp->dp_dirp); 969} 970 971/* 972 * Hang the dir list element off the dirpath binary tree as required 973 * and update the entry for host. 974 */ 975void 976hang_dirp(dp, grp, ep, alldirs) 977 struct dirlist *dp; 978 struct grouplist *grp; 979 struct exportlist *ep; 980 int alldirs; 981{ 982 struct hostlist *hp; 983 struct dirlist *dp2; 984 985 if (alldirs) { 986 if (ep->ex_defdir) 987 free((caddr_t)dp); 988 else 989 ep->ex_defdir = dp; 990 if (grp == (struct grouplist *)NULL) 991 ep->ex_defdir->dp_flag |= DP_DEFSET; 992 else while (grp) { 993 hp = get_ht(); 994 hp->ht_grp = grp; 995 hp->ht_next = ep->ex_defdir->dp_hosts; 996 ep->ex_defdir->dp_hosts = hp; 997 grp = grp->gr_next; 998 } 999 } else { 1000 1001 /* 1002 * Loop throught the directories adding them to the tree. 1003 */ 1004 while (dp) { 1005 dp2 = dp->dp_left; 1006 add_dlist(&ep->ex_dirl, dp, grp); 1007 dp = dp2; 1008 } 1009 } 1010} 1011 1012/* 1013 * Traverse the binary tree either updating a node that is already there 1014 * for the new directory or adding the new node. 1015 */ 1016void 1017add_dlist(dpp, newdp, grp) 1018 struct dirlist **dpp; 1019 struct dirlist *newdp; 1020 struct grouplist *grp; 1021{ 1022 struct dirlist *dp; 1023 struct hostlist *hp; 1024 int cmp; 1025 1026 dp = *dpp; 1027 if (dp) { 1028 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1029 if (cmp > 0) { 1030 add_dlist(&dp->dp_left, newdp, grp); 1031 return; 1032 } else if (cmp < 0) { 1033 add_dlist(&dp->dp_right, newdp, grp); 1034 return; 1035 } else 1036 free((caddr_t)newdp); 1037 } else { 1038 dp = newdp; 1039 dp->dp_left = (struct dirlist *)NULL; 1040 *dpp = dp; 1041 } 1042 if (grp) { 1043 1044 /* 1045 * Hang all of the host(s) off of the directory point. 1046 */ 1047 do { 1048 hp = get_ht(); 1049 hp->ht_grp = grp; 1050 hp->ht_next = dp->dp_hosts; 1051 dp->dp_hosts = hp; 1052 grp = grp->gr_next; 1053 } while (grp); 1054 } else 1055 dp->dp_flag |= DP_DEFSET; 1056} 1057 1058/* 1059 * Search for a dirpath on the export point. 1060 */ 1061struct dirlist * 1062dirp_search(dp, dirpath) 1063 struct dirlist *dp; 1064 char *dirpath; 1065{ 1066 int cmp; 1067 1068 if (dp) { 1069 cmp = strcmp(dp->dp_dirp, dirpath); 1070 if (cmp > 0) 1071 return (dirp_search(dp->dp_left, dirpath)); 1072 else if (cmp < 0) 1073 return (dirp_search(dp->dp_right, dirpath)); 1074 else 1075 return (dp); 1076 } 1077 return (dp); 1078} 1079 1080/* 1081 * Scan for a host match in a directory tree. 1082 */ 1083int 1084chk_host(dp, saddr, defsetp) 1085 struct dirlist *dp; 1086 u_long saddr; 1087 int *defsetp; 1088{ 1089 struct hostlist *hp; 1090 struct grouplist *grp; 1091 u_long **addrp; 1092 1093 if (dp) { 1094 if (dp->dp_flag & DP_DEFSET) 1095 *defsetp = 1; 1096 hp = dp->dp_hosts; 1097 while (hp) { 1098 grp = hp->ht_grp; 1099 switch (grp->gr_type) { 1100 case GT_HOST: 1101 addrp = (u_long **) 1102 grp->gr_ptr.gt_hostent->h_addr_list; 1103 while (*addrp) { 1104 if (**addrp == saddr) 1105 return (1); 1106 addrp++; 1107 } 1108 break; 1109 case GT_NET: 1110 if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 1111 grp->gr_ptr.gt_net.nt_net) 1112 return (1); 1113 break; 1114 }; 1115 hp = hp->ht_next; 1116 } 1117 } 1118 return (0); 1119} 1120 1121/* 1122 * Scan tree for a host that matches the address. 1123 */ 1124int 1125scan_tree(dp, saddr) 1126 struct dirlist *dp; 1127 u_long saddr; 1128{ 1129 int defset; 1130 1131 if (dp) { 1132 if (scan_tree(dp->dp_left, saddr)) 1133 return (1); 1134 if (chk_host(dp, saddr, &defset)) 1135 return (1); 1136 if (scan_tree(dp->dp_right, saddr)) 1137 return (1); 1138 } 1139 return (0); 1140} 1141 1142/* 1143 * Traverse the dirlist tree and free it up. 1144 */ 1145void 1146free_dir(dp) 1147 struct dirlist *dp; 1148{ 1149 1150 if (dp) { 1151 free_dir(dp->dp_left); 1152 free_dir(dp->dp_right); 1153 free_host(dp->dp_hosts); 1154 free((caddr_t)dp); 1155 } 1156} 1157 1158/* 1159 * Parse the option string and update fields. 1160 * Option arguments may either be -<option>=<value> or 1161 * -<option> <value> 1162 */ 1163int 1164do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1165 char **cpp, **endcpp; 1166 struct exportlist *ep; 1167 struct grouplist *grp; 1168 int *has_hostp; 1169 int *exflagsp; 1170 struct ucred *cr; 1171{ 1172 char *cpoptarg, *cpoptend; 1173 char *cp, *endcp, *cpopt, savedc, savedc2; 1174 int allflag, usedarg; 1175 1176 cpopt = *cpp; 1177 cpopt++; 1178 cp = *endcpp; 1179 savedc = *cp; 1180 *cp = '\0'; 1181 while (cpopt && *cpopt) { 1182 allflag = 1; 1183 usedarg = -2; 1184 if (cpoptend = index(cpopt, ',')) { 1185 *cpoptend++ = '\0'; 1186 if (cpoptarg = index(cpopt, '=')) 1187 *cpoptarg++ = '\0'; 1188 } else { 1189 if (cpoptarg = index(cpopt, '=')) 1190 *cpoptarg++ = '\0'; 1191 else { 1192 *cp = savedc; 1193 nextfield(&cp, &endcp); 1194 **endcpp = '\0'; 1195 if (endcp > cp && *cp != '-') { 1196 cpoptarg = cp; 1197 savedc2 = *endcp; 1198 *endcp = '\0'; 1199 usedarg = 0; 1200 } 1201 } 1202 } 1203 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1204 *exflagsp |= MNT_EXRDONLY; 1205 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1206 !(allflag = strcmp(cpopt, "mapall")) || 1207 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1208 usedarg++; 1209 parsecred(cpoptarg, cr); 1210 if (allflag == 0) { 1211 *exflagsp |= MNT_EXPORTANON; 1212 opt_flags |= OP_MAPALL; 1213 } else 1214 opt_flags |= OP_MAPROOT; 1215 } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 1216 *exflagsp |= MNT_EXKERB; 1217 opt_flags |= OP_KERB; 1218 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1219 !strcmp(cpopt, "m"))) { 1220 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1221 syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 1222 return (1); 1223 } 1224 usedarg++; 1225 opt_flags |= OP_MASK; 1226 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1227 !strcmp(cpopt, "n"))) { 1228 if (grp->gr_type != GT_NULL) { 1229 syslog(LOG_ERR, "Network/host conflict"); 1230 return (1); 1231 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1232 syslog(LOG_ERR, "Bad net: %s", cpoptarg); 1233 return (1); 1234 } 1235 grp->gr_type = GT_NET; 1236 *has_hostp = 1; 1237 usedarg++; 1238 opt_flags |= OP_NET; 1239 } else if (!strcmp(cpopt, "alldirs")) { 1240 opt_flags |= OP_ALLDIRS; 1241#ifdef ISO 1242 } else if (cpoptarg && !strcmp(cpopt, "iso")) { 1243 if (get_isoaddr(cpoptarg, grp)) { 1244 syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 1245 return (1); 1246 } 1247 *has_hostp = 1; 1248 usedarg++; 1249 opt_flags |= OP_ISO; 1250#endif /* ISO */ 1251 } else { 1252 syslog(LOG_ERR, "Bad opt %s", cpopt); 1253 return (1); 1254 } 1255 if (usedarg >= 0) { 1256 *endcp = savedc2; 1257 **endcpp = savedc; 1258 if (usedarg > 0) { 1259 *cpp = cp; 1260 *endcpp = endcp; 1261 } 1262 return (0); 1263 } 1264 cpopt = cpoptend; 1265 } 1266 **endcpp = savedc; 1267 return (0); 1268} 1269 1270/* 1271 * Translate a character string to the corresponding list of network 1272 * addresses for a hostname. 1273 */ 1274int 1275get_host(cp, grp) 1276 char *cp; 1277 struct grouplist *grp; 1278{ 1279 struct hostent *hp, *nhp; 1280 char **addrp, **naddrp; 1281 struct hostent t_host; 1282 int i; 1283 u_long saddr; 1284 char *aptr[2]; 1285 1286 if (grp->gr_type != GT_NULL) 1287 return (1); 1288 if ((hp = gethostbyname(cp)) == NULL) { 1289 if (isdigit(*cp)) { 1290 saddr = inet_addr(cp); 1291 if (saddr == -1) { 1292 syslog(LOG_ERR, "Inet_addr failed"); 1293 return (1); 1294 } 1295 if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 1296 AF_INET)) == NULL) { 1297 hp = &t_host; 1298 hp->h_name = cp; 1299 hp->h_addrtype = AF_INET; 1300 hp->h_length = sizeof (u_long); 1301 hp->h_addr_list = aptr; 1302 aptr[0] = (char *)&saddr; 1303 aptr[1] = (char *)NULL; 1304 } 1305 } else { 1306 syslog(LOG_ERR, "Gethostbyname failed"); 1307 return (1); 1308 } 1309 } 1310 grp->gr_type = GT_HOST; 1311 nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 1312 malloc(sizeof(struct hostent)); 1313 if (nhp == (struct hostent *)NULL) 1314 out_of_mem(); 1315 bcopy((caddr_t)hp, (caddr_t)nhp, 1316 sizeof(struct hostent)); 1317 i = strlen(hp->h_name)+1; 1318 nhp->h_name = (char *)malloc(i); 1319 if (nhp->h_name == (char *)NULL) 1320 out_of_mem(); 1321 bcopy(hp->h_name, nhp->h_name, i); 1322 addrp = hp->h_addr_list; 1323 i = 1; 1324 while (*addrp++) 1325 i++; 1326 naddrp = nhp->h_addr_list = (char **) 1327 malloc(i*sizeof(char *)); 1328 if (naddrp == (char **)NULL) 1329 out_of_mem(); 1330 addrp = hp->h_addr_list; 1331 while (*addrp) { 1332 *naddrp = (char *) 1333 malloc(hp->h_length); 1334 if (*naddrp == (char *)NULL) 1335 out_of_mem(); 1336 bcopy(*addrp, *naddrp, 1337 hp->h_length); 1338 addrp++; 1339 naddrp++; 1340 } 1341 *naddrp = (char *)NULL; 1342 if (debug) 1343 fprintf(stderr, "got host %s\n", hp->h_name); 1344 return (0); 1345} 1346 1347/* 1348 * Free up an exports list component 1349 */ 1350void 1351free_exp(ep) 1352 struct exportlist *ep; 1353{ 1354 1355 if (ep->ex_defdir) { 1356 free_host(ep->ex_defdir->dp_hosts); 1357 free((caddr_t)ep->ex_defdir); 1358 } 1359 if (ep->ex_fsdir) 1360 free(ep->ex_fsdir); 1361 free_dir(ep->ex_dirl); 1362 free((caddr_t)ep); 1363} 1364 1365/* 1366 * Free hosts. 1367 */ 1368void 1369free_host(hp) 1370 struct hostlist *hp; 1371{ 1372 struct hostlist *hp2; 1373 1374 while (hp) { 1375 hp2 = hp; 1376 hp = hp->ht_next; 1377 free((caddr_t)hp2); 1378 } 1379} 1380 1381struct hostlist * 1382get_ht() 1383{ 1384 struct hostlist *hp; 1385 1386 hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 1387 if (hp == (struct hostlist *)NULL) 1388 out_of_mem(); 1389 hp->ht_next = (struct hostlist *)NULL; 1390 return (hp); 1391} 1392 1393#ifdef ISO 1394/* 1395 * Translate an iso address. 1396 */ 1397get_isoaddr(cp, grp) 1398 char *cp; 1399 struct grouplist *grp; 1400{ 1401 struct iso_addr *isop; 1402 struct sockaddr_iso *isoaddr; 1403 1404 if (grp->gr_type != GT_NULL) 1405 return (1); 1406 if ((isop = iso_addr(cp)) == NULL) { 1407 syslog(LOG_ERR, 1408 "iso_addr failed, ignored"); 1409 return (1); 1410 } 1411 isoaddr = (struct sockaddr_iso *) 1412 malloc(sizeof (struct sockaddr_iso)); 1413 if (isoaddr == (struct sockaddr_iso *)NULL) 1414 out_of_mem(); 1415 bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 1416 bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 1417 sizeof (struct iso_addr)); 1418 isoaddr->siso_len = sizeof (struct sockaddr_iso); 1419 isoaddr->siso_family = AF_ISO; 1420 grp->gr_type = GT_ISO; 1421 grp->gr_ptr.gt_isoaddr = isoaddr; 1422 return (0); 1423} 1424#endif /* ISO */ 1425 1426/* 1427 * Out of memory, fatal 1428 */ 1429void 1430out_of_mem() 1431{ 1432 1433 syslog(LOG_ERR, "Out of memory"); 1434 exit(2); 1435} 1436 1437/* 1438 * Do the mount syscall with the update flag to push the export info into 1439 * the kernel. 1440 */ 1441int 1442do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 1443 struct exportlist *ep; 1444 struct grouplist *grp; 1445 int exflags; 1446 struct ucred *anoncrp; 1447 char *dirp; 1448 int dirplen; 1449 struct statfs *fsb; 1450{ 1451 char *cp = (char *)NULL; 1452 u_long **addrp; 1453 int done; 1454 char savedc = '\0'; 1455 struct sockaddr_in sin, imask; 1456 union { 1457 struct ufs_args ua; 1458 struct iso_args ia; 1459 struct mfs_args ma; 1460 } args; 1461 u_long net; 1462 1463 args.ua.fspec = 0; 1464 args.ua.export.ex_flags = exflags; 1465 args.ua.export.ex_anon = *anoncrp; 1466 bzero((char *)&sin, sizeof(sin)); 1467 bzero((char *)&imask, sizeof(imask)); 1468 sin.sin_family = AF_INET; 1469 sin.sin_len = sizeof(sin); 1470 imask.sin_family = AF_INET; 1471 imask.sin_len = sizeof(sin); 1472 if (grp->gr_type == GT_HOST) 1473 addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 1474 else 1475 addrp = (u_long **)NULL; 1476 done = FALSE; 1477 while (!done) { 1478 switch (grp->gr_type) { 1479 case GT_HOST: 1480 if (addrp) { 1481 sin.sin_addr.s_addr = **addrp; 1482 args.ua.export.ex_addrlen = sizeof(sin); 1483 } else 1484 args.ua.export.ex_addrlen = 0; 1485 args.ua.export.ex_addr = (struct sockaddr *)&sin; 1486 args.ua.export.ex_masklen = 0; 1487 break; 1488 case GT_NET: 1489 if (grp->gr_ptr.gt_net.nt_mask) 1490 imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 1491 else { 1492 net = ntohl(grp->gr_ptr.gt_net.nt_net); 1493 if (IN_CLASSA(net)) 1494 imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 1495 else if (IN_CLASSB(net)) 1496 imask.sin_addr.s_addr = 1497 inet_addr("255.255.0.0"); 1498 else 1499 imask.sin_addr.s_addr = 1500 inet_addr("255.255.255.0"); 1501 grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 1502 } 1503 sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 1504 args.ua.export.ex_addr = (struct sockaddr *)&sin; 1505 args.ua.export.ex_addrlen = sizeof (sin); 1506 args.ua.export.ex_mask = (struct sockaddr *)&imask; 1507 args.ua.export.ex_masklen = sizeof (imask); 1508 break; 1509#ifdef ISO 1510 case GT_ISO: 1511 args.ua.export.ex_addr = 1512 (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 1513 args.ua.export.ex_addrlen = 1514 sizeof(struct sockaddr_iso); 1515 args.ua.export.ex_masklen = 0; 1516 break; 1517#endif /* ISO */ 1518 default: 1519 syslog(LOG_ERR, "Bad grouptype"); 1520 if (cp) 1521 *cp = savedc; 1522 return (1); 1523 }; 1524 1525 /* 1526 * XXX: 1527 * Maybe I should just use the fsb->f_mntonname path instead 1528 * of looping back up the dirp to the mount point?? 1529 * Also, needs to know how to export all types of local 1530 * exportable file systems and not just MOUNT_UFS. 1531 */ 1532 while (mount(fsb->f_type, dirp, 1533 fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 1534 if (cp) 1535 *cp-- = savedc; 1536 else 1537 cp = dirp + dirplen - 1; 1538 if (errno == EPERM) { 1539 syslog(LOG_ERR, 1540 "Can't change attributes for %s.\n", dirp); 1541 return (1); 1542 } 1543 if (opt_flags & OP_ALLDIRS) { 1544 syslog(LOG_ERR, "Not root dir"); 1545 return (1); 1546 } 1547 /* back up over the last component */ 1548 while (*cp == '/' && cp > dirp) 1549 cp--; 1550 while (*(cp - 1) != '/' && cp > dirp) 1551 cp--; 1552 if (cp == dirp) { 1553 if (debug) 1554 fprintf(stderr,"mnt unsucc\n"); 1555 syslog(LOG_ERR, "Can't export %s", dirp); 1556 return (1); 1557 } 1558 savedc = *cp; 1559 *cp = '\0'; 1560 } 1561 if (addrp) { 1562 ++addrp; 1563 if (*addrp == (u_long *)NULL) 1564 done = TRUE; 1565 } else 1566 done = TRUE; 1567 } 1568 if (cp) 1569 *cp = savedc; 1570 return (0); 1571} 1572 1573/* 1574 * Translate a net address. 1575 */ 1576int 1577get_net(cp, net, maskflg) 1578 char *cp; 1579 struct netmsk *net; 1580 int maskflg; 1581{ 1582 struct netent *np; 1583 long netaddr; 1584 struct in_addr inetaddr, inetaddr2; 1585 char *name; 1586 1587 if (np = getnetbyname(cp)) 1588 inetaddr = inet_makeaddr(np->n_net, 0); 1589 else if (isdigit(*cp)) { 1590 if ((netaddr = inet_network(cp)) == -1) 1591 return (1); 1592 inetaddr = inet_makeaddr(netaddr, 0); 1593 /* 1594 * Due to arbritrary subnet masks, you don't know how many 1595 * bits to shift the address to make it into a network, 1596 * however you do know how to make a network address into 1597 * a host with host == 0 and then compare them. 1598 * (What a pest) 1599 */ 1600 if (!maskflg) { 1601 setnetent(0); 1602 while (np = getnetent()) { 1603 inetaddr2 = inet_makeaddr(np->n_net, 0); 1604 if (inetaddr2.s_addr == inetaddr.s_addr) 1605 break; 1606 } 1607 endnetent(); 1608 } 1609 } else 1610 return (1); 1611 if (maskflg) 1612 net->nt_mask = inetaddr.s_addr; 1613 else { 1614 if (np) 1615 name = np->n_name; 1616 else 1617 name = inet_ntoa(inetaddr); 1618 net->nt_name = (char *)malloc(strlen(name) + 1); 1619 if (net->nt_name == (char *)NULL) 1620 out_of_mem(); 1621 strcpy(net->nt_name, name); 1622 net->nt_net = inetaddr.s_addr; 1623 } 1624 return (0); 1625} 1626 1627/* 1628 * Parse out the next white space separated field 1629 */ 1630void 1631nextfield(cp, endcp) 1632 char **cp; 1633 char **endcp; 1634{ 1635 char *p; 1636 1637 p = *cp; 1638 while (*p == ' ' || *p == '\t') 1639 p++; 1640 if (*p == '\n' || *p == '\0') 1641 *cp = *endcp = p; 1642 else { 1643 *cp = p++; 1644 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 1645 p++; 1646 *endcp = p; 1647 } 1648} 1649 1650/* 1651 * Get an exports file line. Skip over blank lines and handle line 1652 * continuations. 1653 */ 1654int 1655get_line() 1656{ 1657 char *p, *cp; 1658 int len; 1659 int totlen, cont_line; 1660 1661 /* 1662 * Loop around ignoring blank lines and getting all continuation lines. 1663 */ 1664 p = line; 1665 totlen = 0; 1666 do { 1667 if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 1668 return (0); 1669 len = strlen(p); 1670 cp = p + len - 1; 1671 cont_line = 0; 1672 while (cp >= p && 1673 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 1674 if (*cp == '\\') 1675 cont_line = 1; 1676 cp--; 1677 len--; 1678 } 1679 *++cp = '\0'; 1680 if (len > 0) { 1681 totlen += len; 1682 if (totlen >= LINESIZ) { 1683 syslog(LOG_ERR, "Exports line too long"); 1684 exit(2); 1685 } 1686 p = cp; 1687 } 1688 } while (totlen == 0 || cont_line); 1689 return (1); 1690} 1691 1692/* 1693 * Parse a description of a credential. 1694 */ 1695void 1696parsecred(namelist, cr) 1697 char *namelist; 1698 struct ucred *cr; 1699{ 1700 char *name; 1701 int cnt; 1702 char *names; 1703 struct passwd *pw; 1704 struct group *gr; 1705 int ngroups, groups[NGROUPS + 1]; 1706 1707 /* 1708 * Set up the unpriviledged user. 1709 */ 1710 cr->cr_ref = 1; 1711 cr->cr_uid = -2; 1712 cr->cr_groups[0] = -2; 1713 cr->cr_ngroups = 1; 1714 /* 1715 * Get the user's password table entry. 1716 */ 1717 names = strsep(&namelist, " \t\n"); 1718 name = strsep(&names, ":"); 1719 if (isdigit(*name) || *name == '-') 1720 pw = getpwuid(atoi(name)); 1721 else 1722 pw = getpwnam(name); 1723 /* 1724 * Credentials specified as those of a user. 1725 */ 1726 if (names == NULL) { 1727 if (pw == NULL) { 1728 syslog(LOG_ERR, "Unknown user: %s", name); 1729 return; 1730 } 1731 cr->cr_uid = pw->pw_uid; 1732 ngroups = NGROUPS + 1; 1733 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 1734 syslog(LOG_ERR, "Too many groups"); 1735 /* 1736 * Convert from int's to gid_t's and compress out duplicate 1737 */ 1738 cr->cr_ngroups = ngroups - 1; 1739 cr->cr_groups[0] = groups[0]; 1740 for (cnt = 2; cnt < ngroups; cnt++) 1741 cr->cr_groups[cnt - 1] = groups[cnt]; 1742 return; 1743 } 1744 /* 1745 * Explicit credential specified as a colon separated list: 1746 * uid:gid:gid:... 1747 */ 1748 if (pw != NULL) 1749 cr->cr_uid = pw->pw_uid; 1750 else if (isdigit(*name) || *name == '-') 1751 cr->cr_uid = atoi(name); 1752 else { 1753 syslog(LOG_ERR, "Unknown user: %s", name); 1754 return; 1755 } 1756 cr->cr_ngroups = 0; 1757 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 1758 name = strsep(&names, ":"); 1759 if (isdigit(*name) || *name == '-') { 1760 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 1761 } else { 1762 if ((gr = getgrnam(name)) == NULL) { 1763 syslog(LOG_ERR, "Unknown group: %s", name); 1764 continue; 1765 } 1766 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 1767 } 1768 } 1769 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 1770 syslog(LOG_ERR, "Too many groups"); 1771} 1772 1773#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 1774/* 1775 * Routines that maintain the remote mounttab 1776 */ 1777void 1778get_mountlist() 1779{ 1780 struct mountlist *mlp, **mlpp; 1781 char *eos, *dirp; 1782 int len; 1783 char str[STRSIZ]; 1784 FILE *mlfile; 1785 1786 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 1787 syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 1788 return; 1789 } 1790 mlpp = &mlhead; 1791 while (fgets(str, STRSIZ, mlfile) != NULL) { 1792 if ((dirp = index(str, '\t')) == NULL && 1793 (dirp = index(str, ' ')) == NULL) 1794 continue; 1795 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1796 len = dirp-str; 1797 if (len > RPCMNT_NAMELEN) 1798 len = RPCMNT_NAMELEN; 1799 bcopy(str, mlp->ml_host, len); 1800 mlp->ml_host[len] = '\0'; 1801 while (*dirp == '\t' || *dirp == ' ') 1802 dirp++; 1803 if ((eos = index(dirp, '\t')) == NULL && 1804 (eos = index(dirp, ' ')) == NULL && 1805 (eos = index(dirp, '\n')) == NULL) 1806 len = strlen(dirp); 1807 else 1808 len = eos-dirp; 1809 if (len > RPCMNT_PATHLEN) 1810 len = RPCMNT_PATHLEN; 1811 bcopy(dirp, mlp->ml_dirp, len); 1812 mlp->ml_dirp[len] = '\0'; 1813 mlp->ml_next = (struct mountlist *)NULL; 1814 *mlpp = mlp; 1815 mlpp = &mlp->ml_next; 1816 } 1817 fclose(mlfile); 1818} 1819 1820void 1821del_mlist(hostp, dirp) 1822 char *hostp, *dirp; 1823{ 1824 struct mountlist *mlp, **mlpp; 1825 struct mountlist *mlp2; 1826 FILE *mlfile; 1827 int fnd = 0; 1828 1829 mlpp = &mlhead; 1830 mlp = mlhead; 1831 while (mlp) { 1832 if (!strcmp(mlp->ml_host, hostp) && 1833 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 1834 fnd = 1; 1835 mlp2 = mlp; 1836 *mlpp = mlp = mlp->ml_next; 1837 free((caddr_t)mlp2); 1838 } else { 1839 mlpp = &mlp->ml_next; 1840 mlp = mlp->ml_next; 1841 } 1842 } 1843 if (fnd) { 1844 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 1845 syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 1846 return; 1847 } 1848 mlp = mlhead; 1849 while (mlp) { 1850 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1851 mlp = mlp->ml_next; 1852 } 1853 fclose(mlfile); 1854 } 1855} 1856 1857void 1858add_mlist(hostp, dirp) 1859 char *hostp, *dirp; 1860{ 1861 struct mountlist *mlp, **mlpp; 1862 FILE *mlfile; 1863 1864 mlpp = &mlhead; 1865 mlp = mlhead; 1866 while (mlp) { 1867 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 1868 return; 1869 mlpp = &mlp->ml_next; 1870 mlp = mlp->ml_next; 1871 } 1872 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1873 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 1874 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 1875 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 1876 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 1877 mlp->ml_next = (struct mountlist *)NULL; 1878 *mlpp = mlp; 1879 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 1880 syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 1881 return; 1882 } 1883 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1884 fclose(mlfile); 1885} 1886 1887/* 1888 * This function is called via. SIGTERM when the system is going down. 1889 * It sends a broadcast RPCMNT_UMNTALL. 1890 */ 1891void 1892send_umntall() 1893{ 1894 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 1895 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 1896 exit(0); 1897} 1898 1899int 1900umntall_each(resultsp, raddr) 1901 caddr_t resultsp; 1902 struct sockaddr_in *raddr; 1903{ 1904 return (1); 1905} 1906 1907/* 1908 * Free up a group list. 1909 */ 1910void 1911free_grp(grp) 1912 struct grouplist *grp; 1913{ 1914 char **addrp; 1915 1916 if (grp->gr_type == GT_HOST) { 1917 if (grp->gr_ptr.gt_hostent->h_name) { 1918 addrp = grp->gr_ptr.gt_hostent->h_addr_list; 1919 while (addrp && *addrp) 1920 free(*addrp++); 1921 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 1922 free(grp->gr_ptr.gt_hostent->h_name); 1923 } 1924 free((caddr_t)grp->gr_ptr.gt_hostent); 1925 } else if (grp->gr_type == GT_NET) { 1926 if (grp->gr_ptr.gt_net.nt_name) 1927 free(grp->gr_ptr.gt_net.nt_name); 1928 } 1929#ifdef ISO 1930 else if (grp->gr_type == GT_ISO) 1931 free((caddr_t)grp->gr_ptr.gt_isoaddr); 1932#endif 1933 free((caddr_t)grp); 1934} 1935 1936#ifdef DEBUG 1937void 1938SYSLOG(int pri, const char *fmt, ...) 1939{ 1940 va_list ap; 1941 1942 va_start(ap, fmt); 1943 vfprintf(stderr, fmt, ap); 1944 va_end(ap); 1945} 1946#endif /* DEBUG */ 1947 1948/* 1949 * Check options for consistency. 1950 */ 1951int 1952check_options(dp) 1953 struct dirlist *dp; 1954{ 1955 1956 if (dp == (struct dirlist *)NULL) 1957 return (1); 1958 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 1959 (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 1960 (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 1961 syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 1962 return (1); 1963 } 1964 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 1965 syslog(LOG_ERR, "-mask requires -net"); 1966 return (1); 1967 } 1968 if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 1969 syslog(LOG_ERR, "-net and -iso mutually exclusive"); 1970 return (1); 1971 } 1972 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 1973 syslog(LOG_ERR, "-alldir has multiple directories"); 1974 return (1); 1975 } 1976 return (0); 1977} 1978 1979/* 1980 * Check an absolute directory path for any symbolic links. Return true 1981 * if no symbolic links are found. 1982 */ 1983int 1984check_dirpath(dirp) 1985 char *dirp; 1986{ 1987 char *cp; 1988 int ret = 1; 1989 struct stat sb; 1990 1991 cp = dirp + 1; 1992 while (*cp && ret) { 1993 if (*cp == '/') { 1994 *cp = '\0'; 1995 if (lstat(dirp, &sb) < 0 || 1996 (sb.st_mode & S_IFMT) != S_IFDIR) 1997 ret = 0; 1998 *cp = '/'; 1999 } 2000 cp++; 2001 } 2002 if (lstat(dirp, &sb) < 0 || 2003 (sb.st_mode & S_IFMT) != S_IFDIR) 2004 ret = 0; 2005 return (ret); 2006}
| 253 while ((c = getopt(argc, argv, "n")) != EOF) 254 switch (c) { 255 case 'n': 256 root_only = 0; 257 break; 258 default: 259 fprintf(stderr, "Usage: mountd [-n] [export_file]\n"); 260 exit(1); 261 }; 262 argc -= optind; 263 argv += optind; 264 grphead = (struct grouplist *)NULL; 265 exphead = (struct exportlist *)NULL; 266 mlhead = (struct mountlist *)NULL; 267 if (argc == 1) { 268 strncpy(exname, *argv, MAXPATHLEN-1); 269 exname[MAXPATHLEN-1] = '\0'; 270 } else 271 strcpy(exname, _PATH_EXPORTS); 272 openlog("mountd", LOG_PID, LOG_DAEMON); 273 if (debug) 274 fprintf(stderr,"Getting export list.\n"); 275 get_exportlist(); 276 if (debug) 277 fprintf(stderr,"Getting mount list.\n"); 278 get_mountlist(); 279 if (debug) 280 fprintf(stderr,"Here we go.\n"); 281 if (debug == 0) { 282 daemon(0, 0); 283 signal(SIGINT, SIG_IGN); 284 signal(SIGQUIT, SIG_IGN); 285 } 286 signal(SIGHUP, (void (*) __P((int))) get_exportlist); 287 signal(SIGTERM, (void (*) __P((int))) send_umntall); 288 { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w"); 289 if (pidfile != NULL) { 290 fprintf(pidfile, "%d\n", getpid()); 291 fclose(pidfile); 292 } 293 } 294 if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) { 295 syslog(LOG_ERR, "Can't create socket"); 296 exit(1); 297 } 298 pmap_unset(RPCPROG_MNT, RPCMNT_VER1); 299 if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 300 IPPROTO_UDP)) { 301 syslog(LOG_ERR, "Can't register mount"); 302 exit(1); 303 } 304 svc_run(); 305 syslog(LOG_ERR, "Mountd died"); 306 exit(1); 307} 308 309/* 310 * The mount rpc service 311 */ 312void 313mntsrv(rqstp, transp) 314 struct svc_req *rqstp; 315 SVCXPRT *transp; 316{ 317 struct exportlist *ep; 318 struct dirlist *dp; 319 nfsv2fh_t nfh; 320 struct authunix_parms *ucr; 321 struct stat stb; 322 struct statfs fsb; 323 struct hostent *hp; 324 u_long saddr; 325 char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN]; 326 int bad = ENOENT, omask, defset; 327 uid_t uid = -2; 328 329 /* Get authorization */ 330 switch (rqstp->rq_cred.oa_flavor) { 331 case AUTH_UNIX: 332 ucr = (struct authunix_parms *)rqstp->rq_clntcred; 333 uid = ucr->aup_uid; 334 break; 335 case AUTH_NULL: 336 default: 337 break; 338 } 339 340 saddr = transp->xp_raddr.sin_addr.s_addr; 341 hp = (struct hostent *)NULL; 342 switch (rqstp->rq_proc) { 343 case NULLPROC: 344 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 345 syslog(LOG_ERR, "Can't send reply"); 346 return; 347 case RPCMNT_MOUNT: 348 if ((uid != 0 && root_only) || uid == -2) { 349 svcerr_weakauth(transp); 350 return; 351 } 352 if (!svc_getargs(transp, xdr_dir, rpcpath)) { 353 svcerr_decode(transp); 354 return; 355 } 356 357 /* 358 * Get the real pathname and make sure it is a directory 359 * that exists. 360 */ 361 if (realpath(rpcpath, dirpath) == 0 || 362 stat(dirpath, &stb) < 0 || 363 (stb.st_mode & S_IFMT) != S_IFDIR || 364 statfs(dirpath, &fsb) < 0) { 365 chdir("/"); /* Just in case realpath doesn't */ 366 if (debug) 367 fprintf(stderr, "stat failed on %s\n", dirpath); 368 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 369 syslog(LOG_ERR, "Can't send reply"); 370 return; 371 } 372 373 /* Check in the exports list */ 374 omask = sigblock(sigmask(SIGHUP)); 375 ep = ex_search(&fsb.f_fsid); 376 defset = 0; 377 if (ep && (chk_host(ep->ex_defdir, saddr, &defset) || 378 ((dp = dirp_search(ep->ex_dirl, dirpath)) && 379 chk_host(dp, saddr, &defset)) || 380 (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 381 scan_tree(ep->ex_dirl, saddr) == 0))) { 382 /* Get the file handle */ 383 bzero((caddr_t)&nfh, sizeof(nfh)); 384 if (getfh(dirpath, (fhandle_t *)&nfh) < 0) { 385 bad = errno; 386 syslog(LOG_ERR, "Can't get fh for %s", dirpath); 387 if (!svc_sendreply(transp, xdr_long, 388 (caddr_t)&bad)) 389 syslog(LOG_ERR, "Can't send reply"); 390 sigsetmask(omask); 391 return; 392 } 393 if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh)) 394 syslog(LOG_ERR, "Can't send reply"); 395 if (hp == NULL) 396 hp = gethostbyaddr((caddr_t)&saddr, 397 sizeof(saddr), AF_INET); 398 if (hp) 399 add_mlist(hp->h_name, dirpath); 400 else 401 add_mlist(inet_ntoa(transp->xp_raddr.sin_addr), 402 dirpath); 403 if (debug) 404 fprintf(stderr,"Mount successfull.\n"); 405 } else { 406 bad = EACCES; 407 if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad)) 408 syslog(LOG_ERR, "Can't send reply"); 409 } 410 sigsetmask(omask); 411 return; 412 case RPCMNT_DUMP: 413 if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL)) 414 syslog(LOG_ERR, "Can't send reply"); 415 return; 416 case RPCMNT_UMOUNT: 417 if ((uid != 0 && root_only) || uid == -2) { 418 svcerr_weakauth(transp); 419 return; 420 } 421 if (!svc_getargs(transp, xdr_dir, dirpath)) { 422 svcerr_decode(transp); 423 return; 424 } 425 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 426 syslog(LOG_ERR, "Can't send reply"); 427 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 428 if (hp) 429 del_mlist(hp->h_name, dirpath); 430 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath); 431 return; 432 case RPCMNT_UMNTALL: 433 if ((uid != 0 && root_only) || uid == -2) { 434 svcerr_weakauth(transp); 435 return; 436 } 437 if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL)) 438 syslog(LOG_ERR, "Can't send reply"); 439 hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET); 440 if (hp) 441 del_mlist(hp->h_name, (char *)NULL); 442 del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL); 443 return; 444 case RPCMNT_EXPORT: 445 if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL)) 446 syslog(LOG_ERR, "Can't send reply"); 447 return; 448 default: 449 svcerr_noproc(transp); 450 return; 451 } 452} 453 454/* 455 * Xdr conversion for a dirpath string 456 */ 457int 458xdr_dir(xdrsp, dirp) 459 XDR *xdrsp; 460 char *dirp; 461{ 462 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 463} 464 465/* 466 * Xdr routine to generate fhstatus 467 */ 468int 469xdr_fhs(xdrsp, nfh) 470 XDR *xdrsp; 471 nfsv2fh_t *nfh; 472{ 473 int ok = 0; 474 475 if (!xdr_long(xdrsp, &ok)) 476 return (0); 477 return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH)); 478} 479 480int 481xdr_mlist(xdrsp, cp) 482 XDR *xdrsp; 483 caddr_t cp; 484{ 485 struct mountlist *mlp; 486 int true = 1; 487 int false = 0; 488 char *strp; 489 490 mlp = mlhead; 491 while (mlp) { 492 if (!xdr_bool(xdrsp, &true)) 493 return (0); 494 strp = &mlp->ml_host[0]; 495 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 496 return (0); 497 strp = &mlp->ml_dirp[0]; 498 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 499 return (0); 500 mlp = mlp->ml_next; 501 } 502 if (!xdr_bool(xdrsp, &false)) 503 return (0); 504 return (1); 505} 506 507/* 508 * Xdr conversion for export list 509 */ 510int 511xdr_explist(xdrsp, cp) 512 XDR *xdrsp; 513 caddr_t cp; 514{ 515 struct exportlist *ep; 516 int false = 0; 517 int omask, putdef; 518 519 omask = sigblock(sigmask(SIGHUP)); 520 ep = exphead; 521 while (ep) { 522 putdef = 0; 523 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef)) 524 goto errout; 525 if (ep->ex_defdir && putdef == 0 && 526 put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 527 &putdef)) 528 goto errout; 529 ep = ep->ex_next; 530 } 531 sigsetmask(omask); 532 if (!xdr_bool(xdrsp, &false)) 533 return (0); 534 return (1); 535errout: 536 sigsetmask(omask); 537 return (0); 538} 539 540/* 541 * Called from xdr_explist() to traverse the tree and export the 542 * directory paths. 543 */ 544int 545put_exlist(dp, xdrsp, adp, putdefp) 546 struct dirlist *dp; 547 XDR *xdrsp; 548 struct dirlist *adp; 549 int *putdefp; 550{ 551 struct grouplist *grp; 552 struct hostlist *hp; 553 int true = 1; 554 int false = 0; 555 int gotalldir = 0; 556 char *strp; 557 558 if (dp) { 559 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp)) 560 return (1); 561 if (!xdr_bool(xdrsp, &true)) 562 return (1); 563 strp = dp->dp_dirp; 564 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 565 return (1); 566 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 567 gotalldir = 1; 568 *putdefp = 1; 569 } 570 if ((dp->dp_flag & DP_DEFSET) == 0 && 571 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 572 hp = dp->dp_hosts; 573 while (hp) { 574 grp = hp->ht_grp; 575 if (grp->gr_type == GT_HOST) { 576 if (!xdr_bool(xdrsp, &true)) 577 return (1); 578 strp = grp->gr_ptr.gt_hostent->h_name; 579 if (!xdr_string(xdrsp, &strp, 580 RPCMNT_NAMELEN)) 581 return (1); 582 } else if (grp->gr_type == GT_NET) { 583 if (!xdr_bool(xdrsp, &true)) 584 return (1); 585 strp = grp->gr_ptr.gt_net.nt_name; 586 if (!xdr_string(xdrsp, &strp, 587 RPCMNT_NAMELEN)) 588 return (1); 589 } 590 hp = hp->ht_next; 591 if (gotalldir && hp == (struct hostlist *)NULL) { 592 hp = adp->dp_hosts; 593 gotalldir = 0; 594 } 595 } 596 } 597 if (!xdr_bool(xdrsp, &false)) 598 return (1); 599 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp)) 600 return (1); 601 } 602 return (0); 603} 604 605#define LINESIZ 10240 606char line[LINESIZ]; 607FILE *exp_file; 608 609/* 610 * Get the export list 611 */ 612void 613get_exportlist() 614{ 615 struct exportlist *ep, *ep2; 616 struct grouplist *grp, *tgrp; 617 struct exportlist **epp; 618 struct dirlist *dirhead; 619 struct statfs fsb, *fsp; 620 struct hostent *hpe; 621 struct ucred anon; 622 char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 623 int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp; 624 625 /* 626 * First, get rid of the old list 627 */ 628 ep = exphead; 629 while (ep) { 630 ep2 = ep; 631 ep = ep->ex_next; 632 free_exp(ep2); 633 } 634 exphead = (struct exportlist *)NULL; 635 636 grp = grphead; 637 while (grp) { 638 tgrp = grp; 639 grp = grp->gr_next; 640 free_grp(tgrp); 641 } 642 grphead = (struct grouplist *)NULL; 643 644 /* 645 * And delete exports that are in the kernel for all local 646 * file systems. 647 * XXX: Should know how to handle all local exportable file systems 648 * instead of just MOUNT_UFS. 649 */ 650 num = getmntinfo(&fsp, MNT_NOWAIT); 651 for (i = 0; i < num; i++) { 652 union { 653 struct ufs_args ua; 654 struct iso_args ia; 655 struct mfs_args ma; 656 } targs; 657 658 switch (fsp->f_type) { 659 case MOUNT_MFS: 660 case MOUNT_UFS: 661 case MOUNT_CD9660: 662 case MOUNT_MSDOS: 663 targs.ua.fspec = NULL; 664 targs.ua.export.ex_flags = MNT_DELEXPORT; 665 if (mount(fsp->f_type, fsp->f_mntonname, 666 fsp->f_flags | MNT_UPDATE, 667 (caddr_t)&targs) < 0) 668 syslog(LOG_ERR, "Can't delete exports for %s", 669 fsp->f_mntonname); 670 } 671 fsp++; 672 } 673 674 /* 675 * Read in the exports file and build the list, calling 676 * mount() as we go along to push the export rules into the kernel. 677 */ 678 if ((exp_file = fopen(exname, "r")) == NULL) { 679 syslog(LOG_ERR, "Can't open %s", exname); 680 exit(2); 681 } 682 dirhead = (struct dirlist *)NULL; 683 while (get_line()) { 684 if (debug) 685 fprintf(stderr,"Got line %s\n",line); 686 cp = line; 687 nextfield(&cp, &endcp); 688 if (*cp == '#') 689 goto nextline; 690 691 /* 692 * Set defaults. 693 */ 694 has_host = FALSE; 695 anon = def_anon; 696 exflags = MNT_EXPORTED; 697 got_nondir = 0; 698 opt_flags = 0; 699 ep = (struct exportlist *)NULL; 700 701 /* 702 * Create new exports list entry 703 */ 704 len = endcp-cp; 705 tgrp = grp = get_grp(); 706 while (len > 0) { 707 if (len > RPCMNT_NAMELEN) { 708 getexp_err(ep, tgrp); 709 goto nextline; 710 } 711 if (*cp == '-') { 712 if (ep == (struct exportlist *)NULL) { 713 getexp_err(ep, tgrp); 714 goto nextline; 715 } 716 if (debug) 717 fprintf(stderr, "doing opt %s\n", cp); 718 got_nondir = 1; 719 if (do_opt(&cp, &endcp, ep, grp, &has_host, 720 &exflags, &anon)) { 721 getexp_err(ep, tgrp); 722 goto nextline; 723 } 724 } else if (*cp == '/') { 725 savedc = *endcp; 726 *endcp = '\0'; 727 if (check_dirpath(cp) && 728 statfs(cp, &fsb) >= 0) { 729 if (got_nondir) { 730 syslog(LOG_ERR, "Dirs must be first"); 731 getexp_err(ep, tgrp); 732 goto nextline; 733 } 734 if (ep) { 735 if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 736 ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 737 getexp_err(ep, tgrp); 738 goto nextline; 739 } 740 } else { 741 /* 742 * See if this directory is already 743 * in the list. 744 */ 745 ep = ex_search(&fsb.f_fsid); 746 if (ep == (struct exportlist *)NULL) { 747 ep = get_exp(); 748 ep->ex_fs = fsb.f_fsid; 749 ep->ex_fsdir = (char *) 750 malloc(strlen(fsb.f_mntonname) + 1); 751 if (ep->ex_fsdir) 752 strcpy(ep->ex_fsdir, 753 fsb.f_mntonname); 754 else 755 out_of_mem(); 756 if (debug) 757 fprintf(stderr, 758 "Making new ep fs=0x%x,0x%x\n", 759 fsb.f_fsid.val[0], 760 fsb.f_fsid.val[1]); 761 } else if (debug) 762 fprintf(stderr, 763 "Found ep fs=0x%x,0x%x\n", 764 fsb.f_fsid.val[0], 765 fsb.f_fsid.val[1]); 766 } 767 768 /* 769 * Add dirpath to export mount point. 770 */ 771 dirp = add_expdir(&dirhead, cp, len); 772 dirplen = len; 773 } else { 774 getexp_err(ep, tgrp); 775 goto nextline; 776 } 777 *endcp = savedc; 778 } else { 779 savedc = *endcp; 780 *endcp = '\0'; 781 got_nondir = 1; 782 if (ep == (struct exportlist *)NULL) { 783 getexp_err(ep, tgrp); 784 goto nextline; 785 } 786 787 /* 788 * Get the host or netgroup. 789 */ 790 setnetgrent(cp); 791 netgrp = getnetgrent(&hst, &usr, &dom); 792 do { 793 if (has_host) { 794 grp->gr_next = get_grp(); 795 grp = grp->gr_next; 796 } 797 if (netgrp) { 798 if (get_host(hst, grp)) { 799 syslog(LOG_ERR, "Bad netgroup %s", cp); 800 getexp_err(ep, tgrp); 801 goto nextline; 802 } 803 } else if (get_host(cp, grp)) { 804 getexp_err(ep, tgrp); 805 goto nextline; 806 } 807 has_host = TRUE; 808 } while (netgrp && getnetgrent(&hst, &usr, &dom)); 809 endnetgrent(); 810 *endcp = savedc; 811 } 812 cp = endcp; 813 nextfield(&cp, &endcp); 814 len = endcp - cp; 815 } 816 if (check_options(dirhead)) { 817 getexp_err(ep, tgrp); 818 goto nextline; 819 } 820 if (!has_host) { 821 grp->gr_type = GT_HOST; 822 if (debug) 823 fprintf(stderr,"Adding a default entry\n"); 824 /* add a default group and make the grp list NULL */ 825 hpe = (struct hostent *)malloc(sizeof(struct hostent)); 826 if (hpe == (struct hostent *)NULL) 827 out_of_mem(); 828 hpe->h_name = "Default"; 829 hpe->h_addrtype = AF_INET; 830 hpe->h_length = sizeof (u_long); 831 hpe->h_addr_list = (char **)NULL; 832 grp->gr_ptr.gt_hostent = hpe; 833 834 /* 835 * Don't allow a network export coincide with a list of 836 * host(s) on the same line. 837 */ 838 } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 839 getexp_err(ep, tgrp); 840 goto nextline; 841 } 842 843 /* 844 * Loop through hosts, pushing the exports into the kernel. 845 * After loop, tgrp points to the start of the list and 846 * grp points to the last entry in the list. 847 */ 848 grp = tgrp; 849 do { 850 if (do_mount(ep, grp, exflags, &anon, dirp, 851 dirplen, &fsb)) { 852 getexp_err(ep, tgrp); 853 goto nextline; 854 } 855 } while (grp->gr_next && (grp = grp->gr_next)); 856 857 /* 858 * Success. Update the data structures. 859 */ 860 if (has_host) { 861 hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS)); 862 grp->gr_next = grphead; 863 grphead = tgrp; 864 } else { 865 hang_dirp(dirhead, (struct grouplist *)NULL, ep, 866 (opt_flags & OP_ALLDIRS)); 867 free_grp(grp); 868 } 869 dirhead = (struct dirlist *)NULL; 870 if ((ep->ex_flag & EX_LINKED) == 0) { 871 ep2 = exphead; 872 epp = &exphead; 873 874 /* 875 * Insert in the list in alphabetical order. 876 */ 877 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 878 epp = &ep2->ex_next; 879 ep2 = ep2->ex_next; 880 } 881 if (ep2) 882 ep->ex_next = ep2; 883 *epp = ep; 884 ep->ex_flag |= EX_LINKED; 885 } 886nextline: 887 if (dirhead) { 888 free_dir(dirhead); 889 dirhead = (struct dirlist *)NULL; 890 } 891 } 892 fclose(exp_file); 893} 894 895/* 896 * Allocate an export list element 897 */ 898struct exportlist * 899get_exp() 900{ 901 struct exportlist *ep; 902 903 ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 904 if (ep == (struct exportlist *)NULL) 905 out_of_mem(); 906 bzero((caddr_t)ep, sizeof (struct exportlist)); 907 return (ep); 908} 909 910/* 911 * Allocate a group list element 912 */ 913struct grouplist * 914get_grp() 915{ 916 struct grouplist *gp; 917 918 gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 919 if (gp == (struct grouplist *)NULL) 920 out_of_mem(); 921 bzero((caddr_t)gp, sizeof (struct grouplist)); 922 return (gp); 923} 924 925/* 926 * Clean up upon an error in get_exportlist(). 927 */ 928void 929getexp_err(ep, grp) 930 struct exportlist *ep; 931 struct grouplist *grp; 932{ 933 struct grouplist *tgrp; 934 935 syslog(LOG_ERR, "Bad exports list line %s", line); 936 if (ep && (ep->ex_flag & EX_LINKED) == 0) 937 free_exp(ep); 938 while (grp) { 939 tgrp = grp; 940 grp = grp->gr_next; 941 free_grp(tgrp); 942 } 943} 944 945/* 946 * Search the export list for a matching fs. 947 */ 948struct exportlist * 949ex_search(fsid) 950 fsid_t *fsid; 951{ 952 struct exportlist *ep; 953 954 ep = exphead; 955 while (ep) { 956 if (ep->ex_fs.val[0] == fsid->val[0] && 957 ep->ex_fs.val[1] == fsid->val[1]) 958 return (ep); 959 ep = ep->ex_next; 960 } 961 return (ep); 962} 963 964/* 965 * Add a directory path to the list. 966 */ 967char * 968add_expdir(dpp, cp, len) 969 struct dirlist **dpp; 970 char *cp; 971 int len; 972{ 973 struct dirlist *dp; 974 975 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 976 dp->dp_left = *dpp; 977 dp->dp_right = (struct dirlist *)NULL; 978 dp->dp_flag = 0; 979 dp->dp_hosts = (struct hostlist *)NULL; 980 strcpy(dp->dp_dirp, cp); 981 *dpp = dp; 982 return (dp->dp_dirp); 983} 984 985/* 986 * Hang the dir list element off the dirpath binary tree as required 987 * and update the entry for host. 988 */ 989void 990hang_dirp(dp, grp, ep, alldirs) 991 struct dirlist *dp; 992 struct grouplist *grp; 993 struct exportlist *ep; 994 int alldirs; 995{ 996 struct hostlist *hp; 997 struct dirlist *dp2; 998 999 if (alldirs) { 1000 if (ep->ex_defdir) 1001 free((caddr_t)dp); 1002 else 1003 ep->ex_defdir = dp; 1004 if (grp == (struct grouplist *)NULL) 1005 ep->ex_defdir->dp_flag |= DP_DEFSET; 1006 else while (grp) { 1007 hp = get_ht(); 1008 hp->ht_grp = grp; 1009 hp->ht_next = ep->ex_defdir->dp_hosts; 1010 ep->ex_defdir->dp_hosts = hp; 1011 grp = grp->gr_next; 1012 } 1013 } else { 1014 1015 /* 1016 * Loop throught the directories adding them to the tree. 1017 */ 1018 while (dp) { 1019 dp2 = dp->dp_left; 1020 add_dlist(&ep->ex_dirl, dp, grp); 1021 dp = dp2; 1022 } 1023 } 1024} 1025 1026/* 1027 * Traverse the binary tree either updating a node that is already there 1028 * for the new directory or adding the new node. 1029 */ 1030void 1031add_dlist(dpp, newdp, grp) 1032 struct dirlist **dpp; 1033 struct dirlist *newdp; 1034 struct grouplist *grp; 1035{ 1036 struct dirlist *dp; 1037 struct hostlist *hp; 1038 int cmp; 1039 1040 dp = *dpp; 1041 if (dp) { 1042 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1043 if (cmp > 0) { 1044 add_dlist(&dp->dp_left, newdp, grp); 1045 return; 1046 } else if (cmp < 0) { 1047 add_dlist(&dp->dp_right, newdp, grp); 1048 return; 1049 } else 1050 free((caddr_t)newdp); 1051 } else { 1052 dp = newdp; 1053 dp->dp_left = (struct dirlist *)NULL; 1054 *dpp = dp; 1055 } 1056 if (grp) { 1057 1058 /* 1059 * Hang all of the host(s) off of the directory point. 1060 */ 1061 do { 1062 hp = get_ht(); 1063 hp->ht_grp = grp; 1064 hp->ht_next = dp->dp_hosts; 1065 dp->dp_hosts = hp; 1066 grp = grp->gr_next; 1067 } while (grp); 1068 } else 1069 dp->dp_flag |= DP_DEFSET; 1070} 1071 1072/* 1073 * Search for a dirpath on the export point. 1074 */ 1075struct dirlist * 1076dirp_search(dp, dirpath) 1077 struct dirlist *dp; 1078 char *dirpath; 1079{ 1080 int cmp; 1081 1082 if (dp) { 1083 cmp = strcmp(dp->dp_dirp, dirpath); 1084 if (cmp > 0) 1085 return (dirp_search(dp->dp_left, dirpath)); 1086 else if (cmp < 0) 1087 return (dirp_search(dp->dp_right, dirpath)); 1088 else 1089 return (dp); 1090 } 1091 return (dp); 1092} 1093 1094/* 1095 * Scan for a host match in a directory tree. 1096 */ 1097int 1098chk_host(dp, saddr, defsetp) 1099 struct dirlist *dp; 1100 u_long saddr; 1101 int *defsetp; 1102{ 1103 struct hostlist *hp; 1104 struct grouplist *grp; 1105 u_long **addrp; 1106 1107 if (dp) { 1108 if (dp->dp_flag & DP_DEFSET) 1109 *defsetp = 1; 1110 hp = dp->dp_hosts; 1111 while (hp) { 1112 grp = hp->ht_grp; 1113 switch (grp->gr_type) { 1114 case GT_HOST: 1115 addrp = (u_long **) 1116 grp->gr_ptr.gt_hostent->h_addr_list; 1117 while (*addrp) { 1118 if (**addrp == saddr) 1119 return (1); 1120 addrp++; 1121 } 1122 break; 1123 case GT_NET: 1124 if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 1125 grp->gr_ptr.gt_net.nt_net) 1126 return (1); 1127 break; 1128 }; 1129 hp = hp->ht_next; 1130 } 1131 } 1132 return (0); 1133} 1134 1135/* 1136 * Scan tree for a host that matches the address. 1137 */ 1138int 1139scan_tree(dp, saddr) 1140 struct dirlist *dp; 1141 u_long saddr; 1142{ 1143 int defset; 1144 1145 if (dp) { 1146 if (scan_tree(dp->dp_left, saddr)) 1147 return (1); 1148 if (chk_host(dp, saddr, &defset)) 1149 return (1); 1150 if (scan_tree(dp->dp_right, saddr)) 1151 return (1); 1152 } 1153 return (0); 1154} 1155 1156/* 1157 * Traverse the dirlist tree and free it up. 1158 */ 1159void 1160free_dir(dp) 1161 struct dirlist *dp; 1162{ 1163 1164 if (dp) { 1165 free_dir(dp->dp_left); 1166 free_dir(dp->dp_right); 1167 free_host(dp->dp_hosts); 1168 free((caddr_t)dp); 1169 } 1170} 1171 1172/* 1173 * Parse the option string and update fields. 1174 * Option arguments may either be -<option>=<value> or 1175 * -<option> <value> 1176 */ 1177int 1178do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1179 char **cpp, **endcpp; 1180 struct exportlist *ep; 1181 struct grouplist *grp; 1182 int *has_hostp; 1183 int *exflagsp; 1184 struct ucred *cr; 1185{ 1186 char *cpoptarg, *cpoptend; 1187 char *cp, *endcp, *cpopt, savedc, savedc2; 1188 int allflag, usedarg; 1189 1190 cpopt = *cpp; 1191 cpopt++; 1192 cp = *endcpp; 1193 savedc = *cp; 1194 *cp = '\0'; 1195 while (cpopt && *cpopt) { 1196 allflag = 1; 1197 usedarg = -2; 1198 if (cpoptend = index(cpopt, ',')) { 1199 *cpoptend++ = '\0'; 1200 if (cpoptarg = index(cpopt, '=')) 1201 *cpoptarg++ = '\0'; 1202 } else { 1203 if (cpoptarg = index(cpopt, '=')) 1204 *cpoptarg++ = '\0'; 1205 else { 1206 *cp = savedc; 1207 nextfield(&cp, &endcp); 1208 **endcpp = '\0'; 1209 if (endcp > cp && *cp != '-') { 1210 cpoptarg = cp; 1211 savedc2 = *endcp; 1212 *endcp = '\0'; 1213 usedarg = 0; 1214 } 1215 } 1216 } 1217 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1218 *exflagsp |= MNT_EXRDONLY; 1219 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1220 !(allflag = strcmp(cpopt, "mapall")) || 1221 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1222 usedarg++; 1223 parsecred(cpoptarg, cr); 1224 if (allflag == 0) { 1225 *exflagsp |= MNT_EXPORTANON; 1226 opt_flags |= OP_MAPALL; 1227 } else 1228 opt_flags |= OP_MAPROOT; 1229 } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 1230 *exflagsp |= MNT_EXKERB; 1231 opt_flags |= OP_KERB; 1232 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1233 !strcmp(cpopt, "m"))) { 1234 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1235 syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 1236 return (1); 1237 } 1238 usedarg++; 1239 opt_flags |= OP_MASK; 1240 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1241 !strcmp(cpopt, "n"))) { 1242 if (grp->gr_type != GT_NULL) { 1243 syslog(LOG_ERR, "Network/host conflict"); 1244 return (1); 1245 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1246 syslog(LOG_ERR, "Bad net: %s", cpoptarg); 1247 return (1); 1248 } 1249 grp->gr_type = GT_NET; 1250 *has_hostp = 1; 1251 usedarg++; 1252 opt_flags |= OP_NET; 1253 } else if (!strcmp(cpopt, "alldirs")) { 1254 opt_flags |= OP_ALLDIRS; 1255#ifdef ISO 1256 } else if (cpoptarg && !strcmp(cpopt, "iso")) { 1257 if (get_isoaddr(cpoptarg, grp)) { 1258 syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 1259 return (1); 1260 } 1261 *has_hostp = 1; 1262 usedarg++; 1263 opt_flags |= OP_ISO; 1264#endif /* ISO */ 1265 } else { 1266 syslog(LOG_ERR, "Bad opt %s", cpopt); 1267 return (1); 1268 } 1269 if (usedarg >= 0) { 1270 *endcp = savedc2; 1271 **endcpp = savedc; 1272 if (usedarg > 0) { 1273 *cpp = cp; 1274 *endcpp = endcp; 1275 } 1276 return (0); 1277 } 1278 cpopt = cpoptend; 1279 } 1280 **endcpp = savedc; 1281 return (0); 1282} 1283 1284/* 1285 * Translate a character string to the corresponding list of network 1286 * addresses for a hostname. 1287 */ 1288int 1289get_host(cp, grp) 1290 char *cp; 1291 struct grouplist *grp; 1292{ 1293 struct hostent *hp, *nhp; 1294 char **addrp, **naddrp; 1295 struct hostent t_host; 1296 int i; 1297 u_long saddr; 1298 char *aptr[2]; 1299 1300 if (grp->gr_type != GT_NULL) 1301 return (1); 1302 if ((hp = gethostbyname(cp)) == NULL) { 1303 if (isdigit(*cp)) { 1304 saddr = inet_addr(cp); 1305 if (saddr == -1) { 1306 syslog(LOG_ERR, "Inet_addr failed"); 1307 return (1); 1308 } 1309 if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 1310 AF_INET)) == NULL) { 1311 hp = &t_host; 1312 hp->h_name = cp; 1313 hp->h_addrtype = AF_INET; 1314 hp->h_length = sizeof (u_long); 1315 hp->h_addr_list = aptr; 1316 aptr[0] = (char *)&saddr; 1317 aptr[1] = (char *)NULL; 1318 } 1319 } else { 1320 syslog(LOG_ERR, "Gethostbyname failed"); 1321 return (1); 1322 } 1323 } 1324 grp->gr_type = GT_HOST; 1325 nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 1326 malloc(sizeof(struct hostent)); 1327 if (nhp == (struct hostent *)NULL) 1328 out_of_mem(); 1329 bcopy((caddr_t)hp, (caddr_t)nhp, 1330 sizeof(struct hostent)); 1331 i = strlen(hp->h_name)+1; 1332 nhp->h_name = (char *)malloc(i); 1333 if (nhp->h_name == (char *)NULL) 1334 out_of_mem(); 1335 bcopy(hp->h_name, nhp->h_name, i); 1336 addrp = hp->h_addr_list; 1337 i = 1; 1338 while (*addrp++) 1339 i++; 1340 naddrp = nhp->h_addr_list = (char **) 1341 malloc(i*sizeof(char *)); 1342 if (naddrp == (char **)NULL) 1343 out_of_mem(); 1344 addrp = hp->h_addr_list; 1345 while (*addrp) { 1346 *naddrp = (char *) 1347 malloc(hp->h_length); 1348 if (*naddrp == (char *)NULL) 1349 out_of_mem(); 1350 bcopy(*addrp, *naddrp, 1351 hp->h_length); 1352 addrp++; 1353 naddrp++; 1354 } 1355 *naddrp = (char *)NULL; 1356 if (debug) 1357 fprintf(stderr, "got host %s\n", hp->h_name); 1358 return (0); 1359} 1360 1361/* 1362 * Free up an exports list component 1363 */ 1364void 1365free_exp(ep) 1366 struct exportlist *ep; 1367{ 1368 1369 if (ep->ex_defdir) { 1370 free_host(ep->ex_defdir->dp_hosts); 1371 free((caddr_t)ep->ex_defdir); 1372 } 1373 if (ep->ex_fsdir) 1374 free(ep->ex_fsdir); 1375 free_dir(ep->ex_dirl); 1376 free((caddr_t)ep); 1377} 1378 1379/* 1380 * Free hosts. 1381 */ 1382void 1383free_host(hp) 1384 struct hostlist *hp; 1385{ 1386 struct hostlist *hp2; 1387 1388 while (hp) { 1389 hp2 = hp; 1390 hp = hp->ht_next; 1391 free((caddr_t)hp2); 1392 } 1393} 1394 1395struct hostlist * 1396get_ht() 1397{ 1398 struct hostlist *hp; 1399 1400 hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 1401 if (hp == (struct hostlist *)NULL) 1402 out_of_mem(); 1403 hp->ht_next = (struct hostlist *)NULL; 1404 return (hp); 1405} 1406 1407#ifdef ISO 1408/* 1409 * Translate an iso address. 1410 */ 1411get_isoaddr(cp, grp) 1412 char *cp; 1413 struct grouplist *grp; 1414{ 1415 struct iso_addr *isop; 1416 struct sockaddr_iso *isoaddr; 1417 1418 if (grp->gr_type != GT_NULL) 1419 return (1); 1420 if ((isop = iso_addr(cp)) == NULL) { 1421 syslog(LOG_ERR, 1422 "iso_addr failed, ignored"); 1423 return (1); 1424 } 1425 isoaddr = (struct sockaddr_iso *) 1426 malloc(sizeof (struct sockaddr_iso)); 1427 if (isoaddr == (struct sockaddr_iso *)NULL) 1428 out_of_mem(); 1429 bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 1430 bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 1431 sizeof (struct iso_addr)); 1432 isoaddr->siso_len = sizeof (struct sockaddr_iso); 1433 isoaddr->siso_family = AF_ISO; 1434 grp->gr_type = GT_ISO; 1435 grp->gr_ptr.gt_isoaddr = isoaddr; 1436 return (0); 1437} 1438#endif /* ISO */ 1439 1440/* 1441 * Out of memory, fatal 1442 */ 1443void 1444out_of_mem() 1445{ 1446 1447 syslog(LOG_ERR, "Out of memory"); 1448 exit(2); 1449} 1450 1451/* 1452 * Do the mount syscall with the update flag to push the export info into 1453 * the kernel. 1454 */ 1455int 1456do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 1457 struct exportlist *ep; 1458 struct grouplist *grp; 1459 int exflags; 1460 struct ucred *anoncrp; 1461 char *dirp; 1462 int dirplen; 1463 struct statfs *fsb; 1464{ 1465 char *cp = (char *)NULL; 1466 u_long **addrp; 1467 int done; 1468 char savedc = '\0'; 1469 struct sockaddr_in sin, imask; 1470 union { 1471 struct ufs_args ua; 1472 struct iso_args ia; 1473 struct mfs_args ma; 1474 } args; 1475 u_long net; 1476 1477 args.ua.fspec = 0; 1478 args.ua.export.ex_flags = exflags; 1479 args.ua.export.ex_anon = *anoncrp; 1480 bzero((char *)&sin, sizeof(sin)); 1481 bzero((char *)&imask, sizeof(imask)); 1482 sin.sin_family = AF_INET; 1483 sin.sin_len = sizeof(sin); 1484 imask.sin_family = AF_INET; 1485 imask.sin_len = sizeof(sin); 1486 if (grp->gr_type == GT_HOST) 1487 addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 1488 else 1489 addrp = (u_long **)NULL; 1490 done = FALSE; 1491 while (!done) { 1492 switch (grp->gr_type) { 1493 case GT_HOST: 1494 if (addrp) { 1495 sin.sin_addr.s_addr = **addrp; 1496 args.ua.export.ex_addrlen = sizeof(sin); 1497 } else 1498 args.ua.export.ex_addrlen = 0; 1499 args.ua.export.ex_addr = (struct sockaddr *)&sin; 1500 args.ua.export.ex_masklen = 0; 1501 break; 1502 case GT_NET: 1503 if (grp->gr_ptr.gt_net.nt_mask) 1504 imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 1505 else { 1506 net = ntohl(grp->gr_ptr.gt_net.nt_net); 1507 if (IN_CLASSA(net)) 1508 imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 1509 else if (IN_CLASSB(net)) 1510 imask.sin_addr.s_addr = 1511 inet_addr("255.255.0.0"); 1512 else 1513 imask.sin_addr.s_addr = 1514 inet_addr("255.255.255.0"); 1515 grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 1516 } 1517 sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 1518 args.ua.export.ex_addr = (struct sockaddr *)&sin; 1519 args.ua.export.ex_addrlen = sizeof (sin); 1520 args.ua.export.ex_mask = (struct sockaddr *)&imask; 1521 args.ua.export.ex_masklen = sizeof (imask); 1522 break; 1523#ifdef ISO 1524 case GT_ISO: 1525 args.ua.export.ex_addr = 1526 (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 1527 args.ua.export.ex_addrlen = 1528 sizeof(struct sockaddr_iso); 1529 args.ua.export.ex_masklen = 0; 1530 break; 1531#endif /* ISO */ 1532 default: 1533 syslog(LOG_ERR, "Bad grouptype"); 1534 if (cp) 1535 *cp = savedc; 1536 return (1); 1537 }; 1538 1539 /* 1540 * XXX: 1541 * Maybe I should just use the fsb->f_mntonname path instead 1542 * of looping back up the dirp to the mount point?? 1543 * Also, needs to know how to export all types of local 1544 * exportable file systems and not just MOUNT_UFS. 1545 */ 1546 while (mount(fsb->f_type, dirp, 1547 fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 1548 if (cp) 1549 *cp-- = savedc; 1550 else 1551 cp = dirp + dirplen - 1; 1552 if (errno == EPERM) { 1553 syslog(LOG_ERR, 1554 "Can't change attributes for %s.\n", dirp); 1555 return (1); 1556 } 1557 if (opt_flags & OP_ALLDIRS) { 1558 syslog(LOG_ERR, "Not root dir"); 1559 return (1); 1560 } 1561 /* back up over the last component */ 1562 while (*cp == '/' && cp > dirp) 1563 cp--; 1564 while (*(cp - 1) != '/' && cp > dirp) 1565 cp--; 1566 if (cp == dirp) { 1567 if (debug) 1568 fprintf(stderr,"mnt unsucc\n"); 1569 syslog(LOG_ERR, "Can't export %s", dirp); 1570 return (1); 1571 } 1572 savedc = *cp; 1573 *cp = '\0'; 1574 } 1575 if (addrp) { 1576 ++addrp; 1577 if (*addrp == (u_long *)NULL) 1578 done = TRUE; 1579 } else 1580 done = TRUE; 1581 } 1582 if (cp) 1583 *cp = savedc; 1584 return (0); 1585} 1586 1587/* 1588 * Translate a net address. 1589 */ 1590int 1591get_net(cp, net, maskflg) 1592 char *cp; 1593 struct netmsk *net; 1594 int maskflg; 1595{ 1596 struct netent *np; 1597 long netaddr; 1598 struct in_addr inetaddr, inetaddr2; 1599 char *name; 1600 1601 if (np = getnetbyname(cp)) 1602 inetaddr = inet_makeaddr(np->n_net, 0); 1603 else if (isdigit(*cp)) { 1604 if ((netaddr = inet_network(cp)) == -1) 1605 return (1); 1606 inetaddr = inet_makeaddr(netaddr, 0); 1607 /* 1608 * Due to arbritrary subnet masks, you don't know how many 1609 * bits to shift the address to make it into a network, 1610 * however you do know how to make a network address into 1611 * a host with host == 0 and then compare them. 1612 * (What a pest) 1613 */ 1614 if (!maskflg) { 1615 setnetent(0); 1616 while (np = getnetent()) { 1617 inetaddr2 = inet_makeaddr(np->n_net, 0); 1618 if (inetaddr2.s_addr == inetaddr.s_addr) 1619 break; 1620 } 1621 endnetent(); 1622 } 1623 } else 1624 return (1); 1625 if (maskflg) 1626 net->nt_mask = inetaddr.s_addr; 1627 else { 1628 if (np) 1629 name = np->n_name; 1630 else 1631 name = inet_ntoa(inetaddr); 1632 net->nt_name = (char *)malloc(strlen(name) + 1); 1633 if (net->nt_name == (char *)NULL) 1634 out_of_mem(); 1635 strcpy(net->nt_name, name); 1636 net->nt_net = inetaddr.s_addr; 1637 } 1638 return (0); 1639} 1640 1641/* 1642 * Parse out the next white space separated field 1643 */ 1644void 1645nextfield(cp, endcp) 1646 char **cp; 1647 char **endcp; 1648{ 1649 char *p; 1650 1651 p = *cp; 1652 while (*p == ' ' || *p == '\t') 1653 p++; 1654 if (*p == '\n' || *p == '\0') 1655 *cp = *endcp = p; 1656 else { 1657 *cp = p++; 1658 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 1659 p++; 1660 *endcp = p; 1661 } 1662} 1663 1664/* 1665 * Get an exports file line. Skip over blank lines and handle line 1666 * continuations. 1667 */ 1668int 1669get_line() 1670{ 1671 char *p, *cp; 1672 int len; 1673 int totlen, cont_line; 1674 1675 /* 1676 * Loop around ignoring blank lines and getting all continuation lines. 1677 */ 1678 p = line; 1679 totlen = 0; 1680 do { 1681 if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 1682 return (0); 1683 len = strlen(p); 1684 cp = p + len - 1; 1685 cont_line = 0; 1686 while (cp >= p && 1687 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 1688 if (*cp == '\\') 1689 cont_line = 1; 1690 cp--; 1691 len--; 1692 } 1693 *++cp = '\0'; 1694 if (len > 0) { 1695 totlen += len; 1696 if (totlen >= LINESIZ) { 1697 syslog(LOG_ERR, "Exports line too long"); 1698 exit(2); 1699 } 1700 p = cp; 1701 } 1702 } while (totlen == 0 || cont_line); 1703 return (1); 1704} 1705 1706/* 1707 * Parse a description of a credential. 1708 */ 1709void 1710parsecred(namelist, cr) 1711 char *namelist; 1712 struct ucred *cr; 1713{ 1714 char *name; 1715 int cnt; 1716 char *names; 1717 struct passwd *pw; 1718 struct group *gr; 1719 int ngroups, groups[NGROUPS + 1]; 1720 1721 /* 1722 * Set up the unpriviledged user. 1723 */ 1724 cr->cr_ref = 1; 1725 cr->cr_uid = -2; 1726 cr->cr_groups[0] = -2; 1727 cr->cr_ngroups = 1; 1728 /* 1729 * Get the user's password table entry. 1730 */ 1731 names = strsep(&namelist, " \t\n"); 1732 name = strsep(&names, ":"); 1733 if (isdigit(*name) || *name == '-') 1734 pw = getpwuid(atoi(name)); 1735 else 1736 pw = getpwnam(name); 1737 /* 1738 * Credentials specified as those of a user. 1739 */ 1740 if (names == NULL) { 1741 if (pw == NULL) { 1742 syslog(LOG_ERR, "Unknown user: %s", name); 1743 return; 1744 } 1745 cr->cr_uid = pw->pw_uid; 1746 ngroups = NGROUPS + 1; 1747 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 1748 syslog(LOG_ERR, "Too many groups"); 1749 /* 1750 * Convert from int's to gid_t's and compress out duplicate 1751 */ 1752 cr->cr_ngroups = ngroups - 1; 1753 cr->cr_groups[0] = groups[0]; 1754 for (cnt = 2; cnt < ngroups; cnt++) 1755 cr->cr_groups[cnt - 1] = groups[cnt]; 1756 return; 1757 } 1758 /* 1759 * Explicit credential specified as a colon separated list: 1760 * uid:gid:gid:... 1761 */ 1762 if (pw != NULL) 1763 cr->cr_uid = pw->pw_uid; 1764 else if (isdigit(*name) || *name == '-') 1765 cr->cr_uid = atoi(name); 1766 else { 1767 syslog(LOG_ERR, "Unknown user: %s", name); 1768 return; 1769 } 1770 cr->cr_ngroups = 0; 1771 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 1772 name = strsep(&names, ":"); 1773 if (isdigit(*name) || *name == '-') { 1774 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 1775 } else { 1776 if ((gr = getgrnam(name)) == NULL) { 1777 syslog(LOG_ERR, "Unknown group: %s", name); 1778 continue; 1779 } 1780 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 1781 } 1782 } 1783 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 1784 syslog(LOG_ERR, "Too many groups"); 1785} 1786 1787#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 1788/* 1789 * Routines that maintain the remote mounttab 1790 */ 1791void 1792get_mountlist() 1793{ 1794 struct mountlist *mlp, **mlpp; 1795 char *eos, *dirp; 1796 int len; 1797 char str[STRSIZ]; 1798 FILE *mlfile; 1799 1800 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 1801 syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 1802 return; 1803 } 1804 mlpp = &mlhead; 1805 while (fgets(str, STRSIZ, mlfile) != NULL) { 1806 if ((dirp = index(str, '\t')) == NULL && 1807 (dirp = index(str, ' ')) == NULL) 1808 continue; 1809 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1810 len = dirp-str; 1811 if (len > RPCMNT_NAMELEN) 1812 len = RPCMNT_NAMELEN; 1813 bcopy(str, mlp->ml_host, len); 1814 mlp->ml_host[len] = '\0'; 1815 while (*dirp == '\t' || *dirp == ' ') 1816 dirp++; 1817 if ((eos = index(dirp, '\t')) == NULL && 1818 (eos = index(dirp, ' ')) == NULL && 1819 (eos = index(dirp, '\n')) == NULL) 1820 len = strlen(dirp); 1821 else 1822 len = eos-dirp; 1823 if (len > RPCMNT_PATHLEN) 1824 len = RPCMNT_PATHLEN; 1825 bcopy(dirp, mlp->ml_dirp, len); 1826 mlp->ml_dirp[len] = '\0'; 1827 mlp->ml_next = (struct mountlist *)NULL; 1828 *mlpp = mlp; 1829 mlpp = &mlp->ml_next; 1830 } 1831 fclose(mlfile); 1832} 1833 1834void 1835del_mlist(hostp, dirp) 1836 char *hostp, *dirp; 1837{ 1838 struct mountlist *mlp, **mlpp; 1839 struct mountlist *mlp2; 1840 FILE *mlfile; 1841 int fnd = 0; 1842 1843 mlpp = &mlhead; 1844 mlp = mlhead; 1845 while (mlp) { 1846 if (!strcmp(mlp->ml_host, hostp) && 1847 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 1848 fnd = 1; 1849 mlp2 = mlp; 1850 *mlpp = mlp = mlp->ml_next; 1851 free((caddr_t)mlp2); 1852 } else { 1853 mlpp = &mlp->ml_next; 1854 mlp = mlp->ml_next; 1855 } 1856 } 1857 if (fnd) { 1858 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 1859 syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 1860 return; 1861 } 1862 mlp = mlhead; 1863 while (mlp) { 1864 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1865 mlp = mlp->ml_next; 1866 } 1867 fclose(mlfile); 1868 } 1869} 1870 1871void 1872add_mlist(hostp, dirp) 1873 char *hostp, *dirp; 1874{ 1875 struct mountlist *mlp, **mlpp; 1876 FILE *mlfile; 1877 1878 mlpp = &mlhead; 1879 mlp = mlhead; 1880 while (mlp) { 1881 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 1882 return; 1883 mlpp = &mlp->ml_next; 1884 mlp = mlp->ml_next; 1885 } 1886 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1887 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 1888 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 1889 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 1890 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 1891 mlp->ml_next = (struct mountlist *)NULL; 1892 *mlpp = mlp; 1893 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 1894 syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 1895 return; 1896 } 1897 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1898 fclose(mlfile); 1899} 1900 1901/* 1902 * This function is called via. SIGTERM when the system is going down. 1903 * It sends a broadcast RPCMNT_UMNTALL. 1904 */ 1905void 1906send_umntall() 1907{ 1908 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 1909 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 1910 exit(0); 1911} 1912 1913int 1914umntall_each(resultsp, raddr) 1915 caddr_t resultsp; 1916 struct sockaddr_in *raddr; 1917{ 1918 return (1); 1919} 1920 1921/* 1922 * Free up a group list. 1923 */ 1924void 1925free_grp(grp) 1926 struct grouplist *grp; 1927{ 1928 char **addrp; 1929 1930 if (grp->gr_type == GT_HOST) { 1931 if (grp->gr_ptr.gt_hostent->h_name) { 1932 addrp = grp->gr_ptr.gt_hostent->h_addr_list; 1933 while (addrp && *addrp) 1934 free(*addrp++); 1935 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 1936 free(grp->gr_ptr.gt_hostent->h_name); 1937 } 1938 free((caddr_t)grp->gr_ptr.gt_hostent); 1939 } else if (grp->gr_type == GT_NET) { 1940 if (grp->gr_ptr.gt_net.nt_name) 1941 free(grp->gr_ptr.gt_net.nt_name); 1942 } 1943#ifdef ISO 1944 else if (grp->gr_type == GT_ISO) 1945 free((caddr_t)grp->gr_ptr.gt_isoaddr); 1946#endif 1947 free((caddr_t)grp); 1948} 1949 1950#ifdef DEBUG 1951void 1952SYSLOG(int pri, const char *fmt, ...) 1953{ 1954 va_list ap; 1955 1956 va_start(ap, fmt); 1957 vfprintf(stderr, fmt, ap); 1958 va_end(ap); 1959} 1960#endif /* DEBUG */ 1961 1962/* 1963 * Check options for consistency. 1964 */ 1965int 1966check_options(dp) 1967 struct dirlist *dp; 1968{ 1969 1970 if (dp == (struct dirlist *)NULL) 1971 return (1); 1972 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 1973 (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 1974 (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 1975 syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 1976 return (1); 1977 } 1978 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 1979 syslog(LOG_ERR, "-mask requires -net"); 1980 return (1); 1981 } 1982 if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 1983 syslog(LOG_ERR, "-net and -iso mutually exclusive"); 1984 return (1); 1985 } 1986 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 1987 syslog(LOG_ERR, "-alldir has multiple directories"); 1988 return (1); 1989 } 1990 return (0); 1991} 1992 1993/* 1994 * Check an absolute directory path for any symbolic links. Return true 1995 * if no symbolic links are found. 1996 */ 1997int 1998check_dirpath(dirp) 1999 char *dirp; 2000{ 2001 char *cp; 2002 int ret = 1; 2003 struct stat sb; 2004 2005 cp = dirp + 1; 2006 while (*cp && ret) { 2007 if (*cp == '/') { 2008 *cp = '\0'; 2009 if (lstat(dirp, &sb) < 0 || 2010 (sb.st_mode & S_IFMT) != S_IFDIR) 2011 ret = 0; 2012 *cp = '/'; 2013 } 2014 cp++; 2015 } 2016 if (lstat(dirp, &sb) < 0 || 2017 (sb.st_mode & S_IFMT) != S_IFDIR) 2018 ret = 0; 2019 return (ret); 2020}
|