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