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