]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
cryptsetup: port cryptsetup's main key file logic over to read_full_file_full()
authorLennart Poettering <lennart@poettering.net>
Wed, 4 Nov 2020 16:24:53 +0000 (17:24 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 1 Dec 2020 13:17:47 +0000 (14:17 +0100)
Previously, we'd load the file with libcryptsetup's calls. Let's do that
in our own, so that we can make use of READ_FULL_FILE_CONNECT_SOCKET,
i.e. read in keys via AF_UNIX sockets, so that people can plug key
providers into our logic.

This provides functionality similar to Debian's keyscript= crypttab
option (see → #3007), as it allows key scripts to be run as socket
activated services, that have stdout connected to the activated socket.
In contrast to traditional keyscript= support this logic runs stuff out
of process however, which is beneficial, since it allows sandboxing and
similar.

src/cryptsetup/cryptsetup.c

index 7f95749f2fadbb2010bca1382092000aacc7008b..e32cc9207c28a48e6d75aa12390b5be542bddfc7 100644 (file)
@@ -29,6 +29,7 @@
 #include "path-util.h"
 #include "pkcs11-util.h"
 #include "pretty-print.h"
+#include "random-util.h"
 #include "string-util.h"
 #include "strv.h"
 
@@ -550,6 +551,15 @@ static int attach_tcrypt(
         return 0;
 }
 
+static char *make_bindname(const char *volume) {
+        char *s;
+
+        if (asprintf(&s, "@%" PRIx64"/cryptsetup/%s", random_u64(), volume) < 0)
+                return NULL;
+
+        return s;
+}
+
 static int attach_luks_or_plain_or_bitlk(
                 struct crypt_device *cd,
                 const char *name,
@@ -736,13 +746,30 @@ static int attach_luks_or_plain_or_bitlk(
                         return log_error_errno(r, "Failed to activate: %m");
 
         } else if (key_file) {
-                r = crypt_activate_by_keyfile_device_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
-                if (r == -EPERM) {
-                        log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
+                _cleanup_(erase_and_freep) char *kfdata = NULL;
+                _cleanup_free_ char *bindname = NULL;
+                size_t kfsize;
+
+                /* If we read the key via AF_UNIX, make this client recognizable */
+                bindname = make_bindname(name);
+                if (!bindname)
+                        return log_oom();
+
+                r = read_full_file_full(
+                                AT_FDCWD, key_file,
+                                arg_keyfile_offset == 0 ? UINT64_MAX : arg_keyfile_offset,
+                                arg_keyfile_size == 0 ? SIZE_MAX : arg_keyfile_size,
+                                READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
+                                bindname,
+                                &kfdata, &kfsize);
+                if (r == -ENOENT) {
+                        log_error_errno(r, "Failed to activate, key file '%s' missing.", key_file);
                         return -EAGAIN; /* Log actual error, but return EAGAIN */
                 }
-                if (r == -EINVAL) {
-                        log_error_errno(r, "Failed to activate with key file '%s'. (Key file missing?)", key_file);
+
+                r = crypt_activate_by_passphrase(cd, name, arg_key_slot, kfdata, kfsize, flags);
+                if (r == -EPERM) {
+                        log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
                         return -EAGAIN; /* Log actual error, but return EAGAIN */
                 }
                 if (r < 0)