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