1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "sd-device.h"
28 #include "alloc-util.h"
29 #include "ask-password-api.h"
30 #include "crypt-util.h"
31 #include "device-util.h"
35 #include "mount-util.h"
36 #include "parse-util.h"
37 #include "path-util.h"
38 #include "string-util.h"
43 #define ANY_LUKS "LUKS"
45 static const char *arg_type
= NULL
; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT or CRYPT_PLAIN */
46 static char *arg_cipher
= NULL
;
47 static unsigned arg_key_size
= 0;
48 static int arg_key_slot
= CRYPT_ANY_SLOT
;
49 static unsigned arg_keyfile_size
= 0;
50 static uint64_t arg_keyfile_offset
= 0;
51 static char *arg_hash
= NULL
;
52 static char *arg_header
= NULL
;
53 static unsigned arg_tries
= 3;
54 static bool arg_readonly
= false;
55 static bool arg_verify
= false;
56 static bool arg_discards
= false;
57 static bool arg_tcrypt_hidden
= false;
58 static bool arg_tcrypt_system
= false;
59 #ifdef CRYPT_TCRYPT_VERA_MODES
60 static bool arg_tcrypt_veracrypt
= false;
62 static char **arg_tcrypt_keyfiles
= NULL
;
63 static uint64_t arg_offset
= 0;
64 static uint64_t arg_skip
= 0;
65 static usec_t arg_timeout
= USEC_INFINITY
;
67 /* Options Debian's crypttab knows we don't:
77 static int parse_one_option(const char *option
) {
83 /* Handled outside of this tool */
84 if (STR_IN_SET(option
, "noauto", "auto", "nofail", "fail", "_netdev"))
87 if ((val
= startswith(option
, "cipher="))) {
88 r
= free_and_strdup(&arg_cipher
, val
);
92 } else if ((val
= startswith(option
, "size="))) {
94 r
= safe_atou(val
, &arg_key_size
);
96 log_error_errno(r
, "Failed to parse %s, ignoring: %m", option
);
100 if (arg_key_size
% 8) {
101 log_error("size= not a multiple of 8, ignoring.");
107 } else if ((val
= startswith(option
, "key-slot="))) {
110 r
= safe_atoi(val
, &arg_key_slot
);
112 log_error_errno(r
, "Failed to parse %s, ignoring: %m", option
);
116 } else if ((val
= startswith(option
, "tcrypt-keyfile="))) {
118 arg_type
= CRYPT_TCRYPT
;
119 if (path_is_absolute(val
)) {
120 if (strv_extend(&arg_tcrypt_keyfiles
, val
) < 0)
123 log_error("Key file path \"%s\" is not absolute. Ignoring.", val
);
125 } else if ((val
= startswith(option
, "keyfile-size="))) {
127 r
= safe_atou(val
, &arg_keyfile_size
);
129 log_error_errno(r
, "Failed to parse %s, ignoring: %m", option
);
133 } else if ((val
= startswith(option
, "keyfile-offset="))) {
136 r
= safe_atou64(val
, &off
);
138 log_error_errno(r
, "Failed to parse %s, ignoring: %m", option
);
142 if ((size_t) off
!= off
) {
143 /* https://gitlab.com/cryptsetup/cryptsetup/issues/359 */
144 log_error("keyfile-offset= value would truncated to %zu, ignoring.", (size_t) off
);
148 arg_keyfile_offset
= off
;
150 } else if ((val
= startswith(option
, "hash="))) {
151 r
= free_and_strdup(&arg_hash
, val
);
155 } else if ((val
= startswith(option
, "header="))) {
158 if (!path_is_absolute(val
)) {
159 log_error("Header path \"%s\" is not absolute, refusing.", val
);
164 log_error("Duplicate header= option, refusing.");
168 arg_header
= strdup(val
);
172 } else if ((val
= startswith(option
, "tries="))) {
174 r
= safe_atou(val
, &arg_tries
);
176 log_error_errno(r
, "Failed to parse %s, ignoring: %m", option
);
180 } else if (STR_IN_SET(option
, "readonly", "read-only"))
182 else if (streq(option
, "verify"))
184 else if (STR_IN_SET(option
, "allow-discards", "discard"))
186 else if (streq(option
, "luks"))
188 else if (streq(option
, "tcrypt"))
189 arg_type
= CRYPT_TCRYPT
;
190 else if (streq(option
, "tcrypt-hidden")) {
191 arg_type
= CRYPT_TCRYPT
;
192 arg_tcrypt_hidden
= true;
193 } else if (streq(option
, "tcrypt-system")) {
194 arg_type
= CRYPT_TCRYPT
;
195 arg_tcrypt_system
= true;
196 } else if (streq(option
, "tcrypt-veracrypt")) {
197 #ifdef CRYPT_TCRYPT_VERA_MODES
198 arg_type
= CRYPT_TCRYPT
;
199 arg_tcrypt_veracrypt
= true;
201 log_error("This version of cryptsetup does not support tcrypt-veracrypt; refusing.");
204 } else if (STR_IN_SET(option
, "plain", "swap", "tmp"))
205 arg_type
= CRYPT_PLAIN
;
206 else if ((val
= startswith(option
, "timeout="))) {
208 r
= parse_sec_fix_0(val
, &arg_timeout
);
210 log_error_errno(r
, "Failed to parse %s, ignoring: %m", option
);
214 } else if ((val
= startswith(option
, "offset="))) {
216 r
= safe_atou64(val
, &arg_offset
);
218 return log_error_errno(r
, "Failed to parse %s: %m", option
);
220 } else if ((val
= startswith(option
, "skip="))) {
222 r
= safe_atou64(val
, &arg_skip
);
224 return log_error_errno(r
, "Failed to parse %s: %m", option
);
226 } else if (!streq(option
, "none"))
227 log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option
);
232 static int parse_options(const char *options
) {
233 const char *word
, *state
;
239 FOREACH_WORD_SEPARATOR(word
, l
, options
, ",", state
) {
240 _cleanup_free_
char *o
;
242 o
= strndup(word
, l
);
245 r
= parse_one_option(o
);
250 /* sanity-check options */
251 if (arg_type
!= NULL
&& !streq(arg_type
, CRYPT_PLAIN
)) {
253 log_warning("offset= ignored with type %s", arg_type
);
255 log_warning("skip= ignored with type %s", arg_type
);
261 static char* disk_description(const char *path
) {
263 static const char name_fields
[] =
264 "ID_PART_ENTRY_NAME\0"
266 "ID_MODEL_FROM_DATABASE\0"
269 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
276 if (stat(path
, &st
) < 0)
279 if (!S_ISBLK(st
.st_mode
))
282 r
= sd_device_new_from_devnum(&device
, 'b', st
.st_rdev
);
286 NULSTR_FOREACH(i
, name_fields
) {
289 r
= sd_device_get_property_value(device
, i
, &name
);
290 if (r
>= 0 && !isempty(name
))
297 static char *disk_mount_point(const char *label
) {
298 _cleanup_free_
char *device
= NULL
;
299 _cleanup_endmntent_
FILE *f
= NULL
;
302 /* Yeah, we don't support native systemd unit files here for now */
304 if (asprintf(&device
, "/dev/mapper/%s", label
) < 0)
307 f
= setmntent("/etc/fstab", "re");
311 while ((m
= getmntent(f
)))
312 if (path_equal(m
->mnt_fsname
, device
))
313 return strdup(m
->mnt_dir
);
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
, *text
= NULL
, *disk_path
= NULL
;
320 _cleanup_strv_free_erase_
char **passwords
= NULL
;
321 const char *name
= NULL
;
329 description
= disk_description(src
);
330 mount_point
= disk_mount_point(vol
);
332 disk_path
= cescape(src
);
336 if (description
&& streq(vol
, description
))
337 /* If the description string is simply the
338 * volume name, then let's not show this
340 description
= mfree(description
);
342 if (mount_point
&& description
)
343 r
= asprintf(&name_buffer
, "%s (%s) on %s", description
, vol
, mount_point
);
344 else if (mount_point
)
345 r
= asprintf(&name_buffer
, "%s on %s", vol
, mount_point
);
346 else if (description
)
347 r
= asprintf(&name_buffer
, "%s (%s)", description
, vol
);
352 name
= name_buffer
? name_buffer
: vol
;
354 if (asprintf(&text
, "Please enter passphrase for disk %s!", name
) < 0)
357 id
= strjoina("cryptsetup:", disk_path
);
359 r
= ask_password_auto(text
, "drive-harddisk", id
, "cryptsetup", until
,
360 ASK_PASSWORD_PUSH_CACHE
| (accept_cached
*ASK_PASSWORD_ACCEPT_CACHED
),
363 return log_error_errno(r
, "Failed to query password: %m");
366 _cleanup_strv_free_erase_
char **passwords2
= NULL
;
368 assert(strv_length(passwords
) == 1);
370 if (asprintf(&text
, "Please enter passphrase for disk %s! (verification)", name
) < 0)
373 id
= strjoina("cryptsetup-verification:", disk_path
);
375 r
= ask_password_auto(text
, "drive-harddisk", id
, "cryptsetup", until
, ASK_PASSWORD_PUSH_CACHE
, &passwords2
);
377 return log_error_errno(r
, "Failed to query verification password: %m");
379 assert(strv_length(passwords2
) == 1);
381 if (!streq(passwords
[0], passwords2
[0])) {
382 log_warning("Passwords did not match, retrying.");
387 strv_uniq(passwords
);
389 STRV_FOREACH(p
, passwords
) {
392 if (strlen(*p
)+1 >= arg_key_size
)
395 /* Pad password if necessary */
396 c
= new(char, arg_key_size
);
400 strncpy(c
, *p
, arg_key_size
);
405 *ret
= TAKE_PTR(passwords
);
410 static int attach_tcrypt(
411 struct crypt_device
*cd
,
413 const char *key_file
,
418 _cleanup_free_
char *passphrase
= NULL
;
419 struct crypt_params_tcrypt params
= {
420 .flags
= CRYPT_TCRYPT_LEGACY_MODES
,
421 .keyfiles
= (const char **)arg_tcrypt_keyfiles
,
422 .keyfiles_count
= strv_length(arg_tcrypt_keyfiles
)
427 assert(key_file
|| (passwords
&& passwords
[0]));
429 if (arg_tcrypt_hidden
)
430 params
.flags
|= CRYPT_TCRYPT_HIDDEN_HEADER
;
432 if (arg_tcrypt_system
)
433 params
.flags
|= CRYPT_TCRYPT_SYSTEM_HEADER
;
435 #ifdef CRYPT_TCRYPT_VERA_MODES
436 if (arg_tcrypt_veracrypt
)
437 params
.flags
|= CRYPT_TCRYPT_VERA_MODES
;
441 r
= read_one_line_file(key_file
, &passphrase
);
443 log_error_errno(r
, "Failed to read password file '%s': %m", key_file
);
447 params
.passphrase
= passphrase
;
449 params
.passphrase
= passwords
[0];
450 params
.passphrase_size
= strlen(params
.passphrase
);
452 r
= crypt_load(cd
, CRYPT_TCRYPT
, ¶ms
);
454 if (key_file
&& r
== -EPERM
) {
455 log_error("Failed to activate using password file '%s'.", key_file
);
461 return crypt_activate_by_volume_key(cd
, name
, NULL
, 0, flags
);
464 static int attach_luks_or_plain(struct crypt_device
*cd
,
466 const char *key_file
,
467 const char *data_device
,
471 bool pass_volume_key
= false;
475 assert(key_file
|| passwords
);
477 if (!arg_type
|| STR_IN_SET(arg_type
, ANY_LUKS
, CRYPT_LUKS1
)) {
478 r
= crypt_load(cd
, CRYPT_LUKS
, NULL
);
480 log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd
));
485 r
= crypt_set_data_device(cd
, data_device
);
488 if ((!arg_type
&& r
< 0) || streq_ptr(arg_type
, CRYPT_PLAIN
)) {
489 struct crypt_params_plain params
= {
490 .offset
= arg_offset
,
493 const char *cipher
, *cipher_mode
;
494 _cleanup_free_
char *truncated_cipher
= NULL
;
497 /* plain isn't a real hash type. it just means "use no hash" */
498 if (!streq(arg_hash
, "plain"))
499 params
.hash
= arg_hash
;
500 } else if (!key_file
)
501 /* for CRYPT_PLAIN, the behaviour of cryptsetup
502 * package is to not hash when a key file is provided */
503 params
.hash
= "ripemd160";
508 l
= strcspn(arg_cipher
, "-");
509 truncated_cipher
= strndup(arg_cipher
, l
);
510 if (!truncated_cipher
)
513 cipher
= truncated_cipher
;
514 cipher_mode
= arg_cipher
[l
] ? arg_cipher
+l
+1 : "plain";
517 cipher_mode
= "cbc-essiv:sha256";
520 /* for CRYPT_PLAIN limit reads
521 * from keyfile to key length, and
522 * ignore keyfile-size */
523 arg_keyfile_size
= arg_key_size
;
525 /* In contrast to what the name
526 * crypt_setup() might suggest this
527 * doesn't actually format anything,
528 * it just configures encryption
529 * parameters when used for plain
531 r
= crypt_format(cd
, CRYPT_PLAIN
, cipher
, cipher_mode
, NULL
, NULL
, arg_keyfile_size
, ¶ms
);
533 /* hash == NULL implies the user passed "plain" */
534 pass_volume_key
= (params
.hash
== NULL
);
538 return log_error_errno(r
, "Loading of cryptographic parameters failed: %m");
540 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
541 crypt_get_cipher(cd
),
542 crypt_get_cipher_mode(cd
),
543 crypt_get_volume_key_size(cd
)*8,
544 crypt_get_device_name(cd
));
547 r
= crypt_activate_by_keyfile_offset(cd
, name
, arg_key_slot
, key_file
, arg_keyfile_size
, arg_keyfile_offset
, flags
);
549 log_error_errno(r
, "Failed to activate with key file '%s': %m", key_file
);
555 STRV_FOREACH(p
, passwords
) {
557 r
= crypt_activate_by_volume_key(cd
, name
, *p
, arg_key_size
, flags
);
559 r
= crypt_activate_by_passphrase(cd
, name
, arg_key_slot
, *p
, strlen(*p
), flags
);
569 static int help(void) {
571 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
572 "%s detach VOLUME\n\n"
573 "Attaches or detaches an encrypted block device.\n",
574 program_invocation_short_name
,
575 program_invocation_short_name
);
580 int main(int argc
, char *argv
[]) {
581 _cleanup_(crypt_freep
) struct crypt_device
*cd
= NULL
;
590 log_error("This program requires at least two arguments.");
594 log_set_target(LOG_TARGET_AUTO
);
595 log_parse_environment();
600 if (streq(argv
[1], "attach")) {
604 crypt_status_info status
;
605 const char *key_file
= NULL
;
607 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
610 log_error("attach requires at least two arguments.");
616 !streq(argv
[4], "-") &&
617 !streq(argv
[4], "none")) {
619 if (!path_is_absolute(argv
[4]))
620 log_error("Password file path '%s' is not absolute. Ignoring.", argv
[4]);
625 if (argc
>= 6 && argv
[5][0] && !streq(argv
[5], "-")) {
626 if (parse_options(argv
[5]) < 0)
630 /* A delicious drop of snake oil */
631 mlockall(MCL_FUTURE
);
634 log_debug("LUKS header: %s", arg_header
);
635 r
= crypt_init(&cd
, arg_header
);
637 r
= crypt_init(&cd
, argv
[3]);
639 log_error_errno(r
, "crypt_init() failed: %m");
643 crypt_set_log_callback(cd
, cryptsetup_log_glue
, NULL
);
645 status
= crypt_status(cd
, argv
[2]);
646 if (IN_SET(status
, CRYPT_ACTIVE
, CRYPT_BUSY
)) {
647 log_info("Volume %s already active.", argv
[2]);
653 flags
|= CRYPT_ACTIVATE_READONLY
;
656 flags
|= CRYPT_ACTIVATE_ALLOW_DISCARDS
;
658 if (arg_timeout
== USEC_INFINITY
)
661 until
= now(CLOCK_MONOTONIC
) + arg_timeout
;
663 arg_key_size
= (arg_key_size
> 0 ? arg_key_size
: (256 / 8));
668 /* Ideally we'd do this on the open fd, but since this is just a
669 * warning it's OK to do this in two steps. */
670 if (stat(key_file
, &st
) >= 0 && S_ISREG(st
.st_mode
) && (st
.st_mode
& 0005))
671 log_warning("Key file %s is world-readable. This is not a good idea!", key_file
);
674 for (tries
= 0; arg_tries
== 0 || tries
< arg_tries
; tries
++) {
675 _cleanup_strv_free_erase_
char **passwords
= NULL
;
678 r
= get_password(argv
[2], argv
[3], until
, tries
== 0 && !arg_verify
, &passwords
);
685 if (streq_ptr(arg_type
, CRYPT_TCRYPT
))
686 r
= attach_tcrypt(cd
, argv
[2], key_file
, passwords
, flags
);
688 r
= attach_luks_or_plain(cd
,
691 arg_header
? argv
[3] : NULL
,
701 log_error_errno(r
, "Failed to activate: %m");
705 log_warning("Invalid passphrase.");
708 if (arg_tries
!= 0 && tries
>= arg_tries
) {
709 log_error("Too many attempts; giving up.");
714 } else if (streq(argv
[1], "detach")) {
716 r
= crypt_init_by_name(&cd
, argv
[2]);
718 log_info("Volume %s already inactive.", argv
[2]);
723 log_error_errno(r
, "crypt_init_by_name() failed: %m");
727 crypt_set_log_callback(cd
, cryptsetup_log_glue
, NULL
);
729 r
= crypt_deactivate(cd
, argv
[2]);
731 log_error_errno(r
, "Failed to deactivate: %m");
736 log_error("Unknown verb %s.", argv
[1]);
746 strv_free(arg_tcrypt_keyfiles
);
748 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;