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