chiark / gitweb /
journal-gatewayd: log to journal from gnutls
[elogind.git] / src / journal / journal-gatewayd.c
index dfec8352bb91e3092bba134f22dc8c01251a89f9..c9a243841d04a2b67f5b5dc39db9357563e9dba3 100644 (file)
 #include "util.h"
 #include "sd-journal.h"
 #include "sd-daemon.h"
+#include "sd-bus.h"
+#include "bus-util.h"
 #include "logs-show.h"
 #include "microhttpd-util.h"
-#include "virt.h"
 #include "build.h"
+#include "fileio.h"
 
 typedef struct RequestMeta {
         sd_journal *journal;
@@ -106,10 +108,9 @@ static int open_journal(RequestMeta *m) {
         if (m->journal)
                 return 0;
 
-        return sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
+        return sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM);
 }
 
-
 static int respond_oom_internal(struct MHD_Connection *connection) {
         struct MHD_Response *response;
         const char m[] = "Out of memory.\n";
@@ -130,6 +131,7 @@ static int respond_oom_internal(struct MHD_Connection *connection) {
 
 #define respond_oom(connection) log_oom(), respond_oom_internal(connection)
 
+_printf_(3,4)
 static int respond_error(
                 struct MHD_Connection *connection,
                 unsigned code,
@@ -246,7 +248,7 @@ static ssize_t request_reader_entries(
                         }
                 }
 
-                r = output_journal(m->tmp, m->journal, m->mode, 0, OUTPUT_FULL_WIDTH);
+                r = output_journal(m->tmp, m->journal, m->mode, 0, OUTPUT_FULL_WIDTH, NULL);
                 if (r < 0) {
                         log_error("Failed to serialize item: %s", strerror(-r));
                         return MHD_CONTENT_READER_END_WITH_ERROR;
@@ -333,7 +335,7 @@ static int request_parse_range(
 
                 colon2 = strchr(colon + 1, ':');
                 if (colon2) {
-                        char _cleanup_free_ *t;
+                        _cleanup_free_ char *t;
 
                         t = strndup(colon + 1, colon2 - colon - 1);
                         if (!t)
@@ -740,6 +742,36 @@ static int request_handler_file(
         return ret;
 }
 
+static int get_virtualization(char **v) {
+        _cleanup_bus_unref_ sd_bus *bus = NULL;
+        char *b = NULL;
+        int r;
+
+        r = sd_bus_default_system(&bus);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_get_property_string(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "Virtualization",
+                        NULL,
+                        &b);
+        if (r < 0)
+                return r;
+
+        if (isempty(b)) {
+                free(b);
+                *v = NULL;
+                return 0;
+        }
+
+        *v = b;
+        return 1;
+}
+
 static int request_handler_machine(
                 struct MHD_Connection *connection,
                 void *connection_cls) {
@@ -748,10 +780,10 @@ static int request_handler_machine(
         RequestMeta *m = connection_cls;
         int r;
         _cleanup_free_ char* hostname = NULL, *os_name = NULL;
-        uint64_t cutoff_from, cutoff_to, usage;
+        uint64_t cutoff_from = 0, cutoff_to = 0, usage;
         char *json;
         sd_id128_t mid, bid;
-        const char *v = "bare";
+        _cleanup_free_ char *v = NULL;
 
         assert(connection);
         assert(m);
@@ -782,7 +814,7 @@ static int request_handler_machine(
 
         parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &os_name, NULL);
 
-        detect_virtualization(&v);
+        get_virtualization(&v);
 
         r = asprintf(&json,
                      "{ \"machine_id\" : \"" SD_ID128_FORMAT_STR "\","
@@ -790,17 +822,17 @@ static int request_handler_machine(
                      "\"hostname\" : \"%s\","
                      "\"os_pretty_name\" : \"%s\","
                      "\"virtualization\" : \"%s\","
-                     "\"usage\" : \"%llu\","
-                     "\"cutoff_from_realtime\" : \"%llu\","
-                     "\"cutoff_to_realtime\" : \"%llu\" }\n",
+                     "\"usage\" : \"%"PRIu64"\","
+                     "\"cutoff_from_realtime\" : \"%"PRIu64"\","
+                     "\"cutoff_to_realtime\" : \"%"PRIu64"\" }\n",
                      SD_ID128_FORMAT_VAL(mid),
                      SD_ID128_FORMAT_VAL(bid),
-                     hostname_cleanup(hostname),
+                     hostname_cleanup(hostname, false),
                      os_name ? os_name : "Linux",
-                     v,
-                     (unsigned long long) usage,
-                     (unsigned long long) cutoff_from,
-                     (unsigned long long) cutoff_to);
+                     v ? v : "bare",
+                     usage,
+                     cutoff_from,
+                     cutoff_to);
 
         if (r < 0)
                 return respond_oom(connection);
@@ -868,8 +900,9 @@ static int help(void) {
                "HTTP server for journal events.\n\n"
                "  -h --help           Show this help\n"
                "     --version        Show package version\n"
-               "     --cert=CERT.PEM  Specify server certificate in PEM format\n"
-               "     --key=KEY.PEM    Specify server key in PEM format\n",
+               "     --cert=CERT.PEM  Server certificate in PEM format\n"
+               "     --key=KEY.PEM    Server key in PEM format\n"
+               "     --trust=CERT.PEM Certificat authority certificate in PEM format\n",
                program_invocation_short_name);
 
         return 0;
@@ -877,12 +910,14 @@ static int help(void) {
 
 static char *key_pem = NULL;
 static char *cert_pem = NULL;
+static char *trust_pem = NULL;
 
 static int parse_argv(int argc, char *argv[]) {
         enum {
                 ARG_VERSION = 0x100,
                 ARG_KEY,
                 ARG_CERT,
+                ARG_TRUST,
         };
 
         int r, c;
@@ -892,22 +927,25 @@ static int parse_argv(int argc, char *argv[]) {
                 { "version", no_argument,       NULL, ARG_VERSION },
                 { "key",     required_argument, NULL, ARG_KEY     },
                 { "cert",    required_argument, NULL, ARG_CERT    },
-                { NULL,      0,                 NULL, 0           }
+                { "trust",   required_argument, NULL, ARG_TRUST   },
+                {}
         };
 
         assert(argc >= 0);
         assert(argv);
 
         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+
                 switch(c) {
+
+                case 'h':
+                        return help();
+
                 case ARG_VERSION:
                         puts(PACKAGE_STRING);
                         puts(SYSTEMD_FEATURES);
                         return 0;
 
-                case 'h':
-                        return help();
-
                 case ARG_KEY:
                         if (key_pem) {
                                 log_error("Key file specified twice");
@@ -934,12 +972,24 @@ static int parse_argv(int argc, char *argv[]) {
                         assert(cert_pem);
                         break;
 
+                case ARG_TRUST:
+                        if (trust_pem) {
+                                log_error("CA certificate file specified twice");
+                                return -EINVAL;
+                        }
+                        r = read_full_file(optarg, &trust_pem, NULL);
+                        if (r < 0) {
+                                log_error("Failed to read CA certificate file: %s", strerror(-r));
+                                return r;
+                        }
+                        assert(trust_pem);
+                        break;
+
                 case '?':
                         return -EINVAL;
 
                 default:
-                        log_error("Unknown option code %c", c);
-                        return -EINVAL;
+                        assert_not_reached("Unhandled option");
                 }
 
         if (optind < argc) {
@@ -952,6 +1002,11 @@ static int parse_argv(int argc, char *argv[]) {
                 return -EINVAL;
         }
 
+        if (trust_pem && !key_pem) {
+                log_error("CA certificate can only be used with certificate file");
+                return -EINVAL;
+        }
+
         return 1;
 }
 
@@ -969,6 +1024,11 @@ int main(int argc, char *argv[]) {
         if (r == 0)
                 return EXIT_SUCCESS;
 
+#ifdef HAVE_GNUTLS
+        gnutls_global_set_log_function(log_func_gnutls);
+        gnutls_global_set_log_level(GNUTLS_LOG_LEVEL);
+#endif
+
         n = sd_listen_fds(1);
         if (n < 0) {
                 log_error("Failed to determine passed sockets: %s", strerror(-n));
@@ -985,6 +1045,7 @@ int main(int argc, char *argv[]) {
                         { MHD_OPTION_END, 0, NULL },
                         { MHD_OPTION_END, 0, NULL },
                         { MHD_OPTION_END, 0, NULL },
+                        { MHD_OPTION_END, 0, NULL },
                         { MHD_OPTION_END, 0, NULL }};
                 int opts_pos = 2;
                 int flags = MHD_USE_THREAD_PER_CONNECTION|MHD_USE_POLL|MHD_USE_DEBUG;
@@ -1000,6 +1061,11 @@ int main(int argc, char *argv[]) {
                                 {MHD_OPTION_HTTPS_MEM_CERT, 0, cert_pem};
                         flags |= MHD_USE_SSL;
                 }
+                if (trust_pem) {
+                        assert(flags & MHD_USE_SSL);
+                        opts[opts_pos++] = (struct MHD_OptionItem)
+                                {MHD_OPTION_HTTPS_MEM_TRUST, 0, trust_pem};
+                }
 
                 d = MHD_start_daemon(flags, 19531,
                                      NULL, NULL,