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