chiark / gitweb /
Allow addresses to be specified for --listen-... args
[elogind.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 <inttypes.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/prctl.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <getopt.h>
34
35 #include "sd-daemon.h"
36 #include "sd-event.h"
37 #include "journal-file.h"
38 #include "journald-native.h"
39 #include "socket-util.h"
40 #include "mkdir.h"
41 #include "build.h"
42 #include "macro.h"
43 #include "strv.h"
44 #include "fileio.h"
45 #include "conf-parser.h"
46 #include "microhttpd-util.h"
47
48 #ifdef HAVE_GNUTLS
49 #include <gnutls/gnutls.h>
50 #endif
51
52 #include "journal-remote-parse.h"
53 #include "journal-remote-write.h"
54
55 #define REMOTE_JOURNAL_PATH "/var/log/journal/" SD_ID128_FORMAT_STR "/remote-%s.journal"
56
57 #define KEY_FILE   CERTIFICATE_ROOT "/private/journal-remote.pem"
58 #define CERT_FILE  CERTIFICATE_ROOT "/certs/journal-remote.pem"
59 #define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
60
61 static char* arg_output = NULL;
62 static char* arg_url = NULL;
63 static char* arg_getter = NULL;
64 static char* arg_listen_raw = NULL;
65 static char* arg_listen_http = NULL;
66 static char* arg_listen_https = NULL;
67 static char** arg_files = NULL;
68 static int arg_compress = true;
69 static int arg_seal = false;
70 static int http_socket = -1, https_socket = -1;
71 static char** arg_gnutls_log = 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(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(char *getter, char *url) {
148         int r;
149         _cleanup_strv_free_ char **words = NULL;
150
151         assert(getter);
152         words = strv_split_quoted(getter);
153         if (!words)
154                 return log_oom();
155
156         r = spawn_child(words[0], words);
157         if (r < 0)
158                 log_error("Failed to spawn getter %s: %m", getter);
159
160         return r;
161 }
162
163 static int open_output(Writer *s, const char* url) {
164         _cleanup_free_ char *name, *output = NULL;
165         char *c;
166         int r;
167
168         assert(url);
169         name = strdup(url);
170         if (!name)
171                 return log_oom();
172
173         for(c = name; *c; c++) {
174                 if (*c == '/' || *c == ':' || *c == ' ')
175                         *c = '~';
176                 else if (*c == '?') {
177                         *c = '\0';
178                         break;
179                 }
180         }
181
182         if (!arg_output) {
183                 sd_id128_t machine;
184                 r = sd_id128_get_machine(&machine);
185                 if (r < 0) {
186                         log_error("failed to determine machine ID128: %s", strerror(-r));
187                         return r;
188                 }
189
190                 r = asprintf(&output, REMOTE_JOURNAL_PATH,
191                              SD_ID128_FORMAT_VAL(machine), name);
192                 if (r < 0)
193                         return log_oom();
194         } else {
195                 r = is_dir(arg_output, true);
196                 if (r > 0) {
197                         r = asprintf(&output,
198                                      "%s/remote-%s.journal", arg_output, name);
199                         if (r < 0)
200                                 return log_oom();
201                 } else {
202                         output = strdup(arg_output);
203                         if (!output)
204                                 return log_oom();
205                 }
206         }
207
208         r = journal_file_open_reliably(output,
209                                        O_RDWR|O_CREAT, 0640,
210                                        arg_compress, arg_seal,
211                                        &s->metrics,
212                                        s->mmap,
213                                        NULL, &s->journal);
214         if (r < 0)
215                 log_error("Failed to open output journal %s: %s",
216                           arg_output, strerror(-r));
217         else
218                 log_info("Opened output file %s", s->journal->path);
219         return r;
220 }
221
222 /**********************************************************************
223  **********************************************************************
224  **********************************************************************/
225
226 typedef struct MHDDaemonWrapper {
227         uint64_t fd;
228         struct MHD_Daemon *daemon;
229
230         sd_event_source *event;
231 } MHDDaemonWrapper;
232
233 typedef struct RemoteServer {
234         RemoteSource **sources;
235         size_t sources_size;
236         size_t active;
237
238         sd_event *events;
239         sd_event_source *sigterm_event, *sigint_event, *listen_event;
240
241         Writer writer;
242
243         bool check_trust;
244         Hashmap *daemons;
245 } RemoteServer;
246
247 /* This should go away as soon as Âµhttpd allows state to be passed around. */
248 static RemoteServer *server;
249
250 static int dispatch_raw_source_event(sd_event_source *event,
251                                      int fd,
252                                      uint32_t revents,
253                                      void *userdata);
254 static int dispatch_raw_connection_event(sd_event_source *event,
255                                          int fd,
256                                          uint32_t revents,
257                                          void *userdata);
258 static int dispatch_http_event(sd_event_source *event,
259                                int fd,
260                                uint32_t revents,
261                                void *userdata);
262
263 static int get_source_for_fd(RemoteServer *s, int fd, RemoteSource **source) {
264         assert(fd >= 0);
265         assert(source);
266
267         if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
268                 return log_oom();
269
270         if (s->sources[fd] == NULL) {
271                 s->sources[fd] = new0(RemoteSource, 1);
272                 if (!s->sources[fd])
273                         return log_oom();
274                 s->sources[fd]->fd = -1;
275                 s->active++;
276         }
277
278         *source = s->sources[fd];
279         return 0;
280 }
281
282 static int remove_source(RemoteServer *s, int fd) {
283         RemoteSource *source;
284
285         assert(s);
286         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
287
288         source = s->sources[fd];
289         if (source) {
290                 source_free(source);
291                 s->sources[fd] = NULL;
292                 s->active--;
293         }
294
295         close(fd);
296
297         return 0;
298 }
299
300 static int add_source(RemoteServer *s, int fd, const char* name) {
301         RemoteSource *source = NULL;
302         _cleanup_free_ char *realname = NULL;
303         int r;
304
305         assert(s);
306         assert(fd >= 0);
307
308         if (name) {
309                 realname = strdup(name);
310                 if (!realname)
311                         return log_oom();
312         } else {
313                 r = asprintf(&realname, "fd:%d", fd);
314                 if (r < 0)
315                         return log_oom();
316         }
317
318         log_debug("Creating source for fd:%d (%s)", fd, realname);
319
320         r = get_source_for_fd(s, fd, &source);
321         if (r < 0) {
322                 log_error("Failed to create source for fd:%d (%s)", fd, realname);
323                 return r;
324         }
325         assert(source);
326         assert(source->fd < 0);
327         source->fd = fd;
328
329         r = sd_event_add_io(s->events, &source->event,
330                             fd, EPOLLIN, dispatch_raw_source_event, s);
331         if (r < 0) {
332                 log_error("Failed to register event source for fd:%d: %s",
333                           fd, strerror(-r));
334                 goto error;
335         }
336
337         return 1; /* work to do */
338
339  error:
340         remove_source(s, fd);
341         return r;
342 }
343
344 static int add_raw_socket(RemoteServer *s, int fd) {
345         int r;
346
347         r = sd_event_add_io(s->events, &s->listen_event, fd, EPOLLIN,
348                             dispatch_raw_connection_event, s);
349         if (r < 0) {
350                 close(fd);
351                 return r;
352         }
353
354         s->active ++;
355         return 0;
356 }
357
358 static int setup_raw_socket(RemoteServer *s, const char *address) {
359         int fd;
360
361         fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
362         if (fd < 0)
363                 return fd;
364
365         return add_raw_socket(s, fd);
366 }
367
368 /**********************************************************************
369  **********************************************************************
370  **********************************************************************/
371
372 static RemoteSource *request_meta(void **connection_cls) {
373         RemoteSource *source;
374
375         assert(connection_cls);
376         if (*connection_cls)
377                 return *connection_cls;
378
379         source = new0(RemoteSource, 1);
380         if (!source)
381                 return NULL;
382         source->fd = -1;
383
384         log_debug("Added RemoteSource as connection metadata %p", source);
385
386         *connection_cls = source;
387         return source;
388 }
389
390 static void request_meta_free(void *cls,
391                               struct MHD_Connection *connection,
392                               void **connection_cls,
393                               enum MHD_RequestTerminationCode toe) {
394         RemoteSource *s;
395
396         assert(connection_cls);
397         s = *connection_cls;
398
399         log_debug("Cleaning up connection metadata %p", s);
400         source_free(s);
401         *connection_cls = NULL;
402 }
403
404 static int process_http_upload(
405                 struct MHD_Connection *connection,
406                 const char *upload_data,
407                 size_t *upload_data_size,
408                 RemoteSource *source) {
409
410         bool finished = false;
411         int r;
412
413         assert(source);
414
415         log_debug("request_handler_upload: connection %p, %zu bytes",
416                   connection, *upload_data_size);
417
418         if (*upload_data_size) {
419                 log_info("Received %zu bytes", *upload_data_size);
420
421                 r = push_data(source, upload_data, *upload_data_size);
422                 if (r < 0)
423                         return mhd_respond_oom(connection);
424
425                 *upload_data_size = 0;
426         } else
427                 finished = true;
428
429         while (true) {
430                 r = process_source(source, &server->writer, arg_compress, arg_seal);
431                 if (r == -EAGAIN || r == -EWOULDBLOCK)
432                         break;
433                 else if (r < 0) {
434                         log_warning("Failed to process data for connection %p", connection);
435                         if (r == -E2BIG)
436                                 return mhd_respondf(connection,
437                                                     MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
438                                                     "Entry is too large, maximum is %u bytes.\n",
439                                                     DATA_SIZE_MAX);
440                         else
441                                 return mhd_respondf(connection,
442                                                     MHD_HTTP_UNPROCESSABLE_ENTITY,
443                                                     "Processing failed: %s.", strerror(-r));
444                 }
445         }
446
447         if (!finished)
448                 return MHD_YES;
449
450         /* The upload is finished */
451
452         if (source_non_empty(source)) {
453                 log_warning("EOF reached with incomplete data");
454                 return mhd_respond(connection, MHD_HTTP_EXPECTATION_FAILED,
455                                    "Trailing data not processed.");
456         }
457
458         return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
459 };
460
461 static int request_handler(
462                 void *cls,
463                 struct MHD_Connection *connection,
464                 const char *url,
465                 const char *method,
466                 const char *version,
467                 const char *upload_data,
468                 size_t *upload_data_size,
469                 void **connection_cls) {
470
471         const char *header;
472         int r ,code;
473
474         assert(connection);
475         assert(connection_cls);
476         assert(url);
477         assert(method);
478
479         log_debug("Handling a connection %s %s %s", method, url, version);
480
481         if (*connection_cls)
482                 return process_http_upload(connection,
483                                            upload_data, upload_data_size,
484                                            *connection_cls);
485
486         if (!streq(method, "POST"))
487                 return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
488                                    "Unsupported method.\n");
489
490         if (!streq(url, "/upload"))
491                 return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
492                                    "Not found.\n");
493
494         header = MHD_lookup_connection_value(connection,
495                                              MHD_HEADER_KIND, "Content-Type");
496         if (!header || !streq(header, "application/vnd.fdo.journal"))
497                 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
498                                    "Content-Type: application/vnd.fdo.journal"
499                                    " is required.\n");
500
501         if (server->check_trust) {
502                 r = check_permissions(connection, &code);
503                 if (r < 0)
504                         return code;
505         }
506
507         if (!request_meta(connection_cls))
508                 return respond_oom(connection);
509         return MHD_YES;
510 }
511
512 static int setup_microhttpd_server(RemoteServer *s,
513                                    int fd,
514                                    const char *key,
515                                    const char *cert,
516                                    const char *trust) {
517         struct MHD_OptionItem opts[] = {
518                 { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
519                 { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
520                 { MHD_OPTION_LISTEN_SOCKET, fd},
521                 { MHD_OPTION_END},
522                 { MHD_OPTION_END},
523                 { MHD_OPTION_END},
524                 { MHD_OPTION_END}};
525         int opts_pos = 3;
526         int flags =
527                 MHD_USE_DEBUG |
528                 MHD_USE_PEDANTIC_CHECKS |
529                 MHD_USE_EPOLL_LINUX_ONLY |
530                 MHD_USE_DUAL_STACK;
531
532         const union MHD_DaemonInfo *info;
533         int r, epoll_fd;
534         MHDDaemonWrapper *d;
535
536         assert(fd >= 0);
537
538         r = fd_nonblock(fd, true);
539         if (r < 0) {
540                 log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
541                 return r;
542         }
543
544         if (key) {
545                 assert(cert);
546
547                 opts[opts_pos++] = (struct MHD_OptionItem)
548                         {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
549                 opts[opts_pos++] = (struct MHD_OptionItem)
550                         {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
551
552                 flags |= MHD_USE_SSL;
553
554                 if (trust)
555                         opts[opts_pos++] = (struct MHD_OptionItem)
556                                 {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
557         }
558
559         d = new(MHDDaemonWrapper, 1);
560         if (!d)
561                 return log_oom();
562
563         d->fd = (uint64_t) fd;
564
565         d->daemon = MHD_start_daemon(flags, 0,
566                                      NULL, NULL,
567                                      request_handler, NULL,
568                                      MHD_OPTION_ARRAY, opts,
569                                      MHD_OPTION_END);
570         if (!d->daemon) {
571                 log_error("Failed to start Âµhttp daemon");
572                 r = -EINVAL;
573                 goto error;
574         }
575
576         log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
577                   key ? "HTTPS" : "HTTP", fd, d);
578
579
580         info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
581         if (!info) {
582                 log_error("µhttp returned NULL daemon info");
583                 r = -ENOTSUP;
584                 goto error;
585         }
586
587         epoll_fd = info->listen_fd;
588         if (epoll_fd < 0) {
589                 log_error("µhttp epoll fd is invalid");
590                 r = -EUCLEAN;
591                 goto error;
592         }
593
594         r = sd_event_add_io(s->events, &d->event,
595                             epoll_fd, EPOLLIN, dispatch_http_event, d);
596         if (r < 0) {
597                 log_error("Failed to add event callback: %s", strerror(-r));
598                 goto error;
599         }
600
601         r = hashmap_ensure_allocated(&s->daemons, uint64_hash_func, uint64_compare_func);
602         if (r < 0) {
603                 log_oom();
604                 goto error;
605         }
606
607         r = hashmap_put(s->daemons, &d->fd, d);
608         if (r < 0) {
609                 log_error("Failed to add daemon to hashmap: %s", strerror(-r));
610                 goto error;
611         }
612
613         s->active ++;
614         return 0;
615
616 error:
617         MHD_stop_daemon(d->daemon);
618         free(d->daemon);
619         free(d);
620         return r;
621 }
622
623 static int setup_microhttpd_socket(RemoteServer *s,
624                                    const char *address,
625                                    const char *key,
626                                    const char *cert,
627                                    const char *trust) {
628         int fd;
629
630         fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
631         if (fd < 0)
632                 return fd;
633
634         return setup_microhttpd_server(s, fd, key, cert, trust);
635 }
636
637 static int dispatch_http_event(sd_event_source *event,
638                                int fd,
639                                uint32_t revents,
640                                void *userdata) {
641         MHDDaemonWrapper *d = userdata;
642         int r;
643
644         assert(d);
645
646         r = MHD_run(d->daemon);
647         if (r == MHD_NO) {
648                 log_error("MHD_run failed!");
649                 // XXX: unregister daemon
650                 return -EINVAL;
651         }
652
653         return 1; /* work to do */
654 }
655
656 /**********************************************************************
657  **********************************************************************
658  **********************************************************************/
659
660 static int dispatch_sigterm(sd_event_source *event,
661                             const struct signalfd_siginfo *si,
662                             void *userdata) {
663         RemoteServer *s = userdata;
664
665         assert(s);
666
667         log_received_signal(LOG_INFO, si);
668
669         sd_event_exit(s->events, 0);
670         return 0;
671 }
672
673 static int setup_signals(RemoteServer *s) {
674         sigset_t mask;
675         int r;
676
677         assert(s);
678
679         assert_se(sigemptyset(&mask) == 0);
680         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
681         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
682
683         r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, dispatch_sigterm, s);
684         if (r < 0)
685                 return r;
686
687         r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, dispatch_sigterm, s);
688         if (r < 0)
689                 return r;
690
691         return 0;
692 }
693
694 static int fd_fd(const char *spec) {
695         int fd, r;
696
697         r = safe_atoi(spec, &fd);
698         if (r < 0)
699                 return r;
700
701         return -1;
702 }
703
704
705 static int remoteserver_init(RemoteServer *s,
706                              const char* key,
707                              const char* cert,
708                              const char* trust) {
709         int r, n, fd;
710         const char *output_name = NULL;
711         char **file;
712
713         assert(s);
714
715
716         if ((arg_listen_raw || arg_listen_http) && trust) {
717                 log_error("Option --trust makes all non-HTTPS connections untrusted.");
718                 return -EINVAL;
719         }
720
721         sd_event_default(&s->events);
722
723         setup_signals(s);
724
725         assert(server == NULL);
726         server = s;
727
728         n = sd_listen_fds(true);
729         if (n < 0) {
730                 log_error("Failed to read listening file descriptors from environment: %s",
731                           strerror(-n));
732                 return n;
733         } else
734                 log_info("Received %d descriptors", n);
735
736         if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
737                 log_error("Received fewer sockets than expected");
738                 return -EBADFD;
739         }
740
741         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
742                 if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
743                         log_info("Received a listening socket (fd:%d)", fd);
744
745                         if (fd == http_socket)
746                                 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
747                         else if (fd == https_socket)
748                                 r = setup_microhttpd_server(s, fd, key, cert, trust);
749                         else
750                                 r = add_raw_socket(s, fd);
751                 } else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
752                         log_info("Received a connection socket (fd:%d)", fd);
753
754                         r = add_source(s, fd, NULL);
755                 } else {
756                         log_error("Unknown socket passed on fd:%d", fd);
757
758                         return -EINVAL;
759                 }
760
761                 if(r < 0) {
762                         log_error("Failed to register socket (fd:%d): %s",
763                                   fd, strerror(-r));
764                         return r;
765                 }
766
767                 output_name = "socket";
768         }
769
770         if (arg_url) {
771                 _cleanup_free_ char *url = NULL;
772                 _cleanup_strv_free_ char **urlv = strv_new(arg_url, "/entries", NULL);
773                 if (!urlv)
774                         return log_oom();
775                 url = strv_join(urlv, "");
776                 if (!url)
777                         return log_oom();
778
779                 if (arg_getter) {
780                         log_info("Spawning getter %s...", url);
781                         fd = spawn_getter(arg_getter, url);
782                 } else {
783                         log_info("Spawning curl %s...", url);
784                         fd = spawn_curl(url);
785                 }
786                 if (fd < 0)
787                         return fd;
788
789                 r = add_source(s, fd, arg_url);
790                 if (r < 0)
791                         return r;
792
793                 output_name = arg_url;
794         }
795
796         if (arg_listen_raw) {
797                 log_info("Listening on a socket...");
798                 r = setup_raw_socket(s, arg_listen_raw);
799                 if (r < 0)
800                         return r;
801
802                 output_name = arg_listen_raw;
803         }
804
805         if (arg_listen_http) {
806                 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
807                 if (r < 0)
808                         return r;
809
810                 output_name = arg_listen_http;
811         }
812
813         if (arg_listen_https) {
814                 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
815                 if (r < 0)
816                         return r;
817
818                 output_name = arg_listen_https;
819         }
820
821         STRV_FOREACH(file, arg_files) {
822                 if (streq(*file, "-")) {
823                         log_info("Reading standard input...");
824
825                         fd = STDIN_FILENO;
826                         output_name = "stdin";
827                 } else {
828                         log_info("Reading file %s...", *file);
829
830                         fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
831                         if (fd < 0) {
832                                 log_error("Failed to open %s: %m", *file);
833                                 return -errno;
834                         }
835                         output_name = *file;
836                 }
837
838                 r = add_source(s, fd, output_name);
839                 if (r < 0)
840                         return r;
841         }
842
843         if (s->active == 0) {
844                 log_error("Zarro sources specified");
845                 return -EINVAL;
846         }
847
848         if (!!n + !!arg_url + !!arg_listen_raw + !!arg_files)
849                 output_name = "multiple";
850
851         r = writer_init(&s->writer);
852         if (r < 0)
853                 return r;
854
855         r = open_output(&s->writer, output_name);
856         return r;
857 }
858
859 static int server_destroy(RemoteServer *s) {
860         int r;
861         size_t i;
862         MHDDaemonWrapper *d;
863
864         r = writer_close(&s->writer);
865
866         while ((d = hashmap_steal_first(s->daemons))) {
867                 MHD_stop_daemon(d->daemon);
868                 sd_event_source_unref(d->event);
869                 free(d);
870         }
871
872         hashmap_free(s->daemons);
873
874         assert(s->sources_size == 0 || s->sources);
875         for (i = 0; i < s->sources_size; i++)
876                 remove_source(s, i);
877
878         free(s->sources);
879
880         sd_event_source_unref(s->sigterm_event);
881         sd_event_source_unref(s->sigint_event);
882         sd_event_source_unref(s->listen_event);
883         sd_event_unref(s->events);
884
885         /* fds that we're listening on remain open... */
886
887         return r;
888 }
889
890 /**********************************************************************
891  **********************************************************************
892  **********************************************************************/
893
894 static int dispatch_raw_source_event(sd_event_source *event,
895                                      int fd,
896                                      uint32_t revents,
897                                      void *userdata) {
898
899         RemoteServer *s = userdata;
900         RemoteSource *source;
901         int r;
902
903         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
904         source = s->sources[fd];
905         assert(source->fd == fd);
906
907         r = process_source(source, &s->writer, arg_compress, arg_seal);
908         if (source->state == STATE_EOF) {
909                 log_info("EOF reached with source fd:%d (%s)",
910                          source->fd, source->name);
911                 if (source_non_empty(source))
912                         log_warning("EOF reached with incomplete data");
913                 remove_source(s, source->fd);
914                 log_info("%zd active source remaining", s->active);
915         } else if (r == -E2BIG) {
916                 log_error("Entry too big, skipped");
917                 r = 1;
918         }
919
920         return r;
921 }
922
923 static int accept_connection(const char* type, int fd, SocketAddress *addr) {
924         int fd2, r;
925
926         log_debug("Accepting new %s connection on fd:%d", type, fd);
927         fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
928         if (fd2 < 0) {
929                 log_error("accept() on fd:%d failed: %m", fd);
930                 return -errno;
931         }
932
933         switch(socket_address_family(addr)) {
934         case AF_INET:
935         case AF_INET6: {
936                 char* _cleanup_free_ a = NULL;
937
938                 r = socket_address_print(addr, &a);
939                 if (r < 0) {
940                         log_error("socket_address_print(): %s", strerror(-r));
941                         close(fd2);
942                         return r;
943                 }
944
945                 log_info("Accepted %s %s connection from %s",
946                          type,
947                          socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
948                          a);
949
950                 return fd2;
951         };
952         default:
953                 log_error("Rejected %s connection with unsupported family %d",
954                           type, socket_address_family(addr));
955                 close(fd2);
956
957                 return -EINVAL;
958         }
959 }
960
961 static int dispatch_raw_connection_event(sd_event_source *event,
962                                          int fd,
963                                          uint32_t revents,
964                                          void *userdata) {
965         RemoteServer *s = userdata;
966         int fd2;
967         SocketAddress addr = {
968                 .size = sizeof(union sockaddr_union),
969                 .type = SOCK_STREAM,
970         };
971
972         fd2 = accept_connection("raw", fd, &addr);
973         if (fd2 < 0)
974                 return fd2;
975
976         return add_source(s, fd2, NULL);
977 }
978
979 /**********************************************************************
980  **********************************************************************
981  **********************************************************************/
982
983 static int parse_config(void) {
984         const ConfigTableItem items[] = {
985                 { "Remote",  "ServerKeyFile",          config_parse_path,       0, &arg_key        },
986                 { "Remote",  "ServerCertificateFile",  config_parse_path,       0, &arg_cert       },
987                 { "Remote",  "TrustedCertificateFile", config_parse_path,       0, &arg_trust      },
988                 {}};
989         int r;
990
991         r = config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
992                          "Remote\0",
993                          config_item_table_lookup, items,
994                          false, false, NULL);
995         if (r < 0)
996                 log_error("Failed to parse configuration file: %s", strerror(-r));
997
998         return r;
999 }
1000
1001 static void help(void) {
1002         printf("%s [OPTIONS...] {FILE|-}...\n\n"
1003                "Write external journal events to a journal file.\n\n"
1004                "Options:\n"
1005                "  --url=URL            Read events from systemd-journal-gatewayd at URL\n"
1006                "  --getter=COMMAND     Read events from the output of COMMAND\n"
1007                "  --listen-raw=ADDR    Listen for connections at ADDR\n"
1008                "  --listen-http=ADDR   Listen for HTTP connections at ADDR\n"
1009                "  --listen-https=ADDR  Listen for HTTPS connections at ADDR\n"
1010                "  -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1011                "  --[no-]compress      Use XZ-compression in the output journal (default: yes)\n"
1012                "  --[no-]seal          Use Event sealing in the output journal (default: no)\n"
1013                "  --key=FILENAME       Specify key in PEM format (default:\n"
1014                "                           \"" KEY_FILE "\")\n"
1015                "  --cert=FILENAME      Specify certificate in PEM format (default:\n"
1016                "                           \"" CERT_FILE "\")\n"
1017                "  --trust=FILENAME|all Specify CA certificate or disable checking (default:\n"
1018                "                           \"" TRUST_FILE "\")\n"
1019                "  --gnutls-log=CATEGORY...\n"
1020                "                       Specify a list of gnutls logging categories\n"
1021                "  -h --help            Show this help and exit\n"
1022                "  --version            Print version string and exit\n"
1023                "\n"
1024                "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1025                , program_invocation_short_name);
1026 }
1027
1028 static int parse_argv(int argc, char *argv[]) {
1029         enum {
1030                 ARG_VERSION = 0x100,
1031                 ARG_URL,
1032                 ARG_LISTEN_RAW,
1033                 ARG_LISTEN_HTTP,
1034                 ARG_LISTEN_HTTPS,
1035                 ARG_GETTER,
1036                 ARG_COMPRESS,
1037                 ARG_NO_COMPRESS,
1038                 ARG_SEAL,
1039                 ARG_NO_SEAL,
1040                 ARG_KEY,
1041                 ARG_CERT,
1042                 ARG_TRUST,
1043                 ARG_GNUTLS_LOG,
1044         };
1045
1046         static const struct option options[] = {
1047                 { "help",         no_argument,       NULL, 'h'              },
1048                 { "version",      no_argument,       NULL, ARG_VERSION      },
1049                 { "url",          required_argument, NULL, ARG_URL          },
1050                 { "getter",       required_argument, NULL, ARG_GETTER       },
1051                 { "listen-raw",   required_argument, NULL, ARG_LISTEN_RAW   },
1052                 { "listen-http",  required_argument, NULL, ARG_LISTEN_HTTP  },
1053                 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1054                 { "output",       required_argument, NULL, 'o'              },
1055                 { "compress",     no_argument,       NULL, ARG_COMPRESS     },
1056                 { "no-compress",  no_argument,       NULL, ARG_NO_COMPRESS  },
1057                 { "seal",         no_argument,       NULL, ARG_SEAL         },
1058                 { "no-seal",      no_argument,       NULL, ARG_NO_SEAL      },
1059                 { "key",          required_argument, NULL, ARG_KEY          },
1060                 { "cert",         required_argument, NULL, ARG_CERT         },
1061                 { "trust",        required_argument, NULL, ARG_TRUST        },
1062                 { "gnutls-log",   required_argument, NULL, ARG_GNUTLS_LOG   },
1063                 {}
1064         };
1065
1066         int c, r;
1067
1068         assert(argc >= 0);
1069         assert(argv);
1070
1071         while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1072                 switch(c) {
1073                 case 'h':
1074                         help();
1075                         return 0 /* done */;
1076
1077                 case ARG_VERSION:
1078                         puts(PACKAGE_STRING);
1079                         puts(SYSTEMD_FEATURES);
1080                         return 0 /* done */;
1081
1082                 case ARG_URL:
1083                         if (arg_url) {
1084                                 log_error("cannot currently set more than one --url");
1085                                 return -EINVAL;
1086                         }
1087
1088                         arg_url = optarg;
1089                         break;
1090
1091                 case ARG_GETTER:
1092                         if (arg_getter) {
1093                                 log_error("cannot currently use --getter more than once");
1094                                 return -EINVAL;
1095                         }
1096
1097                         arg_getter = optarg;
1098                         break;
1099
1100                 case ARG_LISTEN_RAW:
1101                         if (arg_listen_raw) {
1102                                 log_error("cannot currently use --listen-raw more than once");
1103                                 return -EINVAL;
1104                         }
1105
1106                         arg_listen_raw = optarg;
1107                         break;
1108
1109                 case ARG_LISTEN_HTTP:
1110                         if (arg_listen_http || http_socket >= 0) {
1111                                 log_error("cannot currently use --listen-http more than once");
1112                                 return -EINVAL;
1113                         }
1114
1115                         r = fd_fd(optarg);
1116                         if (r >= 0)
1117                                 http_socket = r;
1118                         else
1119                                 arg_listen_http = optarg;
1120                         break;
1121
1122                 case ARG_LISTEN_HTTPS:
1123                         if (arg_listen_https || https_socket >= 0) {
1124                                 log_error("cannot currently use --listen-https more than once");
1125                                 return -EINVAL;
1126                         }
1127
1128                         r = fd_fd(optarg);
1129                         if (r >= 0)
1130                                 https_socket = r;
1131                         else
1132                                 arg_listen_https = optarg;
1133
1134                         break;
1135
1136                 case ARG_KEY:
1137                         if (arg_key) {
1138                                 log_error("Key file specified twice");
1139                                 return -EINVAL;
1140                         }
1141
1142                         arg_key = strdup(optarg);
1143                         if (!arg_key)
1144                                 return log_oom();
1145
1146                         break;
1147
1148                 case ARG_CERT:
1149                         if (arg_cert) {
1150                                 log_error("Certificate file specified twice");
1151                                 return -EINVAL;
1152                         }
1153
1154                         arg_cert = strdup(optarg);
1155                         if (!arg_cert)
1156                                 return log_oom();
1157
1158                         break;
1159
1160                 case ARG_TRUST:
1161                         if (arg_trust || arg_trust_all) {
1162                                 log_error("Confusing trusted CA configuration");
1163                                 return -EINVAL;
1164                         }
1165
1166                         if (streq(optarg, "all"))
1167                                 arg_trust_all = true;
1168                         else {
1169 #ifdef HAVE_GNUTLS
1170                                 arg_trust = strdup(optarg);
1171                                 if (!arg_trust)
1172                                         return log_oom();
1173 #else
1174                                 log_error("Option --trust is not available.");
1175                                 return -EINVAL;
1176 #endif
1177                         }
1178
1179                         break;
1180
1181                 case 'o':
1182                         if (arg_output) {
1183                                 log_error("cannot use --output/-o more than once");
1184                                 return -EINVAL;
1185                         }
1186
1187                         arg_output = optarg;
1188                         break;
1189
1190                 case ARG_COMPRESS:
1191                         arg_compress = true;
1192                         break;
1193                 case ARG_NO_COMPRESS:
1194                         arg_compress = false;
1195                         break;
1196                 case ARG_SEAL:
1197                         arg_seal = true;
1198                         break;
1199                 case ARG_NO_SEAL:
1200                         arg_seal = false;
1201                         break;
1202
1203                 case ARG_GNUTLS_LOG: {
1204 #ifdef HAVE_GNUTLS
1205                         char *word, *state;
1206                         size_t size;
1207
1208                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1209                                 char *cat;
1210
1211                                 cat = strndup(word, size);
1212                                 if (!cat)
1213                                         return log_oom();
1214
1215                                 if (strv_consume(&arg_gnutls_log, cat) < 0)
1216                                         return log_oom();
1217                         }
1218                         break;
1219 #else
1220                         log_error("Option --gnutls-log is not available.");
1221                         return -EINVAL;
1222 #endif
1223                 }
1224
1225                 case '?':
1226                         return -EINVAL;
1227
1228                 default:
1229                         log_error("Unknown option code %c", c);
1230                         return -EINVAL;
1231                 }
1232
1233         if (optind < argc)
1234                 arg_files = argv + optind;
1235
1236         return 1 /* work to do */;
1237 }
1238
1239 static int load_certificates(char **key, char **cert, char **trust) {
1240         int r;
1241
1242         r = read_full_file(arg_key ?: KEY_FILE, key, NULL);
1243         if (r < 0) {
1244                 log_error("Failed to read key from file '%s': %s",
1245                           arg_key ?: KEY_FILE, strerror(-r));
1246                 return r;
1247         }
1248
1249         r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1250         if (r < 0) {
1251                 log_error("Failed to read certificate from file '%s': %s",
1252                           arg_cert ?: CERT_FILE, strerror(-r));
1253                 return r;
1254         }
1255
1256         if (arg_trust_all)
1257                 log_info("Certificate checking disabled.");
1258         else {
1259                 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1260                 if (r < 0) {
1261                         log_error("Failed to read CA certificate file '%s': %s",
1262                                   arg_trust ?: TRUST_FILE, strerror(-r));
1263                         return r;
1264                 }
1265         }
1266
1267         return 0;
1268 }
1269
1270 static int setup_gnutls_logger(char **categories) {
1271         if (!arg_listen_http && !arg_listen_https)
1272                 return 0;
1273
1274 #ifdef HAVE_GNUTLS
1275         {
1276                 char **cat;
1277                 int r;
1278
1279                 gnutls_global_set_log_function(log_func_gnutls);
1280
1281                 if (categories)
1282                         STRV_FOREACH(cat, categories) {
1283                                 r = log_enable_gnutls_category(*cat);
1284                                 if (r < 0)
1285                                         return r;
1286                         }
1287                 else
1288                         log_reset_gnutls_level();
1289         }
1290 #endif
1291
1292         return 0;
1293 }
1294
1295 int main(int argc, char **argv) {
1296         RemoteServer s = {};
1297         int r, r2;
1298         _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1299
1300         log_show_color(true);
1301         log_parse_environment();
1302
1303         r = parse_config();
1304         if (r < 0)
1305                 return EXIT_FAILURE;
1306
1307         r = parse_argv(argc, argv);
1308         if (r <= 0)
1309                 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1310
1311         r = setup_gnutls_logger(arg_gnutls_log);
1312         if (r < 0)
1313                 return EXIT_FAILURE;
1314
1315         if (load_certificates(&key, &cert, &trust) < 0)
1316                 return EXIT_FAILURE;
1317
1318         if (remoteserver_init(&s, key, cert, trust) < 0)
1319                 return EXIT_FAILURE;
1320
1321         sd_event_set_watchdog(s.events, true);
1322
1323         log_debug("%s running as pid "PID_FMT,
1324                   program_invocation_short_name, getpid());
1325         sd_notify(false,
1326                   "READY=1\n"
1327                   "STATUS=Processing requests...");
1328
1329         while (s.active) {
1330                 r = sd_event_get_state(s.events);
1331                 if (r < 0)
1332                         break;
1333                 if (r == SD_EVENT_FINISHED)
1334                         break;
1335
1336                 r = sd_event_run(s.events, -1);
1337                 if (r < 0) {
1338                         log_error("Failed to run event loop: %s", strerror(-r));
1339                         break;
1340                 }
1341         }
1342
1343         log_info("Finishing after writing %" PRIu64 " entries", s.writer.seqnum);
1344         r2 = server_destroy(&s);
1345
1346         sd_notify(false, "STATUS=Shutting down...");
1347
1348         free(arg_key);
1349         free(arg_cert);
1350         free(arg_trust);
1351
1352         return r >= 0 && r2 >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1353 }