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