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