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