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