2020-11-09 05:23:58 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2010-11-08 05:02:45 +01:00
|
|
|
|
2010-11-12 00:39:17 +01:00
|
|
|
#include <errno.h>
|
2015-10-24 22:58:24 +02:00
|
|
|
#include <mntent.h>
|
|
|
|
#include <sys/mman.h>
|
2019-03-27 11:32:41 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
2010-11-08 05:02:45 +01:00
|
|
|
|
2015-10-23 18:52:53 +02:00
|
|
|
#include "sd-device.h"
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2015-10-23 18:52:53 +02:00
|
|
|
#include "ask-password-api.h"
|
2020-08-28 21:26:33 +02:00
|
|
|
#include "cryptsetup-keyfile.h"
|
2019-08-22 10:21:11 +02:00
|
|
|
#include "cryptsetup-pkcs11.h"
|
2020-04-29 16:37:14 +02:00
|
|
|
#include "cryptsetup-util.h"
|
2015-10-23 18:52:53 +02:00
|
|
|
#include "device-util.h"
|
|
|
|
#include "escape.h"
|
2013-07-13 13:19:38 +02:00
|
|
|
#include "fileio.h"
|
2020-04-29 14:01:44 +02:00
|
|
|
#include "fs-util.h"
|
2019-11-13 17:36:46 +01:00
|
|
|
#include "fstab-util.h"
|
2019-08-22 10:21:11 +02:00
|
|
|
#include "hexdecoct.h"
|
2010-11-08 05:02:45 +01:00
|
|
|
#include "log.h"
|
2018-11-20 09:18:08 +01:00
|
|
|
#include "main-func.h"
|
2020-04-29 16:37:14 +02:00
|
|
|
#include "memory-util.h"
|
2015-10-26 18:44:13 +01:00
|
|
|
#include "mount-util.h"
|
2019-03-14 13:14:33 +01:00
|
|
|
#include "nulstr-util.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2012-05-07 21:36:12 +02:00
|
|
|
#include "path-util.h"
|
2019-08-22 10:21:11 +02:00
|
|
|
#include "pkcs11-util.h"
|
2019-03-14 13:14:33 +01:00
|
|
|
#include "pretty-print.h"
|
2020-11-04 17:24:53 +01:00
|
|
|
#include "random-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2011-02-23 01:12:07 +01:00
|
|
|
#include "strv.h"
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2017-10-12 12:57:25 +02:00
|
|
|
/* internal helper */
|
|
|
|
#define ANY_LUKS "LUKS"
|
2018-08-29 16:38:09 +02:00
|
|
|
/* as in src/cryptsetup.h */
|
|
|
|
#define CRYPT_SECTOR_SIZE 512
|
|
|
|
#define CRYPT_MAX_SECTOR_SIZE 4096
|
2017-10-12 12:57:25 +02:00
|
|
|
|
2020-05-30 12:21:44 +02:00
|
|
|
static const char *arg_type = NULL; /* ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2, CRYPT_TCRYPT, CRYPT_BITLK or CRYPT_PLAIN */
|
2014-03-13 00:46:58 +01:00
|
|
|
static char *arg_cipher = NULL;
|
|
|
|
static unsigned arg_key_size = 0;
|
2018-08-29 16:38:09 +02:00
|
|
|
static unsigned arg_sector_size = CRYPT_SECTOR_SIZE;
|
2014-03-13 00:46:58 +01:00
|
|
|
static int arg_key_slot = CRYPT_ANY_SLOT;
|
|
|
|
static unsigned arg_keyfile_size = 0;
|
2017-12-19 08:51:12 +01:00
|
|
|
static uint64_t arg_keyfile_offset = 0;
|
2020-04-29 14:01:44 +02:00
|
|
|
static bool arg_keyfile_erase = false;
|
2020-04-29 19:41:02 +02:00
|
|
|
static bool arg_try_empty_password = false;
|
2014-03-13 00:46:58 +01:00
|
|
|
static char *arg_hash = NULL;
|
2015-01-08 22:21:06 +01:00
|
|
|
static char *arg_header = NULL;
|
2014-03-13 00:46:58 +01:00
|
|
|
static unsigned arg_tries = 3;
|
|
|
|
static bool arg_readonly = false;
|
|
|
|
static bool arg_verify = false;
|
|
|
|
static bool arg_discards = false;
|
2019-03-11 06:04:06 +01:00
|
|
|
static bool arg_same_cpu_crypt = false;
|
|
|
|
static bool arg_submit_from_crypt_cpus = false;
|
2014-03-13 00:46:58 +01:00
|
|
|
static bool arg_tcrypt_hidden = false;
|
|
|
|
static bool arg_tcrypt_system = false;
|
2016-10-30 15:25:31 +01:00
|
|
|
static bool arg_tcrypt_veracrypt = false;
|
2014-03-13 00:46:58 +01:00
|
|
|
static char **arg_tcrypt_keyfiles = NULL;
|
2015-04-16 13:44:07 +02:00
|
|
|
static uint64_t arg_offset = 0;
|
|
|
|
static uint64_t arg_skip = 0;
|
2017-07-31 08:19:16 +02:00
|
|
|
static usec_t arg_timeout = USEC_INFINITY;
|
2019-08-22 10:21:11 +02:00
|
|
|
static char *arg_pkcs11_uri = NULL;
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2018-11-20 09:18:08 +01:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep);
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_header, freep);
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_tcrypt_keyfiles, strv_freep);
|
2019-08-22 10:21:11 +02:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_uri, freep);
|
2018-11-20 09:18:08 +01:00
|
|
|
|
2010-11-14 02:08:31 +01:00
|
|
|
/* Options Debian's crypttab knows we don't:
|
|
|
|
|
|
|
|
check=
|
|
|
|
checkargs=
|
2020-04-29 10:22:39 +02:00
|
|
|
noearly
|
|
|
|
loud
|
|
|
|
quiet
|
2010-11-14 02:08:31 +01:00
|
|
|
keyscript=
|
2020-04-29 10:22:39 +02:00
|
|
|
initramfs
|
2010-11-14 02:08:31 +01:00
|
|
|
*/
|
|
|
|
|
2010-11-12 00:39:17 +01:00
|
|
|
static int parse_one_option(const char *option) {
|
2016-10-22 22:11:41 +02:00
|
|
|
const char *val;
|
|
|
|
int r;
|
|
|
|
|
2010-11-12 00:39:17 +01:00
|
|
|
assert(option);
|
|
|
|
|
|
|
|
/* Handled outside of this tool */
|
2019-07-16 13:06:16 +02:00
|
|
|
if (STR_IN_SET(option, "noauto", "auto", "nofail", "fail", "_netdev", "keyfile-timeout"))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (startswith(option, "keyfile-timeout="))
|
2010-11-12 00:39:17 +01:00
|
|
|
return 0;
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
if ((val = startswith(option, "cipher="))) {
|
|
|
|
r = free_and_strdup(&arg_cipher, val);
|
|
|
|
if (r < 0)
|
2013-10-02 19:36:28 +02:00
|
|
|
return log_oom();
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(option, "size="))) {
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
r = safe_atou(val, &arg_key_size);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
|
2010-11-12 00:39:17 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-03-25 11:05:28 +01:00
|
|
|
if (arg_key_size % 8) {
|
|
|
|
log_error("size= not a multiple of 8, ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg_key_size /= 8;
|
|
|
|
|
2018-08-29 16:38:09 +02:00
|
|
|
} else if ((val = startswith(option, "sector-size="))) {
|
|
|
|
|
|
|
|
r = safe_atou(val, &arg_sector_size);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg_sector_size % 2) {
|
|
|
|
log_error("sector-size= not a multiple of 2, ignoring.");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arg_sector_size < CRYPT_SECTOR_SIZE || arg_sector_size > CRYPT_MAX_SECTOR_SIZE) {
|
|
|
|
log_error("sector-size= is outside of %u and %u, ignoring.", CRYPT_SECTOR_SIZE, CRYPT_MAX_SECTOR_SIZE);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-29 10:22:39 +02:00
|
|
|
} else if ((val = startswith(option, "key-slot=")) ||
|
|
|
|
(val = startswith(option, "keyslot="))) {
|
2014-01-26 12:02:49 +01:00
|
|
|
|
2017-10-12 12:57:25 +02:00
|
|
|
arg_type = ANY_LUKS;
|
2016-10-22 22:11:41 +02:00
|
|
|
r = safe_atoi(val, &arg_key_slot);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
|
2014-01-26 12:02:49 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(option, "tcrypt-keyfile="))) {
|
2013-07-13 13:19:38 +02:00
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
arg_type = CRYPT_TCRYPT;
|
2016-10-22 22:11:41 +02:00
|
|
|
if (path_is_absolute(val)) {
|
|
|
|
if (strv_extend(&arg_tcrypt_keyfiles, val) < 0)
|
2013-10-02 19:36:28 +02:00
|
|
|
return log_oom();
|
|
|
|
} else
|
2016-10-22 22:11:41 +02:00
|
|
|
log_error("Key file path \"%s\" is not absolute. Ignoring.", val);
|
2013-07-13 13:19:38 +02:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(option, "keyfile-size="))) {
|
2012-08-03 12:47:24 +02:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
r = safe_atou(val, &arg_keyfile_size);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
|
2012-08-03 12:47:24 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(option, "keyfile-offset="))) {
|
2012-06-29 14:36:37 +02:00
|
|
|
|
2019-09-26 15:54:29 +02:00
|
|
|
r = safe_atou64(val, &arg_keyfile_offset);
|
2016-10-22 22:11:41 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
|
2012-06-29 14:36:37 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-04-29 14:01:44 +02:00
|
|
|
} else if ((val = startswith(option, "keyfile-erase="))) {
|
|
|
|
|
|
|
|
r = parse_boolean(val);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg_keyfile_erase = r;
|
|
|
|
|
|
|
|
} else if (streq(option, "keyfile-erase"))
|
|
|
|
arg_keyfile_erase = true;
|
|
|
|
|
|
|
|
else if ((val = startswith(option, "hash="))) {
|
2016-10-22 22:11:41 +02:00
|
|
|
r = free_and_strdup(&arg_hash, val);
|
|
|
|
if (r < 0)
|
2013-10-02 19:36:28 +02:00
|
|
|
return log_oom();
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(option, "header="))) {
|
2017-10-12 12:57:25 +02:00
|
|
|
arg_type = ANY_LUKS;
|
2015-01-08 22:21:06 +01:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (!path_is_absolute(val))
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Header path \"%s\" is not absolute, refusing.", val);
|
2015-01-08 22:21:06 +01:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_header)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"Duplicate header= option, refusing.");
|
2015-01-08 22:21:06 +01:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
arg_header = strdup(val);
|
2015-01-08 22:21:06 +01:00
|
|
|
if (!arg_header)
|
|
|
|
return log_oom();
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(option, "tries="))) {
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
r = safe_atou(val, &arg_tries);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
|
2010-11-12 00:39:17 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
} else if (STR_IN_SET(option, "readonly", "read-only"))
|
|
|
|
arg_readonly = true;
|
2010-11-12 00:39:17 +01:00
|
|
|
else if (streq(option, "verify"))
|
2014-03-13 00:46:58 +01:00
|
|
|
arg_verify = true;
|
|
|
|
else if (STR_IN_SET(option, "allow-discards", "discard"))
|
|
|
|
arg_discards = true;
|
2019-03-11 06:04:06 +01:00
|
|
|
else if (streq(option, "same-cpu-crypt"))
|
|
|
|
arg_same_cpu_crypt = true;
|
|
|
|
else if (streq(option, "submit-from-crypt-cpus"))
|
|
|
|
arg_submit_from_crypt_cpus = true;
|
2010-11-14 01:53:46 +01:00
|
|
|
else if (streq(option, "luks"))
|
2017-10-12 12:57:25 +02:00
|
|
|
arg_type = ANY_LUKS;
|
2020-05-30 12:21:44 +02:00
|
|
|
/* since cryptsetup 2.3.0 (Feb 2020) */
|
|
|
|
#ifdef CRYPT_BITLK
|
|
|
|
else if (streq(option, "bitlk"))
|
|
|
|
arg_type = CRYPT_BITLK;
|
|
|
|
#endif
|
2013-07-13 13:19:38 +02:00
|
|
|
else if (streq(option, "tcrypt"))
|
2014-03-13 00:46:58 +01:00
|
|
|
arg_type = CRYPT_TCRYPT;
|
2020-04-29 10:22:39 +02:00
|
|
|
else if (STR_IN_SET(option, "tcrypt-hidden", "tcrypthidden")) {
|
2014-03-13 00:46:58 +01:00
|
|
|
arg_type = CRYPT_TCRYPT;
|
|
|
|
arg_tcrypt_hidden = true;
|
2013-07-13 13:19:38 +02:00
|
|
|
} else if (streq(option, "tcrypt-system")) {
|
2014-03-13 00:46:58 +01:00
|
|
|
arg_type = CRYPT_TCRYPT;
|
|
|
|
arg_tcrypt_system = true;
|
2020-04-29 10:22:39 +02:00
|
|
|
} else if (STR_IN_SET(option, "tcrypt-veracrypt", "veracrypt")) {
|
2016-10-30 15:25:31 +01:00
|
|
|
arg_type = CRYPT_TCRYPT;
|
|
|
|
arg_tcrypt_veracrypt = true;
|
2020-05-19 17:48:50 +02:00
|
|
|
} else if (STR_IN_SET(option, "plain", "swap", "tmp") ||
|
|
|
|
startswith(option, "tmp="))
|
2014-03-13 00:46:58 +01:00
|
|
|
arg_type = CRYPT_PLAIN;
|
2016-10-22 22:11:41 +02:00
|
|
|
else if ((val = startswith(option, "timeout="))) {
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2017-07-03 14:29:32 +02:00
|
|
|
r = parse_sec_fix_0(val, &arg_timeout);
|
2016-10-22 22:11:41 +02:00
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
|
2010-11-12 00:39:17 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(option, "offset="))) {
|
2015-04-16 13:44:07 +02:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
r = safe_atou64(val, &arg_offset);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to parse %s: %m", option);
|
2015-04-16 13:44:07 +02:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
} else if ((val = startswith(option, "skip="))) {
|
2015-04-16 13:44:07 +02:00
|
|
|
|
2016-10-22 22:11:41 +02:00
|
|
|
r = safe_atou64(val, &arg_skip);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to parse %s: %m", option);
|
2015-04-16 13:44:07 +02:00
|
|
|
|
2019-08-22 10:21:11 +02:00
|
|
|
} else if ((val = startswith(option, "pkcs11-uri="))) {
|
|
|
|
|
|
|
|
if (!pkcs11_uri_valid(val))
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "pkcs11-uri= parameter expects a PKCS#11 URI, refusing");
|
|
|
|
|
|
|
|
r = free_and_strdup(&arg_pkcs11_uri, val);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
2020-04-29 19:41:02 +02:00
|
|
|
} else if ((val = startswith(option, "try-empty-password="))) {
|
|
|
|
|
|
|
|
r = parse_boolean(val);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to parse %s, ignoring: %m", option);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg_try_empty_password = r;
|
|
|
|
|
|
|
|
} else if (streq(option, "try-empty-password"))
|
|
|
|
arg_try_empty_password = true;
|
|
|
|
|
|
|
|
else if (!streq(option, "x-initrd.attach"))
|
2016-10-22 22:11:41 +02:00
|
|
|
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
|
2010-11-12 00:39:17 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int parse_options(const char *options) {
|
|
|
|
assert(options);
|
|
|
|
|
2020-07-31 11:23:44 +02:00
|
|
|
for (;;) {
|
|
|
|
_cleanup_free_ char *word = NULL;
|
|
|
|
int r;
|
|
|
|
|
2020-09-24 14:55:57 +02:00
|
|
|
r = extract_first_word(&options, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
|
2020-07-31 11:23:44 +02:00
|
|
|
if (r < 0)
|
2020-09-24 10:54:10 +02:00
|
|
|
return log_error_errno(r, "Failed to parse options: %m");
|
2020-07-31 11:23:44 +02:00
|
|
|
if (r == 0)
|
|
|
|
break;
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2020-07-31 11:23:44 +02:00
|
|
|
r = parse_one_option(word);
|
2010-11-12 00:39:17 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2015-04-16 13:44:07 +02:00
|
|
|
/* sanity-check options */
|
2019-08-21 10:40:04 +02:00
|
|
|
if (arg_type && !streq(arg_type, CRYPT_PLAIN)) {
|
|
|
|
if (arg_offset != 0)
|
2015-04-16 13:44:07 +02:00
|
|
|
log_warning("offset= ignored with type %s", arg_type);
|
2019-08-21 10:40:04 +02:00
|
|
|
if (arg_skip != 0)
|
2015-04-16 13:44:07 +02:00
|
|
|
log_warning("skip= ignored with type %s", arg_type);
|
|
|
|
}
|
|
|
|
|
2010-11-12 00:39:17 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-13 02:28:21 +02:00
|
|
|
static char* disk_description(const char *path) {
|
2014-03-13 00:46:58 +01:00
|
|
|
static const char name_fields[] =
|
2013-03-26 15:23:54 +01:00
|
|
|
"ID_PART_ENTRY_NAME\0"
|
|
|
|
"DM_NAME\0"
|
|
|
|
"ID_MODEL_FROM_DATABASE\0"
|
2014-03-13 00:46:58 +01:00
|
|
|
"ID_MODEL\0";
|
2013-03-26 15:23:54 +01:00
|
|
|
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
2018-09-01 16:12:47 +02:00
|
|
|
const char *i, *name;
|
2010-11-18 23:34:42 +01:00
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
assert(path);
|
|
|
|
|
|
|
|
if (stat(path, &st) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (!S_ISBLK(st.st_mode))
|
|
|
|
return NULL;
|
|
|
|
|
2018-09-01 16:12:47 +02:00
|
|
|
if (sd_device_new_from_devnum(&device, 'b', st.st_rdev) < 0)
|
2013-10-13 02:28:21 +02:00
|
|
|
return NULL;
|
2010-11-18 23:34:42 +01:00
|
|
|
|
2018-09-01 16:12:47 +02:00
|
|
|
NULSTR_FOREACH(i, name_fields)
|
|
|
|
if (sd_device_get_property_value(device, i, &name) >= 0 &&
|
|
|
|
!isempty(name))
|
2013-10-13 02:28:21 +02:00
|
|
|
return strdup(name);
|
2010-11-18 23:34:42 +01:00
|
|
|
|
2013-10-13 02:28:21 +02:00
|
|
|
return NULL;
|
2010-11-18 23:34:42 +01:00
|
|
|
}
|
|
|
|
|
2011-02-23 18:46:27 +01:00
|
|
|
static char *disk_mount_point(const char *label) {
|
2013-07-13 13:19:36 +02:00
|
|
|
_cleanup_free_ char *device = NULL;
|
2013-10-04 04:13:55 +02:00
|
|
|
_cleanup_endmntent_ FILE *f = NULL;
|
2011-02-23 18:46:27 +01:00
|
|
|
struct mntent *m;
|
|
|
|
|
|
|
|
/* Yeah, we don't support native systemd unit files here for now */
|
|
|
|
|
2020-11-04 18:14:54 +01:00
|
|
|
device = strjoin("/dev/mapper/", label);
|
|
|
|
if (!device)
|
2013-10-04 04:13:55 +02:00
|
|
|
return NULL;
|
2011-02-23 18:46:27 +01:00
|
|
|
|
2019-11-13 17:36:46 +01:00
|
|
|
f = setmntent(fstab_path(), "re");
|
2012-04-22 15:33:43 +02:00
|
|
|
if (!f)
|
2013-10-04 04:13:55 +02:00
|
|
|
return NULL;
|
2011-02-23 18:46:27 +01:00
|
|
|
|
|
|
|
while ((m = getmntent(f)))
|
2013-10-04 04:13:55 +02:00
|
|
|
if (path_equal(m->mnt_fsname, device))
|
|
|
|
return strdup(m->mnt_dir);
|
2011-02-23 18:46:27 +01:00
|
|
|
|
2013-10-04 04:13:55 +02:00
|
|
|
return NULL;
|
2011-02-23 18:46:27 +01:00
|
|
|
}
|
|
|
|
|
2019-08-22 10:21:11 +02:00
|
|
|
static char *friendly_disk_name(const char *src, const char *vol) {
|
|
|
|
_cleanup_free_ char *description = NULL, *mount_point = NULL;
|
|
|
|
char *name_buffer = NULL;
|
|
|
|
int r;
|
2013-07-13 13:19:36 +02:00
|
|
|
|
2015-06-01 17:26:27 +02:00
|
|
|
assert(src);
|
2019-08-22 10:21:11 +02:00
|
|
|
assert(vol);
|
2013-07-13 13:19:36 +02:00
|
|
|
|
2015-06-01 17:26:27 +02:00
|
|
|
description = disk_description(src);
|
|
|
|
mount_point = disk_mount_point(vol);
|
|
|
|
|
2019-08-22 10:21:11 +02:00
|
|
|
/* If the description string is simply the volume name, then let's not show this twice */
|
2015-09-08 23:03:38 +02:00
|
|
|
if (description && streq(vol, description))
|
2015-07-31 19:56:38 +02:00
|
|
|
description = mfree(description);
|
2015-06-01 17:26:27 +02:00
|
|
|
|
|
|
|
if (mount_point && description)
|
|
|
|
r = asprintf(&name_buffer, "%s (%s) on %s", description, vol, mount_point);
|
|
|
|
else if (mount_point)
|
|
|
|
r = asprintf(&name_buffer, "%s on %s", vol, mount_point);
|
|
|
|
else if (description)
|
|
|
|
r = asprintf(&name_buffer, "%s (%s)", description, vol);
|
2019-08-22 10:21:11 +02:00
|
|
|
else
|
|
|
|
return strdup(vol);
|
2015-06-01 17:26:27 +02:00
|
|
|
if (r < 0)
|
2019-08-22 10:21:11 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return name_buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int get_password(
|
|
|
|
const char *vol,
|
|
|
|
const char *src,
|
|
|
|
usec_t until,
|
|
|
|
bool accept_cached,
|
|
|
|
char ***ret) {
|
|
|
|
|
|
|
|
_cleanup_free_ char *friendly = NULL, *text = NULL, *disk_path = NULL;
|
|
|
|
_cleanup_strv_free_erase_ char **passwords = NULL;
|
|
|
|
char **p, *id;
|
|
|
|
int r = 0;
|
|
|
|
|
|
|
|
assert(vol);
|
|
|
|
assert(src);
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
friendly = friendly_disk_name(src, vol);
|
|
|
|
if (!friendly)
|
2015-06-01 17:26:27 +02:00
|
|
|
return log_oom();
|
|
|
|
|
2019-08-22 10:21:11 +02:00
|
|
|
if (asprintf(&text, "Please enter passphrase for disk %s:", friendly) < 0)
|
|
|
|
return log_oom();
|
2015-06-01 17:26:27 +02:00
|
|
|
|
2019-08-22 10:21:11 +02:00
|
|
|
disk_path = cescape(src);
|
|
|
|
if (!disk_path)
|
2013-07-13 13:19:36 +02:00
|
|
|
return log_oom();
|
|
|
|
|
2017-12-12 20:00:31 +01:00
|
|
|
id = strjoina("cryptsetup:", disk_path);
|
2014-03-25 11:05:23 +01:00
|
|
|
|
2015-10-15 16:02:35 +02:00
|
|
|
r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until,
|
|
|
|
ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED),
|
|
|
|
&passwords);
|
2014-11-28 18:23:20 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to query password: %m");
|
2013-07-13 13:19:36 +02:00
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
if (arg_verify) {
|
2015-10-15 16:02:35 +02:00
|
|
|
_cleanup_strv_free_erase_ char **passwords2 = NULL;
|
|
|
|
|
2015-10-14 22:40:23 +02:00
|
|
|
assert(strv_length(passwords) == 1);
|
2013-07-13 13:19:36 +02:00
|
|
|
|
2019-08-22 10:21:11 +02:00
|
|
|
if (asprintf(&text, "Please enter passphrase for disk %s (verification):", friendly) < 0)
|
2015-10-15 16:02:35 +02:00
|
|
|
return log_oom();
|
2013-07-13 13:19:36 +02:00
|
|
|
|
2017-12-12 20:00:31 +01:00
|
|
|
id = strjoina("cryptsetup-verification:", disk_path);
|
2014-03-25 11:05:23 +01:00
|
|
|
|
2015-10-07 11:26:10 +02:00
|
|
|
r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE, &passwords2);
|
2015-10-15 16:02:35 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to query verification password: %m");
|
2013-07-13 13:19:36 +02:00
|
|
|
|
|
|
|
assert(strv_length(passwords2) == 1);
|
|
|
|
|
2020-11-24 13:56:48 +01:00
|
|
|
if (!streq(passwords[0], passwords2[0]))
|
|
|
|
return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN),
|
|
|
|
"Passwords did not match, retrying.");
|
2013-07-13 13:19:36 +02:00
|
|
|
}
|
|
|
|
|
2015-10-14 22:40:23 +02:00
|
|
|
strv_uniq(passwords);
|
2013-07-13 13:19:36 +02:00
|
|
|
|
2015-10-14 22:40:23 +02:00
|
|
|
STRV_FOREACH(p, passwords) {
|
2013-07-13 13:19:36 +02:00
|
|
|
char *c;
|
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
if (strlen(*p)+1 >= arg_key_size)
|
2013-07-13 13:19:36 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Pad password if necessary */
|
2015-10-14 22:40:23 +02:00
|
|
|
c = new(char, arg_key_size);
|
2015-10-15 16:02:35 +02:00
|
|
|
if (!c)
|
|
|
|
return log_oom();
|
2013-07-13 13:19:36 +02:00
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
strncpy(c, *p, arg_key_size);
|
2019-01-21 20:01:38 +01:00
|
|
|
free_and_replace(*p, c);
|
2013-07-13 13:19:36 +02:00
|
|
|
}
|
|
|
|
|
2018-03-22 16:53:26 +01:00
|
|
|
*ret = TAKE_PTR(passwords);
|
2015-10-14 22:40:23 +02:00
|
|
|
|
2015-10-15 16:02:35 +02:00
|
|
|
return 0;
|
2013-07-13 13:19:36 +02:00
|
|
|
}
|
|
|
|
|
2015-10-14 22:40:23 +02:00
|
|
|
static int attach_tcrypt(
|
|
|
|
struct crypt_device *cd,
|
|
|
|
const char *name,
|
|
|
|
const char *key_file,
|
2020-04-29 16:37:14 +02:00
|
|
|
const void *key_data,
|
|
|
|
size_t key_data_size,
|
2015-10-14 22:40:23 +02:00
|
|
|
char **passwords,
|
|
|
|
uint32_t flags) {
|
|
|
|
|
2013-07-13 13:19:38 +02:00
|
|
|
int r = 0;
|
|
|
|
_cleanup_free_ char *passphrase = NULL;
|
|
|
|
struct crypt_params_tcrypt params = {
|
|
|
|
.flags = CRYPT_TCRYPT_LEGACY_MODES,
|
2014-03-13 00:46:58 +01:00
|
|
|
.keyfiles = (const char **)arg_tcrypt_keyfiles,
|
|
|
|
.keyfiles_count = strv_length(arg_tcrypt_keyfiles)
|
2013-07-13 13:19:38 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
assert(cd);
|
|
|
|
assert(name);
|
2020-04-29 16:37:14 +02:00
|
|
|
assert(key_file || key_data || !strv_isempty(passwords));
|
2013-07-13 13:19:38 +02:00
|
|
|
|
2020-01-01 19:17:15 +01:00
|
|
|
if (arg_pkcs11_uri)
|
|
|
|
/* Ask for a regular password */
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EAGAIN),
|
|
|
|
"Sorry, but tcrypt devices are currently not supported in conjunction with pkcs11 support.");
|
2019-08-22 10:21:11 +02:00
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
if (arg_tcrypt_hidden)
|
2013-07-13 13:19:38 +02:00
|
|
|
params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER;
|
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
if (arg_tcrypt_system)
|
2013-07-13 13:19:38 +02:00
|
|
|
params.flags |= CRYPT_TCRYPT_SYSTEM_HEADER;
|
|
|
|
|
2016-10-30 15:25:31 +01:00
|
|
|
if (arg_tcrypt_veracrypt)
|
|
|
|
params.flags |= CRYPT_TCRYPT_VERA_MODES;
|
|
|
|
|
2020-04-29 16:37:14 +02:00
|
|
|
if (key_data) {
|
|
|
|
params.passphrase = key_data;
|
|
|
|
params.passphrase_size = key_data_size;
|
|
|
|
} else {
|
|
|
|
if (key_file) {
|
|
|
|
r = read_one_line_file(key_file, &passphrase);
|
|
|
|
if (r < 0) {
|
|
|
|
log_error_errno(r, "Failed to read password file '%s': %m", key_file);
|
|
|
|
return -EAGAIN; /* log with the actual error, but return EAGAIN */
|
|
|
|
}
|
2013-07-13 13:19:38 +02:00
|
|
|
|
2020-04-29 16:37:14 +02:00
|
|
|
params.passphrase = passphrase;
|
|
|
|
} else
|
|
|
|
params.passphrase = passwords[0];
|
|
|
|
|
|
|
|
params.passphrase_size = strlen(params.passphrase);
|
|
|
|
}
|
2013-07-13 13:19:38 +02:00
|
|
|
|
|
|
|
r = crypt_load(cd, CRYPT_TCRYPT, ¶ms);
|
|
|
|
if (r < 0) {
|
2020-04-29 16:37:14 +02:00
|
|
|
if (r == -EPERM) {
|
2020-04-29 18:17:33 +02:00
|
|
|
if (key_data)
|
2020-04-29 16:37:14 +02:00
|
|
|
log_error_errno(r, "Failed to activate using discovered key. (Key not correct?)");
|
|
|
|
|
2020-04-29 18:17:33 +02:00
|
|
|
if (key_file)
|
2020-04-29 16:37:14 +02:00
|
|
|
log_error_errno(r, "Failed to activate using password file '%s'. (Key data not correct?)", key_file);
|
2020-04-29 18:17:33 +02:00
|
|
|
|
|
|
|
return -EAGAIN; /* log the actual error, but return EAGAIN */
|
2019-01-21 20:19:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return log_error_errno(r, "Failed to load tcrypt superblock on device %s: %m", crypt_get_device_name(cd));
|
2013-07-13 13:19:38 +02:00
|
|
|
}
|
|
|
|
|
2019-01-21 20:19:11 +01:00
|
|
|
r = crypt_activate_by_volume_key(cd, name, NULL, 0, flags);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to activate tcrypt device %s: %m", crypt_get_device_name(cd));
|
|
|
|
|
|
|
|
return 0;
|
2013-07-13 13:19:38 +02:00
|
|
|
}
|
|
|
|
|
2020-11-04 17:24:53 +01:00
|
|
|
static char *make_bindname(const char *volume) {
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
if (asprintf(&s, "@%" PRIx64"/cryptsetup/%s", random_u64(), volume) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2020-11-25 11:51:39 +01:00
|
|
|
static int make_security_device_monitor(sd_event *event, sd_device_monitor **ret) {
|
|
|
|
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
r = sd_device_monitor_new(&monitor);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to allocate device monitor: %m");
|
|
|
|
|
|
|
|
r = sd_device_monitor_filter_add_match_tag(monitor, "security-device");
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to configure device monitor: %m");
|
|
|
|
|
|
|
|
r = sd_device_monitor_attach_event(monitor, event);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to attach device monitor: %m");
|
|
|
|
|
|
|
|
r = sd_device_monitor_start(monitor, NULL, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to start device monitor: %m");
|
|
|
|
|
|
|
|
*ret = TAKE_PTR(monitor);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-30 12:21:44 +02:00
|
|
|
static int attach_luks_or_plain_or_bitlk(
|
2019-08-21 10:40:04 +02:00
|
|
|
struct crypt_device *cd,
|
|
|
|
const char *name,
|
|
|
|
const char *key_file,
|
2020-04-29 16:37:14 +02:00
|
|
|
const void *key_data,
|
|
|
|
size_t key_data_size,
|
2019-08-21 10:40:04 +02:00
|
|
|
char **passwords,
|
2019-08-22 10:21:11 +02:00
|
|
|
uint32_t flags,
|
|
|
|
usec_t until) {
|
2019-08-21 10:40:04 +02:00
|
|
|
|
2013-07-13 13:19:37 +02:00
|
|
|
int r = 0;
|
|
|
|
bool pass_volume_key = false;
|
|
|
|
|
|
|
|
assert(cd);
|
|
|
|
assert(name);
|
|
|
|
|
2019-05-27 09:27:54 +02:00
|
|
|
if ((!arg_type && !crypt_get_type(cd)) || streq_ptr(arg_type, CRYPT_PLAIN)) {
|
2015-04-16 13:44:07 +02:00
|
|
|
struct crypt_params_plain params = {
|
|
|
|
.offset = arg_offset,
|
|
|
|
.skip = arg_skip,
|
2018-08-29 16:38:09 +02:00
|
|
|
.sector_size = arg_sector_size,
|
2015-04-16 13:44:07 +02:00
|
|
|
};
|
2013-07-13 13:19:37 +02:00
|
|
|
const char *cipher, *cipher_mode;
|
|
|
|
_cleanup_free_ char *truncated_cipher = NULL;
|
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
if (arg_hash) {
|
2013-07-13 13:19:37 +02:00
|
|
|
/* plain isn't a real hash type. it just means "use no hash" */
|
2014-03-13 00:46:58 +01:00
|
|
|
if (!streq(arg_hash, "plain"))
|
|
|
|
params.hash = arg_hash;
|
2014-11-24 15:11:12 +01:00
|
|
|
} else if (!key_file)
|
|
|
|
/* for CRYPT_PLAIN, the behaviour of cryptsetup
|
|
|
|
* package is to not hash when a key file is provided */
|
2013-07-13 13:19:37 +02:00
|
|
|
params.hash = "ripemd160";
|
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
if (arg_cipher) {
|
2013-07-13 13:19:37 +02:00
|
|
|
size_t l;
|
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
l = strcspn(arg_cipher, "-");
|
|
|
|
truncated_cipher = strndup(arg_cipher, l);
|
2013-07-13 13:19:37 +02:00
|
|
|
if (!truncated_cipher)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
cipher = truncated_cipher;
|
2014-03-13 00:46:58 +01:00
|
|
|
cipher_mode = arg_cipher[l] ? arg_cipher+l+1 : "plain";
|
2013-07-13 13:19:37 +02:00
|
|
|
} else {
|
|
|
|
cipher = "aes";
|
|
|
|
cipher_mode = "cbc-essiv:sha256";
|
|
|
|
}
|
|
|
|
|
2019-01-21 20:14:42 +01:00
|
|
|
/* for CRYPT_PLAIN limit reads from keyfile to key length, and ignore keyfile-size */
|
2014-03-25 11:05:28 +01:00
|
|
|
arg_keyfile_size = arg_key_size;
|
2013-07-13 13:19:37 +02:00
|
|
|
|
2019-06-27 09:38:30 +02:00
|
|
|
/* In contrast to what the name crypt_format() might suggest this doesn't actually format
|
2019-01-21 20:14:42 +01:00
|
|
|
* anything, it just configures encryption parameters when used for plain mode. */
|
2015-10-14 22:40:23 +02:00
|
|
|
r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, arg_keyfile_size, ¶ms);
|
2019-05-27 09:27:54 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Loading of cryptographic parameters failed: %m");
|
2013-07-13 13:19:37 +02:00
|
|
|
|
|
|
|
/* hash == NULL implies the user passed "plain" */
|
|
|
|
pass_volume_key = (params.hash == NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
log_info("Set cipher %s, mode %s, key size %i bits for device %s.",
|
|
|
|
crypt_get_cipher(cd),
|
|
|
|
crypt_get_cipher_mode(cd),
|
|
|
|
crypt_get_volume_key_size(cd)*8,
|
|
|
|
crypt_get_device_name(cd));
|
|
|
|
|
2019-08-22 10:21:11 +02:00
|
|
|
if (arg_pkcs11_uri) {
|
|
|
|
_cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL;
|
|
|
|
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
|
|
|
|
_cleanup_free_ void *decrypted_key = NULL;
|
|
|
|
_cleanup_free_ char *friendly = NULL;
|
|
|
|
size_t decrypted_key_size = 0;
|
|
|
|
|
2020-04-29 16:37:14 +02:00
|
|
|
if (!key_file && !key_data)
|
2019-08-22 10:21:11 +02:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing.");
|
|
|
|
|
|
|
|
friendly = friendly_disk_name(crypt_get_device_name(cd), name);
|
|
|
|
if (!friendly)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
bool processed = false;
|
|
|
|
|
|
|
|
r = decrypt_pkcs11_key(
|
2020-11-04 17:22:39 +01:00
|
|
|
name,
|
2019-08-22 10:21:11 +02:00
|
|
|
friendly,
|
|
|
|
arg_pkcs11_uri,
|
2020-04-29 16:37:14 +02:00
|
|
|
key_file, arg_keyfile_size, arg_keyfile_offset,
|
|
|
|
key_data, key_data_size,
|
2019-08-22 10:21:11 +02:00
|
|
|
until,
|
|
|
|
&decrypted_key, &decrypted_key_size);
|
|
|
|
if (r >= 0)
|
|
|
|
break;
|
|
|
|
if (r != -EAGAIN) /* EAGAIN means: token not found */
|
|
|
|
return r;
|
|
|
|
|
|
|
|
if (!monitor) {
|
|
|
|
/* We didn't find the token. In this case, watch for it via udev. Let's
|
|
|
|
* create an event loop and monitor first. */
|
|
|
|
|
|
|
|
assert(!event);
|
|
|
|
|
|
|
|
r = sd_event_default(&event);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to allocate event loop: %m");
|
|
|
|
|
2020-11-25 11:51:39 +01:00
|
|
|
r = make_security_device_monitor(event, &monitor);
|
2019-08-22 10:21:11 +02:00
|
|
|
if (r < 0)
|
2020-11-25 11:51:39 +01:00
|
|
|
return r;
|
2019-08-22 10:21:11 +02:00
|
|
|
|
|
|
|
log_notice("Security token %s not present for unlocking volume %s, please plug it in.",
|
2020-04-29 21:27:53 +02:00
|
|
|
arg_pkcs11_uri, friendly);
|
2019-08-22 10:21:11 +02:00
|
|
|
|
|
|
|
/* Let's immediately rescan in case the token appeared in the time we needed
|
|
|
|
* to create and configure the monitor */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
/* Wait for one event, and then eat all subsequent events until there are no
|
|
|
|
* further ones */
|
|
|
|
r = sd_event_run(event, processed ? 0 : UINT64_MAX);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to run event loop: %m");
|
|
|
|
if (r == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
processed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_debug("Got one or more potentially relevant udev events, rescanning PKCS#11...");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pass_volume_key)
|
|
|
|
r = crypt_activate_by_volume_key(cd, name, decrypted_key, decrypted_key_size, flags);
|
|
|
|
else {
|
|
|
|
_cleanup_free_ char *base64_encoded = NULL;
|
|
|
|
|
|
|
|
/* Before using this key as passphrase we base64 encode it. Why? For compatibility
|
|
|
|
* with homed's PKCS#11 hookup: there we want to use the key we acquired through
|
|
|
|
* PKCS#11 for other authentication/decryption mechanisms too, and some of them do
|
|
|
|
* not not take arbitrary binary blobs, but require NUL-terminated strings — most
|
|
|
|
* importantly UNIX password hashes. Hence, for compatibility we want to use a string
|
|
|
|
* without embedded NUL here too, and that's easiest to generate from a binary blob
|
|
|
|
* via base64 encoding. */
|
|
|
|
|
|
|
|
r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
r = crypt_activate_by_passphrase(cd, name, arg_key_slot, base64_encoded, strlen(base64_encoded), flags);
|
|
|
|
}
|
|
|
|
if (r == -EPERM) {
|
|
|
|
log_error_errno(r, "Failed to activate with PKCS#11 decrypted key. (Key incorrect?)");
|
|
|
|
return -EAGAIN; /* log actual error, but return EAGAIN */
|
|
|
|
}
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to activate with PKCS#11 acquired key: %m");
|
|
|
|
|
2020-04-29 16:37:14 +02:00
|
|
|
} else if (key_data) {
|
|
|
|
if (pass_volume_key)
|
|
|
|
r = crypt_activate_by_volume_key(cd, name, key_data, key_data_size, flags);
|
|
|
|
else
|
|
|
|
r = crypt_activate_by_passphrase(cd, name, arg_key_slot, key_data, key_data_size, flags);
|
|
|
|
if (r == -EPERM) {
|
|
|
|
log_error_errno(r, "Failed to activate. (Key incorrect?)");
|
|
|
|
return -EAGAIN; /* Log actual error, but return EAGAIN */
|
|
|
|
}
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to activate: %m");
|
|
|
|
|
2019-08-22 10:21:11 +02:00
|
|
|
} else if (key_file) {
|
2020-11-04 17:24:53 +01:00
|
|
|
_cleanup_(erase_and_freep) char *kfdata = NULL;
|
|
|
|
_cleanup_free_ char *bindname = NULL;
|
|
|
|
size_t kfsize;
|
|
|
|
|
|
|
|
/* If we read the key via AF_UNIX, make this client recognizable */
|
|
|
|
bindname = make_bindname(name);
|
|
|
|
if (!bindname)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
r = read_full_file_full(
|
|
|
|
AT_FDCWD, key_file,
|
|
|
|
arg_keyfile_offset == 0 ? UINT64_MAX : arg_keyfile_offset,
|
|
|
|
arg_keyfile_size == 0 ? SIZE_MAX : arg_keyfile_size,
|
|
|
|
READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
|
|
|
|
bindname,
|
|
|
|
&kfdata, &kfsize);
|
|
|
|
if (r == -ENOENT) {
|
|
|
|
log_error_errno(r, "Failed to activate, key file '%s' missing.", key_file);
|
2019-01-21 20:19:11 +01:00
|
|
|
return -EAGAIN; /* Log actual error, but return EAGAIN */
|
2019-02-23 06:45:03 +01:00
|
|
|
}
|
2020-11-04 17:24:53 +01:00
|
|
|
|
|
|
|
r = crypt_activate_by_passphrase(cd, name, arg_key_slot, kfdata, kfsize, flags);
|
|
|
|
if (r == -EPERM) {
|
|
|
|
log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
|
2019-02-23 06:45:03 +01:00
|
|
|
return -EAGAIN; /* Log actual error, but return EAGAIN */
|
2013-07-13 13:19:37 +02:00
|
|
|
}
|
2019-01-21 20:19:11 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
|
2019-08-21 10:40:04 +02:00
|
|
|
|
2013-07-13 13:19:37 +02:00
|
|
|
} else {
|
|
|
|
char **p;
|
|
|
|
|
2019-01-21 20:19:11 +01:00
|
|
|
r = -EINVAL;
|
2013-07-13 13:19:37 +02:00
|
|
|
STRV_FOREACH(p, passwords) {
|
|
|
|
if (pass_volume_key)
|
2014-03-13 00:46:58 +01:00
|
|
|
r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags);
|
2013-07-13 13:19:37 +02:00
|
|
|
else
|
2014-03-13 00:46:58 +01:00
|
|
|
r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags);
|
2013-07-13 13:19:37 +02:00
|
|
|
if (r >= 0)
|
|
|
|
break;
|
|
|
|
}
|
2019-01-21 20:19:11 +01:00
|
|
|
if (r == -EPERM) {
|
|
|
|
log_error_errno(r, "Failed to activate with specified passphrase. (Passphrase incorrect?)");
|
|
|
|
return -EAGAIN; /* log actual error, but return EAGAIN */
|
|
|
|
}
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to activate with specified passphrase: %m");
|
2013-07-13 13:19:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2011-02-25 02:56:27 +01:00
|
|
|
static int help(void) {
|
2018-08-09 10:32:31 +02:00
|
|
|
_cleanup_free_ char *link = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = terminal_urlify_man("systemd-cryptsetup@.service", "8", &link);
|
|
|
|
if (r < 0)
|
|
|
|
return log_oom();
|
2011-02-25 02:56:27 +01:00
|
|
|
|
|
|
|
printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
|
|
|
|
"%s detach VOLUME\n\n"
|
2018-08-09 10:32:31 +02:00
|
|
|
"Attaches or detaches an encrypted block device.\n"
|
|
|
|
"\nSee the %s for details.\n"
|
|
|
|
, program_invocation_short_name
|
|
|
|
, program_invocation_short_name
|
|
|
|
, link
|
|
|
|
);
|
2011-02-25 02:56:27 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-03-19 21:42:21 +01:00
|
|
|
static uint32_t determine_flags(void) {
|
|
|
|
uint32_t flags = 0;
|
|
|
|
|
|
|
|
if (arg_readonly)
|
|
|
|
flags |= CRYPT_ACTIVATE_READONLY;
|
|
|
|
|
|
|
|
if (arg_discards)
|
|
|
|
flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
|
|
|
|
|
|
|
|
if (arg_same_cpu_crypt)
|
|
|
|
flags |= CRYPT_ACTIVATE_SAME_CPU_CRYPT;
|
|
|
|
|
|
|
|
if (arg_submit_from_crypt_cpus)
|
|
|
|
flags |= CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS;
|
|
|
|
|
2019-11-27 14:27:58 +01:00
|
|
|
#ifdef CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF
|
|
|
|
/* Try to decrease the risk of OOM event if memory hard key derivation function is in use */
|
|
|
|
/* https://gitlab.com/cryptsetup/cryptsetup/issues/446/ */
|
|
|
|
flags |= CRYPT_ACTIVATE_SERIALIZE_MEMORY_HARD_PBKDF;
|
|
|
|
#endif
|
|
|
|
|
2019-03-19 21:42:21 +01:00
|
|
|
return flags;
|
|
|
|
}
|
|
|
|
|
2020-04-29 14:01:44 +02:00
|
|
|
static void remove_and_erasep(const char **p) {
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!*p)
|
|
|
|
return;
|
|
|
|
|
|
|
|
r = unlinkat_deallocate(AT_FDCWD, *p, UNLINK_ERASE);
|
|
|
|
if (r < 0 && r != -ENOENT)
|
|
|
|
log_warning_errno(r, "Unable to erase key file '%s', ignoring: %m", *p);
|
|
|
|
}
|
|
|
|
|
2018-11-20 09:18:08 +01:00
|
|
|
static int run(int argc, char *argv[]) {
|
2017-11-02 09:16:47 +01:00
|
|
|
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
|
2020-11-25 11:42:09 +01:00
|
|
|
const char *verb;
|
2018-11-20 09:18:08 +01:00
|
|
|
int r;
|
2010-11-08 05:02:45 +01:00
|
|
|
|
2018-11-20 09:18:08 +01:00
|
|
|
if (argc <= 1)
|
|
|
|
return help();
|
2011-02-25 02:56:27 +01:00
|
|
|
|
2020-10-09 14:59:44 +02:00
|
|
|
if (argc < 3)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
"This program requires at least two arguments.");
|
2010-11-08 05:02:45 +01:00
|
|
|
|
2018-11-20 11:18:22 +01:00
|
|
|
log_setup_service();
|
2010-11-08 05:02:45 +01:00
|
|
|
|
2020-08-10 12:45:07 +02:00
|
|
|
cryptsetup_enable_logging(cd);
|
2019-07-06 12:51:23 +02:00
|
|
|
|
2011-08-01 20:52:18 +02:00
|
|
|
umask(0022);
|
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
verb = argv[1];
|
|
|
|
|
|
|
|
if (streq(verb, "attach")) {
|
2020-04-29 14:01:44 +02:00
|
|
|
_cleanup_(remove_and_erasep) const char *destroy_key_file = NULL;
|
2020-04-29 16:37:14 +02:00
|
|
|
_cleanup_(erase_and_freep) void *key_data = NULL;
|
2020-11-25 11:42:09 +01:00
|
|
|
const char *volume, *source, *key_file, *options;
|
|
|
|
crypt_status_info status;
|
2020-04-29 16:37:14 +02:00
|
|
|
size_t key_data_size = 0;
|
2020-11-25 11:42:09 +01:00
|
|
|
uint32_t flags = 0;
|
|
|
|
unsigned tries;
|
|
|
|
usec_t until;
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2011-02-23 18:46:27 +01:00
|
|
|
/* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
|
|
|
|
|
2019-01-21 20:02:33 +01:00
|
|
|
if (argc < 4)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least two arguments.");
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
volume = argv[2];
|
|
|
|
source = argv[3];
|
|
|
|
key_file = argc >= 5 && !STR_IN_SET(argv[4], "", "-", "none") ? argv[4] : NULL;
|
|
|
|
options = argc >= 6 && !STR_IN_SET(argv[5], "", "-", "none") ? argv[5] : NULL;
|
2020-04-29 16:37:14 +02:00
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
if (!filename_is_valid(volume))
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
|
|
|
|
|
|
|
if (key_file && !path_is_absolute(key_file)) {
|
|
|
|
log_warning("Password file path '%s' is not absolute. Ignoring.", key_file);
|
|
|
|
key_file = NULL;
|
2010-11-12 00:39:17 +01:00
|
|
|
}
|
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
if (options) {
|
|
|
|
r = parse_options(options);
|
2018-11-20 09:18:08 +01:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
2013-03-26 15:23:54 +01:00
|
|
|
}
|
2010-11-08 05:02:45 +01:00
|
|
|
|
2020-09-24 14:55:57 +02:00
|
|
|
log_debug("%s %s ← %s type=%s cipher=%s", __func__,
|
2020-11-25 11:42:09 +01:00
|
|
|
volume, source, strempty(arg_type), strempty(arg_cipher));
|
2020-09-24 14:55:57 +02:00
|
|
|
|
2010-11-16 03:23:52 +01:00
|
|
|
/* A delicious drop of snake oil */
|
2019-08-21 10:40:04 +02:00
|
|
|
(void) mlockall(MCL_FUTURE);
|
2010-11-16 03:23:52 +01:00
|
|
|
|
2020-04-29 16:37:14 +02:00
|
|
|
if (!key_file) {
|
2020-11-04 18:15:42 +01:00
|
|
|
_cleanup_free_ char *bindname = NULL;
|
2020-04-29 16:37:14 +02:00
|
|
|
const char *fn;
|
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
bindname = make_bindname(volume);
|
2020-11-04 18:15:42 +01:00
|
|
|
if (!bindname)
|
|
|
|
return log_oom();
|
|
|
|
|
2020-04-29 16:37:14 +02:00
|
|
|
/* If a key file is not explicitly specified, search for a key in a well defined
|
|
|
|
* search path, and load it. */
|
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
fn = strjoina(volume, ".key");
|
2020-11-04 18:15:42 +01:00
|
|
|
r = find_key_file(
|
|
|
|
fn,
|
|
|
|
STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"),
|
|
|
|
bindname,
|
|
|
|
&key_data, &key_data_size);
|
2020-04-29 16:37:14 +02:00
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
if (r > 0)
|
2020-11-25 11:42:09 +01:00
|
|
|
log_debug("Automatically discovered key for volume '%s'.", volume);
|
2020-04-29 16:37:14 +02:00
|
|
|
} else if (arg_keyfile_erase)
|
2020-04-29 14:01:44 +02:00
|
|
|
destroy_key_file = key_file; /* let's get this baby erased when we leave */
|
|
|
|
|
2015-01-08 22:21:06 +01:00
|
|
|
if (arg_header) {
|
|
|
|
log_debug("LUKS header: %s", arg_header);
|
2016-12-16 13:15:31 +01:00
|
|
|
r = crypt_init(&cd, arg_header);
|
2015-01-08 22:21:06 +01:00
|
|
|
} else
|
2020-11-25 11:42:09 +01:00
|
|
|
r = crypt_init(&cd, source);
|
2018-11-20 09:18:08 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "crypt_init() failed: %m");
|
2010-11-08 05:02:45 +01:00
|
|
|
|
2020-08-10 12:45:07 +02:00
|
|
|
cryptsetup_enable_logging(cd);
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
status = crypt_status(cd, volume);
|
2017-09-29 00:37:23 +02:00
|
|
|
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
|
2020-11-25 11:42:09 +01:00
|
|
|
log_info("Volume %s already active.", volume);
|
2018-11-20 09:18:08 +01:00
|
|
|
return 0;
|
2010-11-12 00:39:17 +01:00
|
|
|
}
|
|
|
|
|
2019-03-19 21:42:21 +01:00
|
|
|
flags = determine_flags();
|
2019-03-11 06:04:06 +01:00
|
|
|
|
2017-07-31 08:19:16 +02:00
|
|
|
if (arg_timeout == USEC_INFINITY)
|
2011-04-13 21:42:46 +02:00
|
|
|
until = 0;
|
2017-07-31 08:19:16 +02:00
|
|
|
else
|
|
|
|
until = now(CLOCK_MONOTONIC) + arg_timeout;
|
2010-11-14 01:53:46 +01:00
|
|
|
|
2014-03-25 11:05:28 +01:00
|
|
|
arg_key_size = (arg_key_size > 0 ? arg_key_size : (256 / 8));
|
2010-11-14 02:01:29 +01:00
|
|
|
|
2013-07-13 13:19:37 +02:00
|
|
|
if (key_file) {
|
|
|
|
struct stat st;
|
2010-11-14 02:01:29 +01:00
|
|
|
|
2013-07-13 13:19:37 +02:00
|
|
|
/* Ideally we'd do this on the open fd, but since this is just a
|
|
|
|
* warning it's OK to do this in two steps. */
|
2015-02-02 16:53:39 +01:00
|
|
|
if (stat(key_file, &st) >= 0 && S_ISREG(st.st_mode) && (st.st_mode & 0005))
|
|
|
|
log_warning("Key file %s is world-readable. This is not a good idea!", key_file);
|
2010-11-14 02:01:29 +01:00
|
|
|
}
|
|
|
|
|
2020-06-09 14:21:32 +02:00
|
|
|
if (!arg_type || STR_IN_SET(arg_type, ANY_LUKS, CRYPT_LUKS1, CRYPT_LUKS2)) {
|
|
|
|
r = crypt_load(cd, !arg_type || streq(arg_type, ANY_LUKS) ? CRYPT_LUKS : arg_type, NULL);
|
2019-05-27 09:43:03 +02:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd));
|
|
|
|
|
|
|
|
if (arg_header) {
|
2020-11-25 11:42:09 +01:00
|
|
|
r = crypt_set_data_device(cd, source);
|
2019-05-27 09:43:03 +02:00
|
|
|
if (r < 0)
|
2020-11-25 11:42:09 +01:00
|
|
|
return log_error_errno(r, "Failed to set LUKS data device %s: %m", source);
|
2019-05-27 09:43:03 +02:00
|
|
|
}
|
2019-09-26 15:54:29 +02:00
|
|
|
|
2019-05-27 09:44:14 +02:00
|
|
|
/* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
|
2020-04-29 16:37:14 +02:00
|
|
|
if (!key_file && !key_data) {
|
2020-11-25 11:42:09 +01:00
|
|
|
r = crypt_activate_by_token(cd, volume, CRYPT_ANY_TOKEN, NULL, flags);
|
2019-05-27 09:44:14 +02:00
|
|
|
if (r >= 0) {
|
2020-11-25 11:42:09 +01:00
|
|
|
log_debug("Volume %s activated with LUKS token id %i.", volume, r);
|
2019-05-27 09:44:14 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_debug_errno(r, "Token activation unsuccessful for device %s: %m", crypt_get_device_name(cd));
|
|
|
|
}
|
2019-05-27 09:43:03 +02:00
|
|
|
}
|
|
|
|
|
2020-05-30 12:21:44 +02:00
|
|
|
/* since cryptsetup 2.3.0 (Feb 2020) */
|
|
|
|
#ifdef CRYPT_BITLK
|
2020-06-09 14:18:09 +02:00
|
|
|
if (streq_ptr(arg_type, CRYPT_BITLK)) {
|
2020-05-30 12:21:44 +02:00
|
|
|
r = crypt_load(cd, CRYPT_BITLK, NULL);
|
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to load Bitlocker superblock on device %s: %m", crypt_get_device_name(cd));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
|
2015-10-15 16:02:35 +02:00
|
|
|
_cleanup_strv_free_erase_ char **passwords = NULL;
|
2010-11-14 01:53:46 +01:00
|
|
|
|
2020-04-29 19:41:02 +02:00
|
|
|
/* When we were able to acquire multiple keys, let's always process them in this order:
|
|
|
|
*
|
|
|
|
* 1. A key acquired via PKCS#11 token
|
|
|
|
* 2. The discovered key: i.e. key_data + key_data_size
|
|
|
|
* 3. The configured key: i.e. key_file + arg_keyfile_offset + arg_keyfile_size
|
|
|
|
* 4. The empty password, in case arg_try_empty_password is set
|
|
|
|
* 5. We enquire the user for a password
|
|
|
|
*/
|
|
|
|
|
2020-04-29 16:37:14 +02:00
|
|
|
if (!key_file && !key_data && !arg_pkcs11_uri) {
|
2020-04-29 19:41:02 +02:00
|
|
|
|
|
|
|
if (arg_try_empty_password) {
|
|
|
|
/* Hmm, let's try an empty password now, but only once */
|
|
|
|
arg_try_empty_password = false;
|
|
|
|
|
|
|
|
key_data = strdup("");
|
|
|
|
if (!key_data)
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
key_data_size = 0;
|
|
|
|
} else {
|
|
|
|
/* Ask the user for a passphrase only as last resort, if we have
|
|
|
|
* nothing else to check for */
|
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
r = get_password(volume, source, until, tries == 0 && !arg_verify, &passwords);
|
2020-04-29 19:41:02 +02:00
|
|
|
if (r == -EAGAIN)
|
|
|
|
continue;
|
|
|
|
if (r < 0)
|
|
|
|
return r;
|
|
|
|
}
|
2010-11-14 01:53:46 +01:00
|
|
|
}
|
|
|
|
|
2014-03-13 00:46:58 +01:00
|
|
|
if (streq_ptr(arg_type, CRYPT_TCRYPT))
|
2020-11-25 11:42:09 +01:00
|
|
|
r = attach_tcrypt(cd, volume, key_file, key_data, key_data_size, passwords, flags);
|
2013-07-13 13:19:38 +02:00
|
|
|
else
|
2020-11-25 11:42:09 +01:00
|
|
|
r = attach_luks_or_plain_or_bitlk(cd, volume, key_file, key_data, key_data_size, passwords, flags, until);
|
2016-12-16 13:15:31 +01:00
|
|
|
if (r >= 0)
|
2010-11-14 01:53:46 +01:00
|
|
|
break;
|
2019-01-21 20:19:11 +01:00
|
|
|
if (r != -EAGAIN)
|
|
|
|
return r;
|
2010-11-14 01:53:46 +01:00
|
|
|
|
2020-04-29 19:08:03 +02:00
|
|
|
/* Key not correct? Let's try again! */
|
|
|
|
|
2019-01-21 20:19:11 +01:00
|
|
|
key_file = NULL;
|
2020-04-29 16:37:14 +02:00
|
|
|
key_data = erase_and_free(key_data);
|
|
|
|
key_data_size = 0;
|
2020-04-29 19:08:03 +02:00
|
|
|
arg_pkcs11_uri = mfree(arg_pkcs11_uri);
|
2010-11-12 00:39:17 +01:00
|
|
|
}
|
|
|
|
|
2019-01-21 20:02:33 +01:00
|
|
|
if (arg_tries != 0 && tries >= arg_tries)
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Too many attempts to activate; giving up.");
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
} else if (streq(verb, "detach")) {
|
|
|
|
const char *volume;
|
|
|
|
|
|
|
|
volume = argv[2];
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
if (!filename_is_valid(volume))
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
2020-04-29 16:37:14 +02:00
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
r = crypt_init_by_name(&cd, volume);
|
2016-12-16 13:15:31 +01:00
|
|
|
if (r == -ENODEV) {
|
2020-11-25 11:42:09 +01:00
|
|
|
log_info("Volume %s already inactive.", volume);
|
2018-11-20 09:18:08 +01:00
|
|
|
return 0;
|
2010-11-12 00:39:17 +01:00
|
|
|
}
|
2018-11-20 09:18:08 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "crypt_init_by_name() failed: %m");
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2020-08-10 12:45:07 +02:00
|
|
|
cryptsetup_enable_logging(cd);
|
2010-11-12 00:39:17 +01:00
|
|
|
|
2020-11-25 11:42:09 +01:00
|
|
|
r = crypt_deactivate(cd, volume);
|
2018-11-20 09:18:08 +01:00
|
|
|
if (r < 0)
|
|
|
|
return log_error_errno(r, "Failed to deactivate: %m");
|
2010-11-08 05:02:45 +01:00
|
|
|
|
2019-01-21 20:02:33 +01:00
|
|
|
} else
|
2020-11-25 11:42:09 +01:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", verb);
|
2010-11-08 05:02:45 +01:00
|
|
|
|
2018-11-20 09:18:08 +01:00
|
|
|
return 0;
|
2010-11-08 05:02:45 +01:00
|
|
|
}
|
2018-11-20 09:18:08 +01:00
|
|
|
|
|
|
|
DEFINE_MAIN_FUNCTION(run);
|