[SSSD] [PATCHES] [PUSHED] Look up missing names in the simple access provider (sssd-1-9 backport)

Jakub Hrozek jhrozek at redhat.com
Tue Mar 19 21:44:24 UTC 2013


Attached are sssd-1-9 backports of fixes for CVE-2013-0287. They were
pushed already, but I would appreciate even retroactive review.
-------------- next part --------------
>From b63830b142053f99bfe954d4be5a2b0f68ce3a93 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Fri, 22 Feb 2013 11:01:38 +0100
Subject: [PATCH 1/4] Provide a be_get_account_info_send function

In order to resolve group names in the simple access provider we need to
contact the Data Provider in a generic fashion from the access provider.
We can't call any particular implementation (like sdap_generic_send())
because we have no idea what kind of provider is configured as the
id_provider.

This patch splits introduces the be_file_account_request() function into
the data_provider_be module and makes it public.

A future patch should make the be_get_account_info function use the
be_get_account_info_send function.
---
 src/providers/data_provider_be.c | 153 ++++++++++++++++++++++++++++++++++-----
 src/providers/dp_backend.h       |  15 ++++
 2 files changed, 149 insertions(+), 19 deletions(-)

diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
index b261bf8d456829a513ec352c8290d2011bd3526a..f85a04d09b5b41b17be611c333324f7207242979 100644
--- a/src/providers/data_provider_be.c
+++ b/src/providers/data_provider_be.c
@@ -717,6 +717,34 @@ static errno_t be_initgroups_prereq(struct be_req *be_req)
 }
 
 static errno_t
