]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
23769fb3 LP |
2 | |
3 | #include <unistd.h> | |
4 | ||
1e2f3230 | 5 | #include "cryptsetup-keyfile.h" |
23769fb3 LP |
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 | } |