Skip to content

Commit

Permalink
pam: fix section parsing issue
Browse files Browse the repository at this point in the history
Due to a typo it was always necessary to have a `[prompting/password]`
section in sssd.conf to enable the other `prompting` section.

This patch fixes this and adds some unit test to cover that part of the
code.

Resolves: #6081
  • Loading branch information
sumit-bose committed Mar 28, 2022
1 parent fd19512 commit 0de25e0
Show file tree
Hide file tree
Showing 2 changed files with 288 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/responder/pam/pam_prompting_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ static errno_t pam_set_prompting_options(struct confdb_ctx *cdb,
dummy = talloc_asprintf(tmp_ctx, "%s/%s", section_path,
service_name);
for (c = 0; c < num_sections; c++) {
if (strcmp(sections[c], CONFDB_PC_TYPE_PASSWORD) == 0) {
if (strcmp(sections[c], section_path) == 0) {
global = true;
}
if (dummy != NULL && strcmp(sections[c], dummy) == 0) {
Expand Down
288 changes: 287 additions & 1 deletion src/tests/cmocka/test_pam_srv.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ struct pam_test_ctx {

int ncache_hits;
int exp_pam_status;
enum prompt_config_type exp_prompt_config_type;
struct pam_data *pd;
bool provider_contacted;

const char *pam_user_fqdn;
Expand Down Expand Up @@ -172,6 +174,7 @@ void test_pam_setup(struct sss_test_conf_param dom_params[],
pam_test_ctx = talloc_zero(NULL, struct pam_test_ctx);
assert_non_null(pam_test_ctx);

test_dom_suite_setup(TESTS_PATH);
pam_test_ctx->tctx = create_dom_test_ctx(pam_test_ctx, TESTS_PATH,
TEST_CONF_DB, TEST_DOM_NAME,
TEST_ID_PROVIDER, dom_params);
Expand Down Expand Up @@ -212,6 +215,9 @@ void test_pam_setup(struct sss_test_conf_param dom_params[],
assert_non_null(prctx);
pam_test_ctx->cctx->protocol_ctx = prctx;
prctx->cli_protocol_version = register_cli_protocol_version();

pam_test_ctx->pd = create_pam_data(pam_test_ctx);
assert_non_null(pam_test_ctx->pd);
}

static void pam_test_setup_common(void)
Expand Down Expand Up @@ -378,6 +384,7 @@ static int pam_cached_test_setup(void **state)
static int pam_test_teardown(void **state)
{
int ret;
const char *domains[] = {TEST_DOM_NAME, NULL};

ret = sysdb_delete_user(pam_test_ctx->tctx->dom,
pam_test_ctx->pam_user_fqdn, 0);
Expand All @@ -387,6 +394,8 @@ static int pam_test_teardown(void **state)
pam_test_ctx->wrong_user_fqdn, 0);
assert_int_equal(ret, EOK);

test_multidom_suite_cleanup(TESTS_PATH, TEST_CONF_DB, domains);

talloc_free(pam_test_ctx);
return 0;
}
Expand Down Expand Up @@ -466,6 +475,9 @@ int __wrap_pam_dp_send_req(struct pam_auth_req *preq, int timeout)

/* Set expected status */
preq->pd->pam_status = pam_test_ctx->exp_pam_status;
if (pam_test_ctx->pd->resp_list != NULL) {
preq->pd->resp_list = pam_test_ctx->pd->resp_list;
}

preq->callback(preq);

Expand Down Expand Up @@ -3560,6 +3572,272 @@ void test_not_appsvc_app_dom(void **state)
assert_int_equal(ret, EOK);
}

#define MY_PW_PROMPT "my_pw_prompt"
#define MY_2FA_SINGLE_PROMPT "my_2fa_single_prompt"
#define MY_FIRST_PROMPT "my_first_prompt"
#define MY_SECOND_PROMPT "my_second_prompt"
#define MY_SERVICE "my_service"

static int pam_test_setup_pw_prompt(void **state)
{
int ret;

struct sss_test_conf_param prompt_params[] = {
{ "password_prompt", MY_PW_PROMPT},
{ NULL, NULL }, /* Sentinel */
};

ret = pam_test_setup(state);
assert_int_equal(ret, EOK);

ret = add_confdb_params(prompt_params, pam_test_ctx->rctx->cdb, CONFDB_PC_CONF_ENTRY "/" CONFDB_PC_TYPE_PASSWORD);
assert_int_equal(ret, EOK);

return 0;
}

static int test_pam_prompt_check(uint32_t status, uint8_t *body, size_t blen)
{
size_t rp = 0;
uint32_t val;
uint8_t val8t;
int ret;
struct prompt_config **pc = NULL;

assert_int_equal(status, 0);

SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
assert_int_equal(val, pam_test_ctx->exp_pam_status);

SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
assert_int_equal(val, 3);

SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
assert_int_equal(val, SSS_PAM_PROMPT_CONFIG);
SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
ret = pc_list_from_response(val, body + rp, &pc);
assert_int_equal(ret, EOK);
assert_non_null(pc[0]);
assert_int_equal(pc_get_type(pc[0]), pam_test_ctx->exp_prompt_config_type);
switch (pam_test_ctx->exp_prompt_config_type) {
case PC_TYPE_PASSWORD:
assert_string_equal(pc_get_password_prompt(pc[0]), MY_PW_PROMPT);
break;
case PC_TYPE_2FA_SINGLE:
assert_string_equal(pc_get_2fa_single_prompt(pc[0]), MY_2FA_SINGLE_PROMPT);
break;
case PC_TYPE_2FA:
assert_string_equal(pc_get_2fa_1st_prompt(pc[0]), MY_FIRST_PROMPT);
assert_string_equal(pc_get_2fa_2nd_prompt(pc[0]), MY_SECOND_PROMPT);
break;
default:
assert_false(true);
}
assert_null(pc[1]);
pc_list_free(pc);
rp += val;

SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
assert_int_equal(val, SSS_PAM_DOMAIN_NAME);

SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
assert_int_equal(val, 9);
assert_string_equal(body + rp, TEST_DOM_NAME);
rp += val;


switch (pam_test_ctx->exp_prompt_config_type) {
case PC_TYPE_PASSWORD:
SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
assert_int_equal(val, SSS_PASSWORD_PROMPTING);
SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
assert_int_equal(val, 0);
break;
case PC_TYPE_2FA_SINGLE:
case PC_TYPE_2FA:
SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
assert_int_equal(val, SSS_PAM_OTP_INFO);
SAFEALIGN_COPY_UINT32(&val, body + rp, &rp);
assert_int_equal(val, 3);
SAFEALIGN_COPY_UINT8_CHECK(&val8t, body + rp, blen, &rp);
assert_int_equal(val8t, 0);
SAFEALIGN_COPY_UINT8_CHECK(&val8t, body + rp, blen, &rp);
assert_int_equal(val8t, 0);
SAFEALIGN_COPY_UINT8_CHECK(&val8t, body + rp, blen, &rp);
assert_int_equal(val8t, 0);
break;
default:
assert_false(true);
}

assert_int_equal(rp, blen);

return EOK;
}

void test_pam_prompting_password(void **state)
{
int ret;

pam_test_ctx->pctx->prompting_config_sections = NULL;
pam_test_ctx->pctx->num_prompting_config_sections = 0;
ret = confdb_get_sub_sections(pam_test_ctx->pctx, pam_test_ctx->pctx->rctx->cdb, CONFDB_PC_CONF_ENTRY,
&pam_test_ctx->pctx->prompting_config_sections,
&pam_test_ctx->pctx->num_prompting_config_sections);
assert_int_equal(ret, EOK);

ret = pam_add_response(pam_test_ctx->pd, SSS_PASSWORD_PROMPTING, 0, NULL);
assert_int_equal(ret, EOK);

mock_input_pam(pam_test_ctx, "pamuser", NULL, NULL);

will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);

pam_test_ctx->exp_prompt_config_type = PC_TYPE_PASSWORD;
set_cmd_cb(test_pam_prompt_check);
ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
pam_test_ctx->pam_cmds);
assert_int_equal(ret, EOK);

/* Wait until the test finishes with EOK */
ret = test_ev_loop(pam_test_ctx->tctx);
assert_int_equal(ret, EOK);
}

static int pam_test_setup_2fa_single_prompt(void **state)
{
int ret;

struct sss_test_conf_param prompt_params[] = {
{ "first_prompt", MY_2FA_SINGLE_PROMPT},
{ "single_prompt", "true"},
{ NULL, NULL }, /* Sentinel */
};

ret = pam_test_setup(state);
assert_int_equal(ret, EOK);

ret = add_confdb_params(prompt_params, pam_test_ctx->rctx->cdb, CONFDB_PC_CONF_ENTRY "/" CONFDB_PC_TYPE_2FA);
assert_int_equal(ret, EOK);

return 0;
}

void test_pam_prompting_2fa_single(void **state)
{
int ret;
uint8_t otp_info[3] = { '\0' };

pam_test_ctx->pctx->prompting_config_sections = NULL;
pam_test_ctx->pctx->num_prompting_config_sections = 0;
ret = confdb_get_sub_sections(pam_test_ctx->pctx, pam_test_ctx->pctx->rctx->cdb, CONFDB_PC_CONF_ENTRY,
&pam_test_ctx->pctx->prompting_config_sections,
&pam_test_ctx->pctx->num_prompting_config_sections);
assert_int_equal(ret, EOK);

ret = pam_add_response(pam_test_ctx->pd, SSS_PAM_OTP_INFO, 3, otp_info);
assert_int_equal(ret, EOK);

mock_input_pam(pam_test_ctx, "pamuser", NULL, NULL);

will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);

pam_test_ctx->exp_prompt_config_type = PC_TYPE_2FA_SINGLE;
set_cmd_cb(test_pam_prompt_check);

ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
pam_test_ctx->pam_cmds);
assert_int_equal(ret, EOK);

/* Wait until the test finishes with EOK */
ret = test_ev_loop(pam_test_ctx->tctx);
assert_int_equal(ret, EOK);
}