+be_file_account_request(struct be_req *be_req, struct be_acct_req *ar)
+{
+    errno_t ret;
+    struct be_ctx *be_ctx = be_req->be_ctx;
+
+    be_req->req_data = ar;
+
+    /* see if we need a pre request call, only done for initgroups for now */
+    if ((ar->entry_type & 0xFF) == BE_REQ_INITGROUPS) {
+        ret = be_initgroups_prereq(be_req);
+        if (ret) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Prerequest failed"));
+            return ret;
+        }
+    }
+
+    /* process request */
+    ret = be_file_request(be_ctx, be_req,
+                          be_ctx->bet_info[BET_ID].bet_ops->handler);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to file request"));
+        return ret;
+    }
+
+    return EOK;
+}
+
+static errno_t
 split_name_extended(TALLOC_CTX *mem_ctx,
                     const char *filter,
                     char **name,
@@ -742,6 +770,110 @@ split_name_extended(TALLOC_CTX *mem_ctx,
     return EOK;
 }
 
+static void
+be_get_account_info_done(struct be_req *be_req,
+                         int dp_err, int dp_ret,
+                         const char *errstr);
+
+struct be_get_account_info_state {
+    int err_maj;
+    int err_min;
+    const char *err_msg;
+};
+
+struct tevent_req *
+be_get_account_info_send(TALLOC_CTX *mem_ctx,
+                         struct tevent_context *ev,
+                         struct be_client *becli,
+                         struct be_ctx *be_ctx,
+                         struct be_acct_req *ar)
+{
+    struct tevent_req *req;
+    struct be_get_account_info_state *state;
+    struct be_req *be_req;
+    errno_t ret;
+
+    req = tevent_req_create(mem_ctx, &state,
+                            struct be_get_account_info_state);
+    if (!req) return NULL;
+
+    be_req = talloc_zero(mem_ctx, struct be_req);
+    if (be_req == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    be_req->becli = becli;
+    be_req->be_ctx = be_ctx;
+    be_req->fn = be_get_account_info_done;
+    be_req->pvt = req;
+
+    ret = be_file_account_request(be_req, ar);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    return req;
+
+done:
+    tevent_req_error(req, ret);
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static void
+be_get_account_info_done(struct be_req *be_req,
+                         int dp_err, int dp_ret,
+                         const char *errstr)
+{
+    struct tevent_req *req;
+    struct be_get_account_info_state *state;
+
+    req = talloc_get_type(be_req->pvt, struct tevent_req);
+    state = tevent_req_data(req, struct be_get_account_info_state);
+
+    state->err_maj = dp_err;
+    state->err_min = dp_ret;
+    if (errstr) {
+        state->err_msg = talloc_strdup(state, errstr);
+        if (state->err_msg == NULL) {
+            talloc_free(be_req);
+            tevent_req_error(req, ENOMEM);
+            return;
+        }
+    }
+
+    talloc_free(be_req);
+    tevent_req_done(req);
+}
+
+errno_t be_get_account_info_recv(struct tevent_req *req,
+                                 TALLOC_CTX *mem_ctx,
+                                 int *_err_maj,
+                                 int *_err_min,
+                                 const char **_err_msg)
+{
+    struct be_get_account_info_state *state;
+
+    state = tevent_req_data(req, struct be_get_account_info_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    if (_err_maj) {
+        *_err_maj = state->err_maj;
+    }
+
+    if (_err_min) {
+        *_err_min = state->err_min;
+    }
+
+    if (_err_msg) {
+        *_err_msg = talloc_steal(mem_ctx, state->err_msg);
+    }
+
+    return EOK;
+}
+
 static int be_get_account_info(DBusMessage *message, struct sbus_connection *conn)
 {
     struct be_acct_req *req;
@@ -845,8 +977,6 @@ static int be_get_account_info(DBusMessage *message, struct sbus_connection *con
         goto done;
     }
 
-    be_req->req_data = req;
-
     if ((attr_type != BE_ATTR_CORE) &&
         (attr_type != BE_ATTR_MEM) &&
         (attr_type != BE_ATTR_ALL)) {
@@ -893,26 +1023,11 @@ static int be_get_account_info(DBusMessage *message, struct sbus_connection *con
         goto done;
     }
 
-    /* see if we need a pre request call, only done for initgroups for now */
-    if ((type & 0xFF) == BE_REQ_INITGROUPS) {
-        ret = be_initgroups_prereq(be_req);
-        if (ret) {
-            err_maj = DP_ERR_FATAL;
-            err_min = ret;
-            err_msg = "Prerequest failed";
-            goto done;
-        }
-    }
-
-    /* process request */
-
-    ret = be_file_request(becli->bectx->bet_info[BET_ID].pvt_bet_data,
-                          be_req,
-                          becli->bectx->bet_info[BET_ID].bet_ops->handler);
+    ret = be_file_account_request(be_req, req);
     if (ret != EOK) {
         err_maj = DP_ERR_FATAL;
         err_min = ret;
-        err_msg = "Failed to file request";
+        err_msg = "Cannot file account request";
         goto done;
     }
 
diff --git a/src/providers/dp_backend.h b/src/providers/dp_backend.h
index 58a9b7490df8aab06a2a15f8c0fed9ac5ed33600..743b6f4ffe73fe9ec7404218184a7133aba054c6 100644
--- a/src/providers/dp_backend.h
+++ b/src/providers/dp_backend.h
@@ -258,4 +258,19 @@ int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx,
                                         const char *service_name);
 
 void reset_fo(struct be_ctx *be_ctx);
+
+/* Request account information */
+struct tevent_req *
+be_get_account_info_send(TALLOC_CTX *mem_ctx,
+                         struct tevent_context *ev,
+                         struct be_client *becli,
+                         struct be_ctx *be_ctx,
+                         struct be_acct_req *ar);
+
+errno_t be_get_account_info_recv(struct tevent_req *req,
+                                 TALLOC_CTX *mem_ctx,
+                                 int *_err_maj,
+                                 int *_err_min,
+                                 const char **_err_msg);
+
 #endif /* __DP_BACKEND_H___ */
-- 
1.8.1.4

-------------- next part --------------
>From 754b09b5444e6da88ed58d6deaed8b815e268b6b Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sun, 3 Mar 2013 21:43:44 +0100
Subject: [PATCH 2/4] Add unit tests for simple access test by groups

I realized that the current unit tests for the simple access provider
only tested the user directives. To have a baseline and be able to
detect new bugs in the upcoming patch, I implemented unit tests for the
group lists, too.
---
 src/tests/simple_access-tests.c | 283 +++++++++++++++++++++++++++++++++++-----
 1 file changed, 252 insertions(+), 31 deletions(-)

diff --git a/src/tests/simple_access-tests.c b/src/tests/simple_access-tests.c
index c61814eb54c1aa5138a1b45653f9384228c5456a..577c6d334edda513fd0f1e42a859ea333ba5ba23 100644
--- a/src/tests/simple_access-tests.c
+++ b/src/tests/simple_access-tests.c
@@ -30,39 +30,152 @@
 #include "providers/simple/simple_access.h"
 #include "tests/common.h"
 
+#define TESTS_PATH "tests_simple_access"
+#define TEST_CONF_FILE "tests_conf.ldb"
+
 const char *ulist_1[] = {"u1", "u2", NULL};
+const char *glist_1[] = {"g1", "g2", NULL};
 
-struct simple_ctx *ctx = NULL;
+struct simple_test_ctx *test_ctx = NULL;
+
+struct simple_test_ctx {
+    struct sysdb_ctx *sysdb;
+    struct confdb_ctx *confdb;
+
+    struct simple_ctx *ctx;
+};
 
 void setup_simple(void)
 {
-    fail_unless(ctx == NULL, "Simple context already initialized.");
-    ctx = talloc_zero(NULL, struct simple_ctx);
-    fail_unless(ctx != NULL, "Cannot create simple context.");
+    errno_t ret;
+    char *conf_db;
+    const char *val[2];
+    val[1] = NULL;
 
-    ctx->domain = talloc_zero(ctx, struct sss_domain_info);
-    fail_unless(ctx != NULL, "Cannot create domain in simple context.");
-    ctx->domain->case_sensitive = true;
+    /* Create tests directory if it doesn't exist */
+    /* (relative to current dir) */
+    ret = mkdir(TESTS_PATH, 0775);
+    fail_if(ret == -1 && errno != EEXIST,
+            "Could not create %s directory", TESTS_PATH);
+
+    fail_unless(test_ctx == NULL, "Simple context already initialized.");
+    test_ctx = talloc_zero(NULL, struct simple_test_ctx);
+    fail_unless(test_ctx != NULL, "Cannot create simple test context.");
+
+    test_ctx->ctx = talloc_zero(test_ctx, struct simple_ctx);
+    fail_unless(test_ctx->ctx != NULL, "Cannot create simple context.");
+
+    conf_db = talloc_asprintf(test_ctx, "%s/%s", TESTS_PATH, TEST_CONF_FILE);
+    fail_if(conf_db == NULL, "Out of memory, aborting!");
+    DEBUG(SSSDBG_TRACE_LIBS, ("CONFDB: %s\n", conf_db));
+
+    /* Connect to the conf db */
+    ret = confdb_init(test_ctx, &test_ctx->confdb, conf_db);
+    fail_if(ret != EOK, "Could not initialize connection to the confdb");
+
+    val[0] = "LOCAL";
+    ret = confdb_add_param(test_ctx->confdb, true,
+                           "config/sssd", "domains", val);
+    fail_if(ret != EOK, "Could not initialize domains placeholder");
+
+    val[0] = "local";
+    ret = confdb_add_param(test_ctx->confdb, true,
+                           "config/domain/LOCAL", "id_provider", val);
+    fail_if(ret != EOK, "Could not initialize provider");
+
+    val[0] = "TRUE";
+    ret = confdb_add_param(test_ctx->confdb, true,
+                           "config/domain/LOCAL", "enumerate", val);
+    fail_if(ret != EOK, "Could not initialize LOCAL domain");
+
+    val[0] = "TRUE";
+    ret = confdb_add_param(test_ctx->confdb, true,
+                           "config/domain/LOCAL", "cache_credentials", val);
+    fail_if(ret != EOK, "Could not initialize LOCAL domain");
+
+    ret = sysdb_init_domain_and_sysdb(test_ctx, test_ctx->confdb, "local",
+                                      TESTS_PATH,
+                                      &test_ctx->ctx->domain, &test_ctx->ctx->sysdb);
+    fail_if(ret != EOK, "Could not initialize connection to the sysdb (%d)", ret);
+    test_ctx->ctx->domain->case_sensitive = true;
 }
 
 void teardown_simple(void)
 {
     int ret;
-    fail_unless(ctx != NULL, "Simple context already freed.");
-    ret = talloc_free(ctx);
-    ctx = NULL;
+    fail_unless(test_ctx != NULL, "Simple context already freed.");
+    ret = talloc_free(test_ctx);
+    test_ctx = NULL;
     fail_unless(ret == 0, "Connot free simple context.");
 }
 
+void setup_simple_group(void)
+{
+    errno_t ret;
+
+    setup_simple();
+
+    /* Add test users u1 and u2 that would be members of test groups
+     * g1 and g2 respectively */
+    ret = sysdb_store_user(test_ctx->ctx->sysdb,
+                           "u1", NULL, 123, 0, "u1", "/home/u1",
+                           "/bin/bash", NULL, NULL, NULL, -1, 0);
+    fail_if(ret != EOK, "Could not add u1");
+
+    ret = sysdb_store_user(test_ctx->ctx->sysdb,
+                           "u2", NULL, 456, 0, "u1", "/home/u1",
+                           "/bin/bash", NULL, NULL, NULL, -1, 0);
+    fail_if(ret != EOK, "Could not add u2");
+
+    ret = sysdb_store_user(test_ctx->ctx->sysdb,
+                           "u3", NULL, 789, 0, "u1", "/home/u1",
+                           "/bin/bash", NULL, NULL, NULL, -1, 0);
+    fail_if(ret != EOK, "Could not add u3");
+
+    ret = sysdb_add_group(test_ctx->ctx->sysdb,
+                          "g1", 321, NULL, 0, 0);
+    fail_if(ret != EOK, "Could not add g1");
+
+    ret = sysdb_add_group(test_ctx->ctx->sysdb,
+                          "g2", 654, NULL, 0, 0);
+    fail_if(ret != EOK, "Could not add g2");
+
+    ret = sysdb_add_group_member(test_ctx->ctx->sysdb,
+                                 "g1", "u1", SYSDB_MEMBER_USER);
+    fail_if(ret != EOK, "Could not add u1 to g1");
+
+    ret = sysdb_add_group_member(test_ctx->ctx->sysdb,
+                                 "g2", "u2", SYSDB_MEMBER_USER);
+    fail_if(ret != EOK, "Could not add u2 to g2");
+}
+
+void teardown_simple_group(void)
+{
+    errno_t ret;
+
+    ret = sysdb_delete_user(test_ctx->ctx->sysdb, "u1", 0);
+    fail_if(ret != EOK, "Could not delete u1");
+    ret = sysdb_delete_user(test_ctx->ctx->sysdb, "u2", 0);
+    fail_if(ret != EOK, "Could not delete u2");
+    ret = sysdb_delete_user(test_ctx->ctx->sysdb, "u3", 0);
+    fail_if(ret != EOK, "Could not delete u3");
+    ret = sysdb_delete_group(test_ctx->ctx->sysdb, "g1", 0);
+    fail_if(ret != EOK, "Could not delete g1");
+    ret = sysdb_delete_group(test_ctx->ctx->sysdb, "g2", 0);
+    fail_if(ret != EOK, "Could not delete g2");
+
+    teardown_simple();
+}
+
 START_TEST(test_both_empty)
 {
     int ret;
     bool access_granted = false;
 
-    ctx->allow_users = NULL;
-    ctx->deny_users = NULL;
+    test_ctx->ctx->allow_users = NULL;
+    test_ctx->ctx->deny_users = NULL;
 
-    ret = simple_access_check(ctx, "u1", &access_granted);
+    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
     fail_unless(ret == EOK, "access_simple_check failed.");
     fail_unless(access_granted == true, "Access denied "
                                         "while both lists are empty.");
@@ -74,15 +187,15 @@ START_TEST(test_allow_empty)
     int ret;
     bool access_granted = true;
 
-    ctx->allow_users = NULL;
-    ctx->deny_users = discard_const(ulist_1);
+    test_ctx->ctx->allow_users = NULL;
+    test_ctx->ctx->deny_users = discard_const(ulist_1);
 
-    ret = simple_access_check(ctx, "u1", &access_granted);
+    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
     fail_unless(ret == EOK, "access_simple_check failed.");
     fail_unless(access_granted == false, "Access granted "
                                          "while user is in deny list.");
 
-    ret = simple_access_check(ctx, "u3", &access_granted);
+    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
     fail_unless(ret == EOK, "access_simple_check failed.");
     fail_unless(access_granted == true, "Access denied "
                                          "while user is not in deny list.");
@@ -94,15 +207,15 @@ START_TEST(test_deny_empty)
     int ret;
     bool access_granted = false;
 
-    ctx->allow_users = discard_const(ulist_1);
-    ctx->deny_users = NULL;
+    test_ctx->ctx->allow_users = discard_const(ulist_1);
+    test_ctx->ctx->deny_users = NULL;
 
-    ret = simple_access_check(ctx, "u1", &access_granted);
+    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
     fail_unless(ret == EOK, "access_simple_check failed.");
     fail_unless(access_granted == true, "Access denied "
                                         "while user is in allow list.");
 
-    ret = simple_access_check(ctx, "u3", &access_granted);
+    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
     fail_unless(ret == EOK, "access_simple_check failed.");
     fail_unless(access_granted == false, "Access granted "
                                         "while user is not in allow list.");
@@ -114,15 +227,15 @@ START_TEST(test_both_set)
     int ret;
     bool access_granted = false;
 
-    ctx->allow_users = discard_const(ulist_1);
-    ctx->deny_users = discard_const(ulist_1);
+    test_ctx->ctx->allow_users = discard_const(ulist_1);
+    test_ctx->ctx->deny_users = discard_const(ulist_1);
 
-    ret = simple_access_check(ctx, "u1", &access_granted);
+    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
     fail_unless(ret == EOK, "access_simple_check failed.");
     fail_unless(access_granted == false, "Access granted "
                                          "while user is in deny list.");
 
-    ret = simple_access_check(ctx, "u3", &access_granted);
+    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
     fail_unless(ret == EOK, "access_simple_check failed.");
     fail_unless(access_granted == false, "Access granted "
                                         "while user is not in allow list.");
@@ -134,18 +247,18 @@ START_TEST(test_case)
     int ret;
     bool access_granted = false;
 
-    ctx->allow_users = discard_const(ulist_1);
-    ctx->deny_users = NULL;
+    test_ctx->ctx->allow_users = discard_const(ulist_1);
+    test_ctx->ctx->deny_users = NULL;
 
-    ret = simple_access_check(ctx, "U1", &access_granted);
+    ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
     fail_unless(ret == EOK, "access_simple_check failed.");
     fail_unless(access_granted == false, "Access granted "
                                          "for user with different case "
                                          "in case-sensitive domain");
 
-    ctx->domain->case_sensitive = false;
+    test_ctx->ctx->domain->case_sensitive = false;
 
-    ret = simple_access_check(ctx, "U1", &access_granted);
+    ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
     fail_unless(ret == EOK, "access_simple_check failed.");
     fail_unless(access_granted == true, "Access denied "
                                         "for user with different case "
@@ -153,11 +266,95 @@ START_TEST(test_case)
 }
 END_TEST
 
+START_TEST(test_group_allow_empty)
+{
+    int ret;
+    bool access_granted = true;
+
+    test_ctx->ctx->allow_groups = NULL;
+    test_ctx->ctx->deny_groups = discard_const(glist_1);
+
+    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+    fail_unless(ret == EOK, "access_simple_check failed.");
+    fail_unless(access_granted == false, "Access granted "
+                                         "while group is in deny list.");
+
+    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+    fail_unless(ret == EOK, "access_simple_check failed.");
+    fail_unless(access_granted == true, "Access denied "
+                                         "while group is not in deny list.");
+}
+END_TEST
+
+START_TEST(test_group_deny_empty)
+{
+    int ret;
+    bool access_granted = false;
+
+    test_ctx->ctx->allow_groups = discard_const(glist_1);
+    test_ctx->ctx->deny_groups = NULL;
+
+    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+    fail_unless(ret == EOK, "access_simple_check failed.");
+    fail_unless(access_granted == true, "Access denied "
+                                        "while group is in allow list.");
+
+    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+    fail_unless(ret == EOK, "access_simple_check failed.");
+    fail_unless(access_granted == false, "Access granted "
+                                        "while group is not in allow list.");
+}
+END_TEST
+
+START_TEST(test_group_both_set)
+{
+    int ret;
+    bool access_granted = false;
+
+    test_ctx->ctx->allow_groups = discard_const(ulist_1);
+    test_ctx->ctx->deny_groups = discard_const(ulist_1);
+
+    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
+    fail_unless(ret == EOK, "access_simple_check failed.");
+    fail_unless(access_granted == false, "Access granted "
+                                         "while group is in deny list.");
+
+    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
+    fail_unless(ret == EOK, "access_simple_check failed.");
+    fail_unless(access_granted == false, "Access granted "
+                                        "while group is not in allow list.");
+}
+END_TEST
+
+START_TEST(test_group_case)
+{
+    int ret;
+    bool access_granted = false;
+
+    test_ctx->ctx->allow_groups = discard_const(ulist_1);
+    test_ctx->ctx->deny_groups = NULL;
+
+    ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
+    fail_unless(ret == EOK, "access_simple_check failed.");
+    fail_unless(access_granted == false, "Access granted "
+                                         "for group with different case "
+                                         "in case-sensitive domain");
+
+    test_ctx->ctx->domain->case_sensitive = false;
+
+    ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
+    fail_unless(ret == EOK, "access_simple_check failed.");
+    fail_unless(access_granted == true, "Access denied "
+                                        "for group with different case "
+                                        "in case-insensitive domain");
+}
+END_TEST
+
 Suite *access_simple_suite (void)
 {
     Suite *s = suite_create("access_simple");
 
-    TCase *tc_allow_deny = tcase_create("allow/deny");
+    TCase *tc_allow_deny = tcase_create("user allow/deny");
     tcase_add_checked_fixture(tc_allow_deny, setup_simple, teardown_simple);
     tcase_add_test(tc_allow_deny, test_both_empty);
     tcase_add_test(tc_allow_deny, test_allow_empty);
@@ -166,6 +363,15 @@ Suite *access_simple_suite (void)
     tcase_add_test(tc_allow_deny, test_case);
     suite_add_tcase(s, tc_allow_deny);
 
+    TCase *tc_grp_allow_deny = tcase_create("group allow/deny");
+    tcase_add_checked_fixture(tc_grp_allow_deny,
+                              setup_simple_group, teardown_simple_group);
+    tcase_add_test(tc_grp_allow_deny, test_group_allow_empty);
+    tcase_add_test(tc_grp_allow_deny, test_group_deny_empty);
+    tcase_add_test(tc_grp_allow_deny, test_group_both_set);
+    tcase_add_test(tc_grp_allow_deny, test_group_case);
+    suite_add_tcase(s, tc_grp_allow_deny);
+
     return s;
 }
 
@@ -174,6 +380,7 @@ int main(int argc, const char *argv[])
     int opt;
     poptContext pc;
     int number_failed;
+    int ret;
 
     struct poptOption long_options[] = {
         POPT_AUTOHELP
@@ -205,6 +412,20 @@ int main(int argc, const char *argv[])
     srunner_run_all(sr, CK_ENV);
     number_failed = srunner_ntests_failed(sr);
     srunner_free(sr);
+
+    ret = unlink(TESTS_PATH"/"TEST_CONF_FILE);
+    if (ret != EOK) {
+        fprintf(stderr, "Could not delete the test config ldb file (%d) (%s)\n",
+                errno, strerror(errno));
+        return EXIT_FAILURE;
+    }
+    ret = unlink(TESTS_PATH"/"LOCAL_SYSDB_FILE);
+    if (ret != EOK) {
+        fprintf(stderr, "Could not delete the test config ldb file (%d) (%s)\n",
+                errno, strerror(errno));
+        return EXIT_FAILURE;
+    }
+
     return (number_failed==0 ? EXIT_SUCCESS : EXIT_FAILURE);
 }
 
-- 
1.8.1.4

-------------- next part --------------
>From 26590d31f492dbbd36be6d0bde46a4bd3b221edb Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Mon, 4 Mar 2013 16:37:04 +0100
Subject: [PATCH 3/4] Do not compile main() in DP if UNIT_TESTING is defined

The simple access provider unit tests now need to link against the Data
Provider when they start using the be_file_account_request() function.
But then we would start having conflicts as at least the main()
functions would clash.

If UNIT_TESTING is defined, then the data_provider_be.c module does not
contain the main() function and can be linked against directly from
another module that contains its own main() function
---
 src/providers/data_provider_be.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/providers/data_provider_be.c b/src/providers/data_provider_be.c
index f85a04d09b5b41b17be611c333324f7207242979..33590aeef0231427642916c6a2f9bc391c165c21 100644
--- a/src/providers/data_provider_be.c
+++ b/src/providers/data_provider_be.c
@@ -2651,6 +2651,7 @@ fail:
     return ret;
 }
 
+#ifndef UNIT_TESTING
 int main(int argc, const char *argv[])
 {
     int opt;
@@ -2732,6 +2733,7 @@ int main(int argc, const char *argv[])
 
     return 0;
 }
+#endif
 
 static int data_provider_res_init(DBusMessage *message,
                                   struct sbus_connection *conn)
-- 
1.8.1.4

-------------- next part --------------
>From 8b8019fe3dd1564fba657e219ec20ff816c7ffdb Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek at redhat.com>
Date: Sat, 23 Feb 2013 10:44:54 +0100
Subject: [PATCH 4/4] Resolve GIDs in the simple access provider

Changes the simple access provider's interface to be asynchronous. When
the simple access provider encounters a group that has gid, but no
meaningful name, it attempts to resolve the name using the
be_file_account_request function.

Some providers (like the AD provider) might perform initgroups
without resolving the group names. In order for the simple access
provider to work correctly, we need to resolve the groups before
performing the access check. In AD provider, the situation is
even more tricky b/c the groups HAVE name, but their name
attribute is set to SID and they are set as non-POSIX
---
 Makefile.am                                |  17 +-
 src/providers/simple/simple_access.c       | 230 ++-------
 src/providers/simple/simple_access.h       |  11 +-
 src/providers/simple/simple_access_check.c | 723 +++++++++++++++++++++++++++++
 src/tests/simple_access-tests.c            | 373 ++++++++++-----
 5 files changed, 1040 insertions(+), 314 deletions(-)
 create mode 100644 src/providers/simple/simple_access_check.c

diff --git a/Makefile.am b/Makefile.am
index dc0465a8cb6b441cfc810a5da8c448b034cc4b7a..eea535e81ac572713810f8b97dacc58ed221b440 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1008,14 +1008,22 @@ ad_ldap_opt_tests_LDADD = \
 simple_access_tests_SOURCES = \
     src/tests/simple_access-tests.c \
     src/tests/common.c \
-    src/providers/simple/simple_access.c
+    src/providers/simple/simple_access_check.c \
+    src/providers/data_provider_be.c \
+    src/providers/data_provider_fo.c \
+    src/providers/data_provider_callbacks.c \
+    $(SSSD_FAILOVER_OBJ)
 simple_access_tests_CFLAGS = \
     $(AM_CFLAGS) \
-    $(CHECK_CFLAGS)
+    $(CHECK_CFLAGS) \
+    -DUNIT_TESTING
 simple_access_tests_LDADD = \
     $(SSSD_LIBS) \
+    $(CARES_LIBS) \
     $(CHECK_LIBS) \
-    libsss_util.la
+    $(PAM_LIBS) \
+    libsss_util.la \
+    libsss_test_common.la
 
 util_tests_SOURCES = \
     src/tests/util-tests.c
@@ -1347,7 +1355,8 @@ libsss_proxy_la_LDFLAGS = \
     -module
 
 libsss_simple_la_SOURCES = \
-    src/providers/simple/simple_access.c
+    src/providers/simple/simple_access.c \
+    src/providers/simple/simple_access_check.c
 libsss_simple_la_CFLAGS = \
     $(AM_CFLAGS)
 libsss_simple_la_LIBADD = \
diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c
index 70d1f07282d472089a2c6eac05479c39eb03c606..d53a04b4d73bfa4fae23b4522d01cf1e947e7d64 100644
--- a/src/providers/simple/simple_access.c
+++ b/src/providers/simple/simple_access.c
@@ -35,211 +35,13 @@
 #define CONFDB_SIMPLE_ALLOW_GROUPS "simple_allow_groups"
 #define CONFDB_SIMPLE_DENY_GROUPS "simple_deny_groups"
 
-errno_t simple_access_check(struct simple_ctx *ctx, const char *username,
-                            bool *access_granted)
-{
-    int i, j;
-    errno_t ret;
-    TALLOC_CTX *tmp_ctx = NULL;
-    const char *user_attrs[] = { SYSDB_MEMBEROF,
-                                 SYSDB_GIDNUM,
-                                 NULL };
-    const char *group_attrs[] = { SYSDB_NAME,
-                                  NULL };
-    struct ldb_message *msg;
-    struct ldb_message_element *el;
-    char **groups;
-    const char *primary_group;
-    gid_t gid;
-    bool matched;
-    bool cs = ctx->domain->case_sensitive;
-
-    *access_granted = false;
-
-    /* First, check whether the user is in the allowed users list */
-    if (ctx->allow_users != NULL) {
-        for(i = 0; ctx->allow_users[i] != NULL; i++) {
-            if (sss_string_equal(cs, username, ctx->allow_users[i])) {
-                DEBUG(9, ("User [%s] found in allow list, access granted.\n",
-                      username));
-
-                /* Do not return immediately on explicit allow
-                 * We need to make sure none of the user's groups
-                 * are denied.
-                 */
-                *access_granted = true;
-            }
-        }
-    } else if (!ctx->allow_groups) {
-        /* If neither allow rule is in place, we'll assume allowed
-         * unless a deny rule disables us below.
-         */
-        *access_granted = true;
-    }
-
-    /* Next check whether this user has been specifically denied */
-    if (ctx->deny_users != NULL) {
-        for(i = 0; ctx->deny_users[i] != NULL; i++) {
-            if (sss_string_equal(cs, username, ctx->deny_users[i])) {
-                DEBUG(9, ("User [%s] found in deny list, access denied.\n",
-                      username));
-
-                /* Return immediately on explicit denial */
-                *access_granted = false;
-                return EOK;
-            }
-        }
-    }
-
-    if (!ctx->allow_groups && !ctx->deny_groups) {
-        /* There are no group restrictions, so just return
-         * here with whatever we've decided.
-         */
-        return EOK;
-    }
-
-    /* Now get a list of this user's groups and check those against the
-     * simple_allow_groups list.
-     */
-    tmp_ctx = talloc_new(NULL);
-    if (!tmp_ctx) {
-        ret = ENOMEM;
-        goto done;
-    }
-
-    ret = sysdb_search_user_by_name(tmp_ctx, ctx->sysdb,
-                                    username, user_attrs, &msg);
-    if (ret != EOK) {
-        DEBUG(1, ("Could not look up username [%s]: [%d][%s]\n",
-                  username, ret, strerror(ret)));
-        goto done;
-    }
-
-    /* Construct a list of the user's groups */
-    el = ldb_msg_find_element(msg, SYSDB_MEMBEROF);
-    if (el && el->num_values) {
-        /* Get the groups from the memberOf entries
-         * Allocate the array with room for both the NULL
-         * terminator and the primary group
-         */
-        groups = talloc_array(tmp_ctx, char *, el->num_values + 2);
-        if (!groups) {
-            ret = ENOMEM;
-            goto done;
-        }
-
-        for (j = 0; j < el->num_values; j++) {
-            ret = sysdb_group_dn_name(
-                    ctx->sysdb, tmp_ctx,
-                    (char *)el->values[j].data,
-                    &groups[j]);
-            if (ret != EOK) {
-                goto done;
-            }
-        }
-    } else {
-        /* User is not a member of any groups except primary */
-        groups = talloc_array(tmp_ctx, char *, 2);
-        if (!groups) {
-            ret = ENOMEM;
-            goto done;
-        }
-        j = 0;
-    }
-
-    /* Get the user's primary group */
-    gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
-    if (!gid) {
-        ret = EINVAL;
-        goto done;
-    }
-    talloc_zfree(msg);
-
-    ret = sysdb_search_group_by_gid(tmp_ctx, ctx->sysdb,
-                                    gid, group_attrs, &msg);
-    if (ret != EOK) {
-        DEBUG(1, ("Could not look up primary group [%lu]: [%d][%s]\n",
-                  gid, ret, strerror(ret)));
-        /* We have to treat this as non-fatal, because the primary
-         * group may be local to the machine and not available in
-         * our ID provider.
-         */
-    } else {
-        primary_group = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
-        if (!primary_group) {
-            ret = EINVAL;
-            goto done;
-        }
-
-        groups[j] = talloc_strdup(tmp_ctx, primary_group);
-        if (!groups[j]) {
-            ret = ENOMEM;
-            goto done;
-        }
-        j++;
-
-        talloc_zfree(msg);
-    }
-
-    groups[j] = NULL;
-
-    /* Now process allow and deny group rules
-     * If access was already granted above, we'll skip
-     * this redundant rule check
-     */
-    if (ctx->allow_groups && !*access_granted) {
-        matched = false;
-        for (i = 0; ctx->allow_groups[i]; i++) {
-            for(j = 0; groups[j]; j++) {
-                if (sss_string_equal(cs, groups[j], ctx->allow_groups[i])) {
-                    matched = true;
-                    break;
-                }
-            }
-
-            /* If any group has matched, we can skip out on the
-             * processing early
-             */
-            if (matched) {
-                *access_granted = true;
-                break;
-            }
-        }
-    }
-
-    /* Finally, process the deny group rules */
-    if (ctx->deny_groups) {
-        matched = false;
-        for (i = 0; ctx->deny_groups[i]; i++) {
-            for(j = 0; groups[j]; j++) {
-                if (sss_string_equal(cs, groups[j], ctx->deny_groups[i])) {
-                    matched = true;
-                    break;
-                }
-            }
-
-            /* If any group has matched, we can skip out on the
-             * processing early
-             */
-            if (matched) {
-                *access_granted = false;
-                break;
-            }
-        }
-    }
-
-    ret = EOK;
-
-done:
-    talloc_free(tmp_ctx);
-    return ret;
-}
+static void simple_access_check(struct tevent_req *req);
 
 void simple_access_handler(struct be_req *be_req)
 {
-    int ret;
-    bool access_granted = false;
+    struct be_ctx *be_ctx = be_req->be_ctx;
     struct pam_data *pd;
+    struct tevent_req *req;
     struct simple_ctx *ctx;
 
     pd = talloc_get_type(be_req->req_data, struct pam_data);
@@ -255,7 +57,30 @@ void simple_access_handler(struct be_req *be_req)
     ctx = talloc_get_type(be_req->be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
                           struct simple_ctx);
 
-    ret = simple_access_check(ctx, pd->user, &access_granted);
+    req = simple_access_check_send(be_req, be_ctx->ev, ctx, pd->user);
+    if (!req) {
+        pd->pam_status = PAM_SYSTEM_ERR;
+        goto done;
+    }
+    tevent_req_set_callback(req, simple_access_check, be_req);
+    return;
+
+done:
+    be_req->fn(be_req, DP_ERR_OK, pd->pam_status, NULL);
+}
+
+static void simple_access_check(struct tevent_req *req)
+{
+    bool access_granted = false;
+    errno_t ret;
+    struct pam_data *pd;
+    struct be_req *be_req;
+
+    be_req = tevent_req_callback_data(req, struct be_req);
+    pd = talloc_get_type(be_req->req_data, struct pam_data);
+
+    ret = simple_access_check_recv(req, &access_granted);
+    talloc_free(req);
     if (ret != EOK) {
         pd->pam_status = PAM_SYSTEM_ERR;
         goto done;
@@ -290,6 +115,7 @@ int sssm_simple_access_init(struct be_ctx *bectx, struct bet_ops **ops,
 
     ctx->sysdb = bectx->sysdb;
     ctx->domain = bectx->domain;
+    ctx->be_ctx = bectx;
 
     /* Users */
     ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path,
diff --git a/src/providers/simple/simple_access.h b/src/providers/simple/simple_access.h
index abcf61ac29f31b3e424dd12340759ee6cc8c9489..1de9d898bdc3a58bbce2e2c74a02796fa5c3c609 100644
--- a/src/providers/simple/simple_access.h
+++ b/src/providers/simple/simple_access.h
@@ -29,6 +29,7 @@
 struct simple_ctx {
     struct sysdb_ctx *sysdb;
     struct sss_domain_info *domain;
+    struct be_ctx *be_ctx;
 
     char **allow_users;
     char **deny_users;
@@ -36,6 +37,12 @@ struct simple_ctx {
     char **deny_groups;
 };
 
-errno_t simple_access_check(struct simple_ctx *ctx, const char *username,
-                            bool *access_granted);
+struct tevent_req *simple_access_check_send(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct simple_ctx *ctx,
+                                            const char *username);
+
+errno_t simple_access_check_recv(struct tevent_req *req,
+                                 bool *access_granted);
+
 #endif /* __SIMPLE_ACCESS_H__ */
diff --git a/src/providers/simple/simple_access_check.c b/src/providers/simple/simple_access_check.c
new file mode 100644
index 0000000000000000000000000000000000000000..a9e8f632e8af6aae467571db6f093a5b07b5ed91
--- /dev/null
+++ b/src/providers/simple/simple_access_check.c
@@ -0,0 +1,723 @@
+/*
+   SSSD
+
+   Simple access control
+
+   Copyright (C) Sumit Bose <sbose at redhat.com> 2010
+
+   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 "providers/dp_backend.h"
+#include "providers/simple/simple_access.h"
+#include "util/sss_utf8.h"
+#include "db/sysdb.h"
+
+static bool
+is_posix(const struct ldb_message *group)
+{
+    const char *val;
+
+    val = ldb_msg_find_attr_as_string(group, SYSDB_POSIX, NULL);
+    if (!val || /* Groups are posix by default */
+        strcasecmp(val, "TRUE") == 0) {
+        return true;
+    }
+
+    return false;
+}
+
+/* Returns EOK if the result is definitive, EAGAIN if only partial result
+ */
+static errno_t
+simple_check_users(struct simple_ctx *ctx, const char *username,
+                   bool *access_granted)
+{
+    int i;
+    bool cs = ctx->domain->case_sensitive;
+
+    /* First, check whether the user is in the allowed users list */
+    if (ctx->allow_users != NULL) {
+        for(i = 0; ctx->allow_users[i] != NULL; i++) {
+            if (sss_string_equal(cs, username, ctx->allow_users[i])) {
+                DEBUG(SSSDBG_TRACE_LIBS,
+                      ("User [%s] found in allow list, access granted.\n",
+                      username));
+
+                /* Do not return immediately on explicit allow
+                 * We need to make sure none of the user's groups
+                 * are denied.
+                 */
+                *access_granted = true;
+            }
+        }
+    } else if (!ctx->allow_groups) {
+        /* If neither allow rule is in place, we'll assume allowed
+         * unless a deny rule disables us below.
+         */
+        DEBUG(SSSDBG_TRACE_LIBS,
+              ("No allow rule, assumuing allow unless explicitly denied\n"));
+        *access_granted = true;
+    }
+
+    /* Next check whether this user has been specifically denied */
+    if (ctx->deny_users != NULL) {
+        for(i = 0; ctx->deny_users[i] != NULL; i++) {
+            if (sss_string_equal(cs, username, ctx->deny_users[i])) {
+                DEBUG(SSSDBG_TRACE_LIBS,
+                      ("User [%s] found in deny list, access denied.\n",
+                      username));
+
+                /* Return immediately on explicit denial */
+                *access_granted = false;
+                return EOK;
+            }
+        }
+    }
+
+    return EAGAIN;
+}
+
+static errno_t
+simple_check_groups(struct simple_ctx *ctx, const char *username,
+                    const char **group_names, bool *access_granted)
+{
+    bool matched;
+    int i, j;
+    bool cs = ctx->domain->case_sensitive;
+
+    /* Now process allow and deny group rules
+     * If access was already granted above, we'll skip
+     * this redundant rule check
+     */
+    if (ctx->allow_groups && !*access_granted) {
+        matched = false;
+        for (i = 0; ctx->allow_groups[i]; i++) {
+            for(j = 0; group_names[j]; j++) {
+                if (sss_string_equal(cs, group_names[j], ctx->allow_groups[i])) {
+                    matched = true;
+                    break;
+                }
+            }
+
+            /* If any group has matched, we can skip out on the
+             * processing early
+             */
+            if (matched) {
+                DEBUG(SSSDBG_TRACE_LIBS,
+                      ("Group [%s] found in allow list, access granted.\n",
+                      group_names[j]));
+                *access_granted = true;
+                break;
+            }
+        }
+    }
+
+    /* Finally, process the deny group rules */
+    if (ctx->deny_groups) {
+        matched = false;
+        for (i = 0; ctx->deny_groups[i]; i++) {
+            for(j = 0; group_names[j]; j++) {
+                if (sss_string_equal(cs, group_names[j], ctx->deny_groups[i])) {
+                    matched = true;
+                    break;
+                }
+            }
+
+            /* If any group has matched, we can skip out on the
+             * processing early
+             */
+            if (matched) {
+                DEBUG(SSSDBG_TRACE_LIBS,
+                      ("Group [%s] found in deny list, access denied.\n",
+                      group_names[j]));
+                *access_granted = false;
+                break;
+            }
+        }
+    }
+
+    return EOK;
+}
+
+struct simple_resolve_group_state {
+    gid_t gid;
+    struct simple_ctx *ctx;
+
+    const char *name;
+};
+
+static errno_t
+simple_resolve_group_check(struct simple_resolve_group_state *state);
+static void simple_resolve_group_done(struct tevent_req *subreq);
+
+static struct tevent_req *
+simple_resolve_group_send(TALLOC_CTX *mem_ctx,
+                          struct tevent_context *ev,
+                          struct simple_ctx *ctx,
+                          gid_t gid)
+{
+    errno_t ret;
+    struct tevent_req *req;
+    struct tevent_req *subreq;
+    struct simple_resolve_group_state *state;
+    struct be_acct_req *ar;
+
+    req = tevent_req_create(mem_ctx, &state,
+                            struct simple_resolve_group_state);
+    if (!req) return NULL;
+
+    state->gid = gid;
+    state->ctx = ctx;
+
+    /* First check if the group was updated already. If it was (maybe its
+     * parent was updated first), then just shortcut */
+    ret = simple_resolve_group_check(state);
+    if (ret == EOK) {
+        DEBUG(SSSDBG_TRACE_LIBS, ("Group already updated\n"));
+        ret = EOK;
+        goto done;
+    } else if (ret != EAGAIN) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Cannot check if group was already updated\n"));
+        goto done;
+    }
+    /* EAGAIN - still needs update */
+
+    ar = talloc(state, struct be_acct_req);
+    if (!ar) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    ar->entry_type = BE_REQ_GROUP;
+    ar->attr_type = BE_ATTR_CORE;
+    ar->filter_type = BE_FILTER_IDNUM;
+    ar->filter_value = talloc_asprintf(ar, "%llu", (unsigned long long) gid);
+    ar->domain = talloc_strdup(ar, ctx->domain->name);
+    if (!ar->domain || !ar->filter_value) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    subreq = be_get_account_info_send(state, ev, NULL, ctx->be_ctx, ar);
+    if (!subreq) {
+        ret = ENOMEM;
+        goto done;
+    }
+    tevent_req_set_callback(subreq, simple_resolve_group_done, req);
+
+    return req;
+
+done:
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static errno_t
+simple_resolve_group_check(struct simple_resolve_group_state *state)
+{
+    errno_t ret;
+    struct ldb_message *group;
+    const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
+                                  SYSDB_GIDNUM, NULL };
+
+    /* Check the cache by GID again and fetch the name */
+    ret = sysdb_search_group_by_gid(state, state->ctx->domain->sysdb,
+                                    state->gid, group_attrs, &group);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+               ("Could not look up group by gid [%lu]: [%d][%s]\n",
+               state->gid, ret, strerror(ret)));
+        return ret;
+    }
+
+    state->name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
+    if (!state->name) {
+        DEBUG(SSSDBG_OP_FAILURE, ("No group name\n"));
+        return ENOENT;
+    }
+
+    if (is_posix(group) == false) {
+        DEBUG(SSSDBG_TRACE_LIBS,
+              ("The group is still non-POSIX\n"));
+        return EAGAIN;
+    }
+
+    DEBUG(SSSDBG_TRACE_LIBS, ("Got POSIX group\n"));
+    return EOK;
+}
+
+static void simple_resolve_group_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req;
+    struct simple_resolve_group_state *state;
+    int err_maj;
+    int err_min;
+    errno_t ret;
+    const char *err_msg;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct simple_resolve_group_state);
+
+    ret = be_get_account_info_recv(subreq, state,
+                                   &err_maj, &err_min, &err_msg);
+    talloc_zfree(subreq);
+    if (ret) {
+        DEBUG(SSSDBG_OP_FAILURE, ("be_get_account_info_recv failed\n"));
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    if (err_maj) {
+        DEBUG(SSSDBG_MINOR_FAILURE,
+              ("Cannot refresh data from DP: %u,%u: %s\n",
+              err_maj, err_min, err_msg));
+        tevent_req_error(req, EIO);
+        return;
+    }
+
+    /* Check the cache by GID again and fetch the name */
+    ret = simple_resolve_group_check(state);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Refresh failed\n"));
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+static errno_t
+simple_resolve_group_recv(struct tevent_req *req,
+                          TALLOC_CTX *mem_ctx,
+                          const char **name)
+{
+    struct simple_resolve_group_state *state;
+
+    state = tevent_req_data(req, struct simple_resolve_group_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *name = talloc_strdup(mem_ctx, state->name);
+    return EOK;
+}
+
+struct simple_check_groups_state {
+    struct tevent_context *ev;
+    struct simple_ctx *ctx;
+
+    gid_t *lookup_gids;
+    size_t num_gids;
+    size_t giter;
+
+    const char **group_names;
+    size_t num_names;
+};
+
+static void simple_check_get_groups_next(struct tevent_req *subreq);
+
+static errno_t
+simple_check_get_groups_primary(struct simple_check_groups_state *state,
+                                gid_t gid);
+static errno_t
+simple_check_process_group(struct simple_check_groups_state *state,
+                           struct ldb_message *group);
+
+static struct tevent_req *
+simple_check_get_groups_send(TALLOC_CTX *mem_ctx,
+                             struct tevent_context *ev,
+                             struct simple_ctx *ctx,
+                             const char *username)
+{
+    errno_t ret;
+    struct tevent_req *req;
+    struct tevent_req *subreq;
+    struct simple_check_groups_state *state;
+    const char *attrs[] = { SYSDB_NAME, SYSDB_POSIX, SYSDB_GIDNUM, NULL };
+    size_t group_count;
+    struct ldb_message *user;
+    struct ldb_message **groups;
+    int i;
+    gid_t gid;
+    char *cname;
+
+    req = tevent_req_create(mem_ctx, &state,
+                            struct simple_check_groups_state);
+    if (!req) return NULL;
+
+    state->ev = ev;
+    state->ctx = ctx;
+
+    cname = sss_get_cased_name(state, username, ctx->domain->case_sensitive);
+    if (!cname) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    DEBUG(SSSDBG_TRACE_LIBS, ("Looking up groups for user %s\n", cname));
+
+    ret = sysdb_search_user_by_name(state, ctx->domain->sysdb,
+                                    cname, attrs, &user);
+    if (ret == ENOENT) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("No such user %s\n", cname));
+        goto done;
+    } else if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Could not look up username [%s]: [%d][%s]\n",
+              username, ret, strerror(ret)));
+        goto done;
+    }
+
+    ret = sysdb_asq_search(state, ctx->domain->sysdb,
+                           user->dn, NULL, SYSDB_MEMBEROF,
+                           attrs, &group_count, &groups);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC,
+          ("User %s is a member of %d supplemental groups\n",
+           cname, group_count));
+
+    /* One extra space for terminator, one extra space for private group */
+    state->group_names = talloc_zero_array(state, const char *, group_count + 2);
+    state->lookup_gids = talloc_zero_array(state, gid_t, group_count + 2);
+    if (!state->group_names || !state->lookup_gids) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    for (i=0; i < group_count; i++) {
+        /* Some providers (like the AD provider) might perform initgroups
+         * without resolving the group names. In order for the simple access
+         * provider to work correctly, we need to resolve the groups before
+         * performing the access check. In AD provider, the situation is
+         * even more tricky b/c the groups HAVE name, but their name
+         * attribute is set to SID and they are set as non-POSIX
+         */
+        ret = simple_check_process_group(state, groups[i]);
+        if (ret != EOK) {
+            goto done;
+        }
+    }
+
+    gid = ldb_msg_find_attr_as_uint64(user, SYSDB_GIDNUM, 0);
+    if (!gid) {
+        DEBUG(SSSDBG_MINOR_FAILURE, ("User %s has no gid?\n", cname));
+        ret = EINVAL;
+        goto done;
+    }
+
+    ret = simple_check_get_groups_primary(state, gid);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    if (state->num_gids == 0) {
+        /* If all groups could have been resolved by name, we are
+         * done
+         */
+        DEBUG(SSSDBG_TRACE_FUNC, ("All groups had name attribute\n"));
+        ret = EOK;
+        goto done;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, ("Need to resolve %d groups\n", state->num_gids));
+    state->giter = 0;
+    subreq = simple_resolve_group_send(req, state->ev, state->ctx,
+                                       state->lookup_gids[state->giter]);
+    if (!subreq) {
+        ret = ENOMEM;
+        goto done;
+    }
+    tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
+
+    return req;
+
+done:
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static void simple_check_get_groups_next(struct tevent_req *subreq)
+{
+    struct tevent_req *req =
+                        tevent_req_callback_data(subreq, struct tevent_req);
+    struct simple_check_groups_state *state =
+                        tevent_req_data(req, struct simple_check_groups_state);
+    errno_t ret;
+
+    ret = simple_resolve_group_recv(subreq, state->group_names,
+                                    &state->group_names[state->num_names]);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Could not resolve name of group with GID %llu\n",
+              state->lookup_gids[state->giter]));
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    state->num_names++;
+    state->giter++;
+
+    if (state->giter < state->num_gids) {
+        subreq = simple_resolve_group_send(req, state->ev, state->ctx,
+                                           state->lookup_gids[state->giter]);
+        if (!subreq) {
+            tevent_req_error(req, ENOMEM);
+            return;
+        }
+        tevent_req_set_callback(subreq, simple_check_get_groups_next, req);
+        return;
+    }
+
+    DEBUG(SSSDBG_TRACE_INTERNAL, ("All groups resolved. Done.\n"));
+    tevent_req_done(req);
+}
+
+static errno_t
+simple_check_process_group(struct simple_check_groups_state *state,
+                           struct ldb_message *group)
+{
+    const char *name;
+    gid_t gid;
+    bool posix;
+
+    posix = is_posix(group);
+    name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
+    gid = ldb_msg_find_attr_as_uint64(group, SYSDB_GIDNUM, 0);
+
+    /* With the current sysdb layout, every group has a name */
+    if (name == NULL) {
+        return EINVAL;
+    }
+
+    if (gid == 0) {
+        if (posix == true) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("POSIX group without GID\n"));
+            return EINVAL;
+        }
+
+        /* Non-posix group with a name. Still can be used for access
+         * control as the name should point to the real name, no SID
+         */
+        state->group_names[state->num_names] = talloc_strdup(state->group_names,
+                                                             name);
+        if (!state->group_names[state->num_names]) {
+            return ENOMEM;
+        }
+        DEBUG(SSSDBG_TRACE_INTERNAL, ("Adding group %s\n", name));
+        state->num_names++;
+        return EOK;
+    }
+
+    /* Here are only groups with a name and gid. POSIX group can already
+     * be used, non-POSIX groups can be resolved */
+    if (posix) {
+        state->group_names[state->num_names] = talloc_strdup(state->group_names,
+                                                             name);
+        if (!state->group_names[state->num_names]) {
+            return ENOMEM;
+        }
+        DEBUG(SSSDBG_TRACE_INTERNAL, ("Adding group %s\n", name));
+        state->num_names++;
+        return EOK;
+    }
+
+    /* Non-posix group with a GID. Needs resolving */
+    state->lookup_gids[state->num_gids] = gid;
+    DEBUG(SSSDBG_TRACE_INTERNAL, ("Adding GID %llu\n", gid));
+    state->num_gids++;
+    return EOK;
+}
+
+static errno_t
+simple_check_get_groups_primary(struct simple_check_groups_state *state,
+                                gid_t gid)
+{
+    errno_t ret;
+    const char *group_attrs[] = { SYSDB_NAME, SYSDB_POSIX,
+                                  SYSDB_GIDNUM, NULL };
+    struct ldb_message *msg;
+
+    ret = sysdb_search_group_by_gid(state, state->ctx->domain->sysdb,
+                                    gid, group_attrs, &msg);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+               ("Could not look up primary group [%lu]: [%d][%s]\n",
+               gid, ret, strerror(ret)));
+        /* We have to treat this as non-fatal, because the primary
+         * group may be local to the machine and not available in
+         * our ID provider.
+         */
+    } else {
+        ret = simple_check_process_group(state, msg);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_OP_FAILURE, ("Cannot process primary group\n"));
+            return ret;
+        }
+    }
+
+    return EOK;
+}
+
+static errno_t
+simple_check_get_groups_recv(struct tevent_req *req,
+                             TALLOC_CTX *mem_ctx,
+                             const char ***_group_names)
+{
+    struct simple_check_groups_state *state;
+
+    state = tevent_req_data(req, struct simple_check_groups_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *_group_names = talloc_steal(mem_ctx, state->group_names);
+    return EOK;
+}
+
+struct simple_access_check_state {
+    bool access_granted;
+    struct simple_ctx *ctx;
+    const char *username;
+
+    const char **group_names;
+};
+
+static void simple_access_check_done(struct tevent_req *subreq);
+
+struct tevent_req *simple_access_check_send(TALLOC_CTX *mem_ctx,
+                                            struct tevent_context *ev,
+                                            struct simple_ctx *ctx,
+                                            const char *username)
+{
+    errno_t ret;
+    struct tevent_req *req;
+    struct tevent_req *subreq;
+    struct simple_access_check_state *state;
+
+    req = tevent_req_create(mem_ctx, &state,
+                            struct simple_access_check_state);
+    if (!req) return NULL;
+
+    state->access_granted = false;
+    state->ctx = ctx;
+    state->username = talloc_strdup(state, username);
+    if (!state->username) {
+        ret = ENOMEM;
+        goto immediate;
+    }
+
+    DEBUG(SSSDBG_FUNC_DATA, ("Simple access check for %s\n", username));
+
+    ret = simple_check_users(ctx, username, &state->access_granted);
+    if (ret != EAGAIN) {
+        /* Both access denied and an error */
+        goto immediate;
+    }
+
+    if (!ctx->allow_groups && !ctx->deny_groups) {
+        /* There are no group restrictions, so just return
+         * here with whatever we've decided.
+         */
+        DEBUG(SSSDBG_TRACE_LIBS, ("No group restrictions, end request\n"));
+        ret = EOK;
+        goto immediate;
+    }
+
+    /* The group names might not be available. Fire a request to
+     * gather them. In most cases, the request will just shortcut
+     */
+    subreq = simple_check_get_groups_send(state, ev, ctx, username);
+    if (!subreq) {
+        ret = EIO;
+        goto immediate;
+    }
+    tevent_req_set_callback(subreq, simple_access_check_done, req);
+
+    return req;
+
+immediate:
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+    tevent_req_post(req, ev);
+    return req;
+}
+
+
+static void simple_access_check_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req =
+                        tevent_req_callback_data(subreq, struct tevent_req);
+    struct simple_access_check_state *state =
+                        tevent_req_data(req, struct simple_access_check_state);
+    errno_t ret;
+
+    /* We know the names now. Run the check. */
+    ret = simple_check_get_groups_recv(subreq, state, &state->group_names);
+    talloc_zfree(subreq);
+    if (ret == ENOENT) {
+        /* If the user wasn't found, just shortcut */
+        state->access_granted = false;
+        tevent_req_done(req);
+        return;
+    } else if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE,
+              ("Could not collect groups of user %s\n", state->username));
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    ret = simple_check_groups(state->ctx, state->username,
+                              state->group_names, &state->access_granted);
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    /* Now just return whatever we decided */
+    DEBUG(SSSDBG_TRACE_INTERNAL, ("Group check done\n"));
+    tevent_req_done(req);
+}
+
+errno_t simple_access_check_recv(struct tevent_req *req, bool *access_granted)
+{
+    struct simple_access_check_state *state =
+                        tevent_req_data(req, struct simple_access_check_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    DEBUG(SSSDBG_TRACE_LIBS,
+          ("Access %sgranted\n", state->access_granted ? "" : "not "));
+    if (access_granted) {
+        *access_granted = state->access_granted;
+    }
+
+    return EOK;
+}
diff --git a/src/tests/simple_access-tests.c b/src/tests/simple_access-tests.c
index 577c6d334edda513fd0f1e42a859ea333ba5ba23..ab2612db85b6cfe46c87a1fc8b17655dc7a795bb 100644
--- a/src/tests/simple_access-tests.c
+++ b/src/tests/simple_access-tests.c
@@ -27,6 +27,7 @@
 #include <check.h>
 
 #include "confdb/confdb.h"
+#include "db/sysdb_private.h"
 #include "providers/simple/simple_access.h"
 #include "tests/common.h"
 
@@ -35,16 +36,40 @@
 
 const char *ulist_1[] = {"u1", "u2", NULL};
 const char *glist_1[] = {"g1", "g2", NULL};
+const char *glist_1_case[] = {"G1", "G2", NULL};
 
 struct simple_test_ctx *test_ctx = NULL;
 
 struct simple_test_ctx {
     struct sysdb_ctx *sysdb;
     struct confdb_ctx *confdb;
+    struct tevent_context *ev;
+    bool done;
+    int error;
 
+    bool access_granted;
     struct simple_ctx *ctx;
 };
 
+static int test_loop(struct simple_test_ctx *tctx)
+{
+    while (!tctx->done)
+        tevent_loop_once(tctx->ev);
+
+    return tctx->error;
+}
+
+static void simple_access_check_done(struct tevent_req *req)
+{
+    struct simple_test_ctx *tctx =
+                        tevent_req_callback_data(req, struct simple_test_ctx);
+
+
+    tctx->error = simple_access_check_recv(req, &tctx->access_granted);
+    talloc_free(req);
+    tctx->done = true;
+}
+
 void setup_simple(void)
 {
     errno_t ret;
@@ -52,19 +77,22 @@ void setup_simple(void)
     const char *val[2];
     val[1] = NULL;
 
-    /* Create tests directory if it doesn't exist */
-    /* (relative to current dir) */
-    ret = mkdir(TESTS_PATH, 0775);
-    fail_if(ret == -1 && errno != EEXIST,
-            "Could not create %s directory", TESTS_PATH);
-
     fail_unless(test_ctx == NULL, "Simple context already initialized.");
     test_ctx = talloc_zero(NULL, struct simple_test_ctx);
     fail_unless(test_ctx != NULL, "Cannot create simple test context.");
 
+    test_ctx->ev = tevent_context_init(test_ctx);
+    fail_unless(test_ctx->ev != NULL, "Cannot create tevent context.");
+
     test_ctx->ctx = talloc_zero(test_ctx, struct simple_ctx);
     fail_unless(test_ctx->ctx != NULL, "Cannot create simple context.");
 
+    /* Create tests directory if it doesn't exist */
+    /* (relative to current dir) */
+    ret = mkdir(TESTS_PATH, 0775);
+    fail_if(ret == -1 && errno != EEXIST,
+            "Could not create %s directory", TESTS_PATH);
+
     conf_db = talloc_asprintf(test_ctx, "%s/%s", TESTS_PATH, TEST_CONF_FILE);
     fail_if(conf_db == NULL, "Out of memory, aborting!");
     DEBUG(SSSDBG_TRACE_LIBS, ("CONFDB: %s\n", conf_db));
@@ -98,6 +126,7 @@ void setup_simple(void)
                                       &test_ctx->ctx->domain, &test_ctx->ctx->sysdb);
     fail_if(ret != EOK, "Could not initialize connection to the sysdb (%d)", ret);
     test_ctx->ctx->domain->case_sensitive = true;
+    test_ctx->ctx->sysdb->mpg = false; /* Simulate an LDAP domain better */
 }
 
 void teardown_simple(void)
