diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index fcd949c2..d2e12cd3 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -2214,7 +2214,6 @@ typedef struct { 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_dump_func dump; /**< token handler dump function (optional) */ - crypt_token_open_pin_func open_pin; /**< open with passphrase function (optional) */ } crypt_token_handler; /** @@ -2227,9 +2226,14 @@ typedef struct { int crypt_token_register(const crypt_token_handler *handler); /** ABI version for external token in libcryptsetup-token-.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 */ -#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. diff --git a/lib/luks2/luks2_internal.h b/lib/luks2/luks2_internal.h index efb53e83..6a84a475 100644 --- a/lib/luks2/luks2_internal.h +++ b/lib/luks2/luks2_internal.h @@ -164,12 +164,44 @@ typedef struct { digest_dump_func dump; } digest_handler; -typedef struct { - /* public token handler */ - const crypt_token_handler *h; - /* dynamic loadable plugin dlopen handle */ - const void *dlhandle; -} token_handler; +int keyring_open(struct crypt_device *cd, + int token, + char **buffer, + size_t *buffer_len, + void *usrptr); + +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, size_t keylength, uint64_t *area_offset, uint64_t *area_length); diff --git a/lib/luks2/luks2_token.c b/lib/luks2/luks2_token.c index f4fda91b..191444f2 100644 --- a/lib/luks2/luks2_token.c +++ b/lib/luks2/luks2_token.c @@ -25,29 +25,72 @@ #include "luks2_internal.h" -/* Builtin tokens */ -extern const crypt_token_handler keyring_handler; - -static token_handler token_handlers[LUKS2_TOKENS_MAX] = { +static struct crypt_token_handler_internal token_handlers[LUKS2_TOKENS_MAX] = { /* 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 -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 - const crypt_token_handler *token = NULL; - void *handle; - char *error; + struct crypt_token_handler_v2 *token; + void *h; char buf[512]; int i, r; if (!ret || !name || strlen(name) > 64) return -EINVAL; + token = &ret->u.v2; + for (i = 0; name[i]; i++) if (!isalnum(name[i])) 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); - handle = dlopen(buf, RTLD_LAZY); - if (!handle) { + h = dlopen(buf, RTLD_LAZY); + if (!h) { log_dbg(NULL, "%s", dlerror()); return -EINVAL; } dlerror(); - token = dlvsym(handle, CRYPT_TOKEN_ABI_HANDLER, CRYPT_TOKEN_ABI_VERSION1); - error = dlerror(); - if (error) { - log_dbg(cd, "%s", error); - dlclose(handle); - return -EINVAL; + token->name = strdup(name); + token->open = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_OPEN, CRYPT_TOKEN_ABI_VERSION1); + token->buffer_free = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_BUFFER_FREE, CRYPT_TOKEN_ABI_VERSION1); + token->validate = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_VALIDATE, CRYPT_TOKEN_ABI_VERSION1); + token->dump = token_dlvsym(cd, h, CRYPT_TOKEN_ABI_DUMP, CRYPT_TOKEN_ABI_VERSION1); + 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; - ret->dlhandle = handle; + token->dlhandle = h; + ret->version = 2; return 0; +err: + free(CONST_CAST(void *)token->name); + dlclose(h); + memset(token, 0, sizeof(*token)); + + return r; #else return -ENOTSUP; #endif @@ -96,8 +149,8 @@ static int crypt_token_find_free(struct crypt_device *cd, const char *name, int return -EINVAL; } - for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].h; i++) { - if (!strcmp(token_handlers[i].h->name, name)) { + for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].u.v1.name; i++) { + if (!strcmp(token_handlers[i].u.v1.name, name)) { log_dbg(cd, "Keyslot handler %s is already registered.", name); return -EINVAL; } @@ -116,14 +169,15 @@ int crypt_token_register(const crypt_token_handler *handler) { int i, r; - if (!handler->name || !handler->open) + if (!token_validate_v1(NULL, handler)) return -EINVAL; r = crypt_token_find_free(NULL, handler->name, &i); if (r < 0) return r; - token_handlers[i].h = handler; + token_handlers[i].version = 1; + token_handlers[i].u.v1 = *handler; return 0; } @@ -132,24 +186,26 @@ void crypt_token_unload_external_all(struct crypt_device *cd) int i; for (i = LUKS2_TOKENS_MAX - 1; i >= 0; i--) { - if (!token_handlers[i].dlhandle) + if (token_handlers[i].version < 2) 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()); } } -static const crypt_token_handler +static const void *LUKS2_token_handler_type(struct crypt_device *cd, const char *type) { int i; - for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].h; i++) - if (!strcmp(token_handlers[i].h->name, type)) - return token_handlers[i].h; + for (i = 0; i < LUKS2_TOKENS_MAX && token_handlers[i].u.v1.name; i++) + if (!strcmp(token_handlers[i].u.v1.name, type)) + return &token_handlers[i].u; if (i >= LUKS2_TOKENS_MAX) return NULL; @@ -160,10 +216,10 @@ static const crypt_token_handler if (crypt_token_load_external(cd, type, &token_handlers[i])) 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) { struct luks2_hdr *hdr; @@ -305,7 +361,7 @@ static int LUKS2_token_open(struct crypt_device *cd, void *usrptr) { const char *json; - const crypt_token_handler *h; + const struct crypt_token_handler_v2 *h; int r; if (!(h = LUKS2_token_handler(cd, token))) diff --git a/lib/luks2/luks2_token_keyring.c b/lib/luks2/luks2_token_keyring.c index 392523b4..d5604b7b 100644 --- a/lib/luks2/luks2_token_keyring.c +++ b/lib/luks2/luks2_token_keyring.c @@ -23,7 +23,7 @@ #include "luks2_internal.h" -static int keyring_open(struct crypt_device *cd, +int keyring_open(struct crypt_device *cd, int token, char **buffer, size_t *buffer_len, @@ -54,7 +54,7 @@ static int keyring_open(struct crypt_device *cd, return 0; } -static int keyring_validate(struct crypt_device *cd __attribute__((unused)), +int keyring_validate(struct crypt_device *cd __attribute__((unused)), const char *json) { enum json_tokener_error jerr; @@ -92,7 +92,7 @@ out: 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; 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; } - -const crypt_token_handler keyring_handler = { - .name = LUKS2_TOKEN_KEYRING, - .open = keyring_open, - .validate = keyring_validate, - .dump = keyring_dump -};