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