static int pam_test_setup_2fa_single_and_service_prompt(void **state)
{
int ret;

struct sss_test_conf_param prompt_service_params[] = {
{ "first_prompt", MY_FIRST_PROMPT},
{ "second_prompt", MY_SECOND_PROMPT},
{ NULL, NULL }, /* Sentinel */
};

ret = pam_test_setup_2fa_single_prompt(state);
assert_int_equal(ret, EOK);

ret = add_confdb_params(prompt_service_params, pam_test_ctx->rctx->cdb, CONFDB_PC_CONF_ENTRY "/" CONFDB_PC_TYPE_2FA "/" MY_SERVICE);
assert_int_equal(ret, EOK);

return 0;
}

void test_pam_prompting_2fa_single_and_service_glob(void **state)
{
int ret;
uint8_t otp_info[3] = { '\0' };

pam_test_ctx->pctx->prompting_config_sections = NULL;
pam_test_ctx->pctx->num_prompting_config_sections = 0;
ret = confdb_get_sub_sections(pam_test_ctx->pctx, pam_test_ctx->pctx->rctx->cdb, CONFDB_PC_CONF_ENTRY,
&pam_test_ctx->pctx->prompting_config_sections,
&pam_test_ctx->pctx->num_prompting_config_sections);
assert_int_equal(ret, EOK);

ret = pam_add_response(pam_test_ctx->pd, SSS_PAM_OTP_INFO, 3, otp_info);
assert_int_equal(ret, EOK);

mock_input_pam(pam_test_ctx, "pamuser", NULL, NULL);

will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);

