]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cryptsetup: split out key loading from pkcs11 code and teach search path logic
authorLennart Poettering <lennart@poettering.net>
Wed, 29 Apr 2020 12:50:38 +0000 (14:50 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 19 May 2020 15:28:16 +0000 (17:28 +0200)
Let's do some rearrangements, so that we can later on use this to
automatically search for a key file.

meson.build
src/cryptsetup/cryptsetup-pkcs11.c
src/cryptsetup/cryptsetup-util.c [new file with mode: 0644]
src/cryptsetup/cryptsetup-util.h [new file with mode: 0644]

index 121148f8dd367b96178a6e185c0d9cd3e565b1b6..f485616d10df13693811a01ccf23e6efc554c67e 100644 (file)
@@ -2227,8 +2227,10 @@ executable(
 
 if conf.get('HAVE_LIBCRYPTSETUP') == 1
         systemd_cryptsetup_sources = files('''
-                src/cryptsetup/cryptsetup.c
                 src/cryptsetup/cryptsetup-pkcs11.h
+                src/cryptsetup/cryptsetup-util.c
+                src/cryptsetup/cryptsetup-util.h
+                src/cryptsetup/cryptsetup.c
 '''.split())
 
         if conf.get('HAVE_P11KIT') == 1
index ec9186a6aaa527fd59b0dfc425f48553cf6b11af..97a8c68ee8b229ee8bb028f8ca76fadec8b238ad 100644 (file)
@@ -10,6 +10,7 @@
 #include "alloc-util.h"
 #include "ask-password-api.h"
 #include "cryptsetup-pkcs11.h"
+#include "cryptsetup-util.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "format-util.h"
 #include "stat-util.h"
 #include "strv.h"
 
-#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
-
-static int load_key_file(
-                const char *key_file,
-                size_t key_file_size,
-                uint64_t key_file_offset,
-                void **ret_encrypted_key,
-                size_t *ret_encrypted_key_size) {
-
-        _cleanup_(erase_and_freep) char *buffer = NULL;
-        _cleanup_close_ int fd = -1;
-        ssize_t n;
-        int r;
-
-        assert(key_file);
-        assert(ret_encrypted_key);
-        assert(ret_encrypted_key_size);
-
-        fd = open(key_file, O_RDONLY|O_CLOEXEC);
-        if (fd < 0)
-                return log_error_errno(errno, "Failed to load encrypted PKCS#11 key: %m");
-
-        if (key_file_size == 0) {
-                struct stat st;
-
-                if (fstat(fd, &st) < 0)
-                        return log_error_errno(errno, "Failed to stat key file: %m");
-
-                r = stat_verify_regular(&st);
-                if (r < 0)
-                        return log_error_errno(r, "Key file is not a regular file: %m");
-
-                if (st.st_size == 0)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
-                if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
-                        char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
-                        return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
-                                               "Key file larger (%s) than allowed maximum size (%s), refusing.",
-                                               format_bytes(buf1, sizeof(buf1), st.st_size),
-                                               format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
-                }
-
-                if (key_file_offset >= (uint64_t) st.st_size)
-                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
-
-                key_file_size = st.st_size - key_file_offset;
-        }
-
-        buffer = malloc(key_file_size);
-        if (!buffer)
-                return log_oom();
-
-        if (key_file_offset > 0)
-                n = pread(fd, buffer, key_file_size, key_file_offset);
-        else
-                n = read(fd, buffer, key_file_size);
-        if (n < 0)
-                return log_error_errno(errno, "Failed to read PKCS#11 key file: %m");
-        if (n == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
-
-        *ret_encrypted_key = TAKE_PTR(buffer);
-        *ret_encrypted_key_size = (size_t) n;
-
-        return 0;
-}
-
 struct pkcs11_callback_data {
         const char *friendly_name;
         usec_t until;
@@ -181,7 +115,7 @@ int decrypt_pkcs11_key(
 
         /* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
 
-        r = load_key_file(key_file, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
+        r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size);
         if (r < 0)
                 return r;
 
diff --git a/src/cryptsetup/cryptsetup-util.c b/src/cryptsetup/cryptsetup-util.c
new file mode 100644 (file)
index 0000000..8ae70a5
--- /dev/null
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <unistd.h>
+
+#include "cryptsetup-util.h"
+#include "fd-util.h"
+#include "format-util.h"
+#include "memory-util.h"
+#include "path-util.h"
+#include "stat-util.h"
+#include "strv.h"
+
+#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
+
+int load_key_file(
+                const char *key_file,
+                char **search_path,
+                size_t key_file_size,
+                uint64_t key_file_offset,
+                void **ret_key,
+                size_t *ret_key_size) {
+
+        _cleanup_(erase_and_freep) char *buffer = NULL;
+        _cleanup_free_ char *discovered_path = NULL;
+        _cleanup_close_ int fd = -1;
+        ssize_t n;
+        int r;
+
+        assert(key_file);
+        assert(ret_key);
+        assert(ret_key_size);
+
+        if (strv_isempty(search_path) || path_is_absolute(key_file)) {
+                fd = open(key_file, O_RDONLY|O_CLOEXEC);
+                if (fd < 0)
+                        return log_error_errno(errno, "Failed to load key file '%s': %m", key_file);
+        } else {
+                char **i;
+
+                STRV_FOREACH(i, search_path) {
+                        _cleanup_free_ char *joined;
+
+                        joined = path_join(*i, key_file);
+                        if (!joined)
+                                return log_oom();
+
+                        fd = open(joined, O_RDONLY|O_CLOEXEC);
+                        if (fd >= 0) {
+                                discovered_path = TAKE_PTR(joined);
+                                break;
+                        }
+                        if (errno != ENOENT)
+                                return log_error_errno(errno, "Failed to load key file '%s': %m", joined);
+                }
+
+                if (!discovered_path) {
+                        /* Search path supplied, but file not found, report by returning NULL, but not failing */
+                        *ret_key = NULL;
+                        *ret_key_size = 0;
+                        return 0;
+                }
+
+                assert(fd >= 0);
+                key_file = discovered_path;
+        }
+
+        if (key_file_size == 0) {
+                struct stat st;
+
+                if (fstat(fd, &st) < 0)
+                        return log_error_errno(errno, "Failed to stat key file '%s': %m", key_file);
+
+                r = stat_verify_regular(&st);
+                if (r < 0)
+                        return log_error_errno(r, "Key file is not a regular file: %m");
+
+                if (st.st_size == 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
+                if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
+                        char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
+                        return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
+                                               "Key file larger (%s) than allowed maximum size (%s), refusing.",
+                                               format_bytes(buf1, sizeof(buf1), st.st_size),
+                                               format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
+                }
+
+                if (key_file_offset >= (uint64_t) st.st_size)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
+
+                key_file_size = st.st_size - key_file_offset;
+        }
+
+        buffer = malloc(key_file_size);
+        if (!buffer)
+                return log_oom();
+
+        if (key_file_offset > 0)
+                n = pread(fd, buffer, key_file_size, key_file_offset);
+        else
+                n = read(fd, buffer, key_file_size);
+        if (n < 0)
+                return log_error_errno(errno, "Failed to read key file '%s': %m", key_file);
+        if (n == 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
+
+        *ret_key = TAKE_PTR(buffer);
+        *ret_key_size = (size_t) n;
+
+        return 1;
+}
diff --git a/src/cryptsetup/cryptsetup-util.h b/src/cryptsetup/cryptsetup-util.h
new file mode 100644 (file)
index 0000000..7bb7822
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+int load_key_file(
+                const char *key_file,
+                char **search_path,
+                size_t key_file_size,
+                uint64_t key_file_offset,
+                void **ret_key,
+                size_t *ret_key_size);