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/>.
28 #include <sys/prctl.h>
29 #include <sys/socket.h>
33 #include <gnutls/gnutls.h>
36 #include "sd-daemon.h"
38 #include "alloc-util.h"
39 #include "conf-parser.h"
44 #include "journal-file.h"
45 #include "journal-remote-write.h"
46 #include "journal-remote.h"
47 #include "journald-native.h"
49 #include "parse-util.h"
50 #include "signal-util.h"
51 #include "socket-util.h"
52 #include "stat-util.h"
53 #include "stdio-util.h"
54 #include "string-table.h"
55 #include "string-util.h"
58 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
60 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
61 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
62 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
64 static char* arg_url
= NULL
;
65 static char* arg_getter
= NULL
;
66 static char* arg_listen_raw
= NULL
;
67 static char* arg_listen_http
= NULL
;
68 static char* arg_listen_https
= NULL
;
69 static char** arg_files
= NULL
;
70 static int arg_compress
= true;
71 static int arg_seal
= false;
72 static int http_socket
= -1, https_socket
= -1;
73 static char** arg_gnutls_log
= NULL
;
75 static JournalWriteSplitMode arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
76 static char* arg_output
= NULL
;
78 static char *arg_key
= NULL
;
79 static char *arg_cert
= NULL
;
80 static char *arg_trust
= NULL
;
81 static bool arg_trust_all
= false;
83 /**********************************************************************
84 **********************************************************************
85 **********************************************************************/
87 static int spawn_child(const char* child
, char** argv
) {
89 pid_t parent_pid
, child_pid
;
93 return log_error_errno(errno
, "Failed to create pager pipe: %m");
95 parent_pid
= getpid();
99 r
= log_error_errno(errno
, "Failed to fork: %m");
105 if (child_pid
== 0) {
107 (void) reset_all_signal_handlers();
108 (void) reset_signal_mask();
110 r
= dup2(fd
[1], STDOUT_FILENO
);
112 log_error_errno(errno
, "Failed to dup pipe to stdout: %m");
118 /* Make sure the child goes away when the parent dies */
119 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
122 /* Check whether our parent died before we were able
123 * to set the death signal */
124 if (getppid() != parent_pid
)
128 log_error_errno(errno
, "Failed to exec child %s: %m", child
);
134 log_warning_errno(errno
, "Failed to close write end of pipe: %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 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 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
327 if (s
->sources
[fd
] == NULL
) {
328 s
->sources
[fd
] = source_new(fd
, false, name
, writer
);
329 if (!s
->sources
[fd
]) {
330 writer_unref(writer
);
337 *source
= s
->sources
[fd
];
341 static int remove_source(RemoteServer
*s
, int fd
) {
342 RemoteSource
*source
;
345 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
347 source
= s
->sources
[fd
];
349 /* this closes fd too */
351 s
->sources
[fd
] = NULL
;
358 static int add_source(RemoteServer
*s
, int fd
, char* name
, bool own_name
) {
360 RemoteSource
*source
= NULL
;
363 /* This takes ownership of name, even on failure, if own_name is true. */
375 r
= get_source_for_fd(s
, fd
, name
, &source
);
377 log_error_errno(r
, "Failed to create source for fd:%d (%s): %m",
383 r
= sd_event_add_io(s
->events
, &source
->event
,
384 fd
, EPOLLIN
|EPOLLRDHUP
|EPOLLPRI
,
385 dispatch_raw_source_event
, source
);
387 /* Add additional source for buffer processing. It will be
389 r
= sd_event_add_defer(s
->events
, &source
->buffer_event
,
390 dispatch_raw_source_until_block
, source
);
392 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_OFF
);
393 } else if (r
== -EPERM
) {
394 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd
, name
);
395 r
= sd_event_add_defer(s
->events
, &source
->event
,
396 dispatch_blocking_source_event
, source
);
398 sd_event_source_set_enabled(source
->event
, SD_EVENT_ON
);
401 log_error_errno(r
, "Failed to register event source for fd:%d: %m",
406 r
= sd_event_source_set_description(source
->event
, name
);
408 log_error_errno(r
, "Failed to set source name for fd:%d: %m", fd
);
412 return 1; /* work to do */
415 remove_source(s
, fd
);
419 static int add_raw_socket(RemoteServer
*s
, int fd
) {
421 _cleanup_close_
int fd_
= fd
;
422 char name
[sizeof("raw-socket-")-1 + DECIMAL_STR_MAX(int) + 1];
426 r
= sd_event_add_io(s
->events
, &s
->listen_event
,
428 dispatch_raw_connection_event
, s
);
432 xsprintf(name
, "raw-socket-%d", fd
);
434 r
= sd_event_source_set_description(s
->listen_event
, name
);
443 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
446 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
, SOCK_CLOEXEC
);
450 return add_raw_socket(s
, fd
);
453 /**********************************************************************
454 **********************************************************************
455 **********************************************************************/
457 static int request_meta(void **connection_cls
, int fd
, char *hostname
) {
458 RemoteSource
*source
;
462 assert(connection_cls
);
466 r
= get_writer(server
, hostname
, &writer
);
468 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
471 source
= source_new(fd
, true, hostname
, writer
);
473 writer_unref(writer
);
477 log_debug("Added RemoteSource as connection metadata %p", source
);
479 *connection_cls
= source
;
483 static void request_meta_free(void *cls
,
484 struct MHD_Connection
*connection
,
485 void **connection_cls
,
486 enum MHD_RequestTerminationCode toe
) {
489 assert(connection_cls
);
493 log_debug("Cleaning up connection metadata %p", s
);
495 *connection_cls
= NULL
;
499 static int process_http_upload(
500 struct MHD_Connection
*connection
,
501 const char *upload_data
,
502 size_t *upload_data_size
,
503 RemoteSource
*source
) {
505 bool finished
= false;
511 log_trace("%s: connection %p, %zu bytes",
512 __func__
, connection
, *upload_data_size
);
514 if (*upload_data_size
) {
515 log_trace("Received %zu bytes", *upload_data_size
);
517 r
= push_data(source
, upload_data
, *upload_data_size
);
519 return mhd_respond_oom(connection
);
521 *upload_data_size
= 0;
526 r
= process_source(source
, arg_compress
, arg_seal
);
530 log_warning("Failed to process data for connection %p", connection
);
532 return mhd_respondf(connection
,
533 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
,
534 "Entry is too large, maximum is %u bytes.\n",
537 return mhd_respondf(connection
,
538 MHD_HTTP_UNPROCESSABLE_ENTITY
,
539 "Processing failed: %s.", strerror(-r
));
546 /* The upload is finished */
548 remaining
= source_non_empty(source
);
550 log_warning("Premature EOFbyte. %zu bytes lost.", remaining
);
551 return mhd_respondf(connection
, MHD_HTTP_EXPECTATION_FAILED
,
552 "Premature EOF. %zu bytes of trailing data not processed.",
556 return mhd_respond(connection
, MHD_HTTP_ACCEPTED
, "OK.\n");
559 static int request_handler(
561 struct MHD_Connection
*connection
,
565 const char *upload_data
,
566 size_t *upload_data_size
,
567 void **connection_cls
) {
571 _cleanup_free_
char *hostname
= NULL
;
574 assert(connection_cls
);
578 log_trace("Handling a connection %s %s %s", method
, url
, version
);
581 return process_http_upload(connection
,
582 upload_data
, upload_data_size
,
585 if (!streq(method
, "POST"))
586 return mhd_respond(connection
, MHD_HTTP_NOT_ACCEPTABLE
,
587 "Unsupported method.\n");
589 if (!streq(url
, "/upload"))
590 return mhd_respond(connection
, MHD_HTTP_NOT_FOUND
,
593 header
= MHD_lookup_connection_value(connection
,
594 MHD_HEADER_KIND
, "Content-Type");
595 if (!header
|| !streq(header
, "application/vnd.fdo.journal"))
596 return mhd_respond(connection
, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE
,
597 "Content-Type: application/vnd.fdo.journal"
601 const union MHD_ConnectionInfo
*ci
;
603 ci
= MHD_get_connection_info(connection
,
604 MHD_CONNECTION_INFO_CONNECTION_FD
);
606 log_error("MHD_get_connection_info failed: cannot get remote fd");
607 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
608 "Cannot check remote address");
615 if (server
->check_trust
) {
616 r
= check_permissions(connection
, &code
, &hostname
);
620 r
= getpeername_pretty(fd
, false, &hostname
);
622 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
623 "Cannot check remote hostname");
628 r
= request_meta(connection_cls
, fd
, hostname
);
630 return respond_oom(connection
);
632 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
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
, DATA_SIZE_MAX
},
657 MHD_USE_EPOLL_LINUX_ONLY
|
658 MHD_USE_PEDANTIC_CHECKS
|
659 MHD_USE_PIPE_FOR_SHUTDOWN
;
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
);
674 opts
[opts_pos
++] = (struct MHD_OptionItem
)
675 {MHD_OPTION_HTTPS_MEM_KEY
, 0, (char*) key
};
676 opts
[opts_pos
++] = (struct MHD_OptionItem
)
677 {MHD_OPTION_HTTPS_MEM_CERT
, 0, (char*) cert
};
679 flags
|= MHD_USE_SSL
;
682 opts
[opts_pos
++] = (struct MHD_OptionItem
)
683 {MHD_OPTION_HTTPS_MEM_TRUST
, 0, (char*) trust
};
686 d
= new(MHDDaemonWrapper
, 1);
690 d
->fd
= (uint64_t) fd
;
692 d
->daemon
= MHD_start_daemon(flags
, 0,
694 request_handler
, NULL
,
695 MHD_OPTION_ARRAY
, opts
,
698 log_error("Failed to start µhttp daemon");
703 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
704 key
? "HTTPS" : "HTTP", fd
, d
);
707 info
= MHD_get_daemon_info(d
->daemon
, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
);
709 log_error("µhttp returned NULL daemon info");
714 epoll_fd
= info
->listen_fd
;
716 log_error("µhttp epoll fd is invalid");
721 r
= sd_event_add_io(s
->events
, &d
->event
,
723 dispatch_http_event
, d
);
725 log_error_errno(r
, "Failed to add event callback: %m");
729 r
= sd_event_source_set_description(d
->event
, "epoll-fd");
731 log_error_errno(r
, "Failed to set source name: %m");
735 r
= hashmap_ensure_allocated(&s
->daemons
, &uint64_hash_ops
);
741 r
= hashmap_put(s
->daemons
, &d
->fd
, d
);
743 log_error_errno(r
, "Failed to add daemon to hashmap: %m");
751 MHD_stop_daemon(d
->daemon
);
757 static int setup_microhttpd_socket(RemoteServer
*s
,
764 fd
= make_socket_fd(LOG_DEBUG
, address
, SOCK_STREAM
, SOCK_CLOEXEC
);
768 return setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
771 static int dispatch_http_event(sd_event_source
*event
,
775 MHDDaemonWrapper
*d
= userdata
;
780 r
= MHD_run(d
->daemon
);
782 log_error("MHD_run failed!");
783 // XXX: unregister daemon
787 return 1; /* work to do */
790 /**********************************************************************
791 **********************************************************************
792 **********************************************************************/
794 static int setup_signals(RemoteServer
*s
) {
799 assert_se(sigprocmask_many(SIG_SETMASK
, NULL
, SIGINT
, SIGTERM
, -1) >= 0);
801 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
805 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
812 static int negative_fd(const char *spec
) {
813 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
817 r
= safe_atoi(spec
, &fd
);
827 static int remoteserver_init(RemoteServer
*s
,
836 if ((arg_listen_raw
|| arg_listen_http
) && trust
) {
837 log_error("Option --trust makes all non-HTTPS connections untrusted.");
841 r
= sd_event_default(&s
->events
);
843 return log_error_errno(r
, "Failed to allocate event loop: %m");
847 assert(server
== NULL
);
850 r
= init_writer_hashmap(s
);
854 n
= sd_listen_fds(true);
856 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
858 log_debug("Received %d descriptors", n
);
860 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
) {
861 log_error("Received fewer sockets than expected");
865 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
866 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
867 log_debug("Received a listening socket (fd:%d)", fd
);
869 if (fd
== http_socket
)
870 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
871 else if (fd
== https_socket
)
872 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
874 r
= add_raw_socket(s
, fd
);
875 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
878 r
= getpeername_pretty(fd
, false, &hostname
);
880 return log_error_errno(r
, "Failed to retrieve remote name: %m");
882 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
884 r
= add_source(s
, fd
, hostname
, true);
886 log_error("Unknown socket passed on fd:%d", fd
);
892 return log_error_errno(r
, "Failed to register socket (fd:%d): %m",
897 log_info("Spawning getter %s...", arg_getter
);
898 fd
= spawn_getter(arg_getter
);
902 r
= add_source(s
, fd
, (char*) arg_output
, false);
911 if (!strstr(arg_url
, "/entries")) {
912 if (endswith(arg_url
, "/"))
913 url
= strjoina(arg_url
, "entries");
915 url
= strjoina(arg_url
, "/entries");
918 url
= strdupa(arg_url
);
920 log_info("Spawning curl %s...", url
);
921 fd
= spawn_curl(url
);
926 startswith(arg_url
, "https://") ?:
927 startswith(arg_url
, "http://") ?:
930 hostname
= strdupa(hostname
);
933 if ((p
= strchr(hostname
, '/')))
935 if ((p
= strchr(hostname
, ':')))
938 r
= add_source(s
, fd
, hostname
, false);
943 if (arg_listen_raw
) {
944 log_debug("Listening on a socket...");
945 r
= setup_raw_socket(s
, arg_listen_raw
);
950 if (arg_listen_http
) {
951 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
956 if (arg_listen_https
) {
957 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
962 STRV_FOREACH(file
, arg_files
) {
963 const char *output_name
;
965 if (streq(*file
, "-")) {
966 log_debug("Using standard input as source.");
969 output_name
= "stdin";
971 log_debug("Reading file %s...", *file
);
973 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
975 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
979 r
= add_source(s
, fd
, (char*) output_name
, false);
984 if (s
->active
== 0) {
985 log_error("Zero sources specified");
989 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
990 /* In this case we know what the writer will be
991 called, so we can create it and verify that we can
992 create output as expected. */
993 r
= get_writer(s
, NULL
, &s
->_single_writer
);
1001 static void server_destroy(RemoteServer
*s
) {
1003 MHDDaemonWrapper
*d
;
1005 while ((d
= hashmap_steal_first(s
->daemons
))) {
1006 MHD_stop_daemon(d
->daemon
);
1007 sd_event_source_unref(d
->event
);
1011 hashmap_free(s
->daemons
);
1013 assert(s
->sources_size
== 0 || s
->sources
);
1014 for (i
= 0; i
< s
->sources_size
; i
++)
1015 remove_source(s
, i
);
1018 writer_unref(s
->_single_writer
);
1019 hashmap_free(s
->writers
);
1021 sd_event_source_unref(s
->sigterm_event
);
1022 sd_event_source_unref(s
->sigint_event
);
1023 sd_event_source_unref(s
->listen_event
);
1024 sd_event_unref(s
->events
);
1026 /* fds that we're listening on remain open... */
1029 /**********************************************************************
1030 **********************************************************************
1031 **********************************************************************/
1033 static int handle_raw_source(sd_event_source
*event
,
1038 RemoteSource
*source
;
1041 /* Returns 1 if there might be more data pending,
1042 * 0 if data is currently exhausted, negative on error.
1045 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
1046 source
= s
->sources
[fd
];
1047 assert(source
->fd
== fd
);
1049 r
= process_source(source
, arg_compress
, arg_seal
);
1050 if (source
->state
== STATE_EOF
) {
1053 log_debug("EOF reached with source fd:%d (%s)",
1054 source
->fd
, source
->name
);
1056 remaining
= source_non_empty(source
);
1058 log_notice("Premature EOF. %zu bytes lost.", remaining
);
1059 remove_source(s
, source
->fd
);
1060 log_debug("%zu active sources remaining", s
->active
);
1062 } else if (r
== -E2BIG
) {
1063 log_notice_errno(E2BIG
, "Entry too big, skipped");
1065 } else if (r
== -EAGAIN
) {
1068 log_debug_errno(r
, "Closing connection: %m");
1069 remove_source(server
, fd
);
1075 static int dispatch_raw_source_until_block(sd_event_source
*event
,
1077 RemoteSource
*source
= userdata
;
1080 /* Make sure event stays around even if source is destroyed */
1081 sd_event_source_ref(event
);
1083 r
= handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1085 /* No more data for now */
1086 sd_event_source_set_enabled(event
, SD_EVENT_OFF
);
1088 sd_event_source_unref(event
);
1093 static int dispatch_raw_source_event(sd_event_source
*event
,
1097 RemoteSource
*source
= userdata
;
1100 assert(source
->event
);
1101 assert(source
->buffer_event
);
1103 r
= handle_raw_source(event
, fd
, EPOLLIN
, server
);
1105 /* Might have more data. We need to rerun the handler
1106 * until we are sure the buffer is exhausted. */
1107 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_ON
);
1112 static int dispatch_blocking_source_event(sd_event_source
*event
,
1114 RemoteSource
*source
= userdata
;
1116 return handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1119 static int accept_connection(const char* type
, int fd
,
1120 SocketAddress
*addr
, char **hostname
) {
1123 log_debug("Accepting new %s connection on fd:%d", type
, fd
);
1124 fd2
= accept4(fd
, &addr
->sockaddr
.sa
, &addr
->size
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
1126 return log_error_errno(errno
, "accept() on fd:%d failed: %m", fd
);
1128 switch(socket_address_family(addr
)) {
1131 _cleanup_free_
char *a
= NULL
;
1134 r
= socket_address_print(addr
, &a
);
1136 log_error_errno(r
, "socket_address_print(): %m");
1141 r
= socknameinfo_pretty(&addr
->sockaddr
, addr
->size
, &b
);
1143 log_error_errno(r
, "Resolving hostname failed: %m");
1148 log_debug("Accepted %s %s connection from %s",
1150 socket_address_family(addr
) == AF_INET
? "IP" : "IPv6",
1158 log_error("Rejected %s connection with unsupported family %d",
1159 type
, socket_address_family(addr
));
1166 static int dispatch_raw_connection_event(sd_event_source
*event
,
1170 RemoteServer
*s
= userdata
;
1172 SocketAddress addr
= {
1173 .size
= sizeof(union sockaddr_union
),
1174 .type
= SOCK_STREAM
,
1176 char *hostname
= NULL
;
1178 fd2
= accept_connection("raw", fd
, &addr
, &hostname
);
1182 return add_source(s
, fd2
, hostname
, true);
1185 /**********************************************************************
1186 **********************************************************************
1187 **********************************************************************/
1189 static const char* const journal_write_split_mode_table
[_JOURNAL_WRITE_SPLIT_MAX
] = {
1190 [JOURNAL_WRITE_SPLIT_NONE
] = "none",
1191 [JOURNAL_WRITE_SPLIT_HOST
] = "host",
1194 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode
, JournalWriteSplitMode
);
1195 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode
,
1196 journal_write_split_mode
,
1197 JournalWriteSplitMode
,
1198 "Failed to parse split mode setting");
1200 static int parse_config(void) {
1201 const ConfigTableItem items
[] = {
1202 { "Remote", "Seal", config_parse_bool
, 0, &arg_seal
},
1203 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
1204 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
1205 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
1206 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
1209 return config_parse_many(PKGSYSCONFDIR
"/journal-remote.conf",
1210 CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
1211 "Remote\0", config_item_table_lookup
, items
,
1215 static void help(void) {
1216 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1217 "Write external journal events to journal file(s).\n\n"
1218 " -h --help Show this help\n"
1219 " --version Show package version\n"
1220 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1221 " --getter=COMMAND Read events from the output of COMMAND\n"
1222 " --listen-raw=ADDR Listen for connections at ADDR\n"
1223 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1224 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1225 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1226 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1227 " --seal[=BOOL] Use event sealing (default: no)\n"
1228 " --key=FILENAME SSL key in PEM format (default:\n"
1229 " \"" PRIV_KEY_FILE
"\")\n"
1230 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1231 " \"" CERT_FILE
"\")\n"
1232 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1233 " \"" TRUST_FILE
"\")\n"
1234 " --gnutls-log=CATEGORY...\n"
1235 " Specify a list of gnutls logging categories\n"
1236 " --split-mode=none|host How many output files to create\n"
1238 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1239 , program_invocation_short_name
);
1242 static int parse_argv(int argc
, char *argv
[]) {
1244 ARG_VERSION
= 0x100,
1259 static const struct option options
[] = {
1260 { "help", no_argument
, NULL
, 'h' },
1261 { "version", no_argument
, NULL
, ARG_VERSION
},
1262 { "url", required_argument
, NULL
, ARG_URL
},
1263 { "getter", required_argument
, NULL
, ARG_GETTER
},
1264 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
1265 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
1266 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
1267 { "output", required_argument
, NULL
, 'o' },
1268 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
1269 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
1270 { "seal", optional_argument
, NULL
, ARG_SEAL
},
1271 { "key", required_argument
, NULL
, ARG_KEY
},
1272 { "cert", required_argument
, NULL
, ARG_CERT
},
1273 { "trust", required_argument
, NULL
, ARG_TRUST
},
1274 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
1279 bool type_a
, type_b
;
1284 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
1288 return 0 /* done */;
1295 log_error("cannot currently set more than one --url");
1304 log_error("cannot currently use --getter more than once");
1308 arg_getter
= optarg
;
1311 case ARG_LISTEN_RAW
:
1312 if (arg_listen_raw
) {
1313 log_error("cannot currently use --listen-raw more than once");
1317 arg_listen_raw
= optarg
;
1320 case ARG_LISTEN_HTTP
:
1321 if (arg_listen_http
|| http_socket
>= 0) {
1322 log_error("cannot currently use --listen-http more than once");
1326 r
= negative_fd(optarg
);
1330 arg_listen_http
= optarg
;
1333 case ARG_LISTEN_HTTPS
:
1334 if (arg_listen_https
|| https_socket
>= 0) {
1335 log_error("cannot currently use --listen-https more than once");
1339 r
= negative_fd(optarg
);
1343 arg_listen_https
= optarg
;
1349 log_error("Key file specified twice");
1353 arg_key
= strdup(optarg
);
1361 log_error("Certificate file specified twice");
1365 arg_cert
= strdup(optarg
);
1372 if (arg_trust
|| arg_trust_all
) {
1373 log_error("Confusing trusted CA configuration");
1377 if (streq(optarg
, "all"))
1378 arg_trust_all
= true;
1381 arg_trust
= strdup(optarg
);
1385 log_error("Option --trust is not available.");
1394 log_error("cannot use --output/-o more than once");
1398 arg_output
= optarg
;
1401 case ARG_SPLIT_MODE
:
1402 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
1403 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
) {
1404 log_error("Invalid split mode: %s", optarg
);
1411 r
= parse_boolean(optarg
);
1413 log_error("Failed to parse --compress= parameter.");
1419 arg_compress
= true;
1425 r
= parse_boolean(optarg
);
1427 log_error("Failed to parse --seal= parameter.");
1437 case ARG_GNUTLS_LOG
: {
1439 const char* p
= optarg
;
1441 _cleanup_free_
char *word
= NULL
;
1443 r
= extract_first_word(&p
, &word
, ",", 0);
1445 return log_error_errno(r
, "Failed to parse --gnutls-log= argument: %m");
1450 if (strv_push(&arg_gnutls_log
, word
) < 0)
1457 log_error("Option --gnutls-log is not available.");
1466 assert_not_reached("Unknown option code.");
1470 arg_files
= argv
+ optind
;
1472 type_a
= arg_getter
|| !strv_isempty(arg_files
);
1475 || arg_listen_http
|| arg_listen_https
1476 || sd_listen_fds(false) > 0;
1477 if (type_a
&& type_b
) {
1478 log_error("Cannot use file input or --getter with "
1479 "--arg-listen-... or socket activation.");
1484 log_error("Option --output must be specified with file input or --getter.");
1488 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1491 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
1492 && arg_output
&& is_dir(arg_output
, true) > 0) {
1493 log_error("For SplitMode=none, output must be a file.");
1497 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1498 && arg_output
&& is_dir(arg_output
, true) <= 0) {
1499 log_error("For SplitMode=host, output must be a directory.");
1503 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1504 journal_write_split_mode_to_string(arg_split_mode
),
1509 return 1 /* work to do */;
1512 static int load_certificates(char **key
, char **cert
, char **trust
) {
1515 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1517 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1518 arg_key
?: PRIV_KEY_FILE
);
1520 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1522 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1523 arg_cert
?: CERT_FILE
);
1526 log_info("Certificate checking disabled.");
1528 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1530 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1531 arg_trust
?: TRUST_FILE
);
1537 int main(int argc
, char **argv
) {
1538 RemoteServer s
= {};
1540 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1542 log_show_color(true);
1543 log_parse_environment();
1547 return EXIT_FAILURE
;
1549 r
= parse_argv(argc
, argv
);
1551 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1554 if (arg_listen_http
|| arg_listen_https
) {
1555 r
= setup_gnutls_logger(arg_gnutls_log
);
1557 return EXIT_FAILURE
;
1560 if (arg_listen_https
|| https_socket
>= 0)
1561 if (load_certificates(&key
, &cert
, &trust
) < 0)
1562 return EXIT_FAILURE
;
1564 if (remoteserver_init(&s
, key
, cert
, trust
) < 0)
1565 return EXIT_FAILURE
;
1567 r
= sd_event_set_watchdog(s
.events
, true);
1569 log_error_errno(r
, "Failed to enable watchdog: %m");
1571 log_debug("Watchdog is %s.", r
> 0 ? "enabled" : "disabled");
1573 log_debug("%s running as pid "PID_FMT
,
1574 program_invocation_short_name
, getpid());
1577 "STATUS=Processing requests...");
1580 r
= sd_event_get_state(s
.events
);
1583 if (r
== SD_EVENT_FINISHED
)
1586 r
= sd_event_run(s
.events
, -1);
1588 log_error_errno(r
, "Failed to run event loop: %m");
1595 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1596 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1604 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;