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