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