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