chiark / gitweb /
journal-remote: initialize writer hashmap before use
[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         r = sd_event_default(&s->events);
812         if (r < 0) {
813                 log_error("Failed to allocate event loop: %s", strerror(-r));
814                 return r;
815         }
816
817         setup_signals(s);
818
819         assert(server == NULL);
820         server = s;
821
822         r = init_writer_hashmap(s);
823         if (r < 0)
824                 return r;
825
826         n = sd_listen_fds(true);
827         if (n < 0) {
828                 log_error("Failed to read listening file descriptors from environment: %s",
829                           strerror(-n));
830                 return n;
831         } else
832                 log_info("Received %d descriptors", n);
833
834         if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
835                 log_error("Received fewer sockets than expected");
836                 return -EBADFD;
837         }
838
839         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
840                 if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
841                         log_info("Received a listening socket (fd:%d)", fd);
842
843                         if (fd == http_socket)
844                                 r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
845                         else if (fd == https_socket)
846                                 r = setup_microhttpd_server(s, fd, key, cert, trust);
847                         else
848                                 r = add_raw_socket(s, fd);
849                 } else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
850                         char *hostname;
851
852                         r = getnameinfo_pretty(fd, &hostname);
853                         if (r < 0) {
854                                 log_error("Failed to retrieve remote name: %s", strerror(-r));
855                                 return r;
856                         }
857
858                         log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
859
860                         r = add_source(s, fd, hostname, true);
861                         if (r < 0)
862                                 free(hostname);
863                 } else {
864                         log_error("Unknown socket passed on fd:%d", fd);
865
866                         return -EINVAL;
867                 }
868
869                 if(r < 0) {
870                         log_error("Failed to register socket (fd:%d): %s",
871                                   fd, strerror(-r));
872                         return r;
873                 }
874         }
875
876         if (arg_url) {
877                 const char *url, *hostname;
878
879                 url = strappenda(arg_url, "/entries");
880
881                 if (arg_getter) {
882                         log_info("Spawning getter %s...", url);
883                         fd = spawn_getter(arg_getter, url);
884                 } else {
885                         log_info("Spawning curl %s...", url);
886                         fd = spawn_curl(url);
887                 }
888                 if (fd < 0)
889                         return fd;
890
891                 hostname =
892                         startswith(arg_url, "https://") ?:
893                         startswith(arg_url, "http://") ?:
894                         arg_url;
895
896                 r = add_source(s, fd, (char*) hostname, false);
897                 if (r < 0)
898                         return r;
899         }
900
901         if (arg_listen_raw) {
902                 log_info("Listening on a socket...");
903                 r = setup_raw_socket(s, arg_listen_raw);
904                 if (r < 0)
905                         return r;
906         }
907
908         if (arg_listen_http) {
909                 r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
910                 if (r < 0)
911                         return r;
912         }
913
914         if (arg_listen_https) {
915                 r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
916                 if (r < 0)
917                         return r;
918         }
919
920         STRV_FOREACH(file, arg_files) {
921                 const char *output_name;
922
923                 if (streq(*file, "-")) {
924                         log_info("Using standard input as source.");
925
926                         fd = STDIN_FILENO;
927                         output_name = "stdin";
928                 } else {
929                         log_info("Reading file %s...", *file);
930
931                         fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
932                         if (fd < 0) {
933                                 log_error("Failed to open %s: %m", *file);
934                                 return -errno;
935                         }
936                         output_name = *file;
937                 }
938
939                 r = add_source(s, fd, (char*) output_name, false);
940                 if (r < 0)
941                         return r;
942         }
943
944         if (s->active == 0) {
945                 log_error("Zarro sources specified");
946                 return -EINVAL;
947         }
948
949         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
950                 /* In this case we know what the writer will be
951                    called, so we can create it and verify that we can
952                    create output as expected. */
953                 r = get_writer(s, NULL, &s->_single_writer);
954                 if (r < 0)
955                         return r;
956         }
957
958         return 0;
959 }
960
961 static void server_destroy(RemoteServer *s) {
962         size_t i;
963         MHDDaemonWrapper *d;
964
965         while ((d = hashmap_steal_first(s->daemons))) {
966                 MHD_stop_daemon(d->daemon);
967                 sd_event_source_unref(d->event);
968                 free(d);
969         }
970
971         hashmap_free(s->daemons);
972
973         assert(s->sources_size == 0 || s->sources);
974         for (i = 0; i < s->sources_size; i++)
975                 remove_source(s, i);
976         free(s->sources);
977
978         writer_unref(s->_single_writer);
979         hashmap_free(s->writers);
980
981         sd_event_source_unref(s->sigterm_event);
982         sd_event_source_unref(s->sigint_event);
983         sd_event_source_unref(s->listen_event);
984         sd_event_unref(s->events);
985
986         /* fds that we're listening on remain open... */
987 }
988
989 /**********************************************************************
990  **********************************************************************
991  **********************************************************************/
992
993 static int dispatch_raw_source_event(sd_event_source *event,
994                                      int fd,
995                                      uint32_t revents,
996                                      void *userdata) {
997
998         RemoteServer *s = userdata;
999         RemoteSource *source;
1000         int r;
1001
1002         assert(fd >= 0 && fd < (ssize_t) s->sources_size);
1003         source = s->sources[fd];
1004         assert(source->fd == fd);
1005
1006         r = process_source(source, arg_compress, arg_seal);
1007         if (source->state == STATE_EOF) {
1008                 size_t remaining;
1009
1010                 log_info("EOF reached with source fd:%d (%s)",
1011                          source->fd, source->name);
1012
1013                 remaining = source_non_empty(source);
1014                 if (remaining > 0)
1015                         log_warning("Premature EOF. %zu bytes lost.", remaining);
1016                 remove_source(s, source->fd);
1017                 log_info("%zd active sources remaining", s->active);
1018                 return 0;
1019         } else if (r == -E2BIG) {
1020                 log_error("Entry too big, skipped");
1021                 return 1;
1022         } else if (r == -EAGAIN) {
1023                 return 0;
1024         } else if (r < 0) {
1025                 log_info("Closing connection: %s", strerror(-r));
1026                 remove_source(server, fd);
1027                 return 0;
1028         } else
1029                 return 1;
1030 }
1031
1032 static int accept_connection(const char* type, int fd,
1033                              SocketAddress *addr, char **hostname) {
1034         int fd2, r;
1035
1036         log_debug("Accepting new %s connection on fd:%d", type, fd);
1037         fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
1038         if (fd2 < 0) {
1039                 log_error("accept() on fd:%d failed: %m", fd);
1040                 return -errno;
1041         }
1042
1043         switch(socket_address_family(addr)) {
1044         case AF_INET:
1045         case AF_INET6: {
1046                 _cleanup_free_ char *a = NULL;
1047                 char *b;
1048
1049                 r = socket_address_print(addr, &a);
1050                 if (r < 0) {
1051                         log_error("socket_address_print(): %s", strerror(-r));
1052                         close(fd2);
1053                         return r;
1054                 }
1055
1056                 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
1057                 if (r < 0) {
1058                         close(fd2);
1059                         return r;
1060                 }
1061
1062                 log_info("Accepted %s %s connection from %s",
1063                          type,
1064                          socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
1065                          a);
1066
1067                 *hostname = b;
1068
1069                 return fd2;
1070         };
1071         default:
1072                 log_error("Rejected %s connection with unsupported family %d",
1073                           type, socket_address_family(addr));
1074                 close(fd2);
1075
1076                 return -EINVAL;
1077         }
1078 }
1079
1080 static int dispatch_raw_connection_event(sd_event_source *event,
1081                                          int fd,
1082                                          uint32_t revents,
1083                                          void *userdata) {
1084         RemoteServer *s = userdata;
1085         int fd2, r;
1086         SocketAddress addr = {
1087                 .size = sizeof(union sockaddr_union),
1088                 .type = SOCK_STREAM,
1089         };
1090         char *hostname;
1091
1092         fd2 = accept_connection("raw", fd, &addr, &hostname);
1093         if (fd2 < 0)
1094                 return fd2;
1095
1096         r = add_source(s, fd2, hostname, true);
1097         if (r < 0)
1098                 free(hostname);
1099         return r;
1100 }
1101
1102 /**********************************************************************
1103  **********************************************************************
1104  **********************************************************************/
1105
1106 static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
1107         [JOURNAL_WRITE_SPLIT_NONE] = "none",
1108         [JOURNAL_WRITE_SPLIT_HOST] = "host",
1109 };
1110
1111 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
1112 static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
1113                                 journal_write_split_mode,
1114                                 JournalWriteSplitMode,
1115                                 "Failed to parse split mode setting");
1116
1117 static int parse_config(void) {
1118         const ConfigTableItem items[] = {
1119                 { "Remote",  "SplitMode",              config_parse_write_split_mode, 0, &arg_split_mode },
1120                 { "Remote",  "ServerKeyFile",          config_parse_path,             0, &arg_key        },
1121                 { "Remote",  "ServerCertificateFile",  config_parse_path,             0, &arg_cert       },
1122                 { "Remote",  "TrustedCertificateFile", config_parse_path,             0, &arg_trust      },
1123                 {}};
1124
1125         return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
1126                             "Remote\0",
1127                             config_item_table_lookup, items,
1128                             false, false, true, NULL);
1129 }
1130
1131 static void help(void) {
1132         printf("%s [OPTIONS...] {FILE|-}...\n\n"
1133                "Write external journal events to journal file(s).\n\n"
1134                "  -h --help               Show this help\n"
1135                "     --version            Show package version\n"
1136                "     --url=URL            Read events from systemd-journal-gatewayd at URL\n"
1137                "     --getter=COMMAND     Read events from the output of COMMAND\n"
1138                "     --listen-raw=ADDR    Listen for connections at ADDR\n"
1139                "     --listen-http=ADDR   Listen for HTTP connections at ADDR\n"
1140                "     --listen-https=ADDR  Listen for HTTPS connections at ADDR\n"
1141                "  -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
1142                "     --compress[=BOOL]    Use XZ-compression in the output journal (default: yes)\n"
1143                "     --seal[=BOOL]        Use Event sealing in the output journal (default: no)\n"
1144                "     --key=FILENAME       Specify key in PEM format (default:\n"
1145                "                          \"" PRIV_KEY_FILE "\")\n"
1146                "     --cert=FILENAME      Specify certificate in PEM format (default:\n"
1147                "                          \"" CERT_FILE "\")\n"
1148                "     --trust=FILENAME|all Specify CA certificate or disable checking (default:\n"
1149                "                          \"" TRUST_FILE "\")\n"
1150                "     --gnutls-log=CATEGORY...\n"
1151                "                          Specify a list of gnutls logging categories\n"
1152                "\n"
1153                "Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
1154                , program_invocation_short_name);
1155 }
1156
1157 static int parse_argv(int argc, char *argv[]) {
1158         enum {
1159                 ARG_VERSION = 0x100,
1160                 ARG_URL,
1161                 ARG_LISTEN_RAW,
1162                 ARG_LISTEN_HTTP,
1163                 ARG_LISTEN_HTTPS,
1164                 ARG_GETTER,
1165                 ARG_SPLIT_MODE,
1166                 ARG_COMPRESS,
1167                 ARG_SEAL,
1168                 ARG_KEY,
1169                 ARG_CERT,
1170                 ARG_TRUST,
1171                 ARG_GNUTLS_LOG,
1172         };
1173
1174         static const struct option options[] = {
1175                 { "help",         no_argument,       NULL, 'h'              },
1176                 { "version",      no_argument,       NULL, ARG_VERSION      },
1177                 { "url",          required_argument, NULL, ARG_URL          },
1178                 { "getter",       required_argument, NULL, ARG_GETTER       },
1179                 { "listen-raw",   required_argument, NULL, ARG_LISTEN_RAW   },
1180                 { "listen-http",  required_argument, NULL, ARG_LISTEN_HTTP  },
1181                 { "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
1182                 { "output",       required_argument, NULL, 'o'              },
1183                 { "split-mode",   required_argument, NULL, ARG_SPLIT_MODE   },
1184                 { "compress",     optional_argument, NULL, ARG_COMPRESS     },
1185                 { "seal",         optional_argument, NULL, ARG_SEAL         },
1186                 { "key",          required_argument, NULL, ARG_KEY          },
1187                 { "cert",         required_argument, NULL, ARG_CERT         },
1188                 { "trust",        required_argument, NULL, ARG_TRUST        },
1189                 { "gnutls-log",   required_argument, NULL, ARG_GNUTLS_LOG   },
1190                 {}
1191         };
1192
1193         int c, r;
1194         bool type_a, type_b;
1195
1196         assert(argc >= 0);
1197         assert(argv);
1198
1199         while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
1200                 switch(c) {
1201                 case 'h':
1202                         help();
1203                         return 0 /* done */;
1204
1205                 case ARG_VERSION:
1206                         puts(PACKAGE_STRING);
1207                         puts(SYSTEMD_FEATURES);
1208                         return 0 /* done */;
1209
1210                 case ARG_URL:
1211                         if (arg_url) {
1212                                 log_error("cannot currently set more than one --url");
1213                                 return -EINVAL;
1214                         }
1215
1216                         arg_url = optarg;
1217                         break;
1218
1219                 case ARG_GETTER:
1220                         if (arg_getter) {
1221                                 log_error("cannot currently use --getter more than once");
1222                                 return -EINVAL;
1223                         }
1224
1225                         arg_getter = optarg;
1226                         break;
1227
1228                 case ARG_LISTEN_RAW:
1229                         if (arg_listen_raw) {
1230                                 log_error("cannot currently use --listen-raw more than once");
1231                                 return -EINVAL;
1232                         }
1233
1234                         arg_listen_raw = optarg;
1235                         break;
1236
1237                 case ARG_LISTEN_HTTP:
1238                         if (arg_listen_http || http_socket >= 0) {
1239                                 log_error("cannot currently use --listen-http more than once");
1240                                 return -EINVAL;
1241                         }
1242
1243                         r = fd_fd(optarg);
1244                         if (r >= 0)
1245                                 http_socket = r;
1246                         else
1247                                 arg_listen_http = optarg;
1248                         break;
1249
1250                 case ARG_LISTEN_HTTPS:
1251                         if (arg_listen_https || https_socket >= 0) {
1252                                 log_error("cannot currently use --listen-https more than once");
1253                                 return -EINVAL;
1254                         }
1255
1256                         r = fd_fd(optarg);
1257                         if (r >= 0)
1258                                 https_socket = r;
1259                         else
1260                                 arg_listen_https = optarg;
1261
1262                         break;
1263
1264                 case ARG_KEY:
1265                         if (arg_key) {
1266                                 log_error("Key file specified twice");
1267                                 return -EINVAL;
1268                         }
1269
1270                         arg_key = strdup(optarg);
1271                         if (!arg_key)
1272                                 return log_oom();
1273
1274                         break;
1275
1276                 case ARG_CERT:
1277                         if (arg_cert) {
1278                                 log_error("Certificate file specified twice");
1279                                 return -EINVAL;
1280                         }
1281
1282                         arg_cert = strdup(optarg);
1283                         if (!arg_cert)
1284                                 return log_oom();
1285
1286                         break;
1287
1288                 case ARG_TRUST:
1289                         if (arg_trust || arg_trust_all) {
1290                                 log_error("Confusing trusted CA configuration");
1291                                 return -EINVAL;
1292                         }
1293
1294                         if (streq(optarg, "all"))
1295                                 arg_trust_all = true;
1296                         else {
1297 #ifdef HAVE_GNUTLS
1298                                 arg_trust = strdup(optarg);
1299                                 if (!arg_trust)
1300                                         return log_oom();
1301 #else
1302                                 log_error("Option --trust is not available.");
1303                                 return -EINVAL;
1304 #endif
1305                         }
1306
1307                         break;
1308
1309                 case 'o':
1310                         if (arg_output) {
1311                                 log_error("cannot use --output/-o more than once");
1312                                 return -EINVAL;
1313                         }
1314
1315                         arg_output = optarg;
1316                         break;
1317
1318                 case ARG_SPLIT_MODE:
1319                         arg_split_mode = journal_write_split_mode_from_string(optarg);
1320                         if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
1321                                 log_error("Invalid split mode: %s", optarg);
1322                                 return -EINVAL;
1323                         }
1324                         break;
1325
1326                 case ARG_COMPRESS:
1327                         if (optarg) {
1328                                 r = parse_boolean(optarg);
1329                                 if (r < 0) {
1330                                         log_error("Failed to parse --compress= parameter.");
1331                                         return -EINVAL;
1332                                 }
1333
1334                                 arg_compress = !!r;
1335                         } else
1336                                 arg_compress = true;
1337
1338                         break;
1339
1340                 case ARG_SEAL:
1341                         if (optarg) {
1342                                 r = parse_boolean(optarg);
1343                                 if (r < 0) {
1344                                         log_error("Failed to parse --seal= parameter.");
1345                                         return -EINVAL;
1346                                 }
1347
1348                                 arg_seal = !!r;
1349                         } else
1350                                 arg_seal = true;
1351
1352                         break;
1353
1354                 case ARG_GNUTLS_LOG: {
1355 #ifdef HAVE_GNUTLS
1356                         const char *word, *state;
1357                         size_t size;
1358
1359                         FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
1360                                 char *cat;
1361
1362                                 cat = strndup(word, size);
1363                                 if (!cat)
1364                                         return log_oom();
1365
1366                                 if (strv_consume(&arg_gnutls_log, cat) < 0)
1367                                         return log_oom();
1368                         }
1369                         break;
1370 #else
1371                         log_error("Option --gnutls-log is not available.");
1372                         return -EINVAL;
1373 #endif
1374                 }
1375
1376                 case '?':
1377                         return -EINVAL;
1378
1379                 default:
1380                         assert_not_reached("Unknown option code.");
1381                 }
1382
1383         if (optind < argc)
1384                 arg_files = argv + optind;
1385
1386         type_a = arg_getter || !strv_isempty(arg_files);
1387         type_b = arg_url
1388                 || arg_listen_raw
1389                 || arg_listen_http || arg_listen_https
1390                 || sd_listen_fds(false) > 0;
1391         if (type_a && type_b) {
1392                 log_error("Cannot use file input or --getter with "
1393                           "--arg-listen-... or socket activation.");
1394                 return -EINVAL;
1395         }
1396         if (type_a) {
1397                 if (!arg_output) {
1398                         log_error("Option --output must be specified with file input or --getter.");
1399                         return -EINVAL;
1400                 }
1401
1402                 arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
1403         }
1404
1405         if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
1406             && arg_output && is_dir(arg_output, true) > 0) {
1407                 log_error("For SplitMode=none, output must be a file.");
1408                 return -EINVAL;
1409         }
1410
1411         if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
1412             && arg_output && is_dir(arg_output, true) <= 0) {
1413                 log_error("For SplitMode=host, output must be a directory.");
1414                 return -EINVAL;
1415         }
1416
1417         log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
1418                   journal_write_split_mode_to_string(arg_split_mode),
1419                   strna(arg_key),
1420                   strna(arg_cert),
1421                   strna(arg_trust));
1422
1423         return 1 /* work to do */;
1424 }
1425
1426 static int load_certificates(char **key, char **cert, char **trust) {
1427         int r;
1428
1429         r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
1430         if (r < 0) {
1431                 log_error("Failed to read key from file '%s': %s",
1432                           arg_key ?: PRIV_KEY_FILE, strerror(-r));
1433                 return r;
1434         }
1435
1436         r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
1437         if (r < 0) {
1438                 log_error("Failed to read certificate from file '%s': %s",
1439                           arg_cert ?: CERT_FILE, strerror(-r));
1440                 return r;
1441         }
1442
1443         if (arg_trust_all)
1444                 log_info("Certificate checking disabled.");
1445         else {
1446                 r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
1447                 if (r < 0) {
1448                         log_error("Failed to read CA certificate file '%s': %s",
1449                                   arg_trust ?: TRUST_FILE, strerror(-r));
1450                         return r;
1451                 }
1452         }
1453
1454         return 0;
1455 }
1456
1457 static int setup_gnutls_logger(char **categories) {
1458         if (!arg_listen_http && !arg_listen_https)
1459                 return 0;
1460
1461 #ifdef HAVE_GNUTLS
1462         {
1463                 char **cat;
1464                 int r;
1465
1466                 gnutls_global_set_log_function(log_func_gnutls);
1467
1468                 if (categories)
1469                         STRV_FOREACH(cat, categories) {
1470                                 r = log_enable_gnutls_category(*cat);
1471                                 if (r < 0)
1472                                         return r;
1473                         }
1474                 else
1475                         log_reset_gnutls_level();
1476         }
1477 #endif
1478
1479         return 0;
1480 }
1481
1482 int main(int argc, char **argv) {
1483         RemoteServer s = {};
1484         int r;
1485         _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
1486
1487         log_show_color(true);
1488         log_parse_environment();
1489
1490         r = parse_config();
1491         if (r < 0)
1492                 return EXIT_FAILURE;
1493
1494         r = parse_argv(argc, argv);
1495         if (r <= 0)
1496                 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1497
1498         r = setup_gnutls_logger(arg_gnutls_log);
1499         if (r < 0)
1500                 return EXIT_FAILURE;
1501
1502         if (arg_listen_https || https_socket >= 0)
1503                 if (load_certificates(&key, &cert, &trust) < 0)
1504                         return EXIT_FAILURE;
1505
1506         if (remoteserver_init(&s, key, cert, trust) < 0)
1507                 return EXIT_FAILURE;
1508
1509         sd_event_set_watchdog(s.events, true);
1510
1511         log_debug("%s running as pid "PID_FMT,
1512                   program_invocation_short_name, getpid());
1513         sd_notify(false,
1514                   "READY=1\n"
1515                   "STATUS=Processing requests...");
1516
1517         while (s.active) {
1518                 r = sd_event_get_state(s.events);
1519                 if (r < 0)
1520                         break;
1521                 if (r == SD_EVENT_FINISHED)
1522                         break;
1523
1524                 r = sd_event_run(s.events, -1);
1525                 if (r < 0) {
1526                         log_error("Failed to run event loop: %s", strerror(-r));
1527                         break;
1528                 }
1529         }
1530
1531         sd_notifyf(false,
1532                    "STOPPING=1\n"
1533                    "STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
1534         log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
1535
1536         server_destroy(&s);
1537
1538         free(arg_key);
1539         free(arg_cert);
1540         free(arg_trust);
1541
1542         return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1543 }