Preliminary file migration

Pretty raw and untested code which migrates data from v2 to v3,
introducing a new field in the process. This field is neither editable
as of now nor is it honored if it were set.
This commit is contained in:
Johannes Bauer 2021-06-27 00:28:00 +02:00
parent b0909557ad
commit af29d9cbf8
4 changed files with 110 additions and 19 deletions

View File

@ -6,7 +6,7 @@ INSTALL_PREFIX := /usr/local/
CFLAGS := -Wall -Wextra -Wshadow -Wswitch -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Werror=implicit-function-declaration -Werror=format -Wno-unused-parameter CFLAGS := -Wall -Wextra -Wshadow -Wswitch -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Werror=implicit-function-declaration -Werror=format -Wno-unused-parameter
CFLAGS += -O3 -std=c11 -pthread -D_POSIX_SOURCE -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500 -DBUILD_REVISION='"$(BUILD_REVISION)"' CFLAGS += -O3 -std=c11 -pthread -D_POSIX_SOURCE -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500 -DBUILD_REVISION='"$(BUILD_REVISION)"'
CFLAGS += `pkg-config --cflags openssl` CFLAGS += `pkg-config --cflags openssl`
#CFLAGS += -ggdb3 -DDEBUG -fsanitize=address -fsanitize=undefined -fsanitize=leak CFLAGS += -ggdb3 -DDEBUG -fsanitize=address -fsanitize=undefined -fsanitize=leak
PYPGMOPTS := ../Python/pypgmopts/pypgmopts PYPGMOPTS := ../Python/pypgmopts/pypgmopts
LDFLAGS := `pkg-config --libs openssl` LDFLAGS := `pkg-config --libs openssl`

View File

