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