]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal-remote/journal-remote.c
da52e5b86ee605dbd10aa13c77fa76297d5f4e2c
[thirdparty/systemd.git] / src / journal-remote / journal-remote.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2012 Zbigniew Jędrzejewski-Szmek
6
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.
11
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.
16
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/>.
19 ***/
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <getopt.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/prctl.h>
28 #include <sys/socket.h>
29 #include <unistd.h>
30 #include <stdint.h>
31
32 #include "sd-daemon.h"
33
34 #include "alloc-util.h"
35 #include "conf-parser.h"
36 #include "def.h"
37 #include "escape.h"
38 #include "fd-util.h"
39 #include "fileio.h"
40 #include "journal-file.h"
41 #include "journal-remote-write.h"
42 #include "journal-remote.h"
43 #include "journald-native.h"
44 #include "macro.h"
45 #include "parse-util.h"
46 #include "process-util.h"
47 #include "signal-util.h"
48 #include "socket-util.h"
49 #include "stat-util.h"
50 #include "stdio-util.h"
51 #include "string-table.h"
52 #include "string-util.h"
53 #include "strv.h"
54
55 #define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
56
57 #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
58 #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
59 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
60
61 static char* arg_url = NULL;
62 static char* arg_getter = NULL;
63 static char* arg_listen_raw = NULL;
64 static char* arg_listen_http = NULL;
65 static char* arg_listen_https = NULL;
66 static char** arg_files = NULL;
67 static int arg_compress = true;
68 static int arg_seal = false;
69 static int http_socket = -1, https_socket = -1;
70 static char** arg_gnutls_log = NULL;
71
72 static JournalWriteSplitMode arg_split_mode = _JOURNAL_WRITE_SPLIT_INVALID;
73 static char* arg_output = NULL;
74
75 static char *arg_key = NULL;
76 static char *arg_cert = NULL;
77 static char *arg_trust = NULL;
78 static bool arg_trust_all = false;
79
80 /**********************************************************************
81 **********************************************************************
82 **********************************************************************/
83
84 static int spawn_child(const char* child, char** argv) {
85 pid_t child_pid;
86 int fd[2], r;
87
88 if (pipe(fd) < 0)
89 return log_error_errno(errno, "Failed to create pager pipe: %m");
90
91 r = safe_fork("(remote)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &child_pid);
92 if (r < 0) {
93 safe_close_pair(fd);
94 return r;
95 }
96
97 /* In the child */
98 if (r == 0) {
99 safe_close(fd[0]);
100
101 r = rearrange_stdio(STDIN_FILENO, fd[1], STDERR_FILENO);
102 if (r < 0) {
103 log_error_errno(r, "Failed to dup pipe to stdout: %m");
104 _exit(EXIT_FAILURE);
105 }
106
107 execvp(child, argv);
108 log_error_errno(errno, "Failed to exec child %s: %m", child);
109 _exit(EXIT_FAILURE);
110 }
111
112 safe_close(fd[1]);
113
114 r = fd_nonblock(fd[0], true);
115 if (r < 0)
116 log_warning_errno(errno, "Failed to set child pipe to non-blocking: %m");
117
118 return fd[0];
119 }
120
121 static int spawn_curl(const char* url) {
122 char **argv = STRV_MAKE("curl",
123 "-HAccept: application/vnd.fdo.journal",
124 "--silent",
125 "--show-error",
126 url);
127 int r;
128
129 r = spawn_child("curl", argv);
130 if (r < 0)
131 log_error_errno(r, "Failed to spawn curl: %m");
132 return r;
133 }
134
135 static int spawn_getter(const char *getter) {
136 int r;
137 _cleanup_strv_free_ char **words = NULL;
138
139 assert(getter);
140 r = strv_split_extract(&words, getter, WHITESPACE, EXTRACT_QUOTES);
141 if (r < 0)
142 return log_error_errno(r, "Failed to split getter option: %m");
143
144 r = spawn_child(words[0], words);
145 if (r < 0)
146 log_error_errno(r, "Failed to spawn getter %s: %m", getter);
147
148 return r;
149 }
150
151 #define filename_escape(s) xescape((s), "/ ")
152
153 static int open_output(Writer *w, const char* host) {
154 _cleanup_free_ char *_output = NULL;
155 const char *output;
156 int r;
157
158 switch (arg_split_mode) {
159 case JOURNAL_WRITE_SPLIT_NONE:
160 output = arg_output ?: REMOTE_JOURNAL_PATH "/remote.journal";
161 break;
162
163 case JOURNAL_WRITE_SPLIT_HOST: {
164 _cleanup_free_ char *name;
165
166 assert(host);
167
168 name = filename_escape(host);
169 if (!name)
170 return log_oom();
171
172 r = asprintf(&_output, "%s/remote-%s.journal",
173 arg_output ?: REMOTE_JOURNAL_PATH,
174 name);
175 if (r < 0)
176 return log_oom();
177
178 output = _output;
179 break;
180 }
181
182 default:
183 assert_not_reached("what?");
184 }
185
186 r = journal_file_open_reliably(output,
187 O_RDWR|O_CREAT, 0640,
188 arg_compress, (uint64_t) -1, arg_seal,
189 &w->metrics,
190 w->mmap, NULL,
191 NULL, &w->journal);
192 if (r < 0)
193 log_error_errno(r, "Failed to open output journal %s: %m",
194 output);
195 else
196 log_debug("Opened output file %s", w->journal->path);
197 return r;
198 }
199
200 /**********************************************************************
201 **********************************************************************
202 **********************************************************************/
203
204 static int init_writer_hashmap(RemoteServer *s) {
205 static const struct hash_ops *hash_ops[] = {
206 [JOURNAL_WRITE_SPLIT_NONE] = NULL,
207 [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
208 };
209
210 assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(hash_ops));
211
212 s->writers = hashmap_new(hash_ops[arg_split_mode]);
213 if (!s->writers)
214 return log_oom();
215
216 return 0;
217 }
218
219 static int get_writer(RemoteServer *s, const char *host,
220 Writer **writer) {
221 const void *key;
222 _cleanup_writer_unref_ Writer *w = NULL;
223 int r;
224
225 switch(arg_split_mode) {
226 case JOURNAL_WRITE_SPLIT_NONE:
227 key = "one and only";
228 break;
229
230 case JOURNAL_WRITE_SPLIT_HOST:
231 assert(host);
232 key = host;
233 break;
234
235 default:
236 assert_not_reached("what split mode?");
237 }
238
239 w = hashmap_get(s->writers, key);
240 if (w)
241 writer_ref(w);
242 else {
243 w = writer_new(s);
244 if (!w)
245 return log_oom();
246
247 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
248 w->hashmap_key = strdup(key);
249 if (!w->hashmap_key)
250 return log_oom();
251 }
252
253 r = open_output(w, host);
254 if (r < 0)
255 return r;
256
257 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
258 if (r < 0)
259 return r;
260 }
261
262 *writer = TAKE_PTR(w);
263
264 return 0;
265 }
266
267 /**********************************************************************
268 **********************************************************************
269 **********************************************************************/
270
271 /* This should go away as soon as µhttpd allows state to be passed around. */
272 static RemoteServer *server;
273
274 static int dispatch_raw_source_event(sd_event_source *event,
275 int fd,
276 uint32_t revents,
277 void *userdata);
278 static int dispatch_raw_source_until_block(sd_event_source *event,
279 void *userdata);
280 static int dispatch_blocking_source_event(sd_event_source *event,
281 void *userdata);
282 static int dispatch_raw_connection_event(sd_event_source *event,
283 int fd,
284 uint32_t revents,
285 void *userdata);
286 static int null_timer_event_handler(sd_event_source *s,
287 uint64_t usec,
288 void *userdata);
289 static int dispatch_http_event(sd_event_source *event,
290 int fd,
291 uint32_t revents,
292 void *userdata);
293
294 static int get_source_for_fd(RemoteServer *s,
295 int fd, char *name, RemoteSource **source) {
296 Writer *writer;
297 int r;
298
299 /* This takes ownership of name, but only on success. */
300
301 assert(fd >= 0);
302 assert(source);
303
304 if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
305 return log_oom();
306
307 r = get_writer(s, name, &writer);
308 if (r < 0)
309 return log_warning_errno(r, "Failed to get writer for source %s: %m",
310 name);
311
312 if (s->sources[fd] == NULL) {
313 s->sources[fd] = source_new(fd, false, name, writer);
314 if (!s->sources[fd]) {
315 writer_unref(writer);
316 return log_oom();
317 }
318
319 s->active++;
320 }
321
322 *source = s->sources[fd];
323 return 0;
324 }
325
326 static int remove_source(RemoteServer *s, int fd) {
327 RemoteSource *source;
328
329 assert(s);
330 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
331
332 source = s->sources[fd];
333 if (source) {
334 /* this closes fd too */
335 source_free(source);
336 s->sources[fd] = NULL;
337 s->active--;
338 }
339
340 return 0;
341 }
342
343 static int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
344
345 RemoteSource *source = NULL;
346 int r;
347
348 /* This takes ownership of name, even on failure, if own_name is true. */
349
350 assert(s);
351 assert(fd >= 0);
352 assert(name);
353
354 if (!own_name) {
355 name = strdup(name);
356 if (!name)
357 return log_oom();
358 }
359
360 r = get_source_for_fd(s, fd, name, &source);
361 if (r < 0) {
362 log_error_errno(r, "Failed to create source for fd:%d (%s): %m",
363 fd, name);
364 free(name);
365 return r;
366 }
367
368 r = sd_event_add_io(s->events, &source->event,
369 fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
370 dispatch_raw_source_event, source);
371 if (r == 0) {
372 /* Add additional source for buffer processing. It will be
373 * enabled later. */
374 r = sd_event_add_defer(s->events, &source->buffer_event,
375 dispatch_raw_source_until_block, source);
376 if (r == 0)
377 sd_event_source_set_enabled(source->buffer_event, SD_EVENT_OFF);
378 } else if (r == -EPERM) {
379 log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
380 r = sd_event_add_defer(s->events, &source->event,
381 dispatch_blocking_source_event, source);
382 if (r == 0)
383 sd_event_source_set_enabled(source->event, SD_EVENT_ON);
384 }
385 if (r < 0) {
386 log_error_errno(r, "Failed to register event source for fd:%d: %m",
387 fd);
388 goto error;
389 }
390
391 r = sd_event_source_set_description(source->event, name);
392 if (r < 0) {
393 log_error_errno(r, "Failed to set source name for fd:%d: %m", fd);
394 goto error;
395 }
396
397 return 1; /* work to do */
398
399 error:
400 remove_source(s, fd);
401 return r;
402 }
403
404 static int add_raw_socket(RemoteServer *s, int fd) {
405 int r;
406 _cleanup_close_ int fd_ = fd;
407 char name[STRLEN("raw-socket-") + DECIMAL_STR_MAX(int) + 1];
408
409 assert(fd >= 0);
410
411 r = sd_event_add_io(s->events, &s->listen_event,
412 fd, EPOLLIN,
413 dispatch_raw_connection_event, s);
414 if (r < 0)
415 return r;
416
417 xsprintf(name, "raw-socket-%d", fd);
418
419 r = sd_event_source_set_description(s->listen_event, name);
420 if (r < 0)
421 return r;
422
423 fd_ = -1;
424 s->active++;
425 return 0;
426 }
427
428 static int setup_raw_socket(RemoteServer *s, const char *address) {
429 int fd;
430
431 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM, SOCK_CLOEXEC);
432 if (fd < 0)
433 return fd;
434
435 return add_raw_socket(s, fd);
436 }
437
438 /**********************************************************************
439 **********************************************************************
440 **********************************************************************/
441
442 static int request_meta(void **connection_cls, int fd, char *hostname) {
443 RemoteSource *source;
444 Writer *writer;
445 int r;
446
447 assert(connection_cls);
448 if (*connection_cls)
449 return 0;
450
451 r = get_writer(server, hostname, &writer);
452 if (r < 0)
453 return log_warning_errno(r, "Failed to get writer for source %s: %m",
454 hostname);
455
456 source = source_new(fd, true, hostname, writer);
457 if (!source) {
458 writer_unref(writer);
459 return log_oom();
460 }
461
462 log_debug("Added RemoteSource as connection metadata %p", source);
463
464 *connection_cls = source;
465 return 0;
466 }
467
468 static void request_meta_free(void *cls,
469 struct MHD_Connection *connection,
470 void **connection_cls,
471 enum MHD_RequestTerminationCode toe) {
472 RemoteSource *s;
473
474 assert(connection_cls);
475 s = *connection_cls;
476
477 if (s) {
478 log_debug("Cleaning up connection metadata %p", s);
479 source_free(s);
480 *connection_cls = NULL;
481 }
482 }
483
484 static int process_http_upload(
485 struct MHD_Connection *connection,
486 const char *upload_data,
487 size_t *upload_data_size,
488 RemoteSource *source) {
489
490 bool finished = false;
491 size_t remaining;
492 int r;
493
494 assert(source);
495
496 log_trace("%s: connection %p, %zu bytes",
497 __func__, connection, *upload_data_size);
498
499 if (*upload_data_size) {
500 log_trace("Received %zu bytes", *upload_data_size);
501
502 r = journal_importer_push_data(&source->importer,
503 upload_data, *upload_data_size);
504 if (r < 0)
505 return mhd_respond_oom(connection);
506
507 *upload_data_size = 0;
508 } else
509 finished = true;
510
511 for (;;) {
512 r = process_source(source, arg_compress, arg_seal);
513 if (r == -EAGAIN)
514 break;
515 else if (r < 0) {
516 log_warning("Failed to process data for connection %p", connection);
517 if (r == -E2BIG)
518 return mhd_respondf(connection,
519 r, MHD_HTTP_PAYLOAD_TOO_LARGE,
520 "Entry is too large, maximum is " STRINGIFY(DATA_SIZE_MAX) " bytes.");
521 else
522 return mhd_respondf(connection,
523 r, MHD_HTTP_UNPROCESSABLE_ENTITY,
524 "Processing failed: %m.");
525 }
526 }
527
528 if (!finished)
529 return MHD_YES;
530
531 /* The upload is finished */
532
533 remaining = journal_importer_bytes_remaining(&source->importer);
534 if (remaining > 0) {
535 log_warning("Premature EOF byte. %zu bytes lost.", remaining);
536 return mhd_respondf(connection,
537 0, MHD_HTTP_EXPECTATION_FAILED,
538 "Premature EOF. %zu bytes of trailing data not processed.",
539 remaining);
540 }
541
542 return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.");
543 };
544
545 static int request_handler(
546 void *cls,
547 struct MHD_Connection *connection,
548 const char *url,
549 const char *method,
550 const char *version,
551 const char *upload_data,
552 size_t *upload_data_size,
553 void **connection_cls) {
554
555 const char *header;
556 int r, code, fd;
557 _cleanup_free_ char *hostname = NULL;
558
559 assert(connection);
560 assert(connection_cls);
561 assert(url);
562 assert(method);
563
564 log_trace("Handling a connection %s %s %s", method, url, version);
565
566 if (*connection_cls)
567 return process_http_upload(connection,
568 upload_data, upload_data_size,
569 *connection_cls);
570
571 if (!streq(method, "POST"))
572 return mhd_respond(connection, MHD_HTTP_NOT_ACCEPTABLE, "Unsupported method.");
573
574 if (!streq(url, "/upload"))
575 return mhd_respond(connection, MHD_HTTP_NOT_FOUND, "Not found.");
576
577 header = MHD_lookup_connection_value(connection,
578 MHD_HEADER_KIND, "Content-Type");
579 if (!header || !streq(header, "application/vnd.fdo.journal"))
580 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
581 "Content-Type: application/vnd.fdo.journal is required.");
582
583 {
584 const union MHD_ConnectionInfo *ci;
585
586 ci = MHD_get_connection_info(connection,
587 MHD_CONNECTION_INFO_CONNECTION_FD);
588 if (!ci) {
589 log_error("MHD_get_connection_info failed: cannot get remote fd");
590 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
591 "Cannot check remote address.");
592 }
593
594 fd = ci->connect_fd;
595 assert(fd >= 0);
596 }
597
598 if (server->check_trust) {
599 r = check_permissions(connection, &code, &hostname);
600 if (r < 0)
601 return code;
602 } else {
603 r = getpeername_pretty(fd, false, &hostname);
604 if (r < 0)
605 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
606 "Cannot check remote hostname.");
607 }
608
609 assert(hostname);
610
611 r = request_meta(connection_cls, fd, hostname);
612 if (r == -ENOMEM)
613 return respond_oom(connection);
614 else if (r < 0)
615 return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR, "%m");
616
617 hostname = NULL;
618 return MHD_YES;
619 }
620
621 static int setup_microhttpd_server(RemoteServer *s,
622 int fd,
623 const char *key,
624 const char *cert,
625 const char *trust) {
626 struct MHD_OptionItem opts[] = {
627 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
628 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
629 { MHD_OPTION_LISTEN_SOCKET, fd},
630 { MHD_OPTION_CONNECTION_MEMORY_LIMIT, 128*1024},
631 { MHD_OPTION_END},
632 { MHD_OPTION_END},
633 { MHD_OPTION_END},
634 { MHD_OPTION_END},
635 { MHD_OPTION_END}};
636 int opts_pos = 4;
637 int flags =
638 MHD_USE_DEBUG |
639 MHD_USE_DUAL_STACK |
640 MHD_USE_EPOLL |
641 MHD_USE_ITC;
642
643 const union MHD_DaemonInfo *info;
644 int r, epoll_fd;
645 MHDDaemonWrapper *d;
646
647 assert(fd >= 0);
648
649 r = fd_nonblock(fd, true);
650 if (r < 0)
651 return log_error_errno(r, "Failed to make fd:%d nonblocking: %m", fd);
652
653 /* MHD_OPTION_STRICT_FOR_CLIENT is introduced in microhttpd 0.9.54,
654 * and MHD_USE_PEDANTIC_CHECKS will be deprecated in future.
655 * If MHD_USE_PEDANTIC_CHECKS is '#define'd, then it is deprecated
656 * and we should use MHD_OPTION_STRICT_FOR_CLIENT. On the other hand,
657 * if MHD_USE_PEDANTIC_CHECKS is not '#define'd, then it is not
658 * deprecated yet and there exists an enum element with the same name.
659 * So we can safely use it. */
660 #ifdef MHD_USE_PEDANTIC_CHECKS
661 opts[opts_pos++] = (struct MHD_OptionItem)
662 {MHD_OPTION_STRICT_FOR_CLIENT, 1};
663 #else
664 flags |= MHD_USE_PEDANTIC_CHECKS;
665 #endif
666
667 if (key) {
668 assert(cert);
669
670 opts[opts_pos++] = (struct MHD_OptionItem)
671 {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
672 opts[opts_pos++] = (struct MHD_OptionItem)
673 {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
674
675 flags |= MHD_USE_TLS;
676
677 if (trust)
678 opts[opts_pos++] = (struct MHD_OptionItem)
679 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
680 }
681
682 d = new(MHDDaemonWrapper, 1);
683 if (!d)
684 return log_oom();
685
686 d->fd = (uint64_t) fd;
687
688 d->daemon = MHD_start_daemon(flags, 0,
689 NULL, NULL,
690 request_handler, NULL,
691 MHD_OPTION_ARRAY, opts,
692 MHD_OPTION_END);
693 if (!d->daemon) {
694 log_error("Failed to start µhttp daemon");
695 r = -EINVAL;
696 goto error;
697 }
698
699 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
700 key ? "HTTPS" : "HTTP", fd, d);
701
702
703 info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
704 if (!info) {
705 log_error("µhttp returned NULL daemon info");
706 r = -EOPNOTSUPP;
707 goto error;
708 }
709
710 epoll_fd = info->listen_fd;
711 if (epoll_fd < 0) {
712 log_error("µhttp epoll fd is invalid");
713 r = -EUCLEAN;
714 goto error;
715 }
716
717 r = sd_event_add_io(s->events, &d->io_event,
718 epoll_fd, EPOLLIN,
719 dispatch_http_event, d);
720 if (r < 0) {
721 log_error_errno(r, "Failed to add event callback: %m");
722 goto error;
723 }
724
725 r = sd_event_source_set_description(d->io_event, "io_event");
726 if (r < 0) {
727 log_error_errno(r, "Failed to set source name: %m");
728 goto error;
729 }
730
731 r = sd_event_add_time(s->events, &d->timer_event,
732 CLOCK_MONOTONIC, (uint64_t) -1, 0,
733 null_timer_event_handler, d);
734 if (r < 0) {
735 log_error_errno(r, "Failed to add timer_event: %m");
736 goto error;
737 }
738
739 r = sd_event_source_set_description(d->timer_event, "timer_event");
740 if (r < 0) {
741 log_error_errno(r, "Failed to set source name: %m");
742 goto error;
743 }
744
745 r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
746 if (r < 0) {
747 log_oom();
748 goto error;
749 }
750
751 r = hashmap_put(s->daemons, &d->fd, d);
752 if (r < 0) {
753 log_error_errno(r, "Failed to add daemon to hashmap: %m");
754 goto error;
755 }
756
757 s->active++;
758 return 0;
759
760 error:
761 MHD_stop_daemon(d->daemon);
762 free(d->daemon);
763 free(d);
764 return r;
765 }
766
767 static int setup_microhttpd_socket(RemoteServer *s,
768 const char *address,
769 const char *key,
770 const char *cert,
771 const char *trust) {
772 int fd;
773
774 fd = make_socket_fd(LOG_DEBUG, address, SOCK_STREAM, SOCK_CLOEXEC);
775 if (fd < 0)
776 return fd;
777
778 return setup_microhttpd_server(s, fd, key, cert, trust);
779 }
780
781 static int null_timer_event_handler(sd_event_source *timer_event,
782 uint64_t usec,
783 void *userdata) {
784 return dispatch_http_event(timer_event, 0, 0, userdata);
785 }
786
787 static int dispatch_http_event(sd_event_source *event,
788 int fd,
789 uint32_t revents,
790 void *userdata) {
791 MHDDaemonWrapper *d = userdata;
792 int r;
793 MHD_UNSIGNED_LONG_LONG timeout = ULONG_LONG_MAX;
794
795 assert(d);
796
797 r = MHD_run(d->daemon);
798 if (r == MHD_NO) {
799 log_error("MHD_run failed!");
800 // XXX: unregister daemon
801 return -EINVAL;
802 }
803 if (MHD_get_timeout(d->daemon, &timeout) == MHD_NO)
804 timeout = ULONG_LONG_MAX;
805
806 r = sd_event_source_set_time(d->timer_event, timeout);
807 if (r < 0) {
808 log_warning_errno(r, "Unable to set event loop timeout: %m, this may result in indefinite blocking!");
809 return 1;
810 }
811
812 r = sd_event_source_set_enabled(d->timer_event, SD_EVENT_ON);
813 if (r < 0)
814 log_warning_errno(r, "Unable to enable timer_event: %m, this may result in indefinite blocking!");
815
816 return 1; /* work to do */
817 }
818
819 /**********************************************************************
820 **********************************************************************
821 **********************************************************************/
822
823 static int setup_signals(RemoteServer *s) {
824 int r;
825
826 assert(s);
827
828 assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, -1) >= 0);
829
830 r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, NULL, s);
831 if (r < 0)
832 return r;
833
834 r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, NULL, s);
835 if (r < 0)
836 return r;
837
838 return 0;
839 }
840
841 static int negative_fd(const char *spec) {
842 /* Return a non-positive number as its inverse, -EINVAL otherwise. */
843
844 int fd, r;
845
846 r = safe_atoi(spec, &fd);
847 if (r < 0)
848 return r;
849
850 if (fd > 0)
851 return -EINVAL;
852 else
853 return -fd;
854 }
855
856 static int remoteserver_init(RemoteServer *s,
857 const char* key,
858 const char* cert,
859 const char* trust) {
860 int r, n, fd;
861 char **file;
862
863 assert(s);
864
865 if ((arg_listen_raw || arg_listen_http) && trust) {
866 log_error("Option --trust makes all non-HTTPS connections untrusted.");
867 return -EINVAL;
868 }
869
870 r = sd_event_default(&s->events);
871 if (r < 0)
872 return log_error_errno(r, "Failed to allocate event loop: %m");
873
874 setup_signals(s);
875
876 assert(server == NULL);
877 server = s;
878
879 r = init_writer_hashmap(s);
880 if (r < 0)
881 return r;
882
883 n = sd_listen_fds(true);
884 if (n < 0)
885 return log_error_errno(n, "Failed to read listening file descriptors from environment: %m");
886 else
887 log_debug("Received %d descriptors", n);
888
889 if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
890 log_error("Received fewer sockets than expected");
891 return -EBADFD;
892 }
893
894 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
895 if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
896 log_debug("Received a listening socket (fd:%d)", fd);
897
898 if (fd == http_socket)
899 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
900 else if (fd == https_socket)
901 r = setup_microhttpd_server(s, fd, key, cert, trust);
902 else
903 r = add_raw_socket(s, fd);
904 } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
905 char *hostname;
906
907 r = getpeername_pretty(fd, false, &hostname);
908 if (r < 0)
909 return log_error_errno(r, "Failed to retrieve remote name: %m");
910
911 log_debug("Received a connection socket (fd:%d) from %s", fd, hostname);
912
913 r = add_source(s, fd, hostname, true);
914 } else {
915 log_error("Unknown socket passed on fd:%d", fd);
916
917 return -EINVAL;
918 }
919
920 if (r < 0)
921 return log_error_errno(r, "Failed to register socket (fd:%d): %m",
922 fd);
923 }
924
925 if (arg_getter) {
926 log_info("Spawning getter %s...", arg_getter);
927 fd = spawn_getter(arg_getter);
928 if (fd < 0)
929 return fd;
930
931 r = add_source(s, fd, (char*) arg_output, false);
932 if (r < 0)
933 return r;
934 }
935
936 if (arg_url) {
937 const char *url;
938 char *hostname, *p;
939
940 if (!strstr(arg_url, "/entries")) {
941 if (endswith(arg_url, "/"))
942 url = strjoina(arg_url, "entries");
943 else
944 url = strjoina(arg_url, "/entries");
945 }
946 else
947 url = strdupa(arg_url);
948
949 log_info("Spawning curl %s...", url);
950 fd = spawn_curl(url);
951 if (fd < 0)
952 return fd;
953
954 hostname =
955 startswith(arg_url, "https://") ?:
956 startswith(arg_url, "http://") ?:
957 arg_url;
958
959 hostname = strdupa(hostname);
960 if ((p = strchr(hostname, '/')))
961 *p = '\0';
962 if ((p = strchr(hostname, ':')))
963 *p = '\0';
964
965 r = add_source(s, fd, hostname, false);
966 if (r < 0)
967 return r;
968 }
969
970 if (arg_listen_raw) {
971 log_debug("Listening on a socket...");
972 r = setup_raw_socket(s, arg_listen_raw);
973 if (r < 0)
974 return r;
975 }
976
977 if (arg_listen_http) {
978 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
979 if (r < 0)
980 return r;
981 }
982
983 if (arg_listen_https) {
984 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
985 if (r < 0)
986 return r;
987 }
988
989 STRV_FOREACH(file, arg_files) {
990 const char *output_name;
991
992 if (streq(*file, "-")) {
993 log_debug("Using standard input as source.");
994
995 fd = STDIN_FILENO;
996 output_name = "stdin";
997 } else {
998 log_debug("Reading file %s...", *file);
999
1000 fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
1001 if (fd < 0)
1002 return log_error_errno(errno, "Failed to open %s: %m", *file);
1003 output_name = *file;
1004 }
1005
1006 r = add_source(s, fd, (char*) output_name, false);
1007 if (r < 0)
1008 return r;
1009 }
1010
1011 if (s->active == 0) {
1012 log_error("Zero sources specified");
1013 return -EINVAL;
1014 }
1015
1016 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
1017 /* In this case we know what the writer will be
1018 called, so we can create it and verify that we can
1019 create output as expected. */
1020 r = get_writer(s, NULL, &s->_single_writer);
1021 if (r < 0)
1022 return r;
1023 }
1024
1025 return 0;
1026 }
1027
1028 static void MHDDaemonWrapper_free(MHDDaemonWrapper *d) {
1029 MHD_stop_daemon(d->daemon);
1030 sd_event_source_unref(d->io_event);
1031 sd_event_source_unref(d->timer_event);
1032 free(d);
1033 }
1034
1035 static void server_destroy(RemoteServer *s) {
1036 size_t i;
1037
1038 hashmap_free_with_destructor(s->daemons, MHDDaemonWrapper_free);
1039
1040 assert(s->sources_size == 0 || s->sources);
1041 for (i = 0; i < s->sources_size; i++)
1042 remove_source(s, i);
1043 free(s->sources);
1044
1045 writer_unref(s->_single_writer);
1046 hashmap_free(s->writers);
1047
1048 sd_event_source_unref(s->sigterm_event);
1049 sd_event_source_unref(s->sigint_event);
1050 sd_event_source_unref(s->listen_event);
1051 sd_event_unref(s->events);
1052
1053 /* fds that we're listening on remain open... */
1054 }
1055
1056 /**********************************************************************
1057 **********************************************************************
1058 **********************************************************************/
1059
1060 static int handle_raw_source(sd_event_source *event,
1061 int fd,
1062 uint32_t revents,
1063 RemoteServer *s) {
1064
1065 RemoteSource *source;
1066 int r;
1067
1068 /* Returns 1 if there might be more data pending,
1069 * 0 if data is currently exhausted, negative on error.
1070 */
1071
1072 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1073 source = s->sources[fd];
1074 assert(source->importer.fd == fd);
1075
1076 r = process_source(source, arg_compress, arg_seal);
1077 if (journal_importer_eof(&source->importer)) {
1078 size_t remaining;
1079
1080 log_debug("EOF reached with source %s (fd=%d)",
1081 source->importer.name, source->importer.fd);
1082
1083 remaining = journal_importer_bytes_remaining(&source->importer);
1084 if (remaining > 0)
1085 log_notice("Premature EOF. %zu bytes lost.", remaining);
1086 remove_source(s, source->importer.fd);
1087 log_debug("%zu active sources remaining", s->active);
1088 return 0;
1089 } else if (r == -E2BIG) {
1090 log_notice_errno(E2BIG, "Entry too big, skipped");
1091 return 1;
1092 } else if (r == -EAGAIN) {
1093 return 0;
1094 } else if (r < 0) {
1095 log_debug_errno(r, "Closing connection: %m");
1096 remove_source(server, fd);
1097 return 0;
1098 } else
1099 return 1;
1100 }
1101
1102 static int dispatch_raw_source_until_block(sd_event_source *event,
1103 void *userdata) {
1104 RemoteSource *source = userdata;
1105 int r;
1106
1107 /* Make sure event stays around even if source is destroyed */
1108 sd_event_source_ref(event);
1109
1110 r = handle_raw_source(event, source->importer.fd, EPOLLIN, server);
1111 if (r != 1)
1112 /* No more data for now */
1113 sd_event_source_set_enabled(event, SD_EVENT_OFF);
1114
1115 sd_event_source_unref(event);
1116
1117 return r;
1118 }
1119
1120 static int dispatch_raw_source_event(sd_event_source *event,
1121 int fd,
1122 uint32_t revents,
1123 void *userdata) {
1124 RemoteSource *source = userdata;
1125 int r;
1126
1127 assert(source->event);
1128 assert(source->buffer_event);
1129
1130 r = handle_raw_source(event, fd, EPOLLIN, server);
1131 if (r == 1)
1132 /* Might have more data. We need to rerun the handler
1133 * until we are sure the buffer is exhausted. */
1134 sd_event_source_set_enabled(source->buffer_event, SD_EVENT_ON);
1135
1136 return r;
1137 }
1138
1139 static int dispatch_blocking_source_event(sd_event_source *event,
1140 void *userdata) {
1141 RemoteSource *source = userdata;
1142
1143 return handle_raw_source(event, source->importer.fd, EPOLLIN, server);
1144 }
1145
1146 static int accept_connection(const char* type, int fd,
1147 SocketAddress *addr, char **hostname) {
1148 int fd2, r;
1149
1150 log_debug("Accepting new %s connection on fd:%d", type, fd);
1151 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1152 if (fd2 < 0)
1153 return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
1154
1155 switch(socket_address_family(addr)) {
1156 case AF_INET:
1157 case AF_INET6: {
1158 _cleanup_free_ char *a = NULL;
1159 char *b;
1160
1161 r = socket_address_print(addr, &a);
1162 if (r < 0) {
1163 log_error_errno(r, "socket_address_print(): %m");
1164 close(fd2);
1165 return r;
1166 }
1167
1168 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1169 if (r < 0) {
1170 log_error_errno(r, "Resolving hostname failed: %m");
1171 close(fd2);
1172 return r;
1173 }
1174
1175 log_debug("Accepted %s %s connection from %s",
1176 type,
1177 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1178 a);
1179
1180 *hostname = b;
1181
1182 return fd2;
1183 };
1184 default:
1185 log_error("Rejected %s connection with unsupported family %d",
1186 type, socket_address_family(addr));
1187 close(fd2);
1188
1189 return -EINVAL;
1190 }
1191 }
1192
1193 static int dispatch_raw_connection_event(sd_event_source *event,
1194 int fd,
1195 uint32_t revents,
1196 void *userdata) {
1197 RemoteServer *s = userdata;
1198 int fd2;
1199 SocketAddress addr = {
1200 .size = sizeof(union sockaddr_union),
1201 .type = SOCK_STREAM,
1202 };
1203 char *hostname = NULL;
1204
1205 fd2 = accept_connection("raw", fd, &addr, &hostname);
1206 if (fd2 < 0)
1207 return fd2;
1208
1209 return add_source(s, fd2, hostname, true);
1210 }
1211
1212 /**********************************************************************
1213 **********************************************************************
1214 **********************************************************************/
1215
1216 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1217 [JOURNAL_WRITE_SPLIT_NONE] = "none",
1218 [JOURNAL_WRITE_SPLIT_HOST] = "host",
1219 };
1220
1221 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1222 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1223 journal_write_split_mode,
1224 JournalWriteSplitMode,
1225 "Failed to parse split mode setting");
1226
1227 static int parse_config(void) {
1228 const ConfigTableItem items[] = {
1229 { "Remote", "Seal", config_parse_bool, 0, &arg_seal },
1230 { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
1231 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
1232 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
1233 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
1234 {}};
1235
1236 return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-remote.conf",
1237 CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
1238 "Remote\0", config_item_table_lookup, items,
1239 CONFIG_PARSE_WARN, NULL);
1240 }
1241
1242 static void help(void) {
1243 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1244 "Write external journal events to journal file(s).\n\n"
1245 " -h --help Show this help\n"
1246 " --version Show package version\n"
1247 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1248 " --getter=COMMAND Read events from the output of COMMAND\n"
1249 " --listen-raw=ADDR Listen for connections at ADDR\n"
1250 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1251 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1252 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1253 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1254 " --seal[=BOOL] Use event sealing (default: no)\n"
1255 " --key=FILENAME SSL key in PEM format (default:\n"
1256 " \"" PRIV_KEY_FILE "\")\n"
1257 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1258 " \"" CERT_FILE "\")\n"
1259 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1260 " \"" TRUST_FILE "\")\n"
1261 " --gnutls-log=CATEGORY...\n"
1262 " Specify a list of gnutls logging categories\n"
1263 " --split-mode=none|host How many output files to create\n"
1264 "\n"
1265 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1266 , program_invocation_short_name);
1267 }
1268
1269 static int parse_argv(int argc, char *argv[]) {
1270 enum {
1271 ARG_VERSION = 0x100,
1272 ARG_URL,
1273 ARG_LISTEN_RAW,
1274 ARG_LISTEN_HTTP,
1275 ARG_LISTEN_HTTPS,
1276 ARG_GETTER,
1277 ARG_SPLIT_MODE,
1278 ARG_COMPRESS,
1279 ARG_SEAL,
1280 ARG_KEY,
1281 ARG_CERT,
1282 ARG_TRUST,
1283 ARG_GNUTLS_LOG,
1284 };
1285
1286 static const struct option options[] = {
1287 { "help", no_argument, NULL, 'h' },
1288 { "version", no_argument, NULL, ARG_VERSION },
1289 { "url", required_argument, NULL, ARG_URL },
1290 { "getter", required_argument, NULL, ARG_GETTER },
1291 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1292 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1293 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1294 { "output", required_argument, NULL, 'o' },
1295 { "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
1296 { "compress", optional_argument, NULL, ARG_COMPRESS },
1297 { "seal", optional_argument, NULL, ARG_SEAL },
1298 { "key", required_argument, NULL, ARG_KEY },
1299 { "cert", required_argument, NULL, ARG_CERT },
1300 { "trust", required_argument, NULL, ARG_TRUST },
1301 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1302 {}
1303 };
1304
1305 int c, r;
1306 bool type_a, type_b;
1307
1308 assert(argc >= 0);
1309 assert(argv);
1310
1311 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1312 switch(c) {
1313 case 'h':
1314 help();
1315 return 0 /* done */;
1316
1317 case ARG_VERSION:
1318 return version();
1319
1320 case ARG_URL:
1321 if (arg_url) {
1322 log_error("cannot currently set more than one --url");
1323 return -EINVAL;
1324 }
1325
1326 arg_url = optarg;
1327 break;
1328
1329 case ARG_GETTER:
1330 if (arg_getter) {
1331 log_error("cannot currently use --getter more than once");
1332 return -EINVAL;
1333 }
1334
1335 arg_getter = optarg;
1336 break;
1337
1338 case ARG_LISTEN_RAW:
1339 if (arg_listen_raw) {
1340 log_error("cannot currently use --listen-raw more than once");
1341 return -EINVAL;
1342 }
1343
1344 arg_listen_raw = optarg;
1345 break;
1346
1347 case ARG_LISTEN_HTTP:
1348 if (arg_listen_http || http_socket >= 0) {
1349 log_error("cannot currently use --listen-http more than once");
1350 return -EINVAL;
1351 }
1352
1353 r = negative_fd(optarg);
1354 if (r >= 0)
1355 http_socket = r;
1356 else
1357 arg_listen_http = optarg;
1358 break;
1359
1360 case ARG_LISTEN_HTTPS:
1361 if (arg_listen_https || https_socket >= 0) {
1362 log_error("cannot currently use --listen-https more than once");
1363 return -EINVAL;
1364 }
1365
1366 r = negative_fd(optarg);
1367 if (r >= 0)
1368 https_socket = r;
1369 else
1370 arg_listen_https = optarg;
1371
1372 break;
1373
1374 case ARG_KEY:
1375 if (arg_key) {
1376 log_error("Key file specified twice");
1377 return -EINVAL;
1378 }
1379
1380 arg_key = strdup(optarg);
1381 if (!arg_key)
1382 return log_oom();
1383
1384 break;
1385
1386 case ARG_CERT:
1387 if (arg_cert) {
1388 log_error("Certificate file specified twice");
1389 return -EINVAL;
1390 }
1391
1392 arg_cert = strdup(optarg);
1393 if (!arg_cert)
1394 return log_oom();
1395
1396 break;
1397
1398 case ARG_TRUST:
1399 if (arg_trust || arg_trust_all) {
1400 log_error("Confusing trusted CA configuration");
1401 return -EINVAL;
1402 }
1403
1404 if (streq(optarg, "all"))
1405 arg_trust_all = true;
1406 else {
1407 #if HAVE_GNUTLS
1408 arg_trust = strdup(optarg);
1409 if (!arg_trust)
1410 return log_oom();
1411 #else
1412 log_error("Option --trust is not available.");
1413 return -EINVAL;
1414 #endif
1415 }
1416
1417 break;
1418
1419 case 'o':
1420 if (arg_output) {
1421 log_error("cannot use --output/-o more than once");
1422 return -EINVAL;
1423 }
1424
1425 arg_output = optarg;
1426 break;
1427
1428 case ARG_SPLIT_MODE:
1429 arg_split_mode = journal_write_split_mode_from_string(optarg);
1430 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1431 log_error("Invalid split mode: %s", optarg);
1432 return -EINVAL;
1433 }
1434 break;
1435
1436 case ARG_COMPRESS:
1437 if (optarg) {
1438 r = parse_boolean(optarg);
1439 if (r < 0) {
1440 log_error("Failed to parse --compress= parameter.");
1441 return -EINVAL;
1442 }
1443
1444 arg_compress = !!r;
1445 } else
1446 arg_compress = true;
1447
1448 break;
1449
1450 case ARG_SEAL:
1451 if (optarg) {
1452 r = parse_boolean(optarg);
1453 if (r < 0) {
1454 log_error("Failed to parse --seal= parameter.");
1455 return -EINVAL;
1456 }
1457
1458 arg_seal = !!r;
1459 } else
1460 arg_seal = true;
1461
1462 break;
1463
1464 case ARG_GNUTLS_LOG: {
1465 #if HAVE_GNUTLS
1466 const char* p = optarg;
1467 for (;;) {
1468 _cleanup_free_ char *word = NULL;
1469
1470 r = extract_first_word(&p, &word, ",", 0);
1471 if (r < 0)
1472 return log_error_errno(r, "Failed to parse --gnutls-log= argument: %m");
1473
1474 if (r == 0)
1475 break;
1476
1477 if (strv_push(&arg_gnutls_log, word) < 0)
1478 return log_oom();
1479
1480 word = NULL;
1481 }
1482 break;
1483 #else
1484 log_error("Option --gnutls-log is not available.");
1485 return -EINVAL;
1486 #endif
1487 }
1488
1489 case '?':
1490 return -EINVAL;
1491
1492 default:
1493 assert_not_reached("Unknown option code.");
1494 }
1495
1496 if (optind < argc)
1497 arg_files = argv + optind;
1498
1499 type_a = arg_getter || !strv_isempty(arg_files);
1500 type_b = arg_url
1501 || arg_listen_raw
1502 || arg_listen_http || arg_listen_https
1503 || sd_listen_fds(false) > 0;
1504 if (type_a && type_b) {
1505 log_error("Cannot use file input or --getter with "
1506 "--arg-listen-... or socket activation.");
1507 return -EINVAL;
1508 }
1509 if (type_a) {
1510 if (!arg_output) {
1511 log_error("Option --output must be specified with file input or --getter.");
1512 return -EINVAL;
1513 }
1514
1515 if (!IN_SET(arg_split_mode, JOURNAL_WRITE_SPLIT_NONE, _JOURNAL_WRITE_SPLIT_INVALID)) {
1516 log_error("For active sources, only --split-mode=none is allowed.");
1517 return -EINVAL;
1518 }
1519
1520 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1521 }
1522
1523 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID)
1524 arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
1525
1526 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE && arg_output) {
1527 if (is_dir(arg_output, true) > 0) {
1528 log_error("For SplitMode=none, output must be a file.");
1529 return -EINVAL;
1530 }
1531 if (!endswith(arg_output, ".journal")) {
1532 log_error("For SplitMode=none, output file name must end with .journal.");
1533 return -EINVAL;
1534 }
1535 }
1536
1537 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1538 && arg_output && is_dir(arg_output, true) <= 0) {
1539 log_error("For SplitMode=host, output must be a directory.");
1540 return -EINVAL;
1541 }
1542
1543 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1544 journal_write_split_mode_to_string(arg_split_mode),
1545 strna(arg_key),
1546 strna(arg_cert),
1547 strna(arg_trust));
1548
1549 return 1 /* work to do */;
1550 }
1551
1552 static int load_certificates(char **key, char **cert, char **trust) {
1553 int r;
1554
1555 r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1556 if (r < 0)
1557 return log_error_errno(r, "Failed to read key from file '%s': %m",
1558 arg_key ?: PRIV_KEY_FILE);
1559
1560 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1561 if (r < 0)
1562 return log_error_errno(r, "Failed to read certificate from file '%s': %m",
1563 arg_cert ?: CERT_FILE);
1564
1565 if (arg_trust_all)
1566 log_info("Certificate checking disabled.");
1567 else {
1568 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1569 if (r < 0)
1570 return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
1571 arg_trust ?: TRUST_FILE);
1572 }
1573
1574 return 0;
1575 }
1576
1577 int main(int argc, char **argv) {
1578 RemoteServer s = {};
1579 int r;
1580 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1581
1582 log_show_color(true);
1583 log_parse_environment();
1584
1585 r = parse_config();
1586 if (r < 0)
1587 return EXIT_FAILURE;
1588
1589 r = parse_argv(argc, argv);
1590 if (r <= 0)
1591 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1592
1593
1594 if (arg_listen_http || arg_listen_https) {
1595 r = setup_gnutls_logger(arg_gnutls_log);
1596 if (r < 0)
1597 return EXIT_FAILURE;
1598 }
1599
1600 if (arg_listen_https || https_socket >= 0)
1601 if (load_certificates(&key, &cert, &trust) < 0)
1602 return EXIT_FAILURE;
1603
1604 if (remoteserver_init(&s, key, cert, trust) < 0)
1605 return EXIT_FAILURE;
1606
1607 r = sd_event_set_watchdog(s.events, true);
1608 if (r < 0)
1609 log_error_errno(r, "Failed to enable watchdog: %m");
1610 else
1611 log_debug("Watchdog is %sd.", enable_disable(r > 0));
1612
1613 log_debug("%s running as pid "PID_FMT,
1614 program_invocation_short_name, getpid_cached());
1615 sd_notify(false,
1616 "READY=1\n"
1617 "STATUS=Processing requests...");
1618
1619 while (s.active) {
1620 r = sd_event_get_state(s.events);
1621 if (r < 0)
1622 break;
1623 if (r == SD_EVENT_FINISHED)
1624 break;
1625
1626 r = sd_event_run(s.events, -1);
1627 if (r < 0) {
1628 log_error_errno(r, "Failed to run event loop: %m");
1629 break;
1630 }
1631 }
1632
1633 sd_notifyf(false,
1634 "STOPPING=1\n"
1635 "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1636 log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1637
1638 server_destroy(&s);
1639
1640 free(arg_key);
1641 free(arg_cert);
1642 free(arg_trust);
1643
1644 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1645 }