]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup.c
treewide: auto-convert the simple cases to log_*_errno()
[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 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 log_error_errno(-r, "Failed to query password: %m");
285 return r;
286 }
287
288 if (arg_verify) {
289 _cleanup_strv_free_ char **passwords2 = NULL;
290
291 assert(strv_length(*passwords) == 1);
292
293 if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0)
294 return log_oom();
295
296 id = strappenda("cryptsetup-verification:", escaped_name);
297
298 r = ask_password_auto(text, "drive-harddisk", id, until, false, &passwords2);
299 if (r < 0) {
300 log_error_errno(-r, "Failed to query verification password: %m");
301 return r;
302 }
303
304 assert(strv_length(passwords2) == 1);
305
306 if (!streq(*passwords[0], passwords2[0])) {
307 log_warning("Passwords did not match, retrying.");
308 return -EAGAIN;
309 }
310 }
311
312 strv_uniq(*passwords);
313
314 STRV_FOREACH(p, *passwords) {
315 char *c;
316
317 if (strlen(*p)+1 >= arg_key_size)
318 continue;
319
320 /* Pad password if necessary */
321 if (!(c = new(char, arg_key_size)))
322 return log_oom();
323
324 strncpy(c, *p, arg_key_size);
325 free(*p);
326 *p = c;
327 }
328
329 return 0;
330 }
331
332 static int attach_tcrypt(struct crypt_device *cd,
333 const char *name,
334 const char *key_file,
335 char **passwords,
336 uint32_t flags) {
337 int r = 0;
338 _cleanup_free_ char *passphrase = NULL;
339 struct crypt_params_tcrypt params = {
340 .flags = CRYPT_TCRYPT_LEGACY_MODES,
341 .keyfiles = (const char **)arg_tcrypt_keyfiles,
342 .keyfiles_count = strv_length(arg_tcrypt_keyfiles)
343 };
344
345 assert(cd);
346 assert(name);
347 assert(key_file || (passwords && passwords[0]));
348
349 if (arg_tcrypt_hidden)
350 params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
351
352 if (arg_tcrypt_system)
353 params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
354
355 if (key_file) {
356 r = read_one_line_file(key_file, &passphrase);
357 if (r < 0) {
358 log_error_errno(-r, "Failed to read password file '%s': %m", key_file);
359 return -EAGAIN;
360 }
361
362 params.passphrase = passphrase;
363 } else
364 params.passphrase = passwords[0];
365 params.passphrase_size = strlen(params.passphrase);
366
367 r = crypt_load(cd, CRYPT_TCRYPT, &params);
368 if (r < 0) {
369 if (key_file && r == -EPERM) {
370 log_error("Failed to activate using password file '%s'.", key_file);
371 return -EAGAIN;
372 }
373 return r;
374 }
375
376 return crypt_activate_by_volume_key(cd, name, NULL, 0, flags);
377 }
378
379 static int attach_luks_or_plain(struct crypt_device *cd,
380 const char *name,
381 const char *key_file,
382 char **passwords,
383 uint32_t flags) {
384 int r = 0;
385 bool pass_volume_key = false;
386
387 assert(cd);
388 assert(name);
389 assert(key_file || passwords);
390
391 if (!arg_type || streq(arg_type, CRYPT_LUKS1))
392 r = crypt_load(cd, CRYPT_LUKS1, NULL);
393
394 if ((!arg_type && r < 0) || streq_ptr(arg_type, CRYPT_PLAIN)) {
395 struct crypt_params_plain params = {};
396 const char *cipher, *cipher_mode;
397 _cleanup_free_ char *truncated_cipher = NULL;
398
399 if (arg_hash) {
400 /* plain isn't a real hash type. it just means "use no hash" */
401 if (!streq(arg_hash, "plain"))
402 params.hash = arg_hash;
403 } else if (!key_file)
404 /* for CRYPT_PLAIN, the behaviour of cryptsetup
405 * package is to not hash when a key file is provided */
406 params.hash = "ripemd160";
407
408 if (arg_cipher) {
409 size_t l;
410
411 l = strcspn(arg_cipher, "-");
412 truncated_cipher = strndup(arg_cipher, l);
413 if (!truncated_cipher)
414 return log_oom();
415
416 cipher = truncated_cipher;
417 cipher_mode = arg_cipher[l] ? arg_cipher+l+1 : "plain";
418 } else {
419 cipher = "aes";
420 cipher_mode = "cbc-essiv:sha256";
421 }
422
423 /* for CRYPT_PLAIN limit reads
424 * from keyfile to key length, and
425 * ignore keyfile-size */
426 arg_keyfile_size = arg_key_size;
427
428 /* In contrast to what the name
429 * crypt_setup() might suggest this
430 * doesn't actually format anything,
431 * it just configures encryption
432 * parameters when used for plain
433 * mode. */
434 r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode,
435 NULL, NULL, arg_keyfile_size, &params);
436
437 /* hash == NULL implies the user passed "plain" */
438 pass_volume_key = (params.hash == NULL);
439 }
440
441 if (r < 0) {
442 log_error_errno(-r, "Loading of cryptographic parameters failed: %m");
443 return r;
444 }
445
446 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
447 crypt_get_cipher(cd),
448 crypt_get_cipher_mode(cd),
449 crypt_get_volume_key_size(cd)*8,
450 crypt_get_device_name(cd));
451
452 if (key_file) {
453 r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot,
454 key_file, arg_keyfile_size,
455 arg_keyfile_offset, flags);
456 if (r < 0) {
457 log_error_errno(-r, "Failed to activate with key file '%s': %m", key_file);
458 return -EAGAIN;
459 }
460 } else {
461 char **p;
462
463 STRV_FOREACH(p, passwords) {
464 if (pass_volume_key)
465 r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
466 else
467 r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
468
469 if (r >= 0)
470 break;
471 }
472 }
473
474 return r;
475 }
476
477 static int help(void) {
478
479 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
480 "%s detach VOLUME\n\n"
481 "Attaches or detaches an encrypted block device.\n",
482 program_invocation_short_name,
483 program_invocation_short_name);
484
485 return 0;
486 }
487
488 int main(int argc, char *argv[]) {
489 int r = EXIT_FAILURE;
490 struct crypt_device *cd = NULL;
491
492 if (argc <= 1) {
493 help();
494 return EXIT_SUCCESS;
495 }
496
497 if (argc < 3) {
498 log_error("This program requires at least two arguments.");
499 return EXIT_FAILURE;
500 }
501
502 log_set_target(LOG_TARGET_AUTO);
503 log_parse_environment();
504 log_open();
505
506 umask(0022);
507
508 if (streq(argv[1], "attach")) {
509 uint32_t flags = 0;
510 int k;
511 unsigned tries;
512 usec_t until;
513 crypt_status_info status;
514 const char *key_file = NULL, *name = NULL;
515 _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
516
517 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
518
519 if (argc < 4) {
520 log_error("attach requires at least two arguments.");
521 goto finish;
522 }
523
524 if (argc >= 5 &&
525 argv[4][0] &&
526 !streq(argv[4], "-") &&
527 !streq(argv[4], "none")) {
528
529 if (!path_is_absolute(argv[4]))
530 log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
531 else
532 key_file = argv[4];
533 }
534
535 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
536 if (parse_options(argv[5]) < 0)
537 goto finish;
538 }
539
540 /* A delicious drop of snake oil */
541 mlockall(MCL_FUTURE);
542
543 description = disk_description(argv[3]);
544 mount_point = disk_mount_point(argv[2]);
545
546 if (description && streq(argv[2], description)) {
547 /* If the description string is simply the
548 * volume name, then let's not show this
549 * twice */
550 free(description);
551 description = NULL;
552 }
553
554 k = 0;
555 if (mount_point && description)
556 k = asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
557 else if (mount_point)
558 k = asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
559 else if (description)
560 k = asprintf(&name_buffer, "%s (%s)", description, argv[2]);
561
562 if (k < 0) {
563 log_oom();
564 goto finish;
565 }
566 name = name_buffer ? name_buffer : argv[2];
567
568 k = crypt_init(&cd, argv[3]);
569 if (k) {
570 log_error_errno(-k, "crypt_init() failed: %m");
571 goto finish;
572 }
573
574 crypt_set_log_callback(cd, log_glue, NULL);
575
576 status = crypt_status(cd, argv[2]);
577 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
578 log_info("Volume %s already active.", argv[2]);
579 r = EXIT_SUCCESS;
580 goto finish;
581 }
582
583 if (arg_readonly)
584 flags |= CRYPT_ACTIVATE_READONLY;
585
586 if (arg_discards)
587 flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
588
589 if (arg_timeout > 0)
590 until = now(CLOCK_MONOTONIC) + arg_timeout;
591 else
592 until = 0;
593
594 arg_key_size = (arg_key_size > 0 ? arg_key_size : (256 / 8));
595
596 if (key_file) {
597 struct stat st;
598
599 /* Ideally we'd do this on the open fd, but since this is just a
600 * warning it's OK to do this in two steps. */
601 if (stat(key_file, &st) >= 0 && (st.st_mode & 0005))
602 log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
603 }
604
605 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
606 _cleanup_strv_free_ char **passwords = NULL;
607
608 if (!key_file) {
609 k = get_password(name, until, tries == 0 && !arg_verify, &passwords);
610 if (k == -EAGAIN)
611 continue;
612 else if (k < 0)
613 goto finish;
614 }
615
616 if (streq_ptr(arg_type, CRYPT_TCRYPT))
617 k = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
618 else
619 k = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags);
620 if (k >= 0)
621 break;
622 else if (k == -EAGAIN) {
623 key_file = NULL;
624 continue;
625 } else if (k != -EPERM) {
626 log_error_errno(-k, "Failed to activate: %m");
627 goto finish;
628 }
629
630 log_warning("Invalid passphrase.");
631 }
632
633 if (arg_tries != 0 && tries >= arg_tries) {
634 log_error("Too many attempts; giving up.");
635 r = EXIT_FAILURE;
636 goto finish;
637 }
638
639 } else if (streq(argv[1], "detach")) {
640 int k;
641
642 k = crypt_init_by_name(&cd, argv[2]);
643 if (k) {
644 log_error_errno(-k, "crypt_init() failed: %m");
645 goto finish;
646 }
647
648 crypt_set_log_callback(cd, log_glue, NULL);
649
650 k = crypt_deactivate(cd, argv[2]);
651 if (k < 0) {
652 log_error_errno(-k, "Failed to deactivate: %m");
653 goto finish;
654 }
655
656 } else {
657 log_error("Unknown verb %s.", argv[1]);
658 goto finish;
659 }
660
661 r = EXIT_SUCCESS;
662
663 finish:
664
665 if (cd)
666 crypt_free(cd);
667
668 free(arg_cipher);
669 free(arg_hash);
670 strv_free(arg_tcrypt_keyfiles);
671
672 return r;
673 }