Make crypt_activate_by_pin_token addition backward compatible.

The crypt_activate_by_pin_token may be used only from new
dynamicly loadable token plugins.

Also refactors code for dynamically loadable plugins so
that it does not use crypt_token_handler structure anymore.

Old structure remains used only in crypt_token_register call.
This commit is contained in:
Ondrej Kozina
2021-01-21 17:23:15 +01:00
parent 81c44b5eee
commit 10e4d8fbac
4 changed files with 137 additions and 52 deletions

View File

@@ -2214,7 +2214,6 @@ typedef struct {
crypt_token_buffer_free_func buffer_free; /**< token handler buffer_free function (optional) */ crypt_token_buffer_free_func buffer_free; /**< token handler buffer_free function (optional) */
crypt_token_validate_func validate; /**< token handler validate function (optional) */ crypt_token_validate_func validate; /**< token handler validate function (optional) */
crypt_token_dump_func dump; /**< token handler dump function (optional) */ crypt_token_dump_func dump; /**< token handler dump function (optional) */
crypt_token_open_pin_func open_pin; /**< open with passphrase function (optional) */
} crypt_token_handler; } crypt_token_handler;
/** /**
@@ -2227,9 +2226,14 @@ typedef struct {
int crypt_token_register(const crypt_token_handler *handler); int crypt_token_register(const crypt_token_handler *handler);
/** ABI version for external token in libcryptsetup-token-<name>.so */ /** ABI version for external token in libcryptsetup-token-<name>.so */
#define CRYPT_TOKEN_ABI_VERSION1 "CRYPTSETUP_TOKEN_1.0" #define CRYPT_TOKEN_ABI_VERSION1 "CRYPTSETUP_TOKEN_1.0"
/** ABI exported symbol for external token */ /** ABI exported symbol for external token */
#define CRYPT_TOKEN_ABI_HANDLER "cryptsetup_token_handler" #define CRYPT_TOKEN_ABI_OPEN "cryptsetup_token_open" /* mandatory */
#define CRYPT_TOKEN_ABI_OPEN_PIN "cryptsetup_token_open_pin"
#define CRYPT_TOKEN_ABI_BUFFER_FREE "cryptsetup_token_buffer_free"
#define CRYPT_TOKEN_ABI_VALIDATE "cryptsetup_token_validate"
#define CRYPT_TOKEN_ABI_DUMP "cryptsetup_token_dump"
/** /**
* Activate device or check key using a token. * Activate device or check key using a token.

View File

@@ -164,12 +164,44 @@ typedef struct {
digest_dump_func dump; digest_dump_func dump;
} digest_handler; } digest_handler;
typedef struct { int keyring_open(struct crypt_device *cd,
/* public token handler */ int token,
const crypt_token_handler *h; char **buffer,
/* dynamic loadable plugin dlopen handle */ size_t *buffer_len,
const void *dlhandle; void *usrptr);
} token_handler;
void keyring_dump(struct crypt_device *cd, const char *json);
int keyring_validate(struct crypt_device *cd, const char *json);
struct crypt_token_handler_v2 {
const char *name;
crypt_token_open_func open;
crypt_token_buffer_free_func buffer_free;
crypt_token_validate_func validate;
crypt_token_dump_func dump;
/* here ends v1. Do not touch anything above */
crypt_token_open_pin_func open_pin;
void *dlhandle;
};
/*
* Initial sequence of structure members in union 'u' must be always
* identical. Version 4 must fully contain version 3 which must
* subsequently fully contain version 2, etc.
*
* See C standard, section 6.5.2.3, item 5.
*/
struct crypt_token_handler_internal {
uint32_t version;
union {
crypt_token_handler v1; /* deprecated public structure */
struct crypt_token_handler_v2 v2; /* internal helper v2 structure */
} u;
};
int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr, int LUKS2_find_area_gap(struct crypt_device *cd, struct luks2_hdr *hdr,
size_t keylength, uint64_t *area_offset, uint64_t *area_length); size_t keylength, uint64_t *area_offset, uint64_t *area_length);

View File

