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