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 if (nmount(iov, iovlen, fsp->f_flags) < 0 && 1436 errno != ENOENT && errno != ENOTSUP) { 1437 syslog(LOG_ERR, 1438 "can't delete exports for %s: %m %s", 1439 fsp->f_mntonname, errmsg); 1440 } 1441 } 1442 1443 if (iov != NULL) { 1444 /* Free strings allocated by strdup() in getmntopts.c */ 1445 free(iov[0].iov_base); /* fstype */ 1446 free(iov[2].iov_base); /* fspath */ 1447 free(iov[4].iov_base); /* from */ 1448 free(iov[6].iov_base); /* update */ 1449 free(iov[8].iov_base); /* export */ 1450 free(iov[10].iov_base); /* errmsg */ 1451 1452 /* free iov, allocated by realloc() */ 1453 free(iov); 1454 iovlen = 0; 1455 } 1456 1457 /* 1458 * Read in the exports file and build the list, calling 1459 * nmount() as we go along to push the export rules into the kernel. 1460 */ 1461 done = 0; 1462 for (i = 0; exnames[i] != NULL; i++) { 1463 if (debug) 1464 warnx("reading exports from %s", exnames[i]); 1465 if ((exp_file = fopen(exnames[i], "r")) == NULL) { 1466 syslog(LOG_WARNING, "can't open %s", exnames[i]); 1467 continue; 1468 } 1469 get_exportlist_one(); 1470 fclose(exp_file); 1471 done++; 1472 } 1473 if (done == 0) { 1474 syslog(LOG_ERR, "can't open any exports file"); 1475 exit(2); 1476 } 1477 } 1478 1479 /* 1480 * Allocate an export list element 1481 */ 1482 struct exportlist * 1483 get_exp() 1484 { 1485 struct exportlist *ep; 1486 1487 ep = (struct exportlist *)malloc(sizeof (struct exportlist)); 1488 if (ep == (struct exportlist *)NULL) 1489 out_of_mem(); 1490 memset(ep, 0, sizeof(struct exportlist)); 1491 return (ep); 1492 } 1493 1494 /* 1495 * Allocate a group list element 1496 */ 1497 struct grouplist * 1498 get_grp() 1499 { 1500 struct grouplist *gp; 1501 1502 gp = (struct grouplist *)malloc(sizeof (struct grouplist)); 1503 if (gp == (struct grouplist *)NULL) 1504 out_of_mem(); 1505 memset(gp, 0, sizeof(struct grouplist)); 1506 return (gp); 1507 } 1508 1509 /* 1510 * Clean up upon an error in get_exportlist(). 1511 */ 1512 void 1513 getexp_err(ep, grp) 1514 struct exportlist *ep; 1515 struct grouplist *grp; 1516 { 1517 struct grouplist *tgrp; 1518 1519 if (!(opt_flags & OP_QUIET)) 1520 syslog(LOG_ERR, "bad exports list line %s", line); 1521 if (ep && (ep->ex_flag & EX_LINKED) == 0) 1522 free_exp(ep); 1523 while (grp) { 1524 tgrp = grp; 1525 grp = grp->gr_next; 1526 free_grp(tgrp); 1527 } 1528 } 1529 1530 /* 1531 * Search the export list for a matching fs. 1532 */ 1533 struct exportlist * 1534 ex_search(fsid) 1535 fsid_t *fsid; 1536 { 1537 struct exportlist *ep; 1538 1539 ep = exphead; 1540 while (ep) { 1541 if (ep->ex_fs.val[0] == fsid->val[0] && 1542 ep->ex_fs.val[1] == fsid->val[1]) 1543 return (ep); 1544 ep = ep->ex_next; 1545 } 1546 return (ep); 1547 } 1548 1549 /* 1550 * Add a directory path to the list. 1551 */ 1552 char * 1553 add_expdir(dpp, cp, len) 1554 struct dirlist **dpp; 1555 char *cp; 1556 int len; 1557 { 1558 struct dirlist *dp; 1559 1560 dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len); 1561 if (dp == (struct dirlist *)NULL) 1562 out_of_mem(); 1563 dp->dp_left = *dpp; 1564 dp->dp_right = (struct dirlist *)NULL; 1565 dp->dp_flag = 0; 1566 dp->dp_hosts = (struct hostlist *)NULL; 1567 strcpy(dp->dp_dirp, cp); 1568 *dpp = dp; 1569 return (dp->dp_dirp); 1570 } 1571 1572 /* 1573 * Hang the dir list element off the dirpath binary tree as required 1574 * and update the entry for host. 1575 */ 1576 void 1577 hang_dirp(dp, grp, ep, flags) 1578 struct dirlist *dp; 1579 struct grouplist *grp; 1580 struct exportlist *ep; 1581 int flags; 1582 { 1583 struct hostlist *hp; 1584 struct dirlist *dp2; 1585 1586 if (flags & OP_ALLDIRS) { 1587 if (ep->ex_defdir) 1588 free((caddr_t)dp); 1589 else 1590 ep->ex_defdir = dp; 1591 if (grp == (struct grouplist *)NULL) { 1592 ep->ex_defdir->dp_flag |= DP_DEFSET; 1593 } else while (grp) { 1594 hp = get_ht(); 1595 hp->ht_grp = grp; 1596 hp->ht_next = ep->ex_defdir->dp_hosts; 1597 ep->ex_defdir->dp_hosts = hp; 1598 grp = grp->gr_next; 1599 } 1600 } else { 1601 1602 /* 1603 * Loop through the directories adding them to the tree. 1604 */ 1605 while (dp) { 1606 dp2 = dp->dp_left; 1607 add_dlist(&ep->ex_dirl, dp, grp, flags); 1608 dp = dp2; 1609 } 1610 } 1611 } 1612 1613 /* 1614 * Traverse the binary tree either updating a node that is already there 1615 * for the new directory or adding the new node. 1616 */ 1617 void 1618 add_dlist(dpp, newdp, grp, flags) 1619 struct dirlist **dpp; 1620 struct dirlist *newdp; 1621 struct grouplist *grp; 1622 int flags; 1623 { 1624 struct dirlist *dp; 1625 struct hostlist *hp; 1626 int cmp; 1627 1628 dp = *dpp; 1629 if (dp) { 1630 cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); 1631 if (cmp > 0) { 1632 add_dlist(&dp->dp_left, newdp, grp, flags); 1633 return; 1634 } else if (cmp < 0) { 1635 add_dlist(&dp->dp_right, newdp, grp, flags); 1636 return; 1637 } else 1638 free((caddr_t)newdp); 1639 } else { 1640 dp = newdp; 1641 dp->dp_left = (struct dirlist *)NULL; 1642 *dpp = dp; 1643 } 1644 if (grp) { 1645 1646 /* 1647 * Hang all of the host(s) off of the directory point. 1648 */ 1649 do { 1650 hp = get_ht(); 1651 hp->ht_grp = grp; 1652 hp->ht_next = dp->dp_hosts; 1653 dp->dp_hosts = hp; 1654 grp = grp->gr_next; 1655 } while (grp); 1656 } else { 1657 dp->dp_flag |= DP_DEFSET; 1658 } 1659 } 1660 1661 /* 1662 * Search for a dirpath on the export point. 1663 */ 1664 struct dirlist * 1665 dirp_search(dp, dirp) 1666 struct dirlist *dp; 1667 char *dirp; 1668 { 1669 int cmp; 1670 1671 if (dp) { 1672 cmp = strcmp(dp->dp_dirp, dirp); 1673 if (cmp > 0) 1674 return (dirp_search(dp->dp_left, dirp)); 1675 else if (cmp < 0) 1676 return (dirp_search(dp->dp_right, dirp)); 1677 else 1678 return (dp); 1679 } 1680 return (dp); 1681 } 1682 1683 /* 1684 * Scan for a host match in a directory tree. 1685 */ 1686 int 1687 chk_host(dp, saddr, defsetp, hostsetp) 1688 struct dirlist *dp; 1689 struct sockaddr *saddr; 1690 int *defsetp; 1691 int *hostsetp; 1692 { 1693 struct hostlist *hp; 1694 struct grouplist *grp; 1695 struct addrinfo *ai; 1696 1697 if (dp) { 1698 if (dp->dp_flag & DP_DEFSET) 1699 *defsetp = dp->dp_flag; 1700 hp = dp->dp_hosts; 1701 while (hp) { 1702 grp = hp->ht_grp; 1703 switch (grp->gr_type) { 1704 case GT_HOST: 1705 ai = grp->gr_ptr.gt_addrinfo; 1706 for (; ai; ai = ai->ai_next) { 1707 if (!sacmp(ai->ai_addr, saddr, NULL)) { 1708 *hostsetp = 1709 (hp->ht_flag | DP_HOSTSET); 1710 return (1); 1711 } 1712 } 1713 break; 1714 case GT_NET: 1715 if (!sacmp(saddr, (struct sockaddr *) 1716 &grp->gr_ptr.gt_net.nt_net, 1717 (struct sockaddr *) 1718 &grp->gr_ptr.gt_net.nt_mask)) { 1719 *hostsetp = (hp->ht_flag | DP_HOSTSET); 1720 return (1); 1721 } 1722 break; 1723 } 1724 hp = hp->ht_next; 1725 } 1726 } 1727 return (0); 1728 } 1729 1730 /* 1731 * Scan tree for a host that matches the address. 1732 */ 1733 int 1734 scan_tree(dp, saddr) 1735 struct dirlist *dp; 1736 struct sockaddr *saddr; 1737 { 1738 int defset, hostset; 1739 1740 if (dp) { 1741 if (scan_tree(dp->dp_left, saddr)) 1742 return (1); 1743 if (chk_host(dp, saddr, &defset, &hostset)) 1744 return (1); 1745 if (scan_tree(dp->dp_right, saddr)) 1746 return (1); 1747 } 1748 return (0); 1749 } 1750 1751 /* 1752 * Traverse the dirlist tree and free it up. 1753 */ 1754 void 1755 free_dir(dp) 1756 struct dirlist *dp; 1757 { 1758 1759 if (dp) { 1760 free_dir(dp->dp_left); 1761 free_dir(dp->dp_right); 1762 free_host(dp->dp_hosts); 1763 free((caddr_t)dp); 1764 } 1765 } 1766 1767 /* 1768 * Parse the option string and update fields. 1769 * Option arguments may either be -<option>=<value> or 1770 * -<option> <value> 1771 */ 1772 int 1773 do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr) 1774 char **cpp, **endcpp; 1775 struct exportlist *ep; 1776 struct grouplist *grp; 1777 int *has_hostp; 1778 int *exflagsp; 1779 struct xucred *cr; 1780 { 1781 char *cpoptarg, *cpoptend; 1782 char *cp, *endcp, *cpopt, savedc, savedc2; 1783 int allflag, usedarg; 1784 1785 savedc2 = '\0'; 1786 cpopt = *cpp; 1787 cpopt++; 1788 cp = *endcpp; 1789 savedc = *cp; 1790 *cp = '\0'; 1791 while (cpopt && *cpopt) { 1792 allflag = 1; 1793 usedarg = -2; 1794 if ((cpoptend = strchr(cpopt, ','))) { 1795 *cpoptend++ = '\0'; 1796 if ((cpoptarg = strchr(cpopt, '='))) 1797 *cpoptarg++ = '\0'; 1798 } else { 1799 if ((cpoptarg = strchr(cpopt, '='))) 1800 *cpoptarg++ = '\0'; 1801 else { 1802 *cp = savedc; 1803 nextfield(&cp, &endcp); 1804 **endcpp = '\0'; 1805 if (endcp > cp && *cp != '-') { 1806 cpoptarg = cp; 1807 savedc2 = *endcp; 1808 *endcp = '\0'; 1809 usedarg = 0; 1810 } 1811 } 1812 } 1813 if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) { 1814 *exflagsp |= MNT_EXRDONLY; 1815 } else if (cpoptarg && (!strcmp(cpopt, "maproot") || 1816 !(allflag = strcmp(cpopt, "mapall")) || 1817 !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) { 1818 usedarg++; 1819 parsecred(cpoptarg, cr); 1820 if (allflag == 0) { 1821 *exflagsp |= MNT_EXPORTANON; 1822 opt_flags |= OP_MAPALL; 1823 } else 1824 opt_flags |= OP_MAPROOT; 1825 } else if (cpoptarg && (!strcmp(cpopt, "mask") || 1826 !strcmp(cpopt, "m"))) { 1827 if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) { 1828 syslog(LOG_ERR, "bad mask: %s", cpoptarg); 1829 return (1); 1830 } 1831 usedarg++; 1832 opt_flags |= OP_MASK; 1833 } else if (cpoptarg && (!strcmp(cpopt, "network") || 1834 !strcmp(cpopt, "n"))) { 1835 if (strchr(cpoptarg, '/') != NULL) { 1836 if (debug) 1837 fprintf(stderr, "setting OP_MASKLEN\n"); 1838 opt_flags |= OP_MASKLEN; 1839 } 1840 if (grp->gr_type != GT_NULL) { 1841 syslog(LOG_ERR, "network/host conflict"); 1842 return (1); 1843 } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) { 1844 syslog(LOG_ERR, "bad net: %s", cpoptarg); 1845 return (1); 1846 } 1847 grp->gr_type = GT_NET; 1848 *has_hostp = 1; 1849 usedarg++; 1850 opt_flags |= OP_NET; 1851 } else if (!strcmp(cpopt, "alldirs")) { 1852 opt_flags |= OP_ALLDIRS; 1853 } else if (!strcmp(cpopt, "public")) { 1854 *exflagsp |= MNT_EXPUBLIC; 1855 } else if (!strcmp(cpopt, "webnfs")) { 1856 *exflagsp |= (MNT_EXPUBLIC|MNT_EXRDONLY|MNT_EXPORTANON); 1857 opt_flags |= OP_MAPALL; 1858 } else if (cpoptarg && !strcmp(cpopt, "index")) { 1859 ep->ex_indexfile = strdup(cpoptarg); 1860 } else if (!strcmp(cpopt, "quiet")) { 1861 opt_flags |= OP_QUIET; 1862 } else { 1863 syslog(LOG_ERR, "bad opt %s", cpopt); 1864 return (1); 1865 } 1866 if (usedarg >= 0) { 1867 *endcp = savedc2; 1868 **endcpp = savedc; 1869 if (usedarg > 0) { 1870 *cpp = cp; 1871 *endcpp = endcp; 1872 } 1873 return (0); 1874 } 1875 cpopt = cpoptend; 1876 } 1877 **endcpp = savedc; 1878 return (0); 1879 } 1880 1881 /* 1882 * Translate a character string to the corresponding list of network 1883 * addresses for a hostname. 1884 */ 1885 int 1886 get_host(cp, grp, tgrp) 1887 char *cp; 1888 struct grouplist *grp; 1889 struct grouplist *tgrp; 1890 { 1891 struct grouplist *checkgrp; 1892 struct addrinfo *ai, *tai, hints; 1893 int ecode; 1894 char host[NI_MAXHOST]; 1895 1896 if (grp->gr_type != GT_NULL) { 1897 syslog(LOG_ERR, "Bad netgroup type for ip host %s", cp); 1898 return (1); 1899 } 1900 memset(&hints, 0, sizeof hints); 1901 hints.ai_flags = AI_CANONNAME; 1902 hints.ai_protocol = IPPROTO_UDP; 1903 ecode = getaddrinfo(cp, NULL, &hints, &ai); 1904 if (ecode != 0) { 1905 syslog(LOG_ERR,"can't get address info for host %s", cp); 1906 return 1; 1907 } 1908 grp->gr_ptr.gt_addrinfo = ai; 1909 while (ai != NULL) { 1910 if (ai->ai_canonname == NULL) { 1911 if (getnameinfo(ai->ai_addr, ai->ai_addrlen, host, 1912 sizeof host, NULL, 0, NI_NUMERICHOST) != 0) 1913 strlcpy(host, "?", sizeof(host)); 1914 ai->ai_canonname = strdup(host); 1915 ai->ai_flags |= AI_CANONNAME; 1916 } 1917 if (debug) 1918 fprintf(stderr, "got host %s\n", ai->ai_canonname); 1919 /* 1920 * Sanity check: make sure we don't already have an entry 1921 * for this host in the grouplist. 1922 */ 1923 for (checkgrp = tgrp; checkgrp != NULL; 1924 checkgrp = checkgrp->gr_next) { 1925 if (checkgrp->gr_type != GT_HOST) 1926 continue; 1927 for (tai = checkgrp->gr_ptr.gt_addrinfo; tai != NULL; 1928 tai = tai->ai_next) { 1929 if (sacmp(tai->ai_addr, ai->ai_addr, NULL) != 0) 1930 continue; 1931 if (debug) 1932 fprintf(stderr, 1933 "ignoring duplicate host %s\n", 1934 ai->ai_canonname); 1935 grp->gr_type = GT_IGNORE; 1936 return (0); 1937 } 1938 } 1939 ai = ai->ai_next; 1940 } 1941 grp->gr_type = GT_HOST; 1942 return (0); 1943 } 1944 1945 /* 1946 * Free up an exports list component 1947 */ 1948 void 1949 free_exp(ep) 1950 struct exportlist *ep; 1951 { 1952 1953 if (ep->ex_defdir) { 1954 free_host(ep->ex_defdir->dp_hosts); 1955 free((caddr_t)ep->ex_defdir); 1956 } 1957 if (ep->ex_fsdir) 1958 free(ep->ex_fsdir); 1959 if (ep->ex_indexfile) 1960 free(ep->ex_indexfile); 1961 free_dir(ep->ex_dirl); 1962 free((caddr_t)ep); 1963 } 1964 1965 /* 1966 * Free hosts. 1967 */ 1968 void 1969 free_host(hp) 1970 struct hostlist *hp; 1971 { 1972 struct hostlist *hp2; 1973 1974 while (hp) { 1975 hp2 = hp; 1976 hp = hp->ht_next; 1977 free((caddr_t)hp2); 1978 } 1979 } 1980 1981 struct hostlist * 1982 get_ht() 1983 { 1984 struct hostlist *hp; 1985 1986 hp = (struct hostlist *)malloc(sizeof (struct hostlist)); 1987 if (hp == (struct hostlist *)NULL) 1988 out_of_mem(); 1989 hp->ht_next = (struct hostlist *)NULL; 1990 hp->ht_flag = 0; 1991 return (hp); 1992 } 1993 1994 /* 1995 * Out of memory, fatal 1996 */ 1997 void 1998 out_of_mem() 1999 { 2000 2001 syslog(LOG_ERR, "out of memory"); 2002 exit(2); 2003 } 2004 2005 /* 2006 * Do the nmount() syscall with the update flag to push the export info into 2007 * the kernel. 2008 */ 2009 int 2010 do_mount(struct exportlist *ep, struct grouplist *grp, int exflags, 2011 struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) 2012 { 2013 struct statfs fsb1; 2014 struct addrinfo *ai; 2015 struct export_args eap; 2016 char errmsg[255]; 2017 char *cp; 2018 int done; 2019 char savedc; 2020 struct iovec *iov; 2021 int iovlen; 2022 int ret; 2023 2024 cp = NULL; 2025 savedc = '\0'; 2026 iov = NULL; 2027 iovlen = 0; 2028 ret = 0; 2029 2030 bzero(&eap, sizeof(eap)); 2031 bzero(errmsg, sizeof(errmsg)); 2032 eap.ex_flags = exflags; 2033 eap.ex_anon = *anoncrp; 2034 eap.ex_indexfile = ep->ex_indexfile; 2035 if (grp->gr_type == GT_HOST) 2036 ai = grp->gr_ptr.gt_addrinfo; 2037 else 2038 ai = NULL; 2039 done = FALSE; 2040 2041 build_iovec(&iov, &iovlen, "fstype", NULL, 0); 2042 build_iovec(&iov, &iovlen, "fspath", NULL, 0); 2043 build_iovec(&iov, &iovlen, "from", NULL, 0); 2044 build_iovec(&iov, &iovlen, "update", NULL, 0); 2045 build_iovec(&iov, &iovlen, "export", &eap, sizeof(eap)); 2046 build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); 2047 2048 while (!done) { 2049 switch (grp->gr_type) { 2050 case GT_HOST: 2051 if (ai->ai_addr->sa_family == AF_INET6 && have_v6 == 0) 2052 goto skip; 2053 eap.ex_addr = ai->ai_addr; 2054 eap.ex_addrlen = ai->ai_addrlen; 2055 eap.ex_masklen = 0; 2056 break; 2057 case GT_NET: 2058 if (grp->gr_ptr.gt_net.nt_net.ss_family == AF_INET6 && 2059 have_v6 == 0) 2060 goto skip; 2061 eap.ex_addr = 2062 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_net; 2063 eap.ex_addrlen = 2064 ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_net)->sa_len; 2065 eap.ex_mask = 2066 (struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask; 2067 eap.ex_masklen = ((struct sockaddr *)&grp->gr_ptr.gt_net.nt_mask)->sa_len; 2068 break; 2069 case GT_DEFAULT: 2070 eap.ex_addr = NULL; 2071 eap.ex_addrlen = 0; 2072 eap.ex_mask = NULL; 2073 eap.ex_masklen = 0; 2074 break; 2075 case GT_IGNORE: 2076 ret = 0; 2077 goto error_exit; 2078 break; 2079 default: 2080 syslog(LOG_ERR, "bad grouptype"); 2081 if (cp) 2082 *cp = savedc; 2083 ret = 1; 2084 goto error_exit; 2085 }; 2086 2087 /* 2088 * XXX: 2089 * Maybe I should just use the fsb->f_mntonname path instead 2090 * of looping back up the dirp to the mount point?? 2091 * Also, needs to know how to export all types of local 2092 * exportable filesystems and not just "ufs". 2093 */ 2094 iov[1].iov_base = fsb->f_fstypename; /* "fstype" */ 2095 iov[1].iov_len = strlen(fsb->f_fstypename) + 1; 2096 iov[3].iov_base = fsb->f_mntonname; /* "fspath" */ 2097 iov[3].iov_len = strlen(fsb->f_mntonname) + 1; 2098 iov[5].iov_base = fsb->f_mntfromname; /* "from" */ 2099 iov[5].iov_len = strlen(fsb->f_mntfromname) + 1; 2100 2101 while (nmount(iov, iovlen, fsb->f_flags) < 0) { 2102 if (cp) 2103 *cp-- = savedc; 2104 else 2105 cp = dirp + dirplen - 1; 2106 if (opt_flags & OP_QUIET) { 2107 ret = 1; 2108 goto error_exit; 2109 } 2110 if (errno == EPERM) { 2111 if (debug) 2112 warnx("can't change attributes for %s", 2113 dirp); 2114 syslog(LOG_ERR, 2115 "can't change attributes for %s", dirp); 2116 ret = 1; 2117 goto error_exit; 2118 } 2119 if (opt_flags & OP_ALLDIRS) { 2120 if (errno == EINVAL) 2121 syslog(LOG_ERR, 2122 "-alldirs requested but %s is not a filesystem mountpoint", 2123 dirp); 2124 else 2125 syslog(LOG_ERR, 2126 "could not remount %s: %m", 2127 dirp); 2128 ret = 1; 2129 goto error_exit; 2130 } 2131 /* back up over the last component */ 2132 while (*cp == '/' && cp > dirp) 2133 cp--; 2134 while (*(cp - 1) != '/' && cp > dirp) 2135 cp--; 2136 if (cp == dirp) { 2137 if (debug) 2138 warnx("mnt unsucc"); 2139 syslog(LOG_ERR, "can't export %s %s", dirp, 2140 errmsg); 2141 ret = 1; 2142 goto error_exit; 2143 } 2144 savedc = *cp; 2145 *cp = '\0'; 2146 /* Check that we're still on the same filesystem. */ 2147 if (statfs(dirp, &fsb1) != 0 || bcmp(&fsb1.f_fsid, 2148 &fsb->f_fsid, sizeof(fsb1.f_fsid)) != 0) { 2149 *cp = savedc; 2150 syslog(LOG_ERR, "can't export %s %s", dirp, 2151 errmsg); 2152 ret = 1; 2153 goto error_exit; 2154 } 2155 } 2156 skip: 2157 if (ai != NULL) 2158 ai = ai->ai_next; 2159 if (ai == NULL) 2160 done = TRUE; 2161 } 2162 if (cp) 2163 *cp = savedc; 2164 error_exit: 2165 /* free strings allocated by strdup() in getmntopts.c */ 2166 if (iov != NULL) { 2167 free(iov[0].iov_base); /* fstype */ 2168 free(iov[2].iov_base); /* fspath */ 2169 free(iov[4].iov_base); /* from */ 2170 free(iov[6].iov_base); /* update */ 2171 free(iov[8].iov_base); /* export */ 2172 free(iov[10].iov_base); /* errmsg */ 2173 2174 /* free iov, allocated by realloc() */ 2175 free(iov); 2176 } 2177 return (ret); 2178 } 2179 2180 /* 2181 * Translate a net address. 2182 * 2183 * If `maskflg' is nonzero, then `cp' is a netmask, not a network address. 2184 */ 2185 int 2186 get_net(cp, net, maskflg) 2187 char *cp; 2188 struct netmsk *net; 2189 int maskflg; 2190 { 2191 struct netent *np = NULL; 2192 char *name, *p, *prefp; 2193 struct sockaddr_in sin; 2194 struct sockaddr *sa = NULL; 2195 struct addrinfo hints, *ai = NULL; 2196 char netname[NI_MAXHOST]; 2197 long preflen; 2198 2199 p = prefp = NULL; 2200 if ((opt_flags & OP_MASKLEN) && !maskflg) { 2201 p = strchr(cp, '/'); 2202 *p = '\0'; 2203 prefp = p + 1; 2204 } 2205 2206 /* 2207 * Check for a numeric address first. We wish to avoid 2208 * possible DNS lookups in getnetbyname(). 2209 */ 2210 if (isxdigit(*cp) || *cp == ':') { 2211 memset(&hints, 0, sizeof hints); 2212 /* Ensure the mask and the network have the same family. */ 2213 if (maskflg && (opt_flags & OP_NET)) 2214 hints.ai_family = net->nt_net.ss_family; 2215 else if (!maskflg && (opt_flags & OP_HAVEMASK)) 2216 hints.ai_family = net->nt_mask.ss_family; 2217 else 2218 hints.ai_family = AF_UNSPEC; 2219 hints.ai_flags = AI_NUMERICHOST; 2220 if (getaddrinfo(cp, NULL, &hints, &ai) == 0) 2221 sa = ai->ai_addr; 2222 if (sa != NULL && ai->ai_family == AF_INET) { 2223 /* 2224 * The address in `cp' is really a network address, so 2225 * use inet_network() to re-interpret this correctly. 2226 * e.g. "127.1" means 127.1.0.0, not 127.0.0.1. 2227 */ 2228 bzero(&sin, sizeof sin); 2229 sin.sin_family = AF_INET; 2230 sin.sin_len = sizeof sin; 2231 sin.sin_addr = inet_makeaddr(inet_network(cp), 0); 2232 if (debug) 2233 fprintf(stderr, "get_net: v4 addr %s\n", 2234 inet_ntoa(sin.sin_addr)); 2235 sa = (struct sockaddr *)&sin; 2236 } 2237 } 2238 if (sa == NULL && (np = getnetbyname(cp)) != NULL) { 2239 bzero(&sin, sizeof sin); 2240 sin.sin_family = AF_INET; 2241 sin.sin_len = sizeof sin; 2242 sin.sin_addr = inet_makeaddr(np->n_net, 0); 2243 sa = (struct sockaddr *)&sin; 2244 } 2245 if (sa == NULL) 2246 goto fail; 2247 2248 if (maskflg) { 2249 /* The specified sockaddr is a mask. */ 2250 if (checkmask(sa) != 0) 2251 goto fail; 2252 bcopy(sa, &net->nt_mask, sa->sa_len); 2253 opt_flags |= OP_HAVEMASK; 2254 } else { 2255 /* The specified sockaddr is a network address. */ 2256 bcopy(sa, &net->nt_net, sa->sa_len); 2257 2258 /* Get a network name for the export list. */ 2259 if (np) { 2260 name = np->n_name; 2261 } else if (getnameinfo(sa, sa->sa_len, netname, sizeof netname, 2262 NULL, 0, NI_NUMERICHOST) == 0) { 2263 name = netname; 2264 } else { 2265 goto fail; 2266 } 2267 if ((net->nt_name = strdup(name)) == NULL) 2268 out_of_mem(); 2269 2270 /* 2271 * Extract a mask from either a "/<masklen>" suffix, or 2272 * from the class of an IPv4 address. 2273 */ 2274 if (opt_flags & OP_MASKLEN) { 2275 preflen = strtol(prefp, NULL, 10); 2276 if (preflen < 0L || preflen == LONG_MAX) 2277 goto fail; 2278 bcopy(sa, &net->nt_mask, sa->sa_len); 2279 if (makemask(&net->nt_mask, (int)preflen) != 0) 2280 goto fail; 2281 opt_flags |= OP_HAVEMASK; 2282 *p = '/'; 2283 } else if (sa->sa_family == AF_INET && 2284 (opt_flags & OP_MASK) == 0) { 2285 in_addr_t addr; 2286 2287 addr = ((struct sockaddr_in *)sa)->sin_addr.s_addr; 2288 if (IN_CLASSA(addr)) 2289 preflen = 8; 2290 else if (IN_CLASSB(addr)) 2291 preflen = 16; 2292 else if (IN_CLASSC(addr)) 2293 preflen = 24; 2294 else if (IN_CLASSD(addr)) 2295 preflen = 28; 2296 else 2297 preflen = 32; /* XXX */ 2298 2299 bcopy(sa, &net->nt_mask, sa->sa_len); 2300 makemask(&net->nt_mask, (int)preflen); 2301 opt_flags |= OP_HAVEMASK; 2302 } 2303 } 2304 2305 if (ai) 2306 freeaddrinfo(ai); 2307 return 0; 2308 2309 fail: 2310 if (ai) 2311 freeaddrinfo(ai); 2312 return 1; 2313 } 2314 2315 /* 2316 * Parse out the next white space separated field 2317 */ 2318 void 2319 nextfield(cp, endcp) 2320 char **cp; 2321 char **endcp; 2322 { 2323 char *p; 2324 2325 p = *cp; 2326 while (*p == ' ' || *p == '\t') 2327 p++; 2328 if (*p == '\n' || *p == '\0') 2329 *cp = *endcp = p; 2330 else { 2331 *cp = p++; 2332 while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') 2333 p++; 2334 *endcp = p; 2335 } 2336 } 2337 2338 /* 2339 * Get an exports file line. Skip over blank lines and handle line 2340 * continuations. 2341 */ 2342 int 2343 get_line() 2344 { 2345 char *p, *cp; 2346 size_t len; 2347 int totlen, cont_line; 2348 2349 /* 2350 * Loop around ignoring blank lines and getting all continuation lines. 2351 */ 2352 p = line; 2353 totlen = 0; 2354 do { 2355 if ((p = fgetln(exp_file, &len)) == NULL) 2356 return (0); 2357 cp = p + len - 1; 2358 cont_line = 0; 2359 while (cp >= p && 2360 (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) { 2361 if (*cp == '\\') 2362 cont_line = 1; 2363 cp--; 2364 len--; 2365 } 2366 if (cont_line) { 2367 *++cp = ' '; 2368 len++; 2369 } 2370 if (linesize < len + totlen + 1) { 2371 linesize = len + totlen + 1; 2372 line = realloc(line, linesize); 2373 if (line == NULL) 2374 out_of_mem(); 2375 } 2376 memcpy(line + totlen, p, len); 2377 totlen += len; 2378 line[totlen] = '\0'; 2379 } while (totlen == 0 || cont_line); 2380 return (1); 2381 } 2382 2383 /* 2384 * Parse a description of a credential. 2385 */ 2386 void 2387 parsecred(namelist, cr) 2388 char *namelist; 2389 struct xucred *cr; 2390 { 2391 char *name; 2392 int cnt; 2393 char *names; 2394 struct passwd *pw; 2395 struct group *gr; 2396 gid_t groups[NGROUPS + 1]; 2397 int ngroups; 2398 2399 cr->cr_version = XUCRED_VERSION; 2400 /* 2401 * Set up the unprivileged user. 2402 */ 2403 cr->cr_uid = -2; 2404 cr->cr_groups[0] = -2; 2405 cr->cr_ngroups = 1; 2406 /* 2407 * Get the user's password table entry. 2408 */ 2409 names = strsep(&namelist, " \t\n"); 2410 name = strsep(&names, ":"); 2411 if (isdigit(*name) || *name == '-') 2412 pw = getpwuid(atoi(name)); 2413 else 2414 pw = getpwnam(name); 2415 /* 2416 * Credentials specified as those of a user. 2417 */ 2418 if (names == NULL) { 2419 if (pw == NULL) { 2420 syslog(LOG_ERR, "unknown user: %s", name); 2421 return; 2422 } 2423 cr->cr_uid = pw->pw_uid; 2424 ngroups = NGROUPS + 1; 2425 if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups)) 2426 syslog(LOG_ERR, "too many groups"); 2427 /* 2428 * Compress out duplicate. 2429 */ 2430 cr->cr_ngroups = ngroups - 1; 2431 cr->cr_groups[0] = groups[0]; 2432 for (cnt = 2; cnt < ngroups; cnt++) 2433 cr->cr_groups[cnt - 1] = groups[cnt]; 2434 return; 2435 } 2436 /* 2437 * Explicit credential specified as a colon separated list: 2438 * uid:gid:gid:... 2439 */ 2440 if (pw != NULL) 2441 cr->cr_uid = pw->pw_uid; 2442 else if (isdigit(*name) || *name == '-') 2443 cr->cr_uid = atoi(name); 2444 else { 2445 syslog(LOG_ERR, "unknown user: %s", name); 2446 return; 2447 } 2448 cr->cr_ngroups = 0; 2449 while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) { 2450 name = strsep(&names, ":"); 2451 if (isdigit(*name) || *name == '-') { 2452 cr->cr_groups[cr->cr_ngroups++] = atoi(name); 2453 } else { 2454 if ((gr = getgrnam(name)) == NULL) { 2455 syslog(LOG_ERR, "unknown group: %s", name); 2456 continue; 2457 } 2458 cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid; 2459 } 2460 } 2461 if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS) 2462 syslog(LOG_ERR, "too many groups"); 2463 } 2464 2465 #define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50) 2466 /* 2467 * Routines that maintain the remote mounttab 2468 */ 2469 void 2470 get_mountlist() 2471 { 2472 struct mountlist *mlp, **mlpp; 2473 char *host, *dirp, *cp; 2474 char str[STRSIZ]; 2475 FILE *mlfile; 2476 2477 if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) { 2478 if (errno == ENOENT) 2479 return; 2480 else { 2481 syslog(LOG_ERR, "can't open %s", _PATH_RMOUNTLIST); 2482 return; 2483 } 2484 } 2485 mlpp = &mlhead; 2486 while (fgets(str, STRSIZ, mlfile) != NULL) { 2487 cp = str; 2488 host = strsep(&cp, " \t\n"); 2489 dirp = strsep(&cp, " \t\n"); 2490 if (host == NULL || dirp == NULL) 2491 continue; 2492 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2493 if (mlp == (struct mountlist *)NULL) 2494 out_of_mem(); 2495 strncpy(mlp->ml_host, host, RPCMNT_NAMELEN); 2496 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2497 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2498 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2499 mlp->ml_next = (struct mountlist *)NULL; 2500 *mlpp = mlp; 2501 mlpp = &mlp->ml_next; 2502 } 2503 fclose(mlfile); 2504 } 2505 2506 void 2507 del_mlist(char *hostp, char *dirp) 2508 { 2509 struct mountlist *mlp, **mlpp; 2510 struct mountlist *mlp2; 2511 FILE *mlfile; 2512 int fnd = 0; 2513 2514 mlpp = &mlhead; 2515 mlp = mlhead; 2516 while (mlp) { 2517 if (!strcmp(mlp->ml_host, hostp) && 2518 (!dirp || !strcmp(mlp->ml_dirp, dirp))) { 2519 fnd = 1; 2520 mlp2 = mlp; 2521 *mlpp = mlp = mlp->ml_next; 2522 free((caddr_t)mlp2); 2523 } else { 2524 mlpp = &mlp->ml_next; 2525 mlp = mlp->ml_next; 2526 } 2527 } 2528 if (fnd) { 2529 if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) { 2530 syslog(LOG_ERR,"can't update %s", _PATH_RMOUNTLIST); 2531 return; 2532 } 2533 mlp = mlhead; 2534 while (mlp) { 2535 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2536 mlp = mlp->ml_next; 2537 } 2538 fclose(mlfile); 2539 } 2540 } 2541 2542 void 2543 add_mlist(hostp, dirp) 2544 char *hostp, *dirp; 2545 { 2546 struct mountlist *mlp, **mlpp; 2547 FILE *mlfile; 2548 2549 mlpp = &mlhead; 2550 mlp = mlhead; 2551 while (mlp) { 2552 if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp)) 2553 return; 2554 mlpp = &mlp->ml_next; 2555 mlp = mlp->ml_next; 2556 } 2557 mlp = (struct mountlist *)malloc(sizeof (*mlp)); 2558 if (mlp == (struct mountlist *)NULL) 2559 out_of_mem(); 2560 strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN); 2561 mlp->ml_host[RPCMNT_NAMELEN] = '\0'; 2562 strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN); 2563 mlp->ml_dirp[RPCMNT_PATHLEN] = '\0'; 2564 mlp->ml_next = (struct mountlist *)NULL; 2565 *mlpp = mlp; 2566 if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) { 2567 syslog(LOG_ERR, "can't update %s", _PATH_RMOUNTLIST); 2568 return; 2569 } 2570 fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp); 2571 fclose(mlfile); 2572 } 2573 2574 /* 2575 * Free up a group list. 2576 */ 2577 void 2578 free_grp(grp) 2579 struct grouplist *grp; 2580 { 2581 if (grp->gr_type == GT_HOST) { 2582 if (grp->gr_ptr.gt_addrinfo != NULL) 2583 freeaddrinfo(grp->gr_ptr.gt_addrinfo); 2584 } else if (grp->gr_type == GT_NET) { 2585 if (grp->gr_ptr.gt_net.nt_name) 2586 free(grp->gr_ptr.gt_net.nt_name); 2587 } 2588 free((caddr_t)grp); 2589 } 2590 2591 #ifdef DEBUG 2592 void 2593 SYSLOG(int pri, const char *fmt, ...) 2594 { 2595 va_list ap; 2596 2597 va_start(ap, fmt); 2598 vfprintf(stderr, fmt, ap); 2599 va_end(ap); 2600 } 2601 #endif /* DEBUG */ 2602 2603 /* 2604 * Check options for consistency. 2605 */ 2606 int 2607 check_options(dp) 2608 struct dirlist *dp; 2609 { 2610 2611 if (dp == (struct dirlist *)NULL) 2612 return (1); 2613 if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL)) { 2614 syslog(LOG_ERR, "-mapall and -maproot mutually exclusive"); 2615 return (1); 2616 } 2617 if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) { 2618 syslog(LOG_ERR, "-mask requires -network"); 2619 return (1); 2620 } 2621 if ((opt_flags & OP_NET) && (opt_flags & OP_HAVEMASK) == 0) { 2622 syslog(LOG_ERR, "-network requires mask specification"); 2623 return (1); 2624 } 2625 if ((opt_flags & OP_MASK) && (opt_flags & OP_MASKLEN)) { 2626 syslog(LOG_ERR, "-mask and /masklen are mutually exclusive"); 2627 return (1); 2628 } 2629 if ((opt_flags & OP_ALLDIRS) && dp->dp_left) { 2630 syslog(LOG_ERR, "-alldirs has multiple directories"); 2631 return (1); 2632 } 2633 return (0); 2634 } 2635 2636 /* 2637 * Check an absolute directory path for any symbolic links. Return true 2638 */ 2639 int 2640 check_dirpath(dirp) 2641 char *dirp; 2642 { 2643 char *cp; 2644 int ret = 1; 2645 struct stat sb; 2646 2647 cp = dirp + 1; 2648 while (*cp && ret) { 2649 if (*cp == '/') { 2650 *cp = '\0'; 2651 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2652 ret = 0; 2653 *cp = '/'; 2654 } 2655 cp++; 2656 } 2657 if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode)) 2658 ret = 0; 2659 return (ret); 2660 } 2661 2662 /* 2663 * Make a netmask according to the specified prefix length. The ss_family 2664 * and other non-address fields must be initialised before calling this. 2665 */ 2666 int 2667 makemask(struct sockaddr_storage *ssp, int bitlen) 2668 { 2669 u_char *p; 2670 int bits, i, len; 2671 2672 if ((p = sa_rawaddr((struct sockaddr *)ssp, &len)) == NULL) 2673 return (-1); 2674 if (bitlen > len * CHAR_BIT) 2675 return (-1); 2676 2677 for (i = 0; i < len; i++) { 2678 bits = (bitlen > CHAR_BIT) ? CHAR_BIT : bitlen; 2679 *p++ = (1 << bits) - 1; 2680 bitlen -= bits; 2681 } 2682 return 0; 2683 } 2684 2685 /* 2686 * Check that the sockaddr is a valid netmask. Returns 0 if the mask 2687 * is acceptable (i.e. of the form 1...10....0). 2688 */ 2689 int 2690 checkmask(struct sockaddr *sa) 2691 { 2692 u_char *mask; 2693 int i, len; 2694 2695 if ((mask = sa_rawaddr(sa, &len)) == NULL) 2696 return (-1); 2697 2698 for (i = 0; i < len; i++) 2699 if (mask[i] != 0xff) 2700 break; 2701 if (i < len) { 2702 if (~mask[i] & (u_char)(~mask[i] + 1)) 2703 return (-1); 2704 i++; 2705 } 2706 for (; i < len; i++) 2707 if (mask[i] != 0) 2708 return (-1); 2709 return (0); 2710 } 2711 2712 /* 2713 * Compare two sockaddrs according to a specified mask. Return zero if 2714 * `sa1' matches `sa2' when filtered by the netmask in `samask'. 2715 * If samask is NULL, perform a full comparision. 2716 */ 2717 int 2718 sacmp(struct sockaddr *sa1, struct sockaddr *sa2, struct sockaddr *samask) 2719 { 2720 unsigned char *p1, *p2, *mask; 2721 int len, i; 2722 2723 if (sa1->sa_family != sa2->sa_family || 2724 (p1 = sa_rawaddr(sa1, &len)) == NULL || 2725 (p2 = sa_rawaddr(sa2, NULL)) == NULL) 2726 return (1); 2727 2728 switch (sa1->sa_family) { 2729 case AF_INET6: 2730 if (((struct sockaddr_in6 *)sa1)->sin6_scope_id != 2731 ((struct sockaddr_in6 *)sa2)->sin6_scope_id) 2732 return (1); 2733 break; 2734 } 2735 2736 /* Simple binary comparison if no mask specified. */ 2737 if (samask == NULL) 2738 return (memcmp(p1, p2, len)); 2739 2740 /* Set up the mask, and do a mask-based comparison. */ 2741 if (sa1->sa_family != samask->sa_family || 2742 (mask = sa_rawaddr(samask, NULL)) == NULL) 2743 return (1); 2744 2745 for (i = 0; i < len; i++) 2746 if ((p1[i] & mask[i]) != (p2[i] & mask[i])) 2747 return (1); 2748 return (0); 2749 } 2750 2751 /* 2752 * Return a pointer to the part of the sockaddr that contains the 2753 * raw address, and set *nbytes to its length in bytes. Returns 2754 * NULL if the address family is unknown. 2755 */ 2756 void * 2757 sa_rawaddr(struct sockaddr *sa, int *nbytes) { 2758 void *p; 2759 int len; 2760 2761 switch (sa->sa_family) { 2762 case AF_INET: 2763 len = sizeof(((struct sockaddr_in *)sa)->sin_addr); 2764 p = &((struct sockaddr_in *)sa)->sin_addr; 2765 break; 2766 case AF_INET6: 2767 len = sizeof(((struct sockaddr_in6 *)sa)->sin6_addr); 2768 p = &((struct sockaddr_in6 *)sa)->sin6_addr; 2769 break; 2770 default: 2771 p = NULL; 2772 len = 0; 2773 } 2774 2775 if (nbytes != NULL) 2776 *nbytes = len; 2777 return (p); 2778 } 2779 2780 void 2781 huphandler(int sig) 2782 { 2783 got_sighup = 1; 2784 } 2785 2786 void terminate(sig) 2787 int sig; 2788 { 2789 pidfile_remove(pfh); 2790 rpcb_unset(RPCPROG_MNT, RPCMNT_VER1, NULL); 2791 rpcb_unset(RPCPROG_MNT, RPCMNT_VER3, NULL); 2792 exit (0); 2793 } 2794