pam_test_ctx->exp_prompt_config_type = PC_TYPE_2FA_SINGLE;
set_cmd_cb(test_pam_prompt_check);
ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
pam_test_ctx->pam_cmds);
assert_int_equal(ret, EOK);

/* Wait until the test finishes with EOK */
ret = test_ev_loop(pam_test_ctx->tctx);
assert_int_equal(ret, EOK);
}

void test_pam_prompting_2fa_single_and_service_srv(void **state)
{
int ret;
uint8_t otp_info[3] = { '\0' };

pam_test_ctx->pctx->prompting_config_sections = NULL;
pam_test_ctx->pctx->num_prompting_config_sections = 0;
ret = confdb_get_sub_sections(pam_test_ctx->pctx, pam_test_ctx->pctx->rctx->cdb, CONFDB_PC_CONF_ENTRY,
&pam_test_ctx->pctx->prompting_config_sections,
&pam_test_ctx->pctx->num_prompting_config_sections);
assert_int_equal(ret, EOK);

ret = pam_add_response(pam_test_ctx->pd, SSS_PAM_OTP_INFO, 3, otp_info);
assert_int_equal(ret, EOK);

mock_input_pam_ex(pam_test_ctx, "pamuser", NULL, NULL, MY_SERVICE, false);

will_return(__wrap_sss_packet_get_cmd, SSS_PAM_PREAUTH);
will_return(__wrap_sss_packet_get_body, WRAP_CALL_REAL);

pam_test_ctx->exp_prompt_config_type = PC_TYPE_2FA;
set_cmd_cb(test_pam_prompt_check);

ret = sss_cmd_execute(pam_test_ctx->cctx, SSS_PAM_PREAUTH,
pam_test_ctx->pam_cmds);
assert_int_equal(ret, EOK);

/* Wait until the test finishes with EOK */
ret = test_ev_loop(pam_test_ctx->tctx);
assert_int_equal(ret, EOK);
}

int main(int argc, const char *argv[])
{
int rv;
Expand Down Expand Up @@ -3760,8 +4038,16 @@ int main(int argc, const char *argv[])
pam_test_setup_appsvc_app_dom,
pam_test_teardown),
cmocka_unit_test_setup_teardown(test_not_appsvc_app_dom,
pam_test_setup_appsvc_posix_dom,
pam_test_setup_appsvc_app_dom,
pam_test_teardown),
cmocka_unit_test_setup_teardown(test_pam_prompting_password,
pam_test_setup_pw_prompt, pam_test_teardown),
cmocka_unit_test_setup_teardown(test_pam_prompting_2fa_single,
pam_test_setup_2fa_single_prompt, pam_test_teardown),
cmocka_unit_test_setup_teardown(test_pam_prompting_2fa_single_and_service_glob,
pam_test_setup_2fa_single_and_service_prompt, pam_test_teardown),
cmocka_unit_test_setup_teardown(test_pam_prompting_2fa_single_and_service_srv,
pam_test_setup_2fa_single_and_service_prompt, pam_test_teardown),
};

/* Set debug level to invalid value so we can decide if -d 0 was used. */
Expand Down

0 comments on commit 0de25e0

Please sign in to comment.