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 int disk_major_minor(const char *path
, char **ret
) {
257 if (stat(path
, &st
) < 0)
260 if (!S_ISBLK(st
.st_mode
))
263 if (asprintf(ret
, "/dev/block/%d:%d", major(st
.st_rdev
), minor(st
.st_rdev
)) < 0)
269 static char* disk_description(const char *path
) {
271 static const char name_fields
[] =
272 "ID_PART_ENTRY_NAME\0"
274 "ID_MODEL_FROM_DATABASE\0"
277 _cleanup_(sd_device_unrefp
) sd_device
*device
= NULL
;
284 if (stat(path
, &st
) < 0)
287 if (!S_ISBLK(st
.st_mode
))
290 r
= sd_device_new_from_devnum(&device
, 'b', st
.st_rdev
);
294 NULSTR_FOREACH(i
, name_fields
) {
297 r
= sd_device_get_property_value(device
, i
, &name
);
298 if (r
>= 0 && !isempty(name
))
305 static char *disk_mount_point(const char *label
) {
306 _cleanup_free_
char *device
= NULL
;
307 _cleanup_endmntent_
FILE *f
= NULL
;
310 /* Yeah, we don't support native systemd unit files here for now */
312 if (asprintf(&device
, "/dev/mapper/%s", label
) < 0)
315 f
= setmntent("/etc/fstab", "re");
319 while ((m
= getmntent(f
)))
320 if (path_equal(m
->mnt_fsname
, device
))
321 return strdup(m
->mnt_dir
);
326 static int get_password(const char *vol
, const char *src
, usec_t until
, bool accept_cached
, char ***ret
) {
327 _cleanup_free_
char *description
= NULL
, *name_buffer
= NULL
, *mount_point
= NULL
, *maj_min
= NULL
, *text
= NULL
, *escaped_name
= NULL
;
328 _cleanup_strv_free_erase_
char **passwords
= NULL
;
329 const char *name
= NULL
;
337 description
= disk_description(src
);
338 mount_point
= disk_mount_point(vol
);
340 if (description
&& streq(vol
, description
))
341 /* If the description string is simply the
342 * volume name, then let's not show this
344 description
= mfree(description
);
346 if (mount_point
&& description
)
347 r
= asprintf(&name_buffer
, "%s (%s) on %s", description
, vol
, mount_point
);
348 else if (mount_point
)
349 r
= asprintf(&name_buffer
, "%s on %s", vol
, mount_point
);
350 else if (description
)
351 r
= asprintf(&name_buffer
, "%s (%s)", description
, vol
);
356 name
= name_buffer
? name_buffer
: vol
;
358 if (asprintf(&text
, "Please enter passphrase for disk %s!", name
) < 0)
362 (void) disk_major_minor(src
, &maj_min
);
365 escaped_name
= maj_min
;
368 escaped_name
= cescape(src
);
373 id
= strjoina("cryptsetup:", escaped_name
);
375 r
= ask_password_auto(text
, "drive-harddisk", id
, "cryptsetup", until
,
376 ASK_PASSWORD_PUSH_CACHE
| (accept_cached
*ASK_PASSWORD_ACCEPT_CACHED
),
379 return log_error_errno(r
, "Failed to query password: %m");
382 _cleanup_strv_free_erase_
char **passwords2
= NULL
;
384 assert(strv_length(passwords
) == 1);
386 if (asprintf(&text
, "Please enter passphrase for disk %s! (verification)", name
) < 0)
389 id
= strjoina("cryptsetup-verification:", escaped_name
);
391 r
= ask_password_auto(text
, "drive-harddisk", id
, "cryptsetup", until
, ASK_PASSWORD_PUSH_CACHE
, &passwords2
);
393 return log_error_errno(r
, "Failed to query verification password: %m");
395 assert(strv_length(passwords2
) == 1);
397 if (!streq(passwords
[0], passwords2
[0])) {
398 log_warning("Passwords did not match, retrying.");
403 strv_uniq(passwords
);
405 STRV_FOREACH(p
, passwords
) {
408 if (strlen(*p
)+1 >= arg_key_size
)
411 /* Pad password if necessary */
412 c
= new(char, arg_key_size
);
416 strncpy(c
, *p
, arg_key_size
);
427 static int attach_tcrypt(
428 struct crypt_device
*cd
,
430 const char *key_file
,
435 _cleanup_free_
char *passphrase
= NULL
;
436 struct crypt_params_tcrypt params
= {
437 .flags
= CRYPT_TCRYPT_LEGACY_MODES
,
438 .keyfiles
= (const char **)arg_tcrypt_keyfiles
,
439 .keyfiles_count
= strv_length(arg_tcrypt_keyfiles
)
444 assert(key_file
|| (passwords
&& passwords
[0]));
446 if (arg_tcrypt_hidden
)
447 params
.flags
|= CRYPT_TCRYPT_HIDDEN_HEADER
;
449 if (arg_tcrypt_system
)
450 params
.flags
|= CRYPT_TCRYPT_SYSTEM_HEADER
;
452 #ifdef CRYPT_TCRYPT_VERA_MODES
453 if (arg_tcrypt_veracrypt
)
454 params
.flags
|= CRYPT_TCRYPT_VERA_MODES
;
458 r
= read_one_line_file(key_file
, &passphrase
);
460 log_error_errno(r
, "Failed to read password file '%s': %m", key_file
);
464 params
.passphrase
= passphrase
;
466 params
.passphrase
= passwords
[0];
467 params
.passphrase_size
= strlen(params
.passphrase
);
469 r
= crypt_load(cd
, CRYPT_TCRYPT
, ¶ms
);
471 if (key_file
&& r
== -EPERM
) {
472 log_error("Failed to activate using password file '%s'.", key_file
);
478 return crypt_activate_by_volume_key(cd
, name
, NULL
, 0, flags
);
481 static int attach_luks_or_plain(struct crypt_device
*cd
,
483 const char *key_file
,
484 const char *data_device
,
488 bool pass_volume_key
= false;
492 assert(key_file
|| passwords
);
494 if (!arg_type
|| STR_IN_SET(arg_type
, ANY_LUKS
, CRYPT_LUKS1
)) {
495 r
= crypt_load(cd
, CRYPT_LUKS
, NULL
);
497 log_error("crypt_load() failed on device %s.\n", crypt_get_device_name(cd
));
502 r
= crypt_set_data_device(cd
, data_device
);
505 if ((!arg_type
&& r
< 0) || streq_ptr(arg_type
, CRYPT_PLAIN
)) {
506 struct crypt_params_plain params
= {
507 .offset
= arg_offset
,
510 const char *cipher
, *cipher_mode
;
511 _cleanup_free_
char *truncated_cipher
= NULL
;
514 /* plain isn't a real hash type. it just means "use no hash" */
515 if (!streq(arg_hash
, "plain"))
516 params
.hash
= arg_hash
;
517 } else if (!key_file
)
518 /* for CRYPT_PLAIN, the behaviour of cryptsetup
519 * package is to not hash when a key file is provided */
520 params
.hash
= "ripemd160";
525 l
= strcspn(arg_cipher
, "-");
526 truncated_cipher
= strndup(arg_cipher
, l
);
527 if (!truncated_cipher
)
530 cipher
= truncated_cipher
;
531 cipher_mode
= arg_cipher
[l
] ? arg_cipher
+l
+1 : "plain";
534 cipher_mode
= "cbc-essiv:sha256";
537 /* for CRYPT_PLAIN limit reads
538 * from keyfile to key length, and
539 * ignore keyfile-size */
540 arg_keyfile_size
= arg_key_size
;
542 /* In contrast to what the name
543 * crypt_setup() might suggest this
544 * doesn't actually format anything,
545 * it just configures encryption
546 * parameters when used for plain
548 r
= crypt_format(cd
, CRYPT_PLAIN
, cipher
, cipher_mode
, NULL
, NULL
, arg_keyfile_size
, ¶ms
);
550 /* hash == NULL implies the user passed "plain" */
551 pass_volume_key
= (params
.hash
== NULL
);
555 return log_error_errno(r
, "Loading of cryptographic parameters failed: %m");
557 log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
558 crypt_get_cipher(cd
),
559 crypt_get_cipher_mode(cd
),
560 crypt_get_volume_key_size(cd
)*8,
561 crypt_get_device_name(cd
));
564 r
= crypt_activate_by_keyfile_offset(cd
, name
, arg_key_slot
, key_file
, arg_keyfile_size
, arg_keyfile_offset
, flags
);
566 log_error_errno(r
, "Failed to activate with key file '%s': %m", key_file
);
572 STRV_FOREACH(p
, passwords
) {
574 r
= crypt_activate_by_volume_key(cd
, name
, *p
, arg_key_size
, flags
);
576 r
= crypt_activate_by_passphrase(cd
, name
, arg_key_slot
, *p
, strlen(*p
), flags
);
586 static int help(void) {
588 printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
589 "%s detach VOLUME\n\n"
590 "Attaches or detaches an encrypted block device.\n",
591 program_invocation_short_name
,
592 program_invocation_short_name
);
597 int main(int argc
, char *argv
[]) {
598 _cleanup_(crypt_freep
) struct crypt_device
*cd
= NULL
;
607 log_error("This program requires at least two arguments.");
611 log_set_target(LOG_TARGET_AUTO
);
612 log_parse_environment();
617 if (streq(argv
[1], "attach")) {
621 crypt_status_info status
;
622 const char *key_file
= NULL
;
624 /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
627 log_error("attach requires at least two arguments.");
633 !streq(argv
[4], "-") &&
634 !streq(argv
[4], "none")) {
636 if (!path_is_absolute(argv
[4]))
637 log_error("Password file path '%s' is not absolute. Ignoring.", argv
[4]);
642 if (argc
>= 6 && argv
[5][0] && !streq(argv
[5], "-")) {
643 if (parse_options(argv
[5]) < 0)
647 /* A delicious drop of snake oil */
648 mlockall(MCL_FUTURE
);
651 log_debug("LUKS header: %s", arg_header
);
652 r
= crypt_init(&cd
, arg_header
);
654 r
= crypt_init(&cd
, argv
[3]);
656 log_error_errno(r
, "crypt_init() failed: %m");
660 crypt_set_log_callback(cd
, cryptsetup_log_glue
, NULL
);
662 status
= crypt_status(cd
, argv
[2]);
663 if (IN_SET(status
, CRYPT_ACTIVE
, CRYPT_BUSY
)) {
664 log_info("Volume %s already active.", argv
[2]);
670 flags
|= CRYPT_ACTIVATE_READONLY
;
673 flags
|= CRYPT_ACTIVATE_ALLOW_DISCARDS
;
675 if (arg_timeout
== USEC_INFINITY
)
678 until
= now(CLOCK_MONOTONIC
) + arg_timeout
;
680 arg_key_size
= (arg_key_size
> 0 ? arg_key_size
: (256 / 8));
685 /* Ideally we'd do this on the open fd, but since this is just a
686 * warning it's OK to do this in two steps. */
687 if (stat(key_file
, &st
) >= 0 && S_ISREG(st
.st_mode
) && (st
.st_mode
& 0005))
688 log_warning("Key file %s is world-readable. This is not a good idea!", key_file
);
691 for (tries
= 0; arg_tries
== 0 || tries
< arg_tries
; tries
++) {
692 _cleanup_strv_free_erase_
char **passwords
= NULL
;
695 r
= get_password(argv
[2], argv
[3], until
, tries
== 0 && !arg_verify
, &passwords
);
702 if (streq_ptr(arg_type
, CRYPT_TCRYPT
))
703 r
= attach_tcrypt(cd
, argv
[2], key_file
, passwords
, flags
);
705 r
= attach_luks_or_plain(cd
,
708 arg_header
? argv
[3] : NULL
,
718 log_error_errno(r
, "Failed to activate: %m");
722 log_warning("Invalid passphrase.");
725 if (arg_tries
!= 0 && tries
>= arg_tries
) {
726 log_error("Too many attempts; giving up.");
731 } else if (streq(argv
[1], "detach")) {
733 r
= crypt_init_by_name(&cd
, argv
[2]);
735 log_info("Volume %s already inactive.", argv
[2]);
740 log_error_errno(r
, "crypt_init_by_name() failed: %m");
744 crypt_set_log_callback(cd
, cryptsetup_log_glue
, NULL
);
746 r
= crypt_deactivate(cd
, argv
[2]);
748 log_error_errno(r
, "Failed to deactivate: %m");
753 log_error("Unknown verb %s.", argv
[1]);
763 strv_free(arg_tcrypt_keyfiles
);
765 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;