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