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