chiark / gitweb /
journal-remote: add units and read certs from default locations
[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         if (fd >= 0)
702                 return -ENOENT;
703
704         return -fd;
705 }
706
707
708 static int remoteserver_init(RemoteServer *s,
709                              const char* key,
710                              const char* cert,
711                              const char* trust) {
712         int r, n, fd;
713         const char *output_name = NULL;
714         char **file;
715
716         assert(s);
717
718
719         if ((arg_listen_raw || arg_listen_http) && trust) {
720                 log_error("Option --trust makes all non-HTTPS connections untrusted.");
721                 return -EINVAL;
722         }
723
724         sd_event_default(&s->events);
725
726         setup_signals(s);
727
728         assert(server == NULL);
729         server = s;
730
731         n = sd_listen_fds(true);
732         if (n < 0) {
733                 log_error("Failed to read listening file descriptors from environment: %s",
734                           strerror(-n));
735                 return n;
736         } else
737                 log_info("Received %d descriptors", n);
738
739         if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
740                 log_error("Received fewer sockets than expected");
741                 return -EBADFD;
742         }
743
744         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
745                 if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
746                         log_info("Received a listening socket (fd:%d)", fd);
747
748                         if (fd == http_socket)
749                                 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
750                         else if (fd == https_socket)
751                                 r = setup_microhttpd_server(s, fd, key, cert, trust);
752                         else
753                                 r = add_raw_socket(s, fd);
754                 } else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
755                         log_info("Received a connection socket (fd:%d)", fd);
756
757                         r = add_source(s, fd, NULL);
758                 } else {
759                         log_error("Unknown socket passed on fd:%d", fd);
760
761                         return -EINVAL;
762                 }
763
764                 if(r < 0) {
765                         log_error("Failed to register socket (fd:%d): %s",
766                                   fd, strerror(-r));
767                         return r;
768                 }
769
770                 output_name = "socket";
771         }
772
773         if (arg_url) {
774                 _cleanup_free_ char *url = NULL;
775                 _cleanup_strv_free_ char **urlv = strv_new(arg_url, "/entries", NULL);
776                 if (!urlv)
777                         return log_oom();
778                 url = strv_join(urlv, "");
779                 if (!url)
780                         return log_oom();
781
782                 if (arg_getter) {
783                         log_info("Spawning getter %s...", url);
784                         fd = spawn_getter(arg_getter, url);
785                 } else {
786                         log_info("Spawning curl %s...", url);
787                         fd = spawn_curl(url);
788                 }
789                 if (fd < 0)
790                         return fd;
791
792                 r = add_source(s, fd, arg_url);
793                 if (r < 0)
794                         return r;
795
796                 output_name = arg_url;
797         }
798
799         if (arg_listen_raw) {
800                 log_info("Listening on a socket...");
801                 r = setup_raw_socket(s, arg_listen_raw);
802                 if (r < 0)
803                         return r;
804
805                 output_name = arg_listen_raw;
806         }
807
808         if (arg_listen_http) {
809                 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
810                 if (r < 0)
811                         return r;
812
813                 output_name = arg_listen_http;
814         }
815
816         if (arg_listen_https) {
817                 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
818                 if (r < 0)
819                         return r;
820
821                 output_name = arg_listen_https;
822         }
823
824         STRV_FOREACH(file, arg_files) {
825                 if (streq(*file, "-")) {
826                         log_info("Reading standard input...");
827
828                         fd = STDIN_FILENO;
829                         output_name = "stdin";
830                 } else {
831                         log_info("Reading file %s...", *file);
832
833                         fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
834                         if (fd < 0) {
835                                 log_error("Failed to open %s: %m", *file);
836                                 return -errno;
837                         }
838                         output_name = *file;
839                 }
840
841                 r = add_source(s, fd, output_name);
842                 if (r < 0)
843                         return r;
844         }
845
846         if (s->active == 0) {
847                 log_error("Zarro sources specified");
848                 return -EINVAL;
849         }
850
851         if (!!n + !!arg_url + !!arg_listen_raw + !!arg_files)
852                 output_name = "multiple";
853
854         r = writer_init(&s->writer);
855         if (r < 0)
856                 return r;
857
858         r = open_output(&s->writer, output_name);
859         return r;
860 }
861
862 static int server_destroy(RemoteServer *s) {
863         int r;
864         size_t i;
865         MHDDaemonWrapper *d;
866
867         r = writer_close(&s->writer);
868
869         while ((d = hashmap_steal_first(s->daemons))) {
870                 MHD_stop_daemon(d->daemon);
871                 sd_event_source_unref(d->event);
872                 free(d);
873         }
874
875         hashmap_free(s->daemons);
876
877         assert(s->sources_size == 0 || s->sources);
878         for (i = 0; i < s->sources_size; i++)
879                 remove_source(s, i);
880
881         free(s->sources);
882
883         sd_event_source_unref(s->sigterm_event);
884         sd_event_source_unref(s->sigint_event);
885         sd_event_source_unref(s->listen_event);
886         sd_event_unref(s->events);
887
888         /* fds that we're listening on remain open... */
889
890         return r;
891 }
892
893 /**********************************************************************
894  **********************************************************************
895  **********************************************************************/
896
897 static int dispatch_raw_source_event(sd_event_source *event,
898                                      int fd,
899                                      uint32_t revents,
900                                      void *userdata) {
901
902         RemoteServer *s = userdata;
903         RemoteSource *source;
904         int r;
905
906         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
907         source = s->sources[fd];
908         assert(source->fd == fd);
909
910         r = process_source(source, &s->writer, arg_compress, arg_seal);
911         if (source->state == STATE_EOF) {
912                 log_info("EOF reached with source fd:%d (%s)",
913                          source->fd, source->name);
914                 if (source_non_empty(source))
915                         log_warning("EOF reached with incomplete data");
916                 remove_source(s, source->fd);
917                 log_info("%zd active source remaining", s->active);
918         } else if (r == -E2BIG) {
919                 log_error("Entry too big, skipped");
920                 r = 1;
921         }
922
923         return r;
924 }
925
926 static int accept_connection(const char* type, int fd, SocketAddress *addr) {
927         int fd2, r;
928
929         log_debug("Accepting new %s connection on fd:%d", type, fd);
930         fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
931         if (fd2 < 0) {
932                 log_error("accept() on fd:%d failed: %m", fd);
933                 return -errno;
934         }
935
936         switch(socket_address_family(addr)) {
937         case AF_INET:
938         case AF_INET6: {
939                 char* _cleanup_free_ a = NULL;
940
941                 r = socket_address_print(addr, &a);
942                 if (r < 0) {
943                         log_error("socket_address_print(): %s", strerror(-r));
944                         close(fd2);
945                         return r;
946                 }
947
948                 log_info("Accepted %s %s connection from %s",
949                          type,
950                          socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
951                          a);
952
953                 return fd2;
954         };
955         default:
956                 log_error("Rejected %s connection with unsupported family %d",
957                           type, socket_address_family(addr));
958                 close(fd2);
959
960                 return -EINVAL;
961         }
962 }
963
964 static int dispatch_raw_connection_event(sd_event_source *event,
965                                          int fd,
966                                          uint32_t revents,
967                                          void *userdata) {
968         RemoteServer *s = userdata;
969         int fd2;
970         SocketAddress addr = {
971                 .size = sizeof(union sockaddr_union),
972                 .type = SOCK_STREAM,
973         };
974
975         fd2 = accept_connection("raw", fd, &addr);
976         if (fd2 < 0)
977                 return fd2;
978
979         return add_source(s, fd2, NULL);
980 }
981
982 /**********************************************************************
983  **********************************************************************
984  **********************************************************************/
985
986 static int parse_config(void) {
987         const ConfigTableItem items[] = {
988                 { "Remote",  "ServerKeyFile",          config_parse_path,       0, &arg_key        },
989                 { "Remote",  "ServerCertificateFile",  config_parse_path,       0, &arg_cert       },
990                 { "Remote",  "TrustedCertificateFile", config_parse_path,       0, &arg_trust      },
991                 {}};
992         int r;
993
994         r = config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
995                          "Remote\0",
996                          config_item_table_lookup, items,
997                          false, false, NULL);
998         if (r < 0)
999                 log_error("Failed to parse configuration file: %s", strerror(-r));
1000
1001         return r;
1002 }
1003
1004 static void help(void) {
1005         printf("%s [OPTIONS...] {FILE|-}...\n\n"
1006                "Write external journal events to a journal file.\n\n"
1007                "Options:\n"
1008                "  --url=URL            Read events from systemd-journal-gatewayd at URL\n"
1009                "  --getter=COMMAND     Read events from the output of COMMAND\n"
1010                "  --listen-raw=ADDR    Listen for connections at ADDR\n"
1011                "  --listen-http=ADDR   Listen for HTTP connections at ADDR\n"
1012                "  --listen-https=ADDR  Listen for HTTPS connections at ADDR\n"
1013                "  -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1014                "  --[no-]compress      Use XZ-compression in the output journal (default: yes)\n"
1015                "  --[no-]seal          Use Event sealing in the output journal (default: no)\n"
1016                "  --key=FILENAME       Specify key in PEM format (default:\n"
1017                "                           \"" KEY_FILE "\")\n"
1018                "  --cert=FILENAME      Specify certificate in PEM format (default:\n"
1019                "                           \"" CERT_FILE "\")\n"
1020                "  --trust=FILENAME|all Specify CA certificate or disable checking (default:\n"
1021                "                           \"" TRUST_FILE "\")\n"
1022                "  --gnutls-log=CATEGORY...\n"
1023                "                       Specify a list of gnutls logging categories\n"
1024                "  -h --help            Show this help and exit\n"
1025                "  --version            Print version string and exit\n"
1026                "\n"
1027                "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1028                , program_invocation_short_name);
1029 }
1030
1031 static int parse_argv(int argc, char *argv[]) {
1032         enum {
1033                 ARG_VERSION = 0x100,
1034                 ARG_URL,
1035                 ARG_LISTEN_RAW,
1036                 ARG_LISTEN_HTTP,
1037                 ARG_LISTEN_HTTPS,
1038                 ARG_GETTER,
1039                 ARG_COMPRESS,
1040                 ARG_NO_COMPRESS,
1041                 ARG_SEAL,
1042                 ARG_NO_SEAL,
1043                 ARG_KEY,
1044                 ARG_CERT,
1045                 ARG_TRUST,
1046                 ARG_GNUTLS_LOG,
1047         };
1048
1049         static const struct option options[] = {
1050                 { "help",         no_argument,       NULL, 'h'              },
1051                 { "version",      no_argument,       NULL, ARG_VERSION      },
1052                 { "url",          required_argument, NULL, ARG_URL          },
1053                 { "getter",       required_argument, NULL, ARG_GETTER       },
1054                 { "listen-raw",   required_argument, NULL, ARG_LISTEN_RAW   },
1055                 { "listen-http",  required_argument, NULL, ARG_LISTEN_HTTP  },
1056                 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1057                 { "output",       required_argument, NULL, 'o'              },
1058                 { "compress",     no_argument,       NULL, ARG_COMPRESS     },
1059                 { "no-compress",  no_argument,       NULL, ARG_NO_COMPRESS  },
1060                 { "seal",         no_argument,       NULL, ARG_SEAL         },
1061                 { "no-seal",      no_argument,       NULL, ARG_NO_SEAL      },
1062                 { "key",          required_argument, NULL, ARG_KEY          },
1063                 { "cert",         required_argument, NULL, ARG_CERT         },
1064                 { "trust",        required_argument, NULL, ARG_TRUST        },
1065                 { "gnutls-log",   required_argument, NULL, ARG_GNUTLS_LOG   },
1066                 {}
1067         };
1068
1069         int c, r;
1070
1071         assert(argc >= 0);
1072         assert(argv);
1073
1074         while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1075                 switch(c) {
1076                 case 'h':
1077                         help();
1078                         return 0 /* done */;
1079
1080                 case ARG_VERSION:
1081                         puts(PACKAGE_STRING);
1082                         puts(SYSTEMD_FEATURES);
1083                         return 0 /* done */;
1084
1085                 case ARG_URL:
1086                         if (arg_url) {
1087                                 log_error("cannot currently set more than one --url");
1088                                 return -EINVAL;
1089                         }
1090
1091                         arg_url = optarg;
1092                         break;
1093
1094                 case ARG_GETTER:
1095                         if (arg_getter) {
1096                                 log_error("cannot currently use --getter more than once");
1097                                 return -EINVAL;
1098                         }
1099
1100                         arg_getter = optarg;
1101                         break;
1102
1103                 case ARG_LISTEN_RAW:
1104                         if (arg_listen_raw) {
1105                                 log_error("cannot currently use --listen-raw more than once");
1106                                 return -EINVAL;
1107                         }
1108
1109                         arg_listen_raw = optarg;
1110                         break;
1111
1112                 case ARG_LISTEN_HTTP:
1113                         if (arg_listen_http || http_socket >= 0) {
1114                                 log_error("cannot currently use --listen-http more than once");
1115                                 return -EINVAL;
1116                         }
1117
1118                         r = fd_fd(optarg);
1119                         if (r >= 0)
1120                                 http_socket = r;
1121                         else if (r == -ENOENT)
1122                                 arg_listen_http = optarg;
1123                         else {
1124                                 log_error("Invalid port/fd specification %s: %s",
1125                                           optarg, strerror(-r));
1126                                 return -EINVAL;
1127                         }
1128
1129                         break;
1130
1131                 case ARG_LISTEN_HTTPS:
1132                         if (arg_listen_https || https_socket >= 0) {
1133                                 log_error("cannot currently use --listen-https more than once");
1134                                 return -EINVAL;
1135                         }
1136
1137                         r = fd_fd(optarg);
1138                         if (r >= 0)
1139                                 https_socket = r;
1140                         else if (r == -ENOENT)
1141                                 arg_listen_https = optarg;
1142                         else {
1143                                 log_error("Invalid port/fd specification %s: %s",
1144                                           optarg, strerror(-r));
1145                                 return -EINVAL;
1146                         }
1147
1148                         break;
1149
1150                 case ARG_KEY:
1151                         if (arg_key) {
1152                                 log_error("Key file specified twice");
1153                                 return -EINVAL;
1154                         }
1155
1156                         arg_key = strdup(optarg);
1157                         if (!arg_key)
1158                                 return log_oom();
1159
1160                         break;
1161
1162                 case ARG_CERT:
1163                         if (arg_cert) {
1164                                 log_error("Certificate file specified twice");
1165                                 return -EINVAL;
1166                         }
1167
1168                         arg_cert = strdup(optarg);
1169                         if (!arg_cert)
1170                                 return log_oom();
1171
1172                         break;
1173
1174                 case ARG_TRUST:
1175                         if (arg_trust || arg_trust_all) {
1176                                 log_error("Confusing trusted CA configuration");
1177                                 return -EINVAL;
1178                         }
1179
1180                         if (streq(optarg, "all"))
1181                                 arg_trust_all = true;
1182                         else {
1183 #ifdef HAVE_GNUTLS
1184                                 arg_trust = strdup(optarg);
1185                                 if (!arg_trust)
1186                                         return log_oom();
1187 #else
1188                                 log_error("Option --trust is not available.");
1189                                 return -EINVAL;
1190 #endif
1191                         }
1192
1193                         break;
1194
1195                 case 'o':
1196                         if (arg_output) {
1197                                 log_error("cannot use --output/-o more than once");
1198                                 return -EINVAL;
1199                         }
1200
1201                         arg_output = optarg;
1202                         break;
1203
1204                 case ARG_COMPRESS:
1205                         arg_compress = true;
1206                         break;
1207                 case ARG_NO_COMPRESS:
1208                         arg_compress = false;
1209                         break;
1210                 case ARG_SEAL:
1211                         arg_seal = true;
1212                         break;
1213                 case ARG_NO_SEAL:
1214                         arg_seal = false;
1215                         break;
1216
1217                 case ARG_GNUTLS_LOG: {
1218 #ifdef HAVE_GNUTLS
1219                         char *word, *state;
1220                         size_t size;
1221
1222                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1223                                 char *cat;
1224
1225                                 cat = strndup(word, size);
1226                                 if (!cat)
1227                                         return log_oom();
1228
1229                                 if (strv_consume(&arg_gnutls_log, cat) < 0)
1230                                         return log_oom();
1231                         }
1232                         break;
1233 #else
1234                         log_error("Option --gnutls-log is not available.");
1235                         return -EINVAL;
1236 #endif
1237                 }
1238
1239                 case '?':
1240                         return -EINVAL;
1241
1242                 default:
1243                         log_error("Unknown option code %c", c);
1244                         return -EINVAL;
1245                 }
1246
1247         if (optind < argc)
1248                 arg_files = argv + optind;
1249
1250         return 1 /* work to do */;
1251 }
1252
1253 static int load_certificates(char **key, char **cert, char **trust) {
1254         int r;
1255
1256         r = read_full_file(arg_key ?: KEY_FILE, key, NULL);
1257         if (r < 0) {
1258                 log_error("Failed to read key from file '%s': %s",
1259                           arg_key ?: KEY_FILE, strerror(-r));
1260                 return r;
1261         }
1262
1263         r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1264         if (r < 0) {
1265                 log_error("Failed to read certificate from file '%s': %s",
1266                           arg_cert ?: CERT_FILE, strerror(-r));
1267                 return r;
1268         }
1269
1270         if (arg_trust_all)
1271                 log_info("Certificate checking disabled.");
1272         else {
1273                 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1274                 if (r < 0) {
1275                         log_error("Failed to read CA certificate file '%s': %s",
1276                                   arg_trust ?: TRUST_FILE, strerror(-r));
1277                         return r;
1278                 }
1279         }
1280
1281         return 0;
1282 }
1283
1284 static int setup_gnutls_logger(char **categories) {
1285         if (!arg_listen_http && !arg_listen_https)
1286                 return 0;
1287
1288 #ifdef HAVE_GNUTLS
1289         {
1290                 char **cat;
1291                 int r;
1292
1293                 gnutls_global_set_log_function(log_func_gnutls);
1294
1295                 if (categories)
1296                         STRV_FOREACH(cat, categories) {
1297                                 r = log_enable_gnutls_category(*cat);
1298                                 if (r < 0)
1299                                         return r;
1300                         }
1301                 else
1302                         log_reset_gnutls_level();
1303         }
1304 #endif
1305
1306         return 0;
1307 }
1308
1309 int main(int argc, char **argv) {
1310         RemoteServer s = {};
1311         int r, r2;
1312         _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1313
1314         log_show_color(true);
1315         log_parse_environment();
1316
1317         r = parse_config();
1318         if (r < 0)
1319                 return EXIT_FAILURE;
1320
1321         r = parse_argv(argc, argv);
1322         if (r <= 0)
1323                 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1324
1325         r = setup_gnutls_logger(arg_gnutls_log);
1326         if (r < 0)
1327                 return EXIT_FAILURE;
1328
1329         if (load_certificates(&key, &cert, &trust) < 0)
1330                 return EXIT_FAILURE;
1331
1332         if (remoteserver_init(&s, key, cert, trust) < 0)
1333                 return EXIT_FAILURE;
1334
1335         sd_event_set_watchdog(s.events, true);
1336
1337         log_debug("%s running as pid "PID_FMT,
1338                   program_invocation_short_name, getpid());
1339         sd_notify(false,
1340                   "READY=1\n"
1341                   "STATUS=Processing requests...");
1342
1343         while (s.active) {
1344                 r = sd_event_get_state(s.events);
1345                 if (r < 0)
1346                         break;
1347                 if (r == SD_EVENT_FINISHED)
1348                         break;
1349
1350                 r = sd_event_run(s.events, -1);
1351                 if (r < 0) {
1352                         log_error("Failed to run event loop: %s", strerror(-r));
1353                         break;
1354                 }
1355         }
1356
1357         log_info("Finishing after writing %" PRIu64 " entries", s.writer.seqnum);
1358         r2 = server_destroy(&s);
1359
1360         sd_notify(false, "STATUS=Shutting down...");
1361
1362         free(arg_key);
1363         free(arg_cert);
1364         free(arg_trust);
1365
1366         return r >= 0 && r2 >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1367 }