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