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