@@ -25,29 +25,72 @@
#include "luks2_internal.h" #include "luks2_internal.h"
/* Builtin tokens */ static struct crypt_token_handler_internal token_handlers[LUKS2_TOKENS_MAX] = {
extern const crypt_token_handler keyring_handler;
static token_handler token_handlers[LUKS2_TOKENS_MAX] = {
/* keyring builtin token */ /* keyring builtin token */
{ {
.h = &keyring_handler .version = 1,
.u = {
.v1 = { .name = LUKS2_TOKEN_KEYRING,
.open = keyring_open,
.validate = keyring_validate,
.dump = keyring_dump }
}
} }
}; };
#if USE_EXTERNAL_TOKENS
static void *token_dlvsym(struct crypt_device *cd,
void *handle,
const char *symbol,
const char *version)
{
char *error;
void *sym;
log_dbg(cd, "Loading symbol %s@%s.", symbol, version);
sym = dlvsym(handle, symbol, version);
error = dlerror();
if (error)
log_dbg(cd, "Error: %s.", error);
return sym;
}
#endif
static bool token_validate_v1(struct crypt_device *cd, const crypt_token_handler *h)
{
if (!h)
return false;
if (!h->name) {
log_dbg(cd, "Token handler does not provide name attribute.");
return false;
}
if (!h->open) {
log_dbg(cd, "Token handler does not provide open function.");
return false;
}
return true;
}
static int static int
crypt_token_load_external(struct crypt_device *cd, const char *name, token_handler *ret) crypt_token_load_external(struct crypt_device *cd, const char *name, struct crypt_token_handler_internal *ret)
{ {
#if USE_EXTERNAL_TOKENS #if USE_EXTERNAL_TOKENS
const crypt_token_handler *token = NULL; struct crypt_token_handler_v2 *token;
void *handle; void *h;
char *error;
char buf[512]; char buf[512];
int i, r; int i, r;
if (!ret || !name || strlen(name) > 64) if (!ret || !name || strlen(name) > 64)
return -EINVAL; return -EINVAL;
token = &ret->u.v2;
for (i = 0; name[i]; i++) for (i = 0; name[i]; i++)
if (!isalnum(name[i])) if (!isalnum(name[i]))
return -EINVAL; return -EINVAL;
@@ -58,25 +101,35 @@ crypt_token_load_external(struct crypt_device *cd, const char *name, token_handl
log_dbg(cd, "Trying to load %s.", buf); log_dbg(cd, "Trying to load %s.", buf);
handle = dlopen(buf, RTLD_LAZY); h = dlopen(buf, RTLD_LAZY);
if (!handle) { if (!h) {
log_dbg(NULL, "%s", dlerror()); log_dbg(NULL, "%s", dlerror());
return -EINVAL; return -EINVAL;
} }
dlerror(); dlerror();
token = dlvsym(handle, CRYPT_TOKEN_ABI_HANDLER, CRYPT_TOKEN_ABI_VERSION1); token->name = strdup(name);
error = dlerror(); token->open = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_OPEN, CRYPT_TOKEN_ABI_VERSION1);
if (error) { token->buffer_free = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_BUFFER_FREE, CRYPT_TOKEN_ABI_VERSION1);
log_dbg(cd, "%s", error); token->validate = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_VALIDATE, CRYPT_TOKEN_ABI_VERSION1);
dlclose(handle); token->dump = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_DUMP, CRYPT_TOKEN_ABI_VERSION1);
return -EINVAL; token->open_pin = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_OPEN_PIN, CRYPT_TOKEN_ABI_VERSION1);
if (!token_validate_v1(cd, &ret->u.v1)) {
r = -EINVAL;
goto err;
} }
ret->h = token; token->dlhandle = h;
ret->dlhandle = handle; ret->version = 2;
return 0; return 0;
err:
free(CONST_CAST(void *)token->name);
dlclose(h);
memset(token, 0, sizeof(*token));
return r;
#else #else
return -ENOTSUP; return -ENOTSUP;
#endif #endif
@@ -96,8 +149,8 @@ static int crypt_token_find_free(struct crypt_device *cd, const char *name, int
return -EINVAL; return -EINVAL;
} }
for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].h; i++) { for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].u.v1.name; i++) {
if (!strcmp(token_handlers[i].h->name, name)) { if (!strcmp(token_handlers[i].u.v1.name, name)) {
log_dbg(cd, "Keyslot handler %s is already registered.", name); log_dbg(cd, "Keyslot handler %s is already registered.", name);
return -EINVAL; return -EINVAL;
} }
@@ -116,14 +169,15 @@ int crypt_token_register(const crypt_token_handler *handler)
{ {
int i, r; int i, r;
if (!handler->name || !handler->open) if (!token_validate_v1(NULL, handler))
return -EINVAL; return -EINVAL;
r = crypt_token_find_free(NULL, handler->name, &i); r = crypt_token_find_free(NULL, handler->name, &i);
if (r < 0) if (r < 0)
return r; return r;
token_handlers[i].h = handler; token_handlers[i].version = 1;
token_handlers[i].u.v1 = *handler;
return 0; return 0;
} }
@@ -132,24 +186,26 @@ void crypt_token_unload_external_all(struct crypt_device *cd)
int i; int i;
for (i = LUKS2_TOKENS_MAX - 1; i >= 0; i--) { for (i = LUKS2_TOKENS_MAX - 1; i >= 0; i--) {
if (!token_handlers[i].dlhandle) if (token_handlers[i].version < 2)
continue; continue;
log_dbg(cd, "Unloading %s token handler.", token_handlers[i].h->name); log_dbg(cd, "Unloading %s token handler.", token_handlers[i].u.v2.name);
if (dlclose(CONST_CAST(void *)token_handlers[i].dlhandle)) free(CONST_CAST(void *)token_handlers[i].u.v2.name);
if (dlclose(CONST_CAST(void *)token_handlers[i].u.v2.dlhandle))
log_dbg(cd, "%s", dlerror()); log_dbg(cd, "%s", dlerror());
} }
} }
static const crypt_token_handler static const void
*LUKS2_token_handler_type(struct crypt_device *cd, const char *type) *LUKS2_token_handler_type(struct crypt_device *cd, const char *type)
{ {
int i; int i;
for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].h; i++) for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].u.v1.name; i++)
if (!strcmp(token_handlers[i].h->name, type)) if (!strcmp(token_handlers[i].u.v1.name, type))
return token_handlers[i].h; return &token_handlers[i].u;
if (i >= LUKS2_TOKENS_MAX) if (i >= LUKS2_TOKENS_MAX)
return NULL; return NULL;
@@ -160,10 +216,10 @@ static const crypt_token_handler
if (crypt_token_load_external(cd, type, &token_handlers[i])) if (crypt_token_load_external(cd, type, &token_handlers[i]))
return NULL; return NULL;
return token_handlers[i].h; return &token_handlers[i].u;
} }
static const crypt_token_handler static const void
*LUKS2_token_handler(struct crypt_device *cd, int token) *LUKS2_token_handler(struct crypt_device *cd, int token)
{ {
struct luks2_hdr *hdr; struct luks2_hdr *hdr;
@@ -305,7 +361,7 @@ static int LUKS2_token_open(struct crypt_device *cd,
void *usrptr) void *usrptr)
{ {
const char *json; const char *json;
const crypt_token_handler *h; const struct crypt_token_handler_v2 *h;
int r; int r;
if (!(h = LUKS2_token_handler(cd, token))) if (!(h = LUKS2_token_handler(cd, token)))

View File

@@ -23,7 +23,7 @@
#include "luks2_internal.h" #include "luks2_internal.h"
static int keyring_open(struct crypt_device *cd, int keyring_open(struct crypt_device *cd,
int token, int token,
char **buffer, char **buffer,
size_t *buffer_len, size_t *buffer_len,
@@ -54,7 +54,7 @@ static int keyring_open(struct crypt_device *cd,
return 0; return 0;
} }
static int keyring_validate(struct crypt_device *cd __attribute__((unused)), int keyring_validate(struct crypt_device *cd __attribute__((unused)),
const char *json) const char *json)
{ {
enum json_tokener_error jerr; enum json_tokener_error jerr;
@@ -92,7 +92,7 @@ out:
return r; return r;
} }
static void keyring_dump(struct crypt_device *cd, const char *json) void keyring_dump(struct crypt_device *cd, const char *json)
{ {
enum json_tokener_error jerr; enum json_tokener_error jerr;
json_object *jobj_token, *jobj_key; json_object *jobj_token, *jobj_key;
@@ -135,10 +135,3 @@ int LUKS2_token_keyring_get(struct crypt_device *cd, struct luks2_hdr *hdr, int
return token; return token;
} }
const crypt_token_handler keyring_handler = {
.name = LUKS2_TOKEN_KEYRING,
.open = keyring_open,
.validate = keyring_validate,
.dump = keyring_dump
};