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