]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup.c
Merge pull request #1619 from iaguis/nspawn-sysfs-netns-3
[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 ***ret) {
316 _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL, *maj_min = NULL, *text = NULL, *escaped_name = NULL;
317 _cleanup_strv_free_erase_ char **passwords = NULL;
318 const char *name = NULL;
319 char **p, *id;
320 int r = 0;
321
322 assert(vol);
323 assert(src);
324 assert(ret);
325
326 description = disk_description(src);
327 mount_point = disk_mount_point(vol);
328
329 if (description && streq(vol, description))
330 /* If the description string is simply the
331 * volume name, then let's not show this
332 * twice */
333 description = mfree(description);
334
335 if (mount_point && description)
336 r = asprintf(&name_buffer, "%s (%s) on %s", description, vol, mount_point);
337 else if (mount_point)
338 r = asprintf(&name_buffer, "%s on %s", vol, mount_point);
339 else if (description)
340 r = asprintf(&name_buffer, "%s (%s)", description, vol);
341
342 if (r < 0)
343 return log_oom();
344
345 name = name_buffer ? name_buffer : vol;
346
347 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0)
348 return log_oom();
349
350 if (src)
351 (void) disk_major_minor(src, &maj_min);
352
353 if (maj_min) {
354 escaped_name = maj_min;
355 maj_min = NULL;
356 } else
357 escaped_name = cescape(name);
358
359 if (!escaped_name)
360 return log_oom();
361
362 id = strjoina("cryptsetup:", escaped_name);
363
364 r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until,
365 ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
366 &passwords);
367 if (r < 0)
368 return log_error_errno(r, "Failed to query password: %m");
369
370 if (arg_verify) {
371 _cleanup_strv_free_erase_ char **passwords2 = NULL;
372
373 assert(strv_length(passwords) == 1);
374
375 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
376 return log_oom();
377
378 id = strjoina("cryptsetup-verification:", escaped_name);
379
380 r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE, &passwords2);
381 if (r < 0)
382 return log_error_errno(r, "Failed to query verification password: %m");
383
384 assert(strv_length(passwords2) == 1);
385
386 if (!streq(passwords[0], passwords2[0])) {
387 log_warning("Passwords did not match, retrying.");
388 return -EAGAIN;
389 }
390 }
391
392 strv_uniq(passwords);
393
394 STRV_FOREACH(p, passwords) {
395 char *c;
396
397 if (strlen(*p)+1 >= arg_key_size)
398 continue;
399
400 /* Pad password if necessary */
401 c = new(char, arg_key_size);
402 if (!c)
403 return log_oom();
404
405 strncpy(c, *p, arg_key_size);
406 free(*p);
407 *p = c;
408 }
409
410 *ret = passwords;
411 passwords = NULL;
412
413 return 0;
414 }
415
416 static int attach_tcrypt(
417 struct crypt_device *cd,
418 const char *name,
419 const char *key_file,
420 char **passwords,
421 uint32_t flags) {
422
423 int r = 0;
424 _cleanup_free_ char *passphrase = NULL;
425 struct crypt_params_tcrypt params = {
426 .flags = CRYPT_TCRYPT_LEGACY_MODES,
427 .keyfiles = (const char **)arg_tcrypt_keyfiles,
428 .keyfiles_count = strv_length(arg_tcrypt_keyfiles)
429 };
430
431 assert(cd);
432 assert(name);
433 assert(key_file || (passwords && passwords[0]));
434
435 if (arg_tcrypt_hidden)
436 params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
437
438 if (arg_tcrypt_system)
439 params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
440
441 if (key_file) {
442 r = read_one_line_file(key_file, &passphrase);
443 if (r < 0) {
444 log_error_errno(r, "Failed to read password file '%s': %m", key_file);
445 return -EAGAIN;
446 }
447
448 params.passphrase = passphrase;
449 } else
450 params.passphrase = passwords[0];
451 params.passphrase_size = strlen(params.passphrase);
452
453 r = crypt_load(cd, CRYPT_TCRYPT, &params);
454 if (r < 0) {
455 if (key_file && r == -EPERM) {
456 log_error("Failed to activate using password file '%s'.", key_file);
457 return -EAGAIN;
458 }
459 return r;
460 }
461
462 return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);
463 }
464
465 static int attach_luks_or_plain(struct crypt_device *cd,
466 const char *name,
467 const char *key_file,
468 const char *data_device,
469 char **passwords,
470 uint32_t flags) {
471 int r = 0;
472 bool pass_volume_key = false;
473
474 assert(cd);
475 assert(name);
476 assert(key_file || passwords);
477
478 if (!arg_type || streq(arg_type, CRYPT_LUKS1)) {
479 r = crypt_load(cd, CRYPT_LUKS1, NULL);
480 if (r < 0) {
481 log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
482 return r;
483 }
484
485 if (data_device)
486 r = crypt_set_data_device(cd, data_device);
487 }
488
489 if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) {
490 struct crypt_params_plain params = {
491 .offset = arg_offset,
492 .skip = arg_skip,
493 };
494 const char *cipher, *cipher_mode;
495 _cleanup_free_ char *truncated_cipher = NULL;
496
497 if (arg_hash) {
498 /* plain isn't a real hash type. it just means "use no hash" */
499 if (!streq(arg_hash, "plain"))
500 params.hash = arg_hash;
501 } else if (!key_file)
502 /* for CRYPT_PLAIN, the behaviour of cryptsetup
503 * package is to not hash when a key file is provided */
504 params.hash = "ripemd160";
505
506 if (arg_cipher) {
507 size_t l;
508
509 l = strcspn(arg_cipher, "-");
510 truncated_cipher = strndup(arg_cipher, l);
511 if (!truncated_cipher)
512 return log_oom();
513
514 cipher = truncated_cipher;
515 cipher_mode = arg_cipher[l] ? arg_cipher+l+1 : "plain";
516 } else {
517 cipher = "aes";
518 cipher_mode = "cbc-essiv:sha256";
519 }
520
521 /* for CRYPT_PLAIN limit reads
522 * from keyfile to key length, and
523 * ignore keyfile-size */
524 arg_keyfile_size = arg_key_size;
525
526 /* In contrast to what the name
527 * crypt_setup() might suggest this
528 * doesn't actually format anything,
529 * it just configures encryption
530 * parameters when used for plain
531 * mode. */
532 r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, arg_keyfile_size, &params);
533
534 /* hash == NULL implies the user passed "plain" */
535 pass_volume_key = (params.hash == NULL);
536 }
537
538 if (r < 0)
539 return log_error_errno(r, "Loading of cryptographic parameters failed: %m");
540
541 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
542 crypt_get_cipher(cd),
543 crypt_get_cipher_mode(cd),
544 crypt_get_volume_key_size(cd)*8,
545 crypt_get_device_name(cd));
546
547 if (key_file) {
548 r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags);
549 if (r < 0) {
550 log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
551 return -EAGAIN;
552 }
553 } else {
554 char **p;
555
556 STRV_FOREACH(p, passwords) {
557 if (pass_volume_key)
558 r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
559 else
560 r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
561
562 if (r >= 0)
563 break;
564 }
565 }
566
567 return r;
568 }
569
570 static int help(void) {
571
572 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
573 "%s detach VOLUME\n\n"
574 "Attaches or detaches an encrypted block device.\n",
575 program_invocation_short_name,
576 program_invocation_short_name);
577
578 return 0;
579 }
580
581 int main(int argc, char *argv[]) {
582 int r = EXIT_FAILURE;
583 struct crypt_device *cd = NULL;
584
585 if (argc <= 1) {
586 help();
587 return EXIT_SUCCESS;
588 }
589
590 if (argc < 3) {
591 log_error("This program requires at least two arguments.");
592 return EXIT_FAILURE;
593 }
594
595 log_set_target(LOG_TARGET_AUTO);
596 log_parse_environment();
597 log_open();
598
599 umask(0022);
600
601 if (streq(argv[1], "attach")) {
602 uint32_t flags = 0;
603 int k;
604 unsigned tries;
605 usec_t until;
606 crypt_status_info status;
607 const char *key_file = NULL;
608
609 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
610
611 if (argc < 4) {
612 log_error("attach requires at least two arguments.");
613 goto finish;
614 }
615
616 if (argc >= 5 &&
617 argv[4][0] &&
618 !streq(argv[4], "-") &&
619 !streq(argv[4], "none")) {
620
621 if (!path_is_absolute(argv[4]))
622 log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
623 else
624 key_file = argv[4];
625 }
626
627 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
628 if (parse_options(argv[5]) < 0)
629 goto finish;
630 }
631
632 /* A delicious drop of snake oil */
633 mlockall(MCL_FUTURE);
634
635 if (arg_header) {
636 log_debug("LUKS header: %s", arg_header);
637 k = crypt_init(&cd, arg_header);
638 } else
639 k = crypt_init(&cd, argv[3]);
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_erase_ 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 }