chiark / gitweb /
journalctl: output FSS key as QR code on generating
[elogind.git] / src / journal / journalctl.c
index 0df8ce57fd78cae0486f90eade54f1eeaa59ec15..b0d8258dd213dda9428009baa3ccacf259a5301a 100644 (file)
@@ -30,6 +30,8 @@
 #include <time.h>
 #include <getopt.h>
 #include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
 
 #include <systemd/sd-journal.h>
 
@@ -44,6 +46,7 @@
 #include "journal-def.h"
 #include "journal-verify.h"
 #include "journal-authenticate.h"
+#include "journal-qrcode.h"
 #include "fsprg.h"
 
 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
@@ -60,7 +63,9 @@ static bool arg_this_boot = false;
 static const char *arg_directory = NULL;
 static int arg_priorities = 0xFF;
 static const char *arg_verify_key = NULL;
+#ifdef HAVE_GCRYPT
 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
+#endif
 
 static enum {
         ACTION_SHOW,
@@ -91,11 +96,13 @@ static int help(void) {
                "Commands:\n"
                "     --new-id128         Generate a new 128 Bit ID\n"
                "     --header            Show journal header information\n"
+#ifdef HAVE_GCRYPT
                "     --setup-keys        Generate new FSS key pair\n"
                "       --interval=TIME   Time interval for changing the FSS sealing key\n"
                "     --verify            Verify journal file consistency\n"
-               "       --verify-key=KEY  Specify FSS verification key\n",
-               program_invocation_short_name);
+               "       --verify-key=KEY  Specify FSS verification key\n"
+#endif
+               , program_invocation_short_name);
 
         return 0;
 }
@@ -213,13 +220,15 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_action = ACTION_PRINT_HEADER;
                         break;
 
+                case ARG_VERIFY:
+                        arg_action = ACTION_VERIFY;
+                        break;
+
+#ifdef HAVE_GCRYPT
                 case ARG_SETUP_KEYS:
                         arg_action = ACTION_SETUP_KEYS;
                         break;
 
-                case ARG_VERIFY:
-                        arg_action = ACTION_VERIFY;
-                        break;
 
                 case ARG_VERIFY_KEY:
                         arg_action = ACTION_VERIFY;
@@ -233,6 +242,13 @@ static int parse_argv(int argc, char *argv[]) {
                                 return -EINVAL;
                         }
                         break;
+#else
+                case ARG_SETUP_KEYS:
+                case ARG_VERIFY_KEY:
+                case ARG_INTERVAL:
+                        log_error("Forward-secure sealing not available.");
+                        return -ENOTSUP;
+#endif
 
                 case 'p': {
                         const char *dots;
@@ -453,7 +469,7 @@ static int setup_keys(void) {
         size_t mpk_size, seed_size, state_size, i;
         uint8_t *mpk, *seed, *state;
         ssize_t l;
-        int fd = -1, r;
+        int fd = -1, r, attr = 0;
         sd_id128_t machine, boot;
         char *p = NULL, *k = NULL;
         struct FSSHeader h;
@@ -476,7 +492,7 @@ static int setup_keys(void) {
                 return log_oom();
 
         if (access(p, F_OK) >= 0) {
-                log_error("Evolving key file %s exists already.", p);
+                log_error("Sealing key file %s exists already.", p);
                 r = -EEXIST;
                 goto finish;
         }
@@ -530,6 +546,16 @@ static int setup_keys(void) {
                 goto finish;
         }
 
+        /* Enable secure remove, exclusion from dump, synchronous
+         * writing and in-place updating */
+        if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
+                log_warning("FS_IOC_GETFLAGS failed: %m");
+
+        attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
+
+        if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
+                log_warning("FS_IOC_SETFLAGS failed: %m");
+
         zero(h);
         memcpy(h.signature, "KSHHRHLP", 8);
         h.machine_id = machine;
@@ -582,12 +608,26 @@ static int setup_keys(void) {
         printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
 
         if (isatty(STDOUT_FILENO)) {
-                char tsb[FORMAT_TIMESPAN_MAX];
+                char tsb[FORMAT_TIMESPAN_MAX], *hn;
 
                 fprintf(stderr,
                         ANSI_HIGHLIGHT_OFF "\n"
                         "The sealing key is automatically changed every %s.\n",
                         format_timespan(tsb, sizeof(tsb), arg_interval));
+
+                hn = gethostname_malloc();
+
+                if (hn) {
+                        hostname_cleanup(hn);
+                        fprintf(stderr, "The keys have been generated for host %s (" SD_ID128_FORMAT_STR ").\n", hn, SD_ID128_FORMAT_VAL(machine));
+                } else
+                        fprintf(stderr, "The keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
+
+#ifdef HAVE_QRENCODE
+                fputc('\n', stderr);
+                print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
+#endif
+                free(hn);
         }
 
         r = 0;
@@ -605,7 +645,8 @@ finish:
 
         return r;
 #else
-        log_error("Forward-secure journal verification not available.");
+        log_error("Forward-secure sealing not available.");
+        return -ENOTSUP;
 #endif
 }
 
@@ -618,21 +659,30 @@ static int verify(sd_journal *j) {
 
         HASHMAP_FOREACH(f, j->files, i) {
                 int k;
+                usec_t from, to, total;
 
 #ifdef HAVE_GCRYPT
-                if (!arg_verify_key && journal_file_fss_enabled(f))
+                if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
                         log_warning("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
 #endif
 
-                k = journal_file_verify(f, arg_verify_key);
+                k = journal_file_verify(f, arg_verify_key, &from, &to, &total, true);
                 if (k == -EINVAL) {
                         /* If the key was invalid give up right-away. */
                         return k;
                 } else if (k < 0) {
                         log_warning("FAIL: %s (%s)", f->path, strerror(-k));
                         r = k;
-                } else
+                } else {
+                        char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
                         log_info("PASS: %s", f->path);
+
+                        if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
+                                log_info("=> Validated from %s to %s, %s missing",
+                                         format_timestamp(a, sizeof(a), from),
+                                         format_timestamp(b, sizeof(b), to),
+                                         format_timespan(c, sizeof(c), total > to ? total - to : 0));
+                }
         }
 
         return r;