1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Zbigniew Jędrzejewski-Szmek
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/prctl.h>
28 #include <sys/socket.h>
32 #include "sd-daemon.h"
33 #include "signal-util.h"
34 #include "journal-file.h"
35 #include "journald-native.h"
36 #include "socket-util.h"
41 #include "conf-parser.h"
44 #include <gnutls/gnutls.h>
47 #include "journal-remote.h"
48 #include "journal-remote-write.h"
50 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
52 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
53 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
54 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
56 static char* arg_url
= NULL
;
57 static char* arg_getter
= NULL
;
58 static char* arg_listen_raw
= NULL
;
59 static char* arg_listen_http
= NULL
;
60 static char* arg_listen_https
= NULL
;
61 static char** arg_files
= NULL
;
62 static int arg_compress
= true;
63 static int arg_seal
= false;
64 static int http_socket
= -1, https_socket
= -1;
65 static char** arg_gnutls_log
= NULL
;
67 static JournalWriteSplitMode arg_split_mode
= JOURNAL_WRITE_SPLIT_HOST
;
68 static char* arg_output
= NULL
;
70 static char *arg_key
= NULL
;
71 static char *arg_cert
= NULL
;
72 static char *arg_trust
= NULL
;
73 static bool arg_trust_all
= false;
75 /**********************************************************************
76 **********************************************************************
77 **********************************************************************/
79 static int spawn_child(const char* child
, char** argv
) {
81 pid_t parent_pid
, child_pid
;
85 return log_error_errno(errno
, "Failed to create pager pipe: %m");
87 parent_pid
= getpid();
92 log_error_errno(errno
, "Failed to fork: %m");
99 r
= dup2(fd
[1], STDOUT_FILENO
);
101 log_error_errno(errno
, "Failed to dup pipe to stdout: %m");
107 /* Make sure the child goes away when the parent dies */
108 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
) < 0)
111 /* Check whether our parent died before we were able
112 * to set the death signal */
113 if (getppid() != parent_pid
)
117 log_error_errno(errno
, "Failed to exec child %s: %m", child
);
123 log_warning_errno(errno
, "Failed to close write end of pipe: %m");
128 static int spawn_curl(const char* url
) {
129 char **argv
= STRV_MAKE("curl",
130 "-HAccept: application/vnd.fdo.journal",
136 r
= spawn_child("curl", argv
);
138 log_error_errno(errno
, "Failed to spawn curl: %m");
142 static int spawn_getter(const char *getter
, const char *url
) {
144 _cleanup_strv_free_
char **words
= NULL
;
147 r
= strv_split_quoted(&words
, getter
, 0);
149 return log_error_errno(r
, "Failed to split getter option: %m");
151 r
= strv_extend(&words
, url
);
153 return log_error_errno(r
, "Failed to create command line: %m");
155 r
= spawn_child(words
[0], words
);
157 log_error_errno(errno
, "Failed to spawn getter %s: %m", getter
);
162 #define filename_escape(s) xescape((s), "/ ")
164 static int open_output(Writer
*w
, const char* host
) {
165 _cleanup_free_
char *_output
= NULL
;
169 switch (arg_split_mode
) {
170 case JOURNAL_WRITE_SPLIT_NONE
:
171 output
= arg_output
?: REMOTE_JOURNAL_PATH
"/remote.journal";
174 case JOURNAL_WRITE_SPLIT_HOST
: {
175 _cleanup_free_
char *name
;
179 name
= filename_escape(host
);
183 r
= asprintf(&_output
, "%s/remote-%s.journal",
184 arg_output
?: REMOTE_JOURNAL_PATH
,
194 assert_not_reached("what?");
197 r
= journal_file_open_reliably(output
,
198 O_RDWR
|O_CREAT
, 0640,
199 arg_compress
, arg_seal
,
204 log_error_errno(r
, "Failed to open output journal %s: %m",
207 log_debug("Opened output file %s", w
->journal
->path
);
211 /**********************************************************************
212 **********************************************************************
213 **********************************************************************/
215 static int init_writer_hashmap(RemoteServer
*s
) {
216 static const struct hash_ops
*hash_ops
[] = {
217 [JOURNAL_WRITE_SPLIT_NONE
] = NULL
,
218 [JOURNAL_WRITE_SPLIT_HOST
] = &string_hash_ops
,
221 assert(arg_split_mode
>= 0 && arg_split_mode
< (int) ELEMENTSOF(hash_ops
));
223 s
->writers
= hashmap_new(hash_ops
[arg_split_mode
]);
230 static int get_writer(RemoteServer
*s
, const char *host
,
233 _cleanup_writer_unref_ Writer
*w
= NULL
;
236 switch(arg_split_mode
) {
237 case JOURNAL_WRITE_SPLIT_NONE
:
238 key
= "one and only";
241 case JOURNAL_WRITE_SPLIT_HOST
:
247 assert_not_reached("what split mode?");
250 w
= hashmap_get(s
->writers
, key
);
258 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
) {
259 w
->hashmap_key
= strdup(key
);
264 r
= open_output(w
, host
);
268 r
= hashmap_put(s
->writers
, w
->hashmap_key
?: key
, w
);
278 /**********************************************************************
279 **********************************************************************
280 **********************************************************************/
282 /* This should go away as soon as µhttpd allows state to be passed around. */
283 static RemoteServer
*server
;
285 static int dispatch_raw_source_event(sd_event_source
*event
,
289 static int dispatch_raw_source_until_block(sd_event_source
*event
,
291 static int dispatch_blocking_source_event(sd_event_source
*event
,
293 static int dispatch_raw_connection_event(sd_event_source
*event
,
297 static int dispatch_http_event(sd_event_source
*event
,
302 static int get_source_for_fd(RemoteServer
*s
,
303 int fd
, char *name
, RemoteSource
**source
) {
307 /* This takes ownership of name, but only on success. */
312 if (!GREEDY_REALLOC0(s
->sources
, s
->sources_size
, fd
+ 1))
315 r
= get_writer(s
, name
, &writer
);
317 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
320 if (s
->sources
[fd
] == NULL
) {
321 s
->sources
[fd
] = source_new(fd
, false, name
, writer
);
322 if (!s
->sources
[fd
]) {
323 writer_unref(writer
);
330 *source
= s
->sources
[fd
];
334 static int remove_source(RemoteServer
*s
, int fd
) {
335 RemoteSource
*source
;
338 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
340 source
= s
->sources
[fd
];
342 /* this closes fd too */
344 s
->sources
[fd
] = NULL
;
351 static int add_source(RemoteServer
*s
, int fd
, char* name
, bool own_name
) {
353 RemoteSource
*source
= NULL
;
356 /* This takes ownership of name, even on failure, if own_name is true. */
368 r
= get_source_for_fd(s
, fd
, name
, &source
);
370 log_error_errno(r
, "Failed to create source for fd:%d (%s): %m",
376 r
= sd_event_add_io(s
->events
, &source
->event
,
377 fd
, EPOLLIN
|EPOLLRDHUP
|EPOLLPRI
,
378 dispatch_raw_source_event
, source
);
380 /* Add additional source for buffer processing. It will be
382 r
= sd_event_add_defer(s
->events
, &source
->buffer_event
,
383 dispatch_raw_source_until_block
, source
);
385 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_OFF
);
386 } else if (r
== -EPERM
) {
387 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd
, name
);
388 r
= sd_event_add_defer(s
->events
, &source
->event
,
389 dispatch_blocking_source_event
, source
);
391 sd_event_source_set_enabled(source
->event
, SD_EVENT_ON
);
394 log_error_errno(r
, "Failed to register event source for fd:%d: %m",
399 r
= sd_event_source_set_description(source
->event
, name
);
401 log_error_errno(r
, "Failed to set source name for fd:%d: %m", fd
);
405 return 1; /* work to do */
408 remove_source(s
, fd
);
412 static int add_raw_socket(RemoteServer
*s
, int fd
) {
414 _cleanup_close_
int fd_
= fd
;
415 char name
[sizeof("raw-socket-")-1 + DECIMAL_STR_MAX(int) + 1];
419 r
= sd_event_add_io(s
->events
, &s
->listen_event
,
421 dispatch_raw_connection_event
, s
);
425 xsprintf(name
, "raw-socket-%d", fd
);
427 r
= sd_event_source_set_description(s
->listen_event
, name
);
436 static int setup_raw_socket(RemoteServer
*s
, const char *address
) {
439 fd
= make_socket_fd(LOG_INFO
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
443 return add_raw_socket(s
, fd
);
446 /**********************************************************************
447 **********************************************************************
448 **********************************************************************/
450 static int request_meta(void **connection_cls
, int fd
, char *hostname
) {
451 RemoteSource
*source
;
455 assert(connection_cls
);
459 r
= get_writer(server
, hostname
, &writer
);
461 return log_warning_errno(r
, "Failed to get writer for source %s: %m",
464 source
= source_new(fd
, true, hostname
, writer
);
466 writer_unref(writer
);
470 log_debug("Added RemoteSource as connection metadata %p", source
);
472 *connection_cls
= source
;
476 static void request_meta_free(void *cls
,
477 struct MHD_Connection
*connection
,
478 void **connection_cls
,
479 enum MHD_RequestTerminationCode toe
) {
482 assert(connection_cls
);
486 log_debug("Cleaning up connection metadata %p", s
);
488 *connection_cls
= NULL
;
492 static int process_http_upload(
493 struct MHD_Connection
*connection
,
494 const char *upload_data
,
495 size_t *upload_data_size
,
496 RemoteSource
*source
) {
498 bool finished
= false;
504 log_trace("%s: connection %p, %zu bytes",
505 __func__
, connection
, *upload_data_size
);
507 if (*upload_data_size
) {
508 log_trace("Received %zu bytes", *upload_data_size
);
510 r
= push_data(source
, upload_data
, *upload_data_size
);
512 return mhd_respond_oom(connection
);
514 *upload_data_size
= 0;
519 r
= process_source(source
, arg_compress
, arg_seal
);
523 log_warning("Failed to process data for connection %p", connection
);
525 return mhd_respondf(connection
,
526 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE
,
527 "Entry is too large, maximum is %u bytes.\n",
530 return mhd_respondf(connection
,
531 MHD_HTTP_UNPROCESSABLE_ENTITY
,
532 "Processing failed: %s.", strerror(-r
));
539 /* The upload is finished */
541 remaining
= source_non_empty(source
);
543 log_warning("Premature EOFbyte. %zu bytes lost.", remaining
);
544 return mhd_respondf(connection
, MHD_HTTP_EXPECTATION_FAILED
,
545 "Premature EOF. %zu bytes of trailing data not processed.",
549 return mhd_respond(connection
, MHD_HTTP_ACCEPTED
, "OK.\n");
552 static int request_handler(
554 struct MHD_Connection
*connection
,
558 const char *upload_data
,
559 size_t *upload_data_size
,
560 void **connection_cls
) {
564 _cleanup_free_
char *hostname
= NULL
;
567 assert(connection_cls
);
571 log_trace("Handling a connection %s %s %s", method
, url
, version
);
574 return process_http_upload(connection
,
575 upload_data
, upload_data_size
,
578 if (!streq(method
, "POST"))
579 return mhd_respond(connection
, MHD_HTTP_METHOD_NOT_ACCEPTABLE
,
580 "Unsupported method.\n");
582 if (!streq(url
, "/upload"))
583 return mhd_respond(connection
, MHD_HTTP_NOT_FOUND
,
586 header
= MHD_lookup_connection_value(connection
,
587 MHD_HEADER_KIND
, "Content-Type");
588 if (!header
|| !streq(header
, "application/vnd.fdo.journal"))
589 return mhd_respond(connection
, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE
,
590 "Content-Type: application/vnd.fdo.journal"
594 const union MHD_ConnectionInfo
*ci
;
596 ci
= MHD_get_connection_info(connection
,
597 MHD_CONNECTION_INFO_CONNECTION_FD
);
599 log_error("MHD_get_connection_info failed: cannot get remote fd");
600 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
601 "Cannot check remote address");
608 if (server
->check_trust
) {
609 r
= check_permissions(connection
, &code
, &hostname
);
613 r
= getnameinfo_pretty(fd
, &hostname
);
615 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
616 "Cannot check remote hostname");
622 r
= request_meta(connection_cls
, fd
, hostname
);
624 return respond_oom(connection
);
626 return mhd_respond(connection
, MHD_HTTP_INTERNAL_SERVER_ERROR
,
633 static int setup_microhttpd_server(RemoteServer
*s
,
638 struct MHD_OptionItem opts
[] = {
639 { MHD_OPTION_NOTIFY_COMPLETED
, (intptr_t) request_meta_free
},
640 { MHD_OPTION_EXTERNAL_LOGGER
, (intptr_t) microhttpd_logger
},
641 { MHD_OPTION_LISTEN_SOCKET
, fd
},
649 MHD_USE_PEDANTIC_CHECKS
|
650 MHD_USE_EPOLL_LINUX_ONLY
|
653 const union MHD_DaemonInfo
*info
;
659 r
= fd_nonblock(fd
, true);
661 return log_error_errno(r
, "Failed to make fd:%d nonblocking: %m", fd
);
666 opts
[opts_pos
++] = (struct MHD_OptionItem
)
667 {MHD_OPTION_HTTPS_MEM_KEY
, 0, (char*) key
};
668 opts
[opts_pos
++] = (struct MHD_OptionItem
)
669 {MHD_OPTION_HTTPS_MEM_CERT
, 0, (char*) cert
};
671 flags
|= MHD_USE_SSL
;
674 opts
[opts_pos
++] = (struct MHD_OptionItem
)
675 {MHD_OPTION_HTTPS_MEM_TRUST
, 0, (char*) trust
};
678 d
= new(MHDDaemonWrapper
, 1);
682 d
->fd
= (uint64_t) fd
;
684 d
->daemon
= MHD_start_daemon(flags
, 0,
686 request_handler
, NULL
,
687 MHD_OPTION_ARRAY
, opts
,
690 log_error("Failed to start µhttp daemon");
695 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
696 key
? "HTTPS" : "HTTP", fd
, d
);
699 info
= MHD_get_daemon_info(d
->daemon
, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY
);
701 log_error("µhttp returned NULL daemon info");
706 epoll_fd
= info
->listen_fd
;
708 log_error("µhttp epoll fd is invalid");
713 r
= sd_event_add_io(s
->events
, &d
->event
,
715 dispatch_http_event
, d
);
717 log_error_errno(r
, "Failed to add event callback: %m");
721 r
= sd_event_source_set_description(d
->event
, "epoll-fd");
723 log_error_errno(r
, "Failed to set source name: %m");
727 r
= hashmap_ensure_allocated(&s
->daemons
, &uint64_hash_ops
);
733 r
= hashmap_put(s
->daemons
, &d
->fd
, d
);
735 log_error_errno(r
, "Failed to add daemon to hashmap: %m");
743 MHD_stop_daemon(d
->daemon
);
749 static int setup_microhttpd_socket(RemoteServer
*s
,
756 fd
= make_socket_fd(LOG_DEBUG
, address
, SOCK_STREAM
| SOCK_CLOEXEC
);
760 return setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
763 static int dispatch_http_event(sd_event_source
*event
,
767 MHDDaemonWrapper
*d
= userdata
;
772 r
= MHD_run(d
->daemon
);
774 log_error("MHD_run failed!");
775 // XXX: unregister daemon
779 return 1; /* work to do */
782 /**********************************************************************
783 **********************************************************************
784 **********************************************************************/
786 static int setup_signals(RemoteServer
*s
) {
792 assert_se(sigemptyset(&mask
) == 0);
793 sigset_add_many(&mask
, SIGINT
, SIGTERM
, -1);
794 assert_se(sigprocmask(SIG_SETMASK
, &mask
, NULL
) == 0);
796 r
= sd_event_add_signal(s
->events
, &s
->sigterm_event
, SIGTERM
, NULL
, s
);
800 r
= sd_event_add_signal(s
->events
, &s
->sigint_event
, SIGINT
, NULL
, s
);
807 static int negative_fd(const char *spec
) {
808 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
812 r
= safe_atoi(spec
, &fd
);
822 static int remoteserver_init(RemoteServer
*s
,
831 if ((arg_listen_raw
|| arg_listen_http
) && trust
) {
832 log_error("Option --trust makes all non-HTTPS connections untrusted.");
836 r
= sd_event_default(&s
->events
);
838 return log_error_errno(r
, "Failed to allocate event loop: %m");
842 assert(server
== NULL
);
845 r
= init_writer_hashmap(s
);
849 n
= sd_listen_fds(true);
851 return log_error_errno(n
, "Failed to read listening file descriptors from environment: %m");
853 log_debug("Received %d descriptors", n
);
855 if (MAX(http_socket
, https_socket
) >= SD_LISTEN_FDS_START
+ n
) {
856 log_error("Received fewer sockets than expected");
860 for (fd
= SD_LISTEN_FDS_START
; fd
< SD_LISTEN_FDS_START
+ n
; fd
++) {
861 if (sd_is_socket(fd
, AF_UNSPEC
, 0, true)) {
862 log_debug("Received a listening socket (fd:%d)", fd
);
864 if (fd
== http_socket
)
865 r
= setup_microhttpd_server(s
, fd
, NULL
, NULL
, NULL
);
866 else if (fd
== https_socket
)
867 r
= setup_microhttpd_server(s
, fd
, key
, cert
, trust
);
869 r
= add_raw_socket(s
, fd
);
870 } else if (sd_is_socket(fd
, AF_UNSPEC
, 0, false)) {
873 r
= getnameinfo_pretty(fd
, &hostname
);
875 return log_error_errno(r
, "Failed to retrieve remote name: %m");
877 log_debug("Received a connection socket (fd:%d) from %s", fd
, hostname
);
879 r
= add_source(s
, fd
, hostname
, true);
881 log_error("Unknown socket passed on fd:%d", fd
);
887 return log_error_errno(r
, "Failed to register socket (fd:%d): %m",
892 const char *url
, *hostname
;
894 url
= strjoina(arg_url
, "/entries");
897 log_info("Spawning getter %s...", url
);
898 fd
= spawn_getter(arg_getter
, url
);
900 log_info("Spawning curl %s...", url
);
901 fd
= spawn_curl(url
);
907 startswith(arg_url
, "https://") ?:
908 startswith(arg_url
, "http://") ?:
911 r
= add_source(s
, fd
, (char*) hostname
, false);
916 if (arg_listen_raw
) {
917 log_debug("Listening on a socket...");
918 r
= setup_raw_socket(s
, arg_listen_raw
);
923 if (arg_listen_http
) {
924 r
= setup_microhttpd_socket(s
, arg_listen_http
, NULL
, NULL
, NULL
);
929 if (arg_listen_https
) {
930 r
= setup_microhttpd_socket(s
, arg_listen_https
, key
, cert
, trust
);
935 STRV_FOREACH(file
, arg_files
) {
936 const char *output_name
;
938 if (streq(*file
, "-")) {
939 log_debug("Using standard input as source.");
942 output_name
= "stdin";
944 log_debug("Reading file %s...", *file
);
946 fd
= open(*file
, O_RDONLY
|O_CLOEXEC
|O_NOCTTY
|O_NONBLOCK
);
948 return log_error_errno(errno
, "Failed to open %s: %m", *file
);
952 r
= add_source(s
, fd
, (char*) output_name
, false);
957 if (s
->active
== 0) {
958 log_error("Zarro sources specified");
962 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
) {
963 /* In this case we know what the writer will be
964 called, so we can create it and verify that we can
965 create output as expected. */
966 r
= get_writer(s
, NULL
, &s
->_single_writer
);
974 static void server_destroy(RemoteServer
*s
) {
978 while ((d
= hashmap_steal_first(s
->daemons
))) {
979 MHD_stop_daemon(d
->daemon
);
980 sd_event_source_unref(d
->event
);
984 hashmap_free(s
->daemons
);
986 assert(s
->sources_size
== 0 || s
->sources
);
987 for (i
= 0; i
< s
->sources_size
; i
++)
991 writer_unref(s
->_single_writer
);
992 hashmap_free(s
->writers
);
994 sd_event_source_unref(s
->sigterm_event
);
995 sd_event_source_unref(s
->sigint_event
);
996 sd_event_source_unref(s
->listen_event
);
997 sd_event_unref(s
->events
);
999 /* fds that we're listening on remain open... */
1002 /**********************************************************************
1003 **********************************************************************
1004 **********************************************************************/
1006 static int handle_raw_source(sd_event_source
*event
,
1011 RemoteSource
*source
;
1014 /* Returns 1 if there might be more data pending,
1015 * 0 if data is currently exhausted, negative on error.
1018 assert(fd
>= 0 && fd
< (ssize_t
) s
->sources_size
);
1019 source
= s
->sources
[fd
];
1020 assert(source
->fd
== fd
);
1022 r
= process_source(source
, arg_compress
, arg_seal
);
1023 if (source
->state
== STATE_EOF
) {
1026 log_debug("EOF reached with source fd:%d (%s)",
1027 source
->fd
, source
->name
);
1029 remaining
= source_non_empty(source
);
1031 log_notice("Premature EOF. %zu bytes lost.", remaining
);
1032 remove_source(s
, source
->fd
);
1033 log_debug("%zu active sources remaining", s
->active
);
1035 } else if (r
== -E2BIG
) {
1036 log_notice_errno(E2BIG
, "Entry too big, skipped");
1038 } else if (r
== -EAGAIN
) {
1041 log_debug_errno(r
, "Closing connection: %m");
1042 remove_source(server
, fd
);
1048 static int dispatch_raw_source_until_block(sd_event_source
*event
,
1050 RemoteSource
*source
= userdata
;
1053 /* Make sure event stays around even if source is destroyed */
1054 sd_event_source_ref(event
);
1056 r
= handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1058 /* No more data for now */
1059 sd_event_source_set_enabled(event
, SD_EVENT_OFF
);
1061 sd_event_source_unref(event
);
1066 static int dispatch_raw_source_event(sd_event_source
*event
,
1070 RemoteSource
*source
= userdata
;
1073 assert(source
->event
);
1074 assert(source
->buffer_event
);
1076 r
= handle_raw_source(event
, fd
, EPOLLIN
, server
);
1078 /* Might have more data. We need to rerun the handler
1079 * until we are sure the buffer is exhausted. */
1080 sd_event_source_set_enabled(source
->buffer_event
, SD_EVENT_ON
);
1085 static int dispatch_blocking_source_event(sd_event_source
*event
,
1087 RemoteSource
*source
= userdata
;
1089 return handle_raw_source(event
, source
->fd
, EPOLLIN
, server
);
1092 static int accept_connection(const char* type
, int fd
,
1093 SocketAddress
*addr
, char **hostname
) {
1096 log_debug("Accepting new %s connection on fd:%d", type
, fd
);
1097 fd2
= accept4(fd
, &addr
->sockaddr
.sa
, &addr
->size
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
1099 return log_error_errno(errno
, "accept() on fd:%d failed: %m", fd
);
1101 switch(socket_address_family(addr
)) {
1104 _cleanup_free_
char *a
= NULL
;
1107 r
= socket_address_print(addr
, &a
);
1109 log_error_errno(r
, "socket_address_print(): %m");
1114 r
= socknameinfo_pretty(&addr
->sockaddr
, addr
->size
, &b
);
1120 log_debug("Accepted %s %s connection from %s",
1122 socket_address_family(addr
) == AF_INET
? "IP" : "IPv6",
1130 log_error("Rejected %s connection with unsupported family %d",
1131 type
, socket_address_family(addr
));
1138 static int dispatch_raw_connection_event(sd_event_source
*event
,
1142 RemoteServer
*s
= userdata
;
1144 SocketAddress addr
= {
1145 .size
= sizeof(union sockaddr_union
),
1146 .type
= SOCK_STREAM
,
1148 char *hostname
= NULL
;
1150 fd2
= accept_connection("raw", fd
, &addr
, &hostname
);
1154 return add_source(s
, fd2
, hostname
, true);
1157 /**********************************************************************
1158 **********************************************************************
1159 **********************************************************************/
1161 static const char* const journal_write_split_mode_table
[_JOURNAL_WRITE_SPLIT_MAX
] = {
1162 [JOURNAL_WRITE_SPLIT_NONE
] = "none",
1163 [JOURNAL_WRITE_SPLIT_HOST
] = "host",
1166 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode
, JournalWriteSplitMode
);
1167 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode
,
1168 journal_write_split_mode
,
1169 JournalWriteSplitMode
,
1170 "Failed to parse split mode setting");
1172 static int parse_config(void) {
1173 const ConfigTableItem items
[] = {
1174 { "Remote", "SplitMode", config_parse_write_split_mode
, 0, &arg_split_mode
},
1175 { "Remote", "ServerKeyFile", config_parse_path
, 0, &arg_key
},
1176 { "Remote", "ServerCertificateFile", config_parse_path
, 0, &arg_cert
},
1177 { "Remote", "TrustedCertificateFile", config_parse_path
, 0, &arg_trust
},
1180 return config_parse_many(PKGSYSCONFDIR
"/journal-remote.conf",
1181 CONF_DIRS_NULSTR("systemd/journal-remote.conf"),
1182 "Remote\0", config_item_table_lookup
, items
,
1186 static void help(void) {
1187 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1188 "Write external journal events to journal file(s).\n\n"
1189 " -h --help Show this help\n"
1190 " --version Show package version\n"
1191 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1192 " --getter=COMMAND Read events from the output of COMMAND\n"
1193 " --listen-raw=ADDR Listen for connections at ADDR\n"
1194 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1195 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1196 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1197 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1198 " --seal[=BOOL] Use event sealing (default: no)\n"
1199 " --key=FILENAME SSL key in PEM format (default:\n"
1200 " \"" PRIV_KEY_FILE
"\")\n"
1201 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1202 " \"" CERT_FILE
"\")\n"
1203 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1204 " \"" TRUST_FILE
"\")\n"
1205 " --gnutls-log=CATEGORY...\n"
1206 " Specify a list of gnutls logging categories\n"
1207 " --split-mode=none|host How many output files to create\n"
1209 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1210 , program_invocation_short_name
);
1213 static int parse_argv(int argc
, char *argv
[]) {
1215 ARG_VERSION
= 0x100,
1230 static const struct option options
[] = {
1231 { "help", no_argument
, NULL
, 'h' },
1232 { "version", no_argument
, NULL
, ARG_VERSION
},
1233 { "url", required_argument
, NULL
, ARG_URL
},
1234 { "getter", required_argument
, NULL
, ARG_GETTER
},
1235 { "listen-raw", required_argument
, NULL
, ARG_LISTEN_RAW
},
1236 { "listen-http", required_argument
, NULL
, ARG_LISTEN_HTTP
},
1237 { "listen-https", required_argument
, NULL
, ARG_LISTEN_HTTPS
},
1238 { "output", required_argument
, NULL
, 'o' },
1239 { "split-mode", required_argument
, NULL
, ARG_SPLIT_MODE
},
1240 { "compress", optional_argument
, NULL
, ARG_COMPRESS
},
1241 { "seal", optional_argument
, NULL
, ARG_SEAL
},
1242 { "key", required_argument
, NULL
, ARG_KEY
},
1243 { "cert", required_argument
, NULL
, ARG_CERT
},
1244 { "trust", required_argument
, NULL
, ARG_TRUST
},
1245 { "gnutls-log", required_argument
, NULL
, ARG_GNUTLS_LOG
},
1250 bool type_a
, type_b
;
1255 while ((c
= getopt_long(argc
, argv
, "ho:", options
, NULL
)) >= 0)
1259 return 0 /* done */;
1262 puts(PACKAGE_STRING
);
1263 puts(SYSTEMD_FEATURES
);
1264 return 0 /* done */;
1268 log_error("cannot currently set more than one --url");
1277 log_error("cannot currently use --getter more than once");
1281 arg_getter
= optarg
;
1284 case ARG_LISTEN_RAW
:
1285 if (arg_listen_raw
) {
1286 log_error("cannot currently use --listen-raw more than once");
1290 arg_listen_raw
= optarg
;
1293 case ARG_LISTEN_HTTP
:
1294 if (arg_listen_http
|| http_socket
>= 0) {
1295 log_error("cannot currently use --listen-http more than once");
1299 r
= negative_fd(optarg
);
1303 arg_listen_http
= optarg
;
1306 case ARG_LISTEN_HTTPS
:
1307 if (arg_listen_https
|| https_socket
>= 0) {
1308 log_error("cannot currently use --listen-https more than once");
1312 r
= negative_fd(optarg
);
1316 arg_listen_https
= optarg
;
1322 log_error("Key file specified twice");
1326 arg_key
= strdup(optarg
);
1334 log_error("Certificate file specified twice");
1338 arg_cert
= strdup(optarg
);
1345 if (arg_trust
|| arg_trust_all
) {
1346 log_error("Confusing trusted CA configuration");
1350 if (streq(optarg
, "all"))
1351 arg_trust_all
= true;
1354 arg_trust
= strdup(optarg
);
1358 log_error("Option --trust is not available.");
1367 log_error("cannot use --output/-o more than once");
1371 arg_output
= optarg
;
1374 case ARG_SPLIT_MODE
:
1375 arg_split_mode
= journal_write_split_mode_from_string(optarg
);
1376 if (arg_split_mode
== _JOURNAL_WRITE_SPLIT_INVALID
) {
1377 log_error("Invalid split mode: %s", optarg
);
1384 r
= parse_boolean(optarg
);
1386 log_error("Failed to parse --compress= parameter.");
1392 arg_compress
= true;
1398 r
= parse_boolean(optarg
);
1400 log_error("Failed to parse --seal= parameter.");
1410 case ARG_GNUTLS_LOG
: {
1412 const char *word
, *state
;
1415 FOREACH_WORD_SEPARATOR(word
, size
, optarg
, ",", state
) {
1418 cat
= strndup(word
, size
);
1422 if (strv_consume(&arg_gnutls_log
, cat
) < 0)
1427 log_error("Option --gnutls-log is not available.");
1436 assert_not_reached("Unknown option code.");
1440 arg_files
= argv
+ optind
;
1442 type_a
= arg_getter
|| !strv_isempty(arg_files
);
1445 || arg_listen_http
|| arg_listen_https
1446 || sd_listen_fds(false) > 0;
1447 if (type_a
&& type_b
) {
1448 log_error("Cannot use file input or --getter with "
1449 "--arg-listen-... or socket activation.");
1454 log_error("Option --output must be specified with file input or --getter.");
1458 arg_split_mode
= JOURNAL_WRITE_SPLIT_NONE
;
1461 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_NONE
1462 && arg_output
&& is_dir(arg_output
, true) > 0) {
1463 log_error("For SplitMode=none, output must be a file.");
1467 if (arg_split_mode
== JOURNAL_WRITE_SPLIT_HOST
1468 && arg_output
&& is_dir(arg_output
, true) <= 0) {
1469 log_error("For SplitMode=host, output must be a directory.");
1473 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1474 journal_write_split_mode_to_string(arg_split_mode
),
1479 return 1 /* work to do */;
1482 static int load_certificates(char **key
, char **cert
, char **trust
) {
1485 r
= read_full_file(arg_key
?: PRIV_KEY_FILE
, key
, NULL
);
1487 return log_error_errno(r
, "Failed to read key from file '%s': %m",
1488 arg_key
?: PRIV_KEY_FILE
);
1490 r
= read_full_file(arg_cert
?: CERT_FILE
, cert
, NULL
);
1492 return log_error_errno(r
, "Failed to read certificate from file '%s': %m",
1493 arg_cert
?: CERT_FILE
);
1496 log_info("Certificate checking disabled.");
1498 r
= read_full_file(arg_trust
?: TRUST_FILE
, trust
, NULL
);
1500 return log_error_errno(r
, "Failed to read CA certificate file '%s': %m",
1501 arg_trust
?: TRUST_FILE
);
1507 int main(int argc
, char **argv
) {
1508 RemoteServer s
= {};
1510 _cleanup_free_
char *key
= NULL
, *cert
= NULL
, *trust
= NULL
;
1512 log_show_color(true);
1513 log_parse_environment();
1517 return EXIT_FAILURE
;
1519 r
= parse_argv(argc
, argv
);
1521 return r
== 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;
1524 if (arg_listen_http
|| arg_listen_https
) {
1525 r
= setup_gnutls_logger(arg_gnutls_log
);
1527 return EXIT_FAILURE
;
1530 if (arg_listen_https
|| https_socket
>= 0)
1531 if (load_certificates(&key
, &cert
, &trust
) < 0)
1532 return EXIT_FAILURE
;
1534 if (remoteserver_init(&s
, key
, cert
, trust
) < 0)
1535 return EXIT_FAILURE
;
1537 r
= sd_event_set_watchdog(s
.events
, true);
1539 log_error_errno(r
, "Failed to enable watchdog: %m");
1541 log_debug("Watchdog is %s.", r
> 0 ? "enabled" : "disabled");
1543 log_debug("%s running as pid "PID_FMT
,
1544 program_invocation_short_name
, getpid());
1547 "STATUS=Processing requests...");
1550 r
= sd_event_get_state(s
.events
);
1553 if (r
== SD_EVENT_FINISHED
)
1556 r
= sd_event_run(s
.events
, -1);
1558 log_error_errno(r
, "Failed to run event loop: %m");
1565 "STATUS=Shutting down after writing %" PRIu64
" entries...", s
.event_count
);
1566 log_info("Finishing after writing %" PRIu64
" entries", s
.event_count
);
1574 return r
>= 0 ? EXIT_SUCCESS
: EXIT_FAILURE
;