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