]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal-remote/journal-remote.c
journal-remote: remove obsolete variable
[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 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 words = strv_split_quoted(getter);
153 if (!words)
154 return log_oom();
155
156 r = strv_extend(&words, url);
157 if (r < 0) {
158 log_error("Failed to create command line: %s", strerror(-r));
159 return r;
160 }
161
162 r = spawn_child(words[0], words);
163 if (r < 0)
164 log_error("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,
209 NULL, &w->journal);
210 if (r < 0)
211 log_error("Failed to open output journal %s: %s",
212 output, strerror(-r));
213 else
214 log_info("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 {
224 hash_func_t hash_func;
225 compare_func_t compare_func;
226 } functions[] = {
227 [JOURNAL_WRITE_SPLIT_NONE] = {trivial_hash_func,
228 trivial_compare_func},
229 [JOURNAL_WRITE_SPLIT_HOST] = {string_hash_func,
230 string_compare_func},
231 };
232
233 assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(functions));
234
235 s->writers = hashmap_new(functions[arg_split_mode].hash_func,
236 functions[arg_split_mode].compare_func);
237 if (!s->writers)
238 return log_oom();
239
240 return 0;
241 }
242
243 static int get_writer(RemoteServer *s, const char *host,
244 Writer **writer) {
245 const void *key;
246 _cleanup_writer_unref_ Writer *w = NULL;
247 int r;
248
249 switch(arg_split_mode) {
250 case JOURNAL_WRITE_SPLIT_NONE:
251 key = "one and only";
252 break;
253
254 case JOURNAL_WRITE_SPLIT_HOST:
255 assert(host);
256 key = host;
257 break;
258
259 default:
260 assert_not_reached("what split mode?");
261 }
262
263 w = hashmap_get(s->writers, key);
264 if (w)
265 writer_ref(w);
266 else {
267 w = writer_new(s);
268 if (!w)
269 return log_oom();
270
271 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
272 w->hashmap_key = strdup(key);
273 if (!w->hashmap_key)
274 return log_oom();
275 }
276
277 r = open_output(w, host);
278 if (r < 0)
279 return r;
280
281 r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
282 if (r < 0)
283 return r;
284 }
285
286 *writer = w;
287 w = NULL;
288 return 0;
289 }
290
291 /**********************************************************************
292 **********************************************************************
293 **********************************************************************/
294
295 /* This should go away as soon as µhttpd allows state to be passed around. */
296 static RemoteServer *server;
297
298 static int dispatch_raw_source_event(sd_event_source *event,
299 int fd,
300 uint32_t revents,
301 void *userdata);
302 static int dispatch_raw_connection_event(sd_event_source *event,
303 int fd,
304 uint32_t revents,
305 void *userdata);
306 static int dispatch_http_event(sd_event_source *event,
307 int fd,
308 uint32_t revents,
309 void *userdata);
310
311 static int get_source_for_fd(RemoteServer *s,
312 int fd, char *name, RemoteSource **source) {
313 Writer *writer;
314 int r;
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 assert(s);
366 assert(fd >= 0);
367 assert(name);
368
369 if (!own_name) {
370 name = strdup(name);
371 if (!name)
372 return log_oom();
373 }
374
375 r = get_source_for_fd(s, fd, name, &source);
376 if (r < 0) {
377 log_error("Failed to create source for fd:%d (%s): %s",
378 fd, name, strerror(-r));
379 return r;
380 }
381
382 r = sd_event_add_io(s->events, &source->event,
383 fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
384 dispatch_raw_source_event, s);
385 if (r < 0) {
386 log_error("Failed to register event source for fd:%d: %s",
387 fd, strerror(-r));
388 goto error;
389 }
390
391 return 1; /* work to do */
392
393 error:
394 remove_source(s, fd);
395 return r;
396 }
397
398 static int add_raw_socket(RemoteServer *s, int fd) {
399 int r;
400
401 r = sd_event_add_io(s->events, &s->listen_event,
402 fd, EPOLLIN,
403 dispatch_raw_connection_event, s);
404 if (r < 0) {
405 close(fd);
406 return r;
407 }
408
409 s->active ++;
410 return 0;
411 }
412
413 static int setup_raw_socket(RemoteServer *s, const char *address) {
414 int fd;
415
416 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
417 if (fd < 0)
418 return fd;
419
420 return add_raw_socket(s, fd);
421 }
422
423 /**********************************************************************
424 **********************************************************************
425 **********************************************************************/
426
427 static RemoteSource *request_meta(void **connection_cls, int fd, char *hostname) {
428 RemoteSource *source;
429 Writer *writer;
430 int r;
431
432 assert(connection_cls);
433 if (*connection_cls)
434 return *connection_cls;
435
436 r = get_writer(server, hostname, &writer);
437 if (r < 0) {
438 log_warning("Failed to get writer for source %s: %s",
439 hostname, strerror(-r));
440 return NULL;
441 }
442
443 source = source_new(fd, true, hostname, writer);
444 if (!source) {
445 log_oom();
446 writer_unref(writer);
447 return NULL;
448 }
449
450 log_debug("Added RemoteSource as connection metadata %p", source);
451
452 *connection_cls = source;
453 return source;
454 }
455
456 static void request_meta_free(void *cls,
457 struct MHD_Connection *connection,
458 void **connection_cls,
459 enum MHD_RequestTerminationCode toe) {
460 RemoteSource *s;
461
462 assert(connection_cls);
463 s = *connection_cls;
464
465 log_debug("Cleaning up connection metadata %p", s);
466 source_free(s);
467 *connection_cls = NULL;
468 }
469
470 static int process_http_upload(
471 struct MHD_Connection *connection,
472 const char *upload_data,
473 size_t *upload_data_size,
474 RemoteSource *source) {
475
476 bool finished = false;
477 size_t remaining;
478 int r;
479
480 assert(source);
481
482 log_debug("request_handler_upload: connection %p, %zu bytes",
483 connection, *upload_data_size);
484
485 if (*upload_data_size) {
486 log_debug("Received %zu bytes", *upload_data_size);
487
488 r = push_data(source, upload_data, *upload_data_size);
489 if (r < 0)
490 return mhd_respond_oom(connection);
491
492 *upload_data_size = 0;
493 } else
494 finished = true;
495
496 while (true) {
497 r = process_source(source, arg_compress, arg_seal);
498 if (r == -EAGAIN || r == -EWOULDBLOCK)
499 break;
500 else if (r < 0) {
501 log_warning("Failed to process data for connection %p", connection);
502 if (r == -E2BIG)
503 return mhd_respondf(connection,
504 MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
505 "Entry is too large, maximum is %u bytes.\n",
506 DATA_SIZE_MAX);
507 else
508 return mhd_respondf(connection,
509 MHD_HTTP_UNPROCESSABLE_ENTITY,
510 "Processing failed: %s.", strerror(-r));
511 }
512 }
513
514 if (!finished)
515 return MHD_YES;
516
517 /* The upload is finished */
518
519 remaining = source_non_empty(source);
520 if (remaining > 0) {
521 log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
522 return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
523 "Premature EOF. %zu bytes of trailing data not processed.",
524 remaining);
525 }
526
527 return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
528 };
529
530 static int request_handler(
531 void *cls,
532 struct MHD_Connection *connection,
533 const char *url,
534 const char *method,
535 const char *version,
536 const char *upload_data,
537 size_t *upload_data_size,
538 void **connection_cls) {
539
540 const char *header;
541 int r, code, fd;
542 _cleanup_free_ char *hostname = NULL;
543
544 assert(connection);
545 assert(connection_cls);
546 assert(url);
547 assert(method);
548
549 log_debug("Handling a connection %s %s %s", method, url, version);
550
551 if (*connection_cls)
552 return process_http_upload(connection,
553 upload_data, upload_data_size,
554 *connection_cls);
555
556 if (!streq(method, "POST"))
557 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
558 "Unsupported method.\n");
559
560 if (!streq(url, "/upload"))
561 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
562 "Not found.\n");
563
564 header = MHD_lookup_connection_value(connection,
565 MHD_HEADER_KIND, "Content-Type");
566 if (!header || !streq(header, "application/vnd.fdo.journal"))
567 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
568 "Content-Type: application/vnd.fdo.journal"
569 " is required.\n");
570
571 {
572 const union MHD_ConnectionInfo *ci;
573
574 ci = MHD_get_connection_info(connection,
575 MHD_CONNECTION_INFO_CONNECTION_FD);
576 if (!ci) {
577 log_error("MHD_get_connection_info failed: cannot get remote fd");
578 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
579 "Cannot check remote address");
580 return code;
581 }
582
583 fd = ci->connect_fd;
584 assert(fd >= 0);
585 }
586
587 if (server->check_trust) {
588 r = check_permissions(connection, &code, &hostname);
589 if (r < 0)
590 return code;
591 } else {
592 r = getnameinfo_pretty(fd, &hostname);
593 if (r < 0) {
594 return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
595 "Cannot check remote hostname");
596 }
597 }
598
599 assert(hostname);
600
601 if (!request_meta(connection_cls, fd, hostname))
602 return respond_oom(connection);
603 hostname = NULL;
604 return MHD_YES;
605 }
606
607 static int setup_microhttpd_server(RemoteServer *s,
608 int fd,
609 const char *key,
610 const char *cert,
611 const char *trust) {
612 struct MHD_OptionItem opts[] = {
613 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
614 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
615 { MHD_OPTION_LISTEN_SOCKET, fd},
616 { MHD_OPTION_END},
617 { MHD_OPTION_END},
618 { MHD_OPTION_END},
619 { MHD_OPTION_END}};
620 int opts_pos = 3;
621 int flags =
622 MHD_USE_DEBUG |
623 MHD_USE_PEDANTIC_CHECKS |
624 MHD_USE_EPOLL_LINUX_ONLY |
625 MHD_USE_DUAL_STACK;
626
627 const union MHD_DaemonInfo *info;
628 int r, epoll_fd;
629 MHDDaemonWrapper *d;
630
631 assert(fd >= 0);
632
633 r = fd_nonblock(fd, true);
634 if (r < 0) {
635 log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
636 return r;
637 }
638
639 if (key) {
640 assert(cert);
641
642 opts[opts_pos++] = (struct MHD_OptionItem)
643 {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
644 opts[opts_pos++] = (struct MHD_OptionItem)
645 {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
646
647 flags |= MHD_USE_SSL;
648
649 if (trust)
650 opts[opts_pos++] = (struct MHD_OptionItem)
651 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
652 }
653
654 d = new(MHDDaemonWrapper, 1);
655 if (!d)
656 return log_oom();
657
658 d->fd = (uint64_t) fd;
659
660 d->daemon = MHD_start_daemon(flags, 0,
661 NULL, NULL,
662 request_handler, NULL,
663 MHD_OPTION_ARRAY, opts,
664 MHD_OPTION_END);
665 if (!d->daemon) {
666 log_error("Failed to start µhttp daemon");
667 r = -EINVAL;
668 goto error;
669 }
670
671 log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
672 key ? "HTTPS" : "HTTP", fd, d);
673
674
675 info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
676 if (!info) {
677 log_error("µhttp returned NULL daemon info");
678 r = -ENOTSUP;
679 goto error;
680 }
681
682 epoll_fd = info->listen_fd;
683 if (epoll_fd < 0) {
684 log_error("µhttp epoll fd is invalid");
685 r = -EUCLEAN;
686 goto error;
687 }
688
689 r = sd_event_add_io(s->events, &d->event,
690 epoll_fd, EPOLLIN,
691 dispatch_http_event, d);
692 if (r < 0) {
693 log_error("Failed to add event callback: %s", strerror(-r));
694 goto error;
695 }
696
697 r = hashmap_ensure_allocated(&s->daemons, uint64_hash_func, uint64_compare_func);
698 if (r < 0) {
699 log_oom();
700 goto error;
701 }
702
703 r = hashmap_put(s->daemons, &d->fd, d);
704 if (r < 0) {
705 log_error("Failed to add daemon to hashmap: %s", strerror(-r));
706 goto error;
707 }
708
709 s->active ++;
710 return 0;
711
712 error:
713 MHD_stop_daemon(d->daemon);
714 free(d->daemon);
715 free(d);
716 return r;
717 }
718
719 static int setup_microhttpd_socket(RemoteServer *s,
720 const char *address,
721 const char *key,
722 const char *cert,
723 const char *trust) {
724 int fd;
725
726 fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
727 if (fd < 0)
728 return fd;
729
730 return setup_microhttpd_server(s, fd, key, cert, trust);
731 }
732
733 static int dispatch_http_event(sd_event_source *event,
734 int fd,
735 uint32_t revents,
736 void *userdata) {
737 MHDDaemonWrapper *d = userdata;
738 int r;
739
740 assert(d);
741
742 r = MHD_run(d->daemon);
743 if (r == MHD_NO) {
744 log_error("MHD_run failed!");
745 // XXX: unregister daemon
746 return -EINVAL;
747 }
748
749 return 1; /* work to do */
750 }
751
752 /**********************************************************************
753 **********************************************************************
754 **********************************************************************/
755
756 static int dispatch_sigterm(sd_event_source *event,
757 const struct signalfd_siginfo *si,
758 void *userdata) {
759 RemoteServer *s = userdata;
760
761 assert(s);
762
763 log_received_signal(LOG_INFO, si);
764
765 sd_event_exit(s->events, 0);
766 return 0;
767 }
768
769 static int setup_signals(RemoteServer *s) {
770 sigset_t mask;
771 int r;
772
773 assert(s);
774
775 assert_se(sigemptyset(&mask) == 0);
776 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
777 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
778
779 r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, dispatch_sigterm, s);
780 if (r < 0)
781 return r;
782
783 r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, dispatch_sigterm, s);
784 if (r < 0)
785 return r;
786
787 return 0;
788 }
789
790 static int fd_fd(const char *spec) {
791 int fd, r;
792
793 r = safe_atoi(spec, &fd);
794 if (r < 0)
795 return r;
796
797 return -1;
798 }
799
800
801 static int remoteserver_init(RemoteServer *s,
802 const char* key,
803 const char* cert,
804 const char* trust) {
805 int r, n, fd;
806 char **file;
807
808 assert(s);
809
810
811 if ((arg_listen_raw || arg_listen_http) && trust) {
812 log_error("Option --trust makes all non-HTTPS connections untrusted.");
813 return -EINVAL;
814 }
815
816 sd_event_default(&s->events);
817
818 setup_signals(s);
819
820 assert(server == NULL);
821 server = s;
822
823 n = sd_listen_fds(true);
824 if (n < 0) {
825 log_error("Failed to read listening file descriptors from environment: %s",
826 strerror(-n));
827 return n;
828 } else
829 log_info("Received %d descriptors", n);
830
831 if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
832 log_error("Received fewer sockets than expected");
833 return -EBADFD;
834 }
835
836 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
837 if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
838 log_info("Received a listening socket (fd:%d)", fd);
839
840 if (fd == http_socket)
841 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
842 else if (fd == https_socket)
843 r = setup_microhttpd_server(s, fd, key, cert, trust);
844 else
845 r = add_raw_socket(s, fd);
846 } else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
847 char *hostname;
848
849 r = getnameinfo_pretty(fd, &hostname);
850 if (r < 0) {
851 log_error("Failed to retrieve remote name: %s", strerror(-r));
852 return r;
853 }
854
855 log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
856
857 r = add_source(s, fd, hostname, true);
858 if (r < 0)
859 free(hostname);
860 } else {
861 log_error("Unknown socket passed on fd:%d", fd);
862
863 return -EINVAL;
864 }
865
866 if(r < 0) {
867 log_error("Failed to register socket (fd:%d): %s",
868 fd, strerror(-r));
869 return r;
870 }
871 }
872
873 if (arg_url) {
874 const char *url, *hostname;
875
876 url = strappenda(arg_url, "/entries");
877
878 if (arg_getter) {
879 log_info("Spawning getter %s...", url);
880 fd = spawn_getter(arg_getter, url);
881 } else {
882 log_info("Spawning curl %s...", url);
883 fd = spawn_curl(url);
884 }
885 if (fd < 0)
886 return fd;
887
888 hostname =
889 startswith(arg_url, "https://") ?:
890 startswith(arg_url, "http://") ?:
891 arg_url;
892
893 r = add_source(s, fd, (char*) hostname, false);
894 if (r < 0)
895 return r;
896 }
897
898 if (arg_listen_raw) {
899 log_info("Listening on a socket...");
900 r = setup_raw_socket(s, arg_listen_raw);
901 if (r < 0)
902 return r;
903 }
904
905 if (arg_listen_http) {
906 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
907 if (r < 0)
908 return r;
909 }
910
911 if (arg_listen_https) {
912 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
913 if (r < 0)
914 return r;
915 }
916
917 STRV_FOREACH(file, arg_files) {
918 const char *output_name;
919
920 if (streq(*file, "-")) {
921 log_info("Using standard input as source.");
922
923 fd = STDIN_FILENO;
924 output_name = "stdin";
925 } else {
926 log_info("Reading file %s...", *file);
927
928 fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
929 if (fd < 0) {
930 log_error("Failed to open %s: %m", *file);
931 return -errno;
932 }
933 output_name = *file;
934 }
935
936 r = add_source(s, fd, (char*) output_name, false);
937 if (r < 0)
938 return r;
939 }
940
941 if (s->active == 0) {
942 log_error("Zarro sources specified");
943 return -EINVAL;
944 }
945
946 r = init_writer_hashmap(s);
947 if (r < 0)
948 return r;
949
950 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
951 /* In this case we know what the writer will be
952 called, so we can create it and verify that we can
953 create output as expected. */
954 r = get_writer(s, NULL, &s->_single_writer);
955 if (r < 0)
956 return r;
957 }
958
959 return 0;
960 }
961
962 static void server_destroy(RemoteServer *s) {
963 size_t i;
964 MHDDaemonWrapper *d;
965
966 while ((d = hashmap_steal_first(s->daemons))) {
967 MHD_stop_daemon(d->daemon);
968 sd_event_source_unref(d->event);
969 free(d);
970 }
971
972 hashmap_free(s->daemons);
973
974 assert(s->sources_size == 0 || s->sources);
975 for (i = 0; i < s->sources_size; i++)
976 remove_source(s, i);
977 free(s->sources);
978
979 writer_unref(s->_single_writer);
980 hashmap_free(s->writers);
981
982 sd_event_source_unref(s->sigterm_event);
983 sd_event_source_unref(s->sigint_event);
984 sd_event_source_unref(s->listen_event);
985 sd_event_unref(s->events);
986
987 /* fds that we're listening on remain open... */
988 }
989
990 /**********************************************************************
991 **********************************************************************
992 **********************************************************************/
993
994 static int dispatch_raw_source_event(sd_event_source *event,
995 int fd,
996 uint32_t revents,
997 void *userdata) {
998
999 RemoteServer *s = userdata;
1000 RemoteSource *source;
1001 int r;
1002
1003 assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1004 source = s->sources[fd];
1005 assert(source->fd == fd);
1006
1007 r = process_source(source, arg_compress, arg_seal);
1008 if (source->state == STATE_EOF) {
1009 size_t remaining;
1010
1011 log_info("EOF reached with source fd:%d (%s)",
1012 source->fd, source->name);
1013
1014 remaining = source_non_empty(source);
1015 if (remaining > 0)
1016 log_warning("Premature EOF. %zu bytes lost.", remaining);
1017 remove_source(s, source->fd);
1018 log_info("%zd active sources remaining", s->active);
1019 return 0;
1020 } else if (r == -E2BIG) {
1021 log_error("Entry too big, skipped");
1022 return 1;
1023 } else if (r == -EAGAIN) {
1024 return 0;
1025 } else if (r < 0) {
1026 log_info("Closing connection: %s", strerror(-r));
1027 remove_source(server, fd);
1028 return 0;
1029 } else
1030 return 1;
1031 }
1032
1033 static int accept_connection(const char* type, int fd,
1034 SocketAddress *addr, char **hostname) {
1035 int fd2, r;
1036
1037 log_debug("Accepting new %s connection on fd:%d", type, fd);
1038 fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1039 if (fd2 < 0) {
1040 log_error("accept() on fd:%d failed: %m", fd);
1041 return -errno;
1042 }
1043
1044 switch(socket_address_family(addr)) {
1045 case AF_INET:
1046 case AF_INET6: {
1047 _cleanup_free_ char *a = NULL;
1048 char *b;
1049
1050 r = socket_address_print(addr, &a);
1051 if (r < 0) {
1052 log_error("socket_address_print(): %s", strerror(-r));
1053 close(fd2);
1054 return r;
1055 }
1056
1057 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1058 if (r < 0) {
1059 close(fd2);
1060 return r;
1061 }
1062
1063 log_info("Accepted %s %s connection from %s",
1064 type,
1065 socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1066 a);
1067
1068 *hostname = b;
1069
1070 return fd2;
1071 };
1072 default:
1073 log_error("Rejected %s connection with unsupported family %d",
1074 type, socket_address_family(addr));
1075 close(fd2);
1076
1077 return -EINVAL;
1078 }
1079 }
1080
1081 static int dispatch_raw_connection_event(sd_event_source *event,
1082 int fd,
1083 uint32_t revents,
1084 void *userdata) {
1085 RemoteServer *s = userdata;
1086 int fd2, r;
1087 SocketAddress addr = {
1088 .size = sizeof(union sockaddr_union),
1089 .type = SOCK_STREAM,
1090 };
1091 char *hostname;
1092
1093 fd2 = accept_connection("raw", fd, &addr, &hostname);
1094 if (fd2 < 0)
1095 return fd2;
1096
1097 r = add_source(s, fd2, hostname, true);
1098 if (r < 0)
1099 free(hostname);
1100 return r;
1101 }
1102
1103 /**********************************************************************
1104 **********************************************************************
1105 **********************************************************************/
1106
1107 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1108 [JOURNAL_WRITE_SPLIT_NONE] = "none",
1109 [JOURNAL_WRITE_SPLIT_HOST] = "host",
1110 };
1111
1112 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1113 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1114 journal_write_split_mode,
1115 JournalWriteSplitMode,
1116 "Failed to parse split mode setting");
1117
1118 static int parse_config(void) {
1119 const ConfigTableItem items[] = {
1120 { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
1121 { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
1122 { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
1123 { "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
1124 {}};
1125 int r;
1126
1127 r = config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
1128 "Remote\0",
1129 config_item_table_lookup, items,
1130 false, false, NULL);
1131 if (r < 0)
1132 log_error("Failed to parse configuration file: %s", strerror(-r));
1133
1134 return r;
1135 }
1136
1137 static void help(void) {
1138 printf("%s [OPTIONS...] {FILE|-}...\n\n"
1139 "Write external journal events to journal file(s).\n\n"
1140 "Options:\n"
1141 " --url=URL Read events from systemd-journal-gatewayd at URL\n"
1142 " --getter=COMMAND Read events from the output of COMMAND\n"
1143 " --listen-raw=ADDR Listen for connections at ADDR\n"
1144 " --listen-http=ADDR Listen for HTTP connections at ADDR\n"
1145 " --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
1146 " -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1147 " --[no-]compress Use XZ-compression in the output journal (default: yes)\n"
1148 " --[no-]seal Use Event sealing in the output journal (default: no)\n"
1149 " --key=FILENAME Specify key in PEM format (default:\n"
1150 " \"" KEY_FILE "\")\n"
1151 " --cert=FILENAME Specify certificate in PEM format (default:\n"
1152 " \"" CERT_FILE "\")\n"
1153 " --trust=FILENAME|all Specify CA certificate or disable checking (default:\n"
1154 " \"" TRUST_FILE "\")\n"
1155 " --gnutls-log=CATEGORY...\n"
1156 " Specify a list of gnutls logging categories\n"
1157 " -h --help Show this help and exit\n"
1158 " --version Print version string and exit\n"
1159 "\n"
1160 "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1161 , program_invocation_short_name);
1162 }
1163
1164 static int parse_argv(int argc, char *argv[]) {
1165 enum {
1166 ARG_VERSION = 0x100,
1167 ARG_URL,
1168 ARG_LISTEN_RAW,
1169 ARG_LISTEN_HTTP,
1170 ARG_LISTEN_HTTPS,
1171 ARG_GETTER,
1172 ARG_SPLIT_MODE,
1173 ARG_COMPRESS,
1174 ARG_NO_COMPRESS,
1175 ARG_SEAL,
1176 ARG_NO_SEAL,
1177 ARG_KEY,
1178 ARG_CERT,
1179 ARG_TRUST,
1180 ARG_GNUTLS_LOG,
1181 };
1182
1183 static const struct option options[] = {
1184 { "help", no_argument, NULL, 'h' },
1185 { "version", no_argument, NULL, ARG_VERSION },
1186 { "url", required_argument, NULL, ARG_URL },
1187 { "getter", required_argument, NULL, ARG_GETTER },
1188 { "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
1189 { "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
1190 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1191 { "output", required_argument, NULL, 'o' },
1192 { "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
1193 { "compress", no_argument, NULL, ARG_COMPRESS },
1194 { "no-compress", no_argument, NULL, ARG_NO_COMPRESS },
1195 { "seal", no_argument, NULL, ARG_SEAL },
1196 { "no-seal", no_argument, NULL, ARG_NO_SEAL },
1197 { "key", required_argument, NULL, ARG_KEY },
1198 { "cert", required_argument, NULL, ARG_CERT },
1199 { "trust", required_argument, NULL, ARG_TRUST },
1200 { "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
1201 {}
1202 };
1203
1204 int c, r;
1205 bool type_a, type_b;
1206
1207 assert(argc >= 0);
1208 assert(argv);
1209
1210 while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1211 switch(c) {
1212 case 'h':
1213 help();
1214 return 0 /* done */;
1215
1216 case ARG_VERSION:
1217 puts(PACKAGE_STRING);
1218 puts(SYSTEMD_FEATURES);
1219 return 0 /* done */;
1220
1221 case ARG_URL:
1222 if (arg_url) {
1223 log_error("cannot currently set more than one --url");
1224 return -EINVAL;
1225 }
1226
1227 arg_url = optarg;
1228 break;
1229
1230 case ARG_GETTER:
1231 if (arg_getter) {
1232 log_error("cannot currently use --getter more than once");
1233 return -EINVAL;
1234 }
1235
1236 arg_getter = optarg;
1237 break;
1238
1239 case ARG_LISTEN_RAW:
1240 if (arg_listen_raw) {
1241 log_error("cannot currently use --listen-raw more than once");
1242 return -EINVAL;
1243 }
1244
1245 arg_listen_raw = optarg;
1246 break;
1247
1248 case ARG_LISTEN_HTTP:
1249 if (arg_listen_http || http_socket >= 0) {
1250 log_error("cannot currently use --listen-http more than once");
1251 return -EINVAL;
1252 }
1253
1254 r = fd_fd(optarg);
1255 if (r >= 0)
1256 http_socket = r;
1257 else
1258 arg_listen_http = optarg;
1259 break;
1260
1261 case ARG_LISTEN_HTTPS:
1262 if (arg_listen_https || https_socket >= 0) {
1263 log_error("cannot currently use --listen-https more than once");
1264 return -EINVAL;
1265 }
1266
1267 r = fd_fd(optarg);
1268 if (r >= 0)
1269 https_socket = r;
1270 else
1271 arg_listen_https = optarg;
1272
1273 break;
1274
1275 case ARG_KEY:
1276 if (arg_key) {
1277 log_error("Key file specified twice");
1278 return -EINVAL;
1279 }
1280
1281 arg_key = strdup(optarg);
1282 if (!arg_key)
1283 return log_oom();
1284
1285 break;
1286
1287 case ARG_CERT:
1288 if (arg_cert) {
1289 log_error("Certificate file specified twice");
1290 return -EINVAL;
1291 }
1292
1293 arg_cert = strdup(optarg);
1294 if (!arg_cert)
1295 return log_oom();
1296
1297 break;
1298
1299 case ARG_TRUST:
1300 if (arg_trust || arg_trust_all) {
1301 log_error("Confusing trusted CA configuration");
1302 return -EINVAL;
1303 }
1304
1305 if (streq(optarg, "all"))
1306 arg_trust_all = true;
1307 else {
1308 #ifdef HAVE_GNUTLS
1309 arg_trust = strdup(optarg);
1310 if (!arg_trust)
1311 return log_oom();
1312 #else
1313 log_error("Option --trust is not available.");
1314 return -EINVAL;
1315 #endif
1316 }
1317
1318 break;
1319
1320 case 'o':
1321 if (arg_output) {
1322 log_error("cannot use --output/-o more than once");
1323 return -EINVAL;
1324 }
1325
1326 arg_output = optarg;
1327 break;
1328
1329 case ARG_SPLIT_MODE:
1330 arg_split_mode = journal_write_split_mode_from_string(optarg);
1331 if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1332 log_error("Invalid split mode: %s", optarg);
1333 return -EINVAL;
1334 }
1335 break;
1336
1337 case ARG_COMPRESS:
1338 arg_compress = true;
1339 break;
1340 case ARG_NO_COMPRESS:
1341 arg_compress = false;
1342 break;
1343 case ARG_SEAL:
1344 arg_seal = true;
1345 break;
1346 case ARG_NO_SEAL:
1347 arg_seal = false;
1348 break;
1349
1350 case ARG_GNUTLS_LOG: {
1351 #ifdef HAVE_GNUTLS
1352 char *word, *state;
1353 size_t size;
1354
1355 FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1356 char *cat;
1357
1358 cat = strndup(word, size);
1359 if (!cat)
1360 return log_oom();
1361
1362 if (strv_consume(&arg_gnutls_log, cat) < 0)
1363 return log_oom();
1364 }
1365 break;
1366 #else
1367 log_error("Option --gnutls-log is not available.");
1368 return -EINVAL;
1369 #endif
1370 }
1371
1372 case '?':
1373 return -EINVAL;
1374
1375 default:
1376 log_error("Unknown option code %c", c);
1377 return -EINVAL;
1378 }
1379
1380 if (optind < argc)
1381 arg_files = argv + optind;
1382
1383 type_a = arg_getter || !strv_isempty(arg_files);
1384 type_b = arg_url
1385 || arg_listen_raw
1386 || arg_listen_http || arg_listen_https
1387 || sd_listen_fds(false) > 0;
1388 if (type_a && type_b) {
1389 log_error("Cannot use file input or --getter with "
1390 "--arg-listen-... or socket activation.");
1391 return -EINVAL;
1392 }
1393 if (type_a) {
1394 if (!arg_output) {
1395 log_error("Option --output must be specified with file input or --getter.");
1396 return -EINVAL;
1397 }
1398
1399 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1400 }
1401
1402 if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1403 && arg_output && is_dir(arg_output, true) > 0) {
1404 log_error("For SplitMode=none, output must be a file.");
1405 return -EINVAL;
1406 }
1407
1408 if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1409 && arg_output && is_dir(arg_output, true) <= 0) {
1410 log_error("For SplitMode=host, output must be a directory.");
1411 return -EINVAL;
1412 }
1413
1414 log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1415 journal_write_split_mode_to_string(arg_split_mode),
1416 strna(arg_key),
1417 strna(arg_cert),
1418 strna(arg_trust));
1419
1420 return 1 /* work to do */;
1421 }
1422
1423 static int load_certificates(char **key, char **cert, char **trust) {
1424 int r;
1425
1426 r = read_full_file(arg_key ?: KEY_FILE, key, NULL);
1427 if (r < 0) {
1428 log_error("Failed to read key from file '%s': %s",
1429 arg_key ?: KEY_FILE, strerror(-r));
1430 return r;
1431 }
1432
1433 r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1434 if (r < 0) {
1435 log_error("Failed to read certificate from file '%s': %s",
1436 arg_cert ?: CERT_FILE, strerror(-r));
1437 return r;
1438 }
1439
1440 if (arg_trust_all)
1441 log_info("Certificate checking disabled.");
1442 else {
1443 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1444 if (r < 0) {
1445 log_error("Failed to read CA certificate file '%s': %s",
1446 arg_trust ?: TRUST_FILE, strerror(-r));
1447 return r;
1448 }
1449 }
1450
1451 return 0;
1452 }
1453
1454 static int setup_gnutls_logger(char **categories) {
1455 if (!arg_listen_http && !arg_listen_https)
1456 return 0;
1457
1458 #ifdef HAVE_GNUTLS
1459 {
1460 char **cat;
1461 int r;
1462
1463 gnutls_global_set_log_function(log_func_gnutls);
1464
1465 if (categories)
1466 STRV_FOREACH(cat, categories) {
1467 r = log_enable_gnutls_category(*cat);
1468 if (r < 0)
1469 return r;
1470 }
1471 else
1472 log_reset_gnutls_level();
1473 }
1474 #endif
1475
1476 return 0;
1477 }
1478
1479 int main(int argc, char **argv) {
1480 RemoteServer s = {};
1481 int r;
1482 _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1483
1484 log_show_color(true);
1485 log_parse_environment();
1486
1487 r = parse_config();
1488 if (r < 0)
1489 return EXIT_FAILURE;
1490
1491 r = parse_argv(argc, argv);
1492 if (r <= 0)
1493 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1494
1495 r = setup_gnutls_logger(arg_gnutls_log);
1496 if (r < 0)
1497 return EXIT_FAILURE;
1498
1499 if (arg_listen_https || https_socket >= 0)
1500 if (load_certificates(&key, &cert, &trust) < 0)
1501 return EXIT_FAILURE;
1502
1503 if (remoteserver_init(&s, key, cert, trust) < 0)
1504 return EXIT_FAILURE;
1505
1506 sd_event_set_watchdog(s.events, true);
1507
1508 log_debug("%s running as pid "PID_FMT,
1509 program_invocation_short_name, getpid());
1510 sd_notify(false,
1511 "READY=1\n"
1512 "STATUS=Processing requests...");
1513
1514 while (s.active) {
1515 r = sd_event_get_state(s.events);
1516 if (r < 0)
1517 break;
1518 if (r == SD_EVENT_FINISHED)
1519 break;
1520
1521 r = sd_event_run(s.events, -1);
1522 if (r < 0) {
1523 log_error("Failed to run event loop: %s", strerror(-r));
1524 break;
1525 }
1526 }
1527
1528 server_destroy(&s);
1529 log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1530
1531 sd_notify(false, "STATUS=Shutting down...");
1532
1533 free(arg_key);
1534 free(arg_cert);
1535 free(arg_trust);
1536
1537 return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1538 }