]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/cryptsetup/cryptsetup.c
cryptsetup: check that password is not null
[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 char *state, *w;
179 size_t l;
180 int r;
181
182 assert(options);
183
184 FOREACH_WORD_SEPARATOR(w, l, options, ",", state) {
185 _cleanup_free_ char *o;
186
187 o = strndup(w, 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("Failed to query password: %s", strerror(-r));
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("Failed to query verification password: %s", strerror(-r));
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("Failed to read password file '%s': %s", key_file, strerror(-r));
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
404 params.hash = "ripemd160";
405
406 if (arg_cipher) {
407 size_t l;
408
409 l = strcspn(arg_cipher, "-");
410 truncated_cipher = strndup(arg_cipher, l);
411 if (!truncated_cipher)
412 return log_oom();
413
414 cipher = truncated_cipher;
415 cipher_mode = arg_cipher[l] ? arg_cipher+l+1 : "plain";
416 } else {
417 cipher = "aes";
418 cipher_mode = "cbc-essiv:sha256";
419 }
420
421 /* for CRYPT_PLAIN limit reads
422 * from keyfile to key length, and
423 * ignore keyfile-size */
424 arg_keyfile_size = arg_key_size;
425
426 /* In contrast to what the name
427 * crypt_setup() might suggest this
428 * doesn't actually format anything,
429 * it just configures encryption
430 * parameters when used for plain
431 * mode. */
432 r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode,
433 NULL, NULL, arg_keyfile_size, &params);
434
435 /* hash == NULL implies the user passed "plain" */
436 pass_volume_key = (params.hash == NULL);
437 }
438
439 if (r < 0) {
440 log_error("Loading of cryptographic parameters failed: %s", strerror(-r));
441 return r;
442 }
443
444 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
445 crypt_get_cipher(cd),
446 crypt_get_cipher_mode(cd),
447 crypt_get_volume_key_size(cd)*8,
448 crypt_get_device_name(cd));
449
450 if (key_file) {
451 r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot,
452 key_file, arg_keyfile_size,
453 arg_keyfile_offset, flags);
454 if (r < 0) {
455 log_error("Failed to activate with key file '%s': %s", key_file, strerror(-r));
456 return -EAGAIN;
457 }
458 } else {
459 char **p;
460
461 STRV_FOREACH(p, passwords) {
462 if (pass_volume_key)
463 r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
464 else
465 r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
466
467 if (r >= 0)
468 break;
469 }
470 }
471
472 return r;
473 }
474
475 static int help(void) {
476
477 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
478 "%s detach VOLUME\n\n"
479 "Attaches or detaches an encrypted block device.\n",
480 program_invocation_short_name,
481 program_invocation_short_name);
482
483 return 0;
484 }
485
486 int main(int argc, char *argv[]) {
487 int r = EXIT_FAILURE;
488 struct crypt_device *cd = NULL;
489
490 if (argc <= 1) {
491 help();
492 return EXIT_SUCCESS;
493 }
494
495 if (argc < 3) {
496 log_error("This program requires at least two arguments.");
497 return EXIT_FAILURE;
498 }
499
500 log_set_target(LOG_TARGET_AUTO);
501 log_parse_environment();
502 log_open();
503
504 umask(0022);
505
506 if (streq(argv[1], "attach")) {
507 uint32_t flags = 0;
508 int k;
509 unsigned tries;
510 usec_t until;
511 crypt_status_info status;
512 const char *key_file = NULL, *name = NULL;
513 _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
514
515 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
516
517 if (argc < 4) {
518 log_error("attach requires at least two arguments.");
519 goto finish;
520 }
521
522 if (argc >= 5 &&
523 argv[4][0] &&
524 !streq(argv[4], "-") &&
525 !streq(argv[4], "none")) {
526
527 if (!path_is_absolute(argv[4]))
528 log_error("Password file path '%s' is not absolute. Ignoring.", argv[4]);
529 else
530 key_file = argv[4];
531 }
532
533 if (argc >= 6 && argv[5][0] && !streq(argv[5], "-")) {
534 if (parse_options(argv[5]) < 0)
535 goto finish;
536 }
537
538 /* A delicious drop of snake oil */
539 mlockall(MCL_FUTURE);
540
541 description = disk_description(argv[3]);
542 mount_point = disk_mount_point(argv[2]);
543
544 if (description && streq(argv[2], description)) {
545 /* If the description string is simply the
546 * volume name, then let's not show this
547 * twice */
548 free(description);
549 description = NULL;
550 }
551
552 if (mount_point && description)
553 asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
554 else if (mount_point)
555 asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
556 else if (description)
557 asprintf(&name_buffer, "%s (%s)", description, argv[2]);
558
559 name = name_buffer ? name_buffer : argv[2];
560
561 k = crypt_init(&cd, argv[3]);
562 if (k) {
563 log_error("crypt_init() failed: %s", strerror(-k));
564 goto finish;
565 }
566
567 crypt_set_log_callback(cd, log_glue, NULL);
568
569 status = crypt_status(cd, argv[2]);
570 if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
571 log_info("Volume %s already active.", argv[2]);
572 r = EXIT_SUCCESS;
573 goto finish;
574 }
575
576 if (arg_readonly)
577 flags |= CRYPT_ACTIVATE_READONLY;
578
579 if (arg_discards)
580 flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
581
582 if (arg_timeout > 0)
583 until = now(CLOCK_MONOTONIC) + arg_timeout;
584 else
585 until = 0;
586
587 arg_key_size = (arg_key_size > 0 ? arg_key_size : (256 / 8));
588
589 if (key_file) {
590 struct stat st;
591
592 /* Ideally we'd do this on the open fd, but since this is just a
593 * warning it's OK to do this in two steps. */
594 if (stat(key_file, &st) >= 0 && (st.st_mode & 0005))
595 log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
596 }
597
598 for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
599 _cleanup_strv_free_ char **passwords = NULL;
600
601 if (!key_file) {
602 k = get_password(name, until, tries == 0 && !arg_verify, &passwords);
603 if (k == -EAGAIN)
604 continue;
605 else if (k < 0)
606 goto finish;
607 }
608
609 if (streq_ptr(arg_type, CRYPT_TCRYPT))
610 k = attach_tcrypt(cd, argv[2], key_file, passwords, flags);
611 else
612 k = attach_luks_or_plain(cd, argv[2], key_file, passwords, flags);
613 if (k >= 0)
614 break;
615 else if (k == -EAGAIN) {
616 key_file = NULL;
617 continue;
618 } else if (k != -EPERM) {
619 log_error("Failed to activate: %s", strerror(-k));
620 goto finish;
621 }
622
623 log_warning("Invalid passphrase.");
624 }
625
626 if (arg_tries != 0 && tries >= arg_tries) {
627 log_error("Too many attempts; giving up.");
628 r = EXIT_FAILURE;
629 goto finish;
630 }
631
632 } else if (streq(argv[1], "detach")) {
633 int k;
634
635 k = crypt_init_by_name(&cd, argv[2]);
636 if (k) {
637 log_error("crypt_init() failed: %s", strerror(-k));
638 goto finish;
639 }
640
641 crypt_set_log_callback(cd, log_glue, NULL);
642
643 k = crypt_deactivate(cd, argv[2]);
644 if (k < 0) {
645 log_error("Failed to deactivate: %s", strerror(-k));
646 goto finish;
647 }
648
649 } else {
650 log_error("Unknown verb %s.", argv[1]);
651 goto finish;
652 }
653
654 r = EXIT_SUCCESS;
655
656 finish:
657
658 if (cd)
659 crypt_free(cd);
660
661 free(arg_cipher);
662 free(arg_hash);
663 strv_free(arg_tcrypt_keyfiles);
664
665 return r;
666 }