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