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