cryptsetup: support non-LUKS crypto partitions

This commit is contained in:
Lennart Poettering
2010-11-14 19:59:10 +01:00
parent 612eb8e459
commit 260ab28795
4 changed files with 163 additions and 55 deletions
+10
View File
@@ -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);
}
+2
View File
@@ -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
+1 -2
View File
@@ -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
View File
@@ -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,
&params);
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;
}