/*
SSSD
authtok - Utilities tests
Authors:
Pallavi Jha <pallavikumarijha@gmail.com>
Copyright (C) 2013 Red Hat
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 <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <popt.h>
#include "tests/cmocka/common_mock.h"
#include "util/authtok.h"
struct test_state {
struct sss_auth_token *authtoken;
};
static int setup(void **state)
{
struct test_state *ts = NULL;
assert_true(leak_check_setup());
ts = talloc(global_talloc_context, struct test_state);
assert_non_null(ts);
ts->authtoken = sss_authtok_new(ts);
assert_non_null(ts->authtoken);
check_leaks_push(ts);
*state = (void *)ts;
return 0;
}
static int teardown(void **state)
{
struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
assert_non_null(ts);
assert_true(check_leaks_pop(ts));
talloc_free(ts);
assert_true(leak_check_teardown());
return 0;
}
static void test_sss_authtok_new(void **state)
{
struct test_state *ts = talloc_get_type_abort(*state, struct test_state);
struct sss_auth_token *authtoken;
authtoken = sss_authtok_new(ts);
assert_non_null(authtoken);
talloc_free(authtoken);
}
/* @test_authtok_type_x : tests following functions for different value of type
* sss_authtok_set
* sss_authtok_get_type
* sss_authtok_get_size
* sss_authtok_get_data
* sss_authtok_get_password
* sss_authtok_get_ccfile
*
* @test_authtok_type_password : type => SSS_AUTHTOK_TYPE_PASSWORD
* @test_authtok_type_ccfile : type => SSS_AUTHTOK_TYPE_CCFILE
* @test_authtok_type_empty : type => SSS_AUTHTOK_TYPE_EMPTY
*/
/* Test when type has value SSS_AUTHTOK_TYPE_PASSWORD */
static void test_sss_authtok_password(void **state)
{
size_t len;
errno_t ret;
char *data;
size_t ret_len;
const char *pwd;
struct test_state *ts;
enum sss_authtok_type type;
ts = talloc_get_type_abort(*state, struct test_state);
data = talloc_strdup(ts, "password");
assert_non_null(data);
len = strlen(data) + 1;
type = SSS_AUTHTOK_TYPE_PASSWORD;
ret = sss_authtok_set(ts->authtoken, type, (const uint8_t *)data, len);
assert_int_equal(ret, EOK);
assert_int_equal(type, sss_authtok_get_type(ts->authtoken));
assert_int_equal(len, sss_authtok_get_size(ts->authtoken));
assert_string_equal(data, sss_authtok_get_data(ts->authtoken));
ret = sss_authtok_get_password(ts->authtoken, &pwd, &ret_len);
assert_int_equal(ret, EOK);
assert_string_equal(data, pwd);
assert_int_equal(len - 1, ret_len);
ret = sss_authtok_set_password(ts->authtoken, data, len);
assert_int_equal(ret, EOK);
ret = sss_authtok_get_password(ts->authtoken, &pwd, &ret_len);
assert_int_equal(ret, EOK);
assert_string_equal(data, pwd);
assert_int_equal(len - 1, ret_len);
talloc_free(data);
sss_authtok_set_empty(ts->authtoken);
}
/* Test when type has value SSS_AUTHTOK_TYPE_CCFILE */
static void test_sss_authtok_ccfile(void **state)
{
size_t len;
errno_t ret;
char *data;
size_t ret_len;
const char *pwd;
struct test_state *ts;
enum sss_authtok_type type;
ts = talloc_get_type_abort(*state, struct test_state);
data = talloc_strdup(ts, "path/to/cc_file");
assert_non_null(data);
len = strlen(data) + 1;
type = SSS_AUTHTOK_TYPE_CCFILE;
ret = sss_authtok_set(ts->authtoken, type, (const uint8_t *)data, len);
assert_int_equal(ret, EOK);
assert_int_equal(type, sss_authtok_get_type(ts->authtoken));
assert_int_equal(len, sss_authtok_get_size(ts->authtoken));
assert_string_equal(data, sss_authtok_get_data(ts->authtoken));
ret = sss_authtok_get_ccfile(ts->authtoken, &pwd, &ret_len);
assert_int_equal(ret, EOK);
assert_string_equal(data, pwd);
assert_int_equal(len - 1, ret_len);
ret = sss_authtok_set_ccfile(ts->authtoken, data, len);
assert_int_equal(ret, EOK);
ret = sss_authtok_get_ccfile(ts->authtoken, &pwd, &ret_len);
assert_int_equal(ret, EOK);
assert_string_equal(data, pwd);
assert_int_equal(len - 1, ret_len);
ret = sss_authtok_set(ts->authtoken, type, (const uint8_t *) data, 0);
assert_int_equal(ret, EOK);
assert_int_equal(type, sss_authtok_get_type(ts->authtoken));
assert_int_equal(len, sss_authtok_get_size(ts->authtoken));
assert_string_equal(data, sss_authtok_get_data(ts->authtoken));
ret = sss_authtok_get_ccfile(ts->authtoken, &pwd, &ret_len);
assert_int_equal(ret, EOK);
assert_string_equal(data, pwd);
assert_int_equal(len - 1, ret_len);
talloc_free(data);
sss_authtok_set_empty(ts->authtoken);
}
/* Test when type has value SSS_AUTHTOK_TYPE_EMPTY */
static void test_sss_authtok_empty(void **state)
{
errno_t ret;
size_t ret_len;
const char *pwd;
struct test_state *ts;
enum sss_authtok_type type;
type = SSS_AUTHTOK_TYPE_EMPTY;
ts = talloc_get_type_abort(*state, struct test_state);
ret = sss_authtok_set(ts->authtoken, type, NULL, 0);
assert_int_equal(ret, EOK);
assert_int_equal(type, sss_authtok_get_type(ts->authtoken));
assert_int_equal(0, sss_authtok_get_size(ts->authtoken));
assert_null(sss_authtok_get_data(ts->authtoken));
ret = sss_authtok_get_password(ts->authtoken, &pwd, &ret_len);
assert_int_equal(ret, ENOENT);
ret = sss_authtok_get_ccfile(ts->authtoken, &pwd, &ret_len);
assert_int_equal(ret, ENOENT);
sss_authtok_set_empty(ts->authtoken);
assert_int_equal(type, sss_authtok_get_type(ts->authtoken));
assert_int_equal(0, sss_authtok_get_size(ts->authtoken));
assert_null(sss_authtok_get_data(ts->authtoken));
ret = sss_authtok_set(ts->authtoken, type, (const uint8_t*)"", 0);
assert_int_equal(ret, EOK);
assert_int_equal(type, sss_authtok_get_type(ts->authtoken));
assert_int_equal(EOK, sss_authtok_get_size(ts->authtoken));
assert_null(sss_authtok_get_data(ts->authtoken));
ret = sss_authtok_get_password(ts->authtoken, &pwd, &ret_len);
assert_int_equal(ret, ENOENT);
ret = sss_authtok_get_ccfile(ts->authtoken, &pwd, &ret_len);
assert_int_equal(ret, ENOENT);
}
static void test_sss_authtok_wipe_password(void **state)
{
size_t len;
errno_t ret;
char *data;
size_t ret_len;
const char *pwd;
struct test_state *ts;
enum sss_authtok_type type;
ts = talloc_get_type_abort(*state, struct test_state);
data = talloc_strdup(ts, "password");
assert_non_null(data);
len = strlen(data) + 1;
type = SSS_AUTHTOK_TYPE_PASSWORD;
ret = sss_authtok_set(ts->authtoken, type, (const uint8_t *)data, len);
assert_int_equal(ret, EOK);
sss_authtok_wipe_password(ts->authtoken);
ret = sss_authtok_get_password(ts->authtoken, &pwd, &ret_len);
assert_int_equal(ret, EOK);
assert_string_equal(pwd, "");
assert_int_equal(len - 1, ret_len);
sss_authtok_set_empty(ts->authtoken);
talloc_free(data);
}
static void test_sss_authtok_copy(void **state)
{
size_t len;
errno_t ret;
char *data;
struct test_state *ts;
enum sss_authtok_type type;
struct sss_auth_token *dest_authtoken;
ts= talloc_get_type_abort(*state, struct test_state);
dest_authtoken = sss_authtok_new(ts);
assert_non_null(dest_authtoken);
data = talloc_strdup(ts, "password");
assert_non_null(data);
len = strlen(data) + 1;
type = SSS_AUTHTOK_TYPE_EMPTY;
ret = sss_authtok_set(ts->authtoken, type, (const uint8_t *)data, len);
assert_int_equal(ret, EOK);
assert_int_equal(EOK, sss_authtok_copy(ts->authtoken, dest_authtoken));
assert_int_equal(type, sss_authtok_get_type(dest_authtoken));
sss_authtok_set_empty(dest_authtoken);
type = SSS_AUTHTOK_TYPE_PASSWORD;
ret = sss_authtok_set(ts->authtoken, type, (const uint8_t *)data, len);
assert_int_equal(ret, EOK);
ret = sss_authtok_copy(ts->authtoken, dest_authtoken);
assert_int_equal(ret, EOK);
assert_int_equal(type, sss_authtok_get_type(dest_authtoken));
assert_string_equal(data, sss_authtok_get_data(dest_authtoken));
assert_int_equal(len, sss_authtok_get_size(dest_authtoken));
sss_authtok_set_empty(dest_authtoken);
talloc_free(dest_authtoken);
sss_authtok_set_empty(ts->authtoken);
talloc_free(data);
}
void test_sss_authtok_2fa(void **state)
{
int ret;
const char *fa1;
size_t fa1_size;
const char *fa2;
size_t fa2_size;
struct test_state *ts;
ts = talloc_get_type_abort(*state, struct test_state);
ret = sss_authtok_set_2fa(NULL, "a", 0, "b", 0);
assert_int_equal(ret, EINVAL);
/* Test missing first factor */
ret = sss_authtok_set_2fa(ts->authtoken, NULL, 1, "b", 1);
assert_int_equal(ret, EINVAL);
/* Test missing second factor */
ret = sss_authtok_set_2fa(ts->authtoken, "a", 1, NULL, 1);
assert_int_equal(ret, EINVAL);
/* Test wrong first factor length */
ret = sss_authtok_set_2fa(ts->authtoken, "ab", 1, "b", 1);
assert_int_equal(ret, EINVAL);
/* Test wrong second factor length */
ret = sss_authtok_set_2fa(ts->authtoken, "a", 1, "bc", 1);
assert_int_equal(ret, EINVAL);
ret = sss_authtok_set_2fa(ts->authtoken, "a", 1, "bc", 2);
assert_int_equal(ret, EOK);
assert_int_equal(sss_authtok_get_size(ts->authtoken),
2 * sizeof(uint32_t) + 5);
assert_int_equal(sss_authtok_get_type(ts->authtoken), SSS_AUTHTOK_TYPE_2FA);
#if __BYTE_ORDER == __LITTLE_ENDIAN
assert_memory_equal(sss_authtok_get_data(ts->authtoken),
"\2\0\0\0\3\0\0\0a\0bc\0",
2 * sizeof(uint32_t) + 5);
#else
assert_memory_equal(sss_authtok_get_data(ts->authtoken),
"\0\0\0\2\0\0\0\3a\0bc\0",
2 * sizeof(uint32_t) + 5);
#endif
ret = sss_authtok_get_2fa(ts->authtoken, &fa1, &fa1_size, &fa2, &fa2_size);
assert_int_equal(ret, EOK);
assert_int_equal(fa1_size, 1);
assert_string_equal(fa1, "a");
assert_int_equal(fa2_size, 2);
assert_string_equal(fa2, "bc");
sss_authtok_set_empty(ts->authtoken);
/* check return code of empty token */
ret = sss_authtok_get_2fa(ts->authtoken, &fa1, &fa1_size, &fa2, &fa2_size);
assert_int_equal(ret, ENOENT);
/* check return code for other token type */
ret = sss_authtok_set_password(ts->authtoken, "abc", 0);
assert_int_equal(ret, EOK);
ret = sss_authtok_get_2fa(ts->authtoken, &fa1, &fa1_size, &fa2, &fa2_size);
assert_int_equal(ret, EACCES);
sss_authtok_set_empty(ts->authtoken);
/* check return code for garbage */
ret = sss_authtok_set(ts->authtoken, SSS_AUTHTOK_TYPE_2FA,
(const uint8_t *) "1111222233334444", 16);
assert_int_equal(ret, EINVAL);
sss_authtok_set_empty(ts->authtoken);
}
void test_sss_authtok_2fa_blobs(void **state)
{
int ret;
struct test_state *ts;
size_t needed_size;
uint8_t *buf;
char *fa1;
size_t fa1_len;
char *fa2;
size_t fa2_len;
ts = talloc_get_type_abort(*state, struct test_state);
ret = sss_auth_pack_2fa_blob(NULL, 0, "defg", 0, NULL, 0, &needed_size);
assert_int_equal(ret, EINVAL);
ret = sss_auth_pack_2fa_blob("abc", 0, NULL, 0, NULL, 0, &needed_size);
assert_int_equal(ret, EINVAL);
ret = sss_auth_pack_2fa_blob("", 0, "defg", 0, NULL, 0, &needed_size);
assert_int_equal(ret, EINVAL);
ret = sss_auth_pack_2fa_blob("abc", 0, "", 0, NULL, 0, &needed_size);
assert_int_equal(ret, EINVAL);
ret = sss_auth_pack_2fa_blob("abc", 0, "defg", 0, NULL, 0, &needed_size);
assert_int_equal(ret, EAGAIN);
buf = talloc_size(ts, needed_size);
assert_non_null(buf);
ret = sss_auth_pack_2fa_blob("abc", 0, "defg", 0, buf, needed_size,
&needed_size);
assert_int_equal(ret, EOK);
#if __BYTE_ORDER == __LITTLE_ENDIAN
assert_memory_equal(buf, "\4\0\0\0\5\0\0\0abc\0defg\0", needed_size);
#else
assert_memory_equal(buf, "\0\0\0\4\0\0\0\5abc\0defg\0", needed_size);
#endif
ret = sss_auth_unpack_2fa_blob(ts, buf, needed_size, &fa1, &fa1_len, &fa2,
&fa2_len);
assert_int_equal(ret, EOK);
assert_int_equal(fa1_len, 3);
assert_string_equal(fa1, "abc");
assert_int_equal(fa2_len, 4);
assert_string_equal(fa2, "defg");
talloc_free(buf);
talloc_free(fa1);
talloc_free(fa2);
}
#define MISSING_NULL_CHECK do { \
assert_int_equal(ret, EOK); \
assert_int_equal(fa1_len, 3); \
assert_string_equal(fa1, "abc"); \
assert_int_equal(fa2_len, 4); \
assert_string_equal(fa2, "defg"); \
\
talloc_free(fa1); \
talloc_free(fa2); \
} while (0)
void test_sss_authtok_2fa_blobs_missing_null(void **state)
{
int ret;
struct test_state *ts;
char *fa1;
size_t fa1_len;
char *fa2;
size_t fa2_len;
#if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t b0[] = {0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 'a', 'b', 'c', 0x00, 'd', 'e', 'f', 'g', 0x00};
uint8_t b1[] = {0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 0x00};
uint8_t b2[] = {0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 'a', 'b', 'c', 0x00, 'd', 'e', 'f', 'g'};
uint8_t b3[] = {0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 'a', 'b', 'c', 'd', 'e', 'f', 'g'};
#else
uint8_t b0[] = {0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 'a', 'b', 'c', 0x00, 'd', 'e', 'f', 'g', 0x00};
uint8_t b1[] = {0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 0x00};
uint8_t b2[] = {0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 'a', 'b', 'c', 0x00, 'd', 'e', 'f', 'g'};
uint8_t b3[] = {0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 'a', 'b', 'c', 'd', 'e', 'f', 'g'};
#endif
ts = talloc_get_type_abort(*state, struct test_state);
ret = sss_auth_unpack_2fa_blob(ts, b0, sizeof(b0), &fa1, &fa1_len, &fa2,
&fa2_len);
MISSING_NULL_CHECK;
ret = sss_auth_unpack_2fa_blob(ts, b1, sizeof(b1), &fa1, &fa1_len, &fa2,
&fa2_len);
MISSING_NULL_CHECK;
ret = sss_auth_unpack_2fa_blob(ts, b2, sizeof(b2), &fa1, &fa1_len, &fa2,
&fa2_len);
MISSING_NULL_CHECK;
ret = sss_auth_unpack_2fa_blob(ts, b3, sizeof(b3), &fa1, &fa1_len, &fa2,
&fa2_len);
MISSING_NULL_CHECK;
}
void test_sss_authtok_sc_keypad(void **state)
{
struct test_state *ts;
ts = talloc_get_type_abort(*state, struct test_state);
sss_authtok_set_sc_keypad(NULL);
sss_authtok_set_sc_keypad(ts->authtoken);
assert_int_equal(sss_authtok_get_type(ts->authtoken),
SSS_AUTHTOK_TYPE_SC_KEYPAD);
assert_int_equal(sss_authtok_get_size(ts->authtoken), 0);
assert_null(sss_authtok_get_data(ts->authtoken));
}
void test_sss_authtok_sc_pin(void **state)
{
struct test_state *ts;
int ret;
size_t size;
const char *pin;
size_t len;
ts = talloc_get_type_abort(*state, struct test_state);
ret = sss_authtok_set_sc_pin(NULL, NULL, 0);
assert_int_equal(ret, EFAULT);
ret = sss_authtok_set_sc_pin(ts->authtoken, NULL, 0);
assert_int_equal(ret, EINVAL);
ret = sss_authtok_set_sc_pin(ts->authtoken, "12345678", 0);
assert_int_equal(ret, EOK);
assert_int_equal(sss_authtok_get_type(ts->authtoken),
SSS_AUTHTOK_TYPE_SC_PIN);
size = sss_authtok_get_size(ts->authtoken);
assert_int_equal(size, 9);
assert_memory_equal(sss_authtok_get_data(ts->authtoken), "12345678\0",
size);
ret = sss_authtok_set_sc_pin(ts->authtoken, "12345678", 5);
assert_int_equal(ret, EOK);
assert_int_equal(sss_authtok_get_type(ts->authtoken),
SSS_AUTHTOK_TYPE_SC_PIN);
size = sss_authtok_get_size(ts->authtoken);
assert_int_equal(size, 6);
assert_memory_equal(sss_authtok_get_data(ts->authtoken), "12345\0",
size);
ret = sss_authtok_get_sc_pin(ts->authtoken, &pin, &len);
assert_int_equal(ret, EOK);
assert_int_equal(len, 5);
assert_string_equal(pin, "12345");
sss_authtok_set_empty(ts->authtoken);
ret = sss_authtok_get_sc_pin(ts->authtoken, &pin, &len);
assert_int_equal(ret, ENOENT);
ret = sss_authtok_set_password(ts->authtoken, "12345", 0);
assert_int_equal(ret, EOK);
ret = sss_authtok_get_sc_pin(ts->authtoken, &pin, &len);
assert_int_equal(ret, EACCES);
sss_authtok_set_empty(ts->authtoken);
ret = sss_authtok_get_sc_pin(NULL, &pin, &len);
assert_int_equal(ret, EFAULT);
}
int main(int argc, const char *argv[])
{
poptContext pc;
int opt;
struct poptOption long_options[] = {
POPT_AUTOHELP
SSSD_DEBUG_OPTS
POPT_TABLEEND
};
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(test_sss_authtok_new,
setup, teardown),
cmocka_unit_test_setup_teardown(test_sss_authtok_password,
setup, teardown),
cmocka_unit_test_setup_teardown(test_sss_authtok_ccfile,
setup, teardown),
cmocka_unit_test_setup_teardown(test_sss_authtok_empty,
setup, teardown),
cmocka_unit_test_setup_teardown(test_sss_authtok_wipe_password,
setup, teardown),
cmocka_unit_test_setup_teardown(test_sss_authtok_copy,
setup, teardown),
cmocka_unit_test_setup_teardown(test_sss_authtok_2fa,
setup, teardown),
cmocka_unit_test_setup_teardown(test_sss_authtok_2fa_blobs,
setup, teardown),
cmocka_unit_test_setup_teardown(test_sss_authtok_2fa_blobs_missing_null,
setup, teardown),
cmocka_unit_test_setup_teardown(test_sss_authtok_sc_keypad,
setup, teardown),
cmocka_unit_test_setup_teardown(test_sss_authtok_sc_pin,
setup, teardown),
};
/* Set debug level to invalid value so we can deside if -d 0 was used. */
debug_level = SSSDBG_INVALID;
pc = poptGetContext(argv[0], argc, argv, long_options, 0);
while((opt = poptGetNextOpt(pc)) != -1) {
switch(opt) {
default:
fprintf(stderr, "\nInvalid option %s: %s\n\n",
poptBadOption(pc, 0), poptStrerror(opt));
poptPrintUsage(pc, stderr, 0);
return 1;
}
}
poptFreeContext(pc);
DEBUG_CLI_INIT(debug_level);
return cmocka_run_group_tests(tests, NULL, NULL);
}