diff options
author | Stephen Gallagher <sgallagh@redhat.com> | 2010-12-09 10:14:04 -0500 |
---|---|---|
committer | Stephen Gallagher <sgallagh@redhat.com> | 2010-12-13 07:30:24 -0500 |
commit | 1b474ef7011f4bf9ce4aac85dbc9827a9486d5eb (patch) | |
tree | 6e1e86dfbddffac5a89201f26dd4be9ed92eaab1 /src/providers/simple/simple_access.c | |
parent | 583a018d792c7a28762ecfba74ef1adc48724f22 (diff) | |
download | sssd-1b474ef7011f4bf9ce4aac85dbc9827a9486d5eb.tar.gz sssd-1b474ef7011f4bf9ce4aac85dbc9827a9486d5eb.tar.xz sssd-1b474ef7011f4bf9ce4aac85dbc9827a9486d5eb.zip |
Add group support to the simple access provider
This patch adds simple_allow_groups and simple_deny_groups options
to the simple access provider. It makes it possible to grant or
deny access based on a user's group memberships within the domain.
This patch makes one minor change to previous functionality: now
all deny rules will supersede allow rules. Previously, if both
simple_allow_users and simple_deny_users were set with the same
value, the allow would win.
https://fedorahosted.org/sssd/ticket/440
Diffstat (limited to 'src/providers/simple/simple_access.c')
-rw-r--r-- | src/providers/simple/simple_access.c | 224 |
1 files changed, 210 insertions, 14 deletions
diff --git a/src/providers/simple/simple_access.c b/src/providers/simple/simple_access.c index 4d6135fa..a54bad00 100644 --- a/src/providers/simple/simple_access.c +++ b/src/providers/simple/simple_access.c @@ -31,36 +31,200 @@ #define CONFDB_SIMPLE_ALLOW_USERS "simple_allow_users" #define CONFDB_SIMPLE_DENY_USERS "simple_deny_users" +#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; + 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; *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 (strcmp(username, ctx->allow_users[i]) == 0) { 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 (strcmp(username, ctx->deny_users[i]) == 0) { + 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, ctx->domain, + 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 { - *access_granted = true; - if (ctx->deny_users != NULL) { - for(i = 0; ctx->deny_users[i] != NULL; i++) { - if (strcmp(username, ctx->deny_users[i]) == 0) { - DEBUG(9, ("User [%s] found in deny list, access denied.\n", - username)); - *access_granted = false; - return EOK; + /* 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, ctx->domain, + gid, group_attrs, &msg); + if (ret != EOK) { + DEBUG(1, ("Could not look up primary group [%lu]: [%d][%s]\n", + gid, ret, strerror(ret))); + goto done; + } + + 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; + } + groups[j+1] = NULL; + talloc_zfree(msg); + + /* 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 (strcmp(groups[j], ctx->allow_groups[i])== 0) { + matched = true; + break; } } + + /* If any group has matched, we can skip out on the + * processing early + */ + if (matched) { + *access_granted = true; + break; + } } } - return EOK; + /* 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 (strcmp(groups[j], ctx->deny_groups[i])== 0) { + 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; } void simple_access_handler(struct be_req *be_req) @@ -116,6 +280,10 @@ int sssm_simple_access_init(struct be_ctx *bectx, struct bet_ops **ops, return ENOMEM; } + ctx->sysdb = bectx->sysdb; + ctx->domain = bectx->domain; + + /* Users */ ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path, CONFDB_SIMPLE_ALLOW_USERS, &ctx->allow_users); @@ -142,12 +310,40 @@ int sssm_simple_access_init(struct be_ctx *bectx, struct bet_ops **ops, } } - if (ctx->allow_users != NULL && ctx->deny_users != NULL) { - DEBUG(1, ("Access and deny list are defined, only one is allowed.\n")); - ret = EINVAL; - goto failed; + /* Groups */ + ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path, + CONFDB_SIMPLE_ALLOW_GROUPS, + &ctx->allow_groups); + if (ret != EOK) { + if (ret == ENOENT) { + DEBUG(9, ("Allow group list is empty.\n")); + ctx->allow_groups = NULL; + } else { + DEBUG(1, ("confdb_get_string_as_list failed.\n")); + goto failed; + } } + ret = confdb_get_string_as_list(bectx->cdb, ctx, bectx->conf_path, + CONFDB_SIMPLE_DENY_GROUPS, + &ctx->deny_groups); + if (ret != EOK) { + if (ret == ENOENT) { + DEBUG(9, ("Deny user list is empty.\n")); + ctx->deny_groups = NULL; + } else { + DEBUG(1, ("confdb_get_string_as_list failed.\n")); + goto failed; + } + } + + if (!ctx->allow_users && + !ctx->allow_groups && + !ctx->deny_users && + !ctx->deny_groups) { + DEBUG(1, ("No rules supplied for simple access provider. " + "Access will be granted for all users.\n")); + } *ops = &simple_access_ops; *pvt_data = ctx; |