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