Bug Summary

File:build-scan/../src/cryptsetup/cryptsetup.c
Warning:line 259, column 19
Potential leak of memory pointed to by 'o'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name cryptsetup.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -menable-no-infs -menable-no-nans -menable-unsafe-fp-math -fno-signed-zeros -mreassociate -freciprocal-math -fdenormal-fp-math=preserve-sign,preserve-sign -ffp-contract=fast -fno-rounding-math -ffast-math -ffinite-math-only -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/12.0.0 -include config.h -I systemd-cryptsetup.p -I . -I .. -I src/basic -I ../src/basic -I src/shared -I ../src/shared -I src/systemd -I ../src/systemd -I src/journal -I ../src/journal -I src/journal-remote -I ../src/journal-remote -I src/nspawn -I ../src/nspawn -I src/resolve -I ../src/resolve -I src/timesync -I ../src/timesync -I ../src/time-wait-sync -I src/login -I ../src/login -I src/udev -I ../src/udev -I src/libudev -I ../src/libudev -I src/core -I ../src/core -I ../src/libsystemd/sd-bus -I ../src/libsystemd/sd-device -I ../src/libsystemd/sd-hwdb -I ../src/libsystemd/sd-id128 -I ../src/libsystemd/sd-netlink -I ../src/libsystemd/sd-network -I src/libsystemd-network -I ../src/libsystemd-network -D _FILE_OFFSET_BITS=64 -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/12.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wwrite-strings -Wno-unused-parameter -Wno-missing-field-initializers -Wno-unused-result -Wno-format-signedness -Wno-error=nonnull -std=gnu99 -fconst-strings -fdebug-compilation-dir /home/mrc0mmand/repos/@redhat-plumbers/systemd-rhel8/build-scan -ferror-limit 19 -fvisibility hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -analyzer-output=html -faddrsig -o /tmp/scan-build-2021-07-16-221226-1465241-1 -x c ../src/cryptsetup/cryptsetup.c
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include <errno(*__errno_location ()).h>
4#include <mntent.h>
5#include <string.h>
6#include <sys/mman.h>
7
8#include "sd-device.h"
9
10#include "alloc-util.h"
11#include "ask-password-api.h"
12#include "crypt-util.h"
13#include "device-util.h"
14#include "escape.h"
15#include "fileio.h"
16#include "log.h"
17#include "mount-util.h"
18#include "parse-util.h"
19#include "path-util.h"
20#include "string-util.h"
21#include "strv.h"
22#include "util.h"
23
24/* internal helper */
25#define ANY_LUKS"LUKS" "LUKS"
26/* as in src/cryptsetup.h */
27#define CRYPT_SECTOR_SIZE512 512
28#define CRYPT_MAX_SECTOR_SIZE4096 4096
29
30static const char *arg_type = NULL((void*)0); /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT or CRYPT_PLAIN */
31static char *arg_cipher = NULL((void*)0);
32static unsigned arg_key_size = 0;
33#if HAVE_LIBCRYPTSETUP_SECTOR_SIZE1
34static unsigned arg_sector_size = CRYPT_SECTOR_SIZE512;
35#endif
36static int arg_key_slot = CRYPT_ANY_SLOT-1;
37static unsigned arg_keyfile_size = 0;
38static uint64_t arg_keyfile_offset = 0;
39static char *arg_hash = NULL((void*)0);
40static char *arg_header = NULL((void*)0);
41static unsigned arg_tries = 3;
42static bool_Bool arg_readonly = false0;
43static bool_Bool arg_verify = false0;
44static bool_Bool arg_discards = false0;
45static bool_Bool arg_tcrypt_hidden = false0;
46static bool_Bool arg_tcrypt_system = false0;
47#ifdef CRYPT_TCRYPT_VERA_MODES(1 << 4)
48static bool_Bool arg_tcrypt_veracrypt = false0;
49#endif
50static char **arg_tcrypt_keyfiles = NULL((void*)0);
51static uint64_t arg_offset = 0;
52static uint64_t arg_skip = 0;
53static usec_t arg_timeout = USEC_INFINITY((usec_t) -1);
54
55/* Options Debian's crypttab knows we don't:
56
57 precheck=
58 check=
59 checkargs=
60 noearly=
61 loud=
62 keyscript=
63*/
64
65static int parse_one_option(const char *option) {
66 const char *val;
67 int r;
68
69 assert(option)do { if ((__builtin_expect(!!(!(option)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("option"), "../src/cryptsetup/cryptsetup.c"
, 69, __PRETTY_FUNCTION__); } while (0)
;
70
71 /* Handled outside of this tool */
72 if (STR_IN_SET(option, "noauto", "auto", "nofail", "fail", "_netdev", "keyfile-timeout")(!!strv_find((((char**) ((const char*[]) { "noauto", "auto", "nofail"
, "fail", "_netdev", "keyfile-timeout", ((void*)0) }))), (option
)))
)
73 return 0;
74
75 if (startswith(option, "keyfile-timeout="))
76 return 0;
77
78 if ((val = startswith(option, "cipher="))) {
79 r = free_and_strdup(&arg_cipher, val);
80 if (r < 0)
81 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup.c"
, 81, __func__)
;
82
83 } else if ((val = startswith(option, "size="))) {
84
85 r = safe_atou(val, &arg_key_size);
86 if (r < 0) {
87 log_error_errno(r, "Failed to parse %s, ignoring: %m", option)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 87, __func__, "Failed to parse %s, ignoring: %m"
, option) : -abs(_e); })
;
88 return 0;
89 }
90
91 if (arg_key_size % 8) {
92 log_error("size= not a multiple of 8, ignoring.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 92, __func__, "size= not a multiple of 8, ignoring."
) : -abs(_e); })
;
93 return 0;
94 }
95
96 arg_key_size /= 8;
97
98 } else if ((val = startswith(option, "sector-size="))) {
99
100#if HAVE_LIBCRYPTSETUP_SECTOR_SIZE1
101 r = safe_atou(val, &arg_sector_size);
102 if (r < 0) {
103 log_error_errno(r, "Failed to parse %s, ignoring: %m", option)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 103, __func__, "Failed to parse %s, ignoring: %m"
, option) : -abs(_e); })
;
104 return 0;
105 }
106
107 if (arg_sector_size % 2) {
108 log_error("sector-size= not a multiple of 2, ignoring.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 108, __func__, "sector-size= not a multiple of 2, ignoring."
) : -abs(_e); })
;
109 return 0;
110 }
111
112 if (arg_sector_size < CRYPT_SECTOR_SIZE512 || arg_sector_size > CRYPT_MAX_SECTOR_SIZE4096) {
113 log_error("sector-size= is outside of %u and %u, ignoring.", CRYPT_SECTOR_SIZE, CRYPT_MAX_SECTOR_SIZE)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 113, __func__, "sector-size= is outside of %u and %u, ignoring."
, 512, 4096) : -abs(_e); })
;
114 return 0;
115 }
116#else
117 log_error("sector-size= is not supported, compiled with old libcryptsetup.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 117, __func__, "sector-size= is not supported, compiled with old libcryptsetup."
) : -abs(_e); })
;
118 return 0;
119#endif
120
121 } else if ((val = startswith(option, "key-slot="))) {
122
123 arg_type = ANY_LUKS"LUKS";
124 r = safe_atoi(val, &arg_key_slot);
125 if (r < 0) {
126 log_error_errno(r, "Failed to parse %s, ignoring: %m", option)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 126, __func__, "Failed to parse %s, ignoring: %m"
, option) : -abs(_e); })
;
127 return 0;
128 }
129
130 } else if ((val = startswith(option, "tcrypt-keyfile="))) {
131
132 arg_type = CRYPT_TCRYPT"TCRYPT";
133 if (path_is_absolute(val)) {
134 if (strv_extend(&arg_tcrypt_keyfiles, val) < 0)
135 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup.c"
, 135, __func__)
;
136 } else
137 log_error("Key file path \"%s\" is not absolute. Ignoring.", val)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 137, __func__, "Key file path \"%s\" is not absolute. Ignoring."
, val) : -abs(_e); })
;
138
139 } else if ((val = startswith(option, "keyfile-size="))) {
140
141 r = safe_atou(val, &arg_keyfile_size);
142 if (r < 0) {
143 log_error_errno(r, "Failed to parse %s, ignoring: %m", option)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 143, __func__, "Failed to parse %s, ignoring: %m"
, option) : -abs(_e); })
;
144 return 0;
145 }
146
147 } else if ((val = startswith(option, "keyfile-offset="))) {
148 uint64_t off;
149
150 r = safe_atou64(val, &off);
151 if (r < 0) {
152 log_error_errno(r, "Failed to parse %s, ignoring: %m", option)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 152, __func__, "Failed to parse %s, ignoring: %m"
, option) : -abs(_e); })
;
153 return 0;
154 }
155
156 if ((size_t) off != off) {
157 /* https://gitlab.com/cryptsetup/cryptsetup/issues/359 */
158 log_error("keyfile-offset= value would truncated to %zu, ignoring.", (size_t) off)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 158, __func__, "keyfile-offset= value would truncated to %zu, ignoring."
, (size_t) off) : -abs(_e); })
;
159 return 0;
160 }
161
162 arg_keyfile_offset = off;
163
164 } else if ((val = startswith(option, "hash="))) {
165 r = free_and_strdup(&arg_hash, val);
166 if (r < 0)
167 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup.c"
, 167, __func__)
;
168
169 } else if ((val = startswith(option, "header="))) {
170 arg_type = ANY_LUKS"LUKS";
171
172 if (!path_is_absolute(val)) {
173 log_error("Header path \"%s\" is not absolute, refusing.", val)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 173, __func__, "Header path \"%s\" is not absolute, refusing."
, val) : -abs(_e); })
;
174 return -EINVAL22;
175 }
176
177 if (arg_header) {
178 log_error("Duplicate header= option, refusing.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 178, __func__, "Duplicate header= option, refusing."
) : -abs(_e); })
;
179 return -EINVAL22;
180 }
181
182 arg_header = strdup(val);
183 if (!arg_header)
184 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup.c"
, 184, __func__)
;
185
186 } else if ((val = startswith(option, "tries="))) {
187
188 r = safe_atou(val, &arg_tries);
189 if (r < 0) {
190 log_error_errno(r, "Failed to parse %s, ignoring: %m", option)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 190, __func__, "Failed to parse %s, ignoring: %m"
, option) : -abs(_e); })
;
191 return 0;
192 }
193
194 } else if (STR_IN_SET(option, "readonly", "read-only")(!!strv_find((((char**) ((const char*[]) { "readonly", "read-only"
, ((void*)0) }))), (option)))
)
195 arg_readonly = true1;
196 else if (streq(option, "verify")(strcmp((option),("verify")) == 0))
197 arg_verify = true1;
198 else if (STR_IN_SET(option, "allow-discards", "discard")(!!strv_find((((char**) ((const char*[]) { "allow-discards", "discard"
, ((void*)0) }))), (option)))
)
199 arg_discards = true1;
200 else if (streq(option, "luks")(strcmp((option),("luks")) == 0))
201 arg_type = ANY_LUKS"LUKS";
202 else if (streq(option, "tcrypt")(strcmp((option),("tcrypt")) == 0))
203 arg_type = CRYPT_TCRYPT"TCRYPT";
204 else if (streq(option, "tcrypt-hidden")(strcmp((option),("tcrypt-hidden")) == 0)) {
205 arg_type = CRYPT_TCRYPT"TCRYPT";
206 arg_tcrypt_hidden = true1;
207 } else if (streq(option, "tcrypt-system")(strcmp((option),("tcrypt-system")) == 0)) {
208 arg_type = CRYPT_TCRYPT"TCRYPT";
209 arg_tcrypt_system = true1;
210 } else if (streq(option, "tcrypt-veracrypt")(strcmp((option),("tcrypt-veracrypt")) == 0)) {
211#ifdef CRYPT_TCRYPT_VERA_MODES(1 << 4)
212 arg_type = CRYPT_TCRYPT"TCRYPT";
213 arg_tcrypt_veracrypt = true1;
214#else
215 log_error("This version of cryptsetup does not support tcrypt-veracrypt; refusing.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 215, __func__, "This version of cryptsetup does not support tcrypt-veracrypt; refusing."
) : -abs(_e); })
;
216 return -EINVAL22;
217#endif
218 } else if (STR_IN_SET(option, "plain", "swap", "tmp")(!!strv_find((((char**) ((const char*[]) { "plain", "swap", "tmp"
, ((void*)0) }))), (option)))
)
219 arg_type = CRYPT_PLAIN"PLAIN";
220 else if ((val = startswith(option, "timeout="))) {
221
222 r = parse_sec_fix_0(val, &arg_timeout);
223 if (r < 0) {
224 log_error_errno(r, "Failed to parse %s, ignoring: %m", option)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 224, __func__, "Failed to parse %s, ignoring: %m"
, option) : -abs(_e); })
;
225 return 0;
226 }
227
228 } else if ((val = startswith(option, "offset="))) {
229
230 r = safe_atou64(val, &arg_offset);
231 if (r < 0)
232 return log_error_errno(r, "Failed to parse %s: %m", option)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 232, __func__, "Failed to parse %s: %m"
, option) : -abs(_e); })
;
233
234 } else if ((val = startswith(option, "skip="))) {
235
236 r = safe_atou64(val, &arg_skip);
237 if (r < 0)
238 return log_error_errno(r, "Failed to parse %s: %m", option)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 238, __func__, "Failed to parse %s: %m"
, option) : -abs(_e); })
;
239
240 } else if (!streq(option, "none")(strcmp((option),("none")) == 0))
241 log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 241, __func__, "Encountered unknown /etc/crypttab option '%s', ignoring."
, option) : -abs(_e); })
;
242
243 return 0;
244}
245
246static int parse_options(const char *options) {
247 const char *word, *state;
248 size_t l;
249 int r;
250
251 assert(options)do { if ((__builtin_expect(!!(!(options)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("options"), "../src/cryptsetup/cryptsetup.c"
, 251, __PRETTY_FUNCTION__); } while (0)
;
15
Taking false branch
16
Loop condition is false. Exiting loop
252
253 FOREACH_WORD_SEPARATOR(word, l, options, ",", state)for ((state) = (options), (word) = split(&(state), &(
l), (","), (0)); (word); (word) = split(&(state), &(l
), (","), (0)))
{
17
Loop condition is true. Entering loop body
254 _cleanup_free___attribute__((cleanup(freep))) char *o;
255
256 o = strndup(word, l);
18
Memory is allocated
257 if (!o)
19
Assuming 'o' is non-null
20
Taking false branch
258 return -ENOMEM12;
259 r = parse_one_option(o);
21
Potential leak of memory pointed to by 'o'
260 if (r < 0)
261 return r;
262 }
263
264 /* sanity-check options */
265 if (arg_type != NULL((void*)0) && !streq(arg_type, CRYPT_PLAIN)(strcmp((arg_type),("PLAIN")) == 0)) {
266 if (arg_offset)
267 log_warning("offset= ignored with type %s", arg_type)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 267, __func__, "offset= ignored with type %s"
, arg_type) : -abs(_e); })
;
268 if (arg_skip)
269 log_warning("skip= ignored with type %s", arg_type)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 269, __func__, "skip= ignored with type %s"
, arg_type) : -abs(_e); })
;
270 }
271
272 return 0;
273}
274
275static char* disk_description(const char *path) {
276
277 static const char name_fields[] =
278 "ID_PART_ENTRY_NAME\0"
279 "DM_NAME\0"
280 "ID_MODEL_FROM_DATABASE\0"
281 "ID_MODEL\0";
282
283 _cleanup_(sd_device_unrefp)__attribute__((cleanup(sd_device_unrefp))) sd_device *device = NULL((void*)0);
284 struct stat st;
285 const char *i;
286 int r;
287
288 assert(path)do { if ((__builtin_expect(!!(!(path)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("path"), "../src/cryptsetup/cryptsetup.c"
, 288, __PRETTY_FUNCTION__); } while (0)
;
289
290 if (stat(path, &st) < 0)
291 return NULL((void*)0);
292
293 if (!S_ISBLK(st.st_mode)((((st.st_mode)) & 0170000) == (0060000)))
294 return NULL((void*)0);
295
296 r = sd_device_new_from_devnum(&device, 'b', st.st_rdev);
297 if (r < 0)
298 return NULL((void*)0);
299
300 NULSTR_FOREACH(i, name_fields)for ((i) = (name_fields); (i) && *(i); (i) = strchr((
i), 0)+1)
{
301 const char *name;
302
303 r = sd_device_get_property_value(device, i, &name);
304 if (r >= 0 && !isempty(name))
305 return strdup(name);
306 }
307
308 return NULL((void*)0);
309}
310
311static char *disk_mount_point(const char *label) {
312 _cleanup_free___attribute__((cleanup(freep))) char *device = NULL((void*)0);
313 _cleanup_endmntent___attribute__((cleanup(endmntentp))) FILE *f = NULL((void*)0);
314 struct mntent *m;
315
316 /* Yeah, we don't support native systemd unit files here for now */
317
318 if (asprintf(&device, "/dev/mapper/%s", label) < 0)
319 return NULL((void*)0);
320
321 f = setmntent("/etc/fstab", "re");
322 if (!f)
323 return NULL((void*)0);
324
325 while ((m = getmntent(f)))
326 if (path_equal(m->mnt_fsname, device))
327 return strdup(m->mnt_dir);
328
329 return NULL((void*)0);
330}
331
332static int get_password(const char *vol, const char *src, usec_t until, bool_Bool accept_cached, char ***ret) {
333 _cleanup_free___attribute__((cleanup(freep))) char *description = NULL((void*)0), *name_buffer = NULL((void*)0), *mount_point = NULL((void*)0), *text = NULL((void*)0), *disk_path = NULL((void*)0);
334 _cleanup_strv_free_erase___attribute__((cleanup(strv_free_erasep))) char **passwords = NULL((void*)0);
335 const char *name = NULL((void*)0);
336 char **p, *id;
337 int r = 0;
338
339 assert(vol)do { if ((__builtin_expect(!!(!(vol)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("vol"), "../src/cryptsetup/cryptsetup.c"
, 339, __PRETTY_FUNCTION__); } while (0)
;
340 assert(src)do { if ((__builtin_expect(!!(!(src)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("src"), "../src/cryptsetup/cryptsetup.c"
, 340, __PRETTY_FUNCTION__); } while (0)
;
341 assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("ret"), "../src/cryptsetup/cryptsetup.c"
, 341, __PRETTY_FUNCTION__); } while (0)
;
342
343 description = disk_description(src);
344 mount_point = disk_mount_point(vol);
345
346 disk_path = cescape(src);
347 if (!disk_path)
348 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup.c"
, 348, __func__)
;
349
350 if (description && streq(vol, description)(strcmp((vol),(description)) == 0))
351 /* If the description string is simply the
352 * volume name, then let's not show this
353 * twice */
354 description = mfree(description);
355
356 if (mount_point && description)
357 r = asprintf(&name_buffer, "%s (%s) on %s", description, vol, mount_point);
358 else if (mount_point)
359 r = asprintf(&name_buffer, "%s on %s", vol, mount_point);
360 else if (description)
361 r = asprintf(&name_buffer, "%s (%s)", description, vol);
362
363 if (r < 0)
364 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup.c"
, 364, __func__)
;
365
366 name = name_buffer ? name_buffer : vol;
367
368 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0)
369 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup.c"
, 369, __func__)
;
370
371 id = strjoina("cryptsetup:", disk_path)({ const char *_appendees_[] = { "cryptsetup:", disk_path }; char
*_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ = 0; _i_ <
__extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
372
373 r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until,
374 ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
375 &passwords);
376 if (r < 0)
377 return log_error_errno(r, "Failed to query password: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 377, __func__, "Failed to query password: %m"
) : -abs(_e); })
;
378
379 if (arg_verify) {
380 _cleanup_strv_free_erase___attribute__((cleanup(strv_free_erasep))) char **passwords2 = NULL((void*)0);
381
382 assert(strv_length(passwords) == 1)do { if ((__builtin_expect(!!(!(strv_length(passwords) == 1))
,0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("strv_length(passwords) == 1"
), "../src/cryptsetup/cryptsetup.c", 382, __PRETTY_FUNCTION__
); } while (0)
;
383
384 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
385 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup.c"
, 385, __func__)
;
386
387 id = strjoina("cryptsetup-verification:", disk_path)({ const char *_appendees_[] = { "cryptsetup-verification:", disk_path
}; char *_d_, *_p_; size_t _len_ = 0; size_t _i_; for (_i_ =
0; _i_ < __extension__ (__builtin_choose_expr( !__builtin_types_compatible_p
(typeof(_appendees_), typeof(&*(_appendees_))), sizeof(_appendees_
)/sizeof((_appendees_)[0]), ((void)0))) && _appendees_
[_i_]; _i_++) _len_ += strlen(_appendees_[_i_]); _p_ = _d_ = __builtin_alloca
(_len_ + 1); for (_i_ = 0; _i_ < __extension__ (__builtin_choose_expr
( !__builtin_types_compatible_p(typeof(_appendees_), typeof(&
*(_appendees_))), sizeof(_appendees_)/sizeof((_appendees_)[0]
), ((void)0))) && _appendees_[_i_]; _i_++) _p_ = stpcpy
(_p_, _appendees_[_i_]); *_p_ = 0; _d_; })
;
388
389 r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE, &passwords2);
390 if (r < 0)
391 return log_error_errno(r, "Failed to query verification password: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 391, __func__, "Failed to query verification password: %m"
) : -abs(_e); })
;
392
393 assert(strv_length(passwords2) == 1)do { if ((__builtin_expect(!!(!(strv_length(passwords2) == 1)
),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("strv_length(passwords2) == 1"
), "../src/cryptsetup/cryptsetup.c", 393, __PRETTY_FUNCTION__
); } while (0)
;
394
395 if (!streq(passwords[0], passwords2[0])(strcmp((passwords[0]),(passwords2[0])) == 0)) {
396 log_warning("Passwords did not match, retrying.")({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 396, __func__, "Passwords did not match, retrying."
) : -abs(_e); })
;
397 return -EAGAIN11;
398 }
399 }
400
401 strv_uniq(passwords);
402
403 STRV_FOREACH(p, passwords)for ((p) = (passwords); (p) && *(p); (p)++) {
404 char *c;
405
406 if (strlen(*p)+1 >= arg_key_size)
407 continue;
408
409 /* Pad password if necessary */
410 c = new(char, arg_key_size)((char*) malloc_multiply(sizeof(char), (arg_key_size)));
411 if (!c)
412 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup.c"
, 412, __func__)
;
413
414 strncpy(c, *p, arg_key_size);
415 free(*p);
416 *p = c;
417 }
418
419 *ret = TAKE_PTR(passwords)({ typeof(passwords) _ptr_ = (passwords); (passwords) = ((void
*)0); _ptr_; })
;
420
421 return 0;
422}
423
424static int attach_tcrypt(
425 struct crypt_device *cd,
426 const char *name,
427 const char *key_file,
428 char **passwords,
429 uint32_t flags) {
430
431 int r = 0;
432 _cleanup_free___attribute__((cleanup(freep))) char *passphrase = NULL((void*)0);
433 struct crypt_params_tcrypt params = {
434 .flags = CRYPT_TCRYPT_LEGACY_MODES(1 << 0),
435 .keyfiles = (const char **)arg_tcrypt_keyfiles,
436 .keyfiles_count = strv_length(arg_tcrypt_keyfiles)
437 };
438
439 assert(cd)do { if ((__builtin_expect(!!(!(cd)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("cd"), "../src/cryptsetup/cryptsetup.c",
439, __PRETTY_FUNCTION__); } while (0)
;
440 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/cryptsetup/cryptsetup.c"
, 440, __PRETTY_FUNCTION__); } while (0)
;
441 assert(key_file || (passwords && passwords[0]))do { if ((__builtin_expect(!!(!(key_file || (passwords &&
passwords[0]))),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD
, ("key_file || (passwords && passwords[0])"), "../src/cryptsetup/cryptsetup.c"
, 441, __PRETTY_FUNCTION__); } while (0)
;
442
443 if (arg_tcrypt_hidden)
444 params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER(1 << 1);
445
446 if (arg_tcrypt_system)
447 params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER(1 << 3);
448
449#ifdef CRYPT_TCRYPT_VERA_MODES(1 << 4)
450 if (arg_tcrypt_veracrypt)
451 params.flags |= CRYPT_TCRYPT_VERA_MODES(1 << 4);
452#endif
453
454 if (key_file) {
455 r = read_one_line_file(key_file, &passphrase);
456 if (r < 0) {
457 log_error_errno(r, "Failed to read password file '%s': %m", key_file)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 457, __func__, "Failed to read password file '%s': %m"
, key_file) : -abs(_e); })
;
458 return -EAGAIN11; /* log with the actual error, but return EAGAIN */
459 }
460
461 params.passphrase = passphrase;
462 } else
463 params.passphrase = passwords[0];
464 params.passphrase_size = strlen(params.passphrase);
465
466 r = crypt_load(cd, CRYPT_TCRYPT"TCRYPT", &params);
467 if (r < 0) {
468 if (key_file && r == -EPERM1) {
469 log_error("Failed to activate using password file '%s'.", key_file)({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 469, __func__, "Failed to activate using password file '%s'."
, key_file) : -abs(_e); })
;
470 return -EAGAIN11;
471 }
472
473 return log_error_errno(r, "Failed to load tcrypt superblock on device %s: %m", crypt_get_device_name(cd))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 473, __func__, "Failed to load tcrypt superblock on device %s: %m"
, crypt_get_device_name(cd)) : -abs(_e); })
;
474 }
475
476 r = crypt_activate_by_volume_key(cd, name, NULL((void*)0), 0, flags);
477 if (r < 0)
478 return log_error_errno(r, "Failed to activate tcrypt device %s: %m", crypt_get_device_name(cd))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 478, __func__, "Failed to activate tcrypt device %s: %m"
, crypt_get_device_name(cd)) : -abs(_e); })
;
479
480 return 0;
481}
482
483static int attach_luks_or_plain(struct crypt_device *cd,
484 const char *name,
485 const char *key_file,
486 char **passwords,
487 uint32_t flags) {
488 int r = 0;
489 bool_Bool pass_volume_key = false0;
490
491 assert(cd)do { if ((__builtin_expect(!!(!(cd)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("cd"), "../src/cryptsetup/cryptsetup.c",
491, __PRETTY_FUNCTION__); } while (0)
;
492 assert(name)do { if ((__builtin_expect(!!(!(name)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("name"), "../src/cryptsetup/cryptsetup.c"
, 492, __PRETTY_FUNCTION__); } while (0)
;
493 assert(key_file || passwords)do { if ((__builtin_expect(!!(!(key_file || passwords)),0))) log_assert_failed_realm
(LOG_REALM_SYSTEMD, ("key_file || passwords"), "../src/cryptsetup/cryptsetup.c"
, 493, __PRETTY_FUNCTION__); } while (0)
;
494
495 if ((!arg_type && !crypt_get_type(cd)) || streq_ptr(arg_type, CRYPT_PLAIN"PLAIN")) {
496 struct crypt_params_plain params = {
497 .offset = arg_offset,
498 .skip = arg_skip,
499#if HAVE_LIBCRYPTSETUP_SECTOR_SIZE1
500 .sector_size = arg_sector_size,
501#endif
502 };
503 const char *cipher, *cipher_mode;
504 _cleanup_free___attribute__((cleanup(freep))) char *truncated_cipher = NULL((void*)0);
505
506 if (arg_hash) {
507 /* plain isn't a real hash type. it just means "use no hash" */
508 if (!streq(arg_hash, "plain")(strcmp((arg_hash),("plain")) == 0))
509 params.hash = arg_hash;
510 } else if (!key_file)
511 /* for CRYPT_PLAIN, the behaviour of cryptsetup
512 * package is to not hash when a key file is provided */
513 params.hash = "ripemd160";
514
515 if (arg_cipher) {
516 size_t l;
517
518 l = strcspn(arg_cipher, "-");
519 truncated_cipher = strndup(arg_cipher, l);
520 if (!truncated_cipher)
521 return log_oom()log_oom_internal(LOG_REALM_SYSTEMD, "../src/cryptsetup/cryptsetup.c"
, 521, __func__)
;
522
523 cipher = truncated_cipher;
524 cipher_mode = arg_cipher[l] ? arg_cipher+l+1 : "plain";
525 } else {
526 cipher = "aes";
527 cipher_mode = "cbc-essiv:sha256";
528 }
529
530 /* for CRYPT_PLAIN limit reads
531 * from keyfile to key length, and
532 * ignore keyfile-size */
533 arg_keyfile_size = arg_key_size;
534
535 /* In contrast to what the name
536 * crypt_setup() might suggest this
537 * doesn't actually format anything,
538 * it just configures encryption
539 * parameters when used for plain
540 * mode. */
541 r = crypt_format(cd, CRYPT_PLAIN"PLAIN", cipher, cipher_mode, NULL((void*)0), NULL((void*)0), arg_keyfile_size, &params);
542 if (r < 0)
543 return log_error_errno(r, "Loading of cryptographic parameters failed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 543, __func__, "Loading of cryptographic parameters failed: %m"
) : -abs(_e); })
;
544
545 /* hash == NULL implies the user passed "plain" */
546 pass_volume_key = (params.hash == NULL((void*)0));
547 }
548
549 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 553, __func__, "Set cipher %s, mode %s, key size %i bits for device %s."
, crypt_get_cipher(cd), crypt_get_cipher_mode(cd), crypt_get_volume_key_size
(cd)*8, crypt_get_device_name(cd)) : -abs(_e); })
550 crypt_get_cipher(cd),({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 553, __func__, "Set cipher %s, mode %s, key size %i bits for device %s."
, crypt_get_cipher(cd), crypt_get_cipher_mode(cd), crypt_get_volume_key_size
(cd)*8, crypt_get_device_name(cd)) : -abs(_e); })
551 crypt_get_cipher_mode(cd),({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 553, __func__, "Set cipher %s, mode %s, key size %i bits for device %s."
, crypt_get_cipher(cd), crypt_get_cipher_mode(cd), crypt_get_volume_key_size
(cd)*8, crypt_get_device_name(cd)) : -abs(_e); })
552 crypt_get_volume_key_size(cd)*8,({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 553, __func__, "Set cipher %s, mode %s, key size %i bits for device %s."
, crypt_get_cipher(cd), crypt_get_cipher_mode(cd), crypt_get_volume_key_size
(cd)*8, crypt_get_device_name(cd)) : -abs(_e); })
553 crypt_get_device_name(cd))({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 553, __func__, "Set cipher %s, mode %s, key size %i bits for device %s."
, crypt_get_cipher(cd), crypt_get_cipher_mode(cd), crypt_get_volume_key_size
(cd)*8, crypt_get_device_name(cd)) : -abs(_e); })
;
554
555 if (key_file) {
556 r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
557 if (r == -EPERM1) {
558 log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 558, __func__, "Failed to activate with key file '%s'. (Key data incorrect?)"
, key_file) : -abs(_e); })
;
559 return -EAGAIN11; /* Log actual error, but return EAGAIN */
560 }
561 if (r == -EINVAL22) {
562 log_error_errno(r, "Failed to activate with key file '%s'. (Key file missing?)", key_file)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 562, __func__, "Failed to activate with key file '%s'. (Key file missing?)"
, key_file) : -abs(_e); })
;
563 return -EAGAIN11; /* Log actual error, but return EAGAIN */
564 }
565 if (r < 0)
566 return log_error_errno(r, "Failed to activate with key file '%s': %m", key_file)({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 566, __func__, "Failed to activate with key file '%s': %m"
, key_file) : -abs(_e); })
;
567 } else {
568 char **p;
569
570 r = -EINVAL22;
571 STRV_FOREACH(p, passwords)for ((p) = (passwords); (p) && *(p); (p)++) {
572 if (pass_volume_key)
573 r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
574 else
575 r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
576 if (r >= 0)
577 break;
578 }
579 if (r == -EPERM1) {
580 log_error_errno(r, "Failed to activate with specified passphrase. (Passphrase incorrect?)")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 580, __func__, "Failed to activate with specified passphrase. (Passphrase incorrect?)"
) : -abs(_e); })
;
581 return -EAGAIN11; /* log actual error, but return EAGAIN */
582 }
583 if (r < 0)
584 return log_error_errno(r, "Failed to activate with specified passphrase: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 584, __func__, "Failed to activate with specified passphrase: %m"
) : -abs(_e); })
;
585 }
586
587 return r;
588}
589
590static int help(void) {
591
592 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
593 "%s detach VOLUME\n\n"
594 "Attaches or detaches an encrypted block device.\n",
595 program_invocation_short_name,
596 program_invocation_short_name);
597
598 return 0;
599}
600
601int main(int argc, char *argv[]) {
602 _cleanup_(crypt_freep)__attribute__((cleanup(crypt_freep))) struct crypt_device *cd = NULL((void*)0);
603 int r = -EINVAL22;
604
605 if (argc <= 1) {
1
Assuming 'argc' is > 1
2
Taking false branch
606 r = help();
607 goto finish;
608 }
609
610 if (argc < 3) {
3
Assuming 'argc' is >= 3
4
Taking false branch
611 log_error("This program requires at least two arguments.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 611, __func__, "This program requires at least two arguments."
) : -abs(_e); })
;
612 goto finish;
613 }
614
615 log_set_target(LOG_TARGET_AUTO);
616 log_parse_environment()log_parse_environment_realm(LOG_REALM_SYSTEMD);
617 log_open();
618
619 umask(0022);
620
621 if (streq(argv[1], "attach")(strcmp((argv[1]),("attach")) == 0)) {
5
Taking true branch
622 uint32_t flags = 0;
623 unsigned tries;
624 usec_t until;
625 crypt_status_info status;
626 const char *key_file = NULL((void*)0);
627
628 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
629
630 if (argc < 4) {
6
Assuming 'argc' is >= 4
7
Taking false branch
631 log_error("attach requires at least two arguments.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 631, __func__, "attach requires at least two arguments."
) : -abs(_e); })
;
632 goto finish;
633 }
634
635 if (argc >= 5 &&
8
Assuming 'argc' is >= 5
636 argv[4][0] &&
9
Assuming the condition is false
637 !streq(argv[4], "-")(strcmp((argv[4]),("-")) == 0) &&
638 !streq(argv[4], "none")(strcmp((argv[4]),("none")) == 0)) {
639
640 if (!path_is_absolute(argv[4]))
641 log_warning("Password file path '%s' is not absolute. Ignoring.", argv[4])({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 641, __func__, "Password file path '%s' is not absolute. Ignoring."
, argv[4]) : -abs(_e); })
;
642 else
643 key_file = argv[4];
644 }
645
646 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")(strcmp((argv[5]),("-")) == 0)) {
10
Assuming 'argc' is >= 6
11
Assuming the condition is true
12
Assuming the condition is false
13
Taking true branch
647 if (parse_options(argv[5]) < 0)
14
Calling 'parse_options'
648 goto finish;
649 }
650
651 /* A delicious drop of snake oil */
652 mlockall(MCL_FUTURE2);
653
654 if (arg_header) {
655 log_debug("LUKS header: %s", arg_header)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 655, __func__, "LUKS header: %s"
, arg_header) : -abs(_e); })
;
656 r = crypt_init(&cd, arg_header);
657 } else
658 r = crypt_init(&cd, argv[3]);
659 if (r < 0) {
660 log_error_errno(r, "crypt_init() failed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 660, __func__, "crypt_init() failed: %m"
) : -abs(_e); })
;
661 goto finish;
662 }
663
664 crypt_set_log_callback(cd, cryptsetup_log_glue, NULL((void*)0));
665
666 status = crypt_status(cd, argv[2]);
667 if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)({ _Bool _found = 0; static __attribute__ ((unused)) char _static_assert__macros_need_to_be_extended
[20 - sizeof((int[]){CRYPT_ACTIVE, CRYPT_BUSY})/sizeof(int)];
switch(status) { case CRYPT_ACTIVE: case CRYPT_BUSY: _found =
1; break; default: break; } _found; })
) {
668 log_info("Volume %s already active.", argv[2])({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 668, __func__, "Volume %s already active."
, argv[2]) : -abs(_e); })
;
669 r = 0;
670 goto finish;
671 }
672
673 if (arg_readonly)
674 flags |= CRYPT_ACTIVATE_READONLY(1 << 0);
675
676 if (arg_discards)
677 flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS(1 << 3);
678
679#ifdef CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF(1 << 19)
680 /* Try to decrease the risk of OOM event if memory hard key derivation function is in use */
681 /* https://gitlab.com/cryptsetup/cryptsetup/issues/446/ */
682 flags |= CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF(1 << 19);
683#endif
684
685 if (arg_timeout == USEC_INFINITY((usec_t) -1))
686 until = 0;
687 else
688 until = now(CLOCK_MONOTONIC1) + arg_timeout;
689
690 arg_key_size = (arg_key_size > 0 ? arg_key_size : (256 / 8));
691
692 if (key_file) {
693 struct stat st;
694
695 /* Ideally we'd do this on the open fd, but since this is just a
696 * warning it's OK to do this in two steps. */
697 if (stat(key_file, &st) >= 0 && S_ISREG(st.st_mode)((((st.st_mode)) & 0170000) == (0100000)) && (st.st_mode & 0005))
698 log_warning("Key file %s is world-readable. This is not a good idea!", key_file)({ int _level = (((4))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 698, __func__, "Key file %s is world-readable. This is not a good idea!"
, key_file) : -abs(_e); })
;
699 }
700
701 if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1)(!!strv_find((((char**) ((const char*[]) { "LUKS", "LUKS1", (
(void*)0) }))), (arg_type)))
) {
702 r = crypt_load(cd, CRYPT_LUKS((void*)0), NULL((void*)0));
703 if (r < 0)
704 return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd))({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 704, __func__, "Failed to load LUKS superblock on device %s: %m"
, crypt_get_device_name(cd)) : -abs(_e); })
;
705
706 if (arg_header) {
707 r = crypt_set_data_device(cd, argv[3]);
708 if (r < 0)
709 return log_error_errno(r, "Failed to set LUKS data device %s: %m", argv[3])({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 709, __func__, "Failed to set LUKS data device %s: %m"
, argv[3]) : -abs(_e); })
;
710 }
711#ifdef CRYPT_ANY_TOKEN-1
712 /* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
713 if (!key_file) {
714 r = crypt_activate_by_token(cd, argv[2], CRYPT_ANY_TOKEN-1, NULL((void*)0), flags);
715 if (r >= 0) {
716 log_debug("Volume %s activated with LUKS token id %i.", argv[2], r)({ int _level = (((7))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 716, __func__, "Volume %s activated with LUKS token id %i."
, argv[2], r) : -abs(_e); })
;
717 return 0;
718 }
719
720 log_debug_errno(r, "Token activation unsuccessful for device %s: %m", crypt_get_device_name(cd))({ int _level = ((7)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 720, __func__, "Token activation unsuccessful for device %s: %m"
, crypt_get_device_name(cd)) : -abs(_e); })
;
721 }
722#endif
723 }
724
725 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
726 _cleanup_strv_free_erase___attribute__((cleanup(strv_free_erasep))) char **passwords = NULL((void*)0);
727
728 if (!key_file) {
729 r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
730 if (r == -EAGAIN11)
731 continue;
732 if (r < 0)
733 goto finish;
734 }
735
736 if (streq_ptr(arg_type, CRYPT_TCRYPT"TCRYPT"))
737 r = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
738 else
739 r = attach_luks_or_plain(cd,
740 argv[2],
741 key_file,
742 passwords,
743 flags);
744 if (r >= 0)
745 break;
746 if (r != -EAGAIN11)
747 goto finish;
748
749 /* Passphrase not correct? Let's try again! */
750 key_file = NULL((void*)0);
751 }
752
753 if (arg_tries != 0 && tries >= arg_tries) {
754 log_error("Too many attempts; giving up.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 754, __func__, "Too many attempts; giving up."
) : -abs(_e); })
;
755 r = -EPERM1;
756 goto finish;
757 }
758
759 } else if (streq(argv[1], "detach")(strcmp((argv[1]),("detach")) == 0)) {
760
761 r = crypt_init_by_name(&cd, argv[2]);
762 if (r == -ENODEV19) {
763 log_info("Volume %s already inactive.", argv[2])({ int _level = (((6))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 763, __func__, "Volume %s already inactive."
, argv[2]) : -abs(_e); })
;
764 r = 0;
765 goto finish;
766 }
767 if (r < 0) {
768 log_error_errno(r, "crypt_init_by_name() failed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 768, __func__, "crypt_init_by_name() failed: %m"
) : -abs(_e); })
;
769 goto finish;
770 }
771
772 crypt_set_log_callback(cd, cryptsetup_log_glue, NULL((void*)0));
773
774 r = crypt_deactivate(cd, argv[2]);
775 if (r < 0) {
776 log_error_errno(r, "Failed to deactivate: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 776, __func__, "Failed to deactivate: %m"
) : -abs(_e); })
;
777 goto finish;
778 }
779
780 } else {
781 log_error("Unknown verb %s.", argv[1])({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD
); (log_get_max_level_realm(_realm) >= ((_level) & 0x07
)) ? log_internal_realm(((_realm) << 10 | (_level)), _e
, "../src/cryptsetup/cryptsetup.c", 781, __func__, "Unknown verb %s."
, argv[1]) : -abs(_e); })
;
782 goto finish;
783 }
784
785 r = 0;
786
787finish:
788 free(arg_cipher);
789 free(arg_hash);
790 free(arg_header);
791 strv_free(arg_tcrypt_keyfiles);
792
793 return r < 0 ? EXIT_FAILURE1 : EXIT_SUCCESS0;
794}