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