From 71731d26dc4f2c36989779f327b0e9a399486e14 Mon Sep 17 00:00:00 2001 From: Sumit Bose Date: May 10 2017 14:21:42 +0000 Subject: sss_nss_getlistbycert: return results from multiple domains Currently only the results from one domain were returned although all domains were searched and the results were available. Unit tests are updated to cover this case as well. Resolves https://pagure.io/SSSD/sssd/issue/3393 Reviewed-by: Pavel Březina --- diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c index 1931bf6..a4727c1 100644 --- a/src/responder/nss/nss_cmd.c +++ b/src/responder/nss/nss_cmd.c @@ -51,6 +51,7 @@ nss_cmd_ctx_create(TALLOC_CTX *mem_ctx, } static void nss_getby_done(struct tevent_req *subreq); +static void nss_getlistby_done(struct tevent_req *subreq); static errno_t nss_getby_name(struct cli_ctx *cli_ctx, enum cache_req_type type, @@ -212,6 +213,89 @@ done: return EOK; } +static errno_t nss_getlistby_cert(struct cli_ctx *cli_ctx, + enum cache_req_type type) +{ + struct nss_cmd_ctx *cmd_ctx; + struct tevent_req *subreq; + const char *cert; + errno_t ret; + + cmd_ctx = nss_cmd_ctx_create(cli_ctx, cli_ctx, type, NULL); + if (cmd_ctx == NULL) { + ret = ENOMEM; + goto done; + } + + cmd_ctx->sid_id_type = SSS_ID_TYPE_UID; + + ret = nss_protocol_parse_cert(cli_ctx, &cert); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Invalid request message!\n"); + goto done; + } + + DEBUG(SSSDBG_TRACE_FUNC, "Input cert: %s\n", get_last_x_chars(cert, 10)); + + subreq = cache_req_user_by_cert_send(cmd_ctx, cli_ctx->ev, cli_ctx->rctx, + cli_ctx->rctx->ncache, 0, + CACHE_REQ_ANY_DOM, NULL, + cert); + if (subreq == NULL) { + DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert_send failed.\n"); + ret = ENOMEM; + goto done; + } + tevent_req_set_callback(subreq, nss_getlistby_done, cmd_ctx); + + ret = EOK; + +done: + if (ret != EOK) { + talloc_free(cmd_ctx); + return nss_protocol_done(cli_ctx, ret); + } + + return EOK; +} + +static void nss_getlistby_done(struct tevent_req *subreq) +{ + struct cache_req_result **results; + struct nss_cmd_ctx *cmd_ctx; + errno_t ret; + struct cli_protocol *pctx; + + cmd_ctx = tevent_req_callback_data(subreq, struct nss_cmd_ctx); + + ret = cache_req_recv(cmd_ctx, subreq, &results); + talloc_zfree(subreq); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "cache_req_user_by_cert request failed.\n"); + goto done; + } + + pctx = talloc_get_type(cmd_ctx->cli_ctx->protocol_ctx, struct cli_protocol); + + ret = sss_packet_new(pctx->creq, 0, sss_packet_get_cmd(pctx->creq->in), + &pctx->creq->out); + if (ret != EOK) { + goto done; + } + + ret = nss_protocol_fill_name_list_all_domains(cmd_ctx->nss_ctx, cmd_ctx, + pctx->creq->out, results); + if (ret != EOK) { + goto done; + } + + sss_packet_set_error(pctx->creq->out, EOK); + +done: + nss_protocol_done(cmd_ctx->cli_ctx, ret); + talloc_free(cmd_ctx); +} + static errno_t nss_getby_cert(struct cli_ctx *cli_ctx, enum cache_req_type type, nss_protocol_fill_packet_fn fill_fn) @@ -934,8 +1018,7 @@ static errno_t nss_cmd_getnamebycert(struct cli_ctx *cli_ctx) static errno_t nss_cmd_getlistbycert(struct cli_ctx *cli_ctx) { - return nss_getby_cert(cli_ctx, CACHE_REQ_USER_BY_CERT, - nss_protocol_fill_name_list); + return nss_getlistby_cert(cli_ctx, CACHE_REQ_USER_BY_CERT); } struct sss_cmd_table *get_nss_cmds(void) diff --git a/src/responder/nss/nss_protocol.h b/src/responder/nss/nss_protocol.h index e4c0e52..417b089 100644 --- a/src/responder/nss/nss_protocol.h +++ b/src/responder/nss/nss_protocol.h @@ -181,6 +181,12 @@ nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, struct cache_req_result *result); errno_t +nss_protocol_fill_name_list_all_domains(struct nss_ctx *nss_ctx, + struct nss_cmd_ctx *cmd_ctx, + struct sss_packet *packet, + struct cache_req_result **results); + +errno_t nss_protocol_fill_id(struct nss_ctx *nss_ctx, struct nss_cmd_ctx *cmd_ctx, struct sss_packet *packet, diff --git a/src/responder/nss/nss_protocol_sid.c b/src/responder/nss/nss_protocol_sid.c index d4b7ee2..61357c2 100644 --- a/src/responder/nss/nss_protocol_sid.c +++ b/src/responder/nss/nss_protocol_sid.c @@ -561,3 +561,81 @@ nss_protocol_fill_name_list(struct nss_ctx *nss_ctx, return EOK; } + +errno_t +nss_protocol_fill_name_list_all_domains(struct nss_ctx *nss_ctx, + struct nss_cmd_ctx *cmd_ctx, + struct sss_packet *packet, + struct cache_req_result **results) +{ + enum sss_id_type *id_types; + size_t rp = 0; + size_t body_len; + uint8_t *body; + errno_t ret; + struct sized_string *sz_names; + size_t len; + size_t c; + const char *tmp_str; + size_t d; + size_t total = 0; + size_t iter = 0; + + if (results == NULL) { + return EINVAL; + } + + for (d = 0; results[d] != NULL; d++) { + total += results[d]->count; + } + + sz_names = talloc_array(cmd_ctx, struct sized_string, total); + if (sz_names == NULL) { + return ENOMEM; + } + + id_types = talloc_array(cmd_ctx, enum sss_id_type, total); + if (id_types == NULL) { + return ENOMEM; + } + + len = 0; + for (d = 0; results[d] != NULL; d++) { + for (c = 0; c < results[d]->count; c++) { + ret = nss_get_id_type(cmd_ctx, results[d], &(id_types[iter])); + if (ret != EOK) { + return ret; + } + + tmp_str = sss_get_name_from_msg(results[d]->domain, + results[d]->msgs[c]); + if (tmp_str == NULL) { + return EINVAL; + } + to_sized_string(&(sz_names[iter]), tmp_str); + + len += sz_names[iter].len; + iter++; + } + } + + len += (2 + total) * sizeof(uint32_t); + + ret = sss_packet_grow(packet, len); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, "sss_packet_grow failed.\n"); + return ret; + } + + sss_packet_get_body(packet, &body, &body_len); + + SAFEALIGN_SET_UINT32(&body[rp], total, &rp); /* Num results. */ + SAFEALIGN_SET_UINT32(&body[rp], 0, &rp); /* Reserved. */ + for (c = 0; c < total; c++) { + SAFEALIGN_SET_UINT32(&body[rp], id_types[c], &rp); + SAFEALIGN_SET_STRING(&body[rp], sz_names[c].str, sz_names[c].len, + &rp); + } + + return EOK; +} diff --git a/src/tests/cmocka/test_nss_srv.c b/src/tests/cmocka/test_nss_srv.c index 8c72f44..03b5bcc 100644 --- a/src/tests/cmocka/test_nss_srv.c +++ b/src/tests/cmocka/test_nss_srv.c @@ -3808,7 +3808,8 @@ static int test_nss_getnamebycert_check(uint32_t status, uint8_t *body, size_t b return EOK; } -static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t blen) +static int test_nss_getlistbycert_check_exp(uint32_t status, uint8_t *body, + size_t blen, size_t exp) { size_t rp = 0; uint32_t id_type; @@ -3817,13 +3818,13 @@ static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t b const char *name; int found = 0; const char *fq_name1 = "testcertuser@"TEST_DOM_NAME ; - const char *fq_name2 = "testcertuser2@"TEST_DOM_NAME; + const char *fq_name2 = "testcertuser2@"TEST_SUBDOM_NAME; assert_int_equal(status, EOK); /* num_results and reserved */ SAFEALIGN_COPY_UINT32(&num, body + rp, &rp); - assert_in_range(num, 1, 2); + assert_int_equal(num, exp); SAFEALIGN_COPY_UINT32(&reserved, body + rp, &rp); assert_int_equal(reserved, 0); @@ -3858,6 +3859,17 @@ static int test_nss_getlistbycert_check(uint32_t status, uint8_t *body, size_t b return EOK; } +static int test_nss_getlistbycert_check_one(uint32_t status, uint8_t *body, + size_t blen) +{ + return test_nss_getlistbycert_check_exp(status, body, blen, 1); +} + +static int test_nss_getlistbycert_check_two(uint32_t status, uint8_t *body, + size_t blen) +{ + return test_nss_getlistbycert_check_exp(status, body, blen, 2); +} static void test_nss_getnamebycert(void **state) { @@ -3949,7 +3961,7 @@ static void test_nss_getlistbycert(void **state) der = sss_base64_decode(nss_test_ctx, TEST_TOKEN_CERT, &der_size); assert_non_null(der); - ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); + ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); talloc_free(der); assert_int_equal(ret, EOK); @@ -3967,7 +3979,7 @@ static void test_nss_getlistbycert(void **state) /* Should go straight to back end, without contacting DP. */ /* If there is only a single user mapped the result will look like the */ /* result of getnamebycert. */ - set_cmd_cb(test_nss_getlistbycert_check); + set_cmd_cb(test_nss_getlistbycert_check_one); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); @@ -3990,7 +4002,7 @@ static void test_nss_getlistbycert_multi(void **state) attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); - ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); + ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); assert_int_equal(ret, EOK); /* Prime the cache with two valid user */ @@ -4004,11 +4016,11 @@ static void test_nss_getlistbycert_multi(void **state) attrs = sysdb_new_attrs(nss_test_ctx); assert_non_null(attrs); - ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_CERT, der, der_size); + ret = sysdb_attrs_add_mem(attrs, SYSDB_USER_MAPPED_CERT, der, der_size); talloc_free(der); assert_int_equal(ret, EOK); - ret = store_user(nss_test_ctx, nss_test_ctx->tctx->dom, + ret = store_user(nss_test_ctx, nss_test_ctx->subdom, &testbycert2, attrs, 0); assert_int_equal(ret, EOK); talloc_free(attrs); @@ -4019,7 +4031,7 @@ static void test_nss_getlistbycert_multi(void **state) /* Query for that user, call a callback when command finishes */ /* Should go straight to back end, without contacting DP */ - set_cmd_cb(test_nss_getlistbycert_check); + set_cmd_cb(test_nss_getlistbycert_check_two); ret = sss_cmd_execute(nss_test_ctx->cctx, SSS_NSS_GETLISTBYCERT, nss_test_ctx->nss_cmds); assert_int_equal(ret, EOK); @@ -4290,7 +4302,8 @@ int main(int argc, const char *argv[]) cmocka_unit_test_setup_teardown(test_nss_getlistbycert, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getlistbycert_multi, - nss_test_setup, nss_test_teardown), + nss_subdom_test_setup, + nss_subdom_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getsidbyname, nss_test_setup, nss_test_teardown), cmocka_unit_test_setup_teardown(test_nss_getsidbyupn,