@@ -117,18 +146,22 @@ void setup_simple_group(void)
 
     /* Add test users u1 and u2 that would be members of test groups
      * g1 and g2 respectively */
+    ret = sysdb_add_group(test_ctx->ctx->sysdb,
+                          "pvt", 999, NULL, 0, 0);
+    fail_if(ret != EOK, "Could not add private group");
+
     ret = sysdb_store_user(test_ctx->ctx->sysdb,
-                           "u1", NULL, 123, 0, "u1", "/home/u1",
+                           "u1", NULL, 123, 999, "u1", "/home/u1",
                            "/bin/bash", NULL, NULL, NULL, -1, 0);
     fail_if(ret != EOK, "Could not add u1");
 
     ret = sysdb_store_user(test_ctx->ctx->sysdb,
-                           "u2", NULL, 456, 0, "u1", "/home/u1",
+                           "u2", NULL, 456, 999, "u1", "/home/u1",
                            "/bin/bash", NULL, NULL, NULL, -1, 0);
     fail_if(ret != EOK, "Could not add u2");
 
     ret = sysdb_store_user(test_ctx->ctx->sysdb,
-                           "u3", NULL, 789, 0, "u1", "/home/u1",
+                           "u3", NULL, 789, 999, "u1", "/home/u1",
                            "/bin/bash", NULL, NULL, NULL, -1, 0);
     fail_if(ret != EOK, "Could not add u3");
 
