mountd.c revision 193674
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 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#ifndef lint 34static const char copyright[] = 35"@(#) Copyright (c) 1989, 1993\n\ 36 The Regents of the University of California. All rights reserved.\n"; 37#endif /*not lint*/ 38 39#if 0 40#ifndef lint 41static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; 42#endif /*not lint*/ 43#endif 44 45#include <sys/cdefs.h> 46__FBSDID("$FreeBSD: head/usr.sbin/mountd/mountd.c 193674 2009-06-08 03:15:27Z kan $"); 47 48#include <sys/param.h> 49#include <sys/fcntl.h> 50#include <sys/linker.h> 51#include <sys/module.h> 52#include <sys/mount.h> 53#include <sys/stat.h> 54#include <sys/sysctl.h> 55#include <sys/syslog.h> 56 57#include <rpc/rpc.h> 58#include <rpc/rpc_com.h> 59#include <rpc/pmap_clnt.h> 60#include <rpc/pmap_prot.h> 61#include <rpcsvc/mount.h> 62#include <nfs/rpcv2.h> 63#include <nfs/nfsproto.h> 64#include <nfs/nfssvc.h> 65#include <nfsserver/nfs.h> 66 67#include <fs/nfs/nfsport.h> 68 69#include <arpa/inet.h> 70 71#include <ctype.h> 72#include <err.h> 73#include <errno.h> 74#include <grp.h> 75#include <libutil.h> 76#include <limits.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#include "mntopts.h" 86 87#ifdef DEBUG 88#include <stdarg.h> 89#endif 90 91/* 92 * Structures for keeping the mount list and export list 93 */ 94struct mountlist { 95 struct mountlist *ml_next; 96 char ml_host[RPCMNT_NAMELEN+1]; 97 char ml_dirp[RPCMNT_PATHLEN+1]; 98}; 99 100struct dirlist { 101 struct dirlist *dp_left; 102 struct dirlist *dp_right; 103 int dp_flag; 104 struct hostlist *dp_hosts; /* List of hosts this dir exported to */ 105 char dp_dirp[1]; /* Actually malloc'd to size of dir */ 106}; 107/* dp_flag bits */ 108#define DP_DEFSET 0x1 109#define DP_HOSTSET 0x2 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 int ex_numsecflavors; 120 int ex_secflavors[MAXSECFLAVORS]; 121}; 122/* ex_flag bits */ 123#define EX_LINKED 0x1 124 125struct netmsk { 126 struct sockaddr_storage nt_net; 127 struct sockaddr_storage nt_mask; 128 char *nt_name; 129}; 130 131union grouptypes { 132 struct addrinfo *gt_addrinfo; 133 struct netmsk gt_net; 134}; 135 136struct grouplist { 137 int gr_type; 138 union grouptypes gr_ptr; 139 struct grouplist *gr_next; 140}; 141/* Group types */ 142#define GT_NULL 0x0 143#define GT_HOST 0x1 144#define GT_NET 0x2 145#define GT_DEFAULT 0x3 146#define GT_IGNORE 0x5 147 148struct hostlist { 149 int ht_flag; /* Uses DP_xx bits */ 150 struct grouplist *ht_grp; 151 struct hostlist *ht_next; 152}; 153 154struct fhreturn { 155 int fhr_flag; 156 int fhr_vers; 157 nfsfh_t fhr_fh; 158 int fhr_numsecflavors; 159 int *fhr_secflavors; 160}; 161 162/* Global defs */ 163char *add_expdir(struct dirlist **, char *, int); 164void add_dlist(struct dirlist **, struct dirlist *, 165 struct grouplist *, int); 166void add_mlist(char *, char *); 167int check_dirpath(char *); 168int check_options(struct dirlist *); 169int checkmask(struct sockaddr *sa); 170int chk_host(struct dirlist *, struct sockaddr *, int *, int *); 171void create_service(struct netconfig *nconf); 172void del_mlist(char *hostp, char *dirp); 173struct dirlist *dirp_search(struct dirlist *, char *); 174int do_mount(struct exportlist *, struct grouplist *, int, 175 struct xucred *, char *, int, struct statfs *); 176int do_opt(char **, char **, struct exportlist *, struct grouplist *, 177 int *, int *, struct xucred *); 178struct exportlist *ex_search(fsid_t *); 179struct exportlist *get_exp(void); 180void free_dir(struct dirlist *); 181void free_exp(struct exportlist *); 182void free_grp(struct grouplist *); 183void free_host(struct hostlist *); 184void get_exportlist(void); 185int get_host(char *, struct grouplist *, struct grouplist *); 186struct hostlist *get_ht(void); 187int get_line(void); 188void get_mountlist(void); 189int get_net(char *, struct netmsk *, int); 190void getexp_err(struct exportlist *, struct grouplist *); 191struct grouplist *get_grp(void); 192void hang_dirp(struct dirlist *, struct grouplist *, 193 struct exportlist *, int); 194void huphandler(int sig); 195int makemask(struct sockaddr_storage *ssp, int bitlen); 196void mntsrv(struct svc_req *, SVCXPRT *); 197void nextfield(char **, char **); 198void out_of_mem(void); 199void parsecred(char *, struct xucred *); 200int put_exlist(struct dirlist *, XDR *, struct dirlist *, int *, int); 201void *sa_rawaddr(struct sockaddr *sa, int *nbytes); 202int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, 203 struct sockaddr *samask); 204int scan_tree(struct dirlist *, struct sockaddr *); 205static void usage(void); 206int xdr_dir(XDR *, char *); 207int xdr_explist(XDR *, caddr_t); 208int xdr_explist_brief(XDR *, caddr_t); 209int xdr_fhs(XDR *, caddr_t); 210int xdr_mlist(XDR *, caddr_t); 211void terminate(int); 212 213struct exportlist *exphead; 214struct mountlist *mlhead; 215struct grouplist *grphead; 216char *exnames_default[2] = { _PATH_EXPORTS, NULL }; 217char **exnames; 218char **hosts = NULL; 219struct xucred def_anon = { 220 XUCRED_VERSION, 221 (uid_t)-2, 222 1, 223 { (gid_t)-2 }, 224 NULL 225}; 226int force_v2 = 0; 227int resvport_only = 1; 228int nhosts = 0; 229int dir_only = 1; 230int dolog = 0; 231int got_sighup = 0; 232int xcreated = 0; 233 234char *svcport_str = NULL; 235 236int opt_flags; 237static int have_v6 = 1; 238 239int v4root_phase = 0; 240char v4root_dirpath[PATH_MAX + 1]; 241int run_v4server = 0; 242int has_publicfh = 0; 243 244struct pidfh *pfh = NULL; 245/* Bits for opt_flags above */ 246#define OP_MAPROOT 0x01 247#define OP_MAPALL 0x02 248/* 0x4 free */ 249#define OP_MASK 0x08 250#define OP_NET 0x10 251#define OP_ALLDIRS 0x40 252#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ 253#define OP_QUIET 0x100 254#define OP_MASKLEN 0x200 255#define OP_SEC 0x400 256 257#ifdef DEBUG 258int debug = 1; 259void SYSLOG(int, const char *, ...) __printflike(2, 3); 260#define syslog SYSLOG 261#else 262int debug = 0; 263#endif 264 265/* 266 * Mountd server for NFS mount protocol as described in: 267 * NFS: Network File System Protocol Specification, RFC1094, Appendix A 268 * The optional arguments are the exports file name 269 * default: _PATH_EXPORTS 270 * and "-n" to allow nonroot mount. 271 */ 272int 273main(argc, argv) 274 int argc; 275 char **argv; 276{ 277 fd_set readfds; 278 struct netconfig *nconf; 279 char *endptr, **hosts_bak; 280 void *nc_handle; 281 pid_t otherpid; 282 in_port_t svcport; 283 int c, k, s; 284 int maxrec = RPC_MAXDATASIZE; 285 286 /* Check that another mountd isn't already running. */ 287 pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); 288 if (pfh == NULL) { 289 if (errno == EEXIST) 290 errx(1, "mountd already running, pid: %d.", otherpid); 291 warn("cannot open or create pidfile"); 292 } 293 294 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 295 if (s < 0) 296 have_v6 = 0; 297 else 298 close(s); 299 300 while ((c = getopt(argc, argv, "2deh:lnp:r")) != -1) 301 switch (c) { 302 case '2': 303 force_v2 = 1; 304 break; 305 case 'e': 306 run_v4server = 1; 307 break; 308 case 'n': 309 resvport_only = 0; 310 break; 311 case 'r': 312 dir_only = 0; 313 break; 314 case 'd': 315 debug = debug ? 0 : 1; 316 break; 317 case 'l': 318 dolog = 1; 319 break; 320 case 'p': 321 endptr = NULL; 322 svcport = (in_port_t)strtoul(optarg, &endptr, 10); 323 if (endptr == NULL || *endptr != '\0' || 324 svcport == 0 || svcport >= IPPORT_MAX) 325 usage(); 326 svcport_str = strdup(optarg); 327 break; 328 case 'h': 329 ++nhosts; 330 hosts_bak = hosts; 331 hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 332 if (hosts_bak == NULL) { 333 if (hosts != NULL) { 334 for (k = 0; k < nhosts; k++) 335 free(hosts[k]); 336 free(hosts); 337 out_of_mem(); 338 } 339 } 340 hosts = hosts_bak; 341 hosts[nhosts - 1] = strdup(optarg); 342 if (hosts[nhosts - 1] == NULL) { 343 for (k = 0; k < (nhosts - 1); k++) 344 free(hosts[k]); 345 free(hosts); 346 out_of_mem(); 347 } 348 break; 349 default: 350 usage(); 351 }; 352 353 /* 354 * If the "-e" option was specified OR only the nfsd module is 355 * found in the server, run "nfsd". 356 * Otherwise, try and run "nfsserver". 357 */ 358 if (run_v4server > 0) { 359 if (modfind("nfsd") < 0) { 360 /* Not present in kernel, try loading it */ 361 if (kldload("nfsd") < 0 || modfind("nfsd") < 0) 362 errx(1, "NFS server is not available"); 363 } 364 } else if (modfind("nfsserver") < 0 && modfind("nfsd") >= 0) { 365 run_v4server = 1; 366 } else if (modfind("nfsserver") < 0) { 367 /* Not present in kernel, try loading it */ 368 if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) 369 errx(1, "NFS server is not available"); 370 } 371 372 argc -= optind; 373 argv += optind; 374 grphead = (struct grouplist *)NULL; 375 exphead = (struct exportlist *)NULL; 376 mlhead = (struct mountlist *)NULL; 377 if (argc > 0) 378 exnames = argv; 379 else 380 exnames = exnames_default; 381 openlog("mountd", LOG_PID, LOG_DAEMON); 382 if (debug) 383 warnx("getting export list"); 384 get_exportlist(); 385 if (debug) 386 warnx("getting mount list"); 387 get_mountlist(); 388 if (debug) 389 warnx("here we go"); 390 if (debug == 0) { 391 daemon(0, 0); 392 signal(SIGINT, SIG_IGN); 393 signal(SIGQUIT, SIG_IGN); 394 } 395 signal(SIGHUP, huphandler); 396 signal(SIGTERM, terminate); 397 signal(SIGPIPE, SIG_IGN); 398 399 pidfile_write(pfh); 400 401 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 402 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 403 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 404 405 if (!resvport_only) { 406 if (sysctlbyname("vfs.nfsrv.nfs_privport", NULL, NULL, 407 &resvport_only, sizeof(resvport_only)) != 0 && 408 errno != ENOENT) { 409 syslog(LOG_ERR, "sysctl: %m"); 410 exit(1); 411 } 412 } 413 414 /* 415 * If no hosts were specified, add a wildcard entry to bind to 416 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 417 * list. 418 */ 419 if (nhosts == 0) { 420 hosts = malloc(sizeof(char**)); 421 if (hosts == NULL) 422 out_of_mem(); 423 hosts[0] = "*"; 424 nhosts = 1; 425 } else { 426 hosts_bak = hosts; 427 if (have_v6) { 428 hosts_bak = realloc(hosts, (nhosts + 2) * 429 sizeof(char *)); 430 if (hosts_bak == NULL) { 431 for (k = 0; k < nhosts; k++) 432 free(hosts[k]); 433 free(hosts); 434 out_of_mem(); 435 } else 436 hosts = hosts_bak; 437 nhosts += 2; 438 hosts[nhosts - 2] = "::1"; 439 } else { 440 hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 441 if (hosts_bak == NULL) { 442 for (k = 0; k < nhosts; k++) 443 free(hosts[k]); 444 free(hosts); 445 out_of_mem(); 446 } else { 447 nhosts += 1; 448 hosts = hosts_bak; 449 } 450 } 451 452 hosts[nhosts - 1] = "127.0.0.1"; 453 } 454 455 nc_handle = setnetconfig(); 456 while ((nconf = getnetconfig(nc_handle))) { 457 if (nconf->nc_flag & NC_VISIBLE) { 458 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, 459 "inet6") == 0) { 460 /* DO NOTHING */ 461 } else 462 create_service(nconf); 463 } 464 } 465 endnetconfig(nc_handle); 466 467 if (xcreated == 0) { 468 syslog(LOG_ERR, "could not create any services"); 469 exit(1); 470 } 471 472 /* Expand svc_run() here so that we can call get_exportlist(). */ 473 for (;;) { 474 if (got_sighup) { 475 get_exportlist(); 476 got_sighup = 0; 477 } 478 readfds = svc_fdset; 479 switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { 480 case -1: 481 if (errno == EINTR) 482 continue; 483 syslog(LOG_ERR, "mountd died: select: %m"); 484 exit(1); 485 case 0: 486 continue; 487 default: 488 svc_getreqset(&readfds); 489 } 490 } 491} 492 493/* 494 * This routine creates and binds sockets on the appropriate 495 * addresses. It gets called one time for each transport and 496 * registrates the service with rpcbind on that trasport. 497 */ 498void 499create_service(struct netconfig *nconf) 500{ 501 struct addrinfo hints, *res = NULL; 502 struct sockaddr_in *sin; 503 struct sockaddr_in6 *sin6; 504 struct __rpc_sockinfo si; 505 struct netbuf servaddr; 506 SVCXPRT *transp = NULL; 507 int aicode; 508 int fd; 509 int nhostsbak; 510 int one = 1; 511 int r; 512 int registered = 0; 513 u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 514 515 if ((nconf->nc_semantics != NC_TPI_CLTS) && 516 (nconf->nc_semantics != NC_TPI_COTS) && 517 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 518 return; /* not my type */ 519 520 /* 521 * XXX - using RPC library internal functions. 522 */ 523 if (!__rpc_nconf2sockinfo(nconf, &si)) { 524 syslog(LOG_ERR, "cannot get information for %s", 525 nconf->nc_netid); 526 return; 527 } 528 529 /* Get mountd's address on this transport */ 530 memset(&hints, 0, sizeof hints); 531 hints.ai_flags = AI_PASSIVE; 532 hints.ai_family = si.si_af; 533 hints.ai_socktype = si.si_socktype; 534 hints.ai_protocol = si.si_proto; 535 536 /* 537 * Bind to specific IPs if asked to 538 */ 539 nhostsbak = nhosts; 540 while (nhostsbak > 0) { 541 --nhostsbak; 542 /* 543 * XXX - using RPC library internal functions. 544 */ 545 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 546 int non_fatal = 0; 547 if (errno == EPROTONOSUPPORT && 548 nconf->nc_semantics != NC_TPI_CLTS) 549 non_fatal = 1; 550 551 syslog(non_fatal ? LOG_DEBUG : LOG_ERR, 552 "cannot create socket for %s", nconf->nc_netid); 553 return; 554 } 555 556 switch (hints.ai_family) { 557 case AF_INET: 558 if (inet_pton(AF_INET, hosts[nhostsbak], 559 host_addr) == 1) { 560 hints.ai_flags &= AI_NUMERICHOST; 561 } else { 562 /* 563 * Skip if we have an AF_INET6 address. 564 */ 565 if (inet_pton(AF_INET6, hosts[nhostsbak], 566 host_addr) == 1) { 567 close(fd); 568 continue; 569 } 570 } 571 if (si.si_socktype == SOCK_DGRAM && 572 setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &one, 573 sizeof one) < 0) { 574 syslog(LOG_ERR, 575 "can't disable v4-in-v6 on IPv6 socket"); 576 exit(1); 577 } 578 break; 579 case AF_INET6: 580 if (inet_pton(AF_INET6, hosts[nhostsbak], 581 host_addr) == 1) { 582 hints.ai_flags &= AI_NUMERICHOST; 583 } else { 584 /* 585 * Skip if we have an AF_INET address. 586 */ 587 if (inet_pton(AF_INET, hosts[nhostsbak], 588 host_addr) == 1) { 589 close(fd); 590 continue; 591 } 592 } 593 594 /* 595 * We're doing host-based access checks here, so don't 596 * allow v4-in-v6 to confuse things. The kernel will 597 * disable it by default on NFS sockets too. 598 */ 599 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, 600 sizeof one) < 0) { 601 syslog(LOG_ERR, 602 "can't disable v4-in-v6 on IPv6 socket"); 603 exit(1); 604 } 605 break; 606 default: 607 break; 608 } 609 610 /* 611 * If no hosts were specified, just bind to INADDR_ANY 612 */ 613 if (strcmp("*", hosts[nhostsbak]) == 0) { 614 if (svcport_str == NULL) { 615 res = malloc(sizeof(struct addrinfo)); 616 if (res == NULL) 617 out_of_mem(); 618 res->ai_flags = hints.ai_flags; 619 res->ai_family = hints.ai_family; 620 res->ai_protocol = hints.ai_protocol; 621 switch (res->ai_family) { 622 case AF_INET: 623 sin = malloc(sizeof(struct sockaddr_in)); 624 if (sin == NULL) 625 out_of_mem(); 626 sin->sin_family = AF_INET; 627 sin->sin_port = htons(0); 628 sin->sin_addr.s_addr = htonl(INADDR_ANY); 629 res->ai_addr = (struct sockaddr*) sin; 630 res->ai_addrlen = (socklen_t) 631 sizeof(res->ai_addr); 632 break; 633 case AF_INET6: 634 sin6 = malloc(sizeof(struct sockaddr_in6)); 635 if (sin6 == NULL) 636 out_of_mem(); 637 sin6->sin6_family = AF_INET6; 638 sin6->sin6_port = htons(0); 639 sin6->sin6_addr = in6addr_any; 640 res->ai_addr = (struct sockaddr*) sin6; 641 res->ai_addrlen = (socklen_t) 642 sizeof(res->ai_addr); 643 break; 644 default: 645 break; 646 } 647 } else { 648 if ((aicode = getaddrinfo(NULL, svcport_str, 649 &hints, &res)) != 0) { 650 syslog(LOG_ERR, 651 "cannot get local address for %s: %s", 652 nconf->nc_netid, 653 gai_strerror(aicode)); 654 continue; 655 } 656 } 657 } else { 658 if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 659 &hints, &res)) != 0) { 660 syslog(LOG_ERR, 661 "cannot get local address for %s: %s", 662 nconf->nc_netid, gai_strerror(aicode)); 663 continue; 664 } 665 } 666 667 r = bindresvport_sa(fd, res->ai_addr); 668 if (r != 0) { 669 syslog(LOG_ERR, "bindresvport_sa: %m"); 670 exit(1); 671 } 672 673 if (nconf->nc_semantics != NC_TPI_CLTS) 674 listen(fd, SOMAXCONN); 675 676 if (nconf->nc_semantics == NC_TPI_CLTS ) 677 transp = svc_dg_create(fd, 0, 0); 678 else 679 transp = svc_vc_create(fd, RPC_MAXDATASIZE, 680 RPC_MAXDATASIZE); 681 682 if (transp != (SVCXPRT *) NULL) { 683 if (!svc_reg(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv, 684 NULL)) 685 syslog(LOG_ERR, 686 "can't register %s RPCMNT_VER1 service", 687 nconf->nc_netid); 688 if (!force_v2) { 689 if (!svc_reg(transp, RPCPROG_MNT, RPCMNT_VER3, 690 mntsrv, NULL)) 691 syslog(LOG_ERR, 692 "can't register %s RPCMNT_VER3 service", 693 nconf->nc_netid); 694 } 695 } else 696 syslog(LOG_WARNING, "can't create %s services", 697 nconf->nc_netid); 698 699 if (registered == 0) { 700 registered = 1; 701 memset(&hints, 0, sizeof hints); 702 hints.ai_flags = AI_PASSIVE; 703 hints.ai_family = si.si_af; 704 hints.ai_socktype = si.si_socktype; 705 hints.ai_protocol = si.si_proto; 706 707 if (svcport_str == NULL) { 708 svcport_str = malloc(NI_MAXSERV * sizeof(char)); 709 if (svcport_str == NULL) 710 out_of_mem(); 711 712 if (getnameinfo(res->ai_addr, 713 res->ai_addr->sa_len, NULL, NI_MAXHOST, 714 svcport_str, NI_MAXSERV * sizeof(char), 715 NI_NUMERICHOST | NI_NUMERICSERV)) 716 errx(1, "Cannot get port number"); 717 } 718 719 if((aicode = getaddrinfo(NULL, svcport_str, &hints, 720 &res)) != 0) { 721 syslog(LOG_ERR, "cannot get local address: %s", 722 gai_strerror(aicode)); 723 exit(1); 724 } 725 726 servaddr.buf = malloc(res->ai_addrlen); 727 memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 728 servaddr.len = res->ai_addrlen; 729 730 rpcb_set(RPCPROG_MNT, RPCMNT_VER1, nconf, &servaddr); 731 rpcb_set(RPCPROG_MNT, RPCMNT_VER3, nconf, &servaddr); 732 733 xcreated++; 734 freeaddrinfo(res); 735 } 736 } /* end while */ 737} 738 739static void 740usage() 741{ 742 fprintf(stderr, 743 "usage: mountd [-2] [-d] [-e] [-l] [-n] [-p <port>] [-r] " 744 "[-h <bindip>] [export_file ...]\n"); 745 exit(1); 746} 747 748/* 749 * The mount rpc service 750 */ 751void 752mntsrv(rqstp, transp) 753 struct svc_req *rqstp; 754 SVCXPRT *transp; 755{ 756 struct exportlist *ep; 757 struct dirlist *dp; 758 struct fhreturn fhr; 759 struct stat stb; 760 struct statfs fsb; 761 char host[NI_MAXHOST], numerichost[NI_MAXHOST]; 762 int lookup_failed = 1; 763 struct sockaddr *saddr; 764 u_short sport; 765 char rpcpath[RPCMNT_PATHLEN + 1], dirpath[MAXPATHLEN]; 766 int bad = 0, defset, hostset; 767 sigset_t sighup_mask; 768 769 sigemptyset(&sighup_mask); 770 sigaddset(&sighup_mask, SIGHUP); 771 saddr = svc_getrpccaller(transp)->buf; 772 switch (saddr->sa_family) { 773 case AF_INET6: 774 sport = ntohs(((struct sockaddr_in6 *)saddr)->sin6_port); 775 break; 776 case AF_INET: 777 sport = ntohs(((struct sockaddr_in *)saddr)->sin_port); 778 break; 779 default: 780 syslog(LOG_ERR, "request from unknown address family"); 781 return; 782 } 783 lookup_failed = getnameinfo(saddr, saddr->sa_len, host, sizeof host, 784 NULL, 0, 0); 785 getnameinfo(saddr, saddr->sa_len, numerichost, 786 sizeof numerichost, NULL, 0, NI_NUMERICHOST); 787 switch (rqstp->rq_proc) { 788 case NULLPROC: 789 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, NULL)) 790 syslog(LOG_ERR, "can't send reply"); 791 return; 792 case RPCMNT_MOUNT: 793 if (sport >= IPPORT_RESERVED && resvport_only) { 794 syslog(LOG_NOTICE, 795 "mount request from %s from unprivileged port", 796 numerichost); 797 svcerr_weakauth(transp); 798 return; 799 } 800 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 801 syslog(LOG_NOTICE, "undecodable mount request from %s", 802 numerichost); 803 svcerr_decode(transp); 804 return; 805 } 806 807 /* 808 * Get the real pathname and make sure it is a directory 809 * or a regular file if the -r option was specified 810 * and it exists. 811 */ 812 if (realpath(rpcpath, dirpath) == NULL || 813 stat(dirpath, &stb) < 0 || 814 (!S_ISDIR(stb.st_mode) && 815 (dir_only || !S_ISREG(stb.st_mode))) || 816 statfs(dirpath, &fsb) < 0) { 817 chdir("/"); /* Just in case realpath doesn't */ 818 syslog(LOG_NOTICE, 819 "mount request from %s for non existent path %s", 820 numerichost, dirpath); 821 if (debug) 822 warnx("stat failed on %s", dirpath); 823 bad = ENOENT; /* We will send error reply later */ 824 } 825 826 /* Check in the exports list */ 827 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 828 ep = ex_search(&fsb.f_fsid); 829 hostset = defset = 0; 830 if (ep && (chk_host(ep->ex_defdir, saddr, &defset, &hostset) || 831 ((dp = dirp_search(ep->ex_dirl, dirpath)) && 832 chk_host(dp, saddr, &defset, &hostset)) || 833 (defset && scan_tree(ep->ex_defdir, saddr) == 0 && 834 scan_tree(ep->ex_dirl, saddr) == 0))) { 835 if (bad) { 836 if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 837 (caddr_t)&bad)) 838 syslog(LOG_ERR, "can't send reply"); 839 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 840 return; 841 } 842 if (hostset & DP_HOSTSET) 843 fhr.fhr_flag = hostset; 844 else 845 fhr.fhr_flag = defset; 846 fhr.fhr_vers = rqstp->rq_vers; 847 /* Get the file handle */ 848 memset(&fhr.fhr_fh, 0, sizeof(nfsfh_t)); 849 if (getfh(dirpath, (fhandle_t *)&fhr.fhr_fh) < 0) { 850 bad = errno; 851 syslog(LOG_ERR, "can't get fh for %s", dirpath); 852 if (!svc_sendreply(transp, (xdrproc_t)xdr_long, 853 (caddr_t)&bad)) 854 syslog(LOG_ERR, "can't send reply"); 855 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 856 return; 857 } 858 fhr.fhr_numsecflavors = ep->ex_numsecflavors; 859 fhr.fhr_secflavors = ep->ex_secflavors; 860 if (!svc_sendreply(transp, (xdrproc_t)xdr_fhs, 861 (caddr_t)&fhr)) 862 syslog(LOG_ERR, "can't send reply"); 863 if (!lookup_failed) 864 add_mlist(host, dirpath); 865 else 866 add_mlist(numerichost, dirpath); 867 if (debug) 868 warnx("mount successful"); 869 if (dolog) 870 syslog(LOG_NOTICE, 871 "mount request succeeded from %s for %s", 872 numerichost, dirpath); 873 } else { 874 bad = EACCES; 875 syslog(LOG_NOTICE, 876 "mount request denied from %s for %s", 877 numerichost, dirpath); 878 } 879 880 if (bad && !svc_sendreply(transp, (xdrproc_t)xdr_long, 881 (caddr_t)&bad)) 882 syslog(LOG_ERR, "can't send reply"); 883 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 884 return; 885 case RPCMNT_DUMP: 886 if (!svc_sendreply(transp, (xdrproc_t)xdr_mlist, (caddr_t)NULL)) 887 syslog(LOG_ERR, "can't send reply"); 888 else if (dolog) 889 syslog(LOG_NOTICE, 890 "dump request succeeded from %s", 891 numerichost); 892 return; 893 case RPCMNT_UMOUNT: 894 if (sport >= IPPORT_RESERVED && resvport_only) { 895 syslog(LOG_NOTICE, 896 "umount request from %s from unprivileged port", 897 numerichost); 898 svcerr_weakauth(transp); 899 return; 900 } 901 if (!svc_getargs(transp, (xdrproc_t)xdr_dir, rpcpath)) { 902 syslog(LOG_NOTICE, "undecodable umount request from %s", 903 numerichost); 904 svcerr_decode(transp); 905 return; 906 } 907 if (realpath(rpcpath, dirpath) == NULL) { 908 syslog(LOG_NOTICE, "umount request from %s " 909 "for non existent path %s", 910 numerichost, dirpath); 911 } 912 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 913 syslog(LOG_ERR, "can't send reply"); 914 if (!lookup_failed) 915 del_mlist(host, dirpath); 916 del_mlist(numerichost, dirpath); 917 if (dolog) 918 syslog(LOG_NOTICE, 919 "umount request succeeded from %s for %s", 920 numerichost, dirpath); 921 return; 922 case RPCMNT_UMNTALL: 923 if (sport >= IPPORT_RESERVED && resvport_only) { 924 syslog(LOG_NOTICE, 925 "umountall request from %s from unprivileged port", 926 numerichost); 927 svcerr_weakauth(transp); 928 return; 929 } 930 if (!svc_sendreply(transp, (xdrproc_t)xdr_void, (caddr_t)NULL)) 931 syslog(LOG_ERR, "can't send reply"); 932 if (!lookup_failed) 933 del_mlist(host, NULL); 934 del_mlist(numerichost, NULL); 935 if (dolog) 936 syslog(LOG_NOTICE, 937 "umountall request succeeded from %s", 938 numerichost); 939 return; 940 case RPCMNT_EXPORT: 941 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist, (caddr_t)NULL)) 942 if (!svc_sendreply(transp, (xdrproc_t)xdr_explist_brief, 943 (caddr_t)NULL)) 944 syslog(LOG_ERR, "can't send reply"); 945 if (dolog) 946 syslog(LOG_NOTICE, 947 "export request succeeded from %s", 948 numerichost); 949 return; 950 default: 951 svcerr_noproc(transp); 952 return; 953 } 954} 955 956/* 957 * Xdr conversion for a dirpath string 958 */ 959int 960xdr_dir(xdrsp, dirp) 961 XDR *xdrsp; 962 char *dirp; 963{ 964 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 965} 966 967/* 968 * Xdr routine to generate file handle reply 969 */ 970int 971xdr_fhs(xdrsp, cp) 972 XDR *xdrsp; 973 caddr_t cp; 974{ 975 struct fhreturn *fhrp = (struct fhreturn *)cp; 976 u_long ok = 0, len, auth; 977 int i; 978 979 if (!xdr_long(xdrsp, &ok)) 980 return (0); 981 switch (fhrp->fhr_vers) { 982 case 1: 983 return (xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, NFSX_V2FH)); 984 case 3: 985 len = NFSX_V3FH; 986 if (!xdr_long(xdrsp, &len)) 987 return (0); 988 if (!xdr_opaque(xdrsp, (caddr_t)&fhrp->fhr_fh, len)) 989 return (0); 990 if (fhrp->fhr_numsecflavors) { 991 if (!xdr_int(xdrsp, &fhrp->fhr_numsecflavors)) 992 return (0); 993 for (i = 0; i < fhrp->fhr_numsecflavors; i++) 994 if (!xdr_int(xdrsp, &fhrp->fhr_secflavors[i])) 995 return (0); 996 return (1); 997 } else { 998 auth = AUTH_SYS; 999 len = 1; 1000 if (!xdr_long(xdrsp, &len)) 1001 return (0); 1002 return (xdr_long(xdrsp, &auth)); 1003 } 1004 }; 1005 return (0); 1006} 1007 1008int 1009xdr_mlist(xdrsp, cp) 1010 XDR *xdrsp; 1011 caddr_t cp; 1012{ 1013 struct mountlist *mlp; 1014 int true = 1; 1015 int false = 0; 1016 char *strp; 1017 1018 mlp = mlhead; 1019 while (mlp) { 1020 if (!xdr_bool(xdrsp, &true)) 1021 return (0); 1022 strp = &mlp->ml_host[0]; 1023 if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN)) 1024 return (0); 1025 strp = &mlp->ml_dirp[0]; 1026 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 1027 return (0); 1028 mlp = mlp->ml_next; 1029 } 1030 if (!xdr_bool(xdrsp, &false)) 1031 return (0); 1032 return (1); 1033} 1034 1035/* 1036 * Xdr conversion for export list 1037 */ 1038int 1039xdr_explist_common(xdrsp, cp, brief) 1040 XDR *xdrsp; 1041 caddr_t cp; 1042 int brief; 1043{ 1044 struct exportlist *ep; 1045 int false = 0; 1046 int putdef; 1047 sigset_t sighup_mask; 1048 1049 sigemptyset(&sighup_mask); 1050 sigaddset(&sighup_mask, SIGHUP); 1051 sigprocmask(SIG_BLOCK, &sighup_mask, NULL); 1052 ep = exphead; 1053 while (ep) { 1054 putdef = 0; 1055 if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, 1056 &putdef, brief)) 1057 goto errout; 1058 if (ep->ex_defdir && putdef == 0 && 1059 put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL, 1060 &putdef, brief)) 1061 goto errout; 1062 ep = ep->ex_next; 1063 } 1064 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 1065 if (!xdr_bool(xdrsp, &false)) 1066 return (0); 1067 return (1); 1068errout: 1069 sigprocmask(SIG_UNBLOCK, &sighup_mask, NULL); 1070 return (0); 1071} 1072 1073/* 1074 * Called from xdr_explist() to traverse the tree and export the 1075 * directory paths. 1076 */ 1077int 1078put_exlist(dp, xdrsp, adp, putdefp, brief) 1079 struct dirlist *dp; 1080 XDR *xdrsp; 1081 struct dirlist *adp; 1082 int *putdefp; 1083 int brief; 1084{ 1085 struct grouplist *grp; 1086 struct hostlist *hp; 1087 int true = 1; 1088 int false = 0; 1089 int gotalldir = 0; 1090 char *strp; 1091 1092 if (dp) { 1093 if (put_exlist(dp->dp_left, xdrsp, adp, putdefp, brief)) 1094 return (1); 1095 if (!xdr_bool(xdrsp, &true)) 1096 return (1); 1097 strp = dp->dp_dirp; 1098 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 1099 return (1); 1100 if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) { 1101 gotalldir = 1; 1102 *putdefp = 1; 1103 } 1104 if (brief) { 1105 if (!xdr_bool(xdrsp, &true)) 1106 return (1); 1107 strp = "(...)"; 1108 if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN)) 1109 return (1); 1110 } else if ((dp->dp_flag & DP_DEFSET) == 0 && 1111 (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) { 1112 hp = dp->dp_hosts; 1113 while (hp) { 1114 grp = hp->ht_grp; 1115 if (grp->gr_type == GT_HOST) { 1116 if (!xdr_bool(xdrsp, &true)) 1117 return (1); 1118 strp = grp->gr_ptr.gt_addrinfo->ai_canonname; 1119 if (!xdr_string(xdrsp, &strp, 1120 RPCMNT_NAMELEN)) 1121 return (1); 1122 } else if (grp->gr_type == GT_NET) { 1123 if (!xdr_bool(xdrsp, &true)) 1124 return (1); 1125 strp = grp->gr_ptr.gt_net.nt_name; 1126 if (!xdr_string(xdrsp, &strp, 1127 RPCMNT_NAMELEN)) 1128 return (1); 1129 } 1130 hp = hp->ht_next; 1131 if (gotalldir && hp == (struct hostlist *)NULL) { 1132 hp = adp->dp_hosts; 1133 gotalldir = 0; 1134 } 1135 } 1136 } 1137 if (!xdr_bool(xdrsp, &false)) 1138 return (1); 1139 if (put_exlist(dp->dp_right, xdrsp, adp, putdefp, brief)) 1140 return (1); 1141 } 1142 return (0); 1143} 1144 1145int 1146xdr_explist(xdrsp, cp) 1147 XDR *xdrsp; 1148 caddr_t cp; 1149{ 1150 1151 return xdr_explist_common(xdrsp, cp, 0); 1152} 1153 1154int 1155xdr_explist_brief(xdrsp, cp) 1156 XDR *xdrsp; 1157 caddr_t cp; 1158{ 1159 1160 return xdr_explist_common(xdrsp, cp, 1); 1161} 1162 1163char *line; 1164int linesize; 1165FILE *exp_file; 1166 1167/* 1168 * Get the export list from one, currently open file 1169 */ 1170static void 1171get_exportlist_one() 1172{ 1173 struct exportlist *ep, *ep2; 1174 struct grouplist *grp, *tgrp; 1175 struct exportlist **epp; 1176 struct dirlist *dirhead; 1177 struct statfs fsb; 1178 struct xucred anon; 1179 char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; 1180 int len, has_host, exflags, got_nondir, dirplen, netgrp; 1181 1182 v4root_phase = 0; 1183 dirhead = (struct dirlist *)NULL; 1184 while (get_line()) { 1185 if (debug) 1186 warnx("got line %s", line); 1187 cp = line; 1188 nextfield(&cp, &endcp); 1189 if (*cp == '#') 1190 goto nextline; 1191 1192 /* 1193 * Set defaults. 1194 */ 1195 has_host = FALSE; 1196 anon = def_anon; 1197 exflags = MNT_EXPORTED; 1198 got_nondir = 0; 1199 opt_flags = 0; 1200 ep = (struct exportlist *)NULL; 1201 dirp = NULL; 1202 1203 /* 1204 * Handle the V4 root dir. 1205 */ 1206 if (*cp == 'V' && *(cp + 1) == '4' && *(cp + 2) == ':') { 1207 /* 1208 * V4: just indicates that it is the v4 root point, 1209 * so skip over that and set v4root_phase. 1210 */ 1211 if (v4root_phase > 0) { 1212 syslog(LOG_ERR, "V4:duplicate line, ignored"); 1213 goto nextline; 1214 } 1215 v4root_phase = 1; 1216 cp += 3; 1217 nextfield(&cp, &endcp); 1218 } 1219 1220 /* 1221 * Create new exports list entry 1222 */ 1223 len = endcp-cp; 1224 tgrp = grp = get_grp(); 1225 while (len > 0) { 1226 if (len > RPCMNT_NAMELEN) { 1227 getexp_err(ep, tgrp); 1228 goto nextline; 1229 } 1230 if (*cp == '-') { 1231 if (ep == (struct exportlist *)NULL) { 1232 getexp_err(ep, tgrp); 1233 goto nextline; 1234 } 1235 if (debug) 1236 warnx("doing opt %s", cp); 1237 got_nondir = 1; 1238 if (do_opt(&cp, &endcp, ep, grp, &has_host, 1239 &exflags, &anon)) { 1240 getexp_err(ep, tgrp); 1241 goto nextline; 1242 } 1243 } else if (*cp == '/') { 1244 savedc = *endcp; 1245 *endcp = '\0'; 1246 if (v4root_phase > 1) { 1247 if (dirp != NULL) { 1248 syslog(LOG_ERR, "Multiple V4 dirs"); 1249 getexp_err(ep, tgrp); 1250 goto nextline; 1251 } 1252 } 1253 if (check_dirpath(cp) && 1254 statfs(cp, &fsb) >= 0) { 1255 if (got_nondir) { 1256 syslog(LOG_ERR, "dirs must be first"); 1257 getexp_err(ep, tgrp); 1258 goto nextline; 1259 } 1260 if (v4root_phase == 1) { 1261 if (dirp != NULL) { 1262 syslog(LOG_ERR, "Multiple V4 dirs"); 1263 getexp_err(ep, tgrp); 1264 goto nextline; 1265 } 1266 if (strlen(v4root_dirpath) == 0) { 1267 strlcpy(v4root_dirpath, cp, 1268 sizeof (v4root_dirpath)); 1269 } else if (strcmp(v4root_dirpath, cp) 1270 != 0) { 1271 syslog(LOG_ERR, 1272 "different V4 dirpath %s", cp); 1273 getexp_err(ep, tgrp); 1274 goto nextline; 1275 } 1276 dirp = cp; 1277 v4root_phase = 2; 1278 got_nondir = 1; 1279 ep = get_exp(); 1280 } else { 1281 if (ep) { 1282 if (ep->ex_fs.val[0] != 1283 fsb.f_fsid.val[0] || 1284 ep->ex_fs.val[1] != 1285 fsb.f_fsid.val[1]) { 1286 getexp_err(ep, tgrp); 1287 goto nextline; 1288 } 1289 } else { 1290 /* 1291 * See if this directory is already 1292 * in the list. 1293 */ 1294 ep = ex_search(&fsb.f_fsid); 1295 if (ep == (struct exportlist *)NULL) { 1296 ep = get_exp(); 1297 ep->ex_fs = fsb.f_fsid; 1298 ep->ex_fsdir = (char *)malloc 1299 (strlen(fsb.f_mntonname) + 1); 1300 if (ep->ex_fsdir) 1301 strcpy(ep->ex_fsdir, 1302 fsb.f_mntonname); 1303 else 1304 out_of_mem(); 1305 if (debug) 1306 warnx( 1307 "making new ep fs=0x%x,0x%x", 1308 fsb.f_fsid.val[0], 1309 fsb.f_fsid.val[1]); 1310 } else if (debug) 1311 warnx("found ep fs=0x%x,0x%x", 1312 fsb.f_fsid.val[0], 1313 fsb.f_fsid.val[1]); 1314 } 1315 1316 /* 1317 * Add dirpath to export mount point. 1318 */ 1319 dirp = add_expdir(&dirhead, cp, len); 1320 dirplen = len; 1321 } 1322 } else { 1323 getexp_err(ep, tgrp); 1324 goto nextline; 1325 } 1326 *endcp = savedc; 1327 } else { 1328 savedc = *endcp; 1329 *endcp = '\0'; 1330 got_nondir = 1; 1331 if (ep == (struct exportlist *)NULL) { 1332 getexp_err(ep, tgrp); 1333 goto nextline; 1334 } 1335 1336 /* 1337 * Get the host or netgroup. 1338 */ 1339 setnetgrent(cp); 1340 netgrp = getnetgrent(&hst, &usr, &dom); 1341 do { 1342 if (has_host) { 1343 grp->gr_next = get_grp(); 1344 grp = grp->gr_next; 1345 } 1346 if (netgrp) { 1347 if (hst == 0) { 1348 syslog(LOG_ERR, 1349 "null hostname in netgroup %s, skipping", cp); 1350 grp->gr_type = GT_IGNORE; 1351 } else if (get_host(hst, grp, tgrp)) { 1352 syslog(LOG_ERR, 1353 "bad host %s in netgroup %s, skipping", hst, cp); 1354 grp->gr_type = GT_IGNORE; 1355 } 1356 } else if (get_host(cp, grp, tgrp)) { 1357 syslog(LOG_ERR, "bad host %s, skipping", cp); 1358 grp->gr_type = GT_IGNORE; 1359 } 1360 has_host = TRUE; 1361 } while (netgrp && getnetgrent(&hst, &usr, &dom)); 1362 endnetgrent(); 1363 *endcp = savedc; 1364 } 1365 cp = endcp; 1366 nextfield(&cp, &endcp); 1367 len = endcp - cp; 1368 } 1369 if (check_options(dirhead)) { 1370 getexp_err(ep, tgrp); 1371 goto nextline; 1372 } 1373 if (!has_host) { 1374 grp->gr_type = GT_DEFAULT; 1375 if (debug) 1376 warnx("adding a default entry"); 1377 1378 /* 1379 * Don't allow a network export coincide with a list of 1380 * host(s) on the same line. 1381 */ 1382 } else if ((opt_flags & OP_NET) && tgrp->gr_next) { 1383 syslog(LOG_ERR, "network/host conflict"); 1384 getexp_err(ep, tgrp); 1385 goto nextline; 1386 1387 /* 1388 * If an export list was specified on this line, make sure 1389 * that we have at least one valid entry, otherwise skip it. 1390 */ 1391 } else { 1392 grp = tgrp; 1393 while (grp && grp->gr_type == GT_IGNORE) 1394 grp = grp->gr_next; 1395 if (! grp) { 1396 getexp_err(ep, tgrp); 1397 goto nextline; 1398 } 1399 } 1400 1401 if (v4root_phase == 1) { 1402 syslog(LOG_ERR, "V4:root, no dirp, ignored"); 1403 getexp_err(ep, tgrp); 1404 goto nextline; 1405 } 1406 1407 /* 1408 * Loop through hosts, pushing the exports into the kernel. 1409 * After loop, tgrp points to the start of the list and 1410 * grp points to the last entry in the list. 1411 */ 1412 grp = tgrp; 1413 do { 1414 if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, 1415 &fsb)) { 1416 getexp_err(ep, tgrp); 1417 goto nextline; 1418 } 1419 } while (grp->gr_next && (grp = grp->gr_next)); 1420 1421 /* 1422 * For V4: don't enter in mount lists. 1423 */ 1424 if (v4root_phase > 0 && v4root_phase <= 2) 1425 goto nextline; 1426 1427 /* 1428 * Success. Update the data structures. 1429 */ 1430 if (has_host) { 1431 hang_dirp(dirhead, tgrp, ep, opt_flags); 1432 grp->gr_next = grphead; 1433 grphead = tgrp; 1434 } else { 1435 hang_dirp(dirhead, (struct grouplist *)NULL, ep, 1436 opt_flags); 1437 free_grp(grp); 1438 } 1439 dirhead = (struct dirlist *)NULL; 1440 if ((ep->ex_flag & EX_LINKED) == 0) { 1441 ep2 = exphead; 1442 epp = &exphead; 1443 1444 /* 1445 * Insert in the list in alphabetical order. 1446 */ 1447 while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) { 1448 epp = &ep2->ex_next; 1449 ep2 = ep2->ex_next; 1450 } 1451 if (ep2) 1452 ep->ex_next = ep2; 1453 *epp = ep; 1454 ep->ex_flag |= EX_LINKED; 1455 } 1456nextline: 1457 v4root_phase = 0; 1458 if (dirhead) { 1459 free_dir(dirhead); 1460 dirhead = (struct dirlist *)NULL; 1461 } 1462 } 1463} 1464 1465/* 1466 * Get the export list from all specified files 1467 */ 1468void 1469get_exportlist() 1470{ 1471 struct exportlist *ep, *ep2; 1472 struct grouplist *grp, *tgrp; 1473 struct export_args export; 1474 struct iovec *iov; 1475 struct statfs *fsp, *mntbufp; 1476 struct xvfsconf vfc; 1477 char *dirp; 1478 char errmsg[255]; 1479 int dirplen, num, i; 1480 int iovlen; 1481 int done; 1482 struct nfsex_args eargs; 1483 1484 v4root_dirpath[0] = '\0'; 1485 bzero(&export, sizeof(export)); 1486 export.ex_flags = MNT_DELEXPORT; 1487 dirp = NULL; 1488 dirplen = 0; 1489 iov = NULL; 1490 iovlen = 0; 1491 bzero(errmsg, sizeof(errmsg)); 1492 1493 /* 1494 * First, get rid of the old list 1495 */ 1496 ep = exphead; 1497 while (ep) { 1498 ep2 = ep; 1499 ep = ep->ex_next; 1500 free_exp(ep2); 1501 } 1502 exphead = (struct exportlist *)NULL; 1503 1504 grp = grphead; 1505 while (grp) { 1506 tgrp = grp; 1507 grp = grp->gr_next; 1508 free_grp(tgrp); 1509 } 1510 grphead = (struct grouplist *)NULL; 1511 1512 /* 1513 * and the old V4 root dir. 1514 */ 1515 bzero(&eargs, sizeof (eargs)); 1516 eargs.export.ex_flags = MNT_DELEXPORT; 1517 if (run_v4server > 0 && 1518 nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && 1519 errno != ENOENT) 1520 syslog(LOG_ERR, "Can't delete exports for V4:"); 1521 1522 /* 1523 * and clear flag that notes if a public fh has been exported. 1524 */ 1525 has_publicfh = 0; 1526 1527 /* 1528 * And delete exports that are in the kernel for all local 1529 * filesystems. 1530 * XXX: Should know how to handle all local exportable filesystems. 1531 */ 1532 num = getmntinfo(&mntbufp, MNT_NOWAIT); 1533 1534 if (num > 0) { 1535 build_iovec(&iov, &iovlen, "fstype", NULL, 0); 1536 build_iovec(&iov, &iovlen, "fspath", NULL, 0); 1537 build_iovec(&iov, &iovlen, "from", NULL, 0); 1538 build_iovec(&iov, &iovlen, "update", NULL, 0); 1539 build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); 1540 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 1541 } 1542 1543 for (i = 0; i < num; i++) { 1544 fsp = &mntbufp[i]; 1545 if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { 1546 syslog(LOG_ERR, "getvfsbyname() failed for %s", 1547 fsp->f_fstypename); 1548 continue; 1549 } 1550 1551 /* 1552 * Do not delete export for network filesystem by 1553 * passing "export" arg to nmount(). 1554 * It only makes sense to do this for local filesystems. 1555 */ 1556 if (vfc.vfc_flags & VFCF_NETWORK) 1557 continue; 1558 1559 iov[1].iov_base = fsp->f_fstypename; 1560 iov[1].iov_len = strlen(fsp->f_fstypename) + 1; 1561 iov[3].iov_base = fsp->f_mntonname; 1562 iov[3].iov_len = strlen(fsp->f_mntonname) + 1; 1563 iov[5].iov_base = fsp->f_mntfromname; 1564 iov[5].iov_len = strlen(fsp->f_mntfromname) + 1; 1565 1566 if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1567 errno != ENOENT && errno != ENOTSUP) { 1568 syslog(LOG_ERR, 1569 "can't delete exports for %s: %m %s", 1570 fsp->f_mntonname, errmsg); 1571 } 1572 } 1573 1574 if (iov != NULL) { 1575 /* Free strings allocated by strdup() in getmntopts.c */ 1576 free(iov[0].iov_base); /* fstype */ 1577 free(iov[2].iov_base); /* fspath */ 1578 free(iov[4].iov_base); /* from */ 1579 free(iov[6].iov_base); /* update */ 1580 free(iov[8].iov_base); /* export */ 1581 free(iov[10].iov_base); /* errmsg */ 1582 1583 /* free iov, allocated by realloc() */ 1584 free(iov); 1585 iovlen = 0; 1586 } 1587 1588 /* 1589 * Read in the exports file and build the list, calling 1590 * nmount() as we go along to push the export rules into the kernel. 1591 */ 1592 done = 0; 1593 for (i = 0; exnames[i] != NULL; i++) { 1594 if (debug) 1595 warnx("reading exports from %s", exnames[i]); 1596 if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1597 syslog(LOG_WARNING, "can't open %s", exnames[i]); 1598 continue; 1599 } 1600 get_exportlist_one(); 1601 fclose(exp_file); 1602 done++; 1603 } 1604 if (done == 0) { 1605 syslog(LOG_ERR, "can't open any exports file"); 1606 exit(2); 1607 } 1608 1609 /* 1610 * If there was no public fh, clear any previous one set. 1611 */ 1612 if (run_v4server > 0 && has_publicfh == 0) 1613 (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); 1614} 1615 1616/* 1617 * Allocate an export list element 1618 */ 1619struct exportlist * 1620get_exp() 1621{ 1622 struct exportlist *ep; 1623 1624 ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 1625 if (ep == (struct exportlist *)NULL) 1626 out_of_mem(); 1627 memset(ep, 0, sizeof(struct exportlist)); 1628 return (ep); 1629} 1630 1631/* 1632 * Allocate a group list element 1633 */ 1634struct grouplist * 1635get_grp() 1636{ 1637 struct grouplist *gp; 1638 1639 gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 1640 if (gp == (struct grouplist *)NULL) 1641 out_of_mem(); 1642 memset(gp, 0, sizeof(struct grouplist)); 1643 return (gp); 1644} 1645 1646/* 1647 * Clean up upon an error in get_exportlist(). 1648 */ 1649void 1650getexp_err(ep, grp) 1651 struct exportlist *ep; 1652 struct grouplist *grp; 1653{ 1654 struct grouplist *tgrp; 1655 1656 if (!(opt_flags & OP_QUIET)) 1657 syslog(LOG_ERR, "bad exports list line %s", line); 1658 if (ep && (ep->ex_flag & EX_LINKED) == 0) 1659 free_exp(ep); 1660 while (grp) { 1661 tgrp = grp; 1662 grp = grp->gr_next; 1663 free_grp(tgrp); 1664 } 1665} 1666 1667/* 1668 * Search the export list for a matching fs. 1669 */ 1670struct exportlist * 1671ex_search(fsid) 1672 fsid_t *fsid; 1673{ 1674 struct exportlist *ep; 1675 1676 ep = exphead; 1677 while (ep) { 1678 if (ep->ex_fs.val[0] == fsid->val[0] && 1679 ep->ex_fs.val[1] == fsid->val[1]) 1680 return (ep); 1681 ep = ep->ex_next; 1682 } 1683 return (ep); 1684} 1685 1686/* 1687 * Add a directory path to the list. 1688 */ 1689char * 1690add_expdir(dpp, cp, len) 1691 struct dirlist **dpp; 1692 char *cp; 1693 int len; 1694{ 1695 struct dirlist *dp; 1696 1697 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 1698 if (dp == (struct dirlist *)NULL) 1699 out_of_mem(); 1700 dp->dp_left = *dpp; 1701 dp->dp_right = (struct dirlist *)NULL; 1702 dp->dp_flag = 0; 1703 dp->dp_hosts = (struct hostlist *)NULL; 1704 strcpy(dp->dp_dirp, cp); 1705 *dpp = dp; 1706 return (dp->dp_dirp); 1707} 1708 1709/* 1710 * Hang the dir list element off the dirpath binary tree as required 1711 * and update the entry for host. 1712 */ 1713void 1714hang_dirp(dp, grp, ep, flags) 1715 struct dirlist *dp; 1716 struct grouplist *grp; 1717 struct exportlist *ep; 1718 int flags; 1719{ 1720 struct hostlist *hp; 1721 struct dirlist *dp2; 1722 1723 if (flags & OP_ALLDIRS) { 1724 if (ep->ex_defdir) 1725 free((caddr_t)dp); 1726 else 1727 ep->ex_defdir = dp; 1728 if (grp == (struct grouplist *)NULL) { 1729 ep->ex_defdir->dp_flag |= DP_DEFSET; 1730 } else while (grp) { 1731 hp = get_ht(); 1732 hp->ht_grp = grp; 1733 hp->ht_next = ep->ex_defdir->dp_hosts; 1734 ep->ex_defdir->dp_hosts = hp; 1735 grp = grp->gr_next; 1736 } 1737 } else { 1738 1739 /* 1740 * Loop through the directories adding them to the tree. 1741 */ 1742 while (dp) { 1743 dp2 = dp->dp_left; 1744 add_dlist(&ep->ex_dirl, dp, grp, flags); 1745 dp = dp2; 1746 } 1747 } 1748} 1749 1750/* 1751 * Traverse the binary tree either updating a node that is already there 1752 * for the new directory or adding the new node. 1753 */ 1754void 1755add_dlist(dpp, newdp, grp, flags) 1756 struct dirlist **dpp; 1757 struct dirlist *newdp; 1758 struct grouplist *grp; 1759 int flags; 1760{ 1761 struct dirlist *dp; 1762 struct hostlist *hp; 1763 int cmp; 1764 1765 dp = *dpp; 1766 if (dp) { 1767 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1768 if (cmp > 0) { 1769 add_dlist(&dp->dp_left, newdp, grp, flags); 1770 return; 1771 } else if (cmp < 0) { 1772 add_dlist(&dp->dp_right, newdp, grp, flags); 1773 return; 1774 } else 1775 free((caddr_t)newdp); 1776 } else { 1777 dp = newdp; 1778 dp->dp_left = (struct dirlist *)NULL; 1779 *dpp = dp; 1780 } 1781 if (grp) { 1782 1783 /* 1784 * Hang all of the host(s) off of the directory point. 1785 */ 1786 do { 1787 hp = get_ht(); 1788 hp->ht_grp = grp; 1789 hp->ht_next = dp->dp_hosts; 1790 dp->dp_hosts = hp; 1791 grp = grp->gr_next; 1792 } while (grp); 1793 } else { 1794 dp->dp_flag |= DP_DEFSET; 1795 } 1796} 1797 1798/* 1799 * Search for a dirpath on the export point. 1800 */ 1801struct dirlist * 1802dirp_search(dp, dirp) 1803 struct dirlist *dp; 1804 char *dirp; 1805{ 1806 int cmp; 1807 1808 if (dp) { 1809 cmp = strcmp(dp->dp_dirp, dirp); 1810 if (cmp > 0) 1811 return (dirp_search(dp->dp_left, dirp)); 1812 else if (cmp < 0) 1813 return (dirp_search(dp->dp_right, dirp)); 1814 else 1815 return (dp); 1816 } 1817 return (dp); 1818} 1819 1820/* 1821 * Scan for a host match in a directory tree. 1822 */ 1823int 1824chk_host(dp, saddr, defsetp, hostsetp) 1825 struct dirlist *dp; 1826 struct sockaddr *saddr; 1827 int *defsetp; 1828 int *hostsetp; 1829{ 1830 struct hostlist *hp; 1831 struct grouplist *grp; 1832 struct addrinfo *ai; 1833 1834 if (dp) { 1835 if (dp->dp_flag & DP_DEFSET) 1836 *defsetp = dp->dp_flag; 1837 hp = dp->dp_hosts; 1838 while (hp) { 1839 grp = hp->ht_grp; 1840 switch (grp->gr_type) { 1841 case GT_HOST: 1842 ai = grp->gr_ptr.gt_addrinfo; 1843 for (; ai; ai = ai->ai_next) { 1844 if (!sacmp(ai->ai_addr, saddr, NULL)) { 1845 *hostsetp = 1846 (hp->ht_flag | DP_HOSTSET); 1847 return (1); 1848 } 1849 } 1850 break; 1851 case GT_NET: 1852 if (!sacmp(saddr, (struct sockaddr *) 1853 &grp->gr_ptr.gt_net.nt_net, 1854 (struct sockaddr *) 1855 &grp->gr_ptr.gt_net.nt_mask)) { 1856 *hostsetp = (hp->ht_flag | DP_HOSTSET); 1857 return (1); 1858 } 1859 break; 1860 } 1861 hp = hp->ht_next; 1862 } 1863 } 1864 return (0); 1865} 1866 1867/* 1868 * Scan tree for a host that matches the address. 1869 */ 1870int 1871scan_tree(dp, saddr) 1872 struct dirlist *dp; 1873 struct sockaddr *saddr; 1874{ 1875 int defset, hostset; 1876 1877 if (dp) { 1878 if (scan_tree(dp->dp_left, saddr)) 1879 return (1); 1880 if (chk_host(dp, saddr, &defset, &hostset)) 1881 return (1); 1882 if (scan_tree(dp->dp_right, saddr)) 1883 return (1); 1884 } 1885 return (0); 1886} 1887 1888/* 1889 * Traverse the dirlist tree and free it up. 1890 */ 1891void 1892free_dir(dp) 1893 struct dirlist *dp; 1894{ 1895 1896 if (dp) { 1897 free_dir(dp->dp_left); 1898 free_dir(dp->dp_right); 1899 free_host(dp->dp_hosts); 1900 free((caddr_t)dp); 1901 } 1902} 1903 1904/* 1905 * Parse a colon separated list of security flavors 1906 */ 1907int 1908parsesec(seclist, ep) 1909 char *seclist; 1910 struct exportlist *ep; 1911{ 1912 char *cp, savedc; 1913 int flavor; 1914 1915 ep->ex_numsecflavors = 0; 1916 for (;;) { 1917 cp = strchr(seclist, ':'); 1918 if (cp) { 1919 savedc = *cp; 1920 *cp = '\0'; 1921 } 1922 1923 if (!strcmp(seclist, "sys")) 1924 flavor = AUTH_SYS; 1925 else if (!strcmp(seclist, "krb5")) 1926 flavor = RPCSEC_GSS_KRB5; 1927 else if (!strcmp(seclist, "krb5i")) 1928 flavor = RPCSEC_GSS_KRB5I; 1929 else if (!strcmp(seclist, "krb5p")) 1930 flavor = RPCSEC_GSS_KRB5P; 1931 else { 1932 if (cp) 1933 *cp = savedc; 1934 syslog(LOG_ERR, "bad sec flavor: %s", seclist); 1935 return (1); 1936 } 1937 if (ep->ex_numsecflavors == MAXSECFLAVORS) { 1938 if (cp) 1939 *cp = savedc; 1940 syslog(LOG_ERR, "too many sec flavors: %s", seclist); 1941 return (1); 1942 } 1943 ep->ex_secflavors[ep->ex_numsecflavors] = flavor; 1944 ep->ex_numsecflavors++; 1945 if (cp) { 1946 *cp = savedc; 1947 seclist = cp + 1; 1948 } else { 1949 break; 1950 } 1951 } 1952 return (0); 1953} 1954 1955/* 1956 * Parse the option string and update fields. 1957 * Option arguments may either be -<option>=<value> or 1958 * -<option> <value> 1959 */ 1960int 1961do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1962 char **cpp, **endcpp; 1963 struct exportlist *ep; 1964 struct grouplist *grp; 1965 int *has_hostp; 1966 int *exflagsp; 1967 struct xucred *cr; 1968{ 1969 char *cpoptarg, *cpoptend; 1970 char *cp, *endcp, *cpopt, savedc, savedc2; 1971 int allflag, usedarg; 1972 1973 savedc2 = '\0'; 1974 cpopt = *cpp; 1975 cpopt++; 1976 cp = *endcpp; 1977 savedc = *cp; 1978 *cp = '\0'; 1979 while (cpopt && *cpopt) { 1980 allflag = 1; 1981 usedarg = -2; 1982 if ((cpoptend = strchr(cpopt, ','))) { 1983 *cpoptend++ = '\0'; 1984 if ((cpoptarg = strchr(cpopt, '='))) 1985 *cpoptarg++ = '\0'; 1986 } else { 1987 if ((cpoptarg = strchr(cpopt, '='))) 1988 *cpoptarg++ = '\0'; 1989 else { 1990 *cp = savedc; 1991 nextfield(&cp, &endcp); 1992 **endcpp = '\0'; 1993 if (endcp > cp && *cp != '-') { 1994 cpoptarg = cp; 1995 savedc2 = *endcp; 1996 *endcp = '\0'; 1997 usedarg = 0; 1998 } 1999 } 2000 } 2001 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 2002 *exflagsp |= MNT_EXRDONLY; 2003 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 2004 !(allflag = strcmp(cpopt, "mapall")) || 2005 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 2006 usedarg++; 2007 parsecred(cpoptarg, cr); 2008 if (allflag == 0) { 2009 *exflagsp |= MNT_EXPORTANON; 2010 opt_flags |= OP_MAPALL; 2011 } else 2012 opt_flags |= OP_MAPROOT; 2013 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 2014 !strcmp(cpopt, "m"))) { 2015 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 2016 syslog(LOG_ERR, "bad mask: %s", cpoptarg); 2017 return (1); 2018 } 2019 usedarg++; 2020 opt_flags |= OP_MASK; 2021 } else if (cpoptarg && (!strcmp(cpopt, "network") || 2022 !strcmp(cpopt, "n"))) { 2023 if (strchr(cpoptarg, '/') != NULL) { 2024 if (debug) 2025 fprintf(stderr, "setting OP_MASKLEN\n"); 2026 opt_flags |= OP_MASKLEN; 2027 } 2028 if (grp->gr_type != GT_NULL) { 2029 syslog(LOG_ERR, "network/host conflict"); 2030 return (1); 2031 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 2032 syslog(LOG_ERR, "bad net: %s", cpoptarg); 2033 return (1); 2034 } 2035 grp->gr_type = GT_NET; 2036 *has_hostp = 1; 2037 usedarg++; 2038 opt_flags |= OP_NET; 2039 } else if (!strcmp(cpopt, "alldirs")) { 2040 opt_flags |= OP_ALLDIRS; 2041 } else if (!strcmp(cpopt, "public")) { 2042 *exflagsp |= MNT_EXPUBLIC; 2043 } else if (!strcmp(cpopt, "webnfs")) { 2044 *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 2045 opt_flags |= OP_MAPALL; 2046 } else if (cpoptarg && !strcmp(cpopt, "index")) { 2047 ep->ex_indexfile = strdup(cpoptarg); 2048 } else if (!strcmp(cpopt, "quiet")) { 2049 opt_flags |= OP_QUIET; 2050 } else if (!strcmp(cpopt, "sec")) { 2051 if (parsesec(cpoptarg, ep)) 2052 return (1); 2053 opt_flags |= OP_SEC; 2054 usedarg++; 2055 } else { 2056 syslog(LOG_ERR, "bad opt %s", cpopt); 2057 return (1); 2058 } 2059 if (usedarg >= 0) { 2060 *endcp = savedc2; 2061 **endcpp = savedc; 2062 if (usedarg > 0) { 2063 *cpp = cp; 2064 *endcpp = endcp; 2065 } 2066 return (0); 2067 } 2068 cpopt = cpoptend; 2069 } 2070 **endcpp = savedc; 2071 return (0); 2072} 2073 2074/* 2075 * Translate a character string to the corresponding list of network 2076 * addresses for a hostname. 2077 */ 2078int 2079get_host(cp, grp, tgrp) 2080 char *cp; 2081 struct grouplist *grp; 2082 struct grouplist *tgrp; 2083{ 2084 struct grouplist *checkgrp; 2085 struct addrinfo *ai, *tai, hints; 2086 int ecode; 2087 char host[NI_MAXHOST]; 2088 2089 if (grp->gr_type != GT_NULL) { 2090 syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 2091 return (1); 2092 } 2093 memset(&hints, 0, sizeof hints); 2094 hints.ai_flags = AI_CANONNAME; 2095 hints.ai_protocol = IPPROTO_UDP; 2096 ecode = getaddrinfo(cp, NULL, &hints, &ai); 2097 if (ecode != 0) { 2098 syslog(LOG_ERR,"can't get address info for host %s", cp); 2099 return 1; 2100 } 2101 grp->gr_ptr.gt_addrinfo = ai; 2102 while (ai != NULL) { 2103 if (ai->ai_canonname == NULL) { 2104 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 2105 sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 2106 strlcpy(host, "?", sizeof(host)); 2107 ai->ai_canonname = strdup(host); 2108 ai->ai_flags |= AI_CANONNAME; 2109 } 2110 if (debug) 2111 fprintf(stderr, "got host %s\n", ai->ai_canonname); 2112 /* 2113 * Sanity check: make sure we don't already have an entry 2114 * for this host in the grouplist. 2115 */ 2116 for (checkgrp = tgrp; checkgrp != NULL; 2117 checkgrp = checkgrp->gr_next) { 2118 if (checkgrp->gr_type != GT_HOST) 2119 continue; 2120 for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 2121 tai = tai->ai_next) { 2122 if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 2123 continue; 2124 if (debug) 2125 fprintf(stderr, 2126 "ignoring duplicate host %s\n", 2127 ai->ai_canonname); 2128 grp->gr_type = GT_IGNORE; 2129 return (0); 2130 } 2131 } 2132 ai = ai->ai_next; 2133 } 2134 grp->gr_type = GT_HOST; 2135 return (0); 2136} 2137 2138/* 2139 * Free up an exports list component 2140 */ 2141void 2142free_exp(ep) 2143 struct exportlist *ep; 2144{ 2145 2146 if (ep->ex_defdir) { 2147 free_host(ep->ex_defdir->dp_hosts); 2148 free((caddr_t)ep->ex_defdir); 2149 } 2150 if (ep->ex_fsdir) 2151 free(ep->ex_fsdir); 2152 if (ep->ex_indexfile) 2153 free(ep->ex_indexfile); 2154 free_dir(ep->ex_dirl); 2155 free((caddr_t)ep); 2156} 2157 2158/* 2159 * Free hosts. 2160 */ 2161void 2162free_host(hp) 2163 struct hostlist *hp; 2164{ 2165 struct hostlist *hp2; 2166 2167 while (hp) { 2168 hp2 = hp; 2169 hp = hp->ht_next; 2170 free((caddr_t)hp2); 2171 } 2172} 2173 2174struct hostlist * 2175get_ht() 2176{ 2177 struct hostlist *hp; 2178 2179 hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 2180 if (hp == (struct hostlist *)NULL) 2181 out_of_mem(); 2182 hp->ht_next = (struct hostlist *)NULL; 2183 hp->ht_flag = 0; 2184 return (hp); 2185} 2186 2187/* 2188 * Out of memory, fatal 2189 */ 2190void 2191out_of_mem() 2192{ 2193 2194 syslog(LOG_ERR, "out of memory"); 2195 exit(2); 2196} 2197 2198/* 2199 * Do the nmount() syscall with the update flag to push the export info into 2200 * the kernel. 2201 */ 2202int 2203do_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 2204 struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 2205{ 2206 struct statfs fsb1; 2207 struct addrinfo *ai; 2208 struct export_args ea, *eap; 2209 char errmsg[255]; 2210 char *cp; 2211 int done; 2212 char savedc; 2213 struct iovec *iov; 2214 int i, iovlen; 2215 int ret; 2216 struct nfsex_args nfsea; 2217 2218 if (run_v4server > 0) 2219 eap = &nfsea.export; 2220 else 2221 eap = &ea; 2222 2223 cp = NULL; 2224 savedc = '\0'; 2225 iov = NULL; 2226 iovlen = 0; 2227 ret = 0; 2228 2229 bzero(eap, sizeof (struct export_args)); 2230 bzero(errmsg, sizeof(errmsg)); 2231 eap->ex_flags = exflags; 2232 eap->ex_anon = *anoncrp; 2233 eap->ex_indexfile = ep->ex_indexfile; 2234 if (grp->gr_type == GT_HOST) 2235 ai = grp->gr_ptr.gt_addrinfo; 2236 else 2237 ai = NULL; 2238 eap->ex_numsecflavors = ep->ex_numsecflavors; 2239 for (i = 0; i < eap->ex_numsecflavors; i++) 2240 eap->ex_secflavors[i] = ep->ex_secflavors[i]; 2241 if (eap->ex_numsecflavors == 0) { 2242 eap->ex_numsecflavors = 1; 2243 eap->ex_secflavors[0] = AUTH_SYS; 2244 } 2245 done = FALSE; 2246 2247 if (v4root_phase == 0) { 2248 build_iovec(&iov, &iovlen, "fstype", NULL, 0); 2249 build_iovec(&iov, &iovlen, "fspath", NULL, 0); 2250 build_iovec(&iov, &iovlen, "from", NULL, 0); 2251 build_iovec(&iov, &iovlen, "update", NULL, 0); 2252 build_iovec(&iov, &iovlen, "export", eap, 2253 sizeof (struct export_args)); 2254 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2255 } 2256 2257 while (!done) { 2258 switch (grp->gr_type) { 2259 case GT_HOST: 2260 if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 2261 goto skip; 2262 eap->ex_addr = ai->ai_addr; 2263 eap->ex_addrlen = ai->ai_addrlen; 2264 eap->ex_masklen = 0; 2265 break; 2266 case GT_NET: 2267 if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 2268 have_v6 == 0) 2269 goto skip; 2270 eap->ex_addr = 2271 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2272 eap->ex_addrlen = 2273 ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2274 eap->ex_mask = 2275 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2276 eap->ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 2277 break; 2278 case GT_DEFAULT: 2279 eap->ex_addr = NULL; 2280 eap->ex_addrlen = 0; 2281 eap->ex_mask = NULL; 2282 eap->ex_masklen = 0; 2283 break; 2284 case GT_IGNORE: 2285 ret = 0; 2286 goto error_exit; 2287 break; 2288 default: 2289 syslog(LOG_ERR, "bad grouptype"); 2290 if (cp) 2291 *cp = savedc; 2292 ret = 1; 2293 goto error_exit; 2294 }; 2295 2296 /* 2297 * For V4:, use the nfssvc() syscall, instead of mount(). 2298 */ 2299 if (v4root_phase == 2) { 2300 nfsea.fspec = v4root_dirpath; 2301 if (run_v4server > 0 && 2302 nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&nfsea) < 0) { 2303 syslog(LOG_ERR, "Exporting V4: failed"); 2304 return (2); 2305 } 2306 } else { 2307 /* 2308 * XXX: 2309 * Maybe I should just use the fsb->f_mntonname path 2310 * instead of looping back up the dirp to the mount 2311 * point?? 2312 * Also, needs to know how to export all types of local 2313 * exportable filesystems and not just "ufs". 2314 */ 2315 iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 2316 iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 2317 iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 2318 iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 2319 iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 2320 iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 2321 2322 while (nmount(iov, iovlen, fsb->f_flags) < 0) { 2323 if (cp) 2324 *cp-- = savedc; 2325 else 2326 cp = dirp + dirplen - 1; 2327 if (opt_flags & OP_QUIET) { 2328 ret = 1; 2329 goto error_exit; 2330 } 2331 if (errno == EPERM) { 2332 if (debug) 2333 warnx("can't change attributes for %s", 2334 dirp); 2335 syslog(LOG_ERR, 2336 "can't change attributes for %s", 2337 dirp); 2338 ret = 1; 2339 goto error_exit; 2340 } 2341 if (opt_flags & OP_ALLDIRS) { 2342 if (errno == EINVAL) 2343 syslog(LOG_ERR, 2344 "-alldirs requested but %s is not a filesystem mountpoint", 2345 dirp); 2346 else 2347 syslog(LOG_ERR, 2348 "could not remount %s: %m", 2349 dirp); 2350 ret = 1; 2351 goto error_exit; 2352 } 2353 /* back up over the last component */ 2354 while (*cp == '/' && cp > dirp) 2355 cp--; 2356 while (*(cp - 1) != '/' && cp > dirp) 2357 cp--; 2358 if (cp == dirp) { 2359 if (debug) 2360 warnx("mnt unsucc"); 2361 syslog(LOG_ERR, "can't export %s %s", 2362 dirp, errmsg); 2363 ret = 1; 2364 goto error_exit; 2365 } 2366 savedc = *cp; 2367 *cp = '\0'; 2368 /* 2369 * Check that we're still on the same 2370 * filesystem. 2371 */ 2372 if (statfs(dirp, &fsb1) != 0 || 2373 bcmp(&fsb1.f_fsid, &fsb->f_fsid, 2374 sizeof (fsb1.f_fsid)) != 0) { 2375 *cp = savedc; 2376 syslog(LOG_ERR, 2377 "can't export %s %s", dirp, 2378 errmsg); 2379 ret = 1; 2380 goto error_exit; 2381 } 2382 } 2383 } 2384 2385 /* 2386 * For the experimental server: 2387 * If this is the public directory, get the file handle 2388 * and load it into the kernel via the nfssvc() syscall. 2389 */ 2390 if (run_v4server > 0 && (exflags & MNT_EXPUBLIC) != 0) { 2391 fhandle_t fh; 2392 char *public_name; 2393 2394 if (eap->ex_indexfile != NULL) 2395 public_name = eap->ex_indexfile; 2396 else 2397 public_name = dirp; 2398 if (getfh(public_name, &fh) < 0) 2399 syslog(LOG_ERR, 2400 "Can't get public fh for %s", public_name); 2401 else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) 2402 syslog(LOG_ERR, 2403 "Can't set public fh for %s", public_name); 2404 else 2405 has_publicfh = 1; 2406 } 2407skip: 2408 if (ai != NULL) 2409 ai = ai->ai_next; 2410 if (ai == NULL) 2411 done = TRUE; 2412 } 2413 if (cp) 2414 *cp = savedc; 2415error_exit: 2416 /* free strings allocated by strdup() in getmntopts.c */ 2417 if (iov != NULL) { 2418 free(iov[0].iov_base); /* fstype */ 2419 free(iov[2].iov_base); /* fspath */ 2420 free(iov[4].iov_base); /* from */ 2421 free(iov[6].iov_base); /* update */ 2422 free(iov[8].iov_base); /* export */ 2423 free(iov[10].iov_base); /* errmsg */ 2424 2425 /* free iov, allocated by realloc() */ 2426 free(iov); 2427 } 2428 return (ret); 2429} 2430 2431/* 2432 * Translate a net address. 2433 * 2434 * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 2435 */ 2436int 2437get_net(cp, net, maskflg) 2438 char *cp; 2439 struct netmsk *net; 2440 int maskflg; 2441{ 2442 struct netent *np = NULL; 2443 char *name, *p, *prefp; 2444 struct sockaddr_in sin; 2445 struct sockaddr *sa = NULL; 2446 struct addrinfo hints, *ai = NULL; 2447 char netname[NI_MAXHOST]; 2448 long preflen; 2449 2450 p = prefp = NULL; 2451 if ((opt_flags & OP_MASKLEN) && !maskflg) { 2452 p = strchr(cp, '/'); 2453 *p = '\0'; 2454 prefp = p + 1; 2455 } 2456 2457 /* 2458 * Check for a numeric address first. We wish to avoid 2459 * possible DNS lookups in getnetbyname(). 2460 */ 2461 if (isxdigit(*cp) || *cp == ':') { 2462 memset(&hints, 0, sizeof hints); 2463 /* Ensure the mask and the network have the same family. */ 2464 if (maskflg && (opt_flags & OP_NET)) 2465 hints.ai_family = net->nt_net.ss_family; 2466 else if (!maskflg && (opt_flags & OP_HAVEMASK)) 2467 hints.ai_family = net->nt_mask.ss_family; 2468 else 2469 hints.ai_family = AF_UNSPEC; 2470 hints.ai_flags = AI_NUMERICHOST; 2471 if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 2472 sa = ai->ai_addr; 2473 if (sa != NULL && ai->ai_family == AF_INET) { 2474 /* 2475 * The address in `cp' is really a network address, so 2476 * use inet_network() to re-interpret this correctly. 2477 * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 2478 */ 2479 bzero(&sin, sizeof sin); 2480 sin.sin_family = AF_INET; 2481 sin.sin_len = sizeof sin; 2482 sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 2483 if (debug) 2484 fprintf(stderr, "get_net: v4 addr %s\n", 2485 inet_ntoa(sin.sin_addr)); 2486 sa = (struct sockaddr *)&sin; 2487 } 2488 } 2489 if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 2490 bzero(&sin, sizeof sin); 2491 sin.sin_family = AF_INET; 2492 sin.sin_len = sizeof sin; 2493 sin.sin_addr = inet_makeaddr(np->n_net, 0); 2494 sa = (struct sockaddr *)&sin; 2495 } 2496 if (sa == NULL) 2497 goto fail; 2498 2499 if (maskflg) { 2500 /* The specified sockaddr is a mask. */ 2501 if (checkmask(sa) != 0) 2502 goto fail; 2503 bcopy(sa, &net->nt_mask, sa->sa_len); 2504 opt_flags |= OP_HAVEMASK; 2505 } else { 2506 /* The specified sockaddr is a network address. */ 2507 bcopy(sa, &net->nt_net, sa->sa_len); 2508 2509 /* Get a network name for the export list. */ 2510 if (np) { 2511 name = np->n_name; 2512 } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2513 NULL, 0, NI_NUMERICHOST) == 0) { 2514 name = netname; 2515 } else { 2516 goto fail; 2517 } 2518 if ((net->nt_name = strdup(name)) == NULL) 2519 out_of_mem(); 2520 2521 /* 2522 * Extract a mask from either a "/<masklen>" suffix, or 2523 * from the class of an IPv4 address. 2524 */ 2525 if (opt_flags & OP_MASKLEN) { 2526 preflen = strtol(prefp, NULL, 10); 2527 if (preflen < 0L || preflen == LONG_MAX) 2528 goto fail; 2529 bcopy(sa, &net->nt_mask, sa->sa_len); 2530 if (makemask(&net->nt_mask, (int)preflen) != 0) 2531 goto fail; 2532 opt_flags |= OP_HAVEMASK; 2533 *p = '/'; 2534 } else if (sa->sa_family == AF_INET && 2535 (opt_flags & OP_MASK) == 0) { 2536 in_addr_t addr; 2537 2538 addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 2539 if (IN_CLASSA(addr)) 2540 preflen = 8; 2541 else if (IN_CLASSB(addr)) 2542 preflen = 16; 2543 else if (IN_CLASSC(addr)) 2544 preflen = 24; 2545 else if (IN_CLASSD(addr)) 2546 preflen = 28; 2547 else 2548 preflen = 32; /* XXX */ 2549 2550 bcopy(sa, &net->nt_mask, sa->sa_len); 2551 makemask(&net->nt_mask, (int)preflen); 2552 opt_flags |= OP_HAVEMASK; 2553 } 2554 } 2555 2556 if (ai) 2557 freeaddrinfo(ai); 2558 return 0; 2559 2560fail: 2561 if (ai) 2562 freeaddrinfo(ai); 2563 return 1; 2564} 2565 2566/* 2567 * Parse out the next white space separated field 2568 */ 2569void 2570nextfield(cp, endcp) 2571 char **cp; 2572 char **endcp; 2573{ 2574 char *p; 2575 2576 p = *cp; 2577 while (*p == ' ' || *p == '\t') 2578 p++; 2579 if (*p == '\n' || *p == '\0') 2580 *cp = *endcp = p; 2581 else { 2582 *cp = p++; 2583 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 2584 p++; 2585 *endcp = p; 2586 } 2587} 2588 2589/* 2590 * Get an exports file line. Skip over blank lines and handle line 2591 * continuations. 2592 */ 2593int 2594get_line() 2595{ 2596 char *p, *cp; 2597 size_t len; 2598 int totlen, cont_line; 2599 2600 /* 2601 * Loop around ignoring blank lines and getting all continuation lines. 2602 */ 2603 p = line; 2604 totlen = 0; 2605 do { 2606 if ((p = fgetln(exp_file, &len)) == NULL) 2607 return (0); 2608 cp = p + len - 1; 2609 cont_line = 0; 2610 while (cp >= p && 2611 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 2612 if (*cp == '\\') 2613 cont_line = 1; 2614 cp--; 2615 len--; 2616 } 2617 if (cont_line) { 2618 *++cp = ' '; 2619 len++; 2620 } 2621 if (linesize < len + totlen + 1) { 2622 linesize = len + totlen + 1; 2623 line = realloc(line, linesize); 2624 if (line == NULL) 2625 out_of_mem(); 2626 } 2627 memcpy(line + totlen, p, len); 2628 totlen += len; 2629 line[totlen] = '\0'; 2630 } while (totlen == 0 || cont_line); 2631 return (1); 2632} 2633 2634/* 2635 * Parse a description of a credential. 2636 */ 2637void 2638parsecred(namelist, cr) 2639 char *namelist; 2640 struct xucred *cr; 2641{ 2642 char *name; 2643 int cnt; 2644 char *names; 2645 struct passwd *pw; 2646 struct group *gr; 2647 gid_t groups[NGROUPS + 1]; 2648 int ngroups; 2649 2650 cr->cr_version = XUCRED_VERSION; 2651 /* 2652 * Set up the unprivileged user. 2653 */ 2654 cr->cr_uid = -2; 2655 cr->cr_groups[0] = -2; 2656 cr->cr_ngroups = 1; 2657 /* 2658 * Get the user's password table entry. 2659 */ 2660 names = strsep(&namelist, " \t\n"); 2661 name = strsep(&names, ":"); 2662 if (isdigit(*name) || *name == '-') 2663 pw = getpwuid(atoi(name)); 2664 else 2665 pw = getpwnam(name); 2666 /* 2667 * Credentials specified as those of a user. 2668 */ 2669 if (names == NULL) { 2670 if (pw == NULL) { 2671 syslog(LOG_ERR, "unknown user: %s", name); 2672 return; 2673 } 2674 cr->cr_uid = pw->pw_uid; 2675 ngroups = NGROUPS + 1; 2676 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 2677 syslog(LOG_ERR, "too many groups"); 2678 /* 2679 * Compress out duplicate. 2680 */ 2681 cr->cr_ngroups = ngroups - 1; 2682 cr->cr_groups[0] = groups[0]; 2683 for (cnt = 2; cnt < ngroups; cnt++) 2684 cr->cr_groups[cnt - 1] = groups[cnt]; 2685 return; 2686 } 2687 /* 2688 * Explicit credential specified as a colon separated list: 2689 * uid:gid:gid:... 2690 */ 2691 if (pw != NULL) 2692 cr->cr_uid = pw->pw_uid; 2693 else if (isdigit(*name) || *name == '-') 2694 cr->cr_uid = atoi(name); 2695 else { 2696 syslog(LOG_ERR, "unknown user: %s", name); 2697 return; 2698 } 2699 cr->cr_ngroups = 0; 2700 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 2701 name = strsep(&names, ":"); 2702 if (isdigit(*name) || *name == '-') { 2703 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 2704 } else { 2705 if ((gr = getgrnam(name)) == NULL) { 2706 syslog(LOG_ERR, "unknown group: %s", name); 2707 continue; 2708 } 2709 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 2710 } 2711 } 2712 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 2713 syslog(LOG_ERR, "too many groups"); 2714} 2715 2716#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 2717/* 2718 * Routines that maintain the remote mounttab 2719 */ 2720void 2721get_mountlist() 2722{ 2723 struct mountlist *mlp, **mlpp; 2724 char *host, *dirp, *cp; 2725 char str[STRSIZ]; 2726 FILE *mlfile; 2727 2728 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 2729 if (errno == ENOENT) 2730 return; 2731 else { 2732 syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 2733 return; 2734 } 2735 } 2736 mlpp = &mlhead; 2737 while (fgets(str, STRSIZ, mlfile) != NULL) { 2738 cp = str; 2739 host = strsep(&cp, " \t\n"); 2740 dirp = strsep(&cp, " \t\n"); 2741 if (host == NULL || dirp == NULL) 2742 continue; 2743 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2744 if (mlp == (struct mountlist *)NULL) 2745 out_of_mem(); 2746 strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 2747 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2748 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2749 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2750 mlp->ml_next = (struct mountlist *)NULL; 2751 *mlpp = mlp; 2752 mlpp = &mlp->ml_next; 2753 } 2754 fclose(mlfile); 2755} 2756 2757void 2758del_mlist(char *hostp, char *dirp) 2759{ 2760 struct mountlist *mlp, **mlpp; 2761 struct mountlist *mlp2; 2762 FILE *mlfile; 2763 int fnd = 0; 2764 2765 mlpp = &mlhead; 2766 mlp = mlhead; 2767 while (mlp) { 2768 if (!strcmp(mlp->ml_host, hostp) && 2769 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 2770 fnd = 1; 2771 mlp2 = mlp; 2772 *mlpp = mlp = mlp->ml_next; 2773 free((caddr_t)mlp2); 2774 } else { 2775 mlpp = &mlp->ml_next; 2776 mlp = mlp->ml_next; 2777 } 2778 } 2779 if (fnd) { 2780 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 2781 syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 2782 return; 2783 } 2784 mlp = mlhead; 2785 while (mlp) { 2786 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2787 mlp = mlp->ml_next; 2788 } 2789 fclose(mlfile); 2790 } 2791} 2792 2793void 2794add_mlist(hostp, dirp) 2795 char *hostp, *dirp; 2796{ 2797 struct mountlist *mlp, **mlpp; 2798 FILE *mlfile; 2799 2800 mlpp = &mlhead; 2801 mlp = mlhead; 2802 while (mlp) { 2803 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 2804 return; 2805 mlpp = &mlp->ml_next; 2806 mlp = mlp->ml_next; 2807 } 2808 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2809 if (mlp == (struct mountlist *)NULL) 2810 out_of_mem(); 2811 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 2812 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2813 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2814 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2815 mlp->ml_next = (struct mountlist *)NULL; 2816 *mlpp = mlp; 2817 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 2818 syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 2819 return; 2820 } 2821 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2822 fclose(mlfile); 2823} 2824 2825/* 2826 * Free up a group list. 2827 */ 2828void 2829free_grp(grp) 2830 struct grouplist *grp; 2831{ 2832 if (grp->gr_type == GT_HOST) { 2833 if (grp->gr_ptr.gt_addrinfo != NULL) 2834 freeaddrinfo(grp->gr_ptr.gt_addrinfo); 2835 } else if (grp->gr_type == GT_NET) { 2836 if (grp->gr_ptr.gt_net.nt_name) 2837 free(grp->gr_ptr.gt_net.nt_name); 2838 } 2839 free((caddr_t)grp); 2840} 2841 2842#ifdef DEBUG 2843void 2844SYSLOG(int pri, const char *fmt, ...) 2845{ 2846 va_list ap; 2847 2848 va_start(ap, fmt); 2849 vfprintf(stderr, fmt, ap); 2850 va_end(ap); 2851} 2852#endif /* DEBUG */ 2853 2854/* 2855 * Check options for consistency. 2856 */ 2857int 2858check_options(dp) 2859 struct dirlist *dp; 2860{ 2861 2862 if (v4root_phase == 0 && dp == NULL) 2863 return (1); 2864 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 2865 syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 2866 return (1); 2867 } 2868 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 2869 syslog(LOG_ERR, "-mask requires -network"); 2870 return (1); 2871 } 2872 if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 2873 syslog(LOG_ERR, "-network requires mask specification"); 2874 return (1); 2875 } 2876 if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 2877 syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 2878 return (1); 2879 } 2880 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 2881 syslog(LOG_ERR, "-alldirs has multiple directories"); 2882 return (1); 2883 } 2884 if (v4root_phase > 0 && 2885 (opt_flags & 2886 ~(OP_SEC | OP_MASK | OP_NET | OP_HAVEMASK | OP_MASKLEN)) != 0) { 2887 syslog(LOG_ERR,"only -sec,-net,-mask options allowed on V4:"); 2888 return (1); 2889 } 2890 return (0); 2891} 2892 2893/* 2894 * Check an absolute directory path for any symbolic links. Return true 2895 */ 2896int 2897check_dirpath(dirp) 2898 char *dirp; 2899{ 2900 char *cp; 2901 int ret = 1; 2902 struct stat sb; 2903 2904 cp = dirp + 1; 2905 while (*cp && ret) { 2906 if (*cp == '/') { 2907 *cp = '\0'; 2908 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2909 ret = 0; 2910 *cp = '/'; 2911 } 2912 cp++; 2913 } 2914 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2915 ret = 0; 2916 return (ret); 2917} 2918 2919/* 2920 * Make a netmask according to the specified prefix length. The ss_family 2921 * and other non-address fields must be initialised before calling this. 2922 */ 2923int 2924makemask(struct sockaddr_storage *ssp, int bitlen) 2925{ 2926 u_char *p; 2927 int bits, i, len; 2928 2929 if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 2930 return (-1); 2931 if (bitlen > len * CHAR_BIT) 2932 return (-1); 2933 2934 for (i = 0; i < len; i++) { 2935 bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 2936 *p++ = (1 << bits) - 1; 2937 bitlen -= bits; 2938 } 2939 return 0; 2940} 2941 2942/* 2943 * Check that the sockaddr is a valid netmask. Returns 0 if the mask 2944 * is acceptable (i.e. of the form 1...10....0). 2945 */ 2946int 2947checkmask(struct sockaddr *sa) 2948{ 2949 u_char *mask; 2950 int i, len; 2951 2952 if ((mask = sa_rawaddr(sa, &len)) == NULL) 2953 return (-1); 2954 2955 for (i = 0; i < len; i++) 2956 if (mask[i] != 0xff) 2957 break; 2958 if (i < len) { 2959 if (~mask[i] & (u_char)(~mask[i] + 1)) 2960 return (-1); 2961 i++; 2962 } 2963 for (; i < len; i++) 2964 if (mask[i] != 0) 2965 return (-1); 2966 return (0); 2967} 2968 2969/* 2970 * Compare two sockaddrs according to a specified mask. Return zero if 2971 * `sa1' matches `sa2' when filtered by the netmask in `samask'. 2972 * If samask is NULL, perform a full comparision. 2973 */ 2974int 2975sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 2976{ 2977 unsigned char *p1, *p2, *mask; 2978 int len, i; 2979 2980 if (sa1->sa_family != sa2->sa_family || 2981 (p1 = sa_rawaddr(sa1, &len)) == NULL || 2982 (p2 = sa_rawaddr(sa2, NULL)) == NULL) 2983 return (1); 2984 2985 switch (sa1->sa_family) { 2986 case AF_INET6: 2987 if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 2988 ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 2989 return (1); 2990 break; 2991 } 2992 2993 /* Simple binary comparison if no mask specified. */ 2994 if (samask == NULL) 2995 return (memcmp(p1, p2, len)); 2996 2997 /* Set up the mask, and do a mask-based comparison. */ 2998 if (sa1->sa_family != samask->sa_family || 2999 (mask = sa_rawaddr(samask, NULL)) == NULL) 3000 return (1); 3001 3002 for (i = 0; i < len; i++) 3003 if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 3004 return (1); 3005 return (0); 3006} 3007 3008/* 3009 * Return a pointer to the part of the sockaddr that contains the 3010 * raw address, and set *nbytes to its length in bytes. Returns 3011 * NULL if the address family is unknown. 3012 */ 3013void * 3014sa_rawaddr(struct sockaddr *sa, int *nbytes) { 3015 void *p; 3016 int len; 3017 3018 switch (sa->sa_family) { 3019 case AF_INET: 3020 len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 3021 p = &((struct sockaddr_in *)sa)->sin_addr; 3022 break; 3023 case AF_INET6: 3024 len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 3025 p = &((struct sockaddr_in6 *)sa)->sin6_addr; 3026 break; 3027 default: 3028 p = NULL; 3029 len = 0; 3030 } 3031 3032 if (nbytes != NULL) 3033 *nbytes = len; 3034 return (p); 3035} 3036 3037void 3038huphandler(int sig) 3039{ 3040 got_sighup = 1; 3041} 3042 3043void terminate(sig) 3044int sig; 3045{ 3046 pidfile_remove(pfh); 3047 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 3048 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 3049 exit (0); 3050} 3051 3052