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