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