1e2f32305c
"crypt-util.c" is such a generic name, let's avoid that, in particular as libc's/libcrypt's crypt() function is so generically named too that one might thing this is about that. Let's hence be more precise, and make clear that this is about cryptsetup, and nothing else. We already had cryptsetup-util.[ch] in src/cryptsetup/ doing keyfile management. To avoid the needless confusion, let's rename that file to cryptsetup-keyfile.[ch].
111 lines
3.9 KiB
C
111 lines
3.9 KiB
C
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
|
|
#include <unistd.h>
|
|
|
|
#include "cryptsetup-keyfile.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;
|
|
}
|