@ -471,7 +471,7 @@ static enum cmd_returncode_t cmd_rawdump(struct editor_context_t *ctx, const cha
if (!ctx->keydb) { if (!ctx->keydb) {
return COMMAND_SUCCESS; return COMMAND_SUCCESS;
} }
fprintf(stderr, "Version %d, %s, %d hosts.\n", ctx->keydb->keydb_version, ctx->keydb->server_database ? "server" : "client", ctx->keydb->host_count); fprintf(stderr, "Version %d, %s, %d hosts.\n", ctx->keydb->common.keydb_version, ctx->keydb->server_database ? "server" : "client", ctx->keydb->host_count);
for (unsigned int i = 0; i < ctx->keydb->host_count; i++) { for (unsigned int i = 0; i < ctx->keydb->host_count; i++) {
host_entry_t *host = &ctx->keydb->hosts[i]; host_entry_t *host = &ctx->keydb->hosts[i];
fprintf(stderr, "Host %d:\n", i); fprintf(stderr, "Host %d:\n", i);

95
keydb.c
View File

@ -33,12 +33,28 @@
#include "uuid.h" #include "uuid.h"
#include "log.h" #include "log.h"
static unsigned int keydb_getsize_v3_hostcount(unsigned int host_count) {
return sizeof(struct keydb_v3_t) + (host_count * sizeof(struct host_entry_v3_t));
}
static unsigned int keydb_getsize_v3(const struct keydb_v3_t *keydb) {
return keydb_getsize_v3_hostcount(keydb->host_count);
}
static unsigned int keydb_getsize_v2_hostcount(unsigned int host_count) {
return sizeof(struct keydb_v2_t) + (host_count * sizeof(struct host_entry_v2_t));
}
static unsigned int keydb_getsize_v2(const struct keydb_v2_t *keydb) {
return keydb_getsize_v2_hostcount(keydb->host_count);
}
static unsigned int keydb_getsize_hostcount(unsigned int host_count) { static unsigned int keydb_getsize_hostcount(unsigned int host_count) {
return sizeof(keydb_t) + (host_count * sizeof(host_entry_t)); return keydb_getsize_v3_hostcount(host_count);
} }
static unsigned int keydb_getsize(const keydb_t *keydb) { static unsigned int keydb_getsize(const keydb_t *keydb) {
return keydb_getsize_hostcount(keydb->host_count); return keydb_getsize_v3(keydb);
} }
keydb_t* keydb_new(void) { keydb_t* keydb_new(void) {
@ -266,26 +282,79 @@ static bool passphrase_callback(char *buffer, unsigned int bufsize) {
return query_passphrase("Database passphrase: ", buffer, bufsize); return query_passphrase("Database passphrase: ", buffer, bufsize);
} }
static bool keydb_migrate_v2_to_v3(void **keydb_data, unsigned int *keydb_data_size) {
log_msg(LLVL_INFO, "Migrating keydb version 2 to version 3");
struct keydb_v2_t *old_db = *((struct keydb_v2_t **)keydb_data);
unsigned int new_db_size = keydb_getsize_v3_hostcount(old_db->host_count);
struct keydb_v3_t *new_db = calloc(1, new_db_size);
if (!new_db) {
log_msg(LLVL_ERROR, "keydb migration failed to allocate %d bytes of memory", new_db_size);
return false;
}
*new_db = (struct keydb_v3_t) {
.common.keydb_version = 3,
.server_database = old_db->server_database,
.host_count = old_db->host_count,
};
for (unsigned int i = 0; i < new_db->host_count; i++) {
memcpy(&new_db->hosts[i], &old_db->hosts[i], sizeof(old_db->hosts[i]) - sizeof(old_db->hosts[i].volumes));
for (unsigned int j = 0; j < new_db->hosts[i].volume_count; j++) {
memcpy(&new_db->hosts[i].volumes[j], &old_db->hosts[i].volumes[j], sizeof(old_db->hosts[i].volumes[j]));
}
}
OPENSSL_cleanse(old_db, *keydb_data_size);
free(old_db);
*keydb_data = new_db;
*keydb_data_size = new_db_size;
return true;
}
static keydb_t* keydb_migrate(void **keydb_data, unsigned int *keydb_data_size) {
struct keydb_common_header_t *header;
header = *((struct keydb_common_header_t**)keydb_data);
if (header->keydb_version == 2) {
if (*keydb_data_size != keydb_getsize_v2(*keydb_data)) {
log_msg(LLVL_ERROR, "keydb version 2 has wrong size (%u bytes, but expected %u bytes).", *keydb_data_size, keydb_getsize_v2(*keydb_data));
return NULL;
}
if (!keydb_migrate_v2_to_v3(keydb_data, keydb_data_size)) {
log_msg(LLVL_ERROR, "keydb version 2 to 3 migration failed.");
return NULL;
}
}
header = *((struct keydb_common_header_t**)keydb_data);
if (header->keydb_version == 3) {
if (*keydb_data_size != keydb_getsize_v3(*keydb_data)) {
log_msg(LLVL_ERROR, "keydb version 3 has wrong size (%u bytes, but expected %u bytes).", *keydb_data_size, keydb_getsize_v2(*keydb_data));
return NULL;
}
}
header = *((struct keydb_common_header_t**)keydb_data);
if (header->keydb_version != KEYDB_CURRENT_VERSION) {
log_msg(LLVL_ERROR, "keydb could be read, but is of version %u (we expected %u).", header->keydb_version, KEYDB_CURRENT_VERSION);
return NULL;
}
return *((keydb_t**)keydb_data);
}
keydb_t* keydb_read(const char *filename) { keydb_t* keydb_read(const char *filename) {
struct decrypted_file_t decrypted_file = read_encrypted_file(filename, passphrase_callback); struct decrypted_file_t decrypted_file = read_encrypted_file(filename, passphrase_callback);
if (!decrypted_file.success) { if (!decrypted_file.success) {
return NULL; return NULL;
} }
keydb_t *keydb = (keydb_t*)decrypted_file.data; keydb_t *keydb = keydb_migrate(&decrypted_file.data, &decrypted_file.data_length);
if (keydb->common.keydb_version != KEYDB_CURRENT_VERSION) { if (!keydb) {
log_msg(LLVL_ERROR, "keydb in %s could be read, but is of version %u (we expected %u).", filename, keydb->common.keydb_version, KEYDB_CURRENT_VERSION);
OPENSSL_cleanse(decrypted_file.data, decrypted_file.data_length); OPENSSL_cleanse(decrypted_file.data, decrypted_file.data_length);
free(decrypted_file.data); free(decrypted_file.data);
return NULL; return NULL;
} }
if (decrypted_file.data_length != keydb_getsize(keydb)) {
log_msg(LLVL_ERROR, "keydb in %s could be read, but was %u bytes long (we expected %u).", filename, decrypted_file.data_length, keydb_getsize(keydb));
OPENSSL_cleanse(decrypted_file.data, decrypted_file.data_length);
free(decrypted_file.data);
return NULL;
}
return keydb; return keydb;
} }

30
keydb.h
View File

@ -30,7 +30,6 @@
#include "file_encryption.h" #include "file_encryption.h"
#include "global.h" #include "global.h"
#define KEYDB_CURRENT_VERSION 2
enum volume_flag_t { enum volume_flag_t {
VOLUME_FLAG_ALLOW_DISCARD = (1 << 0), VOLUME_FLAG_ALLOW_DISCARD = (1 << 0),
@ -61,10 +60,33 @@ struct keydb_v2_t {
struct host_entry_v2_t hosts[]; struct host_entry_v2_t hosts[];
}; };
struct volume_entry_v3_t {
uint8_t volume_uuid[16]; /* UUID of crypt_LUKS volume */
char devmapper_name[MAX_DEVMAPPER_NAME_LENGTH]; /* dmsetup name when unlocked. Zero-terminated string. */
uint8_t luks_passphrase_raw[LUKS_PASSPHRASE_RAW_SIZE_BYTES]; /* LUKS passphrase used to unlock volume; raw byte data */
unsigned int volume_flags; /* Bitset of enum volume_flag_t */
};
typedef struct volume_entry_v2_t volume_entry_t; struct host_entry_v3_t {
typedef struct host_entry_v2_t host_entry_t; uint8_t host_uuid[16]; /* Host UUID */
typedef struct keydb_v2_t keydb_t; char host_name[MAX_HOST_NAME_LENGTH]; /* Descriptive name of host */
uint8_t tls_psk[PSK_SIZE_BYTES]; /* Raw byte data of TLS-PSK that is used */
unsigned int volume_count; /* Number of volumes of this host */
struct volume_entry_v3_t volumes[MAX_VOLUMES_PER_HOST]; /* Volumes of this host */
};
struct keydb_v3_t {
struct keydb_common_header_t common;
bool server_database;
unsigned int host_count;
struct host_entry_v3_t hosts[];
};
#define KEYDB_CURRENT_VERSION 3
typedef struct volume_entry_v3_t volume_entry_t;
typedef struct host_entry_v3_t host_entry_t;
typedef struct keydb_v3_t keydb_t;
/*************** AUTO GENERATED SECTION FOLLOWS ***************/ /*************** AUTO GENERATED SECTION FOLLOWS ***************/