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