From 326e3d1ed5aca8457ad9b03a5ed7d5cdf08c9d7d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 24 Feb 2015 12:32:10 +0100
Subject: [PATCH 11/12] cache_req: allow id 0 as input and return ENOENT

Looking up zero id is a valid operation so we should not error out, but
return ENOENT instead. However, we cannot go though the standard code
path since internal dp calls are not able to lookup zero id.
---
 src/responder/common/responder_cache_req.c  | 39 ++++++++++++++++---
 src/tests/cmocka/test_responder_cache_req.c | 59 +++++++++++++++++++++++++++++
 2 files changed, 93 insertions(+), 5 deletions(-)

diff --git a/src/responder/common/responder_cache_req.c b/src/responder/common/responder_cache_req.c
index a5cf55a49a29bf4e28c598a7e59f0c64a9f4f441..318e1564cd1f314b3f16bb705343bc985aea046f 100644
--- a/src/responder/common/responder_cache_req.c
+++ b/src/responder/common/responder_cache_req.c
@@ -84,11 +84,6 @@ cache_req_input_create(TALLOC_CTX *mem_ctx,
         break;
     case CACHE_REQ_USER_BY_ID:
     case CACHE_REQ_GROUP_BY_ID:
-        if (id == 0) {
-            DEBUG(SSSDBG_CRIT_FAILURE, "Bug: id cannot be 0!\n");
-            goto fail;
-        }
-
         input->id = id;
         break;
     }
@@ -205,6 +200,35 @@ done:
     return ret;
 }
 
+static errno_t cache_req_check_input(struct cache_req_input *input)
+{
+    switch (input->type) {
+    case CACHE_REQ_USER_BY_NAME:
+    case CACHE_REQ_GROUP_BY_NAME:
+    case CACHE_REQ_INITGROUPS:
+        if (input->orig_name == NULL) {
+            /* This should never happen. If it does it is an error in
+             * the code. */
+            DEBUG(SSSDBG_CRIT_FAILURE, "Bug: name cannot be NULL!\n");
+            return ERR_INTERNAL;
+        }
+        break;
+
+    case CACHE_REQ_USER_BY_ID:
+    case CACHE_REQ_GROUP_BY_ID:
+        /* Internal data provider functions will not perform data provider
+         * lookup for root. We need to shortcut here. */
+        if (input->id == 0) {
+            DEBUG(SSSDBG_TRACE_FUNC, "Got request for ID=0, returning"
+                                     "'not found'.\n");
+            return ENOENT;
+        }
+        break;
+    }
+
+    return EOK;
+}
+
 static errno_t cache_req_check_ncache(struct cache_req_input *input,
                                       struct sss_nc_ctx *ncache,
                                       int neg_timeout)
@@ -648,6 +672,11 @@ struct tevent_req *cache_req_send(TALLOC_CTX *mem_ctx,
     state->cache_refresh_percent = cache_refresh_percent;
     state->input = input;
 
+    ret = cache_req_check_input(input);
+    if (ret != EOK) {
+        goto immediately;
+    }
+
     if (state->input->orig_name != NULL && domain == NULL) {
         /* Parse input name first, since it may contain domain name. */
         subreq = sss_parse_inp_send(state, rctx, input->orig_name);
diff --git a/src/tests/cmocka/test_responder_cache_req.c b/src/tests/cmocka/test_responder_cache_req.c
index 1c942170abaf11c46364915305096cdd3df3074e..6b9b7d2df947ab3401e22a1f1d066fcc069e2aa7 100644
--- a/src/tests/cmocka/test_responder_cache_req.c
+++ b/src/tests/cmocka/test_responder_cache_req.c
@@ -856,6 +856,35 @@ void test_user_by_id_cache_midpoint(void **state)
     assert_int_equal(ldbuid, uid);
 }
 
+void test_user_by_id_cache_root(void **state)
+{
+    struct cache_req_test_ctx *test_ctx = NULL;
+    TALLOC_CTX *req_mem_ctx = NULL;
+    struct tevent_req *req = NULL;
+    errno_t ret;
+
+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+    ret = sysdb_store_user(test_ctx->tctx->dom, "root", "pwd", 0, 0,
+                           NULL, NULL, NULL, "cn=root,dc=test", NULL,
+                           NULL, 1000, time(NULL));
+    assert_int_equal(ret, EOK);
+
+    req_mem_ctx = talloc_new(global_talloc_context);
+    check_leaks_push(req_mem_ctx);
+
+    req = cache_req_user_by_id_send(req_mem_ctx, test_ctx->tctx->ev,
+                                    test_ctx->rctx, test_ctx->ncache, 10, 0,
+                                    test_ctx->tctx->dom->name, 0);
+    assert_non_null(req);
+    tevent_req_set_callback(req, cache_req_user_by_id_test_done, test_ctx);
+
+    ret = test_ev_loop(test_ctx->tctx);
+    assert_int_equal(ret, ENOENT);
+    assert_true(check_leaks_pop(req_mem_ctx));
+    assert_false(test_ctx->dp_called);
+}
+
 void test_user_by_id_ncache(void **state)
 {
     struct cache_req_test_ctx *test_ctx = NULL;
@@ -1584,6 +1613,34 @@ void test_group_by_id_cache_midpoint(void **state)
     assert_int_equal(ldbgid, gid);
 }
 
+void test_group_by_id_cache_root(void **state)
+{
+    struct cache_req_test_ctx *test_ctx = NULL;
+    TALLOC_CTX *req_mem_ctx = NULL;
+    struct tevent_req *req = NULL;
+    errno_t ret;
+
+    test_ctx = talloc_get_type_abort(*state, struct cache_req_test_ctx);
+
+    ret = sysdb_store_group(test_ctx->tctx->dom, "root", 0, NULL,
+                            1000, time(NULL));
+    assert_int_equal(ret, EOK);
+
+    req_mem_ctx = talloc_new(global_talloc_context);
+    check_leaks_push(req_mem_ctx);
+
+    req = cache_req_group_by_id_send(req_mem_ctx, test_ctx->tctx->ev,
+                                     test_ctx->rctx, test_ctx->ncache, 10, 0,
+                                     test_ctx->tctx->dom->name, 0);
+    assert_non_null(req);
+    tevent_req_set_callback(req, cache_req_group_by_id_test_done, test_ctx);
+
+    ret = test_ev_loop(test_ctx->tctx);
+    assert_int_equal(ret, ENOENT);
+    assert_true(check_leaks_pop(req_mem_ctx));
+    assert_false(test_ctx->dp_called);
+}
+
 void test_group_by_id_ncache(void **state)
 {
     struct cache_req_test_ctx *test_ctx = NULL;
@@ -1714,6 +1771,7 @@ int main(int argc, const char *argv[])
         new_single_domain_test(user_by_id_cache_valid),
         new_single_domain_test(user_by_id_cache_expired),
         new_single_domain_test(user_by_id_cache_midpoint),
+        new_single_domain_test(user_by_id_cache_root),
         new_single_domain_test(user_by_id_ncache),
         new_single_domain_test(user_by_id_missing_found),
         new_single_domain_test(user_by_id_missing_notfound),
@@ -1733,6 +1791,7 @@ int main(int argc, const char *argv[])
         new_single_domain_test(group_by_id_cache_valid),
         new_single_domain_test(group_by_id_cache_expired),
         new_single_domain_test(group_by_id_cache_midpoint),
+        new_single_domain_test(group_by_id_cache_root),
         new_single_domain_test(group_by_id_ncache),
         new_single_domain_test(group_by_id_missing_found),
         new_single_domain_test(group_by_id_missing_notfound),
-- 
2.1.0

