]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal-remote/journal-remote.c
Add SPDX license identifiers to source files under the LGPL
[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[sizeof("raw-socket-")-1 + 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 server_destroy(RemoteServer *s) {
1047 size_t i;
1048 MHDDaemonWrapper *d;
1049
1050 while ((d = hashmap_steal_first(s->daemons))) {
1051 MHD_stop_daemon(d->daemon);
1052 sd_event_source_unref(d->io_event);
1053 sd_event_source_unref(d->timer_event);
1054 free(d);
1055 }
1056
1057 hashmap_free(s->daemons);
1058
1059 assert(s->sources_size == 0 || s->sources);
1060 for (i = 0; i < s->sources_size; i++)
1061 remove_source(s, i);
1062 free(s->sources);
1063
1064 writer_unref(s->_single_writer);
1065 hashmap_free(s->writers);
1066
1067 sd_event_source_unref(s->sigterm_event);
1068 sd_event_source_unref(s->sigint_event);
1069 sd_event_source_unref(s->listen_event);
1070 sd_event_unref(s->events);
1071
1072 /* fds that we're listening on remain open... */
1073 }
1074
1075 /**********************************************************************
1076 **********************************************************************
1077 **********************************************************************/
1078
1079 static int handle_raw_source(sd_event_source *event,
1080 int fd,
1081 uint32_t revents,
1082 RemoteServer *s) {
1083
1084 RemoteSource *source;
1085 int r;
1086
1087 /* Returns 1 if there might be more data pending,
1088 * 0 if data is currently exhausted, negative on error.
1089 */
1090
1091 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1092 source = s->sources[fd];
1093 assert(source->importer.fd == fd);
1094
1095 r = process_source(source, arg_compress, arg_seal);
1096 if (journal_importer_eof(&source->importer)) {
1097 size_t remaining;
1098
1099 log_debug("EOF reached with source %s (fd=%d)",
1100 source->importer.name, source->importer.fd);
1101
1102 remaining = journal_importer_bytes_remaining(&source->importer);
1103 if (remaining > 0)
1104 log_notice("Premature EOF. %zu bytes lost.", remaining);
1105 remove_source(s, source->importer.fd);
1106 log_debug("%zu active sources remaining", s->active);
1107 return 0;
1108 } else if (r == -E2BIG) {
1109 log_notice_errno(E2BIG, "Entry too big, skipped");
1110 return 1;
1111 } else if (r == -EAGAIN) {
1112 return 0;
1113 } else if (r < 0) {
1114 log_debug_errno(r, "Closing connection: %m");
1115 remove_source(server, fd);
1116 return 0;
1117 } else
1118 return 1;
1119 }
1120
1121 static int dispatch_raw_source_until_block(sd_event_source *event,
1122 void *userdata) {
1123 RemoteSource *source = userdata;
1124 int r;
1125
1126 /* Make sure event stays around even if source is destroyed */
1127 sd_event_source_ref(event);
1128
1129 r = handle_raw_source(event, source->importer.fd, EPOLLIN, server);
1130 if (r != 1)
1131 /* No more data for now */
1132 sd_event_source_set_enabled(event, SD_EVENT_OFF);
1133
1134 sd_event_source_unref(event);
1135
1136 return r;
1137 }
1138
1139 static int dispatch_raw_source_event(sd_event_source *event,
1140 int fd,
1141 uint32_t revents,
1142 void *userdata) {
1143 RemoteSource *source = userdata;
1144 int r;
1145
1146 assert(source->event);
1147 assert(source->buffer_event);
1148
1149 r = handle_raw_source(event, fd, EPOLLIN, server);
1150 if (r == 1)
1151 /* Might have more data. We need to rerun the handler
1152 * until we are sure the buffer is exhausted. */
1153 sd_event_source_set_enabled(source->buffer_event, SD_EVENT_ON);
1154
1155 return r;
1156 }
1157
1158 static int dispatch_blocking_source_event(sd_event_source *event,
1159 void *userdata) {
1160 RemoteSource *source = userdata;
1161
1162 return handle_raw_source(event, source->importer.fd, EPOLLIN, server);
1163 }
1164
1165 static int accept_connection(const char* type, int fd,
1166 SocketAddress *addr, char **hostname) {
1167 int fd2, r;
1168
1169 log_debug("Accepting new %s connection on fd:%d", type, fd);
1170 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1171 if (fd2 < 0)
1172 return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
1173
1174 switch(socket_address_family(addr)) {
1175 case AF_INET:
1176 case AF_INET6: {
1177 _cleanup_free_ char *a = NULL;
1178 char *b;
1179
1180 r = socket_address_print(addr, &a);
1181 if (r < 0) {
1182 log_error_errno(r, "socket_address_print(): %m");
1183 close(fd2);
1184 return r;
1185 }
1186
1187 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1188 if (r < 0) {
1189 log_error_errno(r, "Resolving hostname failed: %m");
1190 close(fd2);
1191 return r;
1192 }
1193
1194 log_debug("Accepted %s %s connection from %s",
1195 type,
1196 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1197 a);
1198
1199 *hostname = b;
1200
1201 return fd2;
1202 };
1203 default:
1204 log_error("Rejected %s connection with unsupported family %d",
1205 type, socket_address_family(addr));
1206 close(fd2);
1207
1208 return -EINVAL;
1209 }
1210 }
1211
1212 static int dispatch_raw_connection_event(sd_event_source *event,
1213 int fd,
1214 uint32_t revents,
1215 void *userdata) {
1216 RemoteServer *s = userdata;
1217 int fd2;
1218 SocketAddress addr = {
1219 .size = sizeof(union sockaddr_union),
1220 .type = SOCK_STREAM,
1221 };
1222 char *hostname = NULL;
1223
1224 fd2 = accept_connection("raw", fd, &addr, &hostname);
1225 if (fd2 < 0)
1226 return fd2;
1227
1228 return add_source(s, fd2, hostname, true);
1229 }
1230
1231 /**********************************************************************
1232 **********************************************************************
1233 **********************************************************************/
1234
1235 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1236 [JOURNAL_WRITE_SPLIT_NONE] = "none",
1237 [JOURNAL_WRITE_SPLIT_HOST] = "host",
1238 };
1239
1240 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1241 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1242 journal_write_split_mode,
1243 JournalWriteSplitMode,
1244 "Failed to parse split mode setting");
1245
1246 static int parse_config(void) {
1247 const ConfigTableItem items[] = {
1248 { "Remote", "Seal", config_parse_bool, 0, &arg_seal },
1249 { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
1250 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
1251 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
1252 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
1253 {}};
1254
1255 return config_parse_many_nulstr(PKGSYSCONFDIR "/journal-remote.conf",
1256 CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"),
1257 "Remote\0", config_item_table_lookup, items,
1258 CONFIG_PARSE_WARN, NULL);
1259 }
1260
1261 static void help(void) {
1262 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1263 "Write external journal events to journal file(s).\n\n"
1264 " -h --help Show this help\n"
1265 " --version Show package version\n"
1266 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1267 " --getter=COMMAND Read events from the output of COMMAND\n"
1268 " --listen-raw=ADDR Listen for connections at ADDR\n"
1269 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1270 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1271 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1272 " --compress[=BOOL] XZ-compress the output journal (default: yes)\n"
1273 " --seal[=BOOL] Use event sealing (default: no)\n"
1274 " --key=FILENAME SSL key in PEM format (default:\n"
1275 " \"" PRIV_KEY_FILE "\")\n"
1276 " --cert=FILENAME SSL certificate in PEM format (default:\n"
1277 " \"" CERT_FILE "\")\n"
1278 " --trust=FILENAME|all SSL CA certificate or disable checking (default:\n"
1279 " \"" TRUST_FILE "\")\n"
1280 " --gnutls-log=CATEGORY...\n"
1281 " Specify a list of gnutls logging categories\n"
1282 " --split-mode=none|host How many output files to create\n"
1283 "\n"
1284 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1285 , program_invocation_short_name);
1286 }
1287
1288 static int parse_argv(int argc, char *argv[]) {
1289 enum {
1290 ARG_VERSION = 0x100,
1291 ARG_URL,
1292 ARG_LISTEN_RAW,
1293 ARG_LISTEN_HTTP,
1294 ARG_LISTEN_HTTPS,
1295 ARG_GETTER,
1296 ARG_SPLIT_MODE,
1297 ARG_COMPRESS,
1298 ARG_SEAL,
1299 ARG_KEY,
1300 ARG_CERT,
1301 ARG_TRUST,
1302 ARG_GNUTLS_LOG,
1303 };
1304
1305 static const struct option options[] = {
1306 { "help", no_argument, NULL, 'h' },
1307 { "version", no_argument, NULL, ARG_VERSION },
1308 { "url", required_argument, NULL, ARG_URL },
1309 { "getter", required_argument, NULL, ARG_GETTER },
1310 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1311 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1312 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1313 { "output", required_argument, NULL, 'o' },
1314 { "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
1315 { "compress", optional_argument, NULL, ARG_COMPRESS },
1316 { "seal", optional_argument, NULL, ARG_SEAL },
1317 { "key", required_argument, NULL, ARG_KEY },
1318 { "cert", required_argument, NULL, ARG_CERT },
1319 { "trust", required_argument, NULL, ARG_TRUST },
1320 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1321 {}
1322 };
1323
1324 int c, r;
1325 bool type_a, type_b;
1326
1327 assert(argc >= 0);
1328 assert(argv);
1329
1330 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1331 switch(c) {
1332 case 'h':
1333 help();
1334 return 0 /* done */;
1335
1336 case ARG_VERSION:
1337 return version();
1338
1339 case ARG_URL:
1340 if (arg_url) {
1341 log_error("cannot currently set more than one --url");
1342 return -EINVAL;
1343 }
1344
1345 arg_url = optarg;
1346 break;
1347
1348 case ARG_GETTER:
1349 if (arg_getter) {
1350 log_error("cannot currently use --getter more than once");
1351 return -EINVAL;
1352 }
1353
1354 arg_getter = optarg;
1355 break;
1356
1357 case ARG_LISTEN_RAW:
1358 if (arg_listen_raw) {
1359 log_error("cannot currently use --listen-raw more than once");
1360 return -EINVAL;
1361 }
1362
1363 arg_listen_raw = optarg;
1364 break;
1365
1366 case ARG_LISTEN_HTTP:
1367 if (arg_listen_http || http_socket >= 0) {
1368 log_error("cannot currently use --listen-http more than once");
1369 return -EINVAL;
1370 }
1371
1372 r = negative_fd(optarg);
1373 if (r >= 0)
1374 http_socket = r;
1375 else
1376 arg_listen_http = optarg;
1377 break;
1378
1379 case ARG_LISTEN_HTTPS:
1380 if (arg_listen_https || https_socket >= 0) {
1381 log_error("cannot currently use --listen-https more than once");
1382 return -EINVAL;
1383 }
1384
1385 r = negative_fd(optarg);
1386 if (r >= 0)
1387 https_socket = r;
1388 else
1389 arg_listen_https = optarg;
1390
1391 break;
1392
1393 case ARG_KEY:
1394 if (arg_key) {
1395 log_error("Key file specified twice");
1396 return -EINVAL;
1397 }
1398
1399 arg_key = strdup(optarg);
1400 if (!arg_key)
1401 return log_oom();
1402
1403 break;
1404
1405 case ARG_CERT:
1406 if (arg_cert) {
1407 log_error("Certificate file specified twice");
1408 return -EINVAL;
1409 }
1410
1411 arg_cert = strdup(optarg);
1412 if (!arg_cert)
1413 return log_oom();
1414
1415 break;
1416
1417 case ARG_TRUST:
1418 if (arg_trust || arg_trust_all) {
1419 log_error("Confusing trusted CA configuration");
1420 return -EINVAL;
1421 }
1422
1423 if (streq(optarg, "all"))
1424 arg_trust_all = true;
1425 else {
1426 #if HAVE_GNUTLS
1427 arg_trust = strdup(optarg);
1428 if (!arg_trust)
1429 return log_oom();
1430 #else
1431 log_error("Option --trust is not available.");
1432 return -EINVAL;
1433 #endif
1434 }
1435
1436 break;
1437
1438 case 'o':
1439 if (arg_output) {
1440 log_error("cannot use --output/-o more than once");
1441 return -EINVAL;
1442 }
1443
1444 arg_output = optarg;
1445 break;
1446
1447 case ARG_SPLIT_MODE:
1448 arg_split_mode = journal_write_split_mode_from_string(optarg);
1449 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1450 log_error("Invalid split mode: %s", optarg);
1451 return -EINVAL;
1452 }
1453 break;
1454
1455 case ARG_COMPRESS:
1456 if (optarg) {
1457 r = parse_boolean(optarg);
1458 if (r < 0) {
1459 log_error("Failed to parse --compress= parameter.");
1460 return -EINVAL;
1461 }
1462
1463 arg_compress = !!r;
1464 } else
1465 arg_compress = true;
1466
1467 break;
1468
1469 case ARG_SEAL:
1470 if (optarg) {
1471 r = parse_boolean(optarg);
1472 if (r < 0) {
1473 log_error("Failed to parse --seal= parameter.");
1474 return -EINVAL;
1475 }
1476
1477 arg_seal = !!r;
1478 } else
1479 arg_seal = true;
1480
1481 break;
1482
1483 case ARG_GNUTLS_LOG: {
1484 #if HAVE_GNUTLS
1485 const char* p = optarg;
1486 for (;;) {
1487 _cleanup_free_ char *word = NULL;
1488
1489 r = extract_first_word(&p, &word, ",", 0);
1490 if (r < 0)
1491 return log_error_errno(r, "Failed to parse --gnutls-log= argument: %m");
1492
1493 if (r == 0)
1494 break;
1495
1496 if (strv_push(&arg_gnutls_log, word) < 0)
1497 return log_oom();
1498
1499 word = NULL;
1500 }
1501 break;
1502 #else
1503 log_error("Option --gnutls-log is not available.");
1504 return -EINVAL;
1505 #endif
1506 }
1507
1508 case '?':
1509 return -EINVAL;
1510
1511 default:
1512 assert_not_reached("Unknown option code.");
1513 }
1514
1515 if (optind < argc)
1516 arg_files = argv + optind;
1517
1518 type_a = arg_getter || !strv_isempty(arg_files);
1519 type_b = arg_url
1520 || arg_listen_raw
1521 || arg_listen_http || arg_listen_https
1522 || sd_listen_fds(false) > 0;
1523 if (type_a && type_b) {
1524 log_error("Cannot use file input or --getter with "
1525 "--arg-listen-... or socket activation.");
1526 return -EINVAL;
1527 }
1528 if (type_a) {
1529 if (!arg_output) {
1530 log_error("Option --output must be specified with file input or --getter.");
1531 return -EINVAL;
1532 }
1533
1534 if (!IN_SET(arg_split_mode, JOURNAL_WRITE_SPLIT_NONE, _JOURNAL_WRITE_SPLIT_INVALID)) {
1535 log_error("For active sources, only --split-mode=none is allowed.");
1536 return -EINVAL;
1537 }
1538
1539 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1540 }
1541
1542 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID)
1543 arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
1544
1545 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE && arg_output) {
1546 if (is_dir(arg_output, true) > 0) {
1547 log_error("For SplitMode=none, output must be a file.");
1548 return -EINVAL;
1549 }
1550 if (!endswith(arg_output, ".journal")) {
1551 log_error("For SplitMode=none, output file name must end with .journal.");
1552 return -EINVAL;
1553 }
1554 }
1555
1556 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1557 && arg_output && is_dir(arg_output, true) <= 0) {
1558 log_error("For SplitMode=host, output must be a directory.");
1559 return -EINVAL;
1560 }
1561
1562 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1563 journal_write_split_mode_to_string(arg_split_mode),
1564 strna(arg_key),
1565 strna(arg_cert),
1566 strna(arg_trust));
1567
1568 return 1 /* work to do */;
1569 }
1570
1571 static int load_certificates(char **key, char **cert, char **trust) {
1572 int r;
1573
1574 r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1575 if (r < 0)
1576 return log_error_errno(r, "Failed to read key from file '%s': %m",
1577 arg_key ?: PRIV_KEY_FILE);
1578
1579 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1580 if (r < 0)
1581 return log_error_errno(r, "Failed to read certificate from file '%s': %m",
1582 arg_cert ?: CERT_FILE);
1583
1584 if (arg_trust_all)
1585 log_info("Certificate checking disabled.");
1586 else {
1587 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1588 if (r < 0)
1589 return log_error_errno(r, "Failed to read CA certificate file '%s': %m",
1590 arg_trust ?: TRUST_FILE);
1591 }
1592
1593 return 0;
1594 }
1595
1596 int main(int argc, char **argv) {
1597 RemoteServer s = {};
1598 int r;
1599 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1600
1601 log_show_color(true);
1602 log_parse_environment();
1603
1604 r = parse_config();
1605 if (r < 0)
1606 return EXIT_FAILURE;
1607
1608 r = parse_argv(argc, argv);
1609 if (r <= 0)
1610 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1611
1612
1613 if (arg_listen_http || arg_listen_https) {
1614 r = setup_gnutls_logger(arg_gnutls_log);
1615 if (r < 0)
1616 return EXIT_FAILURE;
1617 }
1618
1619 if (arg_listen_https || https_socket >= 0)
1620 if (load_certificates(&key, &cert, &trust) < 0)
1621 return EXIT_FAILURE;
1622
1623 if (remoteserver_init(&s, key, cert, trust) < 0)
1624 return EXIT_FAILURE;
1625
1626 r = sd_event_set_watchdog(s.events, true);
1627 if (r < 0)
1628 log_error_errno(r, "Failed to enable watchdog: %m");
1629 else
1630 log_debug("Watchdog is %sd.", enable_disable(r > 0));
1631
1632 log_debug("%s running as pid "PID_FMT,
1633 program_invocation_short_name, getpid_cached());
1634 sd_notify(false,
1635 "READY=1\n"
1636 "STATUS=Processing requests...");
1637
1638 while (s.active) {
1639 r = sd_event_get_state(s.events);
1640 if (r < 0)
1641 break;
1642 if (r == SD_EVENT_FINISHED)
1643 break;
1644
1645 r = sd_event_run(s.events, -1);
1646 if (r < 0) {
1647 log_error_errno(r, "Failed to run event loop: %m");
1648 break;
1649 }
1650 }
1651
1652 sd_notifyf(false,
1653 "STOPPING=1\n"
1654 "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1655 log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1656
1657 server_destroy(&s);
1658
1659 free(arg_key);
1660 free(arg_cert);
1661 free(arg_trust);
1662
1663 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1664 }