]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup-util.c
Merge pull request #15840 from Werkov/mkosi-opensuse
[thirdparty/systemd.git] / src / cryptsetup / cryptsetup-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <unistd.h>
4
5 #include "cryptsetup-util.h"
6 #include "fd-util.h"
7 #include "format-util.h"
8 #include "memory-util.h"
9 #include "path-util.h"
10 #include "stat-util.h"
11 #include "strv.h"
12
13 #define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */
14
15 int load_key_file(
16 const char *key_file,
17 char **search_path,
18 size_t key_file_size,
19 uint64_t key_file_offset,
20 void **ret_key,
21 size_t *ret_key_size) {
22
23 _cleanup_(erase_and_freep) char *buffer = NULL;
24 _cleanup_free_ char *discovered_path = NULL;
25 _cleanup_close_ int fd = -1;
26 ssize_t n;
27 int r;
28
29 assert(key_file);
30 assert(ret_key);
31 assert(ret_key_size);
32
33 if (strv_isempty(search_path) || path_is_absolute(key_file)) {
34 fd = open(key_file, O_RDONLY|O_CLOEXEC);
35 if (fd < 0)
36 return log_error_errno(errno, "Failed to load key file '%s': %m", key_file);
37 } else {
38 char **i;
39
40 STRV_FOREACH(i, search_path) {
41 _cleanup_free_ char *joined;
42
43 joined = path_join(*i, key_file);
44 if (!joined)
45 return log_oom();
46
47 fd = open(joined, O_RDONLY|O_CLOEXEC);
48 if (fd >= 0) {
49 discovered_path = TAKE_PTR(joined);
50 break;
51 }
52 if (errno != ENOENT)
53 return log_error_errno(errno, "Failed to load key file '%s': %m", joined);
54 }
55
56 if (!discovered_path) {
57 /* Search path supplied, but file not found, report by returning NULL, but not failing */
58 *ret_key = NULL;
59 *ret_key_size = 0;
60 return 0;
61 }
62
63 assert(fd >= 0);
64 key_file = discovered_path;
65 }
66
67 if (key_file_size == 0) {
68 struct stat st;
69
70 if (fstat(fd, &st) < 0)
71 return log_error_errno(errno, "Failed to stat key file '%s': %m", key_file);
72
73 r = stat_verify_regular(&st);
74 if (r < 0)
75 return log_error_errno(r, "Key file is not a regular file: %m");
76
77 if (st.st_size == 0)
78 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing.");
79 if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) {
80 char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
81 return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
82 "Key file larger (%s) than allowed maximum size (%s), refusing.",
83 format_bytes(buf1, sizeof(buf1), st.st_size),
84 format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX));
85 }
86
87 if (key_file_offset >= (uint64_t) st.st_size)
88 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing.");
89
90 key_file_size = st.st_size - key_file_offset;
91 }
92
93 buffer = malloc(key_file_size);
94 if (!buffer)
95 return log_oom();
96
97 if (key_file_offset > 0)
98 n = pread(fd, buffer, key_file_size, key_file_offset);
99 else
100 n = read(fd, buffer, key_file_size);
101 if (n < 0)
102 return log_error_errno(errno, "Failed to read key file '%s': %m", key_file);
103 if (n == 0)
104 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing.");
105
106 *ret_key = TAKE_PTR(buffer);
107 *ret_key_size = (size_t) n;
108
109 return 1;
110 }