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