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 return 1; /* work to do */
404 remove_source(s, fd);
408 static int add_raw_socket(RemoteServer *s, int fd) {
411 r = sd_event_add_io(s->events, &s->listen_event,
413 dispatch_raw_connection_event, s);
423 static int setup_raw_socket(RemoteServer *s, const char *address) {
426 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
430 return add_raw_socket(s, fd);
433 /**********************************************************************
434 **********************************************************************
435 **********************************************************************/
437 static RemoteSource *request_meta(void **connection_cls, int fd, char *hostname) {
438 RemoteSource *source;
442 assert(connection_cls);
444 return *connection_cls;
446 r = get_writer(server, hostname, &writer);
448 log_warning("Failed to get writer for source %s: %s",
449 hostname, strerror(-r));
453 source = source_new(fd, true, hostname, writer);
456 writer_unref(writer);
460 log_debug("Added RemoteSource as connection metadata %p", source);
462 *connection_cls = source;
466 static void request_meta_free(void *cls,
467 struct MHD_Connection *connection,
468 void **connection_cls,
469 enum MHD_RequestTerminationCode toe) {
472 assert(connection_cls);
475 log_debug("Cleaning up connection metadata %p", s);
477 *connection_cls = NULL;
480 static int process_http_upload(
481 struct MHD_Connection *connection,
482 const char *upload_data,
483 size_t *upload_data_size,
484 RemoteSource *source) {
486 bool finished = false;
492 log_debug("request_handler_upload: connection %p, %zu bytes",
493 connection, *upload_data_size);
495 if (*upload_data_size) {
496 log_debug("Received %zu bytes", *upload_data_size);
498 r = push_data(source, upload_data, *upload_data_size);
500 return mhd_respond_oom(connection);
502 *upload_data_size = 0;
507 r = process_source(source, arg_compress, arg_seal);
508 if (r == -EAGAIN || r == -EWOULDBLOCK)
511 log_warning("Failed to process data for connection %p", connection);
513 return mhd_respondf(connection,
514 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
515 "Entry is too large, maximum is %u bytes.\n",
518 return mhd_respondf(connection,
519 MHD_HTTP_UNPROCESSABLE_ENTITY,
520 "Processing failed: %s.", strerror(-r));
527 /* The upload is finished */
529 remaining = source_non_empty(source);
531 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
532 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
533 "Premature EOF. %zu bytes of trailing data not processed.",
537 return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
540 static int request_handler(
542 struct MHD_Connection *connection,
546 const char *upload_data,
547 size_t *upload_data_size,
548 void **connection_cls) {
552 _cleanup_free_ char *hostname = NULL;
555 assert(connection_cls);
559 log_debug("Handling a connection %s %s %s", method, url, version);
562 return process_http_upload(connection,
563 upload_data, upload_data_size,
566 if (!streq(method, "POST"))
567 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
568 "Unsupported method.\n");
570 if (!streq(url, "/upload"))
571 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
574 header = MHD_lookup_connection_value(connection,
575 MHD_HEADER_KIND, "Content-Type");
576 if (!header || !streq(header, "application/vnd.fdo.journal"))
577 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
578 "Content-Type: application/vnd.fdo.journal"
582 const union MHD_ConnectionInfo *ci;
584 ci = MHD_get_connection_info(connection,
585 MHD_CONNECTION_INFO_CONNECTION_FD);
587 log_error("MHD_get_connection_info failed: cannot get remote fd");
588 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
589 "Cannot check remote address");
596 if (server->check_trust) {
597 r = check_permissions(connection, &code, &hostname);
601 r = getnameinfo_pretty(fd, &hostname);
603 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
604 "Cannot check remote hostname");
610 if (!request_meta(connection_cls, fd, hostname))
611 return respond_oom(connection);
616 static int setup_microhttpd_server(RemoteServer *s,
621 struct MHD_OptionItem opts[] = {
622 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
623 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
624 { MHD_OPTION_LISTEN_SOCKET, fd},
632 MHD_USE_PEDANTIC_CHECKS |
633 MHD_USE_EPOLL_LINUX_ONLY |
636 const union MHD_DaemonInfo *info;
642 r = fd_nonblock(fd, true);
644 log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
651 opts[opts_pos++] = (struct MHD_OptionItem)
652 {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
653 opts[opts_pos++] = (struct MHD_OptionItem)
654 {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
656 flags |= MHD_USE_SSL;
659 opts[opts_pos++] = (struct MHD_OptionItem)
660 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
663 d = new(MHDDaemonWrapper, 1);
667 d->fd = (uint64_t) fd;
669 d->daemon = MHD_start_daemon(flags, 0,
671 request_handler, NULL,
672 MHD_OPTION_ARRAY, opts,
675 log_error("Failed to start µhttp daemon");
680 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
681 key ? "HTTPS" : "HTTP", fd, d);
684 info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
686 log_error("µhttp returned NULL daemon info");
691 epoll_fd = info->listen_fd;
693 log_error("µhttp epoll fd is invalid");
698 r = sd_event_add_io(s->events, &d->event,
700 dispatch_http_event, d);
702 log_error("Failed to add event callback: %s", strerror(-r));
706 r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
712 r = hashmap_put(s->daemons, &d->fd, d);
714 log_error("Failed to add daemon to hashmap: %s", strerror(-r));
722 MHD_stop_daemon(d->daemon);
728 static int setup_microhttpd_socket(RemoteServer *s,
735 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
739 return setup_microhttpd_server(s, fd, key, cert, trust);
742 static int dispatch_http_event(sd_event_source *event,
746 MHDDaemonWrapper *d = userdata;
751 r = MHD_run(d->daemon);
753 log_error("MHD_run failed!");
754 // XXX: unregister daemon
758 return 1; /* work to do */
761 /**********************************************************************
762 **********************************************************************
763 **********************************************************************/
765 static int dispatch_sigterm(sd_event_source *event,
766 const struct signalfd_siginfo *si,
768 RemoteServer *s = userdata;
772 log_received_signal(LOG_INFO, si);
774 sd_event_exit(s->events, 0);
778 static int setup_signals(RemoteServer *s) {
784 assert_se(sigemptyset(&mask) == 0);
785 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
786 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
788 r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, dispatch_sigterm, s);
792 r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, dispatch_sigterm, s);
799 static int fd_fd(const char *spec) {
802 r = safe_atoi(spec, &fd);
811 static int remoteserver_init(RemoteServer *s,
820 if ((arg_listen_raw || arg_listen_http) && trust) {
821 log_error("Option --trust makes all non-HTTPS connections untrusted.");
825 r = sd_event_default(&s->events);
827 log_error("Failed to allocate event loop: %s", strerror(-r));
833 assert(server == NULL);
836 r = init_writer_hashmap(s);
840 n = sd_listen_fds(true);
842 log_error("Failed to read listening file descriptors from environment: %s",
846 log_info("Received %d descriptors", n);
848 if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
849 log_error("Received fewer sockets than expected");
853 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
854 if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
855 log_info("Received a listening socket (fd:%d)", fd);
857 if (fd == http_socket)
858 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
859 else if (fd == https_socket)
860 r = setup_microhttpd_server(s, fd, key, cert, trust);
862 r = add_raw_socket(s, fd);
863 } else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
866 r = getnameinfo_pretty(fd, &hostname);
868 log_error("Failed to retrieve remote name: %s", strerror(-r));
872 log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
874 r = add_source(s, fd, hostname, true);
876 log_error("Unknown socket passed on fd:%d", fd);
882 log_error("Failed to register socket (fd:%d): %s",
889 const char *url, *hostname;
891 url = strappenda(arg_url, "/entries");
894 log_info("Spawning getter %s...", url);
895 fd = spawn_getter(arg_getter, url);
897 log_info("Spawning curl %s...", url);
898 fd = spawn_curl(url);
904 startswith(arg_url, "https://") ?:
905 startswith(arg_url, "http://") ?:
908 r = add_source(s, fd, (char*) hostname, false);
913 if (arg_listen_raw) {
914 log_info("Listening on a socket...");
915 r = setup_raw_socket(s, arg_listen_raw);
920 if (arg_listen_http) {
921 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
926 if (arg_listen_https) {
927 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
932 STRV_FOREACH(file, arg_files) {
933 const char *output_name;
935 if (streq(*file, "-")) {
936 log_info("Using standard input as source.");
939 output_name = "stdin";
941 log_info("Reading file %s...", *file);
943 fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
945 log_error("Failed to open %s: %m", *file);
951 r = add_source(s, fd, (char*) output_name, false);
956 if (s->active == 0) {
957 log_error("Zarro sources specified");
961 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
962 /* In this case we know what the writer will be
963 called, so we can create it and verify that we can
964 create output as expected. */
965 r = get_writer(s, NULL, &s->_single_writer);
973 static void server_destroy(RemoteServer *s) {
977 while ((d = hashmap_steal_first(s->daemons))) {
978 MHD_stop_daemon(d->daemon);
979 sd_event_source_unref(d->event);
983 hashmap_free(s->daemons);
985 assert(s->sources_size == 0 || s->sources);
986 for (i = 0; i < s->sources_size; i++)
990 writer_unref(s->_single_writer);
991 hashmap_free(s->writers);
993 sd_event_source_unref(s->sigterm_event);
994 sd_event_source_unref(s->sigint_event);
995 sd_event_source_unref(s->listen_event);
996 sd_event_unref(s->events);
998 /* fds that we're listening on remain open... */
1001 /**********************************************************************
1002 **********************************************************************
1003 **********************************************************************/
1005 static int dispatch_raw_source_event(sd_event_source *event,
1010 RemoteServer *s = userdata;
1011 RemoteSource *source;
1014 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1015 source = s->sources[fd];
1016 assert(source->fd == fd);
1018 r = process_source(source, arg_compress, arg_seal);
1019 if (source->state == STATE_EOF) {
1022 log_info("EOF reached with source fd:%d (%s)",
1023 source->fd, source->name);
1025 remaining = source_non_empty(source);
1027 log_warning("Premature EOF. %zu bytes lost.", remaining);
1028 remove_source(s, source->fd);
1029 log_info("%zd active sources remaining", s->active);
1031 } else if (r == -E2BIG) {
1032 log_error("Entry too big, skipped");
1034 } else if (r == -EAGAIN) {
1037 log_info("Closing connection: %s", strerror(-r));
1038 remove_source(server, fd);
1044 static int dispatch_blocking_source_event(sd_event_source *event,
1046 RemoteSource *source = userdata;
1048 return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
1051 static int accept_connection(const char* type, int fd,
1052 SocketAddress *addr, char **hostname) {
1055 log_debug("Accepting new %s connection on fd:%d", type, fd);
1056 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1058 log_error("accept() on fd:%d failed: %m", fd);
1062 switch(socket_address_family(addr)) {
1065 _cleanup_free_ char *a = NULL;
1068 r = socket_address_print(addr, &a);
1070 log_error("socket_address_print(): %s", strerror(-r));
1075 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1081 log_info("Accepted %s %s connection from %s",
1083 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1091 log_error("Rejected %s connection with unsupported family %d",
1092 type, socket_address_family(addr));
1099 static int dispatch_raw_connection_event(sd_event_source *event,
1103 RemoteServer *s = userdata;
1105 SocketAddress addr = {
1106 .size = sizeof(union sockaddr_union),
1107 .type = SOCK_STREAM,
1111 fd2 = accept_connection("raw", fd, &addr, &hostname);
1115 return add_source(s, fd2, hostname, true);
1118 /**********************************************************************
1119 **********************************************************************
1120 **********************************************************************/
1122 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1123 [JOURNAL_WRITE_SPLIT_NONE] = "none",
1124 [JOURNAL_WRITE_SPLIT_HOST] = "host",
1127 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1128 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1129 journal_write_split_mode,
1130 JournalWriteSplitMode,
1131 "Failed to parse split mode setting");
1133 static int parse_config(void) {
1134 const ConfigTableItem items[] = {
1135 { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
1136 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
1137 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
1138 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
1141 return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
1143 config_item_table_lookup, items,
1144 false, false, true, NULL);
1147 static void help(void) {
1148 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1149 "Write external journal events to journal file(s).\n\n"
1150 " -h --help Show this help\n"
1151 " --version Show package version\n"
1152 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1153 " --getter=COMMAND Read events from the output of COMMAND\n"
1154 " --listen-raw=ADDR Listen for connections at ADDR\n"
1155 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1156 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1157 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1158 " --compress[=BOOL] Use XZ-compression in the output journal (default: yes)\n"
1159 " --seal[=BOOL] Use Event sealing in the output journal (default: no)\n"
1160 " --key=FILENAME Specify key in PEM format (default:\n"
1161 " \"" PRIV_KEY_FILE "\")\n"
1162 " --cert=FILENAME Specify certificate in PEM format (default:\n"
1163 " \"" CERT_FILE "\")\n"
1164 " --trust=FILENAME|all Specify CA certificate or disable checking (default:\n"
1165 " \"" TRUST_FILE "\")\n"
1166 " --gnutls-log=CATEGORY...\n"
1167 " Specify a list of gnutls logging categories\n"
1169 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1170 , program_invocation_short_name);
1173 static int parse_argv(int argc, char *argv[]) {
1175 ARG_VERSION = 0x100,
1190 static const struct option options[] = {
1191 { "help", no_argument, NULL, 'h' },
1192 { "version", no_argument, NULL, ARG_VERSION },
1193 { "url", required_argument, NULL, ARG_URL },
1194 { "getter", required_argument, NULL, ARG_GETTER },
1195 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1196 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1197 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1198 { "output", required_argument, NULL, 'o' },
1199 { "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
1200 { "compress", optional_argument, NULL, ARG_COMPRESS },
1201 { "seal", optional_argument, NULL, ARG_SEAL },
1202 { "key", required_argument, NULL, ARG_KEY },
1203 { "cert", required_argument, NULL, ARG_CERT },
1204 { "trust", required_argument, NULL, ARG_TRUST },
1205 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1210 bool type_a, type_b;
1215 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1219 return 0 /* done */;
1222 puts(PACKAGE_STRING);
1223 puts(SYSTEMD_FEATURES);
1224 return 0 /* done */;
1228 log_error("cannot currently set more than one --url");
1237 log_error("cannot currently use --getter more than once");
1241 arg_getter = optarg;
1244 case ARG_LISTEN_RAW:
1245 if (arg_listen_raw) {
1246 log_error("cannot currently use --listen-raw more than once");
1250 arg_listen_raw = optarg;
1253 case ARG_LISTEN_HTTP:
1254 if (arg_listen_http || http_socket >= 0) {
1255 log_error("cannot currently use --listen-http more than once");
1263 arg_listen_http = optarg;
1266 case ARG_LISTEN_HTTPS:
1267 if (arg_listen_https || https_socket >= 0) {
1268 log_error("cannot currently use --listen-https more than once");
1276 arg_listen_https = optarg;
1282 log_error("Key file specified twice");
1286 arg_key = strdup(optarg);
1294 log_error("Certificate file specified twice");
1298 arg_cert = strdup(optarg);
1305 if (arg_trust || arg_trust_all) {
1306 log_error("Confusing trusted CA configuration");
1310 if (streq(optarg, "all"))
1311 arg_trust_all = true;
1314 arg_trust = strdup(optarg);
1318 log_error("Option --trust is not available.");
1327 log_error("cannot use --output/-o more than once");
1331 arg_output = optarg;
1334 case ARG_SPLIT_MODE:
1335 arg_split_mode = journal_write_split_mode_from_string(optarg);
1336 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1337 log_error("Invalid split mode: %s", optarg);
1344 r = parse_boolean(optarg);
1346 log_error("Failed to parse --compress= parameter.");
1352 arg_compress = true;
1358 r = parse_boolean(optarg);
1360 log_error("Failed to parse --seal= parameter.");
1370 case ARG_GNUTLS_LOG: {
1372 const char *word, *state;
1375 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1378 cat = strndup(word, size);
1382 if (strv_consume(&arg_gnutls_log, cat) < 0)
1387 log_error("Option --gnutls-log is not available.");
1396 assert_not_reached("Unknown option code.");
1400 arg_files = argv + optind;
1402 type_a = arg_getter || !strv_isempty(arg_files);
1405 || arg_listen_http || arg_listen_https
1406 || sd_listen_fds(false) > 0;
1407 if (type_a && type_b) {
1408 log_error("Cannot use file input or --getter with "
1409 "--arg-listen-... or socket activation.");
1414 log_error("Option --output must be specified with file input or --getter.");
1418 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1421 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1422 && arg_output && is_dir(arg_output, true) > 0) {
1423 log_error("For SplitMode=none, output must be a file.");
1427 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1428 && arg_output && is_dir(arg_output, true) <= 0) {
1429 log_error("For SplitMode=host, output must be a directory.");
1433 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1434 journal_write_split_mode_to_string(arg_split_mode),
1439 return 1 /* work to do */;
1442 static int load_certificates(char **key, char **cert, char **trust) {
1445 r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1447 log_error("Failed to read key from file '%s': %s",
1448 arg_key ?: PRIV_KEY_FILE, strerror(-r));
1452 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1454 log_error("Failed to read certificate from file '%s': %s",
1455 arg_cert ?: CERT_FILE, strerror(-r));
1460 log_info("Certificate checking disabled.");
1462 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1464 log_error("Failed to read CA certificate file '%s': %s",
1465 arg_trust ?: TRUST_FILE, strerror(-r));
1473 static int setup_gnutls_logger(char **categories) {
1474 if (!arg_listen_http && !arg_listen_https)
1482 gnutls_global_set_log_function(log_func_gnutls);
1485 STRV_FOREACH(cat, categories) {
1486 r = log_enable_gnutls_category(*cat);
1491 log_reset_gnutls_level();
1498 int main(int argc, char **argv) {
1499 RemoteServer s = {};
1501 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1503 log_show_color(true);
1504 log_parse_environment();
1508 return EXIT_FAILURE;
1510 r = parse_argv(argc, argv);
1512 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1514 r = setup_gnutls_logger(arg_gnutls_log);
1516 return EXIT_FAILURE;
1518 if (arg_listen_https || https_socket >= 0)
1519 if (load_certificates(&key, &cert, &trust) < 0)
1520 return EXIT_FAILURE;
1522 if (remoteserver_init(&s, key, cert, trust) < 0)
1523 return EXIT_FAILURE;
1525 sd_event_set_watchdog(s.events, true);
1527 log_debug("%s running as pid "PID_FMT,
1528 program_invocation_short_name, getpid());
1531 "STATUS=Processing requests...");
1534 r = sd_event_get_state(s.events);
1537 if (r == SD_EVENT_FINISHED)
1540 r = sd_event_run(s.events, -1);
1542 log_error("Failed to run event loop: %s", strerror(-r));
1549 "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1550 log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1558 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;