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