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