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