]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
creds-util: add new helper read_credential_with_decryption()
authorLennart Poettering <lennart@poettering.net>
Fri, 23 Jun 2023 19:48:15 +0000 (21:48 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 4 Jul 2023 20:59:57 +0000 (22:59 +0200)
This is just like read_credential() but also looks into the encrypted
credential directory, not just the regular one.

Normally, we decrypt credentials at the moment we pass them to services.
From service PoV all credentials are hence decrypted credentials.

However, when we want to access credentials in a generator this logic
does not apply: here we have the regular and the encrypted credentials
directory. So far we didn't attempt to make use of credentials in
generators hence.

Let's address and add helper that looks into both directories, and talks
to the TPM if necessary to decrypt the credentials.

src/shared/creds-util.c
src/shared/creds-util.h

index 83a4c84aa9a4f8a0b12f5ed5166074de5039f881..f54481e9b466cf3fcd556c3218eec7ac3727a1e1 100644 (file)
@@ -125,6 +125,80 @@ int read_credential(const char *name, void **ret, size_t *ret_size) {
                         (char**) ret, ret_size);
 }
 
+int read_credential_with_decryption(const char *name, void **ret, size_t *ret_size) {
+        _cleanup_(erase_and_freep) void *data = NULL;
+        _cleanup_free_ char *fn = NULL;
+        size_t sz = 0;
+        const char *d;
+        int r;
+
+        assert(ret);
+
+        /* Just like read_credential() but will also look for encrypted credentials. Note that services only
+         * receive decrypted credentials, hence use read_credential() for those. This helper here is for
+         * generators, i.e. code that runs outside of service context, and thus has no decrypted credentials
+         * yet.
+         *
+         * Note that read_credential_harder_and_warn() logs on its own, while read_credential() does not!
+         * (It's a lot more complex and error prone given its TPM2 connectivty, and is generally called from
+         * generators only where logging is OK).
+         *
+         * Error handling is also a bit different: if we can't find a credential we'll return 0 and NULL
+         * pointers/zero size, rather than -ENXIO/-ENOENT. */
+
+        if (!credential_name_valid(name))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid credential name: %s", name);
+
+        r = read_credential(name, ret, ret_size);
+        if (r >= 0)
+                return 1; /* found */
+        if (!IN_SET(r, -ENXIO, -ENOENT))
+                return log_error_errno(r, "Failed read unencrypted credential '%s': %m", name);
+
+        r = get_encrypted_credentials_dir(&d);
+        if (r == -ENXIO)
+                goto not_found;
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine encrypted credentials directory: %m");
+
+        fn = path_join(d, name);
+        if (!fn)
+                return log_oom();
+
+        r = read_full_file_full(
+                        AT_FDCWD, fn,
+                        UINT64_MAX, SIZE_MAX,
+                        READ_FULL_FILE_SECURE,
+                        NULL,
+                        (char**) data, &sz);
+        if (r == -ENOENT)
+                goto not_found;
+        if (r < 0)
+                return log_error_errno(r, "Failed to read encrypted credential data: %m");
+
+        r = decrypt_credential_and_warn(
+                        name,
+                        now(CLOCK_REALTIME),
+                        /* tpm2_device = */ NULL,
+                        /* tpm2_signature_path = */ NULL,
+                        data,
+                        sz,
+                        ret,
+                        ret_size);
+        if (r < 0)
+                return r;
+
+        return 1; /* found */
+
+not_found:
+        *ret = NULL;
+
+        if (ret_size)
+                *ret_size = 0;
+
+        return 0; /* not found */
+}
+
 int read_credential_strings_many_internal(
                 const char *first_name, char **first_value,
                 ...) {
index 1742678cb95c3149d31137729d74973974e9c4e5..8fbd61e9fe6b48780e0a1cc145116d27aa8f73fd 100644 (file)
@@ -35,7 +35,8 @@ int get_encrypted_credentials_dir(const char **ret);
 #define SYSTEM_CREDENTIALS_DIRECTORY "/run/credentials/@system"
 #define ENCRYPTED_SYSTEM_CREDENTIALS_DIRECTORY "/run/credentials/@encrypted"
 
-int read_credential(const char *name, void **ret, size_t *ret_size);
+int read_credential(const char *name, void **ret, size_t *ret_size); /* use in services! */
+int read_credential_with_decryption(const char *name, void **ret, size_t *ret_size); /* use in generators + pid1! */
 
 int read_credential_strings_many_internal(const char *first_name, char **first_value, ...);