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