summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2013-02-23 10:44:54 +0100
committerJakub Hrozek <jhrozek@redhat.com>2013-04-15 15:15:48 +0200
commit5925e134b87e79e60177b5861ec2a67b659aaa27 (patch)
tree1a1b59f96dc4fbf1d3ca13bdf5e6129a90871859
parentdeb9c70038fe998c81939d784262147709d3fe09 (diff)
downloadsssd-5925e134b87e79e60177b5861ec2a67b659aaa27.tar.gz
sssd-5925e134b87e79e60177b5861ec2a67b659aaa27.tar.xz
sssd-5925e134b87e79e60177b5861ec2a67b659aaa27.zip
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
-rw-r--r--Makefile.am17
-rw-r--r--src/providers/simple/simple_access.c228
-rw-r--r--src/providers/simple/simple_access.h11
-rw-r--r--src/providers/simple/simple_access_check.c723
-rw-r--r--src/tests/simple_access-tests.c361
5 files changed, 1033 insertions, 307 deletions
diff --git a/Makefile.am b/Makefile.am
index dda090daf..223431da4 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 70d1f0728..d53a04b4d 100644
--- a/src/providers/simple/simple_access.c
+++ b/src/providers/simple/simple_access.c
@@ -35,227 +35,52 @@
#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;
- }
+static void simple_access_check(struct tevent_req *req);
- /* 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;
- }
- }
- }
+void simple_access_handler(struct be_req *be_req)
+{
+ struct be_ctx *be_ctx = be_req->be_ctx;
+ struct pam_data *pd;
+ struct tevent_req *req;
+ struct simple_ctx *ctx;
- if (!ctx->allow_groups && !ctx->deny_groups) {
- /* There are no group restrictions, so just return
- * here with whatever we've decided.
- */
- return EOK;
- }
+ pd = talloc_get_type(be_req->req_data, struct pam_data);
- /* 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;
- }
+ pd->pam_status = PAM_SYSTEM_ERR;
- 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)));
+ if (pd->cmd != SSS_PAM_ACCT_MGMT) {
+ DEBUG(4, ("simple access does not handles pam task %d.\n", pd->cmd));
+ pd->pam_status = PAM_MODULE_UNKNOWN;
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;
- }
+ ctx = talloc_get_type(be_req->be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
+ struct simple_ctx);
- /* Get the user's primary group */
- gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);
- if (!gid) {
- ret = EINVAL;
+ req = simple_access_check_send(be_req, be_ctx->ev, ctx, pd->user);
+ if (!req) {
+ pd->pam_status = PAM_SYSTEM_ERR;
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;
+ tevent_req_set_callback(req, simple_access_check, be_req);
+ return;
done:
- talloc_free(tmp_ctx);
- return ret;
+ be_req->fn(be_req, DP_ERR_OK, pd->pam_status, NULL);
}
-void simple_access_handler(struct be_req *be_req)
+static void simple_access_check(struct tevent_req *req)
{
- int ret;
bool access_granted = false;
+ errno_t ret;
struct pam_data *pd;
- struct simple_ctx *ctx;
+ 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);
- pd->pam_status = PAM_SYSTEM_ERR;
-
- if (pd->cmd != SSS_PAM_ACCT_MGMT) {
- DEBUG(4, ("simple access does not handles pam task %d.\n", pd->cmd));
- pd->pam_status = PAM_MODULE_UNKNOWN;
- goto done;
- }
-
- 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);
+ 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 abcf61ac2..1de9d898b 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 000000000..a9e8f632e
--- /dev/null
+++ b/src/providers/simple/simple_access_check.c
@@ -0,0 +1,723 @@
+/*
+ SSSD
+
+ Simple access control
+
+ Copyright (C) Sumit Bose <sbose@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 577c6d334..ab2612db8 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.");
+ 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.");
- 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, "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.");
+ 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.");
- 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, "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.");
+ 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.");
- 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, "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.");
+ 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;
- 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.");
+ 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.");
+ 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;
- 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.");
+ 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.");
+ 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;
- 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.");
+ 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");