From bc052ea17d858c19f9cb9c9e2bc602e754f68831 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: Wed, 7 Jan 2015 18:11:16 +0100 Subject: utils: add sss_authtok_[gs]et_2fa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Lukáš Slebodník --- src/util/authtok-utils.c | 74 +++++++++++++++++++ src/util/authtok-utils.h | 70 ++++++++++++++++++ src/util/authtok.c | 181 +++++++++++++++++++++++++++++++++++++++++++++++ src/util/authtok.h | 44 ++++++++++++ 4 files changed, 369 insertions(+) create mode 100644 src/util/authtok-utils.c create mode 100644 src/util/authtok-utils.h (limited to 'src/util') diff --git a/src/util/authtok-utils.c b/src/util/authtok-utils.c new file mode 100644 index 000000000..65fba9022 --- /dev/null +++ b/src/util/authtok-utils.c @@ -0,0 +1,74 @@ +/* + SSSD - auth utils helpers + + Copyright (C) Sumit Bose 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* This file is use by SSSD clients and the main daemons. Please do not add + * code which is specific to only one of them. */ + +#include + +#include "sss_client/sss_cli.h" + +errno_t sss_auth_pack_2fa_blob(const char *fa1, size_t fa1_len, + const char *fa2, size_t fa2_len, + uint8_t *buf, size_t buf_len, + size_t *_2fa_blob_len) +{ + size_t c; + uint32_t tmp_uint32_t; + + if (fa1 == NULL || *fa1 == '\0' || fa1_len > UINT32_MAX + || fa2 == NULL || *fa2 == '\0' || fa2_len > UINT32_MAX + || (buf == NULL && buf_len != 0)) { + return EINVAL; + } + + if (fa1_len == 0) { + fa1_len = strlen(fa1); + } else { + if (fa1[fa1_len] != '\0') { + return EINVAL; + } + } + + if (fa2_len == 0) { + fa2_len = strlen(fa2); + } else { + if (fa2[fa2_len] != '\0') { + return EINVAL; + } + } + + *_2fa_blob_len = fa1_len + fa2_len + 2 + 2 * sizeof(uint32_t); + if (buf == NULL || buf_len < *_2fa_blob_len) { + return EAGAIN; + } + + c = 0; + tmp_uint32_t = (uint32_t) fa1_len + 1; + SAFEALIGN_COPY_UINT32(buf, &tmp_uint32_t, &c); + tmp_uint32_t = (uint32_t) fa2_len + 1; + SAFEALIGN_COPY_UINT32(buf + c, &tmp_uint32_t, &c); + + memcpy(buf + c, fa1, fa1_len + 1); + c += fa1_len + 1; + + memcpy(buf + c, fa2, fa2_len + 1); + + return 0; +} diff --git a/src/util/authtok-utils.h b/src/util/authtok-utils.h new file mode 100644 index 000000000..07aef3c18 --- /dev/null +++ b/src/util/authtok-utils.h @@ -0,0 +1,70 @@ +/* + SSSD - auth utils helpers + + Copyright (C) Sumit Bose 2015 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __AUTHTOK_UTILS_H__ +#define __AUTHTOK_UTILS_H__ + +#include + +#include "sss_client/sss_cli.h" + +/** + * @brief Fill memory buffer with 2FA blob + * + * @param[in] fa1 First authentication factor, null terminated + * @param[in] fa1_len Length of the first authentication factor, if 0 + * strlen() will be called internally + * @param[in] fa2 Second authentication factor, null terminated + * @param[in] fa2_len Length of the second authentication factor, if 0 + * strlen() will be called internally + * @param[in] buf memory buffer of size buf_len + * @param[in] buf_len size of memory buffer buf + * + * @param[out] _2fa_blob_len size of the 2FA blob + * + * @return EOK on success + * EINVAL if input data is not consistent + * EAGAIN if provided buffer is too small, _2fa_blob_len + * contains the size needed to store the 2FA blob + */ +errno_t sss_auth_pack_2fa_blob(const char *fa1, size_t fa1_len, + const char *fa2, size_t fa2_len, + uint8_t *buf, size_t buf_len, + size_t *_2fa_blob_len); + +/** + * @brief Extract 2FA data from memory buffer + * + * @param[in] mem_ctx Talloc memory context to allocate the 2FA data on + * @param[in] blob Memory buffer containing the 2FA data + * @param[in] blob_len Size of the memory buffer + * @param[out] _fa1 First authentication factor, null terminated + * @param[out] _fa1_len Length of the first authentication factor + * @param[out] _fa2 Second authentication factor, null terminated + * @param[out] _fa2_len Length of the second authentication factor + * + * @return EOK on success + * EINVAL if input data is not consistent + * EINVAL if no memory can be allocated + */ +errno_t sss_auth_unpack_2fa_blob(TALLOC_CTX *mem_ctx, + const uint8_t *blob, size_t blob_len, + char **fa1, size_t *_fa1_len, + char **fa2, size_t *_fa2_len); +#endif /* __AUTHTOK_UTILS_H__ */ diff --git a/src/util/authtok.c b/src/util/authtok.c index b7bc17ed0..45761df80 100644 --- a/src/util/authtok.c +++ b/src/util/authtok.c @@ -38,6 +38,7 @@ size_t sss_authtok_get_size(struct sss_auth_token *tok) switch (tok->type) { case SSS_AUTHTOK_TYPE_PASSWORD: case SSS_AUTHTOK_TYPE_CCFILE: + case SSS_AUTHTOK_TYPE_2FA: return tok->length; case SSS_AUTHTOK_TYPE_EMPTY: return 0; @@ -70,6 +71,7 @@ errno_t sss_authtok_get_password(struct sss_auth_token *tok, } return EOK; case SSS_AUTHTOK_TYPE_CCFILE: + case SSS_AUTHTOK_TYPE_2FA: return EACCES; } @@ -92,6 +94,7 @@ errno_t sss_authtok_get_ccfile(struct sss_auth_token *tok, } return EOK; case SSS_AUTHTOK_TYPE_PASSWORD: + case SSS_AUTHTOK_TYPE_2FA: return EACCES; } @@ -140,6 +143,7 @@ void sss_authtok_set_empty(struct sss_auth_token *tok) case SSS_AUTHTOK_TYPE_EMPTY: return; case SSS_AUTHTOK_TYPE_PASSWORD: + case SSS_AUTHTOK_TYPE_2FA: safezero(tok->data, tok->length); break; case SSS_AUTHTOK_TYPE_CCFILE: @@ -169,6 +173,9 @@ errno_t sss_authtok_set_ccfile(struct sss_auth_token *tok, "ccfile", ccfile, len); } +static errno_t sss_authtok_set_2fa_from_blob(struct sss_auth_token *tok, + const uint8_t *data, size_t len); + errno_t sss_authtok_set(struct sss_auth_token *tok, enum sss_authtok_type type, const uint8_t *data, size_t len) @@ -178,6 +185,8 @@ errno_t sss_authtok_set(struct sss_auth_token *tok, return sss_authtok_set_password(tok, (const char *)data, len); case SSS_AUTHTOK_TYPE_CCFILE: return sss_authtok_set_ccfile(tok, (const char *)data, len); + case SSS_AUTHTOK_TYPE_2FA: + return sss_authtok_set_2fa_from_blob(tok, data, len); case SSS_AUTHTOK_TYPE_EMPTY: sss_authtok_set_empty(tok); return EOK; @@ -230,3 +239,175 @@ void sss_authtok_wipe_password(struct sss_auth_token *tok) safezero(tok->data, tok->length); } +errno_t sss_auth_unpack_2fa_blob(TALLOC_CTX *mem_ctx, + const uint8_t *blob, size_t blob_len, + char **fa1, size_t *_fa1_len, + char **fa2, size_t *_fa2_len) +{ + size_t c; + uint32_t fa1_len; + uint32_t fa2_len; + + if (blob_len < 2 * sizeof(uint32_t)) { + DEBUG(SSSDBG_CRIT_FAILURE, "Blob too small.\n"); + return EINVAL; + } + + c = 0; + SAFEALIGN_COPY_UINT32(&fa1_len, blob, &c); + SAFEALIGN_COPY_UINT32(&fa2_len, blob + c, &c); + + if (blob_len != 2 * sizeof(uint32_t) + fa1_len + fa2_len) { + DEBUG(SSSDBG_CRIT_FAILURE, "Blob size mismatch.\n"); + return EINVAL; + } + + if (fa1_len != 0) { + *fa1 = talloc_strndup(mem_ctx, (const char *) blob + c, fa1_len); + if (*fa1 == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); + return ENOMEM; + } + } else { + *fa1 = NULL; + } + + if (fa2_len != 0) { + *fa2 = talloc_strndup(mem_ctx, (const char *) blob + c + fa1_len, + fa2_len); + if (*fa2 == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n"); + talloc_free(*fa1); + return ENOMEM; + } + } else { + *fa2 = NULL; + } + + /* Re-calculate length for the case where \0 was missing in the blob */ + *_fa1_len = (*fa1 == NULL) ? 0 : strlen(*fa1); + *_fa2_len = (*fa2 == NULL) ? 0 : strlen(*fa2); + + return EOK; +} + +static errno_t sss_authtok_set_2fa_from_blob(struct sss_auth_token *tok, + const uint8_t *data, size_t len) +{ + TALLOC_CTX *tmp_ctx; + int ret; + char *fa1; + size_t fa1_len; + char *fa2; + size_t fa2_len; + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n"); + ret = ENOMEM; + goto done; + } + + ret = sss_auth_unpack_2fa_blob(tmp_ctx, data, len, &fa1, &fa1_len, + &fa2, &fa2_len); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_auth_unpack_2fa_blob failed.\n"); + goto done; + } + + ret = sss_authtok_set_2fa(tok, fa1, fa1_len, fa2, fa2_len); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_set_2fa failed.\n"); + goto done; + } + + ret = EOK; +done: + talloc_free(tmp_ctx); + + if (ret != EOK) { + sss_authtok_set_empty(tok); + } + + return ret; +} + +errno_t sss_authtok_get_2fa(struct sss_auth_token *tok, + const char **fa1, size_t *fa1_len, + const char **fa2, size_t *fa2_len) +{ + size_t c; + uint32_t tmp_uint32_t; + + if (tok->type != SSS_AUTHTOK_TYPE_2FA) { + return (tok->type == SSS_AUTHTOK_TYPE_EMPTY) ? ENOENT : EACCES; + } + + if (tok->length < 2 * sizeof(uint32_t)) { + DEBUG(SSSDBG_CRIT_FAILURE, "Blob too small.\n"); + return EINVAL; + } + + c = 0; + SAFEALIGN_COPY_UINT32(&tmp_uint32_t, tok->data, &c); + *fa1_len = tmp_uint32_t - 1; + SAFEALIGN_COPY_UINT32(&tmp_uint32_t, tok->data + c, &c); + *fa2_len = tmp_uint32_t - 1; + + if (*fa1_len == 0 || *fa2_len == 0 + || tok->length != 2 * sizeof(uint32_t) + *fa1_len + *fa2_len + 2) { + DEBUG(SSSDBG_CRIT_FAILURE, "Blob size mismatch.\n"); + return EINVAL; + } + + if (tok->data[c + *fa1_len] != '\0' + || tok->data[c + *fa1_len + 1 + *fa2_len] != '\0') { + DEBUG(SSSDBG_CRIT_FAILURE, "Missing terminating null character.\n"); + return EINVAL; + } + + *fa1 = (const char *) tok->data + c; + *fa2 = (const char *) tok->data + c + *fa1_len + 1; + + return EOK; +} + +errno_t sss_authtok_set_2fa(struct sss_auth_token *tok, + const char *fa1, size_t fa1_len, + const char *fa2, size_t fa2_len) +{ + int ret; + size_t needed_size; + + if (tok == NULL) { + return EINVAL; + } + + sss_authtok_set_empty(tok); + + ret = sss_auth_pack_2fa_blob(fa1, fa1_len, fa2, fa2_len, NULL, 0, + &needed_size); + if (ret != EAGAIN) { + DEBUG(SSSDBG_CRIT_FAILURE, + "sss_auth_pack_2fa_blob unexpectedly returned [%d].\n", ret); + return EINVAL; + } + + tok->data = talloc_size(tok, needed_size); + if (tok->data == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n"); + return ENOMEM; + } + + ret = sss_auth_pack_2fa_blob(fa1, fa1_len, fa2, fa2_len, tok->data, + needed_size, &needed_size); + if (ret != EOK) { + talloc_free(tok->data); + DEBUG(SSSDBG_OP_FAILURE, "sss_auth_pack_2fa_blob failed.\n"); + return ret; + } + tok->length = needed_size; + tok->type = SSS_AUTHTOK_TYPE_2FA; + + return EOK; +} diff --git a/src/util/authtok.h b/src/util/authtok.h index 1f6def4c3..cb3662708 100644 --- a/src/util/authtok.h +++ b/src/util/authtok.h @@ -21,6 +21,7 @@ #define __AUTHTOK_H__ #include "util/util.h" +#include "util/authtok-utils.h" #include "sss_client/sss_cli.h" /* Use sss_authtok_* accesor functions instead of struct sss_auth_token @@ -179,4 +180,47 @@ void sss_authtok_wipe_password(struct sss_auth_token *tok); */ struct sss_auth_token *sss_authtok_new(TALLOC_CTX *mem_ctx); +/** + * @brief Set authtoken with 2FA data + * + * @param tok A pointer to a sss_auth_token structure to change, also + * used as a memory context to allocate the internal data. + * @param[in] fa1 First authentication factor, null terminated + * @param[in] fa1_len Length of the first authentication factor, if 0 + * strlen() will be called internally + * @param[in] fa2 Second authentication factor, null terminated + * @param[in] fa2_len Length of the second authentication factor, if 0 + * strlen() will be called internally + * + * @return EOK on success + * ENOMEM if memory allocation failed + * EINVAL if input data is not consistent + */ +errno_t sss_authtok_set_2fa(struct sss_auth_token *tok, + const char *fa1, size_t fa1_len, + const char *fa2, size_t fa2_len); + +/** + * @brief Get 2FA factors from authtoken + * + * @param tok A pointer to a sss_auth_token structure to change, also + * used as a memory context to allocate the internal data. + * @param[out] fa1 A pointer to a const char *, that will point to a + * null terminated string holding the first + * authentication factor, may not be modified or freed + * @param[out] fa1_len Length of the first authentication factor + * @param[out] fa2 A pointer to a const char *, that will point to a + * null terminated string holding the second + * authentication factor, may not be modified or freed + * @param[out] fa2_len Length of the second authentication factor + * + * @return EOK on success + * ENOMEM if memory allocation failed + * EINVAL if input data is not consistent + * ENOENT if the token is empty + * EACCESS if the token is not a 2FA token + */ +errno_t sss_authtok_get_2fa(struct sss_auth_token *tok, + const char **fa1, size_t *fa1_len, + const char **fa2, size_t *fa2_len); #endif /* __AUTHTOK_H__ */ -- cgit