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