auditdistd.c revision 243730
1/*- 2 * Copyright (c) 2012 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Pawel Jakub Dawidek under sponsorship from 6 * the FreeBSD Foundation. 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 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/auditdistd.c#1 $ 30 */ 31 32#include "config.h" 33 34#include <sys/param.h> 35#if defined(HAVE_SYS_ENDIAN_H) && defined(HAVE_BSWAP) 36#include <sys/endian.h> 37#else /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */ 38#ifdef HAVE_MACHINE_ENDIAN_H 39#include <machine/endian.h> 40#else /* !HAVE_MACHINE_ENDIAN_H */ 41#ifdef HAVE_ENDIAN_H 42#include <endian.h> 43#else /* !HAVE_ENDIAN_H */ 44#error "No supported endian.h" 45#endif /* !HAVE_ENDIAN_H */ 46#endif /* !HAVE_MACHINE_ENDIAN_H */ 47#include <compat/endian.h> 48#endif /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */ 49#include <sys/queue.h> 50#include <sys/wait.h> 51 52#include <ctype.h> 53#include <err.h> 54#include <errno.h> 55#include <fcntl.h> 56#ifdef HAVE_LIBUTIL_H 57#include <libutil.h> 58#endif 59#include <signal.h> 60#include <stdio.h> 61#include <stdlib.h> 62#include <string.h> 63#include <strings.h> 64#include <unistd.h> 65 66#include <openssl/hmac.h> 67 68#ifndef HAVE_PIDFILE_OPEN 69#include <compat/pidfile.h> 70#endif 71#ifndef HAVE_STRLCPY 72#include <compat/strlcpy.h> 73#endif 74#ifndef HAVE_SIGTIMEDWAIT 75#include "sigtimedwait.h" 76#endif 77 78#include <pjdlog.h> 79 80#include "auditdistd.h" 81#include "proto.h" 82#include "subr.h" 83#include "synch.h" 84 85/* Path to configuration file. */ 86const char *cfgpath = ADIST_CONFIG; 87/* Auditdistd configuration. */ 88static struct adist_config *adcfg; 89/* Was SIGINT or SIGTERM signal received? */ 90bool sigexit_received = false; 91/* PID file handle. */ 92struct pidfh *pfh; 93 94/* How often check for hooks running for too long. */ 95#define SIGNALS_CHECK_INTERVAL 5 96 97static void 98usage(void) 99{ 100 101 errx(EX_USAGE, "[-dFhl] [-c config] [-P pidfile]"); 102} 103 104void 105descriptors_cleanup(struct adist_host *adhost) 106{ 107 struct adist_host *adh; 108 struct adist_listen *lst; 109 110 TAILQ_FOREACH(adh, &adcfg->adc_hosts, adh_next) { 111 if (adh == adhost) 112 continue; 113 if (adh->adh_remote != NULL) { 114 proto_close(adh->adh_remote); 115 adh->adh_remote = NULL; 116 } 117 } 118 TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) { 119 if (lst->adl_conn != NULL) 120 proto_close(lst->adl_conn); 121 } 122 (void)pidfile_close(pfh); 123 pjdlog_fini(); 124} 125 126static void 127child_cleanup(struct adist_host *adhost) 128{ 129 130 if (adhost->adh_conn != NULL) { 131 PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER); 132 proto_close(adhost->adh_conn); 133 adhost->adh_conn = NULL; 134 } 135 adhost->adh_worker_pid = 0; 136} 137 138static void 139child_exit_log(const char *type, unsigned int pid, int status) 140{ 141 142 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 143 pjdlog_debug(1, "%s process exited gracefully (pid=%u).", 144 type, pid); 145 } else if (WIFSIGNALED(status)) { 146 pjdlog_error("%s process killed (pid=%u, signal=%d).", 147 type, pid, WTERMSIG(status)); 148 } else { 149 pjdlog_error("%s process exited ungracefully (pid=%u, exitcode=%d).", 150 type, pid, WIFEXITED(status) ? WEXITSTATUS(status) : -1); 151 } 152} 153 154static void 155child_exit(void) 156{ 157 struct adist_host *adhost; 158 bool restart; 159 int status; 160 pid_t pid; 161 162 restart = false; 163 while ((pid = wait3(&status, WNOHANG, NULL)) > 0) { 164 /* Find host related to the process that just exited. */ 165 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { 166 if (pid == adhost->adh_worker_pid) 167 break; 168 } 169 if (adhost == NULL) { 170 child_exit_log("Sandbox", pid, status); 171 } else { 172 if (adhost->adh_role == ADIST_ROLE_SENDER) 173 restart = true; 174 pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name, 175 role2str(adhost->adh_role)); 176 child_exit_log("Worker", pid, status); 177 child_cleanup(adhost); 178 pjdlog_prefix_set("%s", ""); 179 } 180 } 181 if (!restart) 182 return; 183 /* We have some sender processes to restart. */ 184 sleep(1); 185 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { 186 if (adhost->adh_role != ADIST_ROLE_SENDER) 187 continue; 188 if (adhost->adh_worker_pid != 0) 189 continue; 190 pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name, 191 role2str(adhost->adh_role)); 192 pjdlog_info("Restarting sender process."); 193 adist_sender(adcfg, adhost); 194 pjdlog_prefix_set("%s", ""); 195 } 196} 197 198/* TODO */ 199static void 200adist_reload(void) 201{ 202 203 pjdlog_info("Reloading configuration is not yet implemented."); 204} 205 206static void 207terminate_workers(void) 208{ 209 struct adist_host *adhost; 210 211 pjdlog_info("Termination signal received, exiting."); 212 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { 213 if (adhost->adh_worker_pid == 0) 214 continue; 215 pjdlog_info("Terminating worker process (adhost=%s, role=%s, pid=%u).", 216 adhost->adh_name, role2str(adhost->adh_role), 217 adhost->adh_worker_pid); 218 if (kill(adhost->adh_worker_pid, SIGTERM) == 0) 219 continue; 220 pjdlog_errno(LOG_WARNING, 221 "Unable to send signal to worker process (adhost=%s, role=%s, pid=%u).", 222 adhost->adh_name, role2str(adhost->adh_role), 223 adhost->adh_worker_pid); 224 } 225} 226 227static void 228listen_accept(struct adist_listen *lst) 229{ 230 unsigned char rnd[32], hash[32], resp[32]; 231 struct adist_host *adhost; 232 struct proto_conn *conn; 233 char adname[ADIST_HOSTSIZE]; 234 char laddr[256], raddr[256]; 235 char welcome[8]; 236 int status, version; 237 pid_t pid; 238 239 proto_local_address(lst->adl_conn, laddr, sizeof(laddr)); 240 pjdlog_debug(1, "Accepting connection to %s.", laddr); 241 242 if (proto_accept(lst->adl_conn, &conn) == -1) { 243 pjdlog_errno(LOG_ERR, "Unable to accept connection to %s", 244 laddr); 245 return; 246 } 247 248 proto_local_address(conn, laddr, sizeof(laddr)); 249 proto_remote_address(conn, raddr, sizeof(raddr)); 250 pjdlog_info("Connection from %s to %s.", raddr, laddr); 251 252 /* Error in setting timeout is not critical, but why should it fail? */ 253 if (proto_timeout(conn, ADIST_TIMEOUT) < 0) 254 pjdlog_errno(LOG_WARNING, "Unable to set connection timeout"); 255 256 /* 257 * Before receiving any data see if remote host is known. 258 */ 259 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { 260 if (adhost->adh_role != ADIST_ROLE_RECEIVER) 261 continue; 262 if (!proto_address_match(conn, adhost->adh_remoteaddr)) 263 continue; 264 break; 265 } 266 if (adhost == NULL) { 267 pjdlog_error("Client %s is not known.", raddr); 268 goto close; 269 } 270 /* Ok, remote host is known. */ 271 272 /* Exchange welcome message, which include version number. */ 273 bzero(welcome, sizeof(welcome)); 274 if (proto_recv(conn, welcome, sizeof(welcome)) == -1) { 275 pjdlog_errno(LOG_WARNING, 276 "Unable to receive welcome message from %s", 277 adhost->adh_remoteaddr); 278 goto close; 279 } 280 if (strncmp(welcome, "ADIST", 5) != 0 || !isdigit(welcome[5]) || 281 !isdigit(welcome[6]) || welcome[7] != '\0') { 282 pjdlog_warning("Invalid welcome message from %s.", 283 adhost->adh_remoteaddr); 284 goto close; 285 } 286 287 version = MIN(ADIST_VERSION, atoi(welcome + 5)); 288 289 (void)snprintf(welcome, sizeof(welcome), "ADIST%02d", version); 290 if (proto_send(conn, welcome, sizeof(welcome)) == -1) { 291 pjdlog_errno(LOG_WARNING, 292 "Unable to send welcome message to %s", 293 adhost->adh_remoteaddr); 294 goto close; 295 } 296 297 if (proto_recv(conn, adname, sizeof(adhost->adh_name)) < 0) { 298 pjdlog_errno(LOG_ERR, "Unable to receive hostname from %s", 299 raddr); 300 goto close; 301 } 302 303 /* Find host now that we have hostname. */ 304 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { 305 if (adhost->adh_role != ADIST_ROLE_RECEIVER) 306 continue; 307 if (!proto_address_match(conn, adhost->adh_remoteaddr)) 308 continue; 309 if (strcmp(adhost->adh_name, adname) != 0) 310 continue; 311 break; 312 } 313 if (adhost == NULL) { 314 pjdlog_error("No configuration for host %s from address %s.", 315 adname, raddr); 316 goto close; 317 } 318 319 adhost->adh_version = version; 320 pjdlog_debug(1, "Version %d negotiated with %s.", adhost->adh_version, 321 adhost->adh_remoteaddr); 322 323 /* Now that we know host name setup log prefix. */ 324 pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name, 325 role2str(adhost->adh_role)); 326 327 if (adist_random(rnd, sizeof(rnd)) == -1) { 328 pjdlog_error("Unable to generate challenge."); 329 goto close; 330 } 331 pjdlog_debug(1, "Challenge generated."); 332 333 if (proto_send(conn, rnd, sizeof(rnd)) == -1) { 334 pjdlog_errno(LOG_ERR, "Unable to send challenge to %s", 335 adhost->adh_remoteaddr); 336 goto close; 337 } 338 pjdlog_debug(1, "Challenge sent."); 339 340 if (proto_recv(conn, resp, sizeof(resp)) == -1) { 341 pjdlog_errno(LOG_ERR, "Unable to receive response from %s", 342 adhost->adh_remoteaddr); 343 goto close; 344 } 345 pjdlog_debug(1, "Response received."); 346 347 if (HMAC(EVP_sha256(), adhost->adh_password, 348 (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash, 349 NULL) == NULL) { 350 pjdlog_error("Unable to generate hash."); 351 goto close; 352 } 353 pjdlog_debug(1, "Hash generated."); 354 355 if (memcmp(resp, hash, sizeof(hash)) != 0) { 356 pjdlog_error("Invalid response from %s (wrong password?).", 357 adhost->adh_remoteaddr); 358 goto close; 359 } 360 pjdlog_info("Sender authenticated."); 361 362 if (proto_recv(conn, rnd, sizeof(rnd)) == -1) { 363 pjdlog_errno(LOG_ERR, "Unable to receive challenge from %s", 364 adhost->adh_remoteaddr); 365 goto close; 366 } 367 pjdlog_debug(1, "Challenge received."); 368 369 if (HMAC(EVP_sha256(), adhost->adh_password, 370 (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash, 371 NULL) == NULL) { 372 pjdlog_error("Unable to generate response."); 373 goto close; 374 } 375 pjdlog_debug(1, "Response generated."); 376 377 if (proto_send(conn, hash, sizeof(hash)) == -1) { 378 pjdlog_errno(LOG_ERR, "Unable to send response to %s", 379 adhost->adh_remoteaddr); 380 goto close; 381 } 382 pjdlog_debug(1, "Response sent."); 383 384 if (adhost->adh_worker_pid != 0) { 385 pjdlog_debug(1, 386 "Receiver process exists (pid=%u), stopping it.", 387 (unsigned int)adhost->adh_worker_pid); 388 /* Stop child process. */ 389 if (kill(adhost->adh_worker_pid, SIGINT) == -1) { 390 pjdlog_errno(LOG_ERR, 391 "Unable to stop worker process (pid=%u)", 392 (unsigned int)adhost->adh_worker_pid); 393 /* 394 * Other than logging the problem we 395 * ignore it - nothing smart to do. 396 */ 397 } 398 /* Wait for it to exit. */ 399 else if ((pid = waitpid(adhost->adh_worker_pid, 400 &status, 0)) != adhost->adh_worker_pid) { 401 /* We can only log the problem. */ 402 pjdlog_errno(LOG_ERR, 403 "Waiting for worker process (pid=%u) failed", 404 (unsigned int)adhost->adh_worker_pid); 405 } else { 406 child_exit_log("Worker", adhost->adh_worker_pid, 407 status); 408 } 409 child_cleanup(adhost); 410 } 411 412 adhost->adh_remote = conn; 413 adist_receiver(adcfg, adhost); 414 415 pjdlog_prefix_set("%s", ""); 416 return; 417close: 418 proto_close(conn); 419 pjdlog_prefix_set("%s", ""); 420} 421 422static void 423connection_migrate(struct adist_host *adhost) 424{ 425 struct proto_conn *conn; 426 int16_t val = 0; 427 428 pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name, 429 role2str(adhost->adh_role)); 430 431 PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER); 432 433 if (proto_recv(adhost->adh_conn, &val, sizeof(val)) < 0) { 434 pjdlog_errno(LOG_WARNING, 435 "Unable to receive connection command"); 436 return; 437 } 438 if (proto_set("tls:fingerprint", adhost->adh_fingerprint) == -1) { 439 val = errno; 440 pjdlog_errno(LOG_WARNING, "Unable to set fingerprint"); 441 goto out; 442 } 443 if (proto_connect(adhost->adh_localaddr[0] != '\0' ? 444 adhost->adh_localaddr : NULL, 445 adhost->adh_remoteaddr, -1, &conn) < 0) { 446 val = errno; 447 pjdlog_errno(LOG_WARNING, "Unable to connect to %s", 448 adhost->adh_remoteaddr); 449 goto out; 450 } 451 val = 0; 452out: 453 if (proto_send(adhost->adh_conn, &val, sizeof(val)) < 0) { 454 pjdlog_errno(LOG_WARNING, 455 "Unable to send reply to connection request"); 456 } 457 if (val == 0 && proto_connection_send(adhost->adh_conn, conn) < 0) 458 pjdlog_errno(LOG_WARNING, "Unable to send connection"); 459 460 pjdlog_prefix_set("%s", ""); 461} 462 463static void 464check_signals(void) 465{ 466 struct timespec sigtimeout; 467 sigset_t mask; 468 int signo; 469 470 sigtimeout.tv_sec = 0; 471 sigtimeout.tv_nsec = 0; 472 473 PJDLOG_VERIFY(sigemptyset(&mask) == 0); 474 PJDLOG_VERIFY(sigaddset(&mask, SIGHUP) == 0); 475 PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0); 476 PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0); 477 PJDLOG_VERIFY(sigaddset(&mask, SIGCHLD) == 0); 478 479 while ((signo = sigtimedwait(&mask, NULL, &sigtimeout)) != -1) { 480 switch (signo) { 481 case SIGINT: 482 case SIGTERM: 483 sigexit_received = true; 484 terminate_workers(); 485 exit(EX_OK); 486 break; 487 case SIGCHLD: 488 child_exit(); 489 break; 490 case SIGHUP: 491 adist_reload(); 492 break; 493 default: 494 PJDLOG_ABORT("Unexpected signal (%d).", signo); 495 } 496 } 497} 498 499static void 500main_loop(void) 501{ 502 struct adist_host *adhost; 503 struct adist_listen *lst; 504 struct timeval seltimeout; 505 int fd, maxfd, ret; 506 fd_set rfds; 507 508 seltimeout.tv_sec = SIGNALS_CHECK_INTERVAL; 509 seltimeout.tv_usec = 0; 510 511 pjdlog_info("Started successfully."); 512 513 for (;;) { 514 check_signals(); 515 516 /* Setup descriptors for select(2). */ 517 FD_ZERO(&rfds); 518 maxfd = -1; 519 TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) { 520 if (lst->adl_conn == NULL) 521 continue; 522 fd = proto_descriptor(lst->adl_conn); 523 PJDLOG_ASSERT(fd >= 0); 524 FD_SET(fd, &rfds); 525 maxfd = fd > maxfd ? fd : maxfd; 526 } 527 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { 528 if (adhost->adh_role == ADIST_ROLE_SENDER) { 529 /* Only sender workers asks for connections. */ 530 PJDLOG_ASSERT(adhost->adh_conn != NULL); 531 fd = proto_descriptor(adhost->adh_conn); 532 PJDLOG_ASSERT(fd >= 0); 533 FD_SET(fd, &rfds); 534 maxfd = fd > maxfd ? fd : maxfd; 535 } else { 536 PJDLOG_ASSERT(adhost->adh_conn == NULL); 537 } 538 } 539 540 PJDLOG_ASSERT(maxfd + 1 <= (int)FD_SETSIZE); 541 ret = select(maxfd + 1, &rfds, NULL, NULL, &seltimeout); 542 if (ret == 0) { 543 /* 544 * select(2) timed out, so there should be no 545 * descriptors to check. 546 */ 547 continue; 548 } else if (ret == -1) { 549 if (errno == EINTR) 550 continue; 551 KEEP_ERRNO((void)pidfile_remove(pfh)); 552 pjdlog_exit(EX_OSERR, "select() failed"); 553 } 554 PJDLOG_ASSERT(ret > 0); 555 556 /* 557 * Check for signals before we do anything to update our 558 * info about terminated workers in the meantime. 559 */ 560 check_signals(); 561 562 TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) { 563 if (lst->adl_conn == NULL) 564 continue; 565 if (FD_ISSET(proto_descriptor(lst->adl_conn), &rfds)) 566 listen_accept(lst); 567 } 568 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { 569 if (adhost->adh_role == ADIST_ROLE_SENDER) { 570 PJDLOG_ASSERT(adhost->adh_conn != NULL); 571 if (FD_ISSET(proto_descriptor(adhost->adh_conn), 572 &rfds)) { 573 connection_migrate(adhost); 574 } 575 } else { 576 PJDLOG_ASSERT(adhost->adh_conn == NULL); 577 } 578 } 579 } 580} 581 582static void 583adist_config_dump(struct adist_config *cfg) 584{ 585 struct adist_host *adhost; 586 struct adist_listen *lst; 587 588 pjdlog_debug(2, "Configuration:"); 589 pjdlog_debug(2, " Global:"); 590 pjdlog_debug(2, " pidfile: %s", cfg->adc_pidfile); 591 pjdlog_debug(2, " timeout: %d", cfg->adc_timeout); 592 if (TAILQ_EMPTY(&cfg->adc_listen)) { 593 pjdlog_debug(2, " Sender only, not listening."); 594 } else { 595 pjdlog_debug(2, " Listening on:"); 596 TAILQ_FOREACH(lst, &cfg->adc_listen, adl_next) { 597 pjdlog_debug(2, " listen: %s", lst->adl_addr); 598 pjdlog_debug(2, " conn: %p", lst->adl_conn); 599 } 600 } 601 pjdlog_debug(2, " Hosts:"); 602 TAILQ_FOREACH(adhost, &cfg->adc_hosts, adh_next) { 603 pjdlog_debug(2, " name: %s", adhost->adh_name); 604 pjdlog_debug(2, " role: %s", role2str(adhost->adh_role)); 605 pjdlog_debug(2, " version: %d", adhost->adh_version); 606 pjdlog_debug(2, " localaddr: %s", adhost->adh_localaddr); 607 pjdlog_debug(2, " remoteaddr: %s", adhost->adh_remoteaddr); 608 pjdlog_debug(2, " remote: %p", adhost->adh_remote); 609 pjdlog_debug(2, " directory: %s", adhost->adh_directory); 610 pjdlog_debug(2, " compression: %d", adhost->adh_compression); 611 pjdlog_debug(2, " checksum: %d", adhost->adh_checksum); 612 pjdlog_debug(2, " pid: %ld", (long)adhost->adh_worker_pid); 613 pjdlog_debug(2, " conn: %p", adhost->adh_conn); 614 } 615} 616 617static void 618dummy_sighandler(int sig __unused) 619{ 620 /* Nothing to do. */ 621} 622 623int 624main(int argc, char *argv[]) 625{ 626 struct adist_host *adhost; 627 struct adist_listen *lst; 628 const char *execpath, *pidfile; 629 bool foreground, launchd; 630 pid_t otherpid; 631 int debuglevel; 632 sigset_t mask; 633 634 execpath = argv[0]; 635 if (execpath[0] != '/') { 636 errx(EX_USAGE, 637 "auditdistd requires execution with an absolute path."); 638 } 639 640 /* 641 * We are executed from proto to create sandbox. 642 */ 643 if (argc > 1 && strcmp(argv[1], "proto") == 0) { 644 argc -= 2; 645 argv += 2; 646 if (proto_exec(argc, argv) == -1) 647 err(EX_USAGE, "Unable to execute proto"); 648 } 649 650 foreground = false; 651 debuglevel = 0; 652 launchd = false; 653 pidfile = NULL; 654 655 for (;;) { 656 int ch; 657 658 ch = getopt(argc, argv, "c:dFhlP:"); 659 if (ch == -1) 660 break; 661 switch (ch) { 662 case 'c': 663 cfgpath = optarg; 664 break; 665 case 'd': 666 debuglevel++; 667 break; 668 case 'F': 669 foreground = true; 670 break; 671 case 'l': 672 launchd = true; 673 break; 674 case 'P': 675 pidfile = optarg; 676 break; 677 case 'h': 678 default: 679 usage(); 680 } 681 } 682 argc -= optind; 683 argv += optind; 684 685 pjdlog_init(PJDLOG_MODE_STD); 686 pjdlog_debug_set(debuglevel); 687 688 if (proto_set("execpath", execpath) == -1) 689 pjdlog_exit(EX_TEMPFAIL, "Unable to set executable name"); 690 if (proto_set("user", ADIST_USER) == -1) 691 pjdlog_exit(EX_TEMPFAIL, "Unable to set proto user"); 692 if (proto_set("tcp:port", ADIST_TCP_PORT) == -1) 693 pjdlog_exit(EX_TEMPFAIL, "Unable to set default TCP port"); 694 695 /* 696 * When path to the configuration file is relative, obtain full path, 697 * so we can always find the file, even after daemonizing and changing 698 * working directory to /. 699 */ 700 if (cfgpath[0] != '/') { 701 const char *newcfgpath; 702 703 newcfgpath = realpath(cfgpath, NULL); 704 if (newcfgpath == NULL) { 705 pjdlog_exit(EX_CONFIG, 706 "Unable to obtain full path of %s", cfgpath); 707 } 708 cfgpath = newcfgpath; 709 } 710 711 adcfg = yy_config_parse(cfgpath, true); 712 PJDLOG_ASSERT(adcfg != NULL); 713 adist_config_dump(adcfg); 714 715 if (proto_set("tls:certfile", adcfg->adc_certfile) == -1) 716 pjdlog_exit(EX_TEMPFAIL, "Unable to set certfile path"); 717 if (proto_set("tls:keyfile", adcfg->adc_keyfile) == -1) 718 pjdlog_exit(EX_TEMPFAIL, "Unable to set keyfile path"); 719 720 if (pidfile != NULL) { 721 if (strlcpy(adcfg->adc_pidfile, pidfile, 722 sizeof(adcfg->adc_pidfile)) >= 723 sizeof(adcfg->adc_pidfile)) { 724 pjdlog_exitx(EX_CONFIG, "Pidfile path is too long."); 725 } 726 } 727 if (foreground && pidfile == NULL) { 728 pfh = NULL; 729 } else { 730 pfh = pidfile_open(adcfg->adc_pidfile, 0600, &otherpid); 731 if (pfh == NULL) { 732 if (errno == EEXIST) { 733 pjdlog_exitx(EX_TEMPFAIL, 734 "Another auditdistd is already running, pid: %jd.", 735 (intmax_t)otherpid); 736 } 737 /* 738 * If we cannot create pidfile from other reasons, 739 * only warn. 740 */ 741 pjdlog_errno(LOG_WARNING, 742 "Unable to open or create pidfile %s", 743 adcfg->adc_pidfile); 744 } 745 } 746 747 /* 748 * Restore default actions for interesting signals in case parent 749 * process (like init(8)) decided to ignore some of them (like SIGHUP). 750 */ 751 PJDLOG_VERIFY(signal(SIGHUP, SIG_DFL) != SIG_ERR); 752 PJDLOG_VERIFY(signal(SIGINT, SIG_DFL) != SIG_ERR); 753 PJDLOG_VERIFY(signal(SIGTERM, SIG_DFL) != SIG_ERR); 754 /* 755 * Because SIGCHLD is ignored by default, setup dummy handler for it, 756 * so we can mask it. 757 */ 758 PJDLOG_VERIFY(signal(SIGCHLD, dummy_sighandler) != SIG_ERR); 759 760 PJDLOG_VERIFY(sigemptyset(&mask) == 0); 761 PJDLOG_VERIFY(sigaddset(&mask, SIGHUP) == 0); 762 PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0); 763 PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0); 764 PJDLOG_VERIFY(sigaddset(&mask, SIGCHLD) == 0); 765 PJDLOG_VERIFY(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); 766 767 /* Listen for remote connections. */ 768 TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) { 769 if (proto_server(lst->adl_addr, &lst->adl_conn) == -1) { 770 KEEP_ERRNO((void)pidfile_remove(pfh)); 771 pjdlog_exit(EX_OSERR, "Unable to listen on address %s", 772 lst->adl_addr); 773 } 774 } 775 776 if (!foreground) { 777 if (!launchd && daemon(0, 0) == -1) { 778 KEEP_ERRNO((void)pidfile_remove(pfh)); 779 pjdlog_exit(EX_OSERR, "Unable to daemonize"); 780 } 781 782 /* Start logging to syslog. */ 783 pjdlog_mode_set(PJDLOG_MODE_SYSLOG); 784 } 785 if (pfh != NULL) { 786 /* Write PID to a file. */ 787 if (pidfile_write(pfh) < 0) { 788 pjdlog_errno(LOG_WARNING, 789 "Unable to write PID to a file"); 790 } 791 } 792 793 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { 794 if (adhost->adh_role == ADIST_ROLE_SENDER) 795 adist_sender(adcfg, adhost); 796 } 797 798 main_loop(); 799 800 exit(0); 801} 802