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.24 (Berkeley) 08/09/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 == (struct grouplist *)0) 904 ep->ex_defdir->dp_flag |= DP_DEFSET; 905 else while (grp) { 906 hp = get_ht(); 907 hp->ht_grp = grp; 908 hp->ht_next = ep->ex_defdir->dp_hosts; 909 ep->ex_defdir->dp_hosts = hp; 910 grp = grp->gr_next; 911 } 912 } else { 913 914 /* 915 * Loop throught the directories adding them to the tree. 916 */ 917 while (dp) { 918 dp2 = dp->dp_left; 919 add_dlist(&ep->ex_dirl, dp, grp); 920 dp = dp2; 921 } 922 } 923 } 924 925 /* 926 * Traverse the binary tree either updating a node that is already there 927 * for the new directory or adding the new node. 928 */ 929 void 930 add_dlist(dpp, newdp, grp) 931 struct dirlist **dpp; 932 struct dirlist *newdp; 933 register struct grouplist *grp; 934 { 935 register struct dirlist *dp; 936 register struct hostlist *hp; 937 int cmp; 938 939 dp = *dpp; 940 if (dp) { 941 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 942 if (cmp > 0) { 943 add_dlist(&dp->dp_left, newdp, grp); 944 return; 945 } else if (cmp < 0) { 946 add_dlist(&dp->dp_right, newdp, grp); 947 return; 948 } else 949 free((caddr_t)newdp); 950 } else { 951 dp = newdp; 952 dp->dp_left = (struct dirlist *)0; 953 *dpp = dp; 954 } 955 if (grp) { 956 957 /* 958 * Hang all of the host(s) off of the directory point. 959 */ 960 do { 961 hp = get_ht(); 962 hp->ht_grp = grp; 963 hp->ht_next = dp->dp_hosts; 964 dp->dp_hosts = hp; 965 grp = grp->gr_next; 966 } while (grp); 967 } else 968 dp->dp_flag |= DP_DEFSET; 969 } 970 971 /* 972 * Search for a dirpath on the export point. 973 */ 974 struct dirlist * 975 dirp_search(dp, dirpath) 976 register struct dirlist *dp; 977 char *dirpath; 978 { 979 register int cmp; 980 981 if (dp) { 982 cmp = strcmp(dp->dp_dirp, dirpath); 983 if (cmp > 0) 984 return (dirp_search(dp->dp_left, dirpath)); 985 else if (cmp < 0) 986 return (dirp_search(dp->dp_right, dirpath)); 987 else 988 return (dp); 989 } 990 return (dp); 991 } 992 993 /* 994 * Scan for a host match in a directory tree. 995 */ 996 chk_host(dp, saddr, defsetp) 997 struct dirlist *dp; 998 u_long saddr; 999 int *defsetp; 1000 { 1001 register struct hostlist *hp; 1002 register struct grouplist *grp; 1003 register u_long **addrp; 1004 1005 if (dp) { 1006 if (dp->dp_flag & DP_DEFSET) 1007 *defsetp = 1; 1008 hp = dp->dp_hosts; 1009 while (hp) { 1010 grp = hp->ht_grp; 1011 switch (grp->gr_type) { 1012 case GT_HOST: 1013 addrp = (u_long **) 1014 grp->gr_ptr.gt_hostent->h_addr_list; 1015 while (*addrp) { 1016 if (**addrp == saddr) 1017 return (1); 1018 addrp++; 1019 } 1020 break; 1021 case GT_NET: 1022 if ((saddr & grp->gr_ptr.gt_net.nt_mask) == 1023 grp->gr_ptr.gt_net.nt_net) 1024 return (1); 1025 break; 1026 }; 1027 hp = hp->ht_next; 1028 } 1029 } 1030 return (0); 1031 } 1032 1033 /* 1034 * Scan tree for a host that matches the address. 1035 */ 1036 scan_tree(dp, saddr) 1037 register struct dirlist *dp; 1038 u_long saddr; 1039 { 1040 int defset; 1041 1042 if (dp) { 1043 if (scan_tree(dp->dp_left, saddr)) 1044 return (1); 1045 if (chk_host(dp, saddr, &defset)) 1046 return (1); 1047 if (scan_tree(dp->dp_right, saddr)) 1048 return (1); 1049 } 1050 return (0); 1051 } 1052 1053 /* 1054 * Traverse the dirlist tree and free it up. 1055 */ 1056 void 1057 free_dir(dp) 1058 register struct dirlist *dp; 1059 { 1060 1061 if (dp) { 1062 free_dir(dp->dp_left); 1063 free_dir(dp->dp_right); 1064 free_host(dp->dp_hosts); 1065 free((caddr_t)dp); 1066 } 1067 } 1068 1069 /* 1070 * Parse the option string and update fields. 1071 * Option arguments may either be -<option>=<value> or 1072 * -<option> <value> 1073 */ 1074 do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1075 char **cpp, **endcpp; 1076 struct exportlist *ep; 1077 struct grouplist *grp; 1078 int *has_hostp; 1079 int *exflagsp; 1080 struct ucred *cr; 1081 { 1082 register char *cpoptarg, *cpoptend; 1083 char *cp, *endcp, *cpopt, savedc, savedc2; 1084 int allflag, usedarg; 1085 1086 cpopt = *cpp; 1087 cpopt++; 1088 cp = *endcpp; 1089 savedc = *cp; 1090 *cp = '\0'; 1091 while (cpopt && *cpopt) { 1092 allflag = 1; 1093 usedarg = -2; 1094 if (cpoptend = index(cpopt, ',')) { 1095 *cpoptend++ = '\0'; 1096 if (cpoptarg = index(cpopt, '=')) 1097 *cpoptarg++ = '\0'; 1098 } else { 1099 if (cpoptarg = index(cpopt, '=')) 1100 *cpoptarg++ = '\0'; 1101 else { 1102 *cp = savedc; 1103 nextfield(&cp, &endcp); 1104 **endcpp = '\0'; 1105 if (endcp > cp && *cp != '-') { 1106 cpoptarg = cp; 1107 savedc2 = *endcp; 1108 *endcp = '\0'; 1109 usedarg = 0; 1110 } 1111 } 1112 } 1113 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1114 *exflagsp |= MNT_EXRDONLY; 1115 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1116 !(allflag = strcmp(cpopt, "mapall")) || 1117 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1118 usedarg++; 1119 parsecred(cpoptarg, cr); 1120 if (allflag == 0) { 1121 *exflagsp |= MNT_EXPORTANON; 1122 opt_flags |= OP_MAPALL; 1123 } else 1124 opt_flags |= OP_MAPROOT; 1125 } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) { 1126 *exflagsp |= MNT_EXKERB; 1127 opt_flags |= OP_KERB; 1128 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1129 !strcmp(cpopt, "m"))) { 1130 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1131 syslog(LOG_ERR, "Bad mask: %s", cpoptarg); 1132 return (1); 1133 } 1134 usedarg++; 1135 opt_flags |= OP_MASK; 1136 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1137 !strcmp(cpopt, "n"))) { 1138 if (grp->gr_type != GT_NULL) { 1139 syslog(LOG_ERR, "Network/host conflict"); 1140 return (1); 1141 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1142 syslog(LOG_ERR, "Bad net: %s", cpoptarg); 1143 return (1); 1144 } 1145 grp->gr_type = GT_NET; 1146 *has_hostp = 1; 1147 usedarg++; 1148 opt_flags |= OP_NET; 1149 } else if (!strcmp(cpopt, "alldirs")) { 1150 opt_flags |= OP_ALLDIRS; 1151 #ifdef ISO 1152 } else if (cpoptarg && !strcmp(cpopt, "iso")) { 1153 if (get_isoaddr(cpoptarg, grp)) { 1154 syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg); 1155 return (1); 1156 } 1157 *has_hostp = 1; 1158 usedarg++; 1159 opt_flags |= OP_ISO; 1160 #endif /* ISO */ 1161 } else { 1162 syslog(LOG_ERR, "Bad opt %s", cpopt); 1163 return (1); 1164 } 1165 if (usedarg >= 0) { 1166 *endcp = savedc2; 1167 **endcpp = savedc; 1168 if (usedarg > 0) { 1169 *cpp = cp; 1170 *endcpp = endcp; 1171 } 1172 return (0); 1173 } 1174 cpopt = cpoptend; 1175 } 1176 **endcpp = savedc; 1177 return (0); 1178 } 1179 1180 /* 1181 * Translate a character string to the corresponding list of network 1182 * addresses for a hostname. 1183 */ 1184 get_host(cp, grp) 1185 char *cp; 1186 register struct grouplist *grp; 1187 { 1188 register struct hostent *hp, *nhp; 1189 register char **addrp, **naddrp; 1190 struct hostent t_host; 1191 int i; 1192 u_long saddr; 1193 char *aptr[2]; 1194 1195 if (grp->gr_type != GT_NULL) 1196 return (1); 1197 if ((hp = gethostbyname(cp)) == NULL) { 1198 if (isdigit(*cp)) { 1199 saddr = inet_addr(cp); 1200 if (saddr == -1) { 1201 syslog(LOG_ERR, "Inet_addr failed"); 1202 return (1); 1203 } 1204 if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr), 1205 AF_INET)) == NULL) { 1206 hp = &t_host; 1207 hp->h_name = cp; 1208 hp->h_addrtype = AF_INET; 1209 hp->h_length = sizeof (u_long); 1210 hp->h_addr_list = aptr; 1211 aptr[0] = (char *)&saddr; 1212 aptr[1] = (char *)0; 1213 } 1214 } else { 1215 syslog(LOG_ERR, "Gethostbyname failed"); 1216 return (1); 1217 } 1218 } 1219 grp->gr_type = GT_HOST; 1220 nhp = grp->gr_ptr.gt_hostent = (struct hostent *) 1221 malloc(sizeof(struct hostent)); 1222 if (nhp == (struct hostent *)0) 1223 out_of_mem(); 1224 bcopy((caddr_t)hp, (caddr_t)nhp, 1225 sizeof(struct hostent)); 1226 i = strlen(hp->h_name)+1; 1227 nhp->h_name = (char *)malloc(i); 1228 if (nhp->h_name == (char *)0) 1229 out_of_mem(); 1230 bcopy(hp->h_name, nhp->h_name, i); 1231 addrp = hp->h_addr_list; 1232 i = 1; 1233 while (*addrp++) 1234 i++; 1235 naddrp = nhp->h_addr_list = (char **) 1236 malloc(i*sizeof(char *)); 1237 if (naddrp == (char **)0) 1238 out_of_mem(); 1239 addrp = hp->h_addr_list; 1240 while (*addrp) { 1241 *naddrp = (char *) 1242 malloc(hp->h_length); 1243 if (*naddrp == (char *)0) 1244 out_of_mem(); 1245 bcopy(*addrp, *naddrp, 1246 hp->h_length); 1247 addrp++; 1248 naddrp++; 1249 } 1250 *naddrp = (char *)0; 1251 if (debug) 1252 fprintf(stderr, "got host %s\n", hp->h_name); 1253 return (0); 1254 } 1255 1256 /* 1257 * Free up an exports list component 1258 */ 1259 void 1260 free_exp(ep) 1261 register struct exportlist *ep; 1262 { 1263 1264 if (ep->ex_defdir) { 1265 free_host(ep->ex_defdir->dp_hosts); 1266 free((caddr_t)ep->ex_defdir); 1267 } 1268 if (ep->ex_fsdir) 1269 free(ep->ex_fsdir); 1270 free_dir(ep->ex_dirl); 1271 free((caddr_t)ep); 1272 } 1273 1274 /* 1275 * Free hosts. 1276 */ 1277 void 1278 free_host(hp) 1279 register struct hostlist *hp; 1280 { 1281 register struct hostlist *hp2; 1282 1283 while (hp) { 1284 hp2 = hp; 1285 hp = hp->ht_next; 1286 free((caddr_t)hp2); 1287 } 1288 } 1289 1290 struct hostlist * 1291 get_ht() 1292 { 1293 register struct hostlist *hp; 1294 1295 hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 1296 if (hp == (struct hostlist *)0) 1297 out_of_mem(); 1298 hp->ht_next = (struct hostlist *)0; 1299 return (hp); 1300 } 1301 1302 #ifdef ISO 1303 /* 1304 * Translate an iso address. 1305 */ 1306 get_isoaddr(cp, grp) 1307 char *cp; 1308 struct grouplist *grp; 1309 { 1310 struct iso_addr *isop; 1311 struct sockaddr_iso *isoaddr; 1312 1313 if (grp->gr_type != GT_NULL) 1314 return (1); 1315 if ((isop = iso_addr(cp)) == NULL) { 1316 syslog(LOG_ERR, 1317 "iso_addr failed, ignored"); 1318 return (1); 1319 } 1320 isoaddr = (struct sockaddr_iso *) 1321 malloc(sizeof (struct sockaddr_iso)); 1322 if (isoaddr == (struct sockaddr_iso *)0) 1323 out_of_mem(); 1324 bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso)); 1325 bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr, 1326 sizeof (struct iso_addr)); 1327 isoaddr->siso_len = sizeof (struct sockaddr_iso); 1328 isoaddr->siso_family = AF_ISO; 1329 grp->gr_type = GT_ISO; 1330 grp->gr_ptr.gt_isoaddr = isoaddr; 1331 return (0); 1332 } 1333 #endif /* ISO */ 1334 1335 /* 1336 * Out of memory, fatal 1337 */ 1338 void 1339 out_of_mem() 1340 { 1341 1342 syslog(LOG_ERR, "Out of memory"); 1343 exit(2); 1344 } 1345 1346 /* 1347 * Do the mount syscall with the update flag to push the export info into 1348 * the kernel. 1349 */ 1350 do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb) 1351 struct exportlist *ep; 1352 struct grouplist *grp; 1353 int exflags; 1354 struct ucred *anoncrp; 1355 char *dirp; 1356 int dirplen; 1357 struct statfs *fsb; 1358 { 1359 register char *cp = (char *)0; 1360 register u_long **addrp; 1361 int done; 1362 char savedc; 1363 struct sockaddr_in sin, imask; 1364 struct ufs_args args; 1365 u_long net; 1366 1367 args.fspec = 0; 1368 args.exflags = exflags; 1369 args.anon = *anoncrp; 1370 bzero((char *)&sin, sizeof(sin)); 1371 bzero((char *)&imask, sizeof(imask)); 1372 sin.sin_family = AF_INET; 1373 sin.sin_len = sizeof(sin); 1374 imask.sin_family = AF_INET; 1375 imask.sin_len = sizeof(sin); 1376 if (grp->gr_type == GT_HOST) 1377 addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list; 1378 else 1379 addrp = (u_long **)0; 1380 done = FALSE; 1381 while (!done) { 1382 switch (grp->gr_type) { 1383 case GT_HOST: 1384 if (addrp) 1385 sin.sin_addr.s_addr = **addrp; 1386 else 1387 sin.sin_addr.s_addr = INADDR_ANY; 1388 args.saddr = (struct sockaddr *)&sin; 1389 args.slen = sizeof(sin); 1390 args.msklen = 0; 1391 break; 1392 case GT_NET: 1393 if (grp->gr_ptr.gt_net.nt_mask) 1394 imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask; 1395 else { 1396 net = ntohl(grp->gr_ptr.gt_net.nt_net); 1397 if (IN_CLASSA(net)) 1398 imask.sin_addr.s_addr = inet_addr("255.0.0.0"); 1399 else if (IN_CLASSB(net)) 1400 imask.sin_addr.s_addr = 1401 inet_addr("255.255.0.0"); 1402 else 1403 imask.sin_addr.s_addr = 1404 inet_addr("255.255.255.0"); 1405 grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr; 1406 } 1407 sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net; 1408 args.saddr = (struct sockaddr *)&sin; 1409 args.slen = sizeof (sin); 1410 args.smask = (struct sockaddr *)&imask; 1411 args.msklen = sizeof (imask); 1412 break; 1413 #ifdef ISO 1414 case GT_ISO: 1415 args.saddr = (struct sockaddr *)grp->gr_ptr.gt_isoaddr; 1416 args.slen = sizeof (struct sockaddr_iso); 1417 args.msklen = 0; 1418 break; 1419 #endif /* ISO */ 1420 default: 1421 syslog(LOG_ERR, "Bad grouptype"); 1422 if (cp) 1423 *cp = savedc; 1424 return (1); 1425 }; 1426 1427 /* 1428 * XXX: 1429 * Maybe I should just use the fsb->f_mntonname path instead 1430 * of looping back up the dirp to the mount point?? 1431 * Also, needs to know how to export all types of local 1432 * exportable file systems and not just MOUNT_UFS. 1433 */ 1434 while (mount(fsb->f_type, dirp, 1435 fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) { 1436 if (cp) 1437 *cp-- = savedc; 1438 else 1439 cp = dirp + dirplen - 1; 1440 if (errno == EPERM) { 1441 syslog(LOG_ERR, 1442 "Can't change attributes for %s.\n", dirp); 1443 return (1); 1444 } 1445 if (opt_flags & OP_ALLDIRS) { 1446 syslog(LOG_ERR, "Not root dir"); 1447 return (1); 1448 } 1449 /* back up over the last component */ 1450 while (*cp == '/' && cp > dirp) 1451 cp--; 1452 while (*(cp - 1) != '/' && cp > dirp) 1453 cp--; 1454 if (cp == dirp) { 1455 if (debug) 1456 fprintf(stderr,"mnt unsucc\n"); 1457 syslog(LOG_ERR, "Can't export %s", dirp); 1458 return (1); 1459 } 1460 savedc = *cp; 1461 *cp = '\0'; 1462 } 1463 if (addrp) { 1464 ++addrp; 1465 if (*addrp == (u_long *)0) 1466 done = TRUE; 1467 } else 1468 done = TRUE; 1469 } 1470 if (cp) 1471 *cp = savedc; 1472 return (0); 1473 } 1474 1475 /* 1476 * Translate a net address. 1477 */ 1478 get_net(cp, net, maskflg) 1479 char *cp; 1480 struct netmsk *net; 1481 int maskflg; 1482 { 1483 register struct netent *np; 1484 register long netaddr; 1485 struct in_addr inetaddr, inetaddr2; 1486 char *name; 1487 1488 if (np = getnetbyname(cp)) 1489 inetaddr = inet_makeaddr(np->n_net, 0); 1490 else if (isdigit(*cp)) { 1491 if ((netaddr = inet_network(cp)) == -1) 1492 return (1); 1493 inetaddr = inet_makeaddr(netaddr, 0); 1494 /* 1495 * Due to arbritrary subnet masks, you don't know how many 1496 * bits to shift the address to make it into a network, 1497 * however you do know how to make a network address into 1498 * a host with host == 0 and then compare them. 1499 * (What a pest) 1500 */ 1501 if (!maskflg) { 1502 setnetent(0); 1503 while (np = getnetent()) { 1504 inetaddr2 = inet_makeaddr(np->n_net, 0); 1505 if (inetaddr2.s_addr == inetaddr.s_addr) 1506 break; 1507 } 1508 endnetent(); 1509 } 1510 } else 1511 return (1); 1512 if (maskflg) 1513 net->nt_mask = inetaddr.s_addr; 1514 else { 1515 if (np) 1516 name = np->n_name; 1517 else 1518 name = inet_ntoa(inetaddr); 1519 net->nt_name = (char *)malloc(strlen(name) + 1); 1520 if (net->nt_name == (char *)0) 1521 out_of_mem(); 1522 strcpy(net->nt_name, name); 1523 net->nt_net = inetaddr.s_addr; 1524 } 1525 return (0); 1526 } 1527 1528 /* 1529 * Parse out the next white space separated field 1530 */ 1531 void 1532 nextfield(cp, endcp) 1533 char **cp; 1534 char **endcp; 1535 { 1536 register char *p; 1537 1538 p = *cp; 1539 while (*p == ' ' || *p == '\t') 1540 p++; 1541 if (*p == '\n' || *p == '\0') 1542 *cp = *endcp = p; 1543 else { 1544 *cp = p++; 1545 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 1546 p++; 1547 *endcp = p; 1548 } 1549 } 1550 1551 /* 1552 * Get an exports file line. Skip over blank lines and handle line 1553 * continuations. 1554 */ 1555 get_line() 1556 { 1557 register char *p, *cp; 1558 register int len; 1559 int totlen, cont_line; 1560 1561 /* 1562 * Loop around ignoring blank lines and getting all continuation lines. 1563 */ 1564 p = line; 1565 totlen = 0; 1566 do { 1567 if (fgets(p, LINESIZ - totlen, exp_file) == NULL) 1568 return (0); 1569 len = strlen(p); 1570 cp = p + len - 1; 1571 cont_line = 0; 1572 while (cp >= p && 1573 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 1574 if (*cp == '\\') 1575 cont_line = 1; 1576 cp--; 1577 len--; 1578 } 1579 *++cp = '\0'; 1580 if (len > 0) { 1581 totlen += len; 1582 if (totlen >= LINESIZ) { 1583 syslog(LOG_ERR, "Exports line too long"); 1584 exit(2); 1585 } 1586 p = cp; 1587 } 1588 } while (totlen == 0 || cont_line); 1589 return (1); 1590 } 1591 1592 /* 1593 * Parse a description of a credential. 1594 */ 1595 parsecred(namelist, cr) 1596 char *namelist; 1597 register struct ucred *cr; 1598 { 1599 register char *name; 1600 register int cnt; 1601 char *names; 1602 struct passwd *pw; 1603 struct group *gr; 1604 int ngroups, groups[NGROUPS + 1]; 1605 1606 /* 1607 * Set up the unpriviledged user. 1608 */ 1609 cr->cr_ref = 1; 1610 cr->cr_uid = -2; 1611 cr->cr_groups[0] = -2; 1612 cr->cr_ngroups = 1; 1613 /* 1614 * Get the user's password table entry. 1615 */ 1616 names = strsep(&namelist, " \t\n"); 1617 name = strsep(&names, ":"); 1618 if (isdigit(*name) || *name == '-') 1619 pw = getpwuid(atoi(name)); 1620 else 1621 pw = getpwnam(name); 1622 /* 1623 * Credentials specified as those of a user. 1624 */ 1625 if (names == NULL) { 1626 if (pw == NULL) { 1627 syslog(LOG_ERR, "Unknown user: %s\n", name); 1628 return; 1629 } 1630 cr->cr_uid = pw->pw_uid; 1631 ngroups = NGROUPS + 1; 1632 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 1633 syslog(LOG_ERR, "Too many groups\n"); 1634 /* 1635 * Convert from int's to gid_t's and compress out duplicate 1636 */ 1637 cr->cr_ngroups = ngroups - 1; 1638 cr->cr_groups[0] = groups[0]; 1639 for (cnt = 2; cnt < ngroups; cnt++) 1640 cr->cr_groups[cnt - 1] = groups[cnt]; 1641 return; 1642 } 1643 /* 1644 * Explicit credential specified as a colon separated list: 1645 * uid:gid:gid:... 1646 */ 1647 if (pw != NULL) 1648 cr->cr_uid = pw->pw_uid; 1649 else if (isdigit(*name) || *name == '-') 1650 cr->cr_uid = atoi(name); 1651 else { 1652 syslog(LOG_ERR, "Unknown user: %s\n", name); 1653 return; 1654 } 1655 cr->cr_ngroups = 0; 1656 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 1657 name = strsep(&names, ":"); 1658 if (isdigit(*name) || *name == '-') { 1659 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 1660 } else { 1661 if ((gr = getgrnam(name)) == NULL) { 1662 syslog(LOG_ERR, "Unknown group: %s\n", name); 1663 continue; 1664 } 1665 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 1666 } 1667 } 1668 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 1669 syslog(LOG_ERR, "Too many groups\n"); 1670 } 1671 1672 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 1673 /* 1674 * Routines that maintain the remote mounttab 1675 */ 1676 void 1677 get_mountlist() 1678 { 1679 register struct mountlist *mlp, **mlpp; 1680 register char *eos, *dirp; 1681 int len; 1682 char str[STRSIZ]; 1683 FILE *mlfile; 1684 1685 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 1686 syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST); 1687 return; 1688 } 1689 mlpp = &mlhead; 1690 while (fgets(str, STRSIZ, mlfile) != NULL) { 1691 if ((dirp = index(str, '\t')) == NULL && 1692 (dirp = index(str, ' ')) == NULL) 1693 continue; 1694 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1695 len = dirp-str; 1696 if (len > RPCMNT_NAMELEN) 1697 len = RPCMNT_NAMELEN; 1698 bcopy(str, mlp->ml_host, len); 1699 mlp->ml_host[len] = '\0'; 1700 while (*dirp == '\t' || *dirp == ' ') 1701 dirp++; 1702 if ((eos = index(dirp, '\t')) == NULL && 1703 (eos = index(dirp, ' ')) == NULL && 1704 (eos = index(dirp, '\n')) == NULL) 1705 len = strlen(dirp); 1706 else 1707 len = eos-dirp; 1708 if (len > RPCMNT_PATHLEN) 1709 len = RPCMNT_PATHLEN; 1710 bcopy(dirp, mlp->ml_dirp, len); 1711 mlp->ml_dirp[len] = '\0'; 1712 mlp->ml_next = (struct mountlist *)0; 1713 *mlpp = mlp; 1714 mlpp = &mlp->ml_next; 1715 } 1716 fclose(mlfile); 1717 } 1718 1719 void 1720 del_mlist(hostp, dirp) 1721 register char *hostp, *dirp; 1722 { 1723 register struct mountlist *mlp, **mlpp; 1724 struct mountlist *mlp2; 1725 FILE *mlfile; 1726 int fnd = 0; 1727 1728 mlpp = &mlhead; 1729 mlp = mlhead; 1730 while (mlp) { 1731 if (!strcmp(mlp->ml_host, hostp) && 1732 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 1733 fnd = 1; 1734 mlp2 = mlp; 1735 *mlpp = mlp = mlp->ml_next; 1736 free((caddr_t)mlp2); 1737 } else { 1738 mlpp = &mlp->ml_next; 1739 mlp = mlp->ml_next; 1740 } 1741 } 1742 if (fnd) { 1743 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 1744 syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST); 1745 return; 1746 } 1747 mlp = mlhead; 1748 while (mlp) { 1749 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1750 mlp = mlp->ml_next; 1751 } 1752 fclose(mlfile); 1753 } 1754 } 1755 1756 void 1757 add_mlist(hostp, dirp) 1758 register char *hostp, *dirp; 1759 { 1760 register struct mountlist *mlp, **mlpp; 1761 FILE *mlfile; 1762 1763 mlpp = &mlhead; 1764 mlp = mlhead; 1765 while (mlp) { 1766 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 1767 return; 1768 mlpp = &mlp->ml_next; 1769 mlp = mlp->ml_next; 1770 } 1771 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 1772 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 1773 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 1774 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 1775 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 1776 mlp->ml_next = (struct mountlist *)0; 1777 *mlpp = mlp; 1778 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 1779 syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST); 1780 return; 1781 } 1782 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 1783 fclose(mlfile); 1784 } 1785 1786 /* 1787 * This function is called via. SIGTERM when the system is going down. 1788 * It sends a broadcast RPCMNT_UMNTALL. 1789 */ 1790 void 1791 send_umntall() 1792 { 1793 (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL, 1794 xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each); 1795 exit(0); 1796 } 1797 1798 umntall_each(resultsp, raddr) 1799 caddr_t resultsp; 1800 struct sockaddr_in *raddr; 1801 { 1802 return (1); 1803 } 1804 1805 /* 1806 * Free up a group list. 1807 */ 1808 void 1809 free_grp(grp) 1810 register struct grouplist *grp; 1811 { 1812 register char **addrp; 1813 1814 if (grp->gr_type == GT_HOST) { 1815 if (grp->gr_ptr.gt_hostent->h_name) { 1816 addrp = grp->gr_ptr.gt_hostent->h_addr_list; 1817 while (addrp && *addrp) 1818 free(*addrp++); 1819 free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list); 1820 free(grp->gr_ptr.gt_hostent->h_name); 1821 } 1822 free((caddr_t)grp->gr_ptr.gt_hostent); 1823 } else if (grp->gr_type == GT_NET) { 1824 if (grp->gr_ptr.gt_net.nt_name) 1825 free(grp->gr_ptr.gt_net.nt_name); 1826 } 1827 #ifdef ISO 1828 else if (grp->gr_type == GT_ISO) 1829 free((caddr_t)grp->gr_ptr.gt_isoaddr); 1830 #endif 1831 free((caddr_t)grp); 1832 } 1833 1834 /* 1835 * char *realpath(const char *path, char resolved_path[MAXPATHLEN]) 1836 * 1837 * find the real name of path, by removing all ".", ".." 1838 * and symlink components. 1839 * 1840 * Jan-Simon Pendry, September 1991. 1841 */ 1842 char * 1843 realpath(path, resolved) 1844 char *path; 1845 char resolved[MAXPATHLEN]; 1846 { 1847 int d = open(".", O_RDONLY); 1848 int rootd = 0; 1849 char *p, *q; 1850 struct stat stb; 1851 char wbuf[MAXPATHLEN]; 1852 1853 strcpy(resolved, path); 1854 1855 if (d < 0) 1856 return 0; 1857 1858 loop:; 1859 q = strrchr(resolved, '/'); 1860 if (q) { 1861 p = q + 1; 1862 if (q == resolved) 1863 q = "/"; 1864 else { 1865 do 1866 --q; 1867 while (q > resolved && *q == '/'); 1868 q[1] = '\0'; 1869 q = resolved; 1870 } 1871 if (chdir(q) < 0) 1872 goto out; 1873 } else 1874 p = resolved; 1875 1876 if (lstat(p, &stb) == 0) { 1877 if (S_ISLNK(stb.st_mode)) { 1878 int n = readlink(p, resolved, MAXPATHLEN); 1879 if (n < 0) 1880 goto out; 1881 resolved[n] = '\0'; 1882 goto loop; 1883 } 1884 if (S_ISDIR(stb.st_mode)) { 1885 if (chdir(p) < 0) 1886 goto out; 1887 p = ""; 1888 } 1889 } 1890 1891 strcpy(wbuf, p); 1892 if (getcwd(resolved, MAXPATHLEN) == 0) 1893 goto out; 1894 if (resolved[0] == '/' && resolved[1] == '\0') 1895 rootd = 1; 1896 1897 if (*wbuf) { 1898 if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) { 1899 errno = ENAMETOOLONG; 1900 goto out; 1901 } 1902 if (rootd == 0) 1903 strcat(resolved, "/"); 1904 strcat(resolved, wbuf); 1905 } 1906 1907 if (fchdir(d) < 0) 1908 goto out; 1909 (void) close(d); 1910 1911 return resolved; 1912 1913 out:; 1914 (void) close(d); 1915 return 0; 1916 } 1917 1918 #ifdef DEBUG 1919 void 1920 SYSLOG(int pri, const char *fmt, ...) 1921 { 1922 va_list ap; 1923 1924 va_start(ap, fmt); 1925 vfprintf(stderr, fmt, ap); 1926 va_end(ap); 1927 } 1928 #endif /* DEBUG */ 1929 1930 /* 1931 * Check options for consistency. 1932 */ 1933 check_options(dp) 1934 struct dirlist *dp; 1935 { 1936 1937 if (dp == (struct dirlist *)0) 1938 return (1); 1939 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) || 1940 (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) || 1941 (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) { 1942 syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive"); 1943 return (1); 1944 } 1945 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 1946 syslog(LOG_ERR, "-mask requires -net"); 1947 return (1); 1948 } 1949 if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) { 1950 syslog(LOG_ERR, "-net and -iso mutually exclusive"); 1951 return (1); 1952 } 1953 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 1954 syslog(LOG_ERR, "-alldir has multiple directories"); 1955 return (1); 1956 } 1957 return (0); 1958 } 1959