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