From feb12d3ed2c7f9132c64773c7c41b9e3a608a814 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 20 Aug 2012 16:51:46 +0200 Subject: [PATCH] journal: make libgcrypt dependency optional --- Makefile.am | 4 +- README | 1 + TODO | 6 --- configure.ac | 2 +- src/core/build.h | 20 ++++++++- src/journal/journal-authenticate.c | 57 ++++++++++++++++++++++-- src/journal/journal-authenticate.h | 2 +- src/journal/journal-file.c | 18 ++++++++ src/journal/journal-verify.c | 71 +++++------------------------- src/journal/journalctl.c | 30 +++++++++---- src/journal/test-journal-verify.c | 7 +-- src/journal/test-journal.c | 2 + 12 files changed, 134 insertions(+), 86 deletions(-) diff --git a/Makefile.am b/Makefile.am index 3eeb842afe6..166c357db2d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2402,8 +2402,6 @@ libsystemd_journal_la_SOURCES = \ src/journal/journal-vacuum.h \ src/journal/journal-verify.c \ src/journal/journal-verify.h \ - src/journal/journal-authenticate.c \ - src/journal/journal-authenticate.h \ src/journal/lookup3.c \ src/journal/lookup3.h \ src/journal/journal-send.c \ @@ -2455,6 +2453,8 @@ endif if HAVE_GCRYPT libsystemd_journal_la_SOURCES += \ + src/journal/journal-authenticate.c \ + src/journal/journal-authenticate.h \ src/journal/fsprg.c \ src/journal/fsprg.h diff --git a/README b/README index a5d569028df..334c5972139 100644 --- a/README +++ b/README @@ -42,6 +42,7 @@ REQUIREMENTS: libcap PAM >= 1.1.2 (optional) libcryptsetup (optional) + libgcrypt (optional) libaudit (optional) libacl (optional) libselinux (optional) diff --git a/TODO b/TODO index 875a3db4d6a..e16db6fa4d4 100644 --- a/TODO +++ b/TODO @@ -254,8 +254,6 @@ Features: * cleanup syslog 'priority' vs. 'level' wording -* journal: if mmap() fails for mapping window try to unmap a a few older maps - * dbus upstream still refers to dbus.target and shouldn't * when a service has the same env var set twice we actually store it twice and return that in systemctl show -p... We should only show the last setting @@ -300,8 +298,6 @@ Features: * journal: message catalog -* journal: forward-secure signatures - * document the exit codes when services fail before they are exec()ed * systemctl journal command @@ -503,6 +499,4 @@ Scheduled for removal (or fixing): * xxxOverridable dependencies -* journald.conf: ImportKernel= - * prefdm.service diff --git a/configure.ac b/configure.ac index c1e88daa3f1..3df43b91fd2 100644 --- a/configure.ac +++ b/configure.ac @@ -302,7 +302,7 @@ AC_SUBST(ACL_LIBS) AM_CONDITIONAL([HAVE_ACL], [test "x$have_acl" != xno]) # ------------------------------------------------------------------------------ -AC_ARG_ENABLE([], +AC_ARG_ENABLE([gcrypt], AS_HELP_STRING([--disable-gcrypt],[Disable optional GCRYPT support]), [case "${enableval}" in yes) have_gcrypt=yes ;; diff --git a/src/core/build.h b/src/core/build.h index 0b38050bd48..4513a0bad72 100644 --- a/src/core/build.h +++ b/src/core/build.h @@ -63,4 +63,22 @@ #define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP" #endif -#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ +#ifdef HAVE_GCRYPT +#define _GCRYPT_FEATURE_ "+GCRYPT" +#else +#define _GCRYPT_FEATURE_ "-GCRYPT" +#endif + +#ifdef HAVE_ACL +#define _ACL_FEATURE_ "+ACL" +#else +#define _ACL_FEATURE_ "-ACL" +#endif + +#ifdef HAVE_XZ +#define _XZ_FEATURE_ "+XZ" +#else +#define _XZ_FEATURE_ "-XZ" +#endif + +#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ " " _GCRYPT_FEATURE_ " " _ACL_FEATURE_ " " _XZ_FEATURE_ diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index ddcf856aec1..93cc9d94a18 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -461,8 +461,59 @@ int journal_file_append_first_tag(JournalFile *f) { return 0; } -bool journal_file_fss_enabled(JournalFile *f) { - assert(f); - return JOURNAL_HEADER_SEALED(f->header); +int journal_file_parse_verification_key(JournalFile *f, const char *key) { + uint8_t *seed; + size_t seed_size, c; + const char *k; + int r; + unsigned long long start, interval; + + seed_size = FSPRG_RECOMMENDED_SEEDLEN; + seed = malloc(seed_size); + if (!seed) + return -ENOMEM; + + k = key; + for (c = 0; c < seed_size; c++) { + int x, y; + + while (*k == '-') + k++; + + x = unhexchar(*k); + if (x < 0) { + free(seed); + return -EINVAL; + } + k++; + y = unhexchar(*k); + if (y < 0) { + free(seed); + return -EINVAL; + } + k++; + + seed[c] = (uint8_t) (x * 16 + y); + } + + if (*k != '/') { + free(seed); + return -EINVAL; + } + k++; + + r = sscanf(k, "%llx-%llx", &start, &interval); + if (r != 2) { + free(seed); + return -EINVAL; + } + + f->fsprg_seed = seed; + f->fsprg_seed_size = seed_size; + + f->fss_start_usec = start * interval; + f->fss_interval_usec = interval; + + return 0; } diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h index 4f4f45b1143..447c7b4657f 100644 --- a/src/journal/journal-authenticate.h +++ b/src/journal/journal-authenticate.h @@ -36,7 +36,7 @@ int journal_file_hmac_put_header(JournalFile *f); int journal_file_hmac_put_object(JournalFile *f, int type, uint64_t p); int journal_file_fss_load(JournalFile *f); -bool journal_file_fss_enabled(JournalFile *f); +int journal_file_parse_verification_key(JournalFile *f, const char *key); int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime); int journal_file_fsprg_seek(JournalFile *f, uint64_t epoch); diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 760efaebbb2..f01f12496cd 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -64,9 +64,11 @@ void journal_file_close(JournalFile *f) { assert(f); +#ifdef HAVE_GCRYPT /* Write the final tag */ if (f->seal && f->writable) journal_file_append_tag(f); +#endif /* Sync everything to disk, before we mark the file offline */ if (f->mmap && f->fd >= 0) @@ -764,9 +766,11 @@ static int journal_file_append_data( if (r < 0) return r; +#ifdef HAVE_GCRYPT r = journal_file_hmac_put_object(f, OBJECT_DATA, p); if (r < 0) return r; +#endif /* The linking might have altered the window, so let's * refresh our pointer */ @@ -852,9 +856,11 @@ static int link_entry_into_array(JournalFile *f, if (r < 0) return r; +#ifdef HAVE_GCRYPT r = journal_file_hmac_put_object(f, OBJECT_ENTRY_ARRAY, q); if (r < 0) return r; +#endif o->entry_array.items[i] = htole64(p); @@ -996,9 +1002,11 @@ static int journal_file_append_entry_internal( o->entry.xor_hash = htole64(xor_hash); o->entry.boot_id = f->header->boot_id; +#ifdef HAVE_GCRYPT r = journal_file_hmac_put_object(f, OBJECT_ENTRY, np); if (r < 0) return r; +#endif r = journal_file_link_entry(f, o, np); if (r < 0) @@ -1049,9 +1057,11 @@ int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const st ts->monotonic < le64toh(f->header->tail_entry_monotonic)) return -EINVAL; +#ifdef HAVE_GCRYPT r = journal_file_maybe_append_tag(f, ts->realtime); if (r < 0) return r; +#endif /* alloca() can't take 0, hence let's allocate at least one */ items = alloca(sizeof(EntryItem) * MAX(1, n_iovec)); @@ -2030,11 +2040,13 @@ int journal_file_open( if (f->last_stat.st_size == 0 && f->writable) { newly_created = true; +#ifdef HAVE_GCRYPT /* Try to load the FSPRG state, and if we can't, then * just don't do sealing */ r = journal_file_fss_load(f); if (r < 0) f->seal = false; +#endif r = journal_file_init_header(f, template); if (r < 0) @@ -2064,11 +2076,13 @@ int journal_file_open( goto fail; } +#ifdef HAVE_GCRYPT if (!newly_created && f->writable) { r = journal_file_fss_load(f); if (r < 0) goto fail; } +#endif if (f->writable) { if (metrics) { @@ -2082,9 +2096,11 @@ int journal_file_open( goto fail; } +#ifdef HAVE_GCRYPT r = journal_file_hmac_setup(f); if (r < 0) goto fail; +#endif if (newly_created) { r = journal_file_setup_field_hash_table(f); @@ -2095,9 +2111,11 @@ int journal_file_open( if (r < 0) goto fail; +#ifdef HAVE_GCRYPT r = journal_file_append_first_tag(f); if (r < 0) goto fail; +#endif } r = journal_file_map_field_hash_table(f); diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index 6afeab9a80b..a76384bdb23 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "util.h" #include "macro.h" @@ -37,7 +38,6 @@ * * - evolve key even if nothing happened in regular intervals * - * - Allow building without libgcrypt * - check with sparse * - 64bit conversions * @@ -645,62 +645,6 @@ static int verify_entry_array( return 0; } -static int journal_file_parse_verification_key(JournalFile *f, const char *key) { - uint8_t *seed; - size_t seed_size, c; - const char *k; - int r; - unsigned long long start, interval; - - seed_size = FSPRG_RECOMMENDED_SEEDLEN; - seed = malloc(seed_size); - if (!seed) - return -ENOMEM; - - k = key; - for (c = 0; c < seed_size; c++) { - int x, y; - - while (*k == '-') - k++; - - x = unhexchar(*k); - if (x < 0) { - free(seed); - return -EINVAL; - } - k++; - y = unhexchar(*k); - if (y < 0) { - free(seed); - return -EINVAL; - } - k++; - - seed[c] = (uint8_t) (x * 16 + y); - } - - if (*k != '/') { - free(seed); - return -EINVAL; - } - k++; - - r = sscanf(k, "%llx-%llx", &start, &interval); - if (r != 2) { - free(seed); - return -EINVAL; - } - - f->fsprg_seed = seed; - f->fsprg_seed_size = seed_size; - - f->fss_start_usec = start * interval; - f->fss_interval_usec = interval; - - return 0; -} - int journal_file_verify( JournalFile *f, const char *key, @@ -724,11 +668,15 @@ int journal_file_verify( assert(f); if (key) { +#ifdef HAVE_GCRYPT r = journal_file_parse_verification_key(f, key); if (r < 0) { log_error("Failed to parse seed."); return r; } +#else + return -ENOTSUP; +#endif } else if (f->seal) return -ENOKEY; @@ -936,9 +884,7 @@ int journal_file_verify( n_entry_arrays++; break; - case OBJECT_TAG: { - uint64_t q, rt; - + case OBJECT_TAG: if (!JOURNAL_HEADER_SEALED(f->header)) { log_error("Tag object in file without sealing at %llu", (unsigned long long) p); r = -EBADMSG; @@ -957,7 +903,10 @@ int journal_file_verify( goto fail; } +#ifdef HAVE_GCRYPT if (f->seal) { + uint64_t q, rt; + log_debug("Checking tag %llu..", (unsigned long long) le64toh(o->tag.seqnum)); rt = f->fss_start_usec + o->tag.epoch * f->fss_interval_usec; @@ -1014,13 +963,13 @@ int journal_file_verify( last_tag_realtime = rt; last_sealed_realtime = entry_realtime; } +#endif last_tag = p + ALIGN64(le64toh(o->object.size)); last_epoch = le64toh(o->tag.epoch); n_tags ++; break; - } default: n_weird ++; diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index e61ddf6d924..551cb311b54 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -62,7 +62,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, @@ -93,11 +95,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; } @@ -215,13 +219,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; @@ -235,6 +241,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; @@ -617,7 +630,8 @@ finish: return r; #else - log_error("Forward-secure journal verification not available."); + log_error("Forward-secure sealing not available."); + return -ENOTSUP; #endif } @@ -633,7 +647,7 @@ static int verify(sd_journal *j) { 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 @@ -648,7 +662,7 @@ static int verify(sd_journal *j) { char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX]; log_info("PASS: %s", f->path); - if (arg_verify_key && journal_file_fss_enabled(f)) + 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), diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index ed6e21dc0c5..b6677215c05 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -55,7 +55,7 @@ static int raw_verify(const char *fn, const char *verification_key) { JournalFile *f; int r; - r = journal_file_open(fn, O_RDONLY, 0666, true, true, NULL, NULL, NULL, &f); + r = journal_file_open(fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f); if (r < 0) return r; @@ -107,18 +107,19 @@ int main(int argc, char *argv[]) { log_info("Verifying..."); - assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, true, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0); /* journal_file_print_header(f); */ journal_file_dump(f); assert_se(journal_file_verify(f, verification_key, &from, &to, &total, true) >= 0); - if (verification_key && journal_file_fss_enabled(f)) { + if (verification_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)); } + journal_file_close(f); if (verification_key) { diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index 05bb2ea8ed8..22735001001 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -59,7 +59,9 @@ int main(int argc, char *argv[]) { iovec.iov_len = strlen(test); assert_se(journal_file_append_entry(f, &ts, &iovec, 1, NULL, NULL, NULL) == 0); +#ifdef HAVE_GCRYPT journal_file_append_tag(f); +#endif journal_file_dump(f); assert(journal_file_next_entry(f, NULL, 0, DIRECTION_DOWN, &o, &p) == 1);