1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2012 Zbigniew Jędrzejewski-Szmek
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/prctl.h>
28 #include <sys/socket.h>
32 #include "sd-daemon.h"
34 #include "alloc-util.h"
35 #include "conf-parser.h"
40 #include "journal-file.h"
41 #include "journal-remote-write.h"
42 #include "journal-remote.h"
43 #include "journald-native.h"
45 #include "parse-util.h"
46 #include "process-util.h"
47 #include "signal-util.h"
48 #include "socket-util.h"
49 #include "stat-util.h"
50 #include "stdio-util.h"
51 #include "string-table.h"
52 #include "string-util.h"
55 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
57 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
58 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
59 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
61 static char* arg_url
= NULL
;
62 static char* arg_getter
= NULL
;
63 static char* arg_listen_raw
= NULL
;
64 static char* arg_listen_http
= NULL
;
65 static char* arg_listen_https
= NULL
;
66 static char** arg_files
= NULL
;
67 static int arg_compress
= true;
68 static int arg_seal
= false;
69 static int http_socket
= -1, https_socket
= -1;
70 static char** arg_gnutls_log
= NULL
;
72 static JournalWriteSplitMode arg_split_mode
= _JOURNAL_WRITE_SPLIT_INVALID
;
73 static char* arg_output
= NULL
;
75 static char *arg_key
= NULL
;
76 static char *arg_cert
= NULL
;
77 static char *arg_trust
= NULL
;
78 static bool arg_trust_all
= false;
80 /**********************************************************************
81 **********************************************************************
82 **********************************************************************/
84 static int spawn_child(const char* child
, char** argv
) {
89 return log_error_errno(errno
, "Failed to create pager pipe: %m");
91 r
= safe_fork("(remote)", FORK_RESET_SIGNALS
|FORK_DEATHSIG
|FORK_LOG
, &child_pid
);
101 r
= rearrange_stdio(STDIN_FILENO
, fd
[1], STDERR_FILENO
);
103 log_error_errno(r
, "Failed to dup pipe to stdout: %m");
108 log_error_errno(errno
, "Failed to exec child %s: %m", child
);
114 r
= fd_nonblock(fd
[0], true);
116 log_warning_errno(errno
, "Failed to set child pipe to non-blocking: %m");
121 static int spawn_curl(const char* url
) {
122 char **argv
= STRV_MAKE("curl",
123 "-HAccept: application/vnd.fdo.journal",
129 r
= spawn_child("curl", argv
);
131 log_error_errno(r
, "Failed to spawn curl: %m");
135 static int spawn_getter(const char *getter
) {
137 _cleanup_strv_free_
char **words
= NULL
;
140 r
= strv_split_extract(&words
, getter
, WHITESPACE
, EXTRACT_QUOTES
);
142 return log_error_errno(r
, "Failed to split getter option: %m");
144 r
= spawn_child(words
[0], words
);
146 log_error_errno(r
, "Failed to spawn getter %s: %m", getter
);
151 #define filename_escape(s) xescape((s), "/ ")
153 static int open_output(Writer
*w
, const char* host
) {
154 _cleanup_free_
char *_output
= NULL
;
158 switch (arg_split_mode
) {
159 case JOURNAL_WRITE_SPLIT_NONE
:
160 output
= arg_output
?: REMOTE_JOURNAL_PATH
"/remote.journal";
163 case JOURNAL_WRITE_SPLIT_HOST
: {
164 _cleanup_free_
char *name
;
168 name
= filename_escape(host
);
172 r
= asprintf(&_output
, "%s/remote-%s.journal",
173 arg_output
?: REMOTE_JOURNAL_PATH
,
183 assert_not_reached("what?");
186 r
= journal_file_open_reliably(output
,
187 O_RDWR
|O_CREAT
, 0640,
188 arg_compress
, (uint64_t) -1, arg_seal
,
193 log_error_errno(r
, "Failed to open output journal %s: %m",
196 log_debug("Opened output file %s", w
->journal
->path
);
200 /**********************************************************************
201 **********************************************************************
202 **********************************************************************/
204 static int init_writer_hashmap(RemoteServer
*s
) {
205 static const struct hash_ops
*hash_ops
[] = {
206 [JOURNAL_WRITE_SPLIT_NONE
] = NULL
,
207 [JOURNAL_WRITE_SPLIT_HOST
] = &string_hash_ops
,
210 assert(arg_split_mode
>= 0 && arg_split_mode
< (int) ELEMENTSOF(hash_ops
));
212 s
->writers
= hashmap_new(hash_ops
[arg_split_mode
]);
219 static int get_writer(RemoteServer
*s
, const char *host
,
222 _cleanup_writer_unref_ Writer
*w
= NULL
;
225 switch(arg_split_mode
) {
226 case JOURNAL_WRITE_SPLIT_NONE
:
227 key
= "one and only";
230 case JOURNAL_WRITE_SPLIT_HOST
:
236 assert_not_reached("what split mode?");
239 w
= hashmap_get(s
->writers
, key
);
247 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
) {
248 w
->hashmap_key
= strdup(key
);
253 r
= open_output(w
, host
);
257 r
= hashmap_put(s
->writers
, w
->hashmap_key
?: key
, w
);
262 *writer
= TAKE_PTR(w
);
267 /**********************************************************************
268 **********************************************************************
269 **********************************************************************/
271 /* This should go away as soon as µhttpd allows state to be passed around. */
272 static RemoteServer
*server
;
274 static int dispatch_raw_source_event(sd_event_source
*event
,
278 static int dispatch_raw_source_until_block(sd_event_source
*event
,
280 static int dispatch_blocking_source_event(sd_event_source
*event
,
282 static int dispatch_raw_connection_event(sd_event_source
*event
,
286 static int null_timer_event_handler(sd_event_source
*s
,
289 static int dispatch_http_event(sd_event_source
*event
,
294 static int get_source_for_fd(RemoteServer
*s
,
295 int fd
, char *name
, RemoteSource
**source
) {
299 /* This takes ownership of name, but only on success. */
304 if (!GREEDY_REALLOC0(s
->sources
, s
->sources_size
, fd
+ 1))
307 r
= get_writer(s
, name
, &writer
);
309 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
312 if (s
->sources
[fd
] == NULL
) {
313 s
->sources
[fd
] = source_new(fd
, false, name
, writer
);
314 if (!s
->sources
[fd
]) {
315 writer_unref(writer
);
322 *source
= s
->sources
[fd
];
326 static int remove_source(RemoteServer
*s
, int fd
) {
327 RemoteSource
*source
;
330 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
332 source
= s
->sources
[fd
];
334 /* this closes fd too */
336 s
->sources
[fd
] = NULL
;
343 static int add_source(RemoteServer
*s
, int fd
, char* name
, bool own_name
) {
345 RemoteSource
*source
= NULL
;
348 /* This takes ownership of name, even on failure, if own_name is true. */
360 r
= get_source_for_fd(s
, fd
, name
, &source
);
362 log_error_errno(r
, "Failed to create source for fd:%d (%s): %m",
368 r
= sd_event_add_io(s
->events
, &source
->event
,
369 fd
, EPOLLIN
|EPOLLRDHUP
|EPOLLPRI
,
370 dispatch_raw_source_event
, source
);
372 /* Add additional source for buffer processing. It will be
374 r
= sd_event_add_defer(s
->events
, &source
->buffer_event
,
375 dispatch_raw_source_until_block
, source
);
377 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_OFF
);
378 } else if (r
== -EPERM
) {
379 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd
, name
);
380 r
= sd_event_add_defer(s
->events
, &source
->event
,
381 dispatch_blocking_source_event
, source
);
383 sd_event_source_set_enabled(source
->event
, SD_EVENT_ON
);
386 log_error_errno(r
, "Failed to register event source for fd:%d: %m",
391 r
= sd_event_source_set_description(source
->event
, name
);
393 log_error_errno(r
, "Failed to set source name for fd:%d: %m", fd
);
397 return 1; /* work to do */
400 remove_source(s
, fd
);
404 static int add_raw_socket(RemoteServer
*s
, int fd
) {
406 _cleanup_close_
int fd_
= fd
;
407 char name
[STRLEN("raw-socket-") + DECIMAL_STR_MAX(int) + 1];
411 r
= sd_event_add_io(s
->events
, &s
->listen_event
,
413 dispatch_raw_connection_event
, s
);
417 xsprintf(name
, "raw-socket-%d", fd
);
419 r
= sd_event_source_set_description(s
->listen_event
, name
);
428 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
431 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
, SOCK_CLOEXEC
);
435 return add_raw_socket(s
, fd
);
438 /**********************************************************************
439 **********************************************************************
440 **********************************************************************/
442 static int request_meta(void **connection_cls
, int fd
, char *hostname
) {
443 RemoteSource
*source
;
447 assert(connection_cls
);
451 r
= get_writer(server
, hostname
, &writer
);
453 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
456 source
= source_new(fd
, true, hostname
, writer
);
458 writer_unref(writer
);
462 log_debug("Added RemoteSource as connection metadata %p", source
);
464 *connection_cls
= source
;
468 static void request_meta_free(void *cls
,
469 struct MHD_Connection
*connection
,
470 void **connection_cls
,
471 enum MHD_RequestTerminationCode toe
) {
474 assert(connection_cls
);
478 log_debug("Cleaning up connection metadata %p", s
);
480 *connection_cls
= NULL
;
484 static int process_http_upload(
485 struct MHD_Connection
*connection
,
486 const char *upload_data
,
487 size_t *upload_data_size
,
488 RemoteSource
*source
) {
490 bool finished
= false;
496 log_trace("%s: connection %p, %zu bytes",
497 __func__
, connection
, *upload_data_size
);
499 if (*upload_data_size
) {
500 log_trace("Received %zu bytes", *upload_data_size
);
502 r
= journal_importer_push_data(&source
->importer
,
503 upload_data
, *upload_data_size
);
505 return mhd_respond_oom(connection
);
507 *upload_data_size
= 0;
512 r
= process_source(source
, arg_compress
, arg_seal
);
516 log_warning("Failed to process data for connection %p", connection
);
518 return mhd_respondf(connection
,
519 r
, MHD_HTTP_PAYLOAD_TOO_LARGE
,
520 "Entry is too large, maximum is " STRINGIFY(DATA_SIZE_MAX
) " bytes.");
522 return mhd_respondf(connection
,
523 r
, MHD_HTTP_UNPROCESSABLE_ENTITY
,
524 "Processing failed: %m.");
531 /* The upload is finished */
533 remaining
= journal_importer_bytes_remaining(&source
->importer
);
535 log_warning("Premature EOF byte. %zu bytes lost.", remaining
);
536 return mhd_respondf(connection
,
537 0, MHD_HTTP_EXPECTATION_FAILED
,
538 "Premature EOF. %zu bytes of trailing data not processed.",
542 return mhd_respond(connection
, MHD_HTTP_ACCEPTED
, "OK.");
545 static int request_handler(
547 struct MHD_Connection
*connection
,
551 const char *upload_data
,
552 size_t *upload_data_size
,
553 void **connection_cls
) {
557 _cleanup_free_
char *hostname
= NULL
;
560 assert(connection_cls
);
564 log_trace("Handling a connection %s %s %s", method
, url
, version
);
567 return process_http_upload(connection
,
568 upload_data
, upload_data_size
,
571 if (!streq(method
, "POST"))
572 return mhd_respond(connection
, MHD_HTTP_NOT_ACCEPTABLE
, "Unsupported method.");
574 if (!streq(url
, "/upload"))
575 return mhd_respond(connection
, MHD_HTTP_NOT_FOUND
, "Not found.");
577 header
= MHD_lookup_connection_value(connection
,
578 MHD_HEADER_KIND
, "Content-Type");
579 if (!header
|| !streq(header
, "application/vnd.fdo.journal"))
580 return mhd_respond(connection
, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE
,
581 "Content-Type: application/vnd.fdo.journal is required.");
584 const union MHD_ConnectionInfo
*ci
;
586 ci
= MHD_get_connection_info(connection
,
587 MHD_CONNECTION_INFO_CONNECTION_FD
);
589 log_error("MHD_get_connection_info failed: cannot get remote fd");
590 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
591 "Cannot check remote address.");
598 if (server
->check_trust
) {
599 r
= check_permissions(connection
, &code
, &hostname
);
603 r
= getpeername_pretty(fd
, false, &hostname
);
605 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
606 "Cannot check remote hostname.");
611 r
= request_meta(connection_cls
, fd
, hostname
);
613 return respond_oom(connection
);
615 return mhd_respondf(connection
, r
, MHD_HTTP_INTERNAL_SERVER_ERROR
, "%m");
621 static int setup_microhttpd_server(RemoteServer
*s
,
626 struct MHD_OptionItem opts
[] = {
627 { MHD_OPTION_NOTIFY_COMPLETED
, (intptr_t) request_meta_free
},
628 { MHD_OPTION_EXTERNAL_LOGGER
, (intptr_t) microhttpd_logger
},
629 { MHD_OPTION_LISTEN_SOCKET
, fd
},
630 { MHD_OPTION_CONNECTION_MEMORY_LIMIT
, 128*1024},
643 const union MHD_DaemonInfo
*info
;
649 r
= fd_nonblock(fd
, true);
651 return log_error_errno(r
, "Failed to make fd:%d nonblocking: %m", fd
);
653 /* MHD_OPTION_STRICT_FOR_CLIENT is introduced in microhttpd 0.9.54,
654 * and MHD_USE_PEDANTIC_CHECKS will be deprecated in future.
655 * If MHD_USE_PEDANTIC_CHECKS is '#define'd, then it is deprecated
656 * and we should use MHD_OPTION_STRICT_FOR_CLIENT. On the other hand,
657 * if MHD_USE_PEDANTIC_CHECKS is not '#define'd, then it is not
658 * deprecated yet and there exists an enum element with the same name.
659 * So we can safely use it. */
660 #ifdef MHD_USE_PEDANTIC_CHECKS
661 opts
[opts_pos
++] = (struct MHD_OptionItem
)
662 {MHD_OPTION_STRICT_FOR_CLIENT
, 1};
664 flags
|= MHD_USE_PEDANTIC_CHECKS
;
670 opts
[opts_pos
++] = (struct MHD_OptionItem
)
671 {MHD_OPTION_HTTPS_MEM_KEY
, 0, (char*) key
};
672 opts
[opts_pos
++] = (struct MHD_OptionItem
)
673 {MHD_OPTION_HTTPS_MEM_CERT
, 0, (char*) cert
};
675 flags
|= MHD_USE_TLS
;
678 opts
[opts_pos
++] = (struct MHD_OptionItem
)
679 {MHD_OPTION_HTTPS_MEM_TRUST
, 0, (char*) trust
};
682 d
= new(MHDDaemonWrapper
, 1);
686 d
->fd
= (uint64_t) fd
;
688 d
->daemon
= MHD_start_daemon(flags
, 0,
690 request_handler
, NULL
,
691 MHD_OPTION_ARRAY
, opts
,
694 log_error("Failed to start µhttp daemon");
699 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
700 key
? "HTTPS" : "HTTP", fd
, d
);
703 info
= MHD_get_daemon_info(d
->daemon
, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
);
705 log_error("µhttp returned NULL daemon info");
710 epoll_fd
= info
->listen_fd
;
712 log_error("µhttp epoll fd is invalid");
717 r
= sd_event_add_io(s
->events
, &d
->io_event
,
719 dispatch_http_event
, d
);
721 log_error_errno(r
, "Failed to add event callback: %m");
725 r
= sd_event_source_set_description(d
->io_event
, "io_event");
727 log_error_errno(r
, "Failed to set source name: %m");
731 r
= sd_event_add_time(s
->events
, &d
->timer_event
,
732 CLOCK_MONOTONIC
, (uint64_t) -1, 0,
733 null_timer_event_handler
, d
);
735 log_error_errno(r
, "Failed to add timer_event: %m");
739 r
= sd_event_source_set_description(d
->timer_event
, "timer_event");
741 log_error_errno(r
, "Failed to set source name: %m");
745 r
= hashmap_ensure_allocated(&s
->daemons
, &uint64_hash_ops
);
751 r
= hashmap_put(s
->daemons
, &d
->fd
, d
);
753 log_error_errno(r
, "Failed to add daemon to hashmap: %m");
761 MHD_stop_daemon(d
->daemon
);
767 static int setup_microhttpd_socket(RemoteServer
*s
,
774 fd
= make_socket_fd(LOG_DEBUG
, address
, SOCK_STREAM
, SOCK_CLOEXEC
);
778 return setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
781 static int null_timer_event_handler(sd_event_source
*timer_event
,
784 return dispatch_http_event(timer_event
, 0, 0, userdata
);
787 static int dispatch_http_event(sd_event_source
*event
,
791 MHDDaemonWrapper
*d
= userdata
;
793 MHD_UNSIGNED_LONG_LONG timeout
= ULONG_LONG_MAX
;
797 r
= MHD_run(d
->daemon
);
799 log_error("MHD_run failed!");
800 // XXX: unregister daemon
803 if (MHD_get_timeout(d
->daemon
, &timeout
) == MHD_NO
)
804 timeout
= ULONG_LONG_MAX
;
806 r
= sd_event_source_set_time(d
->timer_event
, timeout
);
808 log_warning_errno(r
, "Unable to set event loop timeout: %m, this may result in indefinite blocking!");
812 r
= sd_event_source_set_enabled(d
->timer_event
, SD_EVENT_ON
);
814 log_warning_errno(r
, "Unable to enable timer_event: %m, this may result in indefinite blocking!");
816 return 1; /* work to do */
819 /**********************************************************************
820 **********************************************************************
821 **********************************************************************/
823 static int setup_signals(RemoteServer
*s
) {
828 assert_se(sigprocmask_many(SIG_SETMASK
, NULL
, SIGINT
, SIGTERM
, -1) >= 0);
830 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
834 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
841 static int negative_fd(const char *spec
) {
842 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
846 r
= safe_atoi(spec
, &fd
);
856 static int remoteserver_init(RemoteServer
*s
,
865 if ((arg_listen_raw
|| arg_listen_http
) && trust
) {
866 log_error("Option --trust makes all non-HTTPS connections untrusted.");
870 r
= sd_event_default(&s
->events
);
872 return log_error_errno(r
, "Failed to allocate event loop: %m");
876 assert(server
== NULL
);
879 r
= init_writer_hashmap(s
);
883 n
= sd_listen_fds(true);
885 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
887 log_debug("Received %d descriptors", n
);
889 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
) {
890 log_error("Received fewer sockets than expected");
894 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
895 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
896 log_debug("Received a listening socket (fd:%d)", fd
);
898 if (fd
== http_socket
)
899 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
900 else if (fd
== https_socket
)
901 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
903 r
= add_raw_socket(s
, fd
);
904 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
907 r
= getpeername_pretty(fd
, false, &hostname
);
909 return log_error_errno(r
, "Failed to retrieve remote name: %m");
911 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
913 r
= add_source(s
, fd
, hostname
, true);
915 log_error("Unknown socket passed on fd:%d", fd
);
921 return log_error_errno(r
, "Failed to register socket (fd:%d): %m",
926 log_info("Spawning getter %s...", arg_getter
);
927 fd
= spawn_getter(arg_getter
);
931 r
= add_source(s
, fd
, (char*) arg_output
, false);
940 if (!strstr(arg_url
, "/entries")) {
941 if (endswith(arg_url
, "/"))
942 url
= strjoina(arg_url
, "entries");
944 url
= strjoina(arg_url
, "/entries");
947 url
= strdupa(arg_url
);
949 log_info("Spawning curl %s...", url
);
950 fd
= spawn_curl(url
);
955 startswith(arg_url
, "https://") ?:
956 startswith(arg_url
, "http://") ?:
959 hostname
= strdupa(hostname
);
960 if ((p
= strchr(hostname
, '/')))
962 if ((p
= strchr(hostname
, ':')))
965 r
= add_source(s
, fd
, hostname
, false);
970 if (arg_listen_raw
) {
971 log_debug("Listening on a socket...");
972 r
= setup_raw_socket(s
, arg_listen_raw
);
977 if (arg_listen_http
) {
978 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
983 if (arg_listen_https
) {
984 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
989 STRV_FOREACH(file
, arg_files
) {
990 const char *output_name
;
992 if (streq(*file
, "-")) {
993 log_debug("Using standard input as source.");
996 output_name
= "stdin";
998 log_debug("Reading file %s...", *file
);
1000 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
1002 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
1003 output_name
= *file
;
1006 r
= add_source(s
, fd
, (char*) output_name
, false);
1011 if (s
->active
== 0) {
1012 log_error("Zero sources specified");
1016 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
1017 /* In this case we know what the writer will be
1018 called, so we can create it and verify that we can
1019 create output as expected. */
1020 r
= get_writer(s
, NULL
, &s
->_single_writer
);
1028 static void MHDDaemonWrapper_free(MHDDaemonWrapper
*d
) {
1029 MHD_stop_daemon(d
->daemon
);
1030 sd_event_source_unref(d
->io_event
);
1031 sd_event_source_unref(d
->timer_event
);
1035 static void server_destroy(RemoteServer
*s
) {
1038 hashmap_free_with_destructor(s
->daemons
, MHDDaemonWrapper_free
);
1040 assert(s
->sources_size
== 0 || s
->sources
);
1041 for (i
= 0; i
< s
->sources_size
; i
++)
1042 remove_source(s
, i
);
1045 writer_unref(s
->_single_writer
);
1046 hashmap_free(s
->writers
);
1048 sd_event_source_unref(s
->sigterm_event
);
1049 sd_event_source_unref(s
->sigint_event
);
1050 sd_event_source_unref(s
->listen_event
);
1051 sd_event_unref(s
->events
);
1053 /* fds that we're listening on remain open... */
1056 /**********************************************************************
1057 **********************************************************************
1058 **********************************************************************/
1060 static int handle_raw_source(sd_event_source
*event
,
1065 RemoteSource
*source
;
1068 /* Returns 1 if there might be more data pending,
1069 * 0 if data is currently exhausted, negative on error.
1072 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
1073 source
= s
->sources
[fd
];
1074 assert(source
->importer
.fd
== fd
);
1076 r
= process_source(source
, arg_compress
, arg_seal
);
1077 if (journal_importer_eof(&source
->importer
)) {
1080 log_debug("EOF reached with source %s (fd=%d)",
1081 source
->importer
.name
, source
->importer
.fd
);
1083 remaining
= journal_importer_bytes_remaining(&source
->importer
);
1085 log_notice("Premature EOF. %zu bytes lost.", remaining
);
1086 remove_source(s
, source
->importer
.fd
);
1087 log_debug("%zu active sources remaining", s
->active
);
1089 } else if (r
== -E2BIG
) {
1090 log_notice_errno(E2BIG
, "Entry too big, skipped");
1092 } else if (r
== -EAGAIN
) {
1095 log_debug_errno(r
, "Closing connection: %m");
1096 remove_source(server
, fd
);
1102 static int dispatch_raw_source_until_block(sd_event_source
*event
,
1104 RemoteSource
*source
= userdata
;
1107 /* Make sure event stays around even if source is destroyed */
1108 sd_event_source_ref(event
);
1110 r
= handle_raw_source(event
, source
->importer
.fd
, EPOLLIN
, server
);
1112 /* No more data for now */
1113 sd_event_source_set_enabled(event
, SD_EVENT_OFF
);
1115 sd_event_source_unref(event
);
1120 static int dispatch_raw_source_event(sd_event_source
*event
,
1124 RemoteSource
*source
= userdata
;
1127 assert(source
->event
);
1128 assert(source
->buffer_event
);
1130 r
= handle_raw_source(event
, fd
, EPOLLIN
, server
);
1132 /* Might have more data. We need to rerun the handler
1133 * until we are sure the buffer is exhausted. */
1134 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_ON
);
1139 static int dispatch_blocking_source_event(sd_event_source
*event
,
1141 RemoteSource
*source
= userdata
;
1143 return handle_raw_source(event
, source
->importer
.fd
, EPOLLIN
, server
);
1146 static int accept_connection(const char* type
, int fd
,
1147 SocketAddress
*addr
, char **hostname
) {
1150 log_debug("Accepting new %s connection on fd:%d", type
, fd
);
1151 fd2
= accept4(fd
, &addr
->sockaddr
.sa
, &addr
->size
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
1153 return log_error_errno(errno
, "accept() on fd:%d failed: %m", fd
);
1155 switch(socket_address_family(addr
)) {
1158 _cleanup_free_
char *a
= NULL
;
1161 r
= socket_address_print(addr
, &a
);
1163 log_error_errno(r
, "socket_address_print(): %m");
1168 r
= socknameinfo_pretty(&addr
->sockaddr
, addr
->size
, &b
);
1170 log_error_errno(r
, "Resolving hostname failed: %m");
1175 log_debug("Accepted %s %s connection from %s",
1177 socket_address_family(addr
) == AF_INET
? "IP" : "IPv6",
1185 log_error("Rejected %s connection with unsupported family %d",
1186 type
, socket_address_family(addr
));
1193 static int dispatch_raw_connection_event(sd_event_source
*event
,
1197 RemoteServer
*s
= userdata
;
1199 SocketAddress addr
= {
1200 .size
= sizeof(union sockaddr_union
),
1201 .type
= SOCK_STREAM
,
1203 char *hostname
= NULL
;
1205 fd2
= accept_connection("raw", fd
, &addr
, &hostname
);
1209 return add_source(s
, fd2
, hostname
, true);
1212 /**********************************************************************
1213 **********************************************************************
1214 **********************************************************************/
1216 static const char* const journal_write_split_mode_table
[_JOURNAL_WRITE_SPLIT_MAX
] = {
1217 [JOURNAL_WRITE_SPLIT_NONE
] = "none",
1218 [JOURNAL_WRITE_SPLIT_HOST
] = "host",
1221 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode
, JournalWriteSplitMode
);
1222 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode
,
1223 journal_write_split_mode
,
1224 JournalWriteSplitMode
,
1225 "Failed to parse split mode setting");
1227 static int parse_config(void) {
1228 const ConfigTableItem items
[] = {
1229 { "Remote", "Seal", config_parse_bool
, 0, &arg_seal
},
1230 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
1231 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
1232 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
1233 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
1236 return config_parse_many_nulstr(PKGSYSCONFDIR
"/journal-remote.conf",
1237 CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
1238 "Remote\0", config_item_table_lookup
, items
,
1239 CONFIG_PARSE_WARN
, NULL
);
1242 static void help(void) {
1243 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1244 "Write external journal events to journal file(s).\n\n"
1245 " -h --help Show this help\n"
1246 " --version Show package version\n"
1247 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1248 " --getter=COMMAND Read events from the output of COMMAND\n"
1249 " --listen-raw=ADDR Listen for connections at ADDR\n"
1250 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1251 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1252 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1253 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1254 " --seal[=BOOL] Use event sealing (default: no)\n"
1255 " --key=FILENAME SSL key in PEM format (default:\n"
1256 " \"" PRIV_KEY_FILE
"\")\n"
1257 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1258 " \"" CERT_FILE
"\")\n"
1259 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1260 " \"" TRUST_FILE
"\")\n"
1261 " --gnutls-log=CATEGORY...\n"
1262 " Specify a list of gnutls logging categories\n"
1263 " --split-mode=none|host How many output files to create\n"
1265 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1266 , program_invocation_short_name
);
1269 static int parse_argv(int argc
, char *argv
[]) {
1271 ARG_VERSION
= 0x100,
1286 static const struct option options
[] = {
1287 { "help", no_argument
, NULL
, 'h' },
1288 { "version", no_argument
, NULL
, ARG_VERSION
},
1289 { "url", required_argument
, NULL
, ARG_URL
},
1290 { "getter", required_argument
, NULL
, ARG_GETTER
},
1291 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
1292 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
1293 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
1294 { "output", required_argument
, NULL
, 'o' },
1295 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
1296 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
1297 { "seal", optional_argument
, NULL
, ARG_SEAL
},
1298 { "key", required_argument
, NULL
, ARG_KEY
},
1299 { "cert", required_argument
, NULL
, ARG_CERT
},
1300 { "trust", required_argument
, NULL
, ARG_TRUST
},
1301 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
1306 bool type_a
, type_b
;
1311 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
1315 return 0 /* done */;
1322 log_error("cannot currently set more than one --url");
1331 log_error("cannot currently use --getter more than once");
1335 arg_getter
= optarg
;
1338 case ARG_LISTEN_RAW
:
1339 if (arg_listen_raw
) {
1340 log_error("cannot currently use --listen-raw more than once");
1344 arg_listen_raw
= optarg
;
1347 case ARG_LISTEN_HTTP
:
1348 if (arg_listen_http
|| http_socket
>= 0) {
1349 log_error("cannot currently use --listen-http more than once");
1353 r
= negative_fd(optarg
);
1357 arg_listen_http
= optarg
;
1360 case ARG_LISTEN_HTTPS
:
1361 if (arg_listen_https
|| https_socket
>= 0) {
1362 log_error("cannot currently use --listen-https more than once");
1366 r
= negative_fd(optarg
);
1370 arg_listen_https
= optarg
;
1376 log_error("Key file specified twice");
1380 arg_key
= strdup(optarg
);
1388 log_error("Certificate file specified twice");
1392 arg_cert
= strdup(optarg
);
1399 if (arg_trust
|| arg_trust_all
) {
1400 log_error("Confusing trusted CA configuration");
1404 if (streq(optarg
, "all"))
1405 arg_trust_all
= true;
1408 arg_trust
= strdup(optarg
);
1412 log_error("Option --trust is not available.");
1421 log_error("cannot use --output/-o more than once");
1425 arg_output
= optarg
;
1428 case ARG_SPLIT_MODE
:
1429 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
1430 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
) {
1431 log_error("Invalid split mode: %s", optarg
);
1438 r
= parse_boolean(optarg
);
1440 log_error("Failed to parse --compress= parameter.");
1446 arg_compress
= true;
1452 r
= parse_boolean(optarg
);
1454 log_error("Failed to parse --seal= parameter.");
1464 case ARG_GNUTLS_LOG
: {
1466 const char* p
= optarg
;
1468 _cleanup_free_
char *word
= NULL
;
1470 r
= extract_first_word(&p
, &word
, ",", 0);
1472 return log_error_errno(r
, "Failed to parse --gnutls-log= argument: %m");
1477 if (strv_push(&arg_gnutls_log
, word
) < 0)
1484 log_error("Option --gnutls-log is not available.");
1493 assert_not_reached("Unknown option code.");
1497 arg_files
= argv
+ optind
;
1499 type_a
= arg_getter
|| !strv_isempty(arg_files
);
1502 || arg_listen_http
|| arg_listen_https
1503 || sd_listen_fds(false) > 0;
1504 if (type_a
&& type_b
) {
1505 log_error("Cannot use file input or --getter with "
1506 "--arg-listen-... or socket activation.");
1511 log_error("Option --output must be specified with file input or --getter.");
1515 if (!IN_SET(arg_split_mode
, JOURNAL_WRITE_SPLIT_NONE
, _JOURNAL_WRITE_SPLIT_INVALID
)) {
1516 log_error("For active sources, only --split-mode=none is allowed.");
1520 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1523 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
)
1524 arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
1526 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
&& arg_output
) {
1527 if (is_dir(arg_output
, true) > 0) {
1528 log_error("For SplitMode=none, output must be a file.");
1531 if (!endswith(arg_output
, ".journal")) {
1532 log_error("For SplitMode=none, output file name must end with .journal.");
1537 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1538 && arg_output
&& is_dir(arg_output
, true) <= 0) {
1539 log_error("For SplitMode=host, output must be a directory.");
1543 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1544 journal_write_split_mode_to_string(arg_split_mode
),
1549 return 1 /* work to do */;
1552 static int load_certificates(char **key
, char **cert
, char **trust
) {
1555 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1557 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1558 arg_key
?: PRIV_KEY_FILE
);
1560 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1562 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1563 arg_cert
?: CERT_FILE
);
1566 log_info("Certificate checking disabled.");
1568 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1570 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1571 arg_trust
?: TRUST_FILE
);
1577 int main(int argc
, char **argv
) {
1578 RemoteServer s
= {};
1580 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1582 log_show_color(true);
1583 log_parse_environment();
1587 return EXIT_FAILURE
;
1589 r
= parse_argv(argc
, argv
);
1591 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1594 if (arg_listen_http
|| arg_listen_https
) {
1595 r
= setup_gnutls_logger(arg_gnutls_log
);
1597 return EXIT_FAILURE
;
1600 if (arg_listen_https
|| https_socket
>= 0)
1601 if (load_certificates(&key
, &cert
, &trust
) < 0)
1602 return EXIT_FAILURE
;
1604 if (remoteserver_init(&s
, key
, cert
, trust
) < 0)
1605 return EXIT_FAILURE
;
1607 r
= sd_event_set_watchdog(s
.events
, true);
1609 log_error_errno(r
, "Failed to enable watchdog: %m");
1611 log_debug("Watchdog is %sd.", enable_disable(r
> 0));
1613 log_debug("%s running as pid "PID_FMT
,
1614 program_invocation_short_name
, getpid_cached());
1617 "STATUS=Processing requests...");
1620 r
= sd_event_get_state(s
.events
);
1623 if (r
== SD_EVENT_FINISHED
)
1626 r
= sd_event_run(s
.events
, -1);
1628 log_error_errno(r
, "Failed to run event loop: %m");
1635 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1636 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1644 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;