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 "signal-util.h"
47 #include "socket-util.h"
48 #include "stat-util.h"
49 #include "stdio-util.h"
50 #include "string-table.h"
51 #include "string-util.h"
54 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
56 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
57 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
58 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
60 static char* arg_url
= NULL
;
61 static char* arg_getter
= NULL
;
62 static char* arg_listen_raw
= NULL
;
63 static char* arg_listen_http
= NULL
;
64 static char* arg_listen_https
= NULL
;
65 static char** arg_files
= NULL
;
66 static int arg_compress
= true;
67 static int arg_seal
= false;
68 static int http_socket
= -1, https_socket
= -1;
69 static char** arg_gnutls_log
= NULL
;
71 static JournalWriteSplitMode arg_split_mode
= _JOURNAL_WRITE_SPLIT_INVALID
;
72 static char* arg_output
= NULL
;
74 static char *arg_key
= NULL
;
75 static char *arg_cert
= NULL
;
76 static char *arg_trust
= NULL
;
77 static bool arg_trust_all
= false;
79 /**********************************************************************
80 **********************************************************************
81 **********************************************************************/
83 static int spawn_child(const char* child
, char** argv
) {
85 pid_t parent_pid
, child_pid
;
89 return log_error_errno(errno
, "Failed to create pager pipe: %m");
91 parent_pid
= getpid_cached();
95 r
= log_error_errno(errno
, "Failed to fork: %m");
101 if (child_pid
== 0) {
103 (void) reset_all_signal_handlers();
104 (void) reset_signal_mask();
106 r
= dup2(fd
[1], STDOUT_FILENO
);
108 log_error_errno(errno
, "Failed to dup pipe to stdout: %m");
114 /* Make sure the child goes away when the parent dies */
115 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
118 /* Check whether our parent died before we were able
119 * to set the death signal */
120 if (getppid() != parent_pid
)
124 log_error_errno(errno
, "Failed to exec child %s: %m", child
);
130 log_warning_errno(errno
, "Failed to close write end of pipe: %m");
132 r
= fd_nonblock(fd
[0], true);
134 log_warning_errno(errno
, "Failed to set child pipe to non-blocking: %m");
139 static int spawn_curl(const char* url
) {
140 char **argv
= STRV_MAKE("curl",
141 "-HAccept: application/vnd.fdo.journal",
147 r
= spawn_child("curl", argv
);
149 log_error_errno(r
, "Failed to spawn curl: %m");
153 static int spawn_getter(const char *getter
) {
155 _cleanup_strv_free_
char **words
= NULL
;
158 r
= strv_split_extract(&words
, getter
, WHITESPACE
, EXTRACT_QUOTES
);
160 return log_error_errno(r
, "Failed to split getter option: %m");
162 r
= spawn_child(words
[0], words
);
164 log_error_errno(r
, "Failed to spawn getter %s: %m", getter
);
169 #define filename_escape(s) xescape((s), "/ ")
171 static int open_output(Writer
*w
, const char* host
) {
172 _cleanup_free_
char *_output
= NULL
;
176 switch (arg_split_mode
) {
177 case JOURNAL_WRITE_SPLIT_NONE
:
178 output
= arg_output
?: REMOTE_JOURNAL_PATH
"/remote.journal";
181 case JOURNAL_WRITE_SPLIT_HOST
: {
182 _cleanup_free_
char *name
;
186 name
= filename_escape(host
);
190 r
= asprintf(&_output
, "%s/remote-%s.journal",
191 arg_output
?: REMOTE_JOURNAL_PATH
,
201 assert_not_reached("what?");
204 r
= journal_file_open_reliably(output
,
205 O_RDWR
|O_CREAT
, 0640,
206 arg_compress
, arg_seal
,
211 log_error_errno(r
, "Failed to open output journal %s: %m",
214 log_debug("Opened output file %s", w
->journal
->path
);
218 /**********************************************************************
219 **********************************************************************
220 **********************************************************************/
222 static int init_writer_hashmap(RemoteServer
*s
) {
223 static const struct hash_ops
*hash_ops
[] = {
224 [JOURNAL_WRITE_SPLIT_NONE
] = NULL
,
225 [JOURNAL_WRITE_SPLIT_HOST
] = &string_hash_ops
,
228 assert(arg_split_mode
>= 0 && arg_split_mode
< (int) ELEMENTSOF(hash_ops
));
230 s
->writers
= hashmap_new(hash_ops
[arg_split_mode
]);
237 static int get_writer(RemoteServer
*s
, const char *host
,
240 _cleanup_writer_unref_ Writer
*w
= NULL
;
243 switch(arg_split_mode
) {
244 case JOURNAL_WRITE_SPLIT_NONE
:
245 key
= "one and only";
248 case JOURNAL_WRITE_SPLIT_HOST
:
254 assert_not_reached("what split mode?");
257 w
= hashmap_get(s
->writers
, key
);
265 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
) {
266 w
->hashmap_key
= strdup(key
);
271 r
= open_output(w
, host
);
275 r
= hashmap_put(s
->writers
, w
->hashmap_key
?: key
, w
);
285 /**********************************************************************
286 **********************************************************************
287 **********************************************************************/
289 /* This should go away as soon as µhttpd allows state to be passed around. */
290 static RemoteServer
*server
;
292 static int dispatch_raw_source_event(sd_event_source
*event
,
296 static int dispatch_raw_source_until_block(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 null_timer_event_handler(sd_event_source
*s
,
307 static int dispatch_http_event(sd_event_source
*event
,
312 static int get_source_for_fd(RemoteServer
*s
,
313 int fd
, char *name
, RemoteSource
**source
) {
317 /* This takes ownership of name, but only on success. */
322 if (!GREEDY_REALLOC0(s
->sources
, s
->sources_size
, fd
+ 1))
325 r
= get_writer(s
, name
, &writer
);
327 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
330 if (s
->sources
[fd
] == NULL
) {
331 s
->sources
[fd
] = source_new(fd
, false, name
, writer
);
332 if (!s
->sources
[fd
]) {
333 writer_unref(writer
);
340 *source
= s
->sources
[fd
];
344 static int remove_source(RemoteServer
*s
, int fd
) {
345 RemoteSource
*source
;
348 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
350 source
= s
->sources
[fd
];
352 /* this closes fd too */
354 s
->sources
[fd
] = NULL
;
361 static int add_source(RemoteServer
*s
, int fd
, char* name
, bool own_name
) {
363 RemoteSource
*source
= NULL
;
366 /* This takes ownership of name, even on failure, if own_name is true. */
378 r
= get_source_for_fd(s
, fd
, name
, &source
);
380 log_error_errno(r
, "Failed to create source for fd:%d (%s): %m",
386 r
= sd_event_add_io(s
->events
, &source
->event
,
387 fd
, EPOLLIN
|EPOLLRDHUP
|EPOLLPRI
,
388 dispatch_raw_source_event
, source
);
390 /* Add additional source for buffer processing. It will be
392 r
= sd_event_add_defer(s
->events
, &source
->buffer_event
,
393 dispatch_raw_source_until_block
, source
);
395 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_OFF
);
396 } else if (r
== -EPERM
) {
397 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd
, name
);
398 r
= sd_event_add_defer(s
->events
, &source
->event
,
399 dispatch_blocking_source_event
, source
);
401 sd_event_source_set_enabled(source
->event
, SD_EVENT_ON
);
404 log_error_errno(r
, "Failed to register event source for fd:%d: %m",
409 r
= sd_event_source_set_description(source
->event
, name
);
411 log_error_errno(r
, "Failed to set source name for fd:%d: %m", fd
);
415 return 1; /* work to do */
418 remove_source(s
, fd
);
422 static int add_raw_socket(RemoteServer
*s
, int fd
) {
424 _cleanup_close_
int fd_
= fd
;
425 char name
[STRLEN("raw-socket-") + DECIMAL_STR_MAX(int) + 1];
429 r
= sd_event_add_io(s
->events
, &s
->listen_event
,
431 dispatch_raw_connection_event
, s
);
435 xsprintf(name
, "raw-socket-%d", fd
);
437 r
= sd_event_source_set_description(s
->listen_event
, name
);
446 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
449 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
, SOCK_CLOEXEC
);
453 return add_raw_socket(s
, fd
);
456 /**********************************************************************
457 **********************************************************************
458 **********************************************************************/
460 static int request_meta(void **connection_cls
, int fd
, char *hostname
) {
461 RemoteSource
*source
;
465 assert(connection_cls
);
469 r
= get_writer(server
, hostname
, &writer
);
471 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
474 source
= source_new(fd
, true, hostname
, writer
);
476 writer_unref(writer
);
480 log_debug("Added RemoteSource as connection metadata %p", source
);
482 *connection_cls
= source
;
486 static void request_meta_free(void *cls
,
487 struct MHD_Connection
*connection
,
488 void **connection_cls
,
489 enum MHD_RequestTerminationCode toe
) {
492 assert(connection_cls
);
496 log_debug("Cleaning up connection metadata %p", s
);
498 *connection_cls
= NULL
;
502 static int process_http_upload(
503 struct MHD_Connection
*connection
,
504 const char *upload_data
,
505 size_t *upload_data_size
,
506 RemoteSource
*source
) {
508 bool finished
= false;
514 log_trace("%s: connection %p, %zu bytes",
515 __func__
, connection
, *upload_data_size
);
517 if (*upload_data_size
) {
518 log_trace("Received %zu bytes", *upload_data_size
);
520 r
= journal_importer_push_data(&source
->importer
,
521 upload_data
, *upload_data_size
);
523 return mhd_respond_oom(connection
);
525 *upload_data_size
= 0;
530 r
= process_source(source
, arg_compress
, arg_seal
);
534 log_warning("Failed to process data for connection %p", connection
);
536 return mhd_respondf(connection
,
537 r
, MHD_HTTP_PAYLOAD_TOO_LARGE
,
538 "Entry is too large, maximum is " STRINGIFY(DATA_SIZE_MAX
) " bytes.");
540 return mhd_respondf(connection
,
541 r
, MHD_HTTP_UNPROCESSABLE_ENTITY
,
542 "Processing failed: %m.");
549 /* The upload is finished */
551 remaining
= journal_importer_bytes_remaining(&source
->importer
);
553 log_warning("Premature EOF byte. %zu bytes lost.", remaining
);
554 return mhd_respondf(connection
,
555 0, MHD_HTTP_EXPECTATION_FAILED
,
556 "Premature EOF. %zu bytes of trailing data not processed.",
560 return mhd_respond(connection
, MHD_HTTP_ACCEPTED
, "OK.");
563 static int request_handler(
565 struct MHD_Connection
*connection
,
569 const char *upload_data
,
570 size_t *upload_data_size
,
571 void **connection_cls
) {
575 _cleanup_free_
char *hostname
= NULL
;
578 assert(connection_cls
);
582 log_trace("Handling a connection %s %s %s", method
, url
, version
);
585 return process_http_upload(connection
,
586 upload_data
, upload_data_size
,
589 if (!streq(method
, "POST"))
590 return mhd_respond(connection
, MHD_HTTP_NOT_ACCEPTABLE
, "Unsupported method.");
592 if (!streq(url
, "/upload"))
593 return mhd_respond(connection
, MHD_HTTP_NOT_FOUND
, "Not found.");
595 header
= MHD_lookup_connection_value(connection
,
596 MHD_HEADER_KIND
, "Content-Type");
597 if (!header
|| !streq(header
, "application/vnd.fdo.journal"))
598 return mhd_respond(connection
, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE
,
599 "Content-Type: application/vnd.fdo.journal is required.");
602 const union MHD_ConnectionInfo
*ci
;
604 ci
= MHD_get_connection_info(connection
,
605 MHD_CONNECTION_INFO_CONNECTION_FD
);
607 log_error("MHD_get_connection_info failed: cannot get remote fd");
608 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
609 "Cannot check remote address.");
616 if (server
->check_trust
) {
617 r
= check_permissions(connection
, &code
, &hostname
);
621 r
= getpeername_pretty(fd
, false, &hostname
);
623 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
624 "Cannot check remote hostname.");
629 r
= request_meta(connection_cls
, fd
, hostname
);
631 return respond_oom(connection
);
633 return mhd_respondf(connection
, r
, MHD_HTTP_INTERNAL_SERVER_ERROR
, "%m");
639 static int setup_microhttpd_server(RemoteServer
*s
,
644 struct MHD_OptionItem opts
[] = {
645 { MHD_OPTION_NOTIFY_COMPLETED
, (intptr_t) request_meta_free
},
646 { MHD_OPTION_EXTERNAL_LOGGER
, (intptr_t) microhttpd_logger
},
647 { MHD_OPTION_LISTEN_SOCKET
, fd
},
648 { MHD_OPTION_CONNECTION_MEMORY_LIMIT
, 128*1024},
661 const union MHD_DaemonInfo
*info
;
667 r
= fd_nonblock(fd
, true);
669 return log_error_errno(r
, "Failed to make fd:%d nonblocking: %m", fd
);
671 /* MHD_OPTION_STRICT_FOR_CLIENT is introduced in microhttpd 0.9.54,
672 * and MHD_USE_PEDANTIC_CHECKS will be deprecated in future.
673 * If MHD_USE_PEDANTIC_CHECKS is '#define'd, then it is deprecated
674 * and we should use MHD_OPTION_STRICT_FOR_CLIENT. On the other hand,
675 * if MHD_USE_PEDANTIC_CHECKS is not '#define'd, then it is not
676 * deprecated yet and there exists an enum element with the same name.
677 * So we can safely use it. */
678 #ifdef MHD_USE_PEDANTIC_CHECKS
679 opts
[opts_pos
++] = (struct MHD_OptionItem
)
680 {MHD_OPTION_STRICT_FOR_CLIENT
, 1};
682 flags
|= MHD_USE_PEDANTIC_CHECKS
;
688 opts
[opts_pos
++] = (struct MHD_OptionItem
)
689 {MHD_OPTION_HTTPS_MEM_KEY
, 0, (char*) key
};
690 opts
[opts_pos
++] = (struct MHD_OptionItem
)
691 {MHD_OPTION_HTTPS_MEM_CERT
, 0, (char*) cert
};
693 flags
|= MHD_USE_TLS
;
696 opts
[opts_pos
++] = (struct MHD_OptionItem
)
697 {MHD_OPTION_HTTPS_MEM_TRUST
, 0, (char*) trust
};
700 d
= new(MHDDaemonWrapper
, 1);
704 d
->fd
= (uint64_t) fd
;
706 d
->daemon
= MHD_start_daemon(flags
, 0,
708 request_handler
, NULL
,
709 MHD_OPTION_ARRAY
, opts
,
712 log_error("Failed to start µhttp daemon");
717 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
718 key
? "HTTPS" : "HTTP", fd
, d
);
721 info
= MHD_get_daemon_info(d
->daemon
, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
);
723 log_error("µhttp returned NULL daemon info");
728 epoll_fd
= info
->listen_fd
;
730 log_error("µhttp epoll fd is invalid");
735 r
= sd_event_add_io(s
->events
, &d
->io_event
,
737 dispatch_http_event
, d
);
739 log_error_errno(r
, "Failed to add event callback: %m");
743 r
= sd_event_source_set_description(d
->io_event
, "io_event");
745 log_error_errno(r
, "Failed to set source name: %m");
749 r
= sd_event_add_time(s
->events
, &d
->timer_event
,
750 CLOCK_MONOTONIC
, UINT64_MAX
, 0,
751 null_timer_event_handler
, d
);
753 log_error_errno(r
, "Failed to add timer_event: %m");
757 r
= sd_event_source_set_description(d
->timer_event
, "timer_event");
759 log_error_errno(r
, "Failed to set source name: %m");
763 r
= hashmap_ensure_allocated(&s
->daemons
, &uint64_hash_ops
);
769 r
= hashmap_put(s
->daemons
, &d
->fd
, d
);
771 log_error_errno(r
, "Failed to add daemon to hashmap: %m");
779 MHD_stop_daemon(d
->daemon
);
785 static int setup_microhttpd_socket(RemoteServer
*s
,
792 fd
= make_socket_fd(LOG_DEBUG
, address
, SOCK_STREAM
, SOCK_CLOEXEC
);
796 return setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
799 static int null_timer_event_handler(sd_event_source
*timer_event
,
802 return dispatch_http_event(timer_event
, 0, 0, userdata
);
805 static int dispatch_http_event(sd_event_source
*event
,
809 MHDDaemonWrapper
*d
= userdata
;
811 MHD_UNSIGNED_LONG_LONG timeout
= ULONG_LONG_MAX
;
815 r
= MHD_run(d
->daemon
);
817 log_error("MHD_run failed!");
818 // XXX: unregister daemon
821 if (MHD_get_timeout(d
->daemon
, &timeout
) == MHD_NO
)
822 timeout
= ULONG_LONG_MAX
;
824 r
= sd_event_source_set_time(d
->timer_event
, timeout
);
826 log_warning_errno(r
, "Unable to set event loop timeout: %m, this may result in indefinite blocking!");
830 r
= sd_event_source_set_enabled(d
->timer_event
, SD_EVENT_ON
);
832 log_warning_errno(r
, "Unable to enable timer_event: %m, this may result in indefinite blocking!");
834 return 1; /* work to do */
837 /**********************************************************************
838 **********************************************************************
839 **********************************************************************/
841 static int setup_signals(RemoteServer
*s
) {
846 assert_se(sigprocmask_many(SIG_SETMASK
, NULL
, SIGINT
, SIGTERM
, -1) >= 0);
848 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
852 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
859 static int negative_fd(const char *spec
) {
860 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
864 r
= safe_atoi(spec
, &fd
);
874 static int remoteserver_init(RemoteServer
*s
,
883 if ((arg_listen_raw
|| arg_listen_http
) && trust
) {
884 log_error("Option --trust makes all non-HTTPS connections untrusted.");
888 r
= sd_event_default(&s
->events
);
890 return log_error_errno(r
, "Failed to allocate event loop: %m");
894 assert(server
== NULL
);
897 r
= init_writer_hashmap(s
);
901 n
= sd_listen_fds(true);
903 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
905 log_debug("Received %d descriptors", n
);
907 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
) {
908 log_error("Received fewer sockets than expected");
912 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
913 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
914 log_debug("Received a listening socket (fd:%d)", fd
);
916 if (fd
== http_socket
)
917 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
918 else if (fd
== https_socket
)
919 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
921 r
= add_raw_socket(s
, fd
);
922 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
925 r
= getpeername_pretty(fd
, false, &hostname
);
927 return log_error_errno(r
, "Failed to retrieve remote name: %m");
929 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
931 r
= add_source(s
, fd
, hostname
, true);
933 log_error("Unknown socket passed on fd:%d", fd
);
939 return log_error_errno(r
, "Failed to register socket (fd:%d): %m",
944 log_info("Spawning getter %s...", arg_getter
);
945 fd
= spawn_getter(arg_getter
);
949 r
= add_source(s
, fd
, (char*) arg_output
, false);
958 if (!strstr(arg_url
, "/entries")) {
959 if (endswith(arg_url
, "/"))
960 url
= strjoina(arg_url
, "entries");
962 url
= strjoina(arg_url
, "/entries");
965 url
= strdupa(arg_url
);
967 log_info("Spawning curl %s...", url
);
968 fd
= spawn_curl(url
);
973 startswith(arg_url
, "https://") ?:
974 startswith(arg_url
, "http://") ?:
977 hostname
= strdupa(hostname
);
978 if ((p
= strchr(hostname
, '/')))
980 if ((p
= strchr(hostname
, ':')))
983 r
= add_source(s
, fd
, hostname
, false);
988 if (arg_listen_raw
) {
989 log_debug("Listening on a socket...");
990 r
= setup_raw_socket(s
, arg_listen_raw
);
995 if (arg_listen_http
) {
996 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
1001 if (arg_listen_https
) {
1002 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
1007 STRV_FOREACH(file
, arg_files
) {
1008 const char *output_name
;
1010 if (streq(*file
, "-")) {
1011 log_debug("Using standard input as source.");
1014 output_name
= "stdin";
1016 log_debug("Reading file %s...", *file
);
1018 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
1020 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
1021 output_name
= *file
;
1024 r
= add_source(s
, fd
, (char*) output_name
, false);
1029 if (s
->active
== 0) {
1030 log_error("Zero sources specified");
1034 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
1035 /* In this case we know what the writer will be
1036 called, so we can create it and verify that we can
1037 create output as expected. */
1038 r
= get_writer(s
, NULL
, &s
->_single_writer
);
1046 static void MHDDaemonWrapper_free(MHDDaemonWrapper
*d
) {
1047 MHD_stop_daemon(d
->daemon
);
1048 sd_event_source_unref(d
->io_event
);
1049 sd_event_source_unref(d
->timer_event
);
1053 static void server_destroy(RemoteServer
*s
) {
1056 hashmap_free_with_destructor(s
->daemons
, MHDDaemonWrapper_free
);
1058 assert(s
->sources_size
== 0 || s
->sources
);
1059 for (i
= 0; i
< s
->sources_size
; i
++)
1060 remove_source(s
, i
);
1063 writer_unref(s
->_single_writer
);
1064 hashmap_free(s
->writers
);
1066 sd_event_source_unref(s
->sigterm_event
);
1067 sd_event_source_unref(s
->sigint_event
);
1068 sd_event_source_unref(s
->listen_event
);
1069 sd_event_unref(s
->events
);
1071 /* fds that we're listening on remain open... */
1074 /**********************************************************************
1075 **********************************************************************
1076 **********************************************************************/
1078 static int handle_raw_source(sd_event_source
*event
,
1083 RemoteSource
*source
;
1086 /* Returns 1 if there might be more data pending,
1087 * 0 if data is currently exhausted, negative on error.
1090 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
1091 source
= s
->sources
[fd
];
1092 assert(source
->importer
.fd
== fd
);
1094 r
= process_source(source
, arg_compress
, arg_seal
);
1095 if (journal_importer_eof(&source
->importer
)) {
1098 log_debug("EOF reached with source %s (fd=%d)",
1099 source
->importer
.name
, source
->importer
.fd
);
1101 remaining
= journal_importer_bytes_remaining(&source
->importer
);
1103 log_notice("Premature EOF. %zu bytes lost.", remaining
);
1104 remove_source(s
, source
->importer
.fd
);
1105 log_debug("%zu active sources remaining", s
->active
);
1107 } else if (r
== -E2BIG
) {
1108 log_notice_errno(E2BIG
, "Entry too big, skipped");
1110 } else if (r
== -EAGAIN
) {
1113 log_debug_errno(r
, "Closing connection: %m");
1114 remove_source(server
, fd
);
1120 static int dispatch_raw_source_until_block(sd_event_source
*event
,
1122 RemoteSource
*source
= userdata
;
1125 /* Make sure event stays around even if source is destroyed */
1126 sd_event_source_ref(event
);
1128 r
= handle_raw_source(event
, source
->importer
.fd
, EPOLLIN
, server
);
1130 /* No more data for now */
1131 sd_event_source_set_enabled(event
, SD_EVENT_OFF
);
1133 sd_event_source_unref(event
);
1138 static int dispatch_raw_source_event(sd_event_source
*event
,
1142 RemoteSource
*source
= userdata
;
1145 assert(source
->event
);
1146 assert(source
->buffer_event
);
1148 r
= handle_raw_source(event
, fd
, EPOLLIN
, server
);
1150 /* Might have more data. We need to rerun the handler
1151 * until we are sure the buffer is exhausted. */
1152 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_ON
);
1157 static int dispatch_blocking_source_event(sd_event_source
*event
,
1159 RemoteSource
*source
= userdata
;
1161 return handle_raw_source(event
, source
->importer
.fd
, EPOLLIN
, server
);
1164 static int accept_connection(const char* type
, int fd
,
1165 SocketAddress
*addr
, char **hostname
) {
1168 log_debug("Accepting new %s connection on fd:%d", type
, fd
);
1169 fd2
= accept4(fd
, &addr
->sockaddr
.sa
, &addr
->size
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
1171 return log_error_errno(errno
, "accept() on fd:%d failed: %m", fd
);
1173 switch(socket_address_family(addr
)) {
1176 _cleanup_free_
char *a
= NULL
;
1179 r
= socket_address_print(addr
, &a
);
1181 log_error_errno(r
, "socket_address_print(): %m");
1186 r
= socknameinfo_pretty(&addr
->sockaddr
, addr
->size
, &b
);
1188 log_error_errno(r
, "Resolving hostname failed: %m");
1193 log_debug("Accepted %s %s connection from %s",
1195 socket_address_family(addr
) == AF_INET
? "IP" : "IPv6",
1203 log_error("Rejected %s connection with unsupported family %d",
1204 type
, socket_address_family(addr
));
1211 static int dispatch_raw_connection_event(sd_event_source
*event
,
1215 RemoteServer
*s
= userdata
;
1217 SocketAddress addr
= {
1218 .size
= sizeof(union sockaddr_union
),
1219 .type
= SOCK_STREAM
,
1221 char *hostname
= NULL
;
1223 fd2
= accept_connection("raw", fd
, &addr
, &hostname
);
1227 return add_source(s
, fd2
, hostname
, true);
1230 /**********************************************************************
1231 **********************************************************************
1232 **********************************************************************/
1234 static const char* const journal_write_split_mode_table
[_JOURNAL_WRITE_SPLIT_MAX
] = {
1235 [JOURNAL_WRITE_SPLIT_NONE
] = "none",
1236 [JOURNAL_WRITE_SPLIT_HOST
] = "host",
1239 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode
, JournalWriteSplitMode
);
1240 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode
,
1241 journal_write_split_mode
,
1242 JournalWriteSplitMode
,
1243 "Failed to parse split mode setting");
1245 static int parse_config(void) {
1246 const ConfigTableItem items
[] = {
1247 { "Remote", "Seal", config_parse_bool
, 0, &arg_seal
},
1248 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
1249 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
1250 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
1251 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
1254 return config_parse_many_nulstr(PKGSYSCONFDIR
"/journal-remote.conf",
1255 CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
1256 "Remote\0", config_item_table_lookup
, items
,
1257 CONFIG_PARSE_WARN
, NULL
);
1260 static void help(void) {
1261 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1262 "Write external journal events to journal file(s).\n\n"
1263 " -h --help Show this help\n"
1264 " --version Show package version\n"
1265 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1266 " --getter=COMMAND Read events from the output of COMMAND\n"
1267 " --listen-raw=ADDR Listen for connections at ADDR\n"
1268 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1269 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1270 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1271 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1272 " --seal[=BOOL] Use event sealing (default: no)\n"
1273 " --key=FILENAME SSL key in PEM format (default:\n"
1274 " \"" PRIV_KEY_FILE
"\")\n"
1275 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1276 " \"" CERT_FILE
"\")\n"
1277 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1278 " \"" TRUST_FILE
"\")\n"
1279 " --gnutls-log=CATEGORY...\n"
1280 " Specify a list of gnutls logging categories\n"
1281 " --split-mode=none|host How many output files to create\n"
1283 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1284 , program_invocation_short_name
);
1287 static int parse_argv(int argc
, char *argv
[]) {
1289 ARG_VERSION
= 0x100,
1304 static const struct option options
[] = {
1305 { "help", no_argument
, NULL
, 'h' },
1306 { "version", no_argument
, NULL
, ARG_VERSION
},
1307 { "url", required_argument
, NULL
, ARG_URL
},
1308 { "getter", required_argument
, NULL
, ARG_GETTER
},
1309 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
1310 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
1311 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
1312 { "output", required_argument
, NULL
, 'o' },
1313 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
1314 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
1315 { "seal", optional_argument
, NULL
, ARG_SEAL
},
1316 { "key", required_argument
, NULL
, ARG_KEY
},
1317 { "cert", required_argument
, NULL
, ARG_CERT
},
1318 { "trust", required_argument
, NULL
, ARG_TRUST
},
1319 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
1324 bool type_a
, type_b
;
1329 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
1333 return 0 /* done */;
1340 log_error("cannot currently set more than one --url");
1349 log_error("cannot currently use --getter more than once");
1353 arg_getter
= optarg
;
1356 case ARG_LISTEN_RAW
:
1357 if (arg_listen_raw
) {
1358 log_error("cannot currently use --listen-raw more than once");
1362 arg_listen_raw
= optarg
;
1365 case ARG_LISTEN_HTTP
:
1366 if (arg_listen_http
|| http_socket
>= 0) {
1367 log_error("cannot currently use --listen-http more than once");
1371 r
= negative_fd(optarg
);
1375 arg_listen_http
= optarg
;
1378 case ARG_LISTEN_HTTPS
:
1379 if (arg_listen_https
|| https_socket
>= 0) {
1380 log_error("cannot currently use --listen-https more than once");
1384 r
= negative_fd(optarg
);
1388 arg_listen_https
= optarg
;
1394 log_error("Key file specified twice");
1398 arg_key
= strdup(optarg
);
1406 log_error("Certificate file specified twice");
1410 arg_cert
= strdup(optarg
);
1417 if (arg_trust
|| arg_trust_all
) {
1418 log_error("Confusing trusted CA configuration");
1422 if (streq(optarg
, "all"))
1423 arg_trust_all
= true;
1426 arg_trust
= strdup(optarg
);
1430 log_error("Option --trust is not available.");
1439 log_error("cannot use --output/-o more than once");
1443 arg_output
= optarg
;
1446 case ARG_SPLIT_MODE
:
1447 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
1448 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
) {
1449 log_error("Invalid split mode: %s", optarg
);
1456 r
= parse_boolean(optarg
);
1458 log_error("Failed to parse --compress= parameter.");
1464 arg_compress
= true;
1470 r
= parse_boolean(optarg
);
1472 log_error("Failed to parse --seal= parameter.");
1482 case ARG_GNUTLS_LOG
: {
1484 const char* p
= optarg
;
1486 _cleanup_free_
char *word
= NULL
;
1488 r
= extract_first_word(&p
, &word
, ",", 0);
1490 return log_error_errno(r
, "Failed to parse --gnutls-log= argument: %m");
1495 if (strv_push(&arg_gnutls_log
, word
) < 0)
1502 log_error("Option --gnutls-log is not available.");
1511 assert_not_reached("Unknown option code.");
1515 arg_files
= argv
+ optind
;
1517 type_a
= arg_getter
|| !strv_isempty(arg_files
);
1520 || arg_listen_http
|| arg_listen_https
1521 || sd_listen_fds(false) > 0;
1522 if (type_a
&& type_b
) {
1523 log_error("Cannot use file input or --getter with "
1524 "--arg-listen-... or socket activation.");
1529 log_error("Option --output must be specified with file input or --getter.");
1533 if (!IN_SET(arg_split_mode
, JOURNAL_WRITE_SPLIT_NONE
, _JOURNAL_WRITE_SPLIT_INVALID
)) {
1534 log_error("For active sources, only --split-mode=none is allowed.");
1538 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1541 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
)
1542 arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
1544 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
&& arg_output
) {
1545 if (is_dir(arg_output
, true) > 0) {
1546 log_error("For SplitMode=none, output must be a file.");
1549 if (!endswith(arg_output
, ".journal")) {
1550 log_error("For SplitMode=none, output file name must end with .journal.");
1555 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1556 && arg_output
&& is_dir(arg_output
, true) <= 0) {
1557 log_error("For SplitMode=host, output must be a directory.");
1561 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1562 journal_write_split_mode_to_string(arg_split_mode
),
1567 return 1 /* work to do */;
1570 static int load_certificates(char **key
, char **cert
, char **trust
) {
1573 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1575 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1576 arg_key
?: PRIV_KEY_FILE
);
1578 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1580 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1581 arg_cert
?: CERT_FILE
);
1584 log_info("Certificate checking disabled.");
1586 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1588 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1589 arg_trust
?: TRUST_FILE
);
1595 int main(int argc
, char **argv
) {
1596 RemoteServer s
= {};
1598 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1600 log_show_color(true);
1601 log_parse_environment();
1605 return EXIT_FAILURE
;
1607 r
= parse_argv(argc
, argv
);
1609 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1612 if (arg_listen_http
|| arg_listen_https
) {
1613 r
= setup_gnutls_logger(arg_gnutls_log
);
1615 return EXIT_FAILURE
;
1618 if (arg_listen_https
|| https_socket
>= 0)
1619 if (load_certificates(&key
, &cert
, &trust
) < 0)
1620 return EXIT_FAILURE
;
1622 if (remoteserver_init(&s
, key
, cert
, trust
) < 0)
1623 return EXIT_FAILURE
;
1625 r
= sd_event_set_watchdog(s
.events
, true);
1627 log_error_errno(r
, "Failed to enable watchdog: %m");
1629 log_debug("Watchdog is %sd.", enable_disable(r
> 0));
1631 log_debug("%s running as pid "PID_FMT
,
1632 program_invocation_short_name
, getpid_cached());
1635 "STATUS=Processing requests...");
1638 r
= sd_event_get_state(s
.events
);
1641 if (r
== SD_EVENT_FINISHED
)
1644 r
= sd_event_run(s
.events
, -1);
1646 log_error_errno(r
, "Failed to run event loop: %m");
1653 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1654 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1662 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;