@@ -163,190 +196,317 @@ void teardown_simple_group(void)
     fail_if(ret != EOK, "Could not delete g1");
     ret = sysdb_delete_group(test_ctx->ctx->sysdb, "g2", 0);
     fail_if(ret != EOK, "Could not delete g2");
+    ret = sysdb_delete_group(test_ctx->ctx->sysdb, "pvt", 0);
+    fail_if(ret != EOK, "Could not delete pvt");
 
     teardown_simple();
 }
 
 START_TEST(test_both_empty)
 {
-    int ret;
-    bool access_granted = false;
+    struct tevent_req *req;
 
     test_ctx->ctx->allow_users = NULL;
     test_ctx->ctx->deny_users = NULL;
 
-    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == true, "Access denied "
-                                        "while both lists are empty.");
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u1");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == true,
+                "Access denied while both lists are empty.");
 }
 END_TEST
 
 START_TEST(test_allow_empty)
 {
-    int ret;
-    bool access_granted = true;
+    struct tevent_req *req;
 
     test_ctx->ctx->allow_users = NULL;
     test_ctx->ctx->deny_users = discard_const(ulist_1);
 
-    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == false, "Access granted "
-                                         "while user is in deny list.");
-
-    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == true, "Access denied "
-                                         "while user is not in deny list.");
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u1");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+    test_ctx->done = false;
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == false,
+                "Access granted while user is in deny list.");
+
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u3");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == true,
+                "Access denied while user is not in deny list.");
 }
 END_TEST
 
 START_TEST(test_deny_empty)
 {
-    int ret;
-    bool access_granted = false;
+    struct tevent_req *req;
 
     test_ctx->ctx->allow_users = discard_const(ulist_1);
     test_ctx->ctx->deny_users = NULL;
 
-    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == true, "Access denied "
-                                        "while user is in allow list.");
-
-    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == false, "Access granted "
-                                        "while user is not in allow list.");
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u1");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+    test_ctx->done = false;
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == true,
+                "Access denied while user is in allow list.");
+
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u3");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == false,
+                "Access granted while user is not in allow list.");
 }
 END_TEST
 
 START_TEST(test_both_set)
 {
-    int ret;
-    bool access_granted = false;
+    struct tevent_req *req;
 
     test_ctx->ctx->allow_users = discard_const(ulist_1);
     test_ctx->ctx->deny_users = discard_const(ulist_1);
 
-    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == false, "Access granted "
-                                         "while user is in deny list.");
-
-    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == false, "Access granted "
-                                        "while user is not in allow list.");
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u1");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+    test_ctx->done = false;
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == false,
+                "Access granted while user is in deny list.");
+
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u3");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == false,
+                "Access granted while user is not in allow list.");
 }
 END_TEST
 
 START_TEST(test_case)
 {
-    int ret;
-    bool access_granted = false;
+    struct tevent_req *req;
 
     test_ctx->ctx->allow_users = discard_const(ulist_1);
     test_ctx->ctx->deny_users = NULL;
 
-    ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == false, "Access granted "
-                                         "for user with different case "
-                                         "in case-sensitive domain");
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "U1");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+    test_ctx->done = false;
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == false,
+                "Access granted for user with different case "
+                "in case-sensitive domain");
 
     test_ctx->ctx->domain->case_sensitive = false;
 
-    ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == true, "Access denied "
-                                        "for user with different case "
-                                        "in case-insensitive domain");
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "U1");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+    test_ctx->done = false;
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == true,
+                "Access denied for user with different case "
+                "in case-sensitive domain");
 }
 END_TEST
 
+START_TEST(test_unknown_user)
+{
+    struct tevent_req *req;
+
+    test_ctx->ctx->allow_users = discard_const(ulist_1);
+    test_ctx->ctx->deny_users = NULL;
+
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "foo");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+    test_ctx->done = false;
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == false,
+                "Access granted for user not present in domain");
+}
+END_TEST
+
+
 START_TEST(test_group_allow_empty)
 {
-    int ret;
-    bool access_granted = true;
+    struct tevent_req *req;
 
     test_ctx->ctx->allow_groups = NULL;
     test_ctx->ctx->deny_groups = discard_const(glist_1);
 
-    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == false, "Access granted "
-                                         "while group is in deny list.");
-
-    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == true, "Access denied "
-                                         "while group is not in deny list.");
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u1");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+    test_ctx->done = false;
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == false,
+                "Access granted while group is in deny list.");
+
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u3");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == true,
+                "Access denied while group is not in deny list.");
 }
 END_TEST
 
 START_TEST(test_group_deny_empty)
 {
-    int ret;
-    bool access_granted = false;
+    struct tevent_req *req;
 
     test_ctx->ctx->allow_groups = discard_const(glist_1);
     test_ctx->ctx->deny_groups = NULL;
 
-    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == true, "Access denied "
-                                        "while group is in allow list.");
-
-    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == false, "Access granted "
-                                        "while group is not in allow list.");
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u1");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+    test_ctx->done = false;
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == true,
+                "Access denied while user is in allow list.");
+
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u3");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == false,
+                "Access granted while user is not in allow list.");
 }
 END_TEST
 
 START_TEST(test_group_both_set)
 {
-    int ret;
-    bool access_granted = false;
+    struct tevent_req *req;
 
     test_ctx->ctx->allow_groups = discard_const(ulist_1);
     test_ctx->ctx->deny_groups = discard_const(ulist_1);
 
-    ret = simple_access_check(test_ctx->ctx, "u1", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == false, "Access granted "
-                                         "while group is in deny list.");
-
-    ret = simple_access_check(test_ctx->ctx, "u3", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == false, "Access granted "
-                                        "while group is not in allow list.");
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u1");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+    test_ctx->done = false;
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == false,
+                "Access granted while user is in deny list.");
+
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "u3");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == false,
+                "Access granted while user is not in allow list.");
 }
 END_TEST
 
 START_TEST(test_group_case)
 {
-    int ret;
-    bool access_granted = false;
+    struct tevent_req *req;
 
-    test_ctx->ctx->allow_groups = discard_const(ulist_1);
+    test_ctx->ctx->allow_groups = discard_const(glist_1_case);
     test_ctx->ctx->deny_groups = NULL;
 
-    ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == false, "Access granted "
-                                         "for group with different case "
-                                         "in case-sensitive domain");
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "U1");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+    test_ctx->done = false;
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == false,
+                "Access granted for user with different case "
+                "in case-sensitive domain");
 
     test_ctx->ctx->domain->case_sensitive = false;
 
-    ret = simple_access_check(test_ctx->ctx, "U1", &access_granted);
-    fail_unless(ret == EOK, "access_simple_check failed.");
-    fail_unless(access_granted == true, "Access denied "
-                                        "for group with different case "
-                                        "in case-insensitive domain");
+    req = simple_access_check_send(test_ctx, test_ctx->ev,
+                                   test_ctx->ctx, "U1");
+    fail_unless(test_ctx != NULL, "Cannot create request\n");
+    tevent_req_set_callback(req, simple_access_check_done, test_ctx);
+
+    test_loop(test_ctx);
+    test_ctx->done = false;
+
+    fail_unless(test_ctx->error == EOK, "access_simple_check failed.");
+    fail_unless(test_ctx->access_granted == true,
+                "Access denied for user with different case "
+                "in case-sensitive domain");
 }
 END_TEST
 
@@ -361,6 +521,7 @@ Suite *access_simple_suite (void)
     tcase_add_test(tc_allow_deny, test_deny_empty);
     tcase_add_test(tc_allow_deny, test_both_set);
     tcase_add_test(tc_allow_deny, test_case);
+    tcase_add_test(tc_allow_deny, test_unknown_user);
     suite_add_tcase(s, tc_allow_deny);
 
     TCase *tc_grp_allow_deny = tcase_create("group allow/deny");
-- 
1.8.1.4



More information about the sssd-devel mailing list