]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup.c
Merge branch 'hostnamectl-dot-v2'
[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 ***passwords) {
316 int r = 0;
317 char **p;
318 _cleanup_free_ char *text = NULL;
319 _cleanup_free_ char *escaped_name = NULL;
320 char *id;
321 const char *name = NULL;
322 _cleanup_free_ char *description = NULL, *name_buffer = NULL,
323 *mount_point = NULL, *maj_min = NULL;
324
325 assert(vol);
326 assert(src);
327 assert(passwords);
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
339 if (mount_point && description)
340 r = asprintf(&name_buffer, "%s (%s) on %s", description, vol, mount_point);
341 else if (mount_point)
342 r = asprintf(&name_buffer, "%s on %s", vol, mount_point);
343 else if (description)
344 r = asprintf(&name_buffer, "%s (%s)", description, vol);
345
346 if (r < 0)
347 return log_oom();
348
349 name = name_buffer ? name_buffer : vol;
350
351 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0)
352 return log_oom();
353
354 if (src)
355 (void) disk_major_minor(src, &maj_min);
356
357 if (maj_min) {
358 escaped_name = maj_min;
359 maj_min = NULL;
360 } else
361 escaped_name = cescape(name);
362
363 if (!escaped_name)
364 return log_oom();
365
366 id = strjoina("cryptsetup:", escaped_name);
367
368 r = ask_password_auto(text, "drive-harddisk", id, until, accept_cached, passwords);
369 if (r < 0)
370 return log_error_errno(r, "Failed to query password: %m");
371
372 if (arg_verify) {
373 _cleanup_strv_free_ char **passwords2 = NULL;
374
375 assert(strv_length(*passwords) == 1);
376
377 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
378 return log_oom();
379
380 id = strjoina("cryptsetup-verification:", escaped_name);
381
382 r = ask_password_auto(text, "drive-harddisk", id, until, false, &passwords2);
383 if (r < 0)
384 return log_error_errno(r, "Failed to query verification password: %m");
385
386 assert(strv_length(passwords2) == 1);
387
388 if (!streq(*passwords[0], passwords2[0])) {
389 log_warning("Passwords did not match, retrying.");
390 return -EAGAIN;
391 }
392 }
393
394 strv_uniq(*passwords);
395
396 STRV_FOREACH(p, *passwords) {
397 char *c;
398
399 if (strlen(*p)+1 >= arg_key_size)
400 continue;
401
402 /* Pad password if necessary */
403 if (!(c = new(char, arg_key_size)))
404 return log_oom();
405
406 strncpy(c, *p, arg_key_size);
407 free(*p);
408 *p = c;
409 }
410
411 return 0;
412 }
413
414 static int attach_tcrypt(struct crypt_device *cd,
415 const char *name,
416 const char *key_file,
417 char **passwords,
418 uint32_t flags) {
419 int r = 0;
420 _cleanup_free_ char *passphrase = NULL;
421 struct crypt_params_tcrypt params = {
422 .flags = CRYPT_TCRYPT_LEGACY_MODES,
423 .keyfiles = (const char **)arg_tcrypt_keyfiles,
424 .keyfiles_count = strv_length(arg_tcrypt_keyfiles)
425 };
426
427 assert(cd);
428 assert(name);
429 assert(key_file || (passwords && passwords[0]));
430
431 if (arg_tcrypt_hidden)
432 params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
433
434 if (arg_tcrypt_system)
435 params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
436
437 if (key_file) {
438 r = read_one_line_file(key_file, &passphrase);
439 if (r < 0) {
440 log_error_errno(r, "Failed to read password file '%s': %m", key_file);
441 return -EAGAIN;
442 }
443
444 params.passphrase = passphrase;
445 } else
446 params.passphrase = passwords[0];
447 params.passphrase_size = strlen(params.passphrase);
448
449 r = crypt_load(cd, CRYPT_TCRYPT, &params);
450 if (r < 0) {
451 if (key_file && r == -EPERM) {
452 log_error("Failed to activate using password file '%s'.", key_file);
453 return -EAGAIN;
454 }
455 return r;
456 }
457
458 return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);
459 }
460
461 static int attach_luks_or_plain(struct crypt_device *cd,
462 const char *name,
463 const char *key_file,
464 const char *data_device,
465 char **passwords,
466 uint32_t flags) {
467 int r = 0;
468 bool pass_volume_key = false;
469
470 assert(cd);
471 assert(name);
472 assert(key_file || passwords);
473
474 if (!arg_type || streq(arg_type, CRYPT_LUKS1)) {
475 r = crypt_load(cd, CRYPT_LUKS1, NULL);
476 if (r < 0) {
477 log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
478 return r;
479 }
480
481 if (data_device)
482 r = crypt_set_data_device(cd, data_device);
483 }
484
485 if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) {
486 struct crypt_params_plain params = {
487 .offset = arg_offset,
488 .skip = arg_skip,
489 };
490 const char *cipher, *cipher_mode;
491 _cleanup_free_ char *truncated_cipher = NULL;
492
493 if (arg_hash) {
494 /* plain isn't a real hash type. it just means "use no hash" */
495 if (!streq(arg_hash, "plain"))
496 params.hash = arg_hash;
497 } else if (!key_file)
498 /* for CRYPT_PLAIN, the behaviour of cryptsetup
499 * package is to not hash when a key file is provided */
500 params.hash = "ripemd160";
501
502 if (arg_cipher) {
503 size_t l;
504
505 l = strcspn(arg_cipher, "-");
506 truncated_cipher = strndup(arg_cipher, l);
507 if (!truncated_cipher)
508 return log_oom();
509
510 cipher = truncated_cipher;
511 cipher_mode = arg_cipher[l] ? arg_cipher+l+1 : "plain";
512 } else {
513 cipher = "aes";
514 cipher_mode = "cbc-essiv:sha256";
515 }
516
517 /* for CRYPT_PLAIN limit reads
518 * from keyfile to key length, and
519 * ignore keyfile-size */
520 arg_keyfile_size = arg_key_size;
521
522 /* In contrast to what the name
523 * crypt_setup() might suggest this
524 * doesn't actually format anything,
525 * it just configures encryption
526 * parameters when used for plain
527 * mode. */
528 r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode,
529 NULL, NULL, arg_keyfile_size, &params);
530
531 /* hash == NULL implies the user passed "plain" */
532 pass_volume_key = (params.hash == NULL);
533 }
534
535 if (r < 0)
536 return log_error_errno(r, "Loading of cryptographic parameters failed: %m");
537
538 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
539 crypt_get_cipher(cd),
540 crypt_get_cipher_mode(cd),
541 crypt_get_volume_key_size(cd)*8,
542 crypt_get_device_name(cd));
543
544 if (key_file) {
545 r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot,
546 key_file, arg_keyfile_size,
547 arg_keyfile_offset, flags);
548 if (r < 0) {
549 log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
550 return -EAGAIN;
551 }
552 } else {
553 char **p;
554
555 STRV_FOREACH(p, passwords) {
556 if (pass_volume_key)
557 r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
558 else
559 r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
560
561 if (r >= 0)
562 break;
563 }
564 }
565
566 return r;
567 }
568
569 static int help(void) {
570
571 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
572 "%s detach VOLUME\n\n"
573 "Attaches or detaches an encrypted block device.\n",
574 program_invocation_short_name,
575 program_invocation_short_name);
576
577 return 0;
578 }
579
580 int main(int argc, char *argv[]) {
581 int r = EXIT_FAILURE;
582 struct crypt_device *cd = NULL;
583
584 if (argc <= 1) {
585 help();
586 return EXIT_SUCCESS;
587 }
588
589 if (argc < 3) {
590 log_error("This program requires at least two arguments.");
591 return EXIT_FAILURE;
592 }
593
594 log_set_target(LOG_TARGET_AUTO);
595 log_parse_environment();
596 log_open();
597
598 umask(0022);
599
600 if (streq(argv[1], "attach")) {
601 uint32_t flags = 0;
602 int k;
603 unsigned tries;
604 usec_t until;
605 crypt_status_info status;
606 const char *key_file = NULL;
607
608 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
609
610 if (argc < 4) {
611 log_error("attach requires at least two arguments.");
612 goto finish;
613 }
614
615 if (argc >= 5 &&
616 argv[4][0] &&
617 !streq(argv[4], "-") &&
618 !streq(argv[4], "none")) {
619
620 if (!path_is_absolute(argv[4]))
621 log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
622 else
623 key_file = argv[4];
624 }
625
626 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
627 if (parse_options(argv[5]) < 0)
628 goto finish;
629 }
630
631 /* A delicious drop of snake oil */
632 mlockall(MCL_FUTURE);
633
634 if (arg_header) {
635 log_debug("LUKS header: %s", arg_header);
636 k = crypt_init(&cd, arg_header);
637 } else
638 k = crypt_init(&cd, argv[3]);
639
640 if (k) {
641 log_error_errno(k, "crypt_init() failed: %m");
642 goto finish;
643 }
644
645 crypt_set_log_callback(cd, log_glue, NULL);
646
647 status = crypt_status(cd, argv[2]);
648 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
649 log_info("Volume %s already active.", argv[2]);
650 r = EXIT_SUCCESS;
651 goto finish;
652 }
653
654 if (arg_readonly)
655 flags |= CRYPT_ACTIVATE_READONLY;
656
657 if (arg_discards)
658 flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
659
660 if (arg_timeout > 0)
661 until = now(CLOCK_MONOTONIC) + arg_timeout;
662 else
663 until = 0;
664
665 arg_key_size = (arg_key_size > 0 ? arg_key_size : (256 / 8));
666
667 if (key_file) {
668 struct stat st;
669
670 /* Ideally we'd do this on the open fd, but since this is just a
671 * warning it's OK to do this in two steps. */
672 if (stat(key_file, &st) >= 0 && S_ISREG(st.st_mode) && (st.st_mode & 0005))
673 log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
674 }
675
676 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
677 _cleanup_strv_free_ char **passwords = NULL;
678
679 if (!key_file) {
680 k = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords);
681 if (k == -EAGAIN)
682 continue;
683 else if (k < 0)
684 goto finish;
685 }
686
687 if (streq_ptr(arg_type, CRYPT_TCRYPT))
688 k = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
689 else
690 k = attach_luks_or_plain(cd,
691 argv[2],
692 key_file,
693 arg_header ? argv[3] : NULL,
694 passwords,
695 flags);
696 if (k >= 0)
697 break;
698 else if (k == -EAGAIN) {
699 key_file = NULL;
700 continue;
701 } else if (k != -EPERM) {
702 log_error_errno(k, "Failed to activate: %m");
703 goto finish;
704 }
705
706 log_warning("Invalid passphrase.");
707 }
708
709 if (arg_tries != 0 && tries >= arg_tries) {
710 log_error("Too many attempts; giving up.");
711 r = EXIT_FAILURE;
712 goto finish;
713 }
714
715 } else if (streq(argv[1], "detach")) {
716 int k;
717
718 k = crypt_init_by_name(&cd, argv[2]);
719 if (k) {
720 log_error_errno(k, "crypt_init() failed: %m");
721 goto finish;
722 }
723
724 crypt_set_log_callback(cd, log_glue, NULL);
725
726 k = crypt_deactivate(cd, argv[2]);
727 if (k < 0) {
728 log_error_errno(k, "Failed to deactivate: %m");
729 goto finish;
730 }
731
732 } else {
733 log_error("Unknown verb %s.", argv[1]);
734 goto finish;
735 }
736
737 r = EXIT_SUCCESS;
738
739 finish:
740
741 if (cd)
742 crypt_free(cd);
743
744 free(arg_cipher);
745 free(arg_hash);
746 free(arg_header);
747 strv_free(arg_tcrypt_keyfiles);
748
749 return r;
750 }