mountd.c revision 1558
1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Herb Hasler and Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38static char copyright[] = 39"@(#) Copyright (c) 1989, 1993\n\ 40 The Regents of the University of California. All rights reserved.\n"; 41#endif not lint 42 43#ifndef lint 44static char sccsid[] = "@(#)mountd.c 8.8 (Berkeley) 2/20/94"; 45#endif not lint 46 47#include <sys/param.h> 48#include <sys/file.h> 49#include <sys/ioctl.h> 50#include <sys/mount.h> 51#include <sys/socket.h> 52#include <sys/stat.h> 53#include <sys/syslog.h> 54#include <sys/ucred.h> 55 56#include <rpc/rpc.h> 57#include <rpc/pmap_clnt.h> 58#include <rpc/pmap_prot.h> 59#ifdef ISO 60#include <netiso/iso.h> 61#endif 62#include <nfs/rpcv2.h> 63#include <nfs/nfsv2.h> 64 65#include <arpa/inet.h> 66 67#include <ctype.h> 68#include <errno.h> 69#include <grp.h> 70#include <netdb.h> 71#include <pwd.h> 72#include <signal.h> 73#include <stdio.h> 74#include <stdlib.h> 75#include <string.h> 76#include <unistd.h> 77#include "pathnames.h" 78 79#ifdef DEBUG 80#include <stdarg.h> 81#endif 82 83/* 84 * Structures for keeping the mount list and export list 85 */ 86struct mountlist { 87 struct mountlist *ml_next; 88 char ml_host[RPCMNT_NAMELEN+1]; 89 char ml_dirp[RPCMNT_PATHLEN+1]; 90}; 91 92struct dirlist { 93 struct dirlist *dp_left; 94 struct dirlist *dp_right; 95 int dp_flag; 96 struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 97 char dp_dirp[1]; /* Actually malloc'd to size of dir */ 98}; 99/* dp_flag bits */ 100#define DP_DEFSET 0x1 101 102struct exportlist { 103 struct exportlist *ex_next; 104 struct dirlist *ex_dirl; 105 struct dirlist *ex_defdir; 106 int ex_flag; 107 fsid_t ex_fs; 108 char *ex_fsdir; 109}; 110/* ex_flag bits */ 111#define EX_LINKED 0x1 112 113struct netmsk { 114 u_long nt_net; 115 u_long nt_mask; 116 char *nt_name; 117}; 118 119union grouptypes { 120 struct hostent *gt_hostent; 121 struct netmsk gt_net; 122#ifdef ISO 123 struct sockaddr_iso *gt_isoaddr; 124#endif 125}; 126 127struct grouplist { 128 int gr_type; 129 union grouptypes gr_ptr; 130 struct grouplist *gr_next; 131}; 132/* Group types */ 133#define GT_NULL 0x0 134#define GT_HOST 0x1 135#define GT_NET 0x2 136#define GT_ISO 0x4 137 138struct hostlist { 139 struct grouplist *ht_grp; 140 struct hostlist *ht_next; 141}; 142 143/* Global defs */ 144char *add_expdir __P((struct dirlist **, char *, int)); 145void add_dlist __P((struct dirlist **, struct dirlist *, 146 struct grouplist *)); 147void add_mlist __P((char *, char *)); 148int check_dirpath __P((char *)); 149int check_options __P((struct dirlist *)); 150int chk_host __P((struct dirlist *, u_long, int *)); 151void del_mlist __P((char *, char *)); 152struct dirlist *dirp_search __P((struct dirlist *, char *)); 153int do_mount __P((struct exportlist *, struct grouplist *, int, 154 struct ucred *, char *, int, struct statfs *)); 155int do_opt __P((char **, char **, struct exportlist *, struct grouplist *, 156 int *, int *, struct ucred *)); 157struct exportlist *ex_search __P((fsid_t *)); 158struct exportlist *get_exp __P((void)); 159void free_dir __P((struct dirlist *)); 160void free_exp __P((struct exportlist *)); 161void free_grp __P((struct grouplist *)); 162void free_host __P((struct hostlist *)); 163void get_exportlist __P((void)); 164int get_host __P((char *, struct grouplist *)); 165struct hostlist *get_ht __P((void)); 166int get_line __P((void)); 167void get_mountlist __P((void)); 168int get_net __P((char *, struct netmsk *, int)); 169void getexp_err __P((struct exportlist *, struct grouplist *)); 170struct grouplist *get_grp __P((void)); 171void hang_dirp __P((struct dirlist *, struct grouplist *, 172 struct exportlist *, int)); 173void mntsrv __P((struct svc_req *, SVCXPRT *)); 174void nextfield __P((char **, char **)); 175void out_of_mem __P((void)); 176void parsecred __P((char *, struct ucred *)); 177int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *)); 178int scan_tree __P((struct dirlist *, u_long)); 179void send_umntall __P((void)); 180int umntall_each __P((caddr_t, struct sockaddr_in *)); 181int xdr_dir __P((XDR *, char *)); 182int xdr_explist __P((XDR *, caddr_t)); 183int xdr_fhs __P((XDR *, nfsv2fh_t *)); 184int xdr_mlist __P((XDR *, caddr_t)); 185 186/* C library */ 187int getnetgrent(); 188void endnetgrent(); 189void setnetgrent(); 190 191#ifdef ISO 192struct iso_addr *iso_addr(); 193#endif 194 195struct exportlist *exphead; 196struct mountlist *mlhead; 197struct grouplist *grphead; 198char exname[MAXPATHLEN]; 199struct ucred def_anon = { 200 1, 201 (uid_t) -2, 202 1, 203 { (gid_t) -2 } 204}; 205int root_only = 1; 206int opt_flags; 207/* Bits for above */ 208#define OP_MAPROOT 0x01 209#define OP_MAPALL 0x02 210#define OP_KERB 0x04 211#define OP_MASK 0x08 212#define OP_NET 0x10 213#define OP_ISO 0x20 214#define OP_ALLDIRS 0x40 215 216#ifdef DEBUG 217int debug = 1; 218void SYSLOG __P((int, const char *, ...)); 219#define syslog SYSLOG 220#else 221int debug = 0; 222#endif 223 224/* 225 * Mountd server for NFS mount protocol as described in: 226 * NFS: Network File System Protocol Specification, RFC1094, Appendix A 227 * The optional arguments are the exports file name 228 * default: _PATH_EXPORTS 229 * and "-n" to allow nonroot mount. 230 */ 231int 232main(argc, argv) 233 int argc; 234 char **argv; 235{ 236 SVCXPRT *transp; 237 int c; 238 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 targs.ua.fspec = NULL; 649 targs.ua.export.ex_flags = MNT_DELEXPORT; 650 if (mount(fsp->f_type, fsp->f_mntonname, 651 fsp->f_flags | MNT_UPDATE, 652 (caddr_t)&targs) < 0) 653 syslog(LOG_ERR, "Can't delete exports for %s", 654 fsp->f_mntonname); 655 } 656 fsp++; 657 } 658 659 /* 660 * Read in the exports file and build the list, calling 661 * mount() as we go along to push the export rules into the kernel. 662 */ 663 if ((exp_file = fopen(exname, "r")) == NULL) { 664 syslog(LOG_ERR, "Can't open %s", exname); 665 exit(2); 666 } 667 dirhead = (struct dirlist *)NULL; 668 while (get_line()) { 669 if (debug) 670 fprintf(stderr,"Got line %s\n",line); 671 cp = line; 672 nextfield(&cp, &endcp); 673 if (*cp == '#') 674 goto nextline; 675 676 /* 677 * Set defaults. 678 */ 679 has_host = FALSE; 680 anon = def_anon; 681 exflags = MNT_EXPORTED; 682 got_nondir = 0; 683 opt_flags = 0; 684 ep = (struct exportlist *)NULL; 685 686 /* 687 * Create new exports list entry 688 */ 689 len = endcp-cp; 690 tgrp = grp = get_grp(); 691 while (len > 0) { 692 if (len > RPCMNT_NAMELEN) { 693 getexp_err(ep, tgrp); 694 goto nextline; 695 } 696 if (*cp == '-') { 697 if (ep == (struct exportlist *)NULL) { 698 getexp_err(ep, tgrp); 699 goto nextline; 700 } 701 if (debug) 702 fprintf(stderr, "doing opt %s\n", cp); 703 got_nondir = 1; 704 if (do_opt(&cp, &endcp, ep, grp, &has_host, 705 &exflags, &anon)) { 706 getexp_err(ep, tgrp); 707 goto nextline; 708 } 709 } else if (*cp == '/') { 710 savedc = *endcp; 711 *endcp = '\0'; 712 if (check_dirpath(cp) && 713 statfs(cp, &fsb) >= 0) { 714 if (got_nondir) { 715 syslog(LOG_ERR, "Dirs must be first"); 716 getexp_err(ep, tgrp); 717 goto nextline; 718 } 719 if (ep) { 720 if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] || 721 ep->ex_fs.val[1] != fsb.f_fsid.val[1]) { 722 getexp_err(ep, tgrp); 723 goto nextline; 724 } 725 } else { 726 /* 727 * See if this directory is already 728 * in the list. 729 */ 730 ep = ex_search(&fsb.f_fsid); 731 if (ep == (struct exportlist *)NULL) { 732 ep = get_exp(); 733 ep->ex_fs = fsb.f_fsid; 734 ep->ex_fsdir = (char *) 735 malloc(strlen(fsb.f_mntonname) + 1); 736 if (ep->ex_fsdir) 737 strcpy(ep->ex_fsdir, 738 fsb.f_mntonname); 739 else 740 out_of_mem(); 741 if (debug) 742 fprintf(stderr, 743 "Making new ep fs=0x%x,0x%x\n", 744 fsb.f_fsid.val[0], 745 fsb.f_fsid.val[1]); 746 } else if (debug) 747 fprintf(stderr, 748 "Found ep fs=0x%x,0x%x\n", 749 fsb.f_fsid.val[0], 750 fsb.f_fsid.val[1]); 751 } 752 753 /* 754 * Add dirpath to export mount point. 755 */ 756 dirp = add_expdir(&dirhead, cp, len); 757 dirplen = len; 758 } else { 759 getexp_err(ep, tgrp); 760 goto nextline; 761 } 762 *endcp = savedc; 763 } else { 764 savedc = *endcp; 765 *endcp = '\0'; 766 got_nondir = 1; 767 if (ep == (struct exportlist *)NULL) { 768 getexp_err(ep, tgrp); 769 goto nextline; 770 } 771 772 /* 773 * Get the host or netgroup. 774 */ 775 setnetgrent(cp); 776 netgrp = getnetgrent(&hst, &usr, &dom); 777 do { 778 if (has_host) { 779 grp->gr_next = get_grp(); 780 grp = grp->gr_next; 781 } 782 if (netgrp) { 783 if (get_host(hst, grp)) { 784 syslog(LOG_ERR, "Bad netgroup %s", cp); 785 getexp_err(ep, tgrp); 786 goto nextline; 787 } 788 } else if (get_host(cp, grp)) { 789 getexp_err(ep, tgrp); 790 goto nextline; 791 } 792 has_host = TRUE; 793 } while (netgrp && getnetgrent(&hst, &usr, &dom)); 794 endnetgrent(); 795 *endcp = savedc; 796 } 797 cp = endcp; 798 nextfield(&cp, &endcp); 799 len = endcp - cp; 800 } 801 if (check_options(dirhead)) { 802 getexp_err(ep, tgrp); 803 goto nextline; 804 } 805 if (!has_host) { 806 grp->gr_type = GT_HOST; 807 if (debug) 808 fprintf(stderr,"Adding a default entry\n"); 809 /* add a default group and make the grp list NULL */ 810 hpe = (struct hostent *)malloc(sizeof(struct hostent)); 811 if (hpe == (struct hostent *)NULL) 812 out_of_mem(); 813 hpe->h_name = "Default"; 814 hpe->h_addrtype = AF_INET; 815 hpe->h_length = sizeof (u_long); 816 hpe->h_addr_list = (char **)NULL; 817 grp->gr_ptr.gt_hostent = hpe; 818 819 /* 820 * Don't allow a network export coincide with a list of 821 * host(s) on the same line. 822 */ 823 } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 824 getexp_err(ep, tgrp); 825 goto nextline; 826 } 827 828 /* 829 * Loop through hosts, pushing the exports into the kernel. 830 * After loop, tgrp points to the start of the list and 831 * grp points to the last entry in the list. 832 */ 833 grp = tgrp; 834 do { 835 if (do_mount(ep, grp, exflags, &anon, dirp, 836 dirplen, &fsb)) { 837 getexp_err(ep, tgrp); 838 goto nextline; 839 } 840 } while (grp->gr_next && (grp = grp->gr_next)); 841 842 /* 843 * Success. Update the data structures. 844 */ 845 if (has_host) { 846 hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS)); 847 grp->gr_next = grphead; 848 grphead = tgrp; 849 } else { 850 hang_dirp(dirhead, (struct grouplist *)NULL, ep, 851 (opt_flags & OP_ALLDIRS)); 852 free_grp(grp); 853 } 854 dirhead = (struct dirlist *)NULL; 855 if ((ep->ex_flag & EX_LINKED) == 0) { 856 ep2 = exphead; 857 epp = &exphead; 858 859 /* 860 * Insert in the list in alphabetical order. 861 */ 862 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 863 epp = &ep2->ex_next; 864 ep2 = ep2->ex_next; 865 } 866 if (ep2) 867 ep->ex_next = ep2; 868 *epp = ep; 869 ep->ex_flag |= EX_LINKED; 870 } 871nextline: 872 if (dirhead) { 873 free_dir(dirhead); 874 dirhead = (struct dirlist *)NULL; 875 } 876 } 877 fclose(exp_file); 878} 879 880/* 881 * Allocate an export list element 882 */ 883struct exportlist * 884get_exp() 885{ 886 struct exportlist *ep; 887 888 ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 889 if (ep == (struct exportlist *)NULL) 890 out_of_mem(); 891 bzero((caddr_t)ep, sizeof (struct exportlist)); 892 return (ep); 893} 894 895/* 896 * Allocate a group list element 897 */ 898struct grouplist * 899get_grp() 900{ 901 struct grouplist *gp; 902 903 gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 904 if (gp == (struct grouplist *)NULL) 905 out_of_mem(); 906 bzero((caddr_t)gp, sizeof (struct grouplist)); 907 return (gp); 908} 909 910/* 911 * Clean up upon an error in get_exportlist(). 912 */ 913void 914getexp_err(ep, grp) 915 struct exportlist *ep; 916 struct grouplist *grp; 917{ 918 struct grouplist *tgrp; 919 920 syslog(LOG_ERR, "Bad exports list line %s", line); 921 if (ep && (ep->ex_flag & EX_LINKED) == 0) 922 free_exp(ep); 923 while (grp) { 924 tgrp = grp; 925 grp = grp->gr_next; 926 free_grp(tgrp); 927 } 928} 929 930/* 931 * Search the export list for a matching fs. 932 */ 933struct exportlist * 934ex_search(fsid) 935 fsid_t *fsid; 936{ 937 struct exportlist *ep; 938 939 ep = exphead; 940 while (ep) { 941 if (ep->ex_fs.val[0] == fsid->val[0] && 942 ep->ex_fs.val[1] == fsid->val[1]) 943 return (ep); 944 ep = ep->ex_next; 945 } 946 return (ep); 947} 948 949/* 950 * Add a directory path to the list. 951 */ 952char * 953add_expdir(dpp, cp, len) 954 struct dirlist **dpp; 955 char *cp; 956 int len; 957{ 958 struct dirlist *dp; 959 960 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 961 dp->dp_left = *dpp; 962 dp->dp_right = (struct dirlist *)NULL; 963 dp->dp_flag = 0; 964 dp->dp_hosts = (struct hostlist *)NULL; 965 strcpy(dp->dp_dirp, cp); 966 *dpp = dp; 967 return (dp->dp_dirp); 968} 969 970/* 971 * Hang the dir list element off the dirpath binary tree as required 972 * and update the entry for host. 973 */ 974void 975hang_dirp(dp, grp, ep, alldirs) 976 struct dirlist *dp; 977 struct grouplist *grp; 978 struct exportlist *ep; 979 int alldirs; 980{ 981 struct hostlist *hp; 982 struct dirlist *dp2; 983 984 if (alldirs) { 985 if (ep->ex_defdir) 986 free((caddr_t)dp); 987 else 988 ep->ex_defdir = dp; 989 if (grp == (struct grouplist *)NULL) 990 ep->ex_defdir->dp_flag |= DP_DEFSET; 991 else while (grp) { 992 hp = get_ht(); 993 hp->ht_grp = grp; 994 hp->ht_next = ep->ex_defdir->dp_hosts; 995 ep->ex_defdir->dp_hosts = hp; 996 grp = grp->gr_next; 997 } 998 } else { 999 1000 /* 1001 * Loop throught the directories adding them to the tree. 1002 */ 1003 while (dp) { 1004 dp2 = dp->dp_left; 1005 add_dlist(&ep->ex_dirl, dp, grp); 1006 dp = dp2; 1007 } 1008 } 1009} 1010 1011/* 1012 * Traverse the binary tree either updating a node that is already there 1013 * for the new directory or adding the new node. 1014 */ 1015void 1016add_dlist(dpp, newdp, grp) 1017 struct dirlist **dpp; 1018 struct dirlist *newdp; 1019 struct grouplist *grp; 1020{ 1021 struct dirlist *dp; 1022 struct hostlist *hp; 1023 int cmp; 1024 1025 dp = *dpp; 1026 if (dp) { 1027 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1028 if (cmp > 0) { 1029 add_dlist(&dp->dp_left, newdp, grp); 1030 return; 1031 } else if (cmp < 0) { 1032 add_dlist(&dp->dp_right, newdp, grp); 1033 return; 1034 } else 1035 free((caddr_t)newdp); 1036 } else { 1037 dp = newdp; 1038 dp->dp_left = (struct dirlist *)NULL; 1039 *dpp = dp; 1040 } 1041 if (grp) { 1042 1043 /* 1044 * Hang all of the host(s) off of the directory point. 1045 */ 1046 do { 1047 hp = get_ht(); 1048 hp->ht_grp = grp; 1049 hp->ht_next = dp->dp_hosts; 1050 dp->dp_hosts = hp; 1051 grp = grp->gr_next; 1052 } while (grp); 1053 } else 1054 dp->dp_flag |= DP_DEFSET; 1055} 1056 1057/* 1058 * Search for a dirpath on the export point. 1059 */ 1060struct dirlist * 1061dirp_search(dp, dirpath) 1062 struct dirlist *dp; 1063 char *dirpath; 1064{ 1065 int cmp; 1066 1067 if (dp) { 1068 cmp = strcmp(dp->dp_dirp, dirpath); 1069 if (cmp > 0) 1070 return (dirp_search(dp->dp_left, dirpath)); 1071 else if (cmp < 0) 1072 return (dirp_search(dp->dp_right, dirpath)); 1073 else 1074 return (dp); 1075 } 1076 return (dp); 1077} 1078 1079/* 1080 * Scan for a host match in a directory tree. 1081 */ 1082int 1083chk_host(dp, saddr, defsetp) 1084 struct dirlist *dp; 1085 u_long saddr; 1086 int *defsetp; 1087{ 1088 struct hostlist *hp; 1089 struct grouplist *grp; 1090 u_long **addrp; 1091 1092 if (dp) { 1093 if (dp->dp_flag & DP_DEFSET) 1094 *defsetp = 1; 1095 hp = dp->dp_hosts; 1096 while (hp) { 1097 grp = hp->ht_grp; 1098 switch (grp->gr_type) { 1099 case GT_HOST: 1100 addrp = (u_long **) 1101 grp->gr_ptr.gt_hostent->h_addr_list; 1102 while (*addrp) { 1103 if (**addrp == saddr) 1104 return (1); 1105 addrp++; 1106 } 1107 break; 1108 case GT_NET: 1109 if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 1110 grp->gr_ptr.gt_net.nt_net) 1111 return (1); 1112 break; 1113 }; 1114 hp = hp->ht_next; 1115 } 1116 } 1117 return (0); 1118} 1119 1120/* 1121 * Scan tree for a host that matches the address. 1122 */ 1123int 1124scan_tree(dp, saddr) 1125 struct dirlist *dp; 1126 u_long saddr; 1127{ 1128 int defset; 1129 1130 if (dp) { 1131 if (scan_tree(dp->dp_left, saddr)) 1132 return (1); 1133 if (chk_host(dp, saddr, &defset)) 1134 return (1); 1135 if (scan_tree(dp->dp_right, saddr)) 1136 return (1); 1137 } 1138 return (0); 1139} 1140 1141/* 1142 * Traverse the dirlist tree and free it up. 1143 */ 1144void 1145free_dir(dp) 1146 struct dirlist *dp; 1147{ 1148 1149 if (dp) { 1150 free_dir(dp->dp_left); 1151 free_dir(dp->dp_right); 1152 free_host(dp->dp_hosts); 1153 free((caddr_t)dp); 1154 } 1155} 1156 1157/* 1158 * Parse the option string and update fields. 1159 * Option arguments may either be -<option>=<value> or 1160 * -<option> <value> 1161 */ 1162int 1163do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1164 char **cpp, **endcpp; 1165 struct exportlist *ep; 1166 struct grouplist *grp; 1167 int *has_hostp; 1168 int *exflagsp; 1169 struct ucred *cr; 1170{ 1171 char *cpoptarg, *cpoptend; 1172 char *cp, *endcp, *cpopt, savedc, savedc2; 1173 int allflag, usedarg; 1174 1175 cpopt = *cpp; 1176 cpopt++; 1177 cp = *endcpp; 1178 savedc = *cp; 1179 *cp = '\0'; 1180 while (cpopt && *cpopt) { 1181 allflag = 1; 1182 usedarg = -2; 1183 if (cpoptend = index(cpopt, ',')) { 1184 *cpoptend++ = '\0'; 1185 if (cpoptarg = index(cpopt, '=')) 1186 *cpoptarg++ = '\0'; 1187 } else { 1188 if (cpoptarg = index(cpopt, '=')) 1189 *cpoptarg++ = '\0'; 1190 else { 1191 *cp = savedc; 1192 nextfield(&cp, &endcp); 1193 **endcpp = '\0'; 1194 if (endcp > cp && *cp != '-') { 1195 cpoptarg = cp; 1196 savedc2 = *endcp; 1197 *endcp = '\0'; 1198 usedarg = 0; 1199 } 1200 } 1201 } 1202 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1203 *exflagsp |= MNT_EXRDONLY; 1204 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1205 !(allflag = strcmp(cpopt, "mapall")) || 1206 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1207 usedarg++; 1208 parsecred(cpoptarg, cr); 1209 if (allflag == 0) { 1210 *exflagsp |= MNT_EXPORTANON; 1211 opt_flags |= OP_MAPALL; 1212 } else 1213 opt_flags |= OP_MAPROOT; 1214 } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 1215 *exflagsp |= MNT_EXKERB; 1216 opt_flags |= OP_KERB; 1217 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1218 !strcmp(cpopt, "m"))) { 1219 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1220 syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 1221 return (1); 1222 } 1223 usedarg++; 1224 opt_flags |= OP_MASK; 1225 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1226 !strcmp(cpopt, "n"))) { 1227 if (grp->gr_type != GT_NULL) { 1228 syslog(LOG_ERR, "Network/host conflict"); 1229 return (1); 1230 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1231 syslog(LOG_ERR, "Bad net: %s", cpoptarg); 1232 return (1); 1233 } 1234 grp->gr_type = GT_NET; 1235 *has_hostp = 1; 1236 usedarg++; 1237 opt_flags |= OP_NET; 1238 } else if (!strcmp(cpopt, "alldirs")) { 1239 opt_flags |= OP_ALLDIRS; 1240#ifdef ISO 1241 } else if (cpoptarg && !strcmp(cpopt, "iso")) { 1242 if (get_isoaddr(cpoptarg, grp)) { 1243 syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 1244 return (1); 1245 } 1246 *has_hostp = 1; 1247 usedarg++; 1248 opt_flags |= OP_ISO; 1249#endif /* ISO */ 1250 } else { 1251 syslog(LOG_ERR, "Bad opt %s", cpopt); 1252 return (1); 1253 } 1254 if (usedarg >= 0) { 1255 *endcp = savedc2; 1256 **endcpp = savedc; 1257 if (usedarg > 0) { 1258 *cpp = cp; 1259 *endcpp = endcp; 1260 } 1261 return (0); 1262 } 1263 cpopt = cpoptend; 1264 } 1265 **endcpp = savedc; 1266 return (0); 1267} 1268 1269/* 1270 * Translate a character string to the corresponding list of network 1271 * addresses for a hostname. 1272 */ 1273int 1274get_host(cp, grp) 1275 char *cp; 1276 struct grouplist *grp; 1277{ 1278 struct hostent *hp, *nhp; 1279 char **addrp, **naddrp; 1280 struct hostent t_host; 1281 int i; 1282 u_long saddr; 1283 char *aptr[2]; 1284 1285 if (grp->gr_type != GT_NULL) 1286 return (1); 1287 if ((hp = gethostbyname(cp)) == NULL) { 1288 if (isdigit(*cp)) { 1289 saddr = inet_addr(cp); 1290 if (saddr == -1) { 1291 syslog(LOG_ERR, "Inet_addr failed"); 1292 return (1); 1293 } 1294 if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 1295 AF_INET)) == NULL) { 1296 hp = &t_host; 1297 hp->h_name = cp; 1298 hp->h_addrtype = AF_INET; 1299 hp->h_length = sizeof (u_long); 1300 hp->h_addr_list = aptr; 1301 aptr[0] = (char *)&saddr; 1302 aptr[1] = (char *)NULL; 1303 } 1304 } else { 1305 syslog(LOG_ERR, "Gethostbyname failed"); 1306 return (1); 1307 } 1308 } 1309 grp->gr_type = GT_HOST; 1310 nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 1311 malloc(sizeof(struct hostent)); 1312 if (nhp == (struct hostent *)NULL) 1313 out_of_mem(); 1314 bcopy((caddr_t)hp, (caddr_t)nhp, 1315 sizeof(struct hostent)); 1316 i = strlen(hp->h_name)+1; 1317 nhp->h_name = (char *)malloc(i); 1318 if (nhp->h_name == (char *)NULL) 1319 out_of_mem(); 1320 bcopy(hp->h_name, nhp->h_name, i); 1321 addrp = hp->h_addr_list; 1322 i = 1; 1323 while (*addrp++) 1324 i++; 1325 naddrp = nhp->h_addr_list = (char **) 1326 malloc(i*sizeof(char *)); 1327 if (naddrp == (char **)NULL) 1328 out_of_mem(); 1329 addrp = hp->h_addr_list; 1330 while (*addrp) { 1331 *naddrp = (char *) 1332 malloc(hp->h_length); 1333 if (*naddrp == (char *)NULL) 1334 out_of_mem(); 1335 bcopy(*addrp, *naddrp, 1336 hp->h_length); 1337 addrp++; 1338 naddrp++; 1339 } 1340 *naddrp = (char *)NULL; 1341 if (debug) 1342 fprintf(stderr, "got host %s\n", hp->h_name); 1343 return (0); 1344} 1345 1346/* 1347 * Free up an exports list component 1348 */ 1349void 1350free_exp(ep) 1351 struct exportlist *ep; 1352{ 1353 1354 if (ep->ex_defdir) { 1355 free_host(ep->ex_defdir->dp_hosts); 1356 free((caddr_t)ep->ex_defdir); 1357 } 1358 if (ep->ex_fsdir) 1359 free(ep->ex_fsdir); 1360 free_dir(ep->ex_dirl); 1361 free((caddr_t)ep); 1362} 1363 1364/* 1365 * Free hosts. 1366 */ 1367void 1368free_host(hp) 1369 struct hostlist *hp; 1370{ 1371 struct hostlist *hp2; 1372 1373 while (hp) { 1374 hp2 = hp; 1375 hp = hp->ht_next; 1376 free((caddr_t)hp2); 1377 } 1378} 1379 1380struct hostlist * 1381get_ht() 1382{ 1383 struct hostlist *hp; 1384 1385 hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 1386 if (hp == (struct hostlist *)NULL) 1387 out_of_mem(); 1388 hp->ht_next = (struct hostlist *)NULL; 1389 return (hp); 1390} 1391 1392#ifdef ISO 1393/* 1394 * Translate an iso address. 1395 */ 1396get_isoaddr(cp, grp) 1397 char *cp; 1398 struct grouplist *grp; 1399{ 1400 struct iso_addr *isop; 1401 struct sockaddr_iso *isoaddr; 1402 1403 if (grp->gr_type != GT_NULL) 1404 return (1); 1405 if ((isop = iso_addr(cp)) == NULL) { 1406 syslog(LOG_ERR, 1407 "iso_addr failed, ignored"); 1408 return (1); 1409 } 1410 isoaddr = (struct sockaddr_iso *) 1411 malloc(sizeof (struct sockaddr_iso)); 1412 if (isoaddr == (struct sockaddr_iso *)NULL) 1413 out_of_mem(); 1414 bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 1415 bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 1416 sizeof (struct iso_addr)); 1417 isoaddr->siso_len = sizeof (struct sockaddr_iso); 1418 isoaddr->siso_family = AF_ISO; 1419 grp->gr_type = GT_ISO; 1420 grp->gr_ptr.gt_isoaddr = isoaddr; 1421 return (0); 1422} 1423#endif /* ISO */ 1424 1425/* 1426 * Out of memory, fatal 1427 */ 1428void 1429out_of_mem() 1430{ 1431 1432 syslog(LOG_ERR, "Out of memory"); 1433 exit(2); 1434} 1435 1436/* 1437 * Do the mount syscall with the update flag to push the export info into 1438 * the kernel. 1439 */ 1440int 1441do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 1442 struct exportlist *ep; 1443 struct grouplist *grp; 1444 int exflags; 1445 struct ucred *anoncrp; 1446 char *dirp; 1447 int dirplen; 1448 struct statfs *fsb; 1449{ 1450 char *cp = (char *)NULL; 1451 u_long **addrp; 1452 int done; 1453 char savedc = '\0'; 1454 struct sockaddr_in sin, imask; 1455 union { 1456 struct ufs_args ua; 1457 struct iso_args ia; 1458 struct mfs_args ma; 1459 } args; 1460 u_long net; 1461 1462 args.ua.fspec = 0; 1463 args.ua.export.ex_flags = exflags; 1464 args.ua.export.ex_anon = *anoncrp; 1465 bzero((char *)&sin, sizeof(sin)); 1466 bzero((char *)&imask, sizeof(imask)); 1467 sin.sin_family = AF_INET; 1468 sin.sin_len = sizeof(sin); 1469 imask.sin_family = AF_INET; 1470 imask.sin_len = sizeof(sin); 1471 if (grp->gr_type == GT_HOST) 1472 addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 1473 else 1474 addrp = (u_long **)NULL; 1475 done = FALSE; 1476 while (!done) { 1477 switch (grp->gr_type) { 1478 case GT_HOST: 1479 if (addrp) { 1480 sin.sin_addr.s_addr = **addrp; 1481 args.ua.export.ex_addrlen = sizeof(sin); 1482 } else 1483 args.ua.export.ex_addrlen = 0; 1484 args.ua.export.ex_addr = (struct sockaddr *)&sin; 1485 args.ua.export.ex_masklen = 0; 1486 break; 1487 case GT_NET: 1488 if (grp->gr_ptr.gt_net.nt_mask) 1489 imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 1490 else { 1491 net = ntohl(grp->gr_ptr.gt_net.nt_net); 1492 if (IN_CLASSA(net)) 1493 imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 1494 else if (IN_CLASSB(net)) 1495 imask.sin_addr.s_addr = 1496 inet_addr("255.255.0.0"); 1497 else 1498 imask.sin_addr.s_addr = 1499 inet_addr("255.255.255.0"); 1500 grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 1501 } 1502 sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 1503 args.ua.export.ex_addr = (struct sockaddr *)&sin; 1504 args.ua.export.ex_addrlen = sizeof (sin); 1505 args.ua.export.ex_mask = (struct sockaddr *)&imask; 1506 args.ua.export.ex_masklen = sizeof (imask); 1507 break; 1508#ifdef ISO 1509 case GT_ISO: 1510 args.ua.export.ex_addr = 1511 (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 1512 args.ua.export.ex_addrlen = 1513 sizeof(struct sockaddr_iso); 1514 args.ua.export.ex_masklen = 0; 1515 break; 1516#endif /* ISO */ 1517 default: 1518 syslog(LOG_ERR, "Bad grouptype"); 1519 if (cp) 1520 *cp = savedc; 1521 return (1); 1522 }; 1523 1524 /* 1525 * XXX: 1526 * Maybe I should just use the fsb->f_mntonname path instead 1527 * of looping back up the dirp to the mount point?? 1528 * Also, needs to know how to export all types of local 1529 * exportable file systems and not just MOUNT_UFS. 1530 */ 1531 while (mount(fsb->f_type, dirp, 1532 fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 1533 if (cp) 1534 *cp-- = savedc; 1535 else 1536 cp = dirp + dirplen - 1; 1537 if (errno == EPERM) { 1538 syslog(LOG_ERR, 1539 "Can't change attributes for %s.\n", dirp); 1540 return (1); 1541 } 1542 if (opt_flags & OP_ALLDIRS) { 1543 syslog(LOG_ERR, "Not root dir"); 1544 return (1); 1545 } 1546 /* back up over the last component */ 1547 while (*cp == '/' && cp > dirp) 1548 cp--; 1549 while (*(cp - 1) != '/' && cp > dirp) 1550 cp--; 1551 if (cp == dirp) { 1552 if (debug) 1553 fprintf(stderr,"mnt unsucc\n"); 1554 syslog(LOG_ERR, "Can't export %s", dirp); 1555 return (1); 1556 } 1557 savedc = *cp; 1558 *cp = '\0'; 1559 } 1560 if (addrp) { 1561 ++addrp; 1562 if (*addrp == (u_long *)NULL) 1563 done = TRUE; 1564 } else 1565 done = TRUE; 1566 } 1567 if (cp) 1568 *cp = savedc; 1569 return (0); 1570} 1571 1572/* 1573 * Translate a net address. 1574 */ 1575int 1576get_net(cp, net, maskflg) 1577 char *cp; 1578 struct netmsk *net; 1579 int maskflg; 1580{ 1581 struct netent *np; 1582 long netaddr; 1583 struct in_addr inetaddr, inetaddr2; 1584 char *name; 1585 1586 if (np = getnetbyname(cp)) 1587 inetaddr = inet_makeaddr(np->n_net, 0); 1588 else if (isdigit(*cp)) { 1589 if ((netaddr = inet_network(cp)) == -1) 1590 return (1); 1591 inetaddr = inet_makeaddr(netaddr, 0); 1592 /* 1593 * Due to arbritrary subnet masks, you don't know how many 1594 * bits to shift the address to make it into a network, 1595 * however you do know how to make a network address into 1596 * a host with host == 0 and then compare them. 1597 * (What a pest) 1598 */ 1599 if (!maskflg) { 1600 setnetent(0); 1601 while (np = getnetent()) { 1602 inetaddr2 = inet_makeaddr(np->n_net, 0); 1603 if (inetaddr2.s_addr == inetaddr.s_addr) 1604 break; 1605 } 1606 endnetent(); 1607 } 1608 } else 1609 return (1); 1610 if (maskflg) 1611 net->nt_mask = inetaddr.s_addr; 1612 else { 1613 if (np) 1614 name = np->n_name; 1615 else 1616 name = inet_ntoa(inetaddr); 1617 net->nt_name = (char *)malloc(strlen(name) + 1); 1618 if (net->nt_name == (char *)NULL) 1619 out_of_mem(); 1620 strcpy(net->nt_name, name); 1621 net->nt_net = inetaddr.s_addr; 1622 } 1623 return (0); 1624} 1625 1626/* 1627 * Parse out the next white space separated field 1628 */ 1629void 1630nextfield(cp, endcp) 1631 char **cp; 1632 char **endcp; 1633{ 1634 char *p; 1635 1636 p = *cp; 1637 while (*p == ' ' || *p == '\t') 1638 p++; 1639 if (*p == '\n' || *p == '\0') 1640 *cp = *endcp = p; 1641 else { 1642 *cp = p++; 1643 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 1644 p++; 1645 *endcp = p; 1646 } 1647} 1648 1649/* 1650 * Get an exports file line. Skip over blank lines and handle line 1651 * continuations. 1652 */ 1653int 1654get_line() 1655{ 1656 char *p, *cp; 1657 int len; 1658 int totlen, cont_line; 1659 1660 /* 1661 * Loop around ignoring blank lines and getting all continuation lines. 1662 */ 1663 p = line; 1664 totlen = 0; 1665 do { 1666 if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 1667 return (0); 1668 len = strlen(p); 1669 cp = p + len - 1; 1670 cont_line = 0; 1671 while (cp >= p && 1672 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 1673 if (*cp == '\\') 1674 cont_line = 1; 1675 cp--; 1676 len--; 1677 } 1678 *++cp = '\0'; 1679 if (len > 0) { 1680 totlen += len; 1681 if (totlen >= LINESIZ) { 1682 syslog(LOG_ERR, "Exports line too long"); 1683 exit(2); 1684 } 1685 p = cp; 1686 } 1687 } while (totlen == 0 || cont_line); 1688 return (1); 1689} 1690 1691/* 1692 * Parse a description of a credential. 1693 */ 1694void 1695parsecred(namelist, cr) 1696 char *namelist; 1697 struct ucred *cr; 1698{ 1699 char *name; 1700 int cnt; 1701 char *names; 1702 struct passwd *pw; 1703 struct group *gr; 1704 int ngroups, groups[NGROUPS + 1]; 1705 1706 /* 1707 * Set up the unpriviledged user. 1708 */ 1709 cr->cr_ref = 1; 1710 cr->cr_uid = -2; 1711 cr->cr_groups[0] = -2; 1712 cr->cr_ngroups = 1; 1713 /* 1714 * Get the user's password table entry. 1715 */ 1716 names = strsep(&namelist, " \t\n"); 1717 name = strsep(&names, ":"); 1718 if (isdigit(*name) || *name == '-') 1719 pw = getpwuid(atoi(name)); 1720 else 1721 pw = getpwnam(name); 1722 /* 1723 * Credentials specified as those of a user. 1724 */ 1725 if (names == NULL) { 1726 if (pw == NULL) { 1727 syslog(LOG_ERR, "Unknown user: %s", name); 1728 return; 1729 } 1730 cr->cr_uid = pw->pw_uid; 1731 ngroups = NGROUPS + 1; 1732 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 1733 syslog(LOG_ERR, "Too many groups"); 1734 /* 1735 * Convert from int's to gid_t's and compress out duplicate 1736 */ 1737 cr->cr_ngroups = ngroups - 1; 1738 cr->cr_groups[0] = groups[0]; 1739 for (cnt = 2; cnt < ngroups; cnt++) 1740 cr->cr_groups[cnt - 1] = groups[cnt]; 1741 return; 1742 } 1743 /* 1744 * Explicit credential specified as a colon separated list: 1745 * uid:gid:gid:... 1746 */ 1747 if (pw != NULL) 1748 cr->cr_uid = pw->pw_uid; 1749 else if (isdigit(*name) || *name == '-') 1750 cr->cr_uid = atoi(name); 1751 else { 1752 syslog(LOG_ERR, "Unknown user: %s", name); 1753 return; 1754 } 1755 cr->cr_ngroups = 0; 1756 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 1757 name = strsep(&names, ":"); 1758 if (isdigit(*name) || *name == '-') { 1759 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 1760 } else { 1761 if ((gr = getgrnam(name)) == NULL) { 1762 syslog(LOG_ERR, "Unknown group: %s", name); 1763 continue; 1764 } 1765 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 1766 } 1767 } 1768 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 1769 syslog(LOG_ERR, "Too many groups"); 1770} 1771 1772#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 1773/* 1774 * Routines that maintain the remote mounttab 1775 */ 1776void 1777get_mountlist() 1778{ 1779 struct mountlist *mlp, **mlpp; 1780 char *eos, *dirp; 1781 int len; 1782 char str[STRSIZ]; 1783 FILE *mlfile; 1784 1785 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 1786 syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 1787 return; 1788 } 1789 mlpp = &mlhead; 1790 while (fgets(str, STRSIZ, mlfile) != NULL) { 1791 if ((dirp = index(str, '\t')) == NULL && 1792 (dirp = index(str, ' ')) == NULL) 1793 continue; 1794 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1795 len = dirp-str; 1796 if (len > RPCMNT_NAMELEN) 1797 len = RPCMNT_NAMELEN; 1798 bcopy(str, mlp->ml_host, len); 1799 mlp->ml_host[len] = '\0'; 1800 while (*dirp == '\t' || *dirp == ' ') 1801 dirp++; 1802 if ((eos = index(dirp, '\t')) == NULL && 1803 (eos = index(dirp, ' ')) == NULL && 1804 (eos = index(dirp, '\n')) == NULL) 1805 len = strlen(dirp); 1806 else 1807 len = eos-dirp; 1808 if (len > RPCMNT_PATHLEN) 1809 len = RPCMNT_PATHLEN; 1810 bcopy(dirp, mlp->ml_dirp, len); 1811 mlp->ml_dirp[len] = '\0'; 1812 mlp->ml_next = (struct mountlist *)NULL; 1813 *mlpp = mlp; 1814 mlpp = &mlp->ml_next; 1815 } 1816 fclose(mlfile); 1817} 1818 1819void 1820del_mlist(hostp, dirp) 1821 char *hostp, *dirp; 1822{ 1823 struct mountlist *mlp, **mlpp; 1824 struct mountlist *mlp2; 1825 FILE *mlfile; 1826 int fnd = 0; 1827 1828 mlpp = &mlhead; 1829 mlp = mlhead; 1830 while (mlp) { 1831 if (!strcmp(mlp->ml_host, hostp) && 1832 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 1833 fnd = 1; 1834 mlp2 = mlp; 1835 *mlpp = mlp = mlp->ml_next; 1836 free((caddr_t)mlp2); 1837 } else { 1838 mlpp = &mlp->ml_next; 1839 mlp = mlp->ml_next; 1840 } 1841 } 1842 if (fnd) { 1843 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 1844 syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 1845 return; 1846 } 1847 mlp = mlhead; 1848 while (mlp) { 1849 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1850 mlp = mlp->ml_next; 1851 } 1852 fclose(mlfile); 1853 } 1854} 1855 1856void 1857add_mlist(hostp, dirp) 1858 char *hostp, *dirp; 1859{ 1860 struct mountlist *mlp, **mlpp; 1861 FILE *mlfile; 1862 1863 mlpp = &mlhead; 1864 mlp = mlhead; 1865 while (mlp) { 1866 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 1867 return; 1868 mlpp = &mlp->ml_next; 1869 mlp = mlp->ml_next; 1870 } 1871 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1872 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 1873 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 1874 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 1875 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 1876 mlp->ml_next = (struct mountlist *)NULL; 1877 *mlpp = mlp; 1878 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 1879 syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 1880 return; 1881 } 1882 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1883 fclose(mlfile); 1884} 1885 1886/* 1887 * This function is called via. SIGTERM when the system is going down. 1888 * It sends a broadcast RPCMNT_UMNTALL. 1889 */ 1890void 1891send_umntall() 1892{ 1893 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 1894 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 1895 exit(0); 1896} 1897 1898int 1899umntall_each(resultsp, raddr) 1900 caddr_t resultsp; 1901 struct sockaddr_in *raddr; 1902{ 1903 return (1); 1904} 1905 1906/* 1907 * Free up a group list. 1908 */ 1909void 1910free_grp(grp) 1911 struct grouplist *grp; 1912{ 1913 char **addrp; 1914 1915 if (grp->gr_type == GT_HOST) { 1916 if (grp->gr_ptr.gt_hostent->h_name) { 1917 addrp = grp->gr_ptr.gt_hostent->h_addr_list; 1918 while (addrp && *addrp) 1919 free(*addrp++); 1920 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 1921 free(grp->gr_ptr.gt_hostent->h_name); 1922 } 1923 free((caddr_t)grp->gr_ptr.gt_hostent); 1924 } else if (grp->gr_type == GT_NET) { 1925 if (grp->gr_ptr.gt_net.nt_name) 1926 free(grp->gr_ptr.gt_net.nt_name); 1927 } 1928#ifdef ISO 1929 else if (grp->gr_type == GT_ISO) 1930 free((caddr_t)grp->gr_ptr.gt_isoaddr); 1931#endif 1932 free((caddr_t)grp); 1933} 1934 1935#ifdef DEBUG 1936void 1937SYSLOG(int pri, const char *fmt, ...) 1938{ 1939 va_list ap; 1940 1941 va_start(ap, fmt); 1942 vfprintf(stderr, fmt, ap); 1943 va_end(ap); 1944} 1945#endif /* DEBUG */ 1946 1947/* 1948 * Check options for consistency. 1949 */ 1950int 1951check_options(dp) 1952 struct dirlist *dp; 1953{ 1954 1955 if (dp == (struct dirlist *)NULL) 1956 return (1); 1957 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 1958 (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 1959 (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 1960 syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 1961 return (1); 1962 } 1963 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 1964 syslog(LOG_ERR, "-mask requires -net"); 1965 return (1); 1966 } 1967 if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 1968 syslog(LOG_ERR, "-net and -iso mutually exclusive"); 1969 return (1); 1970 } 1971 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 1972 syslog(LOG_ERR, "-alldir has multiple directories"); 1973 return (1); 1974 } 1975 return (0); 1976} 1977 1978/* 1979 * Check an absolute directory path for any symbolic links. Return true 1980 * if no symbolic links are found. 1981 */ 1982int 1983check_dirpath(dirp) 1984 char *dirp; 1985{ 1986 char *cp; 1987 int ret = 1; 1988 struct stat sb; 1989 1990 cp = dirp + 1; 1991 while (*cp && ret) { 1992 if (*cp == '/') { 1993 *cp = '\0'; 1994 if (lstat(dirp, &sb) < 0 || 1995 (sb.st_mode & S_IFMT) != S_IFDIR) 1996 ret = 0; 1997 *cp = '/'; 1998 } 1999 cp++; 2000 } 2001 if (lstat(dirp, &sb) < 0 || 2002 (sb.st_mode & S_IFMT) != S_IFDIR) 2003 ret = 0; 2004 return (ret); 2005} 2006