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