mirror of
https://github.com/systemd/systemd.git
synced 2025-03-22 06:50:18 +03:00
cryptsetup and friends: use dispatch_verb() (#36072)
This commit is contained in:
commit
52e2033ebc
@ -6,6 +6,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "cryptsetup-util.h"
|
||||
#include "dropin.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
@ -232,7 +233,7 @@ static int print_dependencies(FILE *f, const char* device_path, const char* time
|
||||
assert(f);
|
||||
assert(device_path);
|
||||
|
||||
if (STR_IN_SET(device_path, "-", "none"))
|
||||
if (!mangle_none(device_path))
|
||||
/* None, nothing to do */
|
||||
return 0;
|
||||
|
||||
@ -795,7 +796,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_crypttab_device(const char *name, const char *device, const char *keyspec, const char *options) {
|
||||
static int add_crypttab_device(const char *name, const char *device, const char *keyspec, const char *options) {
|
||||
_cleanup_free_ char *keyfile = NULL, *keydev = NULL, *headerdev = NULL, *filtered_header = NULL;
|
||||
crypto_device *d = NULL;
|
||||
char *uuid;
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "strv.h"
|
||||
#include "tpm2-pcr.h"
|
||||
#include "tpm2-util.h"
|
||||
#include "verbs.h"
|
||||
|
||||
/* internal helper */
|
||||
#define ANY_LUKS "LUKS"
|
||||
@ -2388,9 +2389,277 @@ static int discover_key(const char *key_file, const char *volume, TokenType toke
|
||||
return r;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
static int verb_attach(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
|
||||
const char *verb;
|
||||
_unused_ _cleanup_(remove_and_erasep) const char *destroy_key_file = NULL;
|
||||
crypt_status_info status;
|
||||
uint32_t flags = 0;
|
||||
unsigned tries;
|
||||
usec_t until;
|
||||
PassphraseType passphrase_type = PASSPHRASE_NONE;
|
||||
int r;
|
||||
|
||||
/* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [KEY-FILE] [CONFIG] */
|
||||
|
||||
assert(argc >= 3 && argc <= 5);
|
||||
|
||||
const char *volume = ASSERT_PTR(argv[1]),
|
||||
*source = ASSERT_PTR(argv[2]),
|
||||
*key_file = argc >= 4 ? mangle_none(argv[3]) : NULL,
|
||||
*config = argc >= 5 ? mangle_none(argv[4]) : NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (config) {
|
||||
r = parse_crypt_config(config);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
log_debug("%s %s ← %s type=%s cipher=%s", __func__,
|
||||
volume, source, strempty(arg_type), strempty(arg_cipher));
|
||||
|
||||
/* A delicious drop of snake oil */
|
||||
(void) mlockall(MCL_FUTURE);
|
||||
|
||||
if (key_file && arg_keyfile_erase)
|
||||
destroy_key_file = key_file; /* let's get this baby erased when we leave */
|
||||
|
||||
if (arg_header) {
|
||||
if (streq_ptr(arg_type, CRYPT_TCRYPT)){
|
||||
log_debug("tcrypt header: %s", arg_header);
|
||||
r = crypt_init_data_device(&cd, arg_header, source);
|
||||
} else {
|
||||
log_debug("LUKS header: %s", arg_header);
|
||||
r = crypt_init(&cd, arg_header);
|
||||
}
|
||||
} else
|
||||
r = crypt_init(&cd, source);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "crypt_init() failed: %m");
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
status = crypt_status(cd, volume);
|
||||
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
|
||||
log_info("Volume %s already active.", volume);
|
||||
return 0;
|
||||
}
|
||||
|
||||
flags = determine_flags();
|
||||
|
||||
until = usec_add(now(CLOCK_MONOTONIC), arg_timeout);
|
||||
if (until == USEC_INFINITY)
|
||||
until = 0;
|
||||
|
||||
if (arg_key_size == 0)
|
||||
arg_key_size = 256U / 8U;
|
||||
|
||||
if (key_file) {
|
||||
struct stat st;
|
||||
|
||||
/* 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. */
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd));
|
||||
|
||||
/* since cryptsetup 2.7.0 (Jan 2024) */
|
||||
#if HAVE_CRYPT_SET_KEYRING_TO_LINK
|
||||
if (arg_link_key_description) {
|
||||
r = crypt_set_keyring_to_link(cd, arg_link_key_description, NULL, arg_link_key_type, arg_link_keyring);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to set keyring or key description to link volume key in, ignoring: %m");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (arg_header) {
|
||||
r = crypt_set_data_device(cd, source);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set LUKS data device %s: %m", source);
|
||||
}
|
||||
|
||||
/* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
|
||||
if (!key_file && use_token_plugins()) {
|
||||
r = crypt_activate_by_token_pin_ask_password(
|
||||
cd,
|
||||
volume,
|
||||
/* type= */ NULL,
|
||||
until,
|
||||
/* userdata= */ NULL,
|
||||
flags,
|
||||
"Please enter LUKS2 token PIN:",
|
||||
"luks2-pin",
|
||||
"cryptsetup.luks2-pin");
|
||||
if (r >= 0) {
|
||||
log_debug("Volume %s activated with a LUKS token.", volume);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug_errno(r, "Token activation unsuccessful for device %s: %m", crypt_get_device_name(cd));
|
||||
}
|
||||
}
|
||||
|
||||
/* since cryptsetup 2.3.0 (Feb 2020) */
|
||||
#ifdef CRYPT_BITLK
|
||||
if (streq_ptr(arg_type, CRYPT_BITLK)) {
|
||||
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
|
||||
|
||||
bool use_cached_passphrase = true, try_discover_key = !key_file;
|
||||
const char *discovered_key_fn = strjoina(volume, ".key");
|
||||
_cleanup_strv_free_erase_ char **passwords = NULL;
|
||||
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
|
||||
_cleanup_(iovec_done_erase) struct iovec discovered_key_data = {};
|
||||
const struct iovec *key_data = NULL;
|
||||
TokenType token_type = determine_token_type();
|
||||
|
||||
log_debug("Beginning attempt %u to unlock.", tries);
|
||||
|
||||
/* When we were able to acquire multiple keys, let's always process them in this order:
|
||||
*
|
||||
* 1. A key acquired via PKCS#11 or FIDO2 token, or TPM2 chip
|
||||
* 2. The configured or discovered key, of which both are exclusive and optional
|
||||
* 3. The empty password, in case arg_try_empty_password is set
|
||||
* 4. We enquire the user for a password
|
||||
*/
|
||||
|
||||
if (try_discover_key) {
|
||||
r = discover_key(discovered_key_fn, volume, token_type, &discovered_key_data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
key_data = &discovered_key_data;
|
||||
}
|
||||
|
||||
if (token_type < 0 && !key_file && !key_data && !passwords) {
|
||||
|
||||
/* If we have nothing to try anymore, then acquire a new password */
|
||||
|
||||
if (arg_try_empty_password) {
|
||||
/* Hmm, let's try an empty password now, but only once */
|
||||
arg_try_empty_password = false;
|
||||
key_data = &iovec_empty;
|
||||
} else {
|
||||
/* Ask the user for a passphrase or recovery key only as last resort, if we
|
||||
* have nothing else to check for */
|
||||
if (passphrase_type == PASSPHRASE_NONE) {
|
||||
passphrase_type = check_registered_passwords(cd);
|
||||
if (passphrase_type == PASSPHRASE_NONE)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No passphrase or recovery key registered.");
|
||||
}
|
||||
|
||||
r = get_password(
|
||||
volume,
|
||||
source,
|
||||
until,
|
||||
/* ignore_cached= */ !use_cached_passphrase || arg_verify,
|
||||
passphrase_type,
|
||||
&passwords);
|
||||
use_cached_passphrase = false;
|
||||
if (r == -EAGAIN)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (streq_ptr(arg_type, CRYPT_TCRYPT))
|
||||
r = attach_tcrypt(cd, volume, token_type, key_file, key_data, passwords, flags);
|
||||
else
|
||||
r = attach_luks_or_plain_or_bitlk(cd, volume, token_type, key_file, key_data, passwords, flags, until);
|
||||
if (r >= 0)
|
||||
break;
|
||||
if (r != -EAGAIN)
|
||||
return r;
|
||||
|
||||
/* Key not correct? Let's try again, but let's invalidate one of the passed fields, so that
|
||||
* we fall back to the next best thing. */
|
||||
|
||||
if (token_type == TOKEN_TPM2) {
|
||||
arg_tpm2_device = mfree(arg_tpm2_device);
|
||||
arg_tpm2_device_auto = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token_type == TOKEN_FIDO2) {
|
||||
arg_fido2_device = mfree(arg_fido2_device);
|
||||
arg_fido2_device_auto = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token_type == TOKEN_PKCS11) {
|
||||
arg_pkcs11_uri = mfree(arg_pkcs11_uri);
|
||||
arg_pkcs11_uri_auto = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (try_discover_key) {
|
||||
try_discover_key = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key_file) {
|
||||
key_file = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (passwords) {
|
||||
passwords = strv_free_erase(passwords);
|
||||
continue;
|
||||
}
|
||||
|
||||
log_debug("Prepared for next attempt to unlock.");
|
||||
}
|
||||
|
||||
if (arg_tries != 0 && tries >= arg_tries)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Too many attempts to activate; giving up.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_detach(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
|
||||
const char *volume = ASSERT_PTR(argv[1]);
|
||||
int r;
|
||||
|
||||
assert(argc == 2);
|
||||
|
||||
if (!filename_is_valid(volume))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
||||
|
||||
r = crypt_init_by_name(&cd, volume);
|
||||
if (r == -ENODEV) {
|
||||
log_info("Volume %s already inactive.", volume);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "crypt_init_by_name() for volume '%s' failed: %m", volume);
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
r = crypt_deactivate(cd, volume);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to deactivate '%s': %m", volume);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
int r;
|
||||
|
||||
log_setup();
|
||||
@ -2403,279 +2672,13 @@ static int run(int argc, char *argv[]) {
|
||||
|
||||
cryptsetup_enable_logging(NULL);
|
||||
|
||||
if (argc - optind < 2)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"This program requires at least two arguments.");
|
||||
verb = ASSERT_PTR(argv[optind]);
|
||||
static const Verb verbs[] = {
|
||||
{ "attach", 3, 5, 0, verb_attach },
|
||||
{ "detach", 2, 2, 0, verb_detach },
|
||||
{}
|
||||
};
|
||||
|
||||
if (streq(verb, "attach")) {
|
||||
_unused_ _cleanup_(remove_and_erasep) const char *destroy_key_file = NULL;
|
||||
crypt_status_info status;
|
||||
uint32_t flags = 0;
|
||||
unsigned tries;
|
||||
usec_t until;
|
||||
PassphraseType passphrase_type = PASSPHRASE_NONE;
|
||||
|
||||
/* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [KEY-FILE] [CONFIG] */
|
||||
|
||||
if (argc - optind < 3)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least two arguments.");
|
||||
if (argc - optind >= 6)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach does not accept more than four arguments.");
|
||||
|
||||
const char *volume = ASSERT_PTR(argv[optind + 1]),
|
||||
*source = ASSERT_PTR(argv[optind + 2]),
|
||||
*key_file = argc - optind >= 4 ? mangle_none(argv[optind + 3]) : NULL,
|
||||
*config = argc - optind >= 5 ? mangle_none(argv[optind + 4]) : NULL;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (config) {
|
||||
r = parse_crypt_config(config);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
log_debug("%s %s ← %s type=%s cipher=%s", __func__,
|
||||
volume, source, strempty(arg_type), strempty(arg_cipher));
|
||||
|
||||
/* A delicious drop of snake oil */
|
||||
(void) mlockall(MCL_FUTURE);
|
||||
|
||||
if (key_file && arg_keyfile_erase)
|
||||
destroy_key_file = key_file; /* let's get this baby erased when we leave */
|
||||
|
||||
if (arg_header) {
|
||||
if (streq_ptr(arg_type, CRYPT_TCRYPT)){
|
||||
log_debug("tcrypt header: %s", arg_header);
|
||||
r = crypt_init_data_device(&cd, arg_header, source);
|
||||
} else {
|
||||
log_debug("LUKS header: %s", arg_header);
|
||||
r = crypt_init(&cd, arg_header);
|
||||
}
|
||||
} else
|
||||
r = crypt_init(&cd, source);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "crypt_init() failed: %m");
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
status = crypt_status(cd, volume);
|
||||
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
|
||||
log_info("Volume %s already active.", volume);
|
||||
return 0;
|
||||
}
|
||||
|
||||
flags = determine_flags();
|
||||
|
||||
until = usec_add(now(CLOCK_MONOTONIC), arg_timeout);
|
||||
if (until == USEC_INFINITY)
|
||||
until = 0;
|
||||
|
||||
if (arg_key_size == 0)
|
||||
arg_key_size = 256U / 8U;
|
||||
|
||||
if (key_file) {
|
||||
struct stat st;
|
||||
|
||||
/* 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. */
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd));
|
||||
|
||||
/* since cryptsetup 2.7.0 (Jan 2024) */
|
||||
#if HAVE_CRYPT_SET_KEYRING_TO_LINK
|
||||
if (arg_link_key_description) {
|
||||
r = crypt_set_keyring_to_link(cd, arg_link_key_description, NULL, arg_link_key_type, arg_link_keyring);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to set keyring or key description to link volume key in, ignoring: %m");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (arg_header) {
|
||||
r = crypt_set_data_device(cd, source);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set LUKS data device %s: %m", source);
|
||||
}
|
||||
|
||||
/* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */
|
||||
if (!key_file && use_token_plugins()) {
|
||||
r = crypt_activate_by_token_pin_ask_password(
|
||||
cd,
|
||||
volume,
|
||||
/* type= */ NULL,
|
||||
until,
|
||||
/* userdata= */ NULL,
|
||||
flags,
|
||||
"Please enter LUKS2 token PIN:",
|
||||
"luks2-pin",
|
||||
"cryptsetup.luks2-pin");
|
||||
if (r >= 0) {
|
||||
log_debug("Volume %s activated with a LUKS token.", volume);
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug_errno(r, "Token activation unsuccessful for device %s: %m", crypt_get_device_name(cd));
|
||||
}
|
||||
}
|
||||
|
||||
/* since cryptsetup 2.3.0 (Feb 2020) */
|
||||
#ifdef CRYPT_BITLK
|
||||
if (streq_ptr(arg_type, CRYPT_BITLK)) {
|
||||
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
|
||||
|
||||
bool use_cached_passphrase = true, try_discover_key = !key_file;
|
||||
const char *discovered_key_fn = strjoina(volume, ".key");
|
||||
_cleanup_strv_free_erase_ char **passwords = NULL;
|
||||
for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) {
|
||||
_cleanup_(iovec_done_erase) struct iovec discovered_key_data = {};
|
||||
const struct iovec *key_data = NULL;
|
||||
TokenType token_type = determine_token_type();
|
||||
|
||||
log_debug("Beginning attempt %u to unlock.", tries);
|
||||
|
||||
/* When we were able to acquire multiple keys, let's always process them in this order:
|
||||
*
|
||||
* 1. A key acquired via PKCS#11 or FIDO2 token, or TPM2 chip
|
||||
* 2. The configured or discovered key, of which both are exclusive and optional
|
||||
* 3. The empty password, in case arg_try_empty_password is set
|
||||
* 4. We enquire the user for a password
|
||||
*/
|
||||
|
||||
if (try_discover_key) {
|
||||
r = discover_key(discovered_key_fn, volume, token_type, &discovered_key_data);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
key_data = &discovered_key_data;
|
||||
}
|
||||
|
||||
if (token_type < 0 && !key_file && !key_data && !passwords) {
|
||||
|
||||
/* If we have nothing to try anymore, then acquire a new password */
|
||||
|
||||
if (arg_try_empty_password) {
|
||||
/* Hmm, let's try an empty password now, but only once */
|
||||
arg_try_empty_password = false;
|
||||
key_data = &iovec_empty;
|
||||
} else {
|
||||
/* Ask the user for a passphrase or recovery key only as last resort, if we have
|
||||
* nothing else to check for */
|
||||
if (passphrase_type == PASSPHRASE_NONE) {
|
||||
passphrase_type = check_registered_passwords(cd);
|
||||
if (passphrase_type == PASSPHRASE_NONE)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No passphrase or recovery key registered.");
|
||||
}
|
||||
|
||||
r = get_password(
|
||||
volume,
|
||||
source,
|
||||
until,
|
||||
/* ignore_cached= */ !use_cached_passphrase || arg_verify,
|
||||
passphrase_type,
|
||||
&passwords);
|
||||
use_cached_passphrase = false;
|
||||
if (r == -EAGAIN)
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
if (streq_ptr(arg_type, CRYPT_TCRYPT))
|
||||
r = attach_tcrypt(cd, volume, token_type, key_file, key_data, passwords, flags);
|
||||
else
|
||||
r = attach_luks_or_plain_or_bitlk(cd, volume, token_type, key_file, key_data, passwords, flags, until);
|
||||
if (r >= 0)
|
||||
break;
|
||||
if (r != -EAGAIN)
|
||||
return r;
|
||||
|
||||
/* Key not correct? Let's try again, but let's invalidate one of the passed fields,
|
||||
* so that we fall back to the next best thing. */
|
||||
|
||||
if (token_type == TOKEN_TPM2) {
|
||||
arg_tpm2_device = mfree(arg_tpm2_device);
|
||||
arg_tpm2_device_auto = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token_type == TOKEN_FIDO2) {
|
||||
arg_fido2_device = mfree(arg_fido2_device);
|
||||
arg_fido2_device_auto = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token_type == TOKEN_PKCS11) {
|
||||
arg_pkcs11_uri = mfree(arg_pkcs11_uri);
|
||||
arg_pkcs11_uri_auto = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (try_discover_key) {
|
||||
try_discover_key = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key_file) {
|
||||
key_file = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (passwords) {
|
||||
passwords = strv_free_erase(passwords);
|
||||
continue;
|
||||
}
|
||||
|
||||
log_debug("Prepared for next attempt to unlock.");
|
||||
}
|
||||
|
||||
if (arg_tries != 0 && tries >= arg_tries)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Too many attempts to activate; giving up.");
|
||||
|
||||
} else if (streq(verb, "detach")) {
|
||||
const char *volume = ASSERT_PTR(argv[optind + 1]);
|
||||
|
||||
if (argc - optind >= 3)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "detach does not accept more than one argument.");
|
||||
|
||||
if (!filename_is_valid(volume))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
||||
|
||||
r = crypt_init_by_name(&cd, volume);
|
||||
if (r == -ENODEV) {
|
||||
log_info("Volume %s already inactive.", volume);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "crypt_init_by_name() for volume '%s' failed: %m", volume);
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
r = crypt_deactivate(cd, volume);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to deactivate '%s': %m", volume);
|
||||
|
||||
} else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", verb);
|
||||
|
||||
return 0;
|
||||
return dispatch_verb(argc, argv, verbs, NULL);
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "process-util.h"
|
||||
#include "string-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "verbs.h"
|
||||
|
||||
static uint32_t arg_activate_flags;
|
||||
static int arg_percent;
|
||||
@ -86,118 +87,118 @@ static const char *integrity_algorithm_select(const void *key_file_buf) {
|
||||
return "crc32c";
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
static int verb_attach(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
|
||||
char *verb, *volume;
|
||||
crypt_status_info status;
|
||||
_cleanup_(erase_and_freep) void *key_buf = NULL;
|
||||
size_t key_buf_size = 0;
|
||||
int r;
|
||||
|
||||
/* attach name device optional_key_file optional_options */
|
||||
|
||||
assert(argc >= 3 && argc <= 5);
|
||||
|
||||
const char *volume = argv[1],
|
||||
*device = argv[2],
|
||||
*key_file = mangle_none(argc > 3 ? argv[3] : NULL),
|
||||
*options = mangle_none(argc > 4 ? argv[4] : NULL);
|
||||
|
||||
if (!filename_is_valid(volume))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
||||
|
||||
if (key_file) {
|
||||
r = load_key_file(key_file, &key_buf, &key_buf_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (options) {
|
||||
r = parse_integrity_options(options, &arg_activate_flags, &arg_percent,
|
||||
&arg_commit_time, &arg_existing_data_device, &arg_integrity_algorithm);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = crypt_init(&cd, device);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open integrity device %s: %m", device);
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
status = crypt_status(cd, volume);
|
||||
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
|
||||
log_info("Volume %s already active.", volume);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = crypt_load(cd,
|
||||
CRYPT_INTEGRITY,
|
||||
&(struct crypt_params_integrity) {
|
||||
.journal_watermark = arg_percent,
|
||||
.journal_commit_time = DIV_ROUND_UP(arg_commit_time, USEC_PER_SEC),
|
||||
.integrity = integrity_algorithm_select(key_buf),
|
||||
});
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load integrity superblock: %m");
|
||||
|
||||
if (!isempty(arg_existing_data_device)) {
|
||||
r = crypt_set_data_device(cd, arg_existing_data_device);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add separate data device: %m");
|
||||
}
|
||||
|
||||
r = crypt_activate_by_volume_key(cd, volume, key_buf, key_buf_size, arg_activate_flags);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up integrity device: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_detach(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
|
||||
int r;
|
||||
|
||||
assert(argc == 2);
|
||||
|
||||
const char *volume = argv[1];
|
||||
|
||||
if (!filename_is_valid(volume))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
||||
|
||||
r = crypt_init_by_name(&cd, volume);
|
||||
if (r == -ENODEV) {
|
||||
log_info("Volume %s already inactive.", volume);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "crypt_init_by_name() failed: %m");
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
r = crypt_deactivate(cd, volume);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to deactivate: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
if (argv_looks_like_help(argc, argv))
|
||||
return help();
|
||||
|
||||
if (argc < 3)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires at least two arguments.");
|
||||
|
||||
verb = argv[1];
|
||||
volume = argv[2];
|
||||
|
||||
log_setup();
|
||||
|
||||
cryptsetup_enable_logging(NULL);
|
||||
|
||||
umask(0022);
|
||||
|
||||
if (streq(verb, "attach")) {
|
||||
/* attach name device optional_key_file optional_options */
|
||||
static const Verb verbs[] = {
|
||||
{ "attach", 3, 5, 0, verb_attach },
|
||||
{ "detach", 2, 2, 0, verb_detach },
|
||||
{}
|
||||
};
|
||||
|
||||
crypt_status_info status;
|
||||
_cleanup_(erase_and_freep) void *key_buf = NULL;
|
||||
const char *device, *key_file, *options;
|
||||
size_t key_buf_size = 0;
|
||||
|
||||
if (argc < 4)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least three arguments.");
|
||||
|
||||
if (argc > 6)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach has a maximum of five arguments.");
|
||||
|
||||
device = argv[3];
|
||||
key_file = mangle_none(argc > 4 ? argv[4] : NULL);
|
||||
options = mangle_none(argc > 5 ? argv[5] : NULL);
|
||||
|
||||
if (!filename_is_valid(volume))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
||||
|
||||
if (key_file) {
|
||||
r = load_key_file(key_file, &key_buf, &key_buf_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (options) {
|
||||
r = parse_integrity_options(options, &arg_activate_flags, &arg_percent,
|
||||
&arg_commit_time, &arg_existing_data_device, &arg_integrity_algorithm);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = crypt_init(&cd, device);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open integrity device %s: %m", device);
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
status = crypt_status(cd, volume);
|
||||
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
|
||||
log_info("Volume %s already active.", volume);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = crypt_load(cd,
|
||||
CRYPT_INTEGRITY,
|
||||
&(struct crypt_params_integrity) {
|
||||
.journal_watermark = arg_percent,
|
||||
.journal_commit_time = DIV_ROUND_UP(arg_commit_time, USEC_PER_SEC),
|
||||
.integrity = integrity_algorithm_select(key_buf),
|
||||
});
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load integrity superblock: %m");
|
||||
|
||||
if (!isempty(arg_existing_data_device)) {
|
||||
r = crypt_set_data_device(cd, arg_existing_data_device);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add separate data device: %m");
|
||||
}
|
||||
|
||||
r = crypt_activate_by_volume_key(cd, volume, key_buf, key_buf_size, arg_activate_flags);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up integrity device: %m");
|
||||
|
||||
} else if (streq(verb, "detach")) {
|
||||
|
||||
if (argc > 3)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "detach has a maximum of two arguments.");
|
||||
|
||||
if (!filename_is_valid(volume))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
||||
|
||||
r = crypt_init_by_name(&cd, volume);
|
||||
if (r == -ENODEV) {
|
||||
log_info("Volume %s already inactive.", volume);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "crypt_init_by_name() failed: %m");
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
r = crypt_deactivate(cd, volume);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to deactivate: %m");
|
||||
|
||||
} else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", verb);
|
||||
|
||||
return 0;
|
||||
return dispatch_verb(argc, argv, verbs, NULL);
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "process-util.h"
|
||||
#include "string-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "verbs.h"
|
||||
|
||||
static char *arg_hash = NULL;
|
||||
static bool arg_superblock = true;
|
||||
@ -274,158 +275,161 @@ static int parse_options(const char *options) {
|
||||
return r;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
static int verb_attach(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
|
||||
const char *verb;
|
||||
_cleanup_free_ void *m = NULL;
|
||||
struct crypt_params_verity p = {};
|
||||
crypt_status_info status;
|
||||
size_t l;
|
||||
int r;
|
||||
|
||||
assert(argc >= 5);
|
||||
|
||||
const char *volume = argv[1],
|
||||
*data_device = argv[2],
|
||||
*verity_device = argv[3],
|
||||
*root_hash = argv[4],
|
||||
*options = mangle_none(argc > 5 ? argv[5] : NULL);
|
||||
|
||||
if (!filename_is_valid(volume))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
||||
|
||||
r = unhexmem(root_hash, &m, &l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse root hash: %m");
|
||||
|
||||
r = crypt_init(&cd, verity_device);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open verity device %s: %m", verity_device);
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
status = crypt_status(cd, volume);
|
||||
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
|
||||
log_info("Volume %s already active.", volume);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options) {
|
||||
r = parse_options(options);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse options: %m");
|
||||
}
|
||||
|
||||
if (arg_superblock) {
|
||||
p = (struct crypt_params_verity) {
|
||||
.fec_device = arg_fec_what,
|
||||
.hash_area_offset = arg_hash_offset,
|
||||
.fec_area_offset = arg_fec_offset,
|
||||
.fec_roots = arg_fec_roots,
|
||||
};
|
||||
|
||||
r = crypt_load(cd, CRYPT_VERITY, &p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load verity superblock: %m");
|
||||
} else {
|
||||
p = (struct crypt_params_verity) {
|
||||
.hash_name = arg_hash,
|
||||
.data_device = data_device,
|
||||
.fec_device = arg_fec_what,
|
||||
.salt = arg_salt,
|
||||
.salt_size = arg_salt_size,
|
||||
.hash_type = arg_format,
|
||||
.data_block_size = arg_data_block_size,
|
||||
.hash_block_size = arg_hash_block_size,
|
||||
.data_size = arg_data_blocks,
|
||||
.hash_area_offset = arg_hash_offset,
|
||||
.fec_area_offset = arg_fec_offset,
|
||||
.fec_roots = arg_fec_roots,
|
||||
.flags = CRYPT_VERITY_NO_HEADER,
|
||||
};
|
||||
|
||||
r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, arg_uuid, NULL, 0, &p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format verity superblock: %m");
|
||||
}
|
||||
|
||||
r = crypt_set_data_device(cd, data_device);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to configure data device: %m");
|
||||
|
||||
if (arg_root_hash_signature) {
|
||||
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
|
||||
_cleanup_free_ char *hash_sig = NULL;
|
||||
size_t hash_sig_size;
|
||||
char *value;
|
||||
|
||||
if ((value = startswith(arg_root_hash_signature, "base64:"))) {
|
||||
r = unbase64mem(value, (void*) &hash_sig, &hash_sig_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", arg_root_hash_signature);
|
||||
} else {
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, arg_root_hash_signature, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&hash_sig, &hash_sig_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read root hash signature: %m");
|
||||
}
|
||||
|
||||
r = crypt_activate_by_signed_key(cd, volume, m, l, hash_sig, hash_sig_size, arg_activate_flags);
|
||||
#else
|
||||
assert_not_reached();
|
||||
#endif
|
||||
} else
|
||||
r = crypt_activate_by_volume_key(cd, volume, m, l, arg_activate_flags);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up verity device '%s': %m", volume);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verb_detach(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(crypt_freep) struct crypt_device *cd = NULL;
|
||||
int r;
|
||||
|
||||
assert(argc == 2);
|
||||
|
||||
const char *volume = argv[1];
|
||||
|
||||
if (!filename_is_valid(volume))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
||||
|
||||
r = crypt_init_by_name(&cd, volume);
|
||||
if (r == -ENODEV) {
|
||||
log_info("Volume %s 'already' inactive.", volume);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "crypt_init_by_name() for volume '%s' failed: %m", volume);
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
r = crypt_deactivate(cd, volume);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to deactivate volume '%s': %m", volume);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
if (argv_looks_like_help(argc, argv))
|
||||
return help();
|
||||
|
||||
if (argc < 3)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires at least two arguments.");
|
||||
|
||||
log_setup();
|
||||
|
||||
cryptsetup_enable_logging(NULL);
|
||||
|
||||
umask(0022);
|
||||
|
||||
verb = argv[1];
|
||||
static const Verb verbs[] = {
|
||||
{ "attach", 5, 6, 0, verb_attach },
|
||||
{ "detach", 2, 2, 0, verb_detach },
|
||||
{}
|
||||
};
|
||||
|
||||
if (streq(verb, "attach")) {
|
||||
const char *volume, *data_device, *verity_device, *root_hash, *options;
|
||||
_cleanup_free_ void *m = NULL;
|
||||
struct crypt_params_verity p = {};
|
||||
crypt_status_info status;
|
||||
size_t l;
|
||||
|
||||
if (argc < 6)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least four arguments.");
|
||||
|
||||
volume = argv[2];
|
||||
data_device = argv[3];
|
||||
verity_device = argv[4];
|
||||
root_hash = argv[5];
|
||||
options = mangle_none(argc > 6 ? argv[6] : NULL);
|
||||
|
||||
if (!filename_is_valid(volume))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
||||
|
||||
r = unhexmem(root_hash, &m, &l);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse root hash: %m");
|
||||
|
||||
r = crypt_init(&cd, verity_device);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open verity device %s: %m", verity_device);
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
status = crypt_status(cd, volume);
|
||||
if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) {
|
||||
log_info("Volume %s already active.", volume);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (options) {
|
||||
r = parse_options(options);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse options: %m");
|
||||
}
|
||||
|
||||
if (arg_superblock) {
|
||||
p = (struct crypt_params_verity) {
|
||||
.fec_device = arg_fec_what,
|
||||
.hash_area_offset = arg_hash_offset,
|
||||
.fec_area_offset = arg_fec_offset,
|
||||
.fec_roots = arg_fec_roots,
|
||||
};
|
||||
|
||||
r = crypt_load(cd, CRYPT_VERITY, &p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to load verity superblock: %m");
|
||||
} else {
|
||||
p = (struct crypt_params_verity) {
|
||||
.hash_name = arg_hash,
|
||||
.data_device = data_device,
|
||||
.fec_device = arg_fec_what,
|
||||
.salt = arg_salt,
|
||||
.salt_size = arg_salt_size,
|
||||
.hash_type = arg_format,
|
||||
.data_block_size = arg_data_block_size,
|
||||
.hash_block_size = arg_hash_block_size,
|
||||
.data_size = arg_data_blocks,
|
||||
.hash_area_offset = arg_hash_offset,
|
||||
.fec_area_offset = arg_fec_offset,
|
||||
.fec_roots = arg_fec_roots,
|
||||
.flags = CRYPT_VERITY_NO_HEADER,
|
||||
};
|
||||
|
||||
r = crypt_format(cd, CRYPT_VERITY, NULL, NULL, arg_uuid, NULL, 0, &p);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to format verity superblock: %m");
|
||||
}
|
||||
|
||||
r = crypt_set_data_device(cd, data_device);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to configure data device: %m");
|
||||
|
||||
if (arg_root_hash_signature) {
|
||||
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
|
||||
_cleanup_free_ char *hash_sig = NULL;
|
||||
size_t hash_sig_size;
|
||||
char *value;
|
||||
|
||||
if ((value = startswith(arg_root_hash_signature, "base64:"))) {
|
||||
r = unbase64mem(value, (void*) &hash_sig, &hash_sig_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse root hash signature '%s': %m", arg_root_hash_signature);
|
||||
} else {
|
||||
r = read_full_file_full(
|
||||
AT_FDCWD, arg_root_hash_signature, UINT64_MAX, SIZE_MAX,
|
||||
READ_FULL_FILE_CONNECT_SOCKET,
|
||||
NULL,
|
||||
&hash_sig, &hash_sig_size);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to read root hash signature: %m");
|
||||
}
|
||||
|
||||
r = crypt_activate_by_signed_key(cd, volume, m, l, hash_sig, hash_sig_size, arg_activate_flags);
|
||||
#else
|
||||
assert_not_reached();
|
||||
#endif
|
||||
} else
|
||||
r = crypt_activate_by_volume_key(cd, volume, m, l, arg_activate_flags);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up verity device '%s': %m", volume);
|
||||
|
||||
} else if (streq(verb, "detach")) {
|
||||
const char *volume;
|
||||
|
||||
volume = argv[2];
|
||||
|
||||
if (!filename_is_valid(volume))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume);
|
||||
|
||||
r = crypt_init_by_name(&cd, volume);
|
||||
if (r == -ENODEV) {
|
||||
log_info("Volume %s 'already' inactive.", volume);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "crypt_init_by_name() for volume '%s' failed: %m", volume);
|
||||
|
||||
cryptsetup_enable_logging(cd);
|
||||
|
||||
r = crypt_deactivate(cd, volume);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to deactivate volume '%s': %m", volume);
|
||||
|
||||
} else
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", verb);
|
||||
|
||||
return 0;
|
||||
return dispatch_verb(argc, argv, verbs, NULL);
|
||||
}
|
||||
|
||||
DEFINE_MAIN_FUNCTION(run);
|
||||
|
Loading…
x
Reference in New Issue
Block a user