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