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