]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup.c
Revert "Trivial typo fixes and code refactorings (#5191)"
[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 static bool arg_tcrypt_veracrypt = false;
56 static char **arg_tcrypt_keyfiles = NULL;
57 static uint64_t arg_offset = 0;
58 static uint64_t arg_skip = 0;
59 static usec_t arg_timeout = 0;
60
61 /* Options Debian's crypttab knows we don't:
62
63 precheck=
64 check=
65 checkargs=
66 noearly=
67 loud=
68 keyscript=
69 */
70
71 static int parse_one_option(const char *option) {
72 const char *val;
73 int r;
74
75 assert(option);
76
77 /* Handled outside of this tool */
78 if (STR_IN_SET(option, "noauto", "auto", "nofail", "fail"))
79 return 0;
80
81 if ((val = startswith(option, "cipher="))) {
82 r = free_and_strdup(&arg_cipher, val);
83 if (r < 0)
84 return log_oom();
85
86 } else if ((val = startswith(option, "size="))) {
87
88 r = safe_atou(val, &arg_key_size);
89 if (r < 0) {
90 log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
91 return 0;
92 }
93
94 if (arg_key_size % 8) {
95 log_error("size= not a multiple of 8, ignoring.");
96 return 0;
97 }
98
99 arg_key_size /= 8;
100
101 } else if ((val = startswith(option, "key-slot="))) {
102
103 arg_type = CRYPT_LUKS1;
104 r = safe_atoi(val, &arg_key_slot);
105 if (r < 0) {
106 log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
107 return 0;
108 }
109
110 } else if ((val = startswith(option, "tcrypt-keyfile="))) {
111
112 arg_type = CRYPT_TCRYPT;
113 if (path_is_absolute(val)) {
114 if (strv_extend(&arg_tcrypt_keyfiles, val) < 0)
115 return log_oom();
116 } else
117 log_error("Key file path \"%s\" is not absolute. Ignoring.", val);
118
119 } else if ((val = startswith(option, "keyfile-size="))) {
120
121 r = safe_atou(val, &arg_keyfile_size);
122 if (r < 0) {
123 log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
124 return 0;
125 }
126
127 } else if ((val = startswith(option, "keyfile-offset="))) {
128
129 r = safe_atou(val, &arg_keyfile_offset);
130 if (r < 0) {
131 log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
132 return 0;
133 }
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 = CRYPT_LUKS1;
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 = CRYPT_LUKS1;
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(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 void log_glue(int level, const char *msg, void *usrptr) {
247 log_debug("%s", msg);
248 }
249
250 static int disk_major_minor(const char *path, char **ret) {
251 struct stat st;
252
253 assert(path);
254
255 if (stat(path, &st) < 0)
256 return -errno;
257
258 if (!S_ISBLK(st.st_mode))
259 return -EINVAL;
260
261 if (asprintf(ret, "/dev/block/%d:%d", major(st.st_rdev), minor(st.st_rdev)) < 0)
262 return -errno;
263
264 return 0;
265 }
266
267 static char* disk_description(const char *path) {
268
269 static const char name_fields[] =
270 "ID_PART_ENTRY_NAME\0"
271 "DM_NAME\0"
272 "ID_MODEL_FROM_DATABASE\0"
273 "ID_MODEL\0";
274
275 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
276 struct stat st;
277 const char *i;
278 int r;
279
280 assert(path);
281
282 if (stat(path, &st) < 0)
283 return NULL;
284
285 if (!S_ISBLK(st.st_mode))
286 return NULL;
287
288 r = sd_device_new_from_devnum(&device, 'b', st.st_rdev);
289 if (r < 0)
290 return NULL;
291
292 NULSTR_FOREACH(i, name_fields) {
293 const char *name;
294
295 r = sd_device_get_property_value(device, i, &name);
296 if (r >= 0 && !isempty(name))
297 return strdup(name);
298 }
299
300 return NULL;
301 }
302
303 static char *disk_mount_point(const char *label) {
304 _cleanup_free_ char *device = NULL;
305 _cleanup_endmntent_ FILE *f = NULL;
306 struct mntent *m;
307
308 /* Yeah, we don't support native systemd unit files here for now */
309
310 if (asprintf(&device, "/dev/mapper/%s", label) < 0)
311 return NULL;
312
313 f = setmntent("/etc/fstab", "re");
314 if (!f)
315 return NULL;
316
317 while ((m = getmntent(f)))
318 if (path_equal(m->mnt_fsname, device))
319 return strdup(m->mnt_dir);
320
321 return NULL;
322 }
323
324 static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***ret) {
325 _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL, *maj_min = NULL, *text = NULL, *escaped_name = NULL;
326 _cleanup_strv_free_erase_ char **passwords = NULL;
327 const char *name = NULL;
328 char **p, *id;
329 int r = 0;
330
331 assert(vol);
332 assert(src);
333 assert(ret);
334
335 description = disk_description(src);
336 mount_point = disk_mount_point(vol);
337
338 if (description && streq(vol, description))
339 /* If the description string is simply the
340 * volume name, then let's not show this
341 * twice */
342 description = mfree(description);
343
344 if (mount_point && description)
345 r = asprintf(&name_buffer, "%s (%s) on %s", description, vol, mount_point);
346 else if (mount_point)
347 r = asprintf(&name_buffer, "%s on %s", vol, mount_point);
348 else if (description)
349 r = asprintf(&name_buffer, "%s (%s)", description, vol);
350
351 if (r < 0)
352 return log_oom();
353
354 name = name_buffer ? name_buffer : vol;
355
356 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0)
357 return log_oom();
358
359 if (src)
360 (void) disk_major_minor(src, &maj_min);
361
362 if (maj_min) {
363 escaped_name = maj_min;
364 maj_min = NULL;
365 } else
366 escaped_name = cescape(name);
367
368 if (!escaped_name)
369 return log_oom();
370
371 id = strjoina("cryptsetup:", escaped_name);
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");
378
379 if (arg_verify) {
380 _cleanup_strv_free_erase_ char **passwords2 = NULL;
381
382 assert(strv_length(passwords) == 1);
383
384 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
385 return log_oom();
386
387 id = strjoina("cryptsetup-verification:", escaped_name);
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");
392
393 assert(strv_length(passwords2) == 1);
394
395 if (!streq(passwords[0], passwords2[0])) {
396 log_warning("Passwords did not match, retrying.");
397 return -EAGAIN;
398 }
399 }
400
401 strv_uniq(passwords);
402
403 STRV_FOREACH(p, passwords) {
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);
411 if (!c)
412 return log_oom();
413
414 strncpy(c, *p, arg_key_size);
415 free(*p);
416 *p = c;
417 }
418
419 *ret = passwords;
420 passwords = NULL;
421
422 return 0;
423 }
424
425 static int attach_tcrypt(
426 struct crypt_device *cd,
427 const char *name,
428 const char *key_file,
429 char **passwords,
430 uint32_t flags) {
431
432 int r = 0;
433 _cleanup_free_ char *passphrase = NULL;
434 struct crypt_params_tcrypt params = {
435 .flags = CRYPT_TCRYPT_LEGACY_MODES,
436 .keyfiles = (const char **)arg_tcrypt_keyfiles,
437 .keyfiles_count = strv_length(arg_tcrypt_keyfiles)
438 };
439
440 assert(cd);
441 assert(name);
442 assert(key_file || (passwords && passwords[0]));
443
444 if (arg_tcrypt_hidden)
445 params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
446
447 if (arg_tcrypt_system)
448 params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
449
450 #ifdef CRYPT_TCRYPT_VERA_MODES
451 if (arg_tcrypt_veracrypt)
452 params.flags |= CRYPT_TCRYPT_VERA_MODES;
453 #endif
454
455 if (key_file) {
456 r = read_one_line_file(key_file, &passphrase);
457 if (r < 0) {
458 log_error_errno(r, "Failed to read password file '%s': %m", key_file);
459 return -EAGAIN;
460 }
461
462 params.passphrase = passphrase;
463 } else
464 params.passphrase = passwords[0];
465 params.passphrase_size = strlen(params.passphrase);
466
467 r = crypt_load(cd, CRYPT_TCRYPT, &params);
468 if (r < 0) {
469 if (key_file && r == -EPERM) {
470 log_error("Failed to activate using password file '%s'.", key_file);
471 return -EAGAIN;
472 }
473 return r;
474 }
475
476 return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);
477 }
478
479 static int attach_luks_or_plain(struct crypt_device *cd,
480 const char *name,
481 const char *key_file,
482 const char *data_device,
483 char **passwords,
484 uint32_t flags) {
485 int r = 0;
486 bool pass_volume_key = false;
487
488 assert(cd);
489 assert(name);
490 assert(key_file || passwords);
491
492 if (!arg_type || streq(arg_type, CRYPT_LUKS1)) {
493 r = crypt_load(cd, CRYPT_LUKS1, NULL);
494 if (r < 0) {
495 log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
496 return r;
497 }
498
499 if (data_device)
500 r = crypt_set_data_device(cd, data_device);
501 }
502
503 if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) {
504 struct crypt_params_plain params = {
505 .offset = arg_offset,
506 .skip = arg_skip,
507 };
508 const char *cipher, *cipher_mode;
509 _cleanup_free_ char *truncated_cipher = NULL;
510
511 if (arg_hash) {
512 /* plain isn't a real hash type. it just means "use no hash" */
513 if (!streq(arg_hash, "plain"))
514 params.hash = arg_hash;
515 } else if (!key_file)
516 /* for CRYPT_PLAIN, the behaviour of cryptsetup
517 * package is to not hash when a key file is provided */
518 params.hash = "ripemd160";
519
520 if (arg_cipher) {
521 size_t l;
522
523 l = strcspn(arg_cipher, "-");
524 truncated_cipher = strndup(arg_cipher, l);
525 if (!truncated_cipher)
526 return log_oom();
527
528 cipher = truncated_cipher;
529 cipher_mode = arg_cipher[l] ? arg_cipher+l+1 : "plain";
530 } else {
531 cipher = "aes";
532 cipher_mode = "cbc-essiv:sha256";
533 }
534
535 /* for CRYPT_PLAIN limit reads
536 * from keyfile to key length, and
537 * ignore keyfile-size */
538 arg_keyfile_size = arg_key_size;
539
540 /* In contrast to what the name
541 * crypt_setup() might suggest this
542 * doesn't actually format anything,
543 * it just configures encryption
544 * parameters when used for plain
545 * mode. */
546 r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, arg_keyfile_size, &params);
547
548 /* hash == NULL implies the user passed "plain" */
549 pass_volume_key = (params.hash == NULL);
550 }
551
552 if (r < 0)
553 return log_error_errno(r, "Loading of cryptographic parameters failed: %m");
554
555 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
556 crypt_get_cipher(cd),
557 crypt_get_cipher_mode(cd),
558 crypt_get_volume_key_size(cd)*8,
559 crypt_get_device_name(cd));
560
561 if (key_file) {
562 r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
563 if (r < 0) {
564 log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
565 return -EAGAIN;
566 }
567 } else {
568 char **p;
569
570 STRV_FOREACH(p, passwords) {
571 if (pass_volume_key)
572 r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
573 else
574 r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
575
576 if (r >= 0)
577 break;
578 }
579 }
580
581 return r;
582 }
583
584 static int help(void) {
585
586 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
587 "%s detach VOLUME\n\n"
588 "Attaches or detaches an encrypted block device.\n",
589 program_invocation_short_name,
590 program_invocation_short_name);
591
592 return 0;
593 }
594
595 int main(int argc, char *argv[]) {
596 struct crypt_device *cd = NULL;
597 int r;
598
599 if (argc <= 1) {
600 r = help();
601 goto finish;
602 }
603
604 if (argc < 3) {
605 log_error("This program requires at least two arguments.");
606 r = -EINVAL;
607 goto finish;
608 }
609
610 log_set_target(LOG_TARGET_AUTO);
611 log_parse_environment();
612 log_open();
613
614 umask(0022);
615
616 if (streq(argv[1], "attach")) {
617 uint32_t flags = 0;
618 unsigned tries;
619 usec_t until;
620 crypt_status_info status;
621 const char *key_file = NULL;
622
623 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
624
625 if (argc < 4) {
626 log_error("attach requires at least two arguments.");
627 goto finish;
628 }
629
630 if (argc >= 5 &&
631 argv[4][0] &&
632 !streq(argv[4], "-") &&
633 !streq(argv[4], "none")) {
634
635 if (!path_is_absolute(argv[4]))
636 log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
637 else
638 key_file = argv[4];
639 }
640
641 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
642 if (parse_options(argv[5]) < 0)
643 goto finish;
644 }
645
646 /* A delicious drop of snake oil */
647 mlockall(MCL_FUTURE);
648
649 if (arg_header) {
650 log_debug("LUKS header: %s", arg_header);
651 r = crypt_init(&cd, arg_header);
652 } else
653 r = crypt_init(&cd, argv[3]);
654 if (r < 0) {
655 log_error_errno(r, "crypt_init() failed: %m");
656 goto finish;
657 }
658
659 crypt_set_log_callback(cd, log_glue, NULL);
660
661 status = crypt_status(cd, argv[2]);
662 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
663 log_info("Volume %s already active.", argv[2]);
664 r = 0;
665 goto finish;
666 }
667
668 if (arg_readonly)
669 flags |= CRYPT_ACTIVATE_READONLY;
670
671 if (arg_discards)
672 flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
673
674 if (arg_timeout > 0)
675 until = now(CLOCK_MONOTONIC) + arg_timeout;
676 else
677 until = 0;
678
679 arg_key_size = (arg_key_size > 0 ? arg_key_size : (256 / 8));
680
681 if (key_file) {
682 struct stat st;
683
684 /* Ideally we'd do this on the open fd, but since this is just a
685 * warning it's OK to do this in two steps. */
686 if (stat(key_file, &st) >= 0 && S_ISREG(st.st_mode) && (st.st_mode & 0005))
687 log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
688 }
689
690 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
691 _cleanup_strv_free_erase_ char **passwords = NULL;
692
693 if (!key_file) {
694 r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
695 if (r == -EAGAIN)
696 continue;
697 if (r < 0)
698 goto finish;
699 }
700
701 if (streq_ptr(arg_type, CRYPT_TCRYPT))
702 r = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
703 else
704 r = attach_luks_or_plain(cd,
705 argv[2],
706 key_file,
707 arg_header ? argv[3] : NULL,
708 passwords,
709 flags);
710 if (r >= 0)
711 break;
712 if (r == -EAGAIN) {
713 key_file = NULL;
714 continue;
715 }
716 if (r != -EPERM) {
717 log_error_errno(r, "Failed to activate: %m");
718 goto finish;
719 }
720
721 log_warning("Invalid passphrase.");
722 }
723
724 if (arg_tries != 0 && tries >= arg_tries) {
725 log_error("Too many attempts; giving up.");
726 r = -EPERM;
727 goto finish;
728 }
729
730 } else if (streq(argv[1], "detach")) {
731
732 r = crypt_init_by_name(&cd, argv[2]);
733 if (r == -ENODEV) {
734 log_info("Volume %s already inactive.", argv[2]);
735 r = 0;
736 goto finish;
737 }
738 if (r < 0) {
739 log_error_errno(r, "crypt_init_by_name() failed: %m");
740 goto finish;
741 }
742
743 crypt_set_log_callback(cd, log_glue, NULL);
744
745 r = crypt_deactivate(cd, argv[2]);
746 if (r < 0) {
747 log_error_errno(r, "Failed to deactivate: %m");
748 goto finish;
749 }
750
751 } else {
752 log_error("Unknown verb %s.", argv[1]);
753 r = -EINVAL;
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 }