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