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