2 * Copyright (c) 2012 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
29 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/auditdistd.c#3 $
32 #include <config/config.h>
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 */
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>
66 #include <openssl/hmac.h>
68 #ifndef HAVE_PIDFILE_OPEN
69 #include <compat/pidfile.h>
72 #include <compat/strlcpy.h>
74 #ifndef HAVE_SIGTIMEDWAIT
75 #include "sigtimedwait.h"
78 #include "auditdistd.h"
84 /* Path to configuration file. */
85 const char *cfgpath = ADIST_CONFIG;
86 /* Auditdistd configuration. */
87 static struct adist_config *adcfg;
88 /* Was SIGINT or SIGTERM signal received? */
89 bool sigexit_received = false;
90 /* PID file handle. */
93 /* How often check for hooks running for too long. */
94 #define SIGNALS_CHECK_INTERVAL 5
100 errx(EX_USAGE, "[-dFhl] [-c config] [-P pidfile]");
104 descriptors_cleanup(struct adist_host *adhost)
106 struct adist_host *adh;
107 struct adist_listen *lst;
109 TAILQ_FOREACH(adh, &adcfg->adc_hosts, adh_next) {
112 if (adh->adh_remote != NULL) {
113 proto_close(adh->adh_remote);
114 adh->adh_remote = NULL;
117 TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
118 if (lst->adl_conn != NULL)
119 proto_close(lst->adl_conn);
121 (void)pidfile_close(pfh);
126 child_cleanup(struct adist_host *adhost)
129 if (adhost->adh_conn != NULL) {
130 PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER);
131 proto_close(adhost->adh_conn);
132 adhost->adh_conn = NULL;
134 adhost->adh_worker_pid = 0;
138 child_exit_log(const char *type, unsigned int pid, int status)
141 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
142 pjdlog_debug(1, "%s process exited gracefully (pid=%u).",
144 } else if (WIFSIGNALED(status)) {
145 pjdlog_error("%s process killed (pid=%u, signal=%d).",
146 type, pid, WTERMSIG(status));
148 pjdlog_error("%s process exited ungracefully (pid=%u, exitcode=%d).",
149 type, pid, WIFEXITED(status) ? WEXITSTATUS(status) : -1);
156 struct adist_host *adhost;
162 while ((pid = wait3(&status, WNOHANG, NULL)) > 0) {
163 /* Find host related to the process that just exited. */
164 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
165 if (pid == adhost->adh_worker_pid)
168 if (adhost == NULL) {
169 child_exit_log("Sandbox", pid, status);
171 if (adhost->adh_role == ADIST_ROLE_SENDER)
173 pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
174 role2str(adhost->adh_role));
175 child_exit_log("Worker", pid, status);
176 child_cleanup(adhost);
177 pjdlog_prefix_set("%s", "");
182 /* We have some sender processes to restart. */
184 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
185 if (adhost->adh_role != ADIST_ROLE_SENDER)
187 if (adhost->adh_worker_pid != 0)
189 pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
190 role2str(adhost->adh_role));
191 pjdlog_info("Restarting sender process.");
192 adist_sender(adcfg, adhost);
193 pjdlog_prefix_set("%s", "");
202 pjdlog_info("Reloading configuration is not yet implemented.");
206 terminate_workers(void)
208 struct adist_host *adhost;
210 pjdlog_info("Termination signal received, exiting.");
211 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
212 if (adhost->adh_worker_pid == 0)
214 pjdlog_info("Terminating worker process (adhost=%s, role=%s, pid=%u).",
215 adhost->adh_name, role2str(adhost->adh_role),
216 adhost->adh_worker_pid);
217 if (kill(adhost->adh_worker_pid, SIGTERM) == 0)
219 pjdlog_errno(LOG_WARNING,
220 "Unable to send signal to worker process (adhost=%s, role=%s, pid=%u).",
221 adhost->adh_name, role2str(adhost->adh_role),
222 adhost->adh_worker_pid);
227 listen_accept(struct adist_listen *lst)
229 unsigned char rnd[32], hash[32], resp[32];
230 struct adist_host *adhost;
231 struct proto_conn *conn;
232 char adname[ADIST_HOSTSIZE];
233 char laddr[256], raddr[256];
238 proto_local_address(lst->adl_conn, laddr, sizeof(laddr));
239 pjdlog_debug(1, "Accepting connection to %s.", laddr);
241 if (proto_accept(lst->adl_conn, &conn) == -1) {
242 pjdlog_errno(LOG_ERR, "Unable to accept connection to %s",
247 proto_local_address(conn, laddr, sizeof(laddr));
248 proto_remote_address(conn, raddr, sizeof(raddr));
249 pjdlog_info("Connection from %s to %s.", raddr, laddr);
251 /* Error in setting timeout is not critical, but why should it fail? */
252 if (proto_timeout(conn, ADIST_TIMEOUT) < 0)
253 pjdlog_errno(LOG_WARNING, "Unable to set connection timeout");
256 * Before receiving any data see if remote host is known.
258 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
259 if (adhost->adh_role != ADIST_ROLE_RECEIVER)
261 if (!proto_address_match(conn, adhost->adh_remoteaddr))
265 if (adhost == NULL) {
266 pjdlog_error("Client %s is not known.", raddr);
269 /* Ok, remote host is known. */
271 /* Exchange welcome message, which include version number. */
272 bzero(welcome, sizeof(welcome));
273 if (proto_recv(conn, welcome, sizeof(welcome)) == -1) {
274 pjdlog_errno(LOG_WARNING,
275 "Unable to receive welcome message from %s",
276 adhost->adh_remoteaddr);
279 if (strncmp(welcome, "ADIST", 5) != 0 || !isdigit(welcome[5]) ||
280 !isdigit(welcome[6]) || welcome[7] != '\0') {
281 pjdlog_warning("Invalid welcome message from %s.",
282 adhost->adh_remoteaddr);
286 version = MIN(ADIST_VERSION, atoi(welcome + 5));
288 (void)snprintf(welcome, sizeof(welcome), "ADIST%02d", version);
289 if (proto_send(conn, welcome, sizeof(welcome)) == -1) {
290 pjdlog_errno(LOG_WARNING,
291 "Unable to send welcome message to %s",
292 adhost->adh_remoteaddr);
296 if (proto_recv(conn, adname, sizeof(adhost->adh_name)) < 0) {
297 pjdlog_errno(LOG_ERR, "Unable to receive hostname from %s",
302 /* Find host now that we have hostname. */
303 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
304 if (adhost->adh_role != ADIST_ROLE_RECEIVER)
306 if (!proto_address_match(conn, adhost->adh_remoteaddr))
308 if (strcmp(adhost->adh_name, adname) != 0)
312 if (adhost == NULL) {
313 pjdlog_error("No configuration for host %s from address %s.",
318 adhost->adh_version = version;
319 pjdlog_debug(1, "Version %d negotiated with %s.", adhost->adh_version,
320 adhost->adh_remoteaddr);
322 /* Now that we know host name setup log prefix. */
323 pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
324 role2str(adhost->adh_role));
326 if (adist_random(rnd, sizeof(rnd)) == -1) {
327 pjdlog_error("Unable to generate challenge.");
330 pjdlog_debug(1, "Challenge generated.");
332 if (proto_send(conn, rnd, sizeof(rnd)) == -1) {
333 pjdlog_errno(LOG_ERR, "Unable to send challenge to %s",
334 adhost->adh_remoteaddr);
337 pjdlog_debug(1, "Challenge sent.");
339 if (proto_recv(conn, resp, sizeof(resp)) == -1) {
340 pjdlog_errno(LOG_ERR, "Unable to receive response from %s",
341 adhost->adh_remoteaddr);
344 pjdlog_debug(1, "Response received.");
346 if (HMAC(EVP_sha256(), adhost->adh_password,
347 (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash,
349 pjdlog_error("Unable to generate hash.");
352 pjdlog_debug(1, "Hash generated.");
354 if (memcmp(resp, hash, sizeof(hash)) != 0) {
355 pjdlog_error("Invalid response from %s (wrong password?).",
356 adhost->adh_remoteaddr);
359 pjdlog_info("Sender authenticated.");
361 if (proto_recv(conn, rnd, sizeof(rnd)) == -1) {
362 pjdlog_errno(LOG_ERR, "Unable to receive challenge from %s",
363 adhost->adh_remoteaddr);
366 pjdlog_debug(1, "Challenge received.");
368 if (HMAC(EVP_sha256(), adhost->adh_password,
369 (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash,
371 pjdlog_error("Unable to generate response.");
374 pjdlog_debug(1, "Response generated.");
376 if (proto_send(conn, hash, sizeof(hash)) == -1) {
377 pjdlog_errno(LOG_ERR, "Unable to send response to %s",
378 adhost->adh_remoteaddr);
381 pjdlog_debug(1, "Response sent.");
383 if (adhost->adh_worker_pid != 0) {
385 "Receiver process exists (pid=%u), stopping it.",
386 (unsigned int)adhost->adh_worker_pid);
387 /* Stop child process. */
388 if (kill(adhost->adh_worker_pid, SIGINT) == -1) {
389 pjdlog_errno(LOG_ERR,
390 "Unable to stop worker process (pid=%u)",
391 (unsigned int)adhost->adh_worker_pid);
393 * Other than logging the problem we
394 * ignore it - nothing smart to do.
397 /* Wait for it to exit. */
398 else if ((pid = waitpid(adhost->adh_worker_pid,
399 &status, 0)) != adhost->adh_worker_pid) {
400 /* We can only log the problem. */
401 pjdlog_errno(LOG_ERR,
402 "Waiting for worker process (pid=%u) failed",
403 (unsigned int)adhost->adh_worker_pid);
405 child_exit_log("Worker", adhost->adh_worker_pid,
408 child_cleanup(adhost);
411 adhost->adh_remote = conn;
412 adist_receiver(adcfg, adhost);
414 pjdlog_prefix_set("%s", "");
418 pjdlog_prefix_set("%s", "");
422 connection_migrate(struct adist_host *adhost)
424 struct proto_conn *conn;
427 pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name,
428 role2str(adhost->adh_role));
430 PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER);
432 if (proto_recv(adhost->adh_conn, &val, sizeof(val)) < 0) {
433 pjdlog_errno(LOG_WARNING,
434 "Unable to receive connection command");
437 if (proto_set("tls:fingerprint", adhost->adh_fingerprint) == -1) {
439 pjdlog_errno(LOG_WARNING, "Unable to set fingerprint");
442 if (proto_connect(adhost->adh_localaddr[0] != '\0' ?
443 adhost->adh_localaddr : NULL,
444 adhost->adh_remoteaddr, -1, &conn) < 0) {
446 pjdlog_errno(LOG_WARNING, "Unable to connect to %s",
447 adhost->adh_remoteaddr);
452 if (proto_send(adhost->adh_conn, &val, sizeof(val)) < 0) {
453 pjdlog_errno(LOG_WARNING,
454 "Unable to send reply to connection request");
456 if (val == 0 && proto_connection_send(adhost->adh_conn, conn) < 0)
457 pjdlog_errno(LOG_WARNING, "Unable to send connection");
459 pjdlog_prefix_set("%s", "");
465 struct timespec sigtimeout;
469 sigtimeout.tv_sec = 0;
470 sigtimeout.tv_nsec = 0;
472 PJDLOG_VERIFY(sigemptyset(&mask) == 0);
473 PJDLOG_VERIFY(sigaddset(&mask, SIGHUP) == 0);
474 PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0);
475 PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0);
476 PJDLOG_VERIFY(sigaddset(&mask, SIGCHLD) == 0);
478 while ((signo = sigtimedwait(&mask, NULL, &sigtimeout)) != -1) {
482 sigexit_received = true;
493 PJDLOG_ABORT("Unexpected signal (%d).", signo);
501 struct adist_host *adhost;
502 struct adist_listen *lst;
503 struct timeval seltimeout;
507 seltimeout.tv_sec = SIGNALS_CHECK_INTERVAL;
508 seltimeout.tv_usec = 0;
510 pjdlog_info("Started successfully.");
515 /* Setup descriptors for select(2). */
518 TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
519 if (lst->adl_conn == NULL)
521 fd = proto_descriptor(lst->adl_conn);
522 PJDLOG_ASSERT(fd >= 0);
524 maxfd = fd > maxfd ? fd : maxfd;
526 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
527 if (adhost->adh_role == ADIST_ROLE_SENDER) {
528 /* Only sender workers asks for connections. */
529 PJDLOG_ASSERT(adhost->adh_conn != NULL);
530 fd = proto_descriptor(adhost->adh_conn);
531 PJDLOG_ASSERT(fd >= 0);
533 maxfd = fd > maxfd ? fd : maxfd;
535 PJDLOG_ASSERT(adhost->adh_conn == NULL);
539 PJDLOG_ASSERT(maxfd + 1 <= (int)FD_SETSIZE);
540 ret = select(maxfd + 1, &rfds, NULL, NULL, &seltimeout);
543 * select(2) timed out, so there should be no
544 * descriptors to check.
547 } else if (ret == -1) {
550 KEEP_ERRNO((void)pidfile_remove(pfh));
551 pjdlog_exit(EX_OSERR, "select() failed");
553 PJDLOG_ASSERT(ret > 0);
556 * Check for signals before we do anything to update our
557 * info about terminated workers in the meantime.
561 TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
562 if (lst->adl_conn == NULL)
564 if (FD_ISSET(proto_descriptor(lst->adl_conn), &rfds))
567 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
568 if (adhost->adh_role == ADIST_ROLE_SENDER) {
569 PJDLOG_ASSERT(adhost->adh_conn != NULL);
570 if (FD_ISSET(proto_descriptor(adhost->adh_conn),
572 connection_migrate(adhost);
575 PJDLOG_ASSERT(adhost->adh_conn == NULL);
582 adist_config_dump(struct adist_config *cfg)
584 struct adist_host *adhost;
585 struct adist_listen *lst;
587 pjdlog_debug(2, "Configuration:");
588 pjdlog_debug(2, " Global:");
589 pjdlog_debug(2, " pidfile: %s", cfg->adc_pidfile);
590 pjdlog_debug(2, " timeout: %d", cfg->adc_timeout);
591 if (TAILQ_EMPTY(&cfg->adc_listen)) {
592 pjdlog_debug(2, " Sender only, not listening.");
594 pjdlog_debug(2, " Listening on:");
595 TAILQ_FOREACH(lst, &cfg->adc_listen, adl_next) {
596 pjdlog_debug(2, " listen: %s", lst->adl_addr);
597 pjdlog_debug(2, " conn: %p", lst->adl_conn);
600 pjdlog_debug(2, " Hosts:");
601 TAILQ_FOREACH(adhost, &cfg->adc_hosts, adh_next) {
602 pjdlog_debug(2, " name: %s", adhost->adh_name);
603 pjdlog_debug(2, " role: %s", role2str(adhost->adh_role));
604 pjdlog_debug(2, " version: %d", adhost->adh_version);
605 pjdlog_debug(2, " localaddr: %s", adhost->adh_localaddr);
606 pjdlog_debug(2, " remoteaddr: %s", adhost->adh_remoteaddr);
607 pjdlog_debug(2, " remote: %p", adhost->adh_remote);
608 pjdlog_debug(2, " directory: %s", adhost->adh_directory);
609 pjdlog_debug(2, " compression: %d", adhost->adh_compression);
610 pjdlog_debug(2, " checksum: %d", adhost->adh_checksum);
611 pjdlog_debug(2, " pid: %ld", (long)adhost->adh_worker_pid);
612 pjdlog_debug(2, " conn: %p", adhost->adh_conn);
617 dummy_sighandler(int sig __unused)
623 main(int argc, char *argv[])
625 struct adist_host *adhost;
626 struct adist_listen *lst;
627 const char *execpath, *pidfile;
628 bool foreground, launchd;
634 if (execpath[0] != '/') {
636 "auditdistd requires execution with an absolute path.");
640 * We are executed from proto to create sandbox.
642 if (argc > 1 && strcmp(argv[1], "proto") == 0) {
645 if (proto_exec(argc, argv) == -1)
646 err(EX_USAGE, "Unable to execute proto");
657 ch = getopt(argc, argv, "c:dFhlP:");
684 pjdlog_init(PJDLOG_MODE_STD);
685 pjdlog_debug_set(debuglevel);
687 if (proto_set("execpath", execpath) == -1)
688 pjdlog_exit(EX_TEMPFAIL, "Unable to set executable name");
689 if (proto_set("user", ADIST_USER) == -1)
690 pjdlog_exit(EX_TEMPFAIL, "Unable to set proto user");
691 if (proto_set("tcp:port", ADIST_TCP_PORT) == -1)
692 pjdlog_exit(EX_TEMPFAIL, "Unable to set default TCP port");
695 * When path to the configuration file is relative, obtain full path,
696 * so we can always find the file, even after daemonizing and changing
697 * working directory to /.
699 if (cfgpath[0] != '/') {
700 const char *newcfgpath;
702 newcfgpath = realpath(cfgpath, NULL);
703 if (newcfgpath == NULL) {
704 pjdlog_exit(EX_CONFIG,
705 "Unable to obtain full path of %s", cfgpath);
707 cfgpath = newcfgpath;
710 adcfg = yy_config_parse(cfgpath, true);
711 PJDLOG_ASSERT(adcfg != NULL);
712 adist_config_dump(adcfg);
714 if (proto_set("tls:certfile", adcfg->adc_certfile) == -1)
715 pjdlog_exit(EX_TEMPFAIL, "Unable to set certfile path");
716 if (proto_set("tls:keyfile", adcfg->adc_keyfile) == -1)
717 pjdlog_exit(EX_TEMPFAIL, "Unable to set keyfile path");
719 if (pidfile != NULL) {
720 if (strlcpy(adcfg->adc_pidfile, pidfile,
721 sizeof(adcfg->adc_pidfile)) >=
722 sizeof(adcfg->adc_pidfile)) {
723 pjdlog_exitx(EX_CONFIG, "Pidfile path is too long.");
726 if (foreground && pidfile == NULL) {
729 pfh = pidfile_open(adcfg->adc_pidfile, 0600, &otherpid);
731 if (errno == EEXIST) {
732 pjdlog_exitx(EX_TEMPFAIL,
733 "Another auditdistd is already running, pid: %jd.",
737 * If we cannot create pidfile from other reasons,
740 pjdlog_errno(LOG_WARNING,
741 "Unable to open or create pidfile %s",
747 * Restore default actions for interesting signals in case parent
748 * process (like init(8)) decided to ignore some of them (like SIGHUP).
750 PJDLOG_VERIFY(signal(SIGHUP, SIG_DFL) != SIG_ERR);
751 PJDLOG_VERIFY(signal(SIGINT, SIG_DFL) != SIG_ERR);
752 PJDLOG_VERIFY(signal(SIGTERM, SIG_DFL) != SIG_ERR);
754 * Because SIGCHLD is ignored by default, setup dummy handler for it,
757 PJDLOG_VERIFY(signal(SIGCHLD, dummy_sighandler) != SIG_ERR);
759 PJDLOG_VERIFY(sigemptyset(&mask) == 0);
760 PJDLOG_VERIFY(sigaddset(&mask, SIGHUP) == 0);
761 PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0);
762 PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0);
763 PJDLOG_VERIFY(sigaddset(&mask, SIGCHLD) == 0);
764 PJDLOG_VERIFY(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
766 /* Listen for remote connections. */
767 TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) {
768 if (proto_server(lst->adl_addr, &lst->adl_conn) == -1) {
769 KEEP_ERRNO((void)pidfile_remove(pfh));
770 pjdlog_exit(EX_OSERR, "Unable to listen on address %s",
776 if (!launchd && daemon(0, 0) == -1) {
777 KEEP_ERRNO((void)pidfile_remove(pfh));
778 pjdlog_exit(EX_OSERR, "Unable to daemonize");
781 /* Start logging to syslog. */
782 pjdlog_mode_set(PJDLOG_MODE_SYSLOG);
785 /* Write PID to a file. */
786 if (pidfile_write(pfh) < 0) {
787 pjdlog_errno(LOG_WARNING,
788 "Unable to write PID to a file");
792 TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) {
793 if (adhost->adh_role == ADIST_ROLE_SENDER)
794 adist_sender(adcfg, adhost);