]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup.c
Add more password agent information
[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 "def.h"
36 #include "libudev.h"
37 #include "udev-util.h"
38
39 static const char *arg_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */
40 static char *arg_cipher = NULL;
41 static unsigned arg_key_size = 0;
42 static int arg_key_slot = CRYPT_ANY_SLOT;
43 static unsigned arg_keyfile_size = 0;
44 static unsigned arg_keyfile_offset = 0;
45 static char *arg_hash = 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 (streq(option, "noauto") || streq(option, "nofail"))
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 } else if (startswith(option, "key-slot=")) {
92
93 arg_type = CRYPT_LUKS1;
94 if (safe_atoi(option+9, &arg_key_slot) < 0) {
95 log_error("key-slot= parse failure, ignoring.");
96 return 0;
97 }
98
99 } else if (startswith(option, "tcrypt-keyfile=")) {
100
101 arg_type = CRYPT_TCRYPT;
102 if (path_is_absolute(option+15)) {
103 if (strv_extend(&arg_tcrypt_keyfiles, option + 15) < 0)
104 return log_oom();
105 } else
106 log_error("Key file path '%s' is not absolute. Ignoring.", option+15);
107
108 } else if (startswith(option, "keyfile-size=")) {
109
110 if (safe_atou(option+13, &arg_keyfile_size) < 0) {
111 log_error("keyfile-size= parse failure, ignoring.");
112 return 0;
113 }
114
115 } else if (startswith(option, "keyfile-offset=")) {
116
117 if (safe_atou(option+15, &arg_keyfile_offset) < 0) {
118 log_error("keyfile-offset= parse failure, ignoring.");
119 return 0;
120 }
121
122 } else if (startswith(option, "hash=")) {
123 char *t;
124
125 t = strdup(option+5);
126 if (!t)
127 return log_oom();
128
129 free(arg_hash);
130 arg_hash = t;
131
132 } else if (startswith(option, "tries=")) {
133
134 if (safe_atou(option+6, &arg_tries) < 0) {
135 log_error("tries= parse failure, ignoring.");
136 return 0;
137 }
138
139 } else if (STR_IN_SET(option, "readonly", "read-only"))
140 arg_readonly = true;
141 else if (streq(option, "verify"))
142 arg_verify = true;
143 else if (STR_IN_SET(option, "allow-discards", "discard"))
144 arg_discards = true;
145 else if (streq(option, "luks"))
146 arg_type = CRYPT_LUKS1;
147 else if (streq(option, "tcrypt"))
148 arg_type = CRYPT_TCRYPT;
149 else if (streq(option, "tcrypt-hidden")) {
150 arg_type = CRYPT_TCRYPT;
151 arg_tcrypt_hidden = true;
152 } else if (streq(option, "tcrypt-system")) {
153 arg_type = CRYPT_TCRYPT;
154 arg_tcrypt_system = true;
155 } else if (STR_IN_SET(option, "plain", "swap", "tmp"))
156 arg_type = CRYPT_PLAIN;
157 else if (startswith(option, "timeout=")) {
158
159 if (parse_sec(option+8, &arg_timeout) < 0) {
160 log_error("timeout= parse failure, ignoring.");
161 return 0;
162 }
163
164 } else if (!streq(option, "none"))
165 log_error("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
166
167 return 0;
168 }
169
170 static int parse_options(const char *options) {
171 char *state, *w;
172 size_t l;
173 int r;
174
175 assert(options);
176
177 FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
178 _cleanup_free_ char *o;
179
180 o = strndup(w, l);
181 if (!o)
182 return -ENOMEM;
183 r = parse_one_option(o);
184 if (r < 0)
185 return r;
186 }
187
188 return 0;
189 }
190
191 static void log_glue(int level, const char *msg, void *usrptr) {
192 log_debug("%s", msg);
193 }
194
195 static char* disk_description(const char *path) {
196
197 static const char name_fields[] =
198 "ID_PART_ENTRY_NAME\0"
199 "DM_NAME\0"
200 "ID_MODEL_FROM_DATABASE\0"
201 "ID_MODEL\0";
202
203 _cleanup_udev_unref_ struct udev *udev = NULL;
204 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
205 struct stat st;
206 const char *i;
207
208 assert(path);
209
210 if (stat(path, &st) < 0)
211 return NULL;
212
213 if (!S_ISBLK(st.st_mode))
214 return NULL;
215
216 udev = udev_new();
217 if (!udev)
218 return NULL;
219
220 device = udev_device_new_from_devnum(udev, 'b', st.st_rdev);
221 if (!device)
222 return NULL;
223
224 NULSTR_FOREACH(i, name_fields) {
225 const char *name;
226
227 name = udev_device_get_property_value(device, i);
228 if (!isempty(name))
229 return strdup(name);
230 }
231
232 return NULL;
233 }
234
235 static char *disk_mount_point(const char *label) {
236 _cleanup_free_ char *device = NULL;
237 _cleanup_endmntent_ FILE *f = NULL;
238 struct mntent *m;
239
240 /* Yeah, we don't support native systemd unit files here for now */
241
242 if (asprintf(&device, "/dev/mapper/%s", label) < 0)
243 return NULL;
244
245 f = setmntent("/etc/fstab", "r");
246 if (!f)
247 return NULL;
248
249 while ((m = getmntent(f)))
250 if (path_equal(m->mnt_fsname, device))
251 return strdup(m->mnt_dir);
252
253 return NULL;
254 }
255
256 static int get_password(const char *name, usec_t until, bool accept_cached, char ***passwords) {
257 int r;
258 char **p;
259 _cleanup_free_ char *text = NULL;
260 _cleanup_free_ char *escaped_name = NULL;
261 char *id;
262
263 assert(name);
264 assert(passwords);
265
266 if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0)
267 return log_oom();
268
269 escaped_name = cescape(name);
270 if (!escaped_name)
271 return log_oom();
272
273 id = strappenda("cryptsetup:", escaped_name);
274
275 r = ask_password_auto(text, "drive-harddisk", id, until, accept_cached, passwords);
276 if (r < 0) {
277 log_error("Failed to query password: %s", strerror(-r));
278 return r;
279 }
280
281 if (arg_verify) {
282 _cleanup_strv_free_ char **passwords2 = NULL;
283
284 assert(strv_length(*passwords) == 1);
285
286 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
287 return log_oom();
288
289 id = strappenda("cryptsetup-verification:", escaped_name);
290
291 r = ask_password_auto(text, "drive-harddisk", id, until, false, &passwords2);
292 if (r < 0) {
293 log_error("Failed to query verification password: %s", strerror(-r));
294 return r;
295 }
296
297 assert(strv_length(passwords2) == 1);
298
299 if (!streq(*passwords[0], passwords2[0])) {
300 log_warning("Passwords did not match, retrying.");
301 return -EAGAIN;
302 }
303 }
304
305 strv_uniq(*passwords);
306
307 STRV_FOREACH(p, *passwords) {
308 char *c;
309
310 if (strlen(*p)+1 >= arg_key_size)
311 continue;
312
313 /* Pad password if necessary */
314 if (!(c = new(char, arg_key_size)))
315 return log_oom();
316
317 strncpy(c, *p, arg_key_size);
318 free(*p);
319 *p = c;
320 }
321
322 return 0;
323 }
324
325 static int attach_tcrypt(struct crypt_device *cd,
326 const char *name,
327 const char *key_file,
328 char **passwords,
329 uint32_t flags) {
330 int r = 0;
331 _cleanup_free_ char *passphrase = NULL;
332 struct crypt_params_tcrypt params = {
333 .flags = CRYPT_TCRYPT_LEGACY_MODES,
334 .keyfiles = (const char **)arg_tcrypt_keyfiles,
335 .keyfiles_count = strv_length(arg_tcrypt_keyfiles)
336 };
337
338 assert(cd);
339 assert(name);
340 assert(key_file || passwords);
341
342 if (arg_tcrypt_hidden)
343 params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
344
345 if (arg_tcrypt_system)
346 params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
347
348 if (key_file) {
349 r = read_one_line_file(key_file, &passphrase);
350 if (r < 0) {
351 log_error("Failed to read password file '%s': %s", key_file, strerror(-r));
352 return -EAGAIN;
353 }
354
355 params.passphrase = passphrase;
356 } else
357 params.passphrase = passwords[0];
358 params.passphrase_size = strlen(params.passphrase);
359
360 r = crypt_load(cd, CRYPT_TCRYPT, &params);
361 if (r < 0) {
362 if (key_file && r == -EPERM) {
363 log_error("Failed to activate using password file '%s'.", key_file);
364 return -EAGAIN;
365 }
366 return r;
367 }
368
369 return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);
370 }
371
372 static int attach_luks_or_plain(struct crypt_device *cd,
373 const char *name,
374 const char *key_file,
375 char **passwords,
376 uint32_t flags) {
377 int r = 0;
378 bool pass_volume_key = false;
379
380 assert(cd);
381 assert(name);
382 assert(key_file || passwords);
383
384 if (!arg_type || streq(arg_type, CRYPT_LUKS1))
385 r = crypt_load(cd, CRYPT_LUKS1, NULL);
386
387 if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) {
388 struct crypt_params_plain params = {};
389 const char *cipher, *cipher_mode;
390 _cleanup_free_ char *truncated_cipher = NULL;
391
392 if (arg_hash) {
393 /* plain isn't a real hash type. it just means "use no hash" */
394 if (!streq(arg_hash, "plain"))
395 params.hash = arg_hash;
396 } else
397 params.hash = "ripemd160";
398
399 if (arg_cipher) {
400 size_t l;
401
402 l = strcspn(arg_cipher, "-");
403 truncated_cipher = strndup(arg_cipher, l);
404 if (!truncated_cipher)
405 return log_oom();
406
407 cipher = truncated_cipher;
408 cipher_mode = arg_cipher[l] ? arg_cipher+l+1 : "plain";
409 } else {
410 cipher = "aes";
411 cipher_mode = "cbc-essiv:sha256";
412 }
413
414 /* for CRYPT_PLAIN limit reads
415 * from keyfile to key length, and
416 * ignore keyfile-size */
417 arg_keyfile_size = arg_key_size / 8;
418
419 /* In contrast to what the name
420 * crypt_setup() might suggest this
421 * doesn't actually format anything,
422 * it just configures encryption
423 * parameters when used for plain
424 * mode. */
425 r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode,
426 NULL, NULL, arg_keyfile_size, &params);
427
428 /* hash == NULL implies the user passed "plain" */
429 pass_volume_key = (params.hash == NULL);
430 }
431
432 if (r < 0) {
433 log_error("Loading of cryptographic parameters failed: %s", strerror(-r));
434 return r;
435 }
436
437 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
438 crypt_get_cipher(cd),
439 crypt_get_cipher_mode(cd),
440 crypt_get_volume_key_size(cd)*8,
441 crypt_get_device_name(cd));
442
443 if (key_file) {
444 r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot,
445 key_file, arg_keyfile_size,
446 arg_keyfile_offset, flags);
447 if (r < 0) {
448 log_error("Failed to activate with key file '%s': %s", key_file, strerror(-r));
449 return -EAGAIN;
450 }
451 } else {
452 char **p;
453
454 STRV_FOREACH(p, passwords) {
455 if (pass_volume_key)
456 r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
457 else
458 r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
459
460 if (r >= 0)
461 break;
462 }
463 }
464
465 return r;
466 }
467
468 static int help(void) {
469
470 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
471 "%s detach VOLUME\n\n"
472 "Attaches or detaches an encrypted block device.\n",
473 program_invocation_short_name,
474 program_invocation_short_name);
475
476 return 0;
477 }
478
479 int main(int argc, char *argv[]) {
480 int r = EXIT_FAILURE;
481 struct crypt_device *cd = NULL;
482
483 if (argc <= 1) {
484 help();
485 return EXIT_SUCCESS;
486 }
487
488 if (argc < 3) {
489 log_error("This program requires at least two arguments.");
490 return EXIT_FAILURE;
491 }
492
493 log_set_target(LOG_TARGET_AUTO);
494 log_parse_environment();
495 log_open();
496
497 umask(0022);
498
499 if (streq(argv[1], "attach")) {
500 uint32_t flags = 0;
501 int k;
502 unsigned tries;
503 usec_t until;
504 crypt_status_info status;
505 const char *key_file = NULL, *name = NULL;
506 _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
507
508 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
509
510 if (argc < 4) {
511 log_error("attach requires at least two arguments.");
512 goto finish;
513 }
514
515 if (argc >= 5 &&
516 argv[4][0] &&
517 !streq(argv[4], "-") &&
518 !streq(argv[4], "none")) {
519
520 if (!path_is_absolute(argv[4]))
521 log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
522 else
523 key_file = argv[4];
524 }
525
526 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
527 if (parse_options(argv[5]) < 0)
528 goto finish;
529 }
530
531 /* A delicious drop of snake oil */
532 mlockall(MCL_FUTURE);
533
534 description = disk_description(argv[3]);
535 mount_point = disk_mount_point(argv[2]);
536
537 if (description && streq(argv[2], description)) {
538 /* If the description string is simply the
539 * volume name, then let's not show this
540 * twice */
541 free(description);
542 description = NULL;
543 }
544
545 if (mount_point && description)
546 asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
547 else if (mount_point)
548 asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
549 else if (description)
550 asprintf(&name_buffer, "%s (%s)", description, argv[2]);
551
552 name = name_buffer ? name_buffer : argv[2];
553
554 k = crypt_init(&cd, argv[3]);
555 if (k) {
556 log_error("crypt_init() failed: %s", strerror(-k));
557 goto finish;
558 }
559
560 crypt_set_log_callback(cd, log_glue, NULL);
561
562 status = crypt_status(cd, argv[2]);
563 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
564 log_info("Volume %s already active.", argv[2]);
565 r = EXIT_SUCCESS;
566 goto finish;
567 }
568
569 if (arg_readonly)
570 flags |= CRYPT_ACTIVATE_READONLY;
571
572 if (arg_discards)
573 flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
574
575 if (arg_timeout > 0)
576 until = now(CLOCK_MONOTONIC) + arg_timeout;
577 else
578 until = 0;
579
580 arg_key_size = (arg_key_size > 0 ? arg_key_size : 256);
581
582 if (key_file) {
583 struct stat st;
584
585 /* Ideally we'd do this on the open fd, but since this is just a
586 * warning it's OK to do this in two steps. */
587 if (stat(key_file, &st) >= 0 && (st.st_mode & 0005))
588 log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
589 }
590
591 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
592 _cleanup_strv_free_ char **passwords = NULL;
593
594 if (!key_file) {
595 k = get_password(name, until, tries == 0 && !arg_verify, &passwords);
596 if (k == -EAGAIN)
597 continue;
598 else if (k < 0)
599 goto finish;
600 }
601
602 if (streq_ptr(arg_type, CRYPT_TCRYPT))
603 k = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
604 else
605 k = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags);
606 if (k >= 0)
607 break;
608 else if (k == -EAGAIN) {
609 key_file = NULL;
610 continue;
611 } else if (k != -EPERM) {
612 log_error("Failed to activate: %s", strerror(-k));
613 goto finish;
614 }
615
616 log_warning("Invalid passphrase.");
617 }
618
619 if (arg_tries != 0 && tries >= arg_tries) {
620 log_error("Too many attempts; giving up.");
621 r = EXIT_FAILURE;
622 goto finish;
623 }
624
625 } else if (streq(argv[1], "detach")) {
626 int k;
627
628 k = crypt_init_by_name(&cd, argv[2]);
629 if (k) {
630 log_error("crypt_init() failed: %s", strerror(-k));
631 goto finish;
632 }
633
634 crypt_set_log_callback(cd, log_glue, NULL);
635
636 k = crypt_deactivate(cd, argv[2]);
637 if (k < 0) {
638 log_error("Failed to deactivate: %s", strerror(-k));
639 goto finish;
640 }
641
642 } else {
643 log_error("Unknown verb %s.", argv[1]);
644 goto finish;
645 }
646
647 r = EXIT_SUCCESS;
648
649 finish:
650
651 if (cd)
652 crypt_free(cd);
653
654 free(arg_cipher);
655 free(arg_hash);
656 strv_free(arg_tcrypt_keyfiles);
657
658 return r;
659 }