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