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