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