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