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