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