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