1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Zbigniew Jędrzejewski-Szmek
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/prctl.h>
28 #include <sys/socket.h>
30 #include <sys/types.h>
34 #include "sd-daemon.h"
35 #include "journal-file.h"
36 #include "journald-native.h"
37 #include "socket-util.h"
43 #include "conf-parser.h"
44 #include "siphash24.h"
47 #include <gnutls/gnutls.h>
50 #include "journal-remote.h"
51 #include "journal-remote-write.h"
53 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
55 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
56 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
57 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
59 static char* arg_url = NULL;
60 static char* arg_getter = NULL;
61 static char* arg_listen_raw = NULL;
62 static char* arg_listen_http = NULL;
63 static char* arg_listen_https = NULL;
64 static char** arg_files = NULL;
65 static int arg_compress = true;
66 static int arg_seal = false;
67 static int http_socket = -1, https_socket = -1;
68 static char** arg_gnutls_log = NULL;
70 static JournalWriteSplitMode arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
71 static char* arg_output = NULL;
73 static char *arg_key = NULL;
74 static char *arg_cert = NULL;
75 static char *arg_trust = NULL;
76 static bool arg_trust_all = false;
78 /**********************************************************************
79 **********************************************************************
80 **********************************************************************/
82 static int spawn_child(const char* child, char** argv) {
84 pid_t parent_pid, child_pid;
88 log_error("Failed to create pager pipe: %m");
92 parent_pid = getpid();
97 log_error("Failed to fork: %m");
103 if (child_pid == 0) {
104 r = dup2(fd[1], STDOUT_FILENO);
106 log_error("Failed to dup pipe to stdout: %m");
112 /* Make sure the child goes away when the parent dies */
113 if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
116 /* Check whether our parent died before we were able
117 * to set the death signal */
118 if (getppid() != parent_pid)
122 log_error("Failed to exec child %s: %m", child);
128 log_warning("Failed to close write end of pipe: %m");
133 static int spawn_curl(const char* url) {
134 char **argv = STRV_MAKE("curl",
135 "-HAccept: application/vnd.fdo.journal",
141 r = spawn_child("curl", argv);
143 log_error("Failed to spawn curl: %m");
147 static int spawn_getter(const char *getter, const char *url) {
149 _cleanup_strv_free_ char **words = NULL;
152 r = strv_split_quoted(&words, getter);
154 log_error("Failed to split getter option: %s", strerror(-r));
158 r = strv_extend(&words, url);
160 log_error("Failed to create command line: %s", strerror(-r));
164 r = spawn_child(words[0], words);
166 log_error("Failed to spawn getter %s: %m", getter);
171 #define filename_escape(s) xescape((s), "/ ")
173 static int open_output(Writer *w, const char* host) {
174 _cleanup_free_ char *_output = NULL;
178 switch (arg_split_mode) {
179 case JOURNAL_WRITE_SPLIT_NONE:
180 output = arg_output ?: REMOTE_JOURNAL_PATH "/remote.journal";
183 case JOURNAL_WRITE_SPLIT_HOST: {
184 _cleanup_free_ char *name;
188 name = filename_escape(host);
192 r = asprintf(&_output, "%s/remote-%s.journal",
193 arg_output ?: REMOTE_JOURNAL_PATH,
203 assert_not_reached("what?");
206 r = journal_file_open_reliably(output,
207 O_RDWR|O_CREAT, 0640,
208 arg_compress, arg_seal,
213 log_error("Failed to open output journal %s: %s",
214 output, strerror(-r));
216 log_info("Opened output file %s", w->journal->path);
220 /**********************************************************************
221 **********************************************************************
222 **********************************************************************/
224 static int init_writer_hashmap(RemoteServer *s) {
225 static const struct hash_ops *hash_ops[] = {
226 [JOURNAL_WRITE_SPLIT_NONE] = NULL,
227 [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
230 assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(hash_ops));
232 s->writers = hashmap_new(hash_ops[arg_split_mode]);
239 static int get_writer(RemoteServer *s, const char *host,
242 _cleanup_writer_unref_ Writer *w = NULL;
245 switch(arg_split_mode) {
246 case JOURNAL_WRITE_SPLIT_NONE:
247 key = "one and only";
250 case JOURNAL_WRITE_SPLIT_HOST:
256 assert_not_reached("what split mode?");
259 w = hashmap_get(s->writers, key);
267 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
268 w->hashmap_key = strdup(key);
273 r = open_output(w, host);
277 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
287 /**********************************************************************
288 **********************************************************************
289 **********************************************************************/
291 /* This should go away as soon as µhttpd allows state to be passed around. */
292 static RemoteServer *server;
294 static int dispatch_raw_source_event(sd_event_source *event,
298 static int dispatch_blocking_source_event(sd_event_source *event,
300 static int dispatch_raw_connection_event(sd_event_source *event,
304 static int dispatch_http_event(sd_event_source *event,
309 static int get_source_for_fd(RemoteServer *s,
310 int fd, char *name, RemoteSource **source) {
314 /* This takes ownership of name, but only on success. */
319 if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
322 r = get_writer(s, name, &writer);
324 log_warning("Failed to get writer for source %s: %s",
329 if (s->sources[fd] == NULL) {
330 s->sources[fd] = source_new(fd, false, name, writer);
331 if (!s->sources[fd]) {
332 writer_unref(writer);
339 *source = s->sources[fd];
343 static int remove_source(RemoteServer *s, int fd) {
344 RemoteSource *source;
347 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
349 source = s->sources[fd];
351 /* this closes fd too */
353 s->sources[fd] = NULL;
360 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
362 RemoteSource *source;
365 /* This takes ownership of name, even on failure, if own_name is true. */
377 r = get_source_for_fd(s, fd, name, &source);
379 log_error("Failed to create source for fd:%d (%s): %s",
380 fd, name, strerror(-r));
385 r = sd_event_add_io(s->events, &source->event,
386 fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
387 dispatch_raw_source_event, s);
389 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
390 r = sd_event_add_defer(s->events, &source->event,
391 dispatch_blocking_source_event, source);
393 sd_event_source_set_enabled(source->event, SD_EVENT_ON);
396 log_error("Failed to register event source for fd:%d: %s",
401 r = sd_event_source_set_name(source->event, name);
403 log_error("Failed to set source name for fd:%d: %s", fd, strerror(-r));
407 return 1; /* work to do */
410 remove_source(s, fd);
414 static int add_raw_socket(RemoteServer *s, int fd) {
416 _cleanup_close_ int fd_ = fd;
417 char name[strlen("raw-socket-") + DECIMAL_STR_MAX(int)];
421 r = sd_event_add_io(s->events, &s->listen_event,
423 dispatch_raw_connection_event, s);
427 snprintf(name, sizeof(name), "raw-socket-%d", fd);
429 r = sd_event_source_set_name(s->listen_event, name);
438 static int setup_raw_socket(RemoteServer *s, const char *address) {
441 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
445 return add_raw_socket(s, fd);
448 /**********************************************************************
449 **********************************************************************
450 **********************************************************************/
452 static int request_meta(void **connection_cls, int fd, char *hostname) {
453 RemoteSource *source;
457 assert(connection_cls);
461 r = get_writer(server, hostname, &writer);
463 log_warning("Failed to get writer for source %s: %s",
464 hostname, strerror(-r));
468 source = source_new(fd, true, hostname, writer);
470 writer_unref(writer);
474 log_debug("Added RemoteSource as connection metadata %p", source);
476 *connection_cls = source;
480 static void request_meta_free(void *cls,
481 struct MHD_Connection *connection,
482 void **connection_cls,
483 enum MHD_RequestTerminationCode toe) {
486 assert(connection_cls);
490 log_debug("Cleaning up connection metadata %p", s);
492 *connection_cls = NULL;
496 static int process_http_upload(
497 struct MHD_Connection *connection,
498 const char *upload_data,
499 size_t *upload_data_size,
500 RemoteSource *source) {
502 bool finished = false;
508 log_trace("%s: connection %p, %zu bytes",
509 __func__, connection, *upload_data_size);
511 if (*upload_data_size) {
512 log_trace("Received %zu bytes", *upload_data_size);
514 r = push_data(source, upload_data, *upload_data_size);
516 return mhd_respond_oom(connection);
518 *upload_data_size = 0;
523 r = process_source(source, arg_compress, arg_seal);
524 if (r == -EAGAIN || r == -EWOULDBLOCK)
527 log_warning("Failed to process data for connection %p", connection);
529 return mhd_respondf(connection,
530 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
531 "Entry is too large, maximum is %u bytes.\n",
534 return mhd_respondf(connection,
535 MHD_HTTP_UNPROCESSABLE_ENTITY,
536 "Processing failed: %s.", strerror(-r));
543 /* The upload is finished */
545 remaining = source_non_empty(source);
547 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
548 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
549 "Premature EOF. %zu bytes of trailing data not processed.",
553 return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
556 static int request_handler(
558 struct MHD_Connection *connection,
562 const char *upload_data,
563 size_t *upload_data_size,
564 void **connection_cls) {
568 _cleanup_free_ char *hostname = NULL;
571 assert(connection_cls);
575 log_trace("Handling a connection %s %s %s", method, url, version);
578 return process_http_upload(connection,
579 upload_data, upload_data_size,
582 if (!streq(method, "POST"))
583 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
584 "Unsupported method.\n");
586 if (!streq(url, "/upload"))
587 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
590 header = MHD_lookup_connection_value(connection,
591 MHD_HEADER_KIND, "Content-Type");
592 if (!header || !streq(header, "application/vnd.fdo.journal"))
593 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
594 "Content-Type: application/vnd.fdo.journal"
598 const union MHD_ConnectionInfo *ci;
600 ci = MHD_get_connection_info(connection,
601 MHD_CONNECTION_INFO_CONNECTION_FD);
603 log_error("MHD_get_connection_info failed: cannot get remote fd");
604 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
605 "Cannot check remote address");
612 if (server->check_trust) {
613 r = check_permissions(connection, &code, &hostname);
617 r = getnameinfo_pretty(fd, &hostname);
619 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
620 "Cannot check remote hostname");
626 r = request_meta(connection_cls, fd, hostname);
628 return respond_oom(connection);
630 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
637 static int setup_microhttpd_server(RemoteServer *s,
642 struct MHD_OptionItem opts[] = {
643 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
644 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
645 { MHD_OPTION_LISTEN_SOCKET, fd},
653 MHD_USE_PEDANTIC_CHECKS |
654 MHD_USE_EPOLL_LINUX_ONLY |
657 const union MHD_DaemonInfo *info;
663 r = fd_nonblock(fd, true);
665 log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
672 opts[opts_pos++] = (struct MHD_OptionItem)
673 {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
674 opts[opts_pos++] = (struct MHD_OptionItem)
675 {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
677 flags |= MHD_USE_SSL;
680 opts[opts_pos++] = (struct MHD_OptionItem)
681 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
684 d = new(MHDDaemonWrapper, 1);
688 d->fd = (uint64_t) fd;
690 d->daemon = MHD_start_daemon(flags, 0,
692 request_handler, NULL,
693 MHD_OPTION_ARRAY, opts,
696 log_error("Failed to start µhttp daemon");
701 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
702 key ? "HTTPS" : "HTTP", fd, d);
705 info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
707 log_error("µhttp returned NULL daemon info");
712 epoll_fd = info->listen_fd;
714 log_error("µhttp epoll fd is invalid");
719 r = sd_event_add_io(s->events, &d->event,
721 dispatch_http_event, d);
723 log_error("Failed to add event callback: %s", strerror(-r));
727 r = sd_event_source_set_name(d->event, "epoll-fd");
729 log_error("Failed to set source name: %s", strerror(-r));
733 r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
739 r = hashmap_put(s->daemons, &d->fd, d);
741 log_error("Failed to add daemon to hashmap: %s", strerror(-r));
749 MHD_stop_daemon(d->daemon);
755 static int setup_microhttpd_socket(RemoteServer *s,
762 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
766 return setup_microhttpd_server(s, fd, key, cert, trust);
769 static int dispatch_http_event(sd_event_source *event,
773 MHDDaemonWrapper *d = userdata;
778 r = MHD_run(d->daemon);
780 log_error("MHD_run failed!");
781 // XXX: unregister daemon
785 return 1; /* work to do */
788 /**********************************************************************
789 **********************************************************************
790 **********************************************************************/
792 static int setup_signals(RemoteServer *s) {
798 assert_se(sigemptyset(&mask) == 0);
799 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
800 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
802 r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
806 r = sd_event_source_set_name(s->sigterm_event, "sigterm");
810 r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
814 r = sd_event_source_set_name(s->sigint_event, "sigint");
821 static int negative_fd(const char *spec) {
822 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
826 r = safe_atoi(spec, &fd);
836 static int remoteserver_init(RemoteServer *s,
845 if ((arg_listen_raw || arg_listen_http) && trust) {
846 log_error("Option --trust makes all non-HTTPS connections untrusted.");
850 r = sd_event_default(&s->events);
852 log_error("Failed to allocate event loop: %s", strerror(-r));
858 assert(server == NULL);
861 r = init_writer_hashmap(s);
865 n = sd_listen_fds(true);
867 log_error("Failed to read listening file descriptors from environment: %s",
871 log_info("Received %d descriptors", n);
873 if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
874 log_error("Received fewer sockets than expected");
878 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
879 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
880 log_info("Received a listening socket (fd:%d)", fd);
882 if (fd == http_socket)
883 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
884 else if (fd == https_socket)
885 r = setup_microhttpd_server(s, fd, key, cert, trust);
887 r = add_raw_socket(s, fd);
888 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
891 r = getnameinfo_pretty(fd, &hostname);
893 log_error("Failed to retrieve remote name: %s", strerror(-r));
897 log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
899 r = add_source(s, fd, hostname, true);
901 log_error("Unknown socket passed on fd:%d", fd);
907 log_error("Failed to register socket (fd:%d): %s",
914 const char *url, *hostname;
916 url = strappenda(arg_url, "/entries");
919 log_info("Spawning getter %s...", url);
920 fd = spawn_getter(arg_getter, url);
922 log_info("Spawning curl %s...", url);
923 fd = spawn_curl(url);
929 startswith(arg_url, "https://") ?:
930 startswith(arg_url, "http://") ?:
933 r = add_source(s, fd, (char*) hostname, false);
938 if (arg_listen_raw) {
939 log_info("Listening on a socket...");
940 r = setup_raw_socket(s, arg_listen_raw);
945 if (arg_listen_http) {
946 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
951 if (arg_listen_https) {
952 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
957 STRV_FOREACH(file, arg_files) {
958 const char *output_name;
960 if (streq(*file, "-")) {
961 log_info("Using standard input as source.");
964 output_name = "stdin";
966 log_info("Reading file %s...", *file);
968 fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
970 log_error("Failed to open %s: %m", *file);
976 r = add_source(s, fd, (char*) output_name, false);
981 if (s->active == 0) {
982 log_error("Zarro sources specified");
986 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
987 /* In this case we know what the writer will be
988 called, so we can create it and verify that we can
989 create output as expected. */
990 r = get_writer(s, NULL, &s->_single_writer);
998 static void server_destroy(RemoteServer *s) {
1000 MHDDaemonWrapper *d;
1002 while ((d = hashmap_steal_first(s->daemons))) {
1003 MHD_stop_daemon(d->daemon);
1004 sd_event_source_unref(d->event);
1008 hashmap_free(s->daemons);
1010 assert(s->sources_size == 0 || s->sources);
1011 for (i = 0; i < s->sources_size; i++)
1012 remove_source(s, i);
1015 writer_unref(s->_single_writer);
1016 hashmap_free(s->writers);
1018 sd_event_source_unref(s->sigterm_event);
1019 sd_event_source_unref(s->sigint_event);
1020 sd_event_source_unref(s->listen_event);
1021 sd_event_unref(s->events);
1023 /* fds that we're listening on remain open... */
1026 /**********************************************************************
1027 **********************************************************************
1028 **********************************************************************/
1030 static int dispatch_raw_source_event(sd_event_source *event,
1035 RemoteServer *s = userdata;
1036 RemoteSource *source;
1039 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1040 source = s->sources[fd];
1041 assert(source->fd == fd);
1043 r = process_source(source, arg_compress, arg_seal);
1044 if (source->state == STATE_EOF) {
1047 log_info("EOF reached with source fd:%d (%s)",
1048 source->fd, source->name);
1050 remaining = source_non_empty(source);
1052 log_warning("Premature EOF. %zu bytes lost.", remaining);
1053 remove_source(s, source->fd);
1054 log_info("%zd active sources remaining", s->active);
1056 } else if (r == -E2BIG) {
1057 log_error("Entry too big, skipped");
1059 } else if (r == -EAGAIN) {
1062 log_info("Closing connection: %s", strerror(-r));
1063 remove_source(server, fd);
1069 static int dispatch_blocking_source_event(sd_event_source *event,
1071 RemoteSource *source = userdata;
1073 return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
1076 static int accept_connection(const char* type, int fd,
1077 SocketAddress *addr, char **hostname) {
1080 log_debug("Accepting new %s connection on fd:%d", type, fd);
1081 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1083 log_error("accept() on fd:%d failed: %m", fd);
1087 switch(socket_address_family(addr)) {
1090 _cleanup_free_ char *a = NULL;
1093 r = socket_address_print(addr, &a);
1095 log_error("socket_address_print(): %s", strerror(-r));
1100 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1106 log_info("Accepted %s %s connection from %s",
1108 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1116 log_error("Rejected %s connection with unsupported family %d",
1117 type, socket_address_family(addr));
1124 static int dispatch_raw_connection_event(sd_event_source *event,
1128 RemoteServer *s = userdata;
1130 SocketAddress addr = {
1131 .size = sizeof(union sockaddr_union),
1132 .type = SOCK_STREAM,
1136 fd2 = accept_connection("raw", fd, &addr, &hostname);
1140 return add_source(s, fd2, hostname, true);
1143 /**********************************************************************
1144 **********************************************************************
1145 **********************************************************************/
1147 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1148 [JOURNAL_WRITE_SPLIT_NONE] = "none",
1149 [JOURNAL_WRITE_SPLIT_HOST] = "host",
1152 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1153 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1154 journal_write_split_mode,
1155 JournalWriteSplitMode,
1156 "Failed to parse split mode setting");
1158 static int parse_config(void) {
1159 const ConfigTableItem items[] = {
1160 { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
1161 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
1162 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
1163 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
1166 return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
1168 config_item_table_lookup, items,
1169 false, false, true, NULL);
1172 static void help(void) {
1173 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1174 "Write external journal events to journal file(s).\n\n"
1175 " -h --help Show this help\n"
1176 " --version Show package version\n"
1177 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1178 " --getter=COMMAND Read events from the output of COMMAND\n"
1179 " --listen-raw=ADDR Listen for connections at ADDR\n"
1180 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1181 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1182 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1183 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1184 " --seal[=BOOL] Use event sealing (default: no)\n"
1185 " --key=FILENAME SSL key in PEM format (default:\n"
1186 " \"" PRIV_KEY_FILE "\")\n"
1187 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1188 " \"" CERT_FILE "\")\n"
1189 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1190 " \"" TRUST_FILE "\")\n"
1191 " --gnutls-log=CATEGORY...\n"
1192 " Specify a list of gnutls logging categories\n"
1193 " --split-mode=none|host How many output files to create\n"
1195 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1196 , program_invocation_short_name);
1199 static int parse_argv(int argc, char *argv[]) {
1201 ARG_VERSION = 0x100,
1216 static const struct option options[] = {
1217 { "help", no_argument, NULL, 'h' },
1218 { "version", no_argument, NULL, ARG_VERSION },
1219 { "url", required_argument, NULL, ARG_URL },
1220 { "getter", required_argument, NULL, ARG_GETTER },
1221 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1222 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1223 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1224 { "output", required_argument, NULL, 'o' },
1225 { "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
1226 { "compress", optional_argument, NULL, ARG_COMPRESS },
1227 { "seal", optional_argument, NULL, ARG_SEAL },
1228 { "key", required_argument, NULL, ARG_KEY },
1229 { "cert", required_argument, NULL, ARG_CERT },
1230 { "trust", required_argument, NULL, ARG_TRUST },
1231 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1236 bool type_a, type_b;
1241 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1245 return 0 /* done */;
1248 puts(PACKAGE_STRING);
1249 puts(SYSTEMD_FEATURES);
1250 return 0 /* done */;
1254 log_error("cannot currently set more than one --url");
1263 log_error("cannot currently use --getter more than once");
1267 arg_getter = optarg;
1270 case ARG_LISTEN_RAW:
1271 if (arg_listen_raw) {
1272 log_error("cannot currently use --listen-raw more than once");
1276 arg_listen_raw = optarg;
1279 case ARG_LISTEN_HTTP:
1280 if (arg_listen_http || http_socket >= 0) {
1281 log_error("cannot currently use --listen-http more than once");
1285 r = negative_fd(optarg);
1289 arg_listen_http = optarg;
1292 case ARG_LISTEN_HTTPS:
1293 if (arg_listen_https || https_socket >= 0) {
1294 log_error("cannot currently use --listen-https more than once");
1298 r = negative_fd(optarg);
1302 arg_listen_https = optarg;
1308 log_error("Key file specified twice");
1312 arg_key = strdup(optarg);
1320 log_error("Certificate file specified twice");
1324 arg_cert = strdup(optarg);
1331 if (arg_trust || arg_trust_all) {
1332 log_error("Confusing trusted CA configuration");
1336 if (streq(optarg, "all"))
1337 arg_trust_all = true;
1340 arg_trust = strdup(optarg);
1344 log_error("Option --trust is not available.");
1353 log_error("cannot use --output/-o more than once");
1357 arg_output = optarg;
1360 case ARG_SPLIT_MODE:
1361 arg_split_mode = journal_write_split_mode_from_string(optarg);
1362 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1363 log_error("Invalid split mode: %s", optarg);
1370 r = parse_boolean(optarg);
1372 log_error("Failed to parse --compress= parameter.");
1378 arg_compress = true;
1384 r = parse_boolean(optarg);
1386 log_error("Failed to parse --seal= parameter.");
1396 case ARG_GNUTLS_LOG: {
1398 const char *word, *state;
1401 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1404 cat = strndup(word, size);
1408 if (strv_consume(&arg_gnutls_log, cat) < 0)
1413 log_error("Option --gnutls-log is not available.");
1422 assert_not_reached("Unknown option code.");
1426 arg_files = argv + optind;
1428 type_a = arg_getter || !strv_isempty(arg_files);
1431 || arg_listen_http || arg_listen_https
1432 || sd_listen_fds(false) > 0;
1433 if (type_a && type_b) {
1434 log_error("Cannot use file input or --getter with "
1435 "--arg-listen-... or socket activation.");
1440 log_error("Option --output must be specified with file input or --getter.");
1444 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1447 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1448 && arg_output && is_dir(arg_output, true) > 0) {
1449 log_error("For SplitMode=none, output must be a file.");
1453 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1454 && arg_output && is_dir(arg_output, true) <= 0) {
1455 log_error("For SplitMode=host, output must be a directory.");
1459 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1460 journal_write_split_mode_to_string(arg_split_mode),
1465 return 1 /* work to do */;
1468 static int load_certificates(char **key, char **cert, char **trust) {
1471 r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1473 log_error("Failed to read key from file '%s': %s",
1474 arg_key ?: PRIV_KEY_FILE, strerror(-r));
1478 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1480 log_error("Failed to read certificate from file '%s': %s",
1481 arg_cert ?: CERT_FILE, strerror(-r));
1486 log_info("Certificate checking disabled.");
1488 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1490 log_error("Failed to read CA certificate file '%s': %s",
1491 arg_trust ?: TRUST_FILE, strerror(-r));
1499 static int setup_gnutls_logger(char **categories) {
1500 if (!arg_listen_http && !arg_listen_https)
1508 gnutls_global_set_log_function(log_func_gnutls);
1511 STRV_FOREACH(cat, categories) {
1512 r = log_enable_gnutls_category(*cat);
1517 log_reset_gnutls_level();
1524 int main(int argc, char **argv) {
1525 RemoteServer s = {};
1527 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1529 log_show_color(true);
1530 log_parse_environment();
1534 return EXIT_FAILURE;
1536 r = parse_argv(argc, argv);
1538 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1540 r = setup_gnutls_logger(arg_gnutls_log);
1542 return EXIT_FAILURE;
1544 if (arg_listen_https || https_socket >= 0)
1545 if (load_certificates(&key, &cert, &trust) < 0)
1546 return EXIT_FAILURE;
1548 if (remoteserver_init(&s, key, cert, trust) < 0)
1549 return EXIT_FAILURE;
1551 r = sd_event_set_watchdog(s.events, true);
1553 log_error("Failed to enable watchdog: %s", strerror(-r));
1555 log_debug("Watchdog is %s.", r > 0 ? "enabled" : "disabled");
1557 log_debug("%s running as pid "PID_FMT,
1558 program_invocation_short_name, getpid());
1561 "STATUS=Processing requests...");
1564 r = sd_event_get_state(s.events);
1567 if (r == SD_EVENT_FINISHED)
1570 r = sd_event_run(s.events, -1);
1572 log_error("Failed to run event loop: %s", strerror(-r));
1579 "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1580 log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1588 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;