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 unsigned 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="))) {
135 r
= safe_atou(val
, &arg_keyfile_offset
);
137 log_error_errno(r
, "Failed to parse %s, ignoring: %m", option
);
141 } else if ((val
= startswith(option
, "hash="))) {
142 r
= free_and_strdup(&arg_hash
, val
);
146 } else if ((val
= startswith(option
, "header="))) {
149 if (!path_is_absolute(val
)) {
150 log_error("Header path \"%s\" is not absolute, refusing.", val
);
155 log_error("Duplicate header= option, refusing.");
159 arg_header
= strdup(val
);
163 } else if ((val
= startswith(option
, "tries="))) {
165 r
= safe_atou(val
, &arg_tries
);
167 log_error_errno(r
, "Failed to parse %s, ignoring: %m", option
);
171 } else if (STR_IN_SET(option
, "readonly", "read-only"))
173 else if (streq(option
, "verify"))
175 else if (STR_IN_SET(option
, "allow-discards", "discard"))
177 else if (streq(option
, "luks"))
179 else if (streq(option
, "tcrypt"))
180 arg_type
= CRYPT_TCRYPT
;
181 else if (streq(option
, "tcrypt-hidden")) {
182 arg_type
= CRYPT_TCRYPT
;
183 arg_tcrypt_hidden
= true;
184 } else if (streq(option
, "tcrypt-system")) {
185 arg_type
= CRYPT_TCRYPT
;
186 arg_tcrypt_system
= true;
187 } else if (streq(option
, "tcrypt-veracrypt")) {
188 #ifdef CRYPT_TCRYPT_VERA_MODES
189 arg_type
= CRYPT_TCRYPT
;
190 arg_tcrypt_veracrypt
= true;
192 log_error("This version of cryptsetup does not support tcrypt-veracrypt; refusing.");
195 } else if (STR_IN_SET(option
, "plain", "swap", "tmp"))
196 arg_type
= CRYPT_PLAIN
;
197 else if ((val
= startswith(option
, "timeout="))) {
199 r
= parse_sec_fix_0(val
, &arg_timeout
);
201 log_error_errno(r
, "Failed to parse %s, ignoring: %m", option
);
205 } else if ((val
= startswith(option
, "offset="))) {
207 r
= safe_atou64(val
, &arg_offset
);
209 return log_error_errno(r
, "Failed to parse %s: %m", option
);
211 } else if ((val
= startswith(option
, "skip="))) {
213 r
= safe_atou64(val
, &arg_skip
);
215 return log_error_errno(r
, "Failed to parse %s: %m", option
);
217 } else if (!streq(option
, "none"))
218 log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option
);
223 static int parse_options(const char *options
) {
224 const char *word
, *state
;
230 FOREACH_WORD_SEPARATOR(word
, l
, options
, ",", state
) {
231 _cleanup_free_
char *o
;
233 o
= strndup(word
, l
);
236 r
= parse_one_option(o
);
241 /* sanity-check options */
242 if (arg_type
!= NULL
&& !streq(arg_type
, CRYPT_PLAIN
)) {
244 log_warning("offset= ignored with type %s", arg_type
);
246 log_warning("skip= ignored with type %s", arg_type
);
252 static char* disk_description(const char *path
) {
254 static const char name_fields
[] =
255 "ID_PART_ENTRY_NAME\0"
257 "ID_MODEL_FROM_DATABASE\0"
260 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
267 if (stat(path
, &st
) < 0)
270 if (!S_ISBLK(st
.st_mode
))
273 r
= sd_device_new_from_devnum(&device
, 'b', st
.st_rdev
);
277 NULSTR_FOREACH(i
, name_fields
) {
280 r
= sd_device_get_property_value(device
, i
, &name
);
281 if (r
>= 0 && !isempty(name
))
288 static char *disk_mount_point(const char *label
) {
289 _cleanup_free_
char *device
= NULL
;
290 _cleanup_endmntent_
FILE *f
= NULL
;
293 /* Yeah, we don't support native systemd unit files here for now */
295 if (asprintf(&device
, "/dev/mapper/%s", label
) < 0)
298 f
= setmntent("/etc/fstab", "re");
302 while ((m
= getmntent(f
)))
303 if (path_equal(m
->mnt_fsname
, device
))
304 return strdup(m
->mnt_dir
);
309 static int get_password(const char *vol
, const char *src
, usec_t until
, bool accept_cached
, char ***ret
) {
310 _cleanup_free_
char *description
= NULL
, *name_buffer
= NULL
, *mount_point
= NULL
, *text
= NULL
, *disk_path
= NULL
;
311 _cleanup_strv_free_erase_
char **passwords
= NULL
;
312 const char *name
= NULL
;
320 description
= disk_description(src
);
321 mount_point
= disk_mount_point(vol
);
323 disk_path
= cescape(src
);
327 if (description
&& streq(vol
, description
))
328 /* If the description string is simply the
329 * volume name, then let's not show this
331 description
= mfree(description
);
333 if (mount_point
&& description
)
334 r
= asprintf(&name_buffer
, "%s (%s) on %s", description
, vol
, mount_point
);
335 else if (mount_point
)
336 r
= asprintf(&name_buffer
, "%s on %s", vol
, mount_point
);
337 else if (description
)
338 r
= asprintf(&name_buffer
, "%s (%s)", description
, vol
);
343 name
= name_buffer
? name_buffer
: vol
;
345 if (asprintf(&text
, "Please enter passphrase for disk %s!", name
) < 0)
348 id
= strjoina("cryptsetup:", disk_path
);
350 r
= ask_password_auto(text
, "drive-harddisk", id
, "cryptsetup", until
,
351 ASK_PASSWORD_PUSH_CACHE
| (accept_cached
*ASK_PASSWORD_ACCEPT_CACHED
),
354 return log_error_errno(r
, "Failed to query password: %m");
357 _cleanup_strv_free_erase_
char **passwords2
= NULL
;
359 assert(strv_length(passwords
) == 1);
361 if (asprintf(&text
, "Please enter passphrase for disk %s! (verification)", name
) < 0)
364 id
= strjoina("cryptsetup-verification:", disk_path
);
366 r
= ask_password_auto(text
, "drive-harddisk", id
, "cryptsetup", until
, ASK_PASSWORD_PUSH_CACHE
, &passwords2
);
368 return log_error_errno(r
, "Failed to query verification password: %m");
370 assert(strv_length(passwords2
) == 1);
372 if (!streq(passwords
[0], passwords2
[0])) {
373 log_warning("Passwords did not match, retrying.");
378 strv_uniq(passwords
);
380 STRV_FOREACH(p
, passwords
) {
383 if (strlen(*p
)+1 >= arg_key_size
)
386 /* Pad password if necessary */
387 c
= new(char, arg_key_size
);
391 strncpy(c
, *p
, arg_key_size
);
402 static int attach_tcrypt(
403 struct crypt_device
*cd
,
405 const char *key_file
,
410 _cleanup_free_
char *passphrase
= NULL
;
411 struct crypt_params_tcrypt params
= {
412 .flags
= CRYPT_TCRYPT_LEGACY_MODES
,
413 .keyfiles
= (const char **)arg_tcrypt_keyfiles
,
414 .keyfiles_count
= strv_length(arg_tcrypt_keyfiles
)
419 assert(key_file
|| (passwords
&& passwords
[0]));
421 if (arg_tcrypt_hidden
)
422 params
.flags
|= CRYPT_TCRYPT_HIDDEN_HEADER
;
424 if (arg_tcrypt_system
)
425 params
.flags
|= CRYPT_TCRYPT_SYSTEM_HEADER
;
427 #ifdef CRYPT_TCRYPT_VERA_MODES
428 if (arg_tcrypt_veracrypt
)
429 params
.flags
|= CRYPT_TCRYPT_VERA_MODES
;
433 r
= read_one_line_file(key_file
, &passphrase
);
435 log_error_errno(r
, "Failed to read password file '%s': %m", key_file
);
439 params
.passphrase
= passphrase
;
441 params
.passphrase
= passwords
[0];
442 params
.passphrase_size
= strlen(params
.passphrase
);
444 r
= crypt_load(cd
, CRYPT_TCRYPT
, ¶ms
);
446 if (key_file
&& r
== -EPERM
) {
447 log_error("Failed to activate using password file '%s'.", key_file
);
453 return crypt_activate_by_volume_key(cd
, name
, NULL
, 0, flags
);
456 static int attach_luks_or_plain(struct crypt_device
*cd
,
458 const char *key_file
,
459 const char *data_device
,
463 bool pass_volume_key
= false;
467 assert(key_file
|| passwords
);
469 if (!arg_type
|| STR_IN_SET(arg_type
, ANY_LUKS
, CRYPT_LUKS1
)) {
470 r
= crypt_load(cd
, CRYPT_LUKS
, NULL
);
472 log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd
));
477 r
= crypt_set_data_device(cd
, data_device
);
480 if ((!arg_type
&& r
< 0) || streq_ptr(arg_type
, CRYPT_PLAIN
)) {
481 struct crypt_params_plain params
= {
482 .offset
= arg_offset
,
485 const char *cipher
, *cipher_mode
;
486 _cleanup_free_
char *truncated_cipher
= NULL
;
489 /* plain isn't a real hash type. it just means "use no hash" */
490 if (!streq(arg_hash
, "plain"))
491 params
.hash
= arg_hash
;
492 } else if (!key_file
)
493 /* for CRYPT_PLAIN, the behaviour of cryptsetup
494 * package is to not hash when a key file is provided */
495 params
.hash
= "ripemd160";
500 l
= strcspn(arg_cipher
, "-");
501 truncated_cipher
= strndup(arg_cipher
, l
);
502 if (!truncated_cipher
)
505 cipher
= truncated_cipher
;
506 cipher_mode
= arg_cipher
[l
] ? arg_cipher
+l
+1 : "plain";
509 cipher_mode
= "cbc-essiv:sha256";
512 /* for CRYPT_PLAIN limit reads
513 * from keyfile to key length, and
514 * ignore keyfile-size */
515 arg_keyfile_size
= arg_key_size
;
517 /* In contrast to what the name
518 * crypt_setup() might suggest this
519 * doesn't actually format anything,
520 * it just configures encryption
521 * parameters when used for plain
523 r
= crypt_format(cd
, CRYPT_PLAIN
, cipher
, cipher_mode
, NULL
, NULL
, arg_keyfile_size
, ¶ms
);
525 /* hash == NULL implies the user passed "plain" */
526 pass_volume_key
= (params
.hash
== NULL
);
530 return log_error_errno(r
, "Loading of cryptographic parameters failed: %m");
532 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
533 crypt_get_cipher(cd
),
534 crypt_get_cipher_mode(cd
),
535 crypt_get_volume_key_size(cd
)*8,
536 crypt_get_device_name(cd
));
539 r
= crypt_activate_by_keyfile_offset(cd
, name
, arg_key_slot
, key_file
, arg_keyfile_size
, arg_keyfile_offset
, flags
);
541 log_error_errno(r
, "Failed to activate with key file '%s': %m", key_file
);
547 STRV_FOREACH(p
, passwords
) {
549 r
= crypt_activate_by_volume_key(cd
, name
, *p
, arg_key_size
, flags
);
551 r
= crypt_activate_by_passphrase(cd
, name
, arg_key_slot
, *p
, strlen(*p
), flags
);
561 static int help(void) {
563 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
564 "%s detach VOLUME\n\n"
565 "Attaches or detaches an encrypted block device.\n",
566 program_invocation_short_name
,
567 program_invocation_short_name
);
572 int main(int argc
, char *argv
[]) {
573 _cleanup_(crypt_freep
) struct crypt_device
*cd
= NULL
;
582 log_error("This program requires at least two arguments.");
586 log_set_target(LOG_TARGET_AUTO
);
587 log_parse_environment();
592 if (streq(argv
[1], "attach")) {
596 crypt_status_info status
;
597 const char *key_file
= NULL
;
599 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
602 log_error("attach requires at least two arguments.");
608 !streq(argv
[4], "-") &&
609 !streq(argv
[4], "none")) {
611 if (!path_is_absolute(argv
[4]))
612 log_error("Password file path '%s' is not absolute. Ignoring.", argv
[4]);
617 if (argc
>= 6 && argv
[5][0] && !streq(argv
[5], "-")) {
618 if (parse_options(argv
[5]) < 0)
622 /* A delicious drop of snake oil */
623 mlockall(MCL_FUTURE
);
626 log_debug("LUKS header: %s", arg_header
);
627 r
= crypt_init(&cd
, arg_header
);
629 r
= crypt_init(&cd
, argv
[3]);
631 log_error_errno(r
, "crypt_init() failed: %m");
635 crypt_set_log_callback(cd
, cryptsetup_log_glue
, NULL
);
637 status
= crypt_status(cd
, argv
[2]);
638 if (IN_SET(status
, CRYPT_ACTIVE
, CRYPT_BUSY
)) {
639 log_info("Volume %s already active.", argv
[2]);
645 flags
|= CRYPT_ACTIVATE_READONLY
;
648 flags
|= CRYPT_ACTIVATE_ALLOW_DISCARDS
;
650 if (arg_timeout
== USEC_INFINITY
)
653 until
= now(CLOCK_MONOTONIC
) + arg_timeout
;
655 arg_key_size
= (arg_key_size
> 0 ? arg_key_size
: (256 / 8));
660 /* Ideally we'd do this on the open fd, but since this is just a
661 * warning it's OK to do this in two steps. */
662 if (stat(key_file
, &st
) >= 0 && S_ISREG(st
.st_mode
) && (st
.st_mode
& 0005))
663 log_warning("Key file %s is world-readable. This is not a good idea!", key_file
);
666 for (tries
= 0; arg_tries
== 0 || tries
< arg_tries
; tries
++) {
667 _cleanup_strv_free_erase_
char **passwords
= NULL
;
670 r
= get_password(argv
[2], argv
[3], until
, tries
== 0 && !arg_verify
, &passwords
);
677 if (streq_ptr(arg_type
, CRYPT_TCRYPT
))
678 r
= attach_tcrypt(cd
, argv
[2], key_file
, passwords
, flags
);
680 r
= attach_luks_or_plain(cd
,
683 arg_header
? argv
[3] : NULL
,
693 log_error_errno(r
, "Failed to activate: %m");
697 log_warning("Invalid passphrase.");
700 if (arg_tries
!= 0 && tries
>= arg_tries
) {
701 log_error("Too many attempts; giving up.");
706 } else if (streq(argv
[1], "detach")) {
708 r
= crypt_init_by_name(&cd
, argv
[2]);
710 log_info("Volume %s already inactive.", argv
[2]);
715 log_error_errno(r
, "crypt_init_by_name() failed: %m");
719 crypt_set_log_callback(cd
, cryptsetup_log_glue
, NULL
);
721 r
= crypt_deactivate(cd
, argv
[2]);
723 log_error_errno(r
, "Failed to deactivate: %m");
728 log_error("Unknown verb %s.", argv
[1]);
738 strv_free(arg_tcrypt_keyfiles
);
740 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;