cryptsetup: support non-LUKS crypto partitions
This commit is contained in:
@@ -480,3 +480,13 @@ finish:
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int ask_password_auto(const char *message, const char *icon, usec_t until, char **_passphrase) {
|
||||
assert(message);
|
||||
assert(_passphrase);
|
||||
|
||||
if (isatty(STDIN_FILENO))
|
||||
return ask_password_tty(message, until, NULL, _passphrase);
|
||||
else
|
||||
return ask_password_agent(message, icon, until, _passphrase);
|
||||
}
|
||||
|
||||
@@ -28,4 +28,6 @@ int ask_password_tty(const char *message, usec_t until, const char *flag_file, c
|
||||
|
||||
int ask_password_agent(const char *message, const char *icon, usec_t until, char **_passphrase);
|
||||
|
||||
int ask_password_auto(const char *message, const char *icon, usec_t until, char **_passphrase);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -115,9 +115,8 @@ static int create_disk(
|
||||
"\n[Service]\n"
|
||||
"Type=oneshot\n"
|
||||
"RemainAfterExit=yes\n"
|
||||
"ExecStart=" SYSTEMD_CRYPTSETUP_PATH " %s '%s' '%s' '%s' '%s'\n"
|
||||
"ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
|
||||
"ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
|
||||
options && has_option(options, "swap") ? "format-and-attach" : "attach",
|
||||
name, u, strempty(password), strempty(options),
|
||||
name);
|
||||
|
||||
|
||||
+150
-53
@@ -28,21 +28,21 @@
|
||||
#include "util.h"
|
||||
#include "ask-password-api.h"
|
||||
|
||||
static unsigned opt_tries = 0;
|
||||
static const char *opt_type = NULL; /* LUKS1 or PLAIN */
|
||||
static char *opt_cipher = NULL;
|
||||
static unsigned opt_size = 0;
|
||||
static char *opt_cipher_mode = NULL;
|
||||
static unsigned opt_key_size = 0;
|
||||
static char *opt_hash = NULL;
|
||||
static unsigned opt_tries = 0;
|
||||
static bool opt_readonly = false;
|
||||
static bool opt_verify = false;
|
||||
static usec_t arg_timeout = 0;
|
||||
static usec_t opt_timeout = 0;
|
||||
|
||||
static int parse_one_option(const char *option) {
|
||||
assert(option);
|
||||
|
||||
/* Handled outside of this tool */
|
||||
if (streq(option, "swap") ||
|
||||
streq(option, "tmp") ||
|
||||
streq(option, "noauto"))
|
||||
if (streq(option, "noauto"))
|
||||
return 0;
|
||||
|
||||
if (startswith(option, "cipher=")) {
|
||||
@@ -56,7 +56,7 @@ static int parse_one_option(const char *option) {
|
||||
|
||||
} else if (startswith(option, "size=")) {
|
||||
|
||||
if (safe_atou(option+5, &opt_size) < 0) {
|
||||
if (safe_atou(option+5, &opt_key_size) < 0) {
|
||||
log_error("size= parse failure, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
@@ -70,6 +70,15 @@ static int parse_one_option(const char *option) {
|
||||
free(opt_hash);
|
||||
opt_hash = t;
|
||||
|
||||
} else if (startswith(option, "mode=")) {
|
||||
char *t;
|
||||
|
||||
if (!(t = strdup(option+5)))
|
||||
return -ENOMEM;
|
||||
|
||||
free(opt_cipher_mode);
|
||||
opt_cipher_mode = t;
|
||||
|
||||
} else if (startswith(option, "tries=")) {
|
||||
|
||||
if (safe_atou(option+6, &opt_tries) < 0) {
|
||||
@@ -81,9 +90,15 @@ static int parse_one_option(const char *option) {
|
||||
opt_readonly = true;
|
||||
else if (streq(option, "verify"))
|
||||
opt_verify = true;
|
||||
else if (streq(option, "luks"))
|
||||
opt_type = CRYPT_LUKS1;
|
||||
else if (streq(option, "plain") ||
|
||||
streq(option, "swap") ||
|
||||
streq(option, "tmp"))
|
||||
opt_type = CRYPT_PLAIN;
|
||||
else if (startswith(option, "timeout=")) {
|
||||
|
||||
if (parse_usec(option+8, &arg_timeout) < 0) {
|
||||
if (parse_usec(option+8, &opt_timeout) < 0) {
|
||||
log_error("timeout= parse failure, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
@@ -119,35 +134,15 @@ static int parse_options(const char *options) {
|
||||
}
|
||||
|
||||
static void log_glue(int level, const char *msg, void *usrptr) {
|
||||
|
||||
log_full(level == CRYPT_LOG_ERROR ? LOG_ERR :
|
||||
level == CRYPT_LOG_VERBOSE ? LOG_INFO :
|
||||
level == CRYPT_LOG_DEBUG ? LOG_DEBUG :
|
||||
LOG_NOTICE,
|
||||
"%s", msg);
|
||||
}
|
||||
|
||||
static int password_glue(const char *msg, char *buf, size_t length, void *usrptr) {
|
||||
usec_t until;
|
||||
char *password = NULL;
|
||||
int k;
|
||||
|
||||
until = now(CLOCK_MONOTONIC) + (arg_timeout > 0 ? arg_timeout : 60 * USEC_PER_SEC);
|
||||
|
||||
if ((k = ask_password_agent(msg, "drive-harddisk", until, &password)) < 0)
|
||||
return k;
|
||||
|
||||
strncpy(buf, password, length-1);
|
||||
buf[length-1] = 0;
|
||||
|
||||
free(password);
|
||||
|
||||
return strlen(buf);
|
||||
log_debug("%s", msg);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r = EXIT_FAILURE;
|
||||
struct crypt_device *cd = NULL;
|
||||
char *password = NULL;
|
||||
const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL;
|
||||
crypt_status_info status;
|
||||
|
||||
if (argc < 3) {
|
||||
log_error("This program requires at least two arguments.");
|
||||
@@ -158,11 +153,12 @@ int main(int argc, char *argv[]) {
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
if (streq(argv[1], "attach") ||
|
||||
streq(argv[1], "format-and-attach")) {
|
||||
if (streq(argv[1], "attach")) {
|
||||
uint32_t flags = 0;
|
||||
int k;
|
||||
unsigned try;
|
||||
const char *key_file = NULL;
|
||||
usec_t until;
|
||||
|
||||
if (argc < 4) {
|
||||
log_error("attach requires at least two arguments.");
|
||||
@@ -186,34 +182,129 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
crypt_set_log_callback(cd, log_glue, NULL);
|
||||
crypt_set_password_callback(cd, password_glue, NULL);
|
||||
|
||||
if (streq(argv[1], "format-and-attach")) {
|
||||
|
||||
/* Format with random key and attach */
|
||||
|
||||
log_error("Formatting not yet supported.");
|
||||
goto finish;
|
||||
|
||||
} else if ((k = crypt_load(cd, CRYPT_LUKS1, NULL))) {
|
||||
log_error("crypt_load() failed: %s", strerror(-k));
|
||||
status = crypt_status(cd, argv[2]);
|
||||
if (status == CRYPT_ACTIVE || status == CRYPT_BUSY) {
|
||||
log_info("Volume %s already active.", argv[2]);
|
||||
r = EXIT_SUCCESS;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (opt_readonly)
|
||||
flags |= CRYPT_ACTIVATE_READONLY;
|
||||
|
||||
if (key_file) {
|
||||
crypt_set_password_retry(cd, 1);
|
||||
k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, 0, flags);
|
||||
} else {
|
||||
crypt_set_password_retry(cd, opt_tries > 0 ? opt_tries : 3);
|
||||
k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, NULL, 0, flags);
|
||||
until = now(CLOCK_MONOTONIC) + (opt_timeout > 0 ? opt_timeout : 60 * USEC_PER_SEC);
|
||||
|
||||
opt_tries = opt_tries > 0 ? opt_tries : 3;
|
||||
opt_key_size = (opt_key_size > 0 ? opt_key_size : 256);
|
||||
cipher = opt_cipher ? opt_cipher : "aes";
|
||||
cipher_mode = opt_cipher_mode ? opt_cipher_mode : "cbc-essiv:sha256";
|
||||
hash = opt_hash ? opt_hash : "ripemd160";
|
||||
|
||||
for (try = 0; try < opt_tries; try++) {
|
||||
bool pass_volume_key = false;
|
||||
|
||||
free(password);
|
||||
password = NULL;
|
||||
|
||||
if (!key_file) {
|
||||
|
||||
if ((k = ask_password_auto("Please enter passphrase for disk:", "drive-harddisk", until, &password)) < 0) {
|
||||
log_error("Failed to query password: %s", strerror(-k));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (opt_verify) {
|
||||
char *password2 = NULL;
|
||||
|
||||
if ((k = ask_password_auto("Please enter passphrase for disk (verification):", "drive-harddisk", until, &password2)) < 0) {
|
||||
log_error("Failed to query verification password: %s", strerror(-k));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (!streq(password, password2)) {
|
||||
log_warning("Passwords did not match, retrying.");
|
||||
free(password2);
|
||||
continue;
|
||||
}
|
||||
|
||||
free(password2);
|
||||
}
|
||||
|
||||
if (strlen(password)+1 < opt_key_size) {
|
||||
char *c;
|
||||
|
||||
/* Pad password if necessary */
|
||||
|
||||
if (!(c = new(char, opt_key_size))) {
|
||||
log_error("Out of memory.");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
strncpy(c, password, opt_key_size);
|
||||
free(password);
|
||||
password = c;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opt_type || streq(opt_type, CRYPT_LUKS1))
|
||||
k = crypt_load(cd, CRYPT_LUKS1, NULL);
|
||||
|
||||
if ((!opt_type && k < 0) || streq_ptr(opt_type, CRYPT_PLAIN)) {
|
||||
struct crypt_params_plain params;
|
||||
|
||||
zero(params);
|
||||
params.hash = hash;
|
||||
|
||||
/* In contrast to what the name
|
||||
* crypt_setup() might suggest this
|
||||
* doesn't actually format anything,
|
||||
* it just configures encryption
|
||||
* parameters when used for plain
|
||||
* mode. */
|
||||
k = crypt_format(cd, CRYPT_PLAIN,
|
||||
cipher,
|
||||
cipher_mode,
|
||||
NULL,
|
||||
NULL,
|
||||
opt_key_size / 8,
|
||||
¶ms);
|
||||
|
||||
pass_volume_key = streq(hash, "plain");
|
||||
}
|
||||
|
||||
if (k < 0) {
|
||||
log_error("Loading of cryptographic parameters failed: %s", strerror(-k));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
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,
|
||||
argv[3]);
|
||||
|
||||
if (key_file)
|
||||
k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, opt_key_size, flags);
|
||||
else if (pass_volume_key)
|
||||
k = crypt_activate_by_volume_key(cd, argv[2], password, opt_key_size, flags);
|
||||
else
|
||||
k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, password, strlen(password), flags);
|
||||
|
||||
if (k >= 0)
|
||||
break;
|
||||
|
||||
if (k != -EPERM) {
|
||||
log_error("Failed to activate: %s", strerror(-k));
|
||||
goto finish;
|
||||
}
|
||||
|
||||
log_warning("Invalid passphrase.");
|
||||
}
|
||||
|
||||
if (k < 0) {
|
||||
log_error("Failed to activate: %s", strerror(-k));
|
||||
goto finish;
|
||||
if (try >= opt_tries) {
|
||||
log_error("Too many attempts.");
|
||||
r = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
} else if (streq(argv[1], "detach")) {
|
||||
@@ -243,5 +334,11 @@ finish:
|
||||
if (cd)
|
||||
crypt_free(cd);
|
||||
|
||||
free(opt_cipher);
|
||||
free(opt_cipher_mode);
|
||||
free(opt_hash);
|
||||
|
||||
free(password);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user