Blob Blame History Raw
From 71731d26dc4f2c36989779f327b0e9a399486e14 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sbose@redhat.com>
Date: Tue, 9 May 2017 16:57:43 +0200
Subject: [PATCH] sss_nss_getlistbycert: return results from multiple domains
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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 <pbrezina@redhat.com>
---
 src/responder/nss/nss_cmd.c          | 87 +++++++++++++++++++++++++++++++++++-
 src/responder/nss/nss_protocol.h     |  6 +++
 src/responder/nss/nss_protocol_sid.c | 78 ++++++++++++++++++++++++++++++++
 src/tests/cmocka/test_nss_srv.c      | 33 +++++++++-----
 4 files changed, 192 insertions(+), 12 deletions(-)

diff --git a/src/responder/nss/nss_cmd.c b/src/responder/nss/nss_cmd.c
index 1931bf62a686c7f30852dac547866609cf54a81b..a4727c18786a86c28b5415ba82295967a47a8ec0 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 e4c0e52c0e642e885ef2c8423ea564beff7242cf..417b0891615dcb8771d49f7b2f4d276342ca3150 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 d4b7ee22d7c68a9e6f7c668f7268cdc5f36768b3..61357c2bf92e2f15d978b64a15ad5bd5aa354445 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 8c72f44f1869558893627e1f2f91b5f3b96c6317..03b5bcc302322551a32f5b8cfe4b7698947abbe7 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,
-- 
2.9.3