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