]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup.c
cryptsetup: port from libudev to sd-device
[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 usec_t arg_timeout = 0;
54
55 /* Options Debian's crypttab knows we don't:
56
57 offset=
58 skip=
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 (!streq(option, "none"))
189 log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
190
191 return 0;
192 }
193
194 static int parse_options(const char *options) {
195 const char *word, *state;
196 size_t l;
197 int r;
198
199 assert(options);
200
201 FOREACH_WORD_SEPARATOR(word, l, options, ",", state) {
202 _cleanup_free_ char *o;
203
204 o = strndup(word, l);
205 if (!o)
206 return -ENOMEM;
207 r = parse_one_option(o);
208 if (r < 0)
209 return r;
210 }
211
212 return 0;
213 }
214
215 static void log_glue(int level, const char *msg, void *usrptr) {
216 log_debug("%s", msg);
217 }
218
219 static char* disk_description(const char *path) {
220
221 static const char name_fields[] =
222 "ID_PART_ENTRY_NAME\0"
223 "DM_NAME\0"
224 "ID_MODEL_FROM_DATABASE\0"
225 "ID_MODEL\0";
226
227 _cleanup_device_unref_ sd_device *device = NULL;
228 struct stat st;
229 const char *i;
230 int r;
231
232 assert(path);
233
234 if (stat(path, &st) < 0)
235 return NULL;
236
237 if (!S_ISBLK(st.st_mode))
238 return NULL;
239
240 r = sd_device_new_from_devnum(&device, 'b', st.st_rdev);
241 if (r < 0)
242 return NULL;
243
244 NULSTR_FOREACH(i, name_fields) {
245 const char *name;
246
247 r = sd_device_get_property_value(device, i, &name);
248 if (r >= 0 && !isempty(name))
249 return strdup(name);
250 }
251
252 return NULL;
253 }
254
255 static char *disk_mount_point(const char *label) {
256 _cleanup_free_ char *device = NULL;
257 _cleanup_endmntent_ FILE *f = NULL;
258 struct mntent *m;
259
260 /* Yeah, we don't support native systemd unit files here for now */
261
262 if (asprintf(&device, "/dev/mapper/%s", label) < 0)
263 return NULL;
264
265 f = setmntent("/etc/fstab", "r");
266 if (!f)
267 return NULL;
268
269 while ((m = getmntent(f)))
270 if (path_equal(m->mnt_fsname, device))
271 return strdup(m->mnt_dir);
272
273 return NULL;
274 }
275
276 static int get_password(const char *name, usec_t until, bool accept_cached, char ***passwords) {
277 int r;
278 char **p;
279 _cleanup_free_ char *text = NULL;
280 _cleanup_free_ char *escaped_name = NULL;
281 char *id;
282
283 assert(name);
284 assert(passwords);
285
286 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0)
287 return log_oom();
288
289 escaped_name = cescape(name);
290 if (!escaped_name)
291 return log_oom();
292
293 id = strjoina("cryptsetup:", escaped_name);
294
295 r = ask_password_auto(text, "drive-harddisk", id, until, accept_cached, passwords);
296 if (r < 0)
297 return log_error_errno(r, "Failed to query password: %m");
298
299 if (arg_verify) {
300 _cleanup_strv_free_ char **passwords2 = NULL;
301
302 assert(strv_length(*passwords) == 1);
303
304 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
305 return log_oom();
306
307 id = strjoina("cryptsetup-verification:", escaped_name);
308
309 r = ask_password_auto(text, "drive-harddisk", id, until, false, &passwords2);
310 if (r < 0)
311 return log_error_errno(r, "Failed to query verification password: %m");
312
313 assert(strv_length(passwords2) == 1);
314
315 if (!streq(*passwords[0], passwords2[0])) {
316 log_warning("Passwords did not match, retrying.");
317 return -EAGAIN;
318 }
319 }
320
321 strv_uniq(*passwords);
322
323 STRV_FOREACH(p, *passwords) {
324 char *c;
325
326 if (strlen(*p)+1 >= arg_key_size)
327 continue;
328
329 /* Pad password if necessary */
330 if (!(c = new(char, arg_key_size)))
331 return log_oom();
332
333 strncpy(c, *p, arg_key_size);
334 free(*p);
335 *p = c;
336 }
337
338 return 0;
339 }
340
341 static int attach_tcrypt(struct crypt_device *cd,
342 const char *name,
343 const char *key_file,
344 char **passwords,
345 uint32_t flags) {
346 int r = 0;
347 _cleanup_free_ char *passphrase = NULL;
348 struct crypt_params_tcrypt params = {
349 .flags = CRYPT_TCRYPT_LEGACY_MODES,
350 .keyfiles = (const char **)arg_tcrypt_keyfiles,
351 .keyfiles_count = strv_length(arg_tcrypt_keyfiles)
352 };
353
354 assert(cd);
355 assert(name);
356 assert(key_file || (passwords && passwords[0]));
357
358 if (arg_tcrypt_hidden)
359 params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
360
361 if (arg_tcrypt_system)
362 params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
363
364 if (key_file) {
365 r = read_one_line_file(key_file, &passphrase);
366 if (r < 0) {
367 log_error_errno(r, "Failed to read password file '%s': %m", key_file);
368 return -EAGAIN;
369 }
370
371 params.passphrase = passphrase;
372 } else
373 params.passphrase = passwords[0];
374 params.passphrase_size = strlen(params.passphrase);
375
376 r = crypt_load(cd, CRYPT_TCRYPT, &params);
377 if (r < 0) {
378 if (key_file && r == -EPERM) {
379 log_error("Failed to activate using password file '%s'.", key_file);
380 return -EAGAIN;
381 }
382 return r;
383 }
384
385 return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);
386 }
387
388 static int attach_luks_or_plain(struct crypt_device *cd,
389 const char *name,
390 const char *key_file,
391 const char *data_device,
392 char **passwords,
393 uint32_t flags) {
394 int r = 0;
395 bool pass_volume_key = false;
396
397 assert(cd);
398 assert(name);
399 assert(key_file || passwords);
400
401 if (!arg_type || streq(arg_type, CRYPT_LUKS1)) {
402 r = crypt_load(cd, CRYPT_LUKS1, NULL);
403 if (r < 0) {
404 log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd));
405 return r;
406 }
407
408 if (data_device)
409 r = crypt_set_data_device(cd, data_device);
410 }
411
412 if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) {
413 struct crypt_params_plain params = {};
414 const char *cipher, *cipher_mode;
415 _cleanup_free_ char *truncated_cipher = NULL;
416
417 if (arg_hash) {
418 /* plain isn't a real hash type. it just means "use no hash" */
419 if (!streq(arg_hash, "plain"))
420 params.hash = arg_hash;
421 } else if (!key_file)
422 /* for CRYPT_PLAIN, the behaviour of cryptsetup
423 * package is to not hash when a key file is provided */
424 params.hash = "ripemd160";
425
426 if (arg_cipher) {
427 size_t l;
428
429 l = strcspn(arg_cipher, "-");
430 truncated_cipher = strndup(arg_cipher, l);
431 if (!truncated_cipher)
432 return log_oom();
433
434 cipher = truncated_cipher;
435 cipher_mode = arg_cipher[l] ? arg_cipher+l+1 : "plain";
436 } else {
437 cipher = "aes";
438 cipher_mode = "cbc-essiv:sha256";
439 }
440
441 /* for CRYPT_PLAIN limit reads
442 * from keyfile to key length, and
443 * ignore keyfile-size */
444 arg_keyfile_size = arg_key_size;
445
446 /* In contrast to what the name
447 * crypt_setup() might suggest this
448 * doesn't actually format anything,
449 * it just configures encryption
450 * parameters when used for plain
451 * mode. */
452 r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode,
453 NULL, NULL, arg_keyfile_size, &params);
454
455 /* hash == NULL implies the user passed "plain" */
456 pass_volume_key = (params.hash == NULL);
457 }
458
459 if (r < 0)
460 return log_error_errno(r, "Loading of cryptographic parameters failed: %m");
461
462 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
463 crypt_get_cipher(cd),
464 crypt_get_cipher_mode(cd),
465 crypt_get_volume_key_size(cd)*8,
466 crypt_get_device_name(cd));
467
468 if (key_file) {
469 r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot,
470 key_file, arg_keyfile_size,
471 arg_keyfile_offset, flags);
472 if (r < 0) {
473 log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
474 return -EAGAIN;
475 }
476 } else {
477 char **p;
478
479 STRV_FOREACH(p, passwords) {
480 if (pass_volume_key)
481 r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
482 else
483 r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
484
485 if (r >= 0)
486 break;
487 }
488 }
489
490 return r;
491 }
492
493 static int help(void) {
494
495 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
496 "%s detach VOLUME\n\n"
497 "Attaches or detaches an encrypted block device.\n",
498 program_invocation_short_name,
499 program_invocation_short_name);
500
501 return 0;
502 }
503
504 int main(int argc, char *argv[]) {
505 int r = EXIT_FAILURE;
506 struct crypt_device *cd = NULL;
507
508 if (argc <= 1) {
509 help();
510 return EXIT_SUCCESS;
511 }
512
513 if (argc < 3) {
514 log_error("This program requires at least two arguments.");
515 return EXIT_FAILURE;
516 }
517
518 log_set_target(LOG_TARGET_AUTO);
519 log_parse_environment();
520 log_open();
521
522 umask(0022);
523
524 if (streq(argv[1], "attach")) {
525 uint32_t flags = 0;
526 int k;
527 unsigned tries;
528 usec_t until;
529 crypt_status_info status;
530 const char *key_file = NULL, *name = NULL;
531 _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
532
533 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
534
535 if (argc < 4) {
536 log_error("attach requires at least two arguments.");
537 goto finish;
538 }
539
540 if (argc >= 5 &&
541 argv[4][0] &&
542 !streq(argv[4], "-") &&
543 !streq(argv[4], "none")) {
544
545 if (!path_is_absolute(argv[4]))
546 log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
547 else
548 key_file = argv[4];
549 }
550
551 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
552 if (parse_options(argv[5]) < 0)
553 goto finish;
554 }
555
556 /* A delicious drop of snake oil */
557 mlockall(MCL_FUTURE);
558
559 description = disk_description(argv[3]);
560 mount_point = disk_mount_point(argv[2]);
561
562 if (description && streq(argv[2], description)) {
563 /* If the description string is simply the
564 * volume name, then let's not show this
565 * twice */
566 free(description);
567 description = NULL;
568 }
569
570 k = 0;
571 if (mount_point && description)
572 k = asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
573 else if (mount_point)
574 k = asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
575 else if (description)
576 k = asprintf(&name_buffer, "%s (%s)", description, argv[2]);
577
578 if (k < 0) {
579 log_oom();
580 goto finish;
581 }
582 name = name_buffer ? name_buffer : argv[2];
583
584 if (arg_header) {
585 log_debug("LUKS header: %s", arg_header);
586 k = crypt_init(&cd, arg_header);
587 } else
588 k = crypt_init(&cd, argv[3]);
589
590 if (k) {
591 log_error_errno(k, "crypt_init() failed: %m");
592 goto finish;
593 }
594
595 crypt_set_log_callback(cd, log_glue, NULL);
596
597 status = crypt_status(cd, argv[2]);
598 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
599 log_info("Volume %s already active.", argv[2]);
600 r = EXIT_SUCCESS;
601 goto finish;
602 }
603
604 if (arg_readonly)
605 flags |= CRYPT_ACTIVATE_READONLY;
606
607 if (arg_discards)
608 flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
609
610 if (arg_timeout > 0)
611 until = now(CLOCK_MONOTONIC) + arg_timeout;
612 else
613 until = 0;
614
615 arg_key_size = (arg_key_size > 0 ? arg_key_size : (256 / 8));
616
617 if (key_file) {
618 struct stat st;
619
620 /* Ideally we'd do this on the open fd, but since this is just a
621 * warning it's OK to do this in two steps. */
622 if (stat(key_file, &st) >= 0 && S_ISREG(st.st_mode) && (st.st_mode & 0005))
623 log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
624 }
625
626 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
627 _cleanup_strv_free_ char **passwords = NULL;
628
629 if (!key_file) {
630 k = get_password(name, until, tries == 0 && !arg_verify, &passwords);
631 if (k == -EAGAIN)
632 continue;
633 else if (k < 0)
634 goto finish;
635 }
636
637 if (streq_ptr(arg_type, CRYPT_TCRYPT))
638 k = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
639 else
640 k = attach_luks_or_plain(cd,
641 argv[2],
642 key_file,
643 arg_header ? argv[3] : NULL,
644 passwords,
645 flags);
646 if (k >= 0)
647 break;
648 else if (k == -EAGAIN) {
649 key_file = NULL;
650 continue;
651 } else if (k != -EPERM) {
652 log_error_errno(k, "Failed to activate: %m");
653 goto finish;
654 }
655
656 log_warning("Invalid passphrase.");
657 }
658
659 if (arg_tries != 0 && tries >= arg_tries) {
660 log_error("Too many attempts; giving up.");
661 r = EXIT_FAILURE;
662 goto finish;
663 }
664
665 } else if (streq(argv[1], "detach")) {
666 int k;
667
668 k = crypt_init_by_name(&cd, argv[2]);
669 if (k) {
670 log_error_errno(k, "crypt_init() failed: %m");
671 goto finish;
672 }
673
674 crypt_set_log_callback(cd, log_glue, NULL);
675
676 k = crypt_deactivate(cd, argv[2]);
677 if (k < 0) {
678 log_error_errno(k, "Failed to deactivate: %m");
679 goto finish;
680 }
681
682 } else {
683 log_error("Unknown verb %s.", argv[1]);
684 goto finish;
685 }
686
687 r = EXIT_SUCCESS;
688
689 finish:
690
691 if (cd)
692 crypt_free(cd);
693
694 free(arg_cipher);
695 free(arg_hash);
696 free(arg_header);
697 strv_free(arg_tcrypt_keyfiles);
698
699 return r;
700 }