summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am8
-rw-r--r--src/providers/ldap/sdap_async_groups.c (renamed from src/providers/ldap/sdap_async_accounts.c)2523
-rw-r--r--src/providers/ldap/sdap_async_initgroups.c2049
-rw-r--r--src/providers/ldap/sdap_async_private.h17
-rw-r--r--src/providers/ldap/sdap_async_users.c513
5 files changed, 2594 insertions, 2516 deletions
diff --git a/Makefile.am b/Makefile.am
index c0267d29..92b0c105 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -804,7 +804,9 @@ libsss_ldap_la_SOURCES = \
src/providers/ldap/ldap_init.c \
src/providers/ldap/ldap_common.c \
src/providers/ldap/sdap_async.c \
- src/providers/ldap/sdap_async_accounts.c \
+ src/providers/ldap/sdap_async_users.c \
+ src/providers/ldap/sdap_async_groups.c \
+ src/providers/ldap/sdap_async_initgroups.c \
src/providers/ldap/sdap_async_connection.c \
src/providers/ldap/sdap_async_netgroups.c \
src/providers/ldap/sdap_child_helpers.c \
@@ -901,7 +903,9 @@ libsss_ipa_la_SOURCES = \
src/providers/ldap/ldap_auth.c \
src/providers/ldap/ldap_common.c \
src/providers/ldap/sdap_async.c \
- src/providers/ldap/sdap_async_accounts.c \
+ src/providers/ldap/sdap_async_users.c \
+ src/providers/ldap/sdap_async_groups.c \
+ src/providers/ldap/sdap_async_initgroups.c \
src/providers/ldap/sdap_async_connection.c \
src/providers/ldap/sdap_async_netgroups.c \
src/providers/ldap/sdap_child_helpers.c \
diff --git a/src/providers/ldap/sdap_async_accounts.c b/src/providers/ldap/sdap_async_groups.c
index 47653245..99b1a9e6 100644
--- a/src/providers/ldap/sdap_async_accounts.c
+++ b/src/providers/ldap/sdap_async_groups.c
@@ -1,10 +1,11 @@
/*
SSSD
- Async LDAP Helper routines
+ Async LDAP Helper routines - retrieving groups
Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
Copyright (C) 2010, Ralf Haferkamp <rhafer@suse.de>, Novell Inc.
+ Copyright (C) Jan Zeleny <jzeleny@redhat.com> - 2011
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
@@ -25,492 +26,6 @@
#include "providers/ldap/sdap_async_private.h"
#include "providers/ldap/ldap_common.h"
-/* ==Save-User-Entry====================================================== */
-
-/* FIXME: support storing additional attributes */
-
-static int sdap_save_user(TALLOC_CTX *memctx,
- struct sysdb_ctx *ctx,
- struct sdap_options *opts,
- struct sss_domain_info *dom,
- struct sysdb_attrs *attrs,
- const char **ldap_attrs,
- bool is_initgr,
- char **_usn_value)
-{
- struct ldb_message_element *el;
- int ret;
- const char *name = NULL;
- const char *pwd;
- const char *gecos;
- const char *homedir;
- const char *shell;
- uid_t uid;
- gid_t gid;
- struct sysdb_attrs *user_attrs;
- char *upn = NULL;
- size_t i;
- char *val = NULL;
- int cache_timeout;
- char *usn_value = NULL;
- size_t c;
- char **missing = NULL;
- TALLOC_CTX *tmpctx = NULL;
-
- DEBUG(9, ("Save user\n"));
-
- tmpctx = talloc_new(memctx);
- if (!tmpctx) {
- ret = ENOMEM;
- goto fail;
- }
-
- user_attrs = sysdb_new_attrs(tmpctx);
- if (user_attrs == NULL) {
- ret = ENOMEM;
- goto fail;
- }
-
- ret = sysdb_attrs_primary_name(ctx, attrs,
- opts->user_map[SDAP_AT_USER_NAME].name,
- &name);
- if (ret != EOK) {
- DEBUG(1, ("Failed to save the user - entry has no name attribute\n"));
- goto fail;
- }
-
- ret = sysdb_attrs_get_el(attrs,
- opts->user_map[SDAP_AT_USER_PWD].sys_name, &el);
- if (ret) goto fail;
- if (el->num_values == 0) pwd = NULL;
- else pwd = (const char *)el->values[0].data;
-
- ret = sysdb_attrs_get_el(attrs,
- opts->user_map[SDAP_AT_USER_GECOS].sys_name, &el);
- if (ret) goto fail;
- if (el->num_values == 0) gecos = NULL;
- else gecos = (const char *)el->values[0].data;
-
- if (!gecos) {
- /* Fall back to the user's full name */
- ret = sysdb_attrs_get_el(
- attrs,
- opts->user_map[SDAP_AT_USER_FULLNAME].sys_name, &el);
- if (ret) goto fail;
- if (el->num_values > 0) gecos = (const char *)el->values[0].data;
- }
-
- ret = sysdb_attrs_get_el(attrs,
- opts->user_map[SDAP_AT_USER_HOME].sys_name, &el);
- if (ret) goto fail;
- if (el->num_values == 0) homedir = NULL;
- else homedir = (const char *)el->values[0].data;
-
- ret = sysdb_attrs_get_el(attrs,
- opts->user_map[SDAP_AT_USER_SHELL].sys_name, &el);
- if (ret) goto fail;
- if (el->num_values == 0) shell = NULL;
- else shell = (const char *)el->values[0].data;
-
- ret = sysdb_attrs_get_uint32_t(attrs,
- opts->user_map[SDAP_AT_USER_UID].sys_name,
- &uid);
- if (ret != EOK) {
- DEBUG(1, ("no uid provided for [%s] in domain [%s].\n",
- name, dom->name));
- ret = EINVAL;
- goto fail;
- }
-
- /* check that the uid is valid for this domain */
- if (OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) {
- DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
- name));
- ret = EINVAL;
- goto fail;
- }
-
- ret = sysdb_attrs_get_uint32_t(attrs,
- opts->user_map[SDAP_AT_USER_GID].sys_name,
- &gid);
- if (ret != EOK) {
- DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",
- name, dom->name));
- ret = EINVAL;
- goto fail;
- }
-
- /* check that the gid is valid for this domain */
- if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
- DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
- name));
- ret = EINVAL;
- goto fail;
- }
-
- ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
- if (ret) {
- goto fail;
- }
- if (el->num_values == 0) {
- DEBUG(7, ("Original DN is not available for [%s].\n", name));
- } else {
- DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n",
- el->values[0].data, name));
- ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_DN,
- (const char *) el->values[0].data);
- if (ret) {
- goto fail;
- }
- }
-
- ret = sysdb_attrs_get_el(attrs, SYSDB_MEMBEROF, &el);
- if (ret) {
- goto fail;
- }
- if (el->num_values == 0) {
- DEBUG(7, ("Original memberOf is not available for [%s].\n",
- name));
- } else {
- DEBUG(7, ("Adding original memberOf attributes to [%s].\n",
- name));
- for (i = 0; i < el->num_values; i++) {
- ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF,
- (const char *) el->values[i].data);
- if (ret) {
- goto fail;
- }
- }
- }
-
- ret = sysdb_attrs_get_el(attrs,
- opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name, &el);
- if (ret) {
- goto fail;
- }
- if (el->num_values == 0) {
- DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
- name));
- } else {
- ret = sysdb_attrs_add_string(user_attrs,
- opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name,
- (const char*)el->values[0].data);
- if (ret) {
- goto fail;
- }
- }
-
- ret = sysdb_attrs_get_el(attrs,
- opts->user_map[SDAP_AT_USER_USN].sys_name, &el);
- if (ret) {
- goto fail;
- }
- if (el->num_values == 0) {
- DEBUG(7, ("Original USN value is not available for [%s].\n",
- name));
- } else {
- ret = sysdb_attrs_add_string(user_attrs,
- opts->user_map[SDAP_AT_USER_USN].sys_name,
- (const char*)el->values[0].data);
- if (ret) {
- goto fail;
- }
- usn_value = talloc_strdup(memctx, (const char*)el->values[0].data);
- if (!usn_value) {
- ret = ENOMEM;
- goto fail;
- }
- }
-
- ret = sysdb_attrs_get_el(attrs,
- opts->user_map[SDAP_AT_USER_PRINC].sys_name, &el);
- if (ret) {
- goto fail;
- }
- if (el->num_values == 0) {
- DEBUG(7, ("User principal is not available for [%s].\n", name));
- } else {
- upn = talloc_strdup(user_attrs, (const char*) el->values[0].data);
- if (!upn) {
- ret = ENOMEM;
- goto fail;
- }
- if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) {
- make_realm_upper_case(upn);
- }
- DEBUG(7, ("Adding user principal [%s] to attributes of [%s].\n",
- upn, name));
- ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn);
- if (ret) {
- goto fail;
- }
- }
-
- for (i = SDAP_FIRST_EXTRA_USER_AT; i < SDAP_OPTS_USER; i++) {
- ret = sysdb_attrs_get_el(attrs, opts->user_map[i].sys_name, &el);
- if (ret) {
- goto fail;
- }
- if (el->num_values > 0) {
- for (c = 0; c < el->num_values; c++) {
- DEBUG(9, ("Adding [%s]=[%s] to user attributes.\n",
- opts->user_map[i].sys_name,
- (const char*) el->values[c].data));
- val = talloc_strdup(user_attrs, (const char*) el->values[c].data);
- if (val == NULL) {
- ret = ENOMEM;
- goto fail;
- }
- ret = sysdb_attrs_add_string(user_attrs,
- opts->user_map[i].sys_name, val);
- if (ret) {
- goto fail;
- }
- }
- }
- }
-
- cache_timeout = dp_opt_get_int(opts->basic, SDAP_ENTRY_CACHE_TIMEOUT);
-
- if (is_initgr) {
- ret = sysdb_attrs_add_time_t(user_attrs, SYSDB_INITGR_EXPIRE,
- (cache_timeout ?
- (time(NULL) + cache_timeout) : 0));
- if (ret) {
- goto fail;
- }
- }
-
- /* Make sure that any attributes we requested from LDAP that we
- * did not receive are also removed from the sysdb
- */
- ret = list_missing_attrs(user_attrs, opts->user_map, SDAP_OPTS_USER,
- ldap_attrs, attrs, &missing);
- if (ret != EOK) {
- goto fail;
- }
-
- /* Remove missing attributes */
- if (missing && !missing[0]) {
- /* Nothing to remove */
- talloc_zfree(missing);
- }
-
- DEBUG(6, ("Storing info for user %s\n", name));
-
- ret = sysdb_store_user(ctx, name, pwd, uid, gid, gecos, homedir, shell,
- user_attrs, missing, cache_timeout);
- if (ret) goto fail;
-
- if (_usn_value) {
- *_usn_value = usn_value;
- }
-
- talloc_steal(memctx, user_attrs);
- talloc_free(tmpctx);
- return EOK;
-
-fail:
- DEBUG(2, ("Failed to save user [%s]\n",
- name ? name : "Unknown"));
- talloc_free(tmpctx);
- return ret;
-}
-
-
-/* ==Generic-Function-to-save-multiple-users============================= */
-
-static int sdap_save_users(TALLOC_CTX *memctx,
- struct sysdb_ctx *sysdb,
- const char **attrs,
- struct sss_domain_info *dom,
- struct sdap_options *opts,
- struct sysdb_attrs **users,
- int num_users,
- char **_usn_value)
-{
- TALLOC_CTX *tmpctx;
- char *higher_usn = NULL;
- char *usn_value;
- int ret;
- int i;
-
- if (num_users == 0) {
- /* Nothing to do if there are no users */
- return EOK;
- }
-
- tmpctx = talloc_new(memctx);
- if (!tmpctx) {
- return ENOMEM;
- }
-
- ret = sysdb_transaction_start(sysdb);
- if (ret) {
- goto done;
- }
-
- for (i = 0; i < num_users; i++) {
- usn_value = NULL;
-
- ret = sdap_save_user(tmpctx, sysdb, opts, dom,
- users[i], attrs, false,
- &usn_value);
-
- /* Do not fail completely on errors.
- * Just report the failure to save and go on */
- if (ret) {
- DEBUG(2, ("Failed to store user %d. Ignoring.\n", i));
- } else {
- DEBUG(9, ("User %d processed!\n", i));
- }
-
- if (usn_value) {
- if (higher_usn) {
- if ((strlen(usn_value) > strlen(higher_usn)) ||
- (strcmp(usn_value, higher_usn) > 0)) {
- talloc_zfree(higher_usn);
- higher_usn = usn_value;
- } else {
- talloc_zfree(usn_value);
- }
- } else {
- higher_usn = usn_value;
- }
- }
- }
-
- ret = sysdb_transaction_commit(sysdb);
- if (ret) {
- DEBUG(1, ("Failed to commit transaction!\n"));
- goto done;
- }
-
- if (_usn_value) {
- *_usn_value = talloc_steal(memctx, higher_usn);
- }
-
-done:
- talloc_zfree(tmpctx);
- return ret;
-}
-
-
-/* ==Search-Users-with-filter============================================= */
-
-struct sdap_get_users_state {
- struct tevent_context *ev;
- struct sdap_options *opts;
- struct sdap_handle *sh;
- struct sss_domain_info *dom;
- struct sysdb_ctx *sysdb;
- const char **attrs;
- const char *filter;
-
- char *higher_usn;
- struct sysdb_attrs **users;
- size_t count;
-};
-
-static void sdap_get_users_process(struct tevent_req *subreq);
-
-struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sss_domain_info *dom,
- struct sysdb_ctx *sysdb,
- struct sdap_options *opts,
- struct sdap_handle *sh,
- const char **attrs,
- const char *filter,
- int timeout)
-{
- struct tevent_req *req, *subreq;
- struct sdap_get_users_state *state;
-
- req = tevent_req_create(memctx, &state, struct sdap_get_users_state);
- if (!req) return NULL;
-
- state->ev = ev;
- state->opts = opts;
- state->dom = dom;
- state->sh = sh;
- state->sysdb = sysdb;
- state->filter = filter;
- state->attrs = attrs;
- state->higher_usn = NULL;
- state->users = NULL;
- state->count = 0;
-
- subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
- dp_opt_get_string(state->opts->basic,
- SDAP_USER_SEARCH_BASE),
- LDAP_SCOPE_SUBTREE,
- state->filter, state->attrs,
- state->opts->user_map, SDAP_OPTS_USER,
- timeout);
- if (!subreq) {
- talloc_zfree(req);
- return NULL;
- }
- tevent_req_set_callback(subreq, sdap_get_users_process, req);
-
- return req;
-}
-
-static void sdap_get_users_process(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(subreq,
- struct tevent_req);
- struct sdap_get_users_state *state = tevent_req_data(req,
- struct sdap_get_users_state);
- int ret;
-
- ret = sdap_get_generic_recv(subreq, state,
- &state->count, &state->users);
- talloc_zfree(subreq);
- if (ret) {
- tevent_req_error(req, ret);
- return;
- }
-
- DEBUG(6, ("Search for users, returned %d results.\n", state->count));
-
- if (state->count == 0) {
- tevent_req_error(req, ENOENT);
- return;
- }
-
- ret = sdap_save_users(state, state->sysdb,
- state->attrs,
- state->dom, state->opts,
- state->users, state->count,
- &state->higher_usn);
- if (ret) {
- DEBUG(2, ("Failed to store users.\n"));
- tevent_req_error(req, ret);
- return;
- }
-
- DEBUG(9, ("Saving %d Users - Done\n", state->count));
-
- tevent_req_done(req);
-}
-
-int sdap_get_users_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx, char **usn_value)
-{
- struct sdap_get_users_state *state = tevent_req_data(req,
- struct sdap_get_users_state);
-
- TEVENT_REQ_RETURN_ON_ERROR(req);
-
- if (usn_value) {
- *usn_value = talloc_steal(mem_ctx, state->higher_usn);
- }
-
- return EOK;
-}
-
/* ==Group-Parsing Routines=============================================== */
static int sdap_find_entry_by_origDN(TALLOC_CTX *memctx,
@@ -663,7 +178,9 @@ done:
/* FIXME: support storing additional attributes */
static errno_t
-sdap_store_group_with_gid(struct sysdb_ctx *ctx,
+sdap_store_group_with_gid(TALLOC_CTX *mem_ctx,
+ struct sysdb_ctx *ctx,
+ struct sss_domain_info *domain,
const char *name,
gid_t gid,
struct sysdb_attrs *group_attrs,
@@ -852,7 +369,8 @@ static int sdap_save_group(TALLOC_CTX *memctx,
DEBUG(6, ("Storing info for group %s\n", name));
- ret = sdap_store_group_with_gid(ctx, name, gid, group_attrs,
+ ret = sdap_store_group_with_gid(group_attrs, ctx, dom,
+ name, gid, group_attrs,
dp_opt_get_int(opts->basic,
SDAP_ENTRY_CACHE_TIMEOUT),
posix_group);
@@ -1308,8 +826,8 @@ sdap_process_group_members_2307(struct sdap_process_group_state *state,
/* We need to skip over zero-length usernames */
if (member_name[0] == '\0') continue;
- ret = sysdb_search_user_by_name(state, state->sysdb, member_name,
- NULL, &msg);
+ ret = sysdb_search_user_by_name(state, state->sysdb,
+ member_name, NULL, &msg);
if (ret == EOK) {
strdn = sysdb_user_strdn(state->sysdb_dns->values,
state->dom->name,
@@ -2080,1260 +1598,6 @@ done:
return ret;
}
-/* ==Save-fake-group-list=====================================*/
-static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
- struct sdap_options *opts,
- struct sss_domain_info *dom,
- char **groupnames,
- struct sysdb_attrs **ldap_groups,
- int ldap_groups_count)
-{
- TALLOC_CTX *tmp_ctx;
- struct ldb_message *msg;
- int i, mi, ai;
- const char *name;
- const char *original_dn;
- char **missing;
- gid_t gid;
- int ret;
- bool in_transaction = false;
- bool posix;
-
- /* There are no groups in LDAP but we should add user to groups ?? */
- if (ldap_groups_count == 0) return EOK;
-
- tmp_ctx = talloc_new(NULL);
- if (!tmp_ctx) return ENOMEM;
-
- missing = talloc_array(tmp_ctx, char *, ldap_groups_count+1);
- if (!missing) {
- ret = ENOMEM;
- goto fail;
- }
- mi = 0;
-
- ret = sysdb_transaction_start(sysdb);
- if (ret != EOK) {
- DEBUG(1, ("Cannot start sysdb transaction [%d]: %s\n",
- ret, strerror(ret)));
- goto fail;
- }
- in_transaction = true;
-
- for (i=0; groupnames[i]; i++) {
- ret = sysdb_search_group_by_name(tmp_ctx, sysdb,
- groupnames[i], NULL, &msg);
- if (ret == EOK) {
- continue;
- } else if (ret == ENOENT) {
- DEBUG(7, ("Group #%d [%s] is not cached, need to add a fake entry\n",
- i, groupnames[i]));
- missing[mi] = groupnames[i];
- mi++;
- continue;
- } else if (ret != ENOENT) {
- DEBUG(1, ("search for group failed [%d]: %s\n",
- ret, strerror(ret)));
- goto fail;
- }
- }
- missing[mi] = NULL;
-
- /* All groups are cached, nothing to do */
- if (mi == 0) {
- talloc_zfree(tmp_ctx);
- goto done;
- }
-
- for (i=0; missing[i]; i++) {
- /* The group is not in sysdb, need to add a fake entry */
- for (ai=0; ai < ldap_groups_count; ai++) {
- ret = sysdb_attrs_primary_name(sysdb, ldap_groups[ai],
- opts->group_map[SDAP_AT_GROUP_NAME].name,
- &name);
- if (ret != EOK) {
- DEBUG(1, ("The group has no name attribute\n"));
- goto fail;
- }
-
- if (strcmp(name, missing[i]) == 0) {
- posix = true;
- ret = sysdb_attrs_get_uint32_t(ldap_groups[ai],
- SYSDB_GIDNUM,
- &gid);
- if (ret == ENOENT || (ret == EOK && gid == 0)) {
- DEBUG(9, ("The group %s gid was %s\n",
- name, ret == ENOENT ? "missing" : "zero"));
- DEBUG(8, ("Marking group %s as non-posix and setting GID=0!\n", name));
- gid = 0;
- posix = false;
- } else if (ret) {
- DEBUG(1, ("The GID attribute is malformed\n"));
- goto fail;
- }
-
- ret = sysdb_attrs_get_string(ldap_groups[ai],
- SYSDB_ORIG_DN,
- &original_dn);
- if (ret) {
- DEBUG(5, ("The group has no name original DN\n"));
- original_dn = NULL;
- }
-
- DEBUG(8, ("Adding fake group %s to sysdb\n", name));
- ret = sysdb_add_incomplete_group(sysdb, name,
- gid, original_dn, posix);
- if (ret != EOK) {
- goto fail;
- }
- break;
- }
- }
-
- if (ai == ldap_groups_count) {
- DEBUG(2, ("Group %s not present in LDAP\n", missing[i]));
- ret = EINVAL;
- goto fail;
- }
- }
-
-done:
- ret = sysdb_transaction_commit(sysdb);
- if (ret != EOK) {
- DEBUG(1, ("sysdb_transaction_commit failed.\n"));
- goto fail;
- }
- in_transaction = false;
- ret = EOK;
-fail:
- if (in_transaction) {
- sysdb_transaction_cancel(sysdb);
- }
- return ret;
-}
-
-static int sdap_initgr_common_store(struct sysdb_ctx *sysdb,
- struct sdap_options *opts,
- struct sss_domain_info *dom,
- const char *name,
- enum sysdb_member_type type,
- char **sysdb_grouplist,
- struct sysdb_attrs **ldap_groups,
- int ldap_groups_count,
- bool add_fake)
-{
- TALLOC_CTX *tmp_ctx;
- char **ldap_grouplist = NULL;
- char **add_groups;
- char **del_groups;
- int ret;
-
- tmp_ctx = talloc_new(NULL);
- if (!tmp_ctx) return ENOMEM;
-
- if (ldap_groups_count == 0) {
- /* No groups for this user in LDAP.
- * We need to ensure that there are no groups
- * in the sysdb either.
- */
- ldap_grouplist = NULL;
- } else {
- ret = sysdb_attrs_primary_name_list(
- sysdb, tmp_ctx,
- ldap_groups, ldap_groups_count,
- opts->group_map[SDAP_AT_GROUP_NAME].name,
- &ldap_grouplist);
- if (ret != EOK) {
- DEBUG(1, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
- ret, strerror(ret)));
- goto done;
- }
- }
-
- /* Find the differences between the sysdb and LDAP lists
- * Groups in the sysdb only must be removed.
- */
- ret = diff_string_lists(tmp_ctx, ldap_grouplist, sysdb_grouplist,
- &add_groups, &del_groups, NULL);
- if (ret != EOK) goto done;
-
- /* Add fake entries for any groups the user should be added as
- * member of but that are not cached in sysdb
- */
- if (add_fake && add_groups && add_groups[0]) {
- ret = sdap_add_incomplete_groups(sysdb, opts, dom,
- add_groups, ldap_groups,
- ldap_groups_count);
- if (ret != EOK) {
- DEBUG(1, ("Adding incomplete users failed\n"));
- goto done;
- }
- }
-
- DEBUG(8, ("Updating memberships for %s\n", name));
- ret = sysdb_update_members(sysdb, name, type,
- (const char *const *) add_groups,
- (const char *const *) del_groups);
- if (ret != EOK) {
- DEBUG(1, ("Membership update failed [%d]: %s\n",
- ret, strerror(ret)));
- goto done;
- }
-
- ret = EOK;
-done:
- talloc_zfree(tmp_ctx);
- return ret;
-}
-
-/* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307-Classic/BIS========= */
-
-struct sdap_initgr_rfc2307_state {
- struct tevent_context *ev;
- struct sysdb_ctx *sysdb;
- struct sdap_options *opts;
- struct sss_domain_info *dom;
- struct sdap_handle *sh;
- const char *name;
-
- struct sdap_op *op;
-
- struct sysdb_attrs **ldap_groups;
- size_t ldap_groups_count;
-};
-
-static void sdap_initgr_rfc2307_process(struct tevent_req *subreq);
-struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sdap_options *opts,
- struct sysdb_ctx *sysdb,
- struct sss_domain_info *dom,
- struct sdap_handle *sh,
- const char *base_dn,
- const char *name)
-{
- struct tevent_req *req, *subreq;
- struct sdap_initgr_rfc2307_state *state;
- const char *filter;
- const char **attrs;
- char *clean_name;
- errno_t ret;
-
- req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);
- if (!req) return NULL;
-
- state->ev = ev;
- state->opts = opts;
- state->sysdb = sysdb;
- state->dom = dom;
- state->sh = sh;
- state->op = NULL;
- state->name = talloc_strdup(state, name);
- if (!state->name) {
- talloc_zfree(req);
- return NULL;
- }
-
- ret = build_attrs_from_map(state, opts->group_map,
- SDAP_OPTS_GROUP, &attrs);
- if (ret != EOK) {
- talloc_free(req);
- return NULL;
- }
-
- ret = sss_filter_sanitize(state, name, &clean_name);
- if (ret != EOK) {
- talloc_free(req);
- return NULL;
- }
-
- filter = talloc_asprintf(state,
- "(&(%s=%s)(objectclass=%s)(%s=*)(&(%s=*)(!(%s=0))))",
- opts->group_map[SDAP_AT_GROUP_MEMBER].name,
- clean_name,
- opts->group_map[SDAP_OC_GROUP].name,
- opts->group_map[SDAP_AT_GROUP_NAME].name,
- opts->group_map[SDAP_AT_GROUP_GID].name,
- opts->group_map[SDAP_AT_GROUP_GID].name);
- if (!filter) {
- talloc_zfree(req);
- return NULL;
- }
- talloc_zfree(clean_name);
-
- subreq = sdap_get_generic_send(state, state->ev, state->opts,
- state->sh, base_dn, LDAP_SCOPE_SUBTREE,
- filter, attrs,
- state->opts->group_map, SDAP_OPTS_GROUP,
- dp_opt_get_int(state->opts->basic,
- SDAP_SEARCH_TIMEOUT));
- if (!subreq) {
- talloc_zfree(req);
- return NULL;
- }
- tevent_req_set_callback(subreq, sdap_initgr_rfc2307_process, req);
-
- return req;
-}
-
-static void sdap_initgr_rfc2307_process(struct tevent_req *subreq)
-{
- struct tevent_req *req;
- struct sdap_initgr_rfc2307_state *state;
- struct sysdb_attrs **ldap_groups;
- char **sysdb_grouplist = NULL;
- struct ldb_message *msg;
- struct ldb_message_element *groups;
- size_t count;
- const char *attrs[2];
- int ret;
- int i;
-
- req = tevent_req_callback_data(subreq, struct tevent_req);
- state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
-
- ret = sdap_get_generic_recv(subreq, state, &count, &ldap_groups);
- talloc_zfree(subreq);
- if (ret) {
- tevent_req_error(req, ret);
- return;
- }
-
- /* Search for all groups for which this user is a member */
- attrs[0] = SYSDB_MEMBEROF;
- attrs[1] = NULL;
- ret = sysdb_search_user_by_name(state, state->sysdb,
- state->name, attrs, &msg);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- return;
- }
-
- groups = ldb_msg_find_element(msg, SYSDB_MEMBEROF);
- if (!groups || groups->num_values == 0) {
- /* No groups for this user in sysdb currently */
- sysdb_grouplist = NULL;
- } else {
- sysdb_grouplist = talloc_array(state, char *, groups->num_values+1);
- if (!sysdb_grouplist) {
- tevent_req_error(req, ENOMEM);
- return;
- }
-
- /* Get a list of the groups by groupname only */
- for (i=0; i < groups->num_values; i++) {
- ret = sysdb_group_dn_name(state->sysdb,
- sysdb_grouplist,
- (const char *)groups->values[i].data,
- &sysdb_grouplist[i]);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- return;
- }
- }
- sysdb_grouplist[groups->num_values] = NULL;
- }
-
- /* There are no nested groups here so we can just update the
- * memberships */
- ret = sdap_initgr_common_store(state->sysdb, state->opts,
- state->dom, state->name,
- SYSDB_MEMBER_USER, sysdb_grouplist,
- ldap_groups, count, true);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- return;
- }
-
- tevent_req_done(req);
-}
-
-static int sdap_initgr_rfc2307_recv(struct tevent_req *req)
-{
- TEVENT_REQ_RETURN_ON_ERROR(req);
-
- return EOK;
-}
-
-
-/* ==Initgr-call-(groups-a-user-is-member-of)-nested-groups=============== */
-
-struct sdap_initgr_nested_state {
- struct tevent_context *ev;
- struct sysdb_ctx *sysdb;
- struct sdap_options *opts;
- struct sss_domain_info *dom;
- struct sdap_handle *sh;
-
- struct sysdb_attrs *user;
- const char *username;
-
- const char **grp_attrs;
-
- char *filter;
- char **group_dns;
- int count;
- int cur;
-
- struct sdap_op *op;
-
- struct sysdb_attrs **groups;
- int groups_cur;
-};
-
-static void sdap_initgr_nested_search(struct tevent_req *subreq);
-static void sdap_initgr_nested_store(struct tevent_req *req);
-static struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sdap_options *opts,
- struct sysdb_ctx *sysdb,
- struct sss_domain_info *dom,
- struct sdap_handle *sh,
- struct sysdb_attrs *user,
- const char **grp_attrs)
-{
- struct tevent_req *req, *subreq;
- struct sdap_initgr_nested_state *state;
- struct ldb_message_element *el;
- int i;
- errno_t ret;
-
- req = tevent_req_create(memctx, &state, struct sdap_initgr_nested_state);
- if (!req) return NULL;
-
- state->ev = ev;
- state->opts = opts;
- state->sysdb = sysdb;
- state->dom = dom;
- state->sh = sh;
- state->grp_attrs = grp_attrs;
- state->user = user;
- state->op = NULL;
-
- ret = sysdb_attrs_primary_name(sysdb, user,
- opts->user_map[SDAP_AT_USER_NAME].name,
- &state->username);
- if (ret != EOK) {
- DEBUG(1, ("User entry had no username\n"));
- talloc_free(req);
- return NULL;
- }
-
- state->filter = talloc_asprintf(state, "(&(objectclass=%s)(%s=*))",
- opts->group_map[SDAP_OC_GROUP].name,
- opts->group_map[SDAP_AT_GROUP_NAME].name);
- if (!state->filter) {
- talloc_zfree(req);
- return NULL;
- }
-
- /* TODO: test rootDSE for deref support and use it if available */
- /* TODO: or test rootDSE for ASQ support and use it if available */
-
- ret = sysdb_attrs_get_el(user, SYSDB_MEMBEROF, &el);
- if (ret || !el || el->num_values == 0) {
- DEBUG(4, ("User entry lacks original memberof ?\n"));
- /* We can't find any groups for this user, so we'll
- * have to assume there aren't any. Just return
- * success here.
- */
- tevent_req_done(req);
- tevent_req_post(req, ev);
- return req;
- }
- state->count = el->num_values;
-
- state->groups = talloc_zero_array(state, struct sysdb_attrs *,
- state->count + 1);;
- if (!state->groups) {
- talloc_zfree(req);
- return NULL;
- }
- state->groups_cur = 0;
-
- state->group_dns = talloc_array(state, char *, state->count + 1);
- if (!state->group_dns) {
- talloc_zfree(req);
- return NULL;
- }
- for (i = 0; i < state->count; i++) {
- state->group_dns[i] = talloc_strdup(state->group_dns,
- (char *)el->values[i].data);
- if (!state->group_dns[i]) {
- talloc_zfree(req);
- return NULL;
- }
- }
- state->group_dns[i] = NULL; /* terminate */
- state->cur = 0;
-
- subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
- state->group_dns[state->cur],
- LDAP_SCOPE_BASE,
- state->filter, state->grp_attrs,
- state->opts->group_map, SDAP_OPTS_GROUP,
- dp_opt_get_int(state->opts->basic,
- SDAP_SEARCH_TIMEOUT));
- if (!subreq) {
- talloc_zfree(req);
- return NULL;
- }
- tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
-
- return req;
-}
-
-static void sdap_initgr_nested_search(struct tevent_req *subreq)
-{
- struct tevent_req *req;
- struct sdap_initgr_nested_state *state;
- struct sysdb_attrs **groups;
- size_t count;
- int ret;
-
- req = tevent_req_callback_data(subreq, struct tevent_req);
- state = tevent_req_data(req, struct sdap_initgr_nested_state);
-
- ret = sdap_get_generic_recv(subreq, state, &count, &groups);
- talloc_zfree(subreq);
- if (ret) {
- tevent_req_error(req, ret);
- return;
- }
-
- if (count == 1) {
- state->groups[state->groups_cur] = groups[0];
- state->groups_cur++;
- } else {
- DEBUG(2, ("Search for group %s, returned %d results. Skipping\n",
- state->group_dns[state->cur], count));
- }
-
- state->cur++;
- if (state->cur < state->count) {
- subreq = sdap_get_generic_send(state, state->ev,
- state->opts, state->sh,
- state->group_dns[state->cur],
- LDAP_SCOPE_BASE,
- state->filter, state->grp_attrs,
- state->opts->group_map,
- SDAP_OPTS_GROUP,
- dp_opt_get_int(state->opts->basic,
- SDAP_SEARCH_TIMEOUT));
- if (!subreq) {
- tevent_req_error(req, ENOMEM);
- return;
- }
- tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
- } else {
- sdap_initgr_nested_store(req);
- }
-}
-
-static int sdap_initgr_nested_store_group(struct sysdb_ctx *sysdb,
- struct sdap_options *opts,
- struct sss_domain_info *dom,
- struct sysdb_attrs *group,
- struct sysdb_attrs **groups,
- int ngroups);
-
-static void sdap_initgr_nested_store(struct tevent_req *req)
-{
- struct sdap_initgr_nested_state *state;
-
- struct ldb_message_element *el;
- errno_t ret;
- int i, mi;
- struct ldb_message **direct_sysdb_groups = NULL;
- size_t direct_sysdb_count = 0;
-
- const char *orig_dn;
- const char *user_dn;
- struct ldb_dn *basedn;
- static const char *group_attrs[] = { SYSDB_NAME, NULL };
- const char *member_filter;
- char **sysdb_grouplist = NULL;
- char **ldap_grouplist = NULL;
- const char *tmp_str;
-
- int ndirect;
- struct sysdb_attrs **direct_groups;
-
- state = tevent_req_data(req, struct sdap_initgr_nested_state);
-
- /* Get direct LDAP parents */
- ret = sysdb_attrs_get_string(state->user, SYSDB_ORIG_DN, &orig_dn);
- if (ret != EOK) {
- DEBUG(2, ("The user has no original DN\n"));
- goto done;
- }
-
- direct_groups = talloc_zero_array(state, struct sysdb_attrs *,
- state->count + 1);
- if (!direct_groups) {
- ret = ENOMEM;
- goto done;
- }
- ndirect = 0;
-
- for (i=0; i < state->groups_cur ; i++) {
- ret = sysdb_attrs_get_el(state->groups[i], SYSDB_MEMBER, &el);
- if (ret) {
- DEBUG(3, ("A group with no members during initgroups?\n"));
- goto done;
- }
-
- for (mi = 0; mi < el->num_values; mi++) {
- if (strcasecmp((const char *) el->values[mi].data, orig_dn) != 0) {
- continue;
- }
-
- direct_groups[ndirect] = state->groups[i];
- ndirect++;
- }
- }
-
- DEBUG(7, ("The user %s is a direct member of %d LDAP groups\n",
- state->username, ndirect));
-
- /* Get direct sysdb parents */
- user_dn = sysdb_user_strdn(state, state->dom->name, state->username);
- if (!user_dn) {
- ret = ENOMEM;
- goto done;
- }
-
- member_filter = talloc_asprintf(state, "(&(%s=%s)(%s=%s))",
- SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS,
- SYSDB_MEMBER, user_dn);
- if (!member_filter) {
- ret = ENOMEM;
- goto done;
- }
-
- basedn = ldb_dn_new_fmt(state, sysdb_ctx_get_ldb(state->sysdb),
- SYSDB_TMPL_GROUP_BASE,
- state->dom->name);
- if (!basedn) {
- ret = ENOMEM;
- goto done;
- }
-
- DEBUG(8, ("searching sysdb with filter [%s]\n", member_filter));
-
- ret = sysdb_search_entry(state, state->sysdb, basedn,
- LDB_SCOPE_SUBTREE, member_filter, group_attrs,
- &direct_sysdb_count, &direct_sysdb_groups);
- if (ret == EOK) {
- /* Get the list of sysdb groups by name */
- sysdb_grouplist = talloc_array(state, char *, direct_sysdb_count+1);
- if (!sysdb_grouplist) {
- ret = ENOMEM;
- goto done;
- }
-
- for(i = 0; i < direct_sysdb_count; i++) {
- tmp_str = ldb_msg_find_attr_as_string(direct_sysdb_groups[i],
- SYSDB_NAME, NULL);
- if (!tmp_str) {
- /* This should never happen, but if it does, just continue */
- continue;
- }
-
- sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);
- if (!sysdb_grouplist[i]) {
- DEBUG(1, ("A group with no name?\n"));
- ret = EIO;
- goto done;
- }
- }
- sysdb_grouplist[i] = NULL;
- } else if (ret == ENOENT) {
- direct_sysdb_groups = NULL;
- direct_sysdb_count = 0;
- } else {
- DEBUG(2, ("sysdb_search_entry failed: [%d]: %s\n", ret, strerror(ret)));
- goto done;
- }
- DEBUG(7, ("The user %s is a member of %d sysdb groups\n",
- state->username, direct_sysdb_count));
-
- /* Store the direct parents with full member/memberof pairs */
- ret = sdap_initgr_common_store(state->sysdb, state->opts,
- state->dom,
- state->username,
- SYSDB_MEMBER_USER,
- sysdb_grouplist,
- direct_groups,
- ndirect, true);
- if (ret != EOK) {
- DEBUG(1, ("sdap_initgr_common_store failed [%d]: %s\n",
- ret, strerror(ret)));
- goto done;
- }
-
- /* Not all indirect groups may be cached.
- * Add fake entries for those that are not */
- ret = sysdb_attrs_primary_name_list(
- state->sysdb, state,
- state->groups, state->groups_cur,
- state->opts->group_map[SDAP_AT_GROUP_NAME].name,
- &ldap_grouplist);
- if (ret != EOK) {
- DEBUG(1, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
- ret, strerror(ret)));
- goto done;
- }
-
- ret = sdap_add_incomplete_groups(state->sysdb, state->opts,
- state->dom, ldap_grouplist,
- state->groups, state->groups_cur);
- if (ret != EOK) {
- DEBUG(1, ("adding incomplete groups failed [%d]: %s\n",
- ret, strerror(ret)));
- goto done;
- }
-
- /* Set the indirect memberships */
- for (i=0; i < state->groups_cur ; i++) {
- ret = sdap_initgr_nested_store_group(state->sysdb, state->opts,
- state->dom, state->groups[i],
- state->groups, state->groups_cur);
- if (ret != EOK) {
- DEBUG(2, ("Cannot fix nested group membership\n"));
- goto done;
- }
- }
-
-done:
- if (ret != EOK) {
- tevent_req_error(req, ret);
- return;
- }
-
- tevent_req_done(req);
-}
-
-static int sdap_initgr_nested_get_direct_parents(TALLOC_CTX *mem_ctx,
- struct sysdb_attrs *attrs,
- struct sysdb_attrs **groups,
- int ngroups,
- struct sysdb_attrs ***_direct_parents,
- int *_ndirect);
-
-static int sdap_initgr_nested_store_group(struct sysdb_ctx *sysdb,
- struct sdap_options *opts,
- struct sss_domain_info *dom,
- struct sysdb_attrs *group,
- struct sysdb_attrs **groups,
- int ngroups)
-{
- TALLOC_CTX *tmp_ctx;
- const char *member_filter;
- const char *group_orig_dn;
- const char *group_name;
- const char *group_dn;
- int ret;
- int i;
- struct ldb_message **direct_sysdb_groups = NULL;
- size_t direct_sysdb_count = 0;
- static const char *group_attrs[] = { SYSDB_NAME, NULL };
- struct ldb_dn *basedn;
- int ndirect;
- struct sysdb_attrs **direct_groups;
- char **sysdb_grouplist = NULL;
- const char *tmp_str;
-
- tmp_ctx = talloc_new(NULL);
- if (!tmp_ctx) return ENOMEM;
-
- basedn = ldb_dn_new_fmt(tmp_ctx, sysdb_ctx_get_ldb(sysdb),
- SYSDB_TMPL_GROUP_BASE,
- dom->name);
- if (!basedn) {
- ret = ENOMEM;
- goto done;
- }
-
- ret = sysdb_attrs_get_string(group, SYSDB_ORIG_DN, &group_orig_dn);
- if (ret != EOK) {
- goto done;
- }
-
- ret = sysdb_attrs_primary_name(sysdb, group,
- opts->group_map[SDAP_AT_GROUP_NAME].name,
- &group_name);
- if (ret != EOK) {
- goto done;
- }
-
- /* Get direct sysdb parents */
- group_dn = sysdb_group_strdn(tmp_ctx, dom->name, group_name);
- if (!group_dn) {
- ret = ENOMEM;
- goto done;
- }
-
- member_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(%s=%s))",
- SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS,
- SYSDB_MEMBER, group_dn);
- if (!member_filter) {
- ret = ENOMEM;
- goto done;
- }
-
- DEBUG(8, ("searching sysdb with filter %s\n", member_filter));
-
- ret = sysdb_search_entry(tmp_ctx, sysdb, basedn,
- LDB_SCOPE_SUBTREE, member_filter, group_attrs,
- &direct_sysdb_count, &direct_sysdb_groups);
- if (ret == EOK) {
- /* Get the list of sysdb groups by name */
- sysdb_grouplist = talloc_array(tmp_ctx, char *, direct_sysdb_count+1);
- if (!sysdb_grouplist) {
- ret = ENOMEM;
- goto done;
- }
-
- for(i = 0; i < direct_sysdb_count; i++) {
- tmp_str = ldb_msg_find_attr_as_string(direct_sysdb_groups[i],
- SYSDB_NAME, NULL);
- if (!tmp_str) {
- /* This should never happen, but if it does, just continue */
- continue;
- }
-
- sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);
- if (!sysdb_grouplist[i]) {
- DEBUG(1, ("A group with no name?\n"));
- ret = EIO;
- goto done;
- }
- }
- sysdb_grouplist[i] = NULL;
- } else if (ret == ENOENT) {
- sysdb_grouplist = NULL;
- direct_sysdb_count = 0;
- } else {
- DEBUG(2, ("sysdb_search_entry failed: [%d]: %s\n", ret, strerror(ret)));
- goto done;
- }
- DEBUG(7, ("The group %s is a member of %d sysdb groups\n",
- group_name, direct_sysdb_count));
-
- /* Filter only parents from full set */
- ret = sdap_initgr_nested_get_direct_parents(tmp_ctx, group, groups,
- ngroups, &direct_groups,
- &ndirect);
- if (ret != EOK) {
- DEBUG(1, ("Cannot get parent groups [%d]: %s\n",
- ret, strerror(ret)));
- goto done;
- }
- DEBUG(7, ("The group %s is a direct member of %d LDAP groups\n",
- group_name, ndirect));
-
- /* Store the direct parents with full member/memberof pairs */
- ret = sdap_initgr_common_store(sysdb, opts, dom, group_name,
- SYSDB_MEMBER_GROUP, sysdb_grouplist,
- direct_groups, ndirect, false);
- if (ret != EOK) {
- DEBUG(1, ("sdap_initgr_common_store failed [%d]: %s\n",
- ret, strerror(ret)));
- goto done;
- }
-
- ret = EOK;
-done:
- talloc_zfree(tmp_ctx);
- return ret;
-}
-
-static int sdap_initgr_nested_get_direct_parents(TALLOC_CTX *mem_ctx,
- struct sysdb_attrs *attrs,
- struct sysdb_attrs **groups,
- int ngroups,
- struct sysdb_attrs ***_direct_parents,
- int *_ndirect)
-{
- TALLOC_CTX *tmp_ctx;
- struct ldb_message_element *member;
- int i, mi;
- int ret;
- const char *orig_dn;
-
- int ndirect;
- struct sysdb_attrs **direct_groups;
-
- tmp_ctx = talloc_new(NULL);
- if (!tmp_ctx) return ENOMEM;
-
-
- direct_groups = talloc_zero_array(tmp_ctx, struct sysdb_attrs *,
- ngroups + 1);
- if (!direct_groups) {
- ret = ENOMEM;
- goto done;
- }
- ndirect = 0;
-
- ret = sysdb_attrs_get_string(attrs, SYSDB_ORIG_DN, &orig_dn);
- if (ret != EOK) {
- DEBUG(3, ("Missing originalDN\n"));
- goto done;
- }
- DEBUG(9, ("Looking up direct parents for group [%s]\n", orig_dn));
-
- /* FIXME - Filter only parents from full set to avoid searching
- * through all members of huge groups. That requires asking for memberOf
- * with the group LDAP search
- */
-
- /* Filter only direct parents from the list of all groups */
- for (i=0; i < ngroups; i++) {
- ret = sysdb_attrs_get_el(groups[i], SYSDB_MEMBER, &member);
- if (ret) {
- DEBUG(7, ("A group with no members during initgroups?\n"));
- continue;
- }
-
- for (mi = 0; mi < member->num_values; mi++) {
- if (strcasecmp((const char *) member->values[mi].data, orig_dn) != 0) {
- continue;
- }
-
- direct_groups[ndirect] = groups[i];
- ndirect++;
- }
- }
- direct_groups[ndirect] = NULL;
-
- DEBUG(9, ("The group [%s] has %d direct parents\n", orig_dn, ndirect));
-
- *_direct_parents = direct_groups;
- *_ndirect = ndirect;
- ret = EOK;
-done:
- talloc_zfree(tmp_ctx);
- return ret;
-}
-
-static int sdap_initgr_nested_recv(struct tevent_req *req)
-{
- TEVENT_REQ_RETURN_ON_ERROR(req);
-
- return EOK;
-}
-
-
-/* ==Initgr-call-(groups-a-user-is-member-of)============================= */
-
-struct sdap_get_initgr_state {
- struct tevent_context *ev;
- struct sysdb_ctx *sysdb;
- struct sdap_options *opts;
- struct sss_domain_info *dom;
- struct sdap_handle *sh;
- struct sdap_id_ctx *id_ctx;
- const char *name;
- const char **grp_attrs;
- const char **ldap_attrs;
-
- struct sysdb_attrs *orig_user;
-};
-
-static void sdap_get_initgr_user(struct tevent_req *subreq);
-static void sdap_get_initgr_done(struct tevent_req *subreq);
-
-struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sdap_handle *sh,
- struct sdap_id_ctx *id_ctx,
- const char *name,
- const char **grp_attrs)
-{
- struct tevent_req *req, *subreq;
- struct sdap_get_initgr_state *state;
- const char *base_dn;
- char *filter;
- int ret;
- char *clean_name;
-
- DEBUG(9, ("Retrieving info for initgroups call\n"));
-
- req = tevent_req_create(memctx, &state, struct sdap_get_initgr_state);
- if (!req) return NULL;
-
- state->ev = ev;
- state->opts = id_ctx->opts;
- state->sysdb = id_ctx->be->sysdb;
- state->dom = id_ctx->be->domain;
- state->sh = sh;
- state->id_ctx = id_ctx;
- state->name = name;
- state->grp_attrs = grp_attrs;
- state->orig_user = NULL;
-
- ret = sss_filter_sanitize(state, name, &clean_name);
- if (ret != EOK) {
- return NULL;
- }
-
- filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
- state->opts->user_map[SDAP_AT_USER_NAME].name,
- clean_name,
- state->opts->user_map[SDAP_OC_USER].name);
- if (!filter) {
- talloc_zfree(req);
- return NULL;
- }
-
- base_dn = dp_opt_get_string(state->opts->basic,
- SDAP_USER_SEARCH_BASE);
- if (!base_dn) {
- talloc_zfree(req);
- return NULL;
- }
-
- ret = build_attrs_from_map(state, state->opts->user_map,
- SDAP_OPTS_USER, &state->ldap_attrs);
- if (ret) {
- talloc_zfree(req);
- return NULL;
- }
-
- subreq = sdap_get_generic_send(state, state->ev,
- state->opts, state->sh,
- base_dn, LDAP_SCOPE_SUBTREE,
- filter, state->ldap_attrs,
- state->opts->user_map, SDAP_OPTS_USER,
- dp_opt_get_int(state->opts->basic,
- SDAP_SEARCH_TIMEOUT));
- if (!subreq) {
- talloc_zfree(req);
- return NULL;
- }
- tevent_req_set_callback(subreq, sdap_get_initgr_user, req);
-
- return req;
-}
-
-static struct tevent_req *sdap_initgr_rfc2307bis_send(
- TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sdap_options *opts,
- struct sysdb_ctx *sysdb,
- struct sss_domain_info *dom,
- struct sdap_handle *sh,
- const char *base_dn,
- const char *name,
- const char *orig_dn);
-static void sdap_get_initgr_user(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(subreq,
- struct tevent_req);
- struct sdap_get_initgr_state *state = tevent_req_data(req,
- struct sdap_get_initgr_state);
- struct sysdb_attrs **usr_attrs;
- size_t count;
- int ret;
- const char *orig_dn;
-
- DEBUG(9, ("Receiving info for the user\n"));
-
- ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs);
- talloc_zfree(subreq);
- if (ret) {
- tevent_req_error(req, ret);
- return;
- }
-
- if (count != 1) {
- DEBUG(2, ("Expected one user entry and got %d\n", count));
- tevent_req_error(req, ENOENT);
- return;
- }
-
- state->orig_user = usr_attrs[0];
-
- ret = sysdb_transaction_start(state->sysdb);
- if (ret) {
- tevent_req_error(req, ret);
- return;
- }
-
- DEBUG(9, ("Storing the user\n"));
-
- ret = sdap_save_user(state, state->sysdb,
- state->opts, state->dom,
- state->orig_user, state->ldap_attrs,
- true, NULL);
- if (ret) {
- sysdb_transaction_cancel(state->sysdb);
- tevent_req_error(req, ret);
- return;
- }
-
- DEBUG(9, ("Commit change\n"));
-
- ret = sysdb_transaction_commit(state->sysdb);
- if (ret) {
- tevent_req_error(req, ret);
- return;
- }
-
- DEBUG(9, ("Process user's groups\n"));
-
- switch (state->opts->schema_type) {
- case SDAP_SCHEMA_RFC2307:
- subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts,
- state->sysdb, state->dom, state->sh,
- dp_opt_get_string(state->opts->basic,
- SDAP_GROUP_SEARCH_BASE),
- state->name);
- if (!subreq) {
- tevent_req_error(req, ENOMEM);
- return;
- }
- tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
- break;
-
- case SDAP_SCHEMA_RFC2307BIS:
- ret = sysdb_attrs_get_string(state->orig_user,
- SYSDB_ORIG_DN,
- &orig_dn);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- return;
- }
-
- subreq = sdap_initgr_rfc2307bis_send(
- state, state->ev, state->opts, state->sysdb,
- state->dom, state->sh,
- dp_opt_get_string(state->opts->basic,
- SDAP_GROUP_SEARCH_BASE),
- state->name, orig_dn);
- if (!subreq) {
- tevent_req_error(req, ENOMEM);
- return;
- }
- talloc_steal(subreq, orig_dn);
- tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
- break;
- case SDAP_SCHEMA_IPA_V1:
- case SDAP_SCHEMA_AD:
- /* TODO: AD uses a different member/memberof schema
- * We need an AD specific call that is able to unroll
- * nested groups by doing extensive recursive searches */
-
- subreq = sdap_initgr_nested_send(state, state->ev, state->opts,
- state->sysdb, state->dom, state->sh,
- state->orig_user, state->grp_attrs);
- if (!subreq) {
- tevent_req_error(req, ENOMEM);
- return;
- }
- tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
- return;
-
- default:
- tevent_req_error(req, EINVAL);
- return;
- }
-}
-
-static int sdap_initgr_rfc2307bis_recv(struct tevent_req *req);
-static void sdap_get_initgr_pgid(struct tevent_req *req);
-static void sdap_get_initgr_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(subreq,
- struct tevent_req);
- struct sdap_get_initgr_state *state = tevent_req_data(req,
- struct sdap_get_initgr_state);
- int ret;
- gid_t primary_gid;
- char *gid;
-
- DEBUG(9, ("Initgroups done\n"));
-
- switch (state->opts->schema_type) {
- case SDAP_SCHEMA_RFC2307:
- ret = sdap_initgr_rfc2307_recv(subreq);
- break;
-
- case SDAP_SCHEMA_RFC2307BIS:
- ret = sdap_initgr_rfc2307bis_recv(subreq);
- break;
-
- case SDAP_SCHEMA_IPA_V1:
- case SDAP_SCHEMA_AD:
- ret = sdap_initgr_nested_recv(subreq);
- break;
-
- default:
-
- ret = EINVAL;
- break;
- }
-
- talloc_zfree(subreq);
- if (ret) {
- DEBUG(9, ("Error in initgroups: [%d][%s]\n",
- ret, strerror(ret)));
- tevent_req_error(req, ret);
- return;
- }
-
- /* We also need to update the user's primary group, since
- * the user may not be an explicit member of that group
- */
- ret = sysdb_attrs_get_uint32_t(state->orig_user, SYSDB_GIDNUM, &primary_gid);
- if (ret != EOK) {
- DEBUG(6, ("Could not find user's primary GID\n"));
- tevent_req_error(req, ret);
- return;
- }
-
- gid = talloc_asprintf(state, "%lu", (unsigned long)primary_gid);
- if (gid == NULL) {
- tevent_req_error(req, ENOMEM);
- return;
- }
-
- subreq = groups_get_send(req, state->ev, state->id_ctx, gid,
- BE_FILTER_IDNUM, BE_ATTR_ALL);
- if (!subreq) {
- tevent_req_error(req, ENOMEM);
- return;
- }
- tevent_req_set_callback(subreq, sdap_get_initgr_pgid, req);
-
- tevent_req_done(req);
-}
-
-static void sdap_get_initgr_pgid(struct tevent_req *subreq)
-{
- struct tevent_req *req =
- tevent_req_callback_data(subreq, struct tevent_req);
- errno_t ret;
-
- ret = groups_get_recv(subreq, NULL);
- talloc_zfree(subreq);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- return;
- }
-
- tevent_req_done(req);
-}
-
-int sdap_get_initgr_recv(struct tevent_req *req)
-{
- TEVENT_REQ_RETURN_ON_ERROR(req);
-
- return EOK;
-}
-
struct sdap_deref_ctx {
const char *orig_dn;
@@ -4544,772 +2808,3 @@ static errno_t sdap_nested_group_process_recv(struct tevent_req *req)
return EOK;
}
-
-static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq);
-static struct tevent_req *sdap_initgr_rfc2307bis_send(
- TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sdap_options *opts,
- struct sysdb_ctx *sysdb,
- struct sss_domain_info *dom,
- struct sdap_handle *sh,
- const char *base_dn,
- const char *name,
- const char *orig_dn)
-{
- errno_t ret;
- struct tevent_req *req;
- struct tevent_req *subreq;
- struct sdap_initgr_rfc2307_state *state;
- const char *filter;
- const char **attrs;
- char *clean_orig_dn;
-
- req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);
- if (!req) return NULL;
-
- state->ev = ev;
- state->opts = opts;
- state->sysdb = sysdb;
- state->dom = dom;
- state->sh = sh;
- state->op = NULL;
- state->name = name;
-
- ret = build_attrs_from_map(state, opts->group_map,
- SDAP_OPTS_GROUP, &attrs);
- if (ret != EOK) {
- talloc_free(req);
- return NULL;
- }
-
- ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn);
- if (ret != EOK) {
- talloc_free(req);
- return NULL;
- }
-
- filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)(%s=*))",
- opts->group_map[SDAP_AT_GROUP_MEMBER].name,
- clean_orig_dn,
- opts->group_map[SDAP_OC_GROUP].name,
- opts->group_map[SDAP_AT_GROUP_NAME].name);
- if (!filter) {
- talloc_zfree(req);
- return NULL;
- }
- talloc_zfree(clean_orig_dn);
-
- DEBUG(6, ("Looking up parent groups for user [%s]\n", orig_dn));
- subreq = sdap_get_generic_send(state, state->ev, state->opts,
- state->sh, base_dn, LDAP_SCOPE_SUBTREE,
- filter, attrs,
- state->opts->group_map, SDAP_OPTS_GROUP,
- dp_opt_get_int(state->opts->basic,
- SDAP_SEARCH_TIMEOUT));
- if (!subreq) {
- talloc_zfree(req);
- return NULL;
- }
- tevent_req_set_callback(subreq, sdap_initgr_rfc2307bis_process, req);
-
- return req;
-
-}
-
-errno_t save_rfc2307bis_user_memberships(
- struct sdap_initgr_rfc2307_state *state);
-struct tevent_req *rfc2307bis_nested_groups_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct sdap_options *opts, struct sysdb_ctx *sysdb,
- struct sss_domain_info *dom, struct sdap_handle *sh,
- struct sysdb_attrs **groups, size_t num_groups,
- size_t nesting);
-static void sdap_initgr_rfc2307bis_done(struct tevent_req *subreq);
-static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq)
-{
- struct tevent_req *req;
- struct sdap_initgr_rfc2307_state *state;
- int ret;
-
- req = tevent_req_callback_data(subreq, struct tevent_req);
- state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
-
- ret = sdap_get_generic_recv(subreq, state,
- &state->ldap_groups_count,
- &state->ldap_groups);
- talloc_zfree(subreq);
- if (ret) {
- tevent_req_error(req, ret);
- return;
- }
-
- if (state->ldap_groups_count == 0) {
- /* Start a transaction to look up the groups in the sysdb
- * and update them with LDAP data
- */
- ret = save_rfc2307bis_user_memberships(state);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- } else {
- tevent_req_done(req);
- }
- return;
- }
-
- subreq = rfc2307bis_nested_groups_send(state, state->ev, state->opts,
- state->sysdb, state->dom,
- state->sh, state->ldap_groups,
- state->ldap_groups_count, 0);
- if (!subreq) {
- tevent_req_error(req, EIO);
- return;
- }
- tevent_req_set_callback(subreq, sdap_initgr_rfc2307bis_done, req);
-}
-
-errno_t save_rfc2307bis_user_memberships(
- struct sdap_initgr_rfc2307_state *state)
-{
- errno_t ret, tret;
- char *member_dn;
- char *sanitized_dn;
- char *filter;
- const char **attrs;
- size_t reply_count, i;
- struct ldb_message **replies;
- char **ldap_grouplist;
- char **sysdb_grouplist;
- char **add_groups;
- char **del_groups;
- const char *tmp_str;
- bool in_transaction = false;
-
- TALLOC_CTX *tmp_ctx = talloc_new(NULL);
- if(!tmp_ctx) {
- return ENOMEM;
- }
-
- DEBUG(7, ("Save parent groups to sysdb\n"));
- ret = sysdb_transaction_start(state->sysdb);
- if (ret != EOK) {
- goto error;
- }
- in_transaction = true;
-
- /* Save this user and their memberships */
- attrs = talloc_array(tmp_ctx, const char *, 2);
- if (!attrs) {
- ret = ENOMEM;
- goto error;
- }
-
- attrs[0] = SYSDB_NAME;
- attrs[1] = NULL;
-
- member_dn = sysdb_user_strdn(tmp_ctx, state->dom->name, state->name);
- if (!member_dn) {
- ret = ENOMEM;
- goto error;
- }
- ret = sss_filter_sanitize(tmp_ctx, member_dn, &sanitized_dn);
- if (ret != EOK) {
- goto error;
- }
- talloc_free(member_dn);
-
- filter = talloc_asprintf(tmp_ctx, "(member=%s)", sanitized_dn);
- if (!filter) {
- ret = ENOMEM;
- goto error;
- }
- talloc_free(sanitized_dn);
-
- ret = sysdb_search_groups(tmp_ctx, state->sysdb, filter, attrs,
- &reply_count, &replies);
- if (ret != EOK && ret != ENOENT) {
- goto error;
- } if (ret == ENOENT) {
- reply_count = 0;
- }
-
- if (reply_count == 0) {
- DEBUG(6, ("User [%s] is not a direct member of any groups\n",
- state->name));
- sysdb_grouplist = NULL;
- } else {
- sysdb_grouplist = talloc_array(tmp_ctx, char *, reply_count+1);
- if (!sysdb_grouplist) {
- ret = ENOMEM;
- goto error;
- }
-
- for (i = 0; i < reply_count; i++) {
- tmp_str = ldb_msg_find_attr_as_string(replies[i],
- SYSDB_NAME,
- NULL);
- if (!tmp_str) {
- /* This should never happen, but if it
- * does, just skip it.
- */
- continue;
- }
-
- sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);
- if (!sysdb_grouplist[i]) {
- ret = ENOMEM;
- goto error;
- }
- }
- sysdb_grouplist[i] = NULL;
- }
-
- if (state->ldap_groups_count == 0) {
- ldap_grouplist = NULL;
- }
- else {
- ret = sysdb_attrs_primary_name_list(
- state->sysdb, tmp_ctx,
- state->ldap_groups, state->ldap_groups_count,
- state->opts->group_map[SDAP_AT_GROUP_NAME].name,
- &ldap_grouplist);
- if (ret != EOK) {
- goto error;
- }
- }
-
- /* Find the differences between the sysdb and ldap lists
- * Groups in ldap only must be added to the sysdb;
- * groups in the sysdb only must be removed.
- */
- ret = diff_string_lists(tmp_ctx,
- ldap_grouplist, sysdb_grouplist,
- &add_groups, &del_groups, NULL);
- if (ret != EOK) {
- goto error;
- }
-
- DEBUG(8, ("Updating memberships for %s\n", state->name));
- ret = sysdb_update_members(state->sysdb, state->name, SYSDB_MEMBER_USER,
- (const char *const *)add_groups,
- (const char *const *)del_groups);
- if (ret != EOK) {
- goto error;
- }
-
- ret = sysdb_transaction_commit(state->sysdb);
- if (ret != EOK) {
- goto error;
- }
-
- return EOK;
-
-error:
- if (in_transaction) {
- tret = sysdb_transaction_cancel(state->sysdb);
- if (tret != EOK) {
- DEBUG(1, ("Failed to cancel transaction\n"));
- }
- }
- talloc_free(tmp_ctx);
- return ret;
-}
-
-static errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req);
-static void sdap_initgr_rfc2307bis_done(struct tevent_req *subreq)
-{
- errno_t ret;
- struct tevent_req *req =
- tevent_req_callback_data(subreq, struct tevent_req);
- struct sdap_initgr_rfc2307_state *state =
- tevent_req_data(req, struct sdap_initgr_rfc2307_state);
-
- ret = rfc2307bis_nested_groups_recv(subreq);
- talloc_zfree(subreq);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- return;
- }
-
- /* save the user memberships */
- ret = save_rfc2307bis_user_memberships(state);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- } else {
- tevent_req_done(req);
- }
- return;
-}
-
-struct sdap_rfc2307bis_nested_ctx {
- struct tevent_context *ev;
- struct sdap_options *opts;
- struct sysdb_ctx *sysdb;
- struct sss_domain_info *dom;
- struct sdap_handle *sh;
- struct sysdb_attrs **groups;
- size_t num_groups;
-
- size_t nesting_level;
-
- size_t group_iter;
- struct sysdb_attrs **ldap_groups;
- size_t ldap_groups_count;
-
- struct sysdb_handle *handle;
-};
-
-static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req);
-struct tevent_req *rfc2307bis_nested_groups_send(
- TALLOC_CTX *mem_ctx, struct tevent_context *ev,
- struct sdap_options *opts, struct sysdb_ctx *sysdb,
- struct sss_domain_info *dom, struct sdap_handle *sh,
- struct sysdb_attrs **groups, size_t num_groups,
- size_t nesting)
-{
- errno_t ret;
- struct tevent_req *req;
- struct sdap_rfc2307bis_nested_ctx *state;
-
- req = tevent_req_create(mem_ctx, &state,
- struct sdap_rfc2307bis_nested_ctx);
- if (!req) return NULL;
-
- if ((num_groups == 0) ||
- (nesting > dp_opt_get_int(opts->basic, SDAP_NESTING_LEVEL))) {
- /* No parent groups to process or too deep*/
- tevent_req_done(req);
- tevent_req_post(req, ev);
- return req;
- }
-
- state->ev = ev;
- state->opts = opts;
- state->sysdb = sysdb;
- state->dom = dom;
- state->sh = sh;
- state->groups = groups;
- state->num_groups = num_groups;
- state->group_iter = 0;
- state->nesting_level = nesting;
-
- ret = rfc2307bis_nested_groups_step(req);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- tevent_req_post(req, ev);
- }
- return req;
-}
-
-static void rfc2307bis_nested_groups_process(struct tevent_req *subreq);
-static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req)
-{
- errno_t ret, tret;
- struct tevent_req *subreq;
- const char *name;
- struct sysdb_attrs **grouplist;
- char **groupnamelist;
- bool in_transaction = false;
- TALLOC_CTX *tmp_ctx = NULL;
- char *filter;
- const char *orig_dn;
- const char **attrs;
- char *clean_orig_dn;
- struct sdap_rfc2307bis_nested_ctx *state =
- tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
-
- tmp_ctx = talloc_new(state);
- if (!tmp_ctx) {
- ret = ENOMEM;
- goto error;
- }
-
- ret = sysdb_attrs_primary_name(
- state->sysdb,
- state->groups[state->group_iter],
- state->opts->group_map[SDAP_AT_GROUP_NAME].name,
- &name);
- if (ret != EOK) {
- goto error;
- }
-
- DEBUG(6, ("Processing group [%s]\n", name));
-
- ret = sysdb_transaction_start(state->sysdb);
- if (ret != EOK) {
- goto error;
- }
- in_transaction = true;
-
- /* First, save the group we're processing to the sysdb
- * sdap_add_incomplete_groups_send will add them if needed
- */
-
- /* sdap_add_incomplete_groups_send expects a list of groups */
- grouplist = talloc_array(tmp_ctx, struct sysdb_attrs *, 1);
- if (!grouplist) {
- ret = ENOMEM;
- goto error;
- }
- grouplist[0] = state->groups[state->group_iter];
-
- groupnamelist = talloc_array(tmp_ctx, char *, 2);
- if (!groupnamelist) {
- ret = ENOMEM;
- goto error;
- }
- groupnamelist[0] = talloc_strdup(groupnamelist, name);
- if (!groupnamelist[0]) {
- ret = ENOMEM;
- goto error;
- }
- groupnamelist[1] = NULL;
-
- DEBUG(6, ("Saving incomplete group [%s] to the sysdb\n",
- groupnamelist[0]));
- ret = sdap_add_incomplete_groups(state->sysdb, state->opts,
- state->dom, groupnamelist,
- grouplist, 1);
- if (ret != EOK) {
- goto error;
- }
-
- ret = sysdb_transaction_commit(state->sysdb);
- if (ret != EOK) {
- goto error;
- }
-
- /* Get any parent groups for this group */
- ret = sysdb_attrs_get_string(state->groups[state->group_iter],
- SYSDB_ORIG_DN,
- &orig_dn);
- if (ret != EOK) {
- goto error;
- }
-
- ret = build_attrs_from_map(tmp_ctx, state->opts->group_map,
- SDAP_OPTS_GROUP, &attrs);
- if (ret != EOK) {
- goto error;
- }
-
- ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn);
- if (ret != EOK) {
- goto error;
- }
-
- filter = talloc_asprintf(
- tmp_ctx, "(&(%s=%s)(objectclass=%s)(%s=*))",
- state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
- clean_orig_dn,
- state->opts->group_map[SDAP_OC_GROUP].name,
- state->opts->group_map[SDAP_AT_GROUP_NAME].name);
- if (!filter) {
- ret = ENOMEM;
- goto error;
- }
- talloc_zfree(clean_orig_dn);
-
- DEBUG(6, ("Looking up parent groups for group [%s]\n", orig_dn));
- subreq = sdap_get_generic_send(state, state->ev, state->opts,
- state->sh,
- dp_opt_get_string(state->opts->basic,
- SDAP_GROUP_SEARCH_BASE),
- LDAP_SCOPE_SUBTREE,
- filter, attrs,
- state->opts->group_map, SDAP_OPTS_GROUP,
- dp_opt_get_int(state->opts->basic,
- SDAP_SEARCH_TIMEOUT));
- if (!subreq) {
- ret = EIO;
- goto error;
- }
- talloc_steal(subreq, tmp_ctx);
- tevent_req_set_callback(subreq,
- rfc2307bis_nested_groups_process,
- req);
-
- return EOK;
-
-error:
- if (in_transaction) {
- tret = sysdb_transaction_cancel(state->sysdb);
- if (tret != EOK) {
- DEBUG(1, ("Failed to cancel transaction\n"));
- }
- }
-
- talloc_free(tmp_ctx);
- return ret;
-}
-
-static errno_t rfc2307bis_nested_groups_update_sysdb(
- struct sdap_rfc2307bis_nested_ctx *state);
-static void rfc2307bis_nested_groups_done(struct tevent_req *subreq);
-static void rfc2307bis_nested_groups_process(struct tevent_req *subreq)
-{
- errno_t ret;
- struct tevent_req *req =
- tevent_req_callback_data(subreq, struct tevent_req);
- struct sdap_rfc2307bis_nested_ctx *state =
- tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
-
- ret = sdap_get_generic_recv(subreq, state,
- &state->ldap_groups_count,
- &state->ldap_groups);
- talloc_zfree(subreq);
- if (ret) {
- tevent_req_error(req, ret);
- return;
- }
-
- if (state->ldap_groups_count == 0) {
- /* No parent groups for this group in LDAP
- * We need to ensure that there are no groups
- * in the sysdb either.
- */
-
- ret = rfc2307bis_nested_groups_update_sysdb(state);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- return;
- }
-
- state->group_iter++;
- if (state->group_iter < state->num_groups) {
- ret = rfc2307bis_nested_groups_step(req);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- return;
- }
- } else {
- tevent_req_done(req);
- }
- return;
- }
-
- /* Otherwise, recurse into the groups */
- subreq = rfc2307bis_nested_groups_send(
- state, state->ev, state->opts, state->sysdb,
- state->dom, state->sh,
- state->ldap_groups,
- state->ldap_groups_count,
- state->nesting_level+1);
- if (!subreq) {
- tevent_req_error(req, EIO);
- return;
- }
- tevent_req_set_callback(subreq, rfc2307bis_nested_groups_done, req);
-}
-
-static errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req)
-{
- TEVENT_REQ_RETURN_ON_ERROR(req);
- return EOK;
-}
-
-static void rfc2307bis_nested_groups_done(struct tevent_req *subreq)
-{
- errno_t ret;
- struct tevent_req *req =
- tevent_req_callback_data(subreq, struct tevent_req);
- struct sdap_rfc2307bis_nested_ctx *state =
- tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
-
- ret = rfc2307bis_nested_groups_recv(subreq);
- talloc_zfree(subreq);
- if (ret != EOK) {
- DEBUG(6, ("rfc2307bis_nested failed [%d][%s]\n",
- ret, strerror(ret)));
- tevent_req_error(req, ret);
- return;
- }
-
- /* All of the parent groups have been added
- * Now add the memberships
- */
-
- ret = rfc2307bis_nested_groups_update_sysdb(state);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- return;
- }
-
- state->group_iter++;
- if (state->group_iter < state->num_groups) {
- ret = rfc2307bis_nested_groups_step(req);
- if (ret != EOK) {
- tevent_req_error(req, ret);
- }
- } else {
- tevent_req_done(req);
- }
-}
-
-static errno_t rfc2307bis_nested_groups_update_sysdb(
- struct sdap_rfc2307bis_nested_ctx *state)
-{
- errno_t ret, tret;
- const char *name;
- bool in_transaction = false;
- char *member_dn;
- char *sanitized_dn;
- char *filter;
- const char **attrs;
- size_t reply_count, i;
- struct ldb_message **replies;
- char **sysdb_grouplist;
- char **ldap_grouplist;
- char **add_groups;
- char **del_groups;
- const char *tmp_str;
-
- TALLOC_CTX *tmp_ctx = talloc_new(state);
- if (!tmp_ctx) {
- return ENOMEM;
- }
-
- /* Start a transaction to look up the groups in the sysdb
- * and update them with LDAP data
- */
- ret = sysdb_transaction_start(state->sysdb);
- if (ret != EOK) {
- goto error;
- }
- in_transaction = true;
-
- ret = sysdb_attrs_primary_name(
- state->sysdb,
- state->groups[state->group_iter],
- state->opts->group_map[SDAP_AT_GROUP_NAME].name,
- &name);
- if (ret != EOK) {
- goto error;
- }
-
- DEBUG(6, ("Processing group [%s]\n", name));
-
- attrs = talloc_array(tmp_ctx, const char *, 2);
- if (!attrs) {
- ret = ENOMEM;
- goto error;
- }
- attrs[0] = SYSDB_NAME;
- attrs[1] = NULL;
-
- member_dn = sysdb_group_strdn(tmp_ctx, state->dom->name, name);
- if (!member_dn) {
- ret = ENOMEM;
- goto error;
- }
-
- ret = sss_filter_sanitize(tmp_ctx, member_dn, &sanitized_dn);
- if (ret != EOK) {
- goto error;
- }
- talloc_free(member_dn);
-
- filter = talloc_asprintf(tmp_ctx, "(member=%s)", sanitized_dn);
- if (!filter) {
- ret = ENOMEM;
- goto error;
- }
- talloc_free(sanitized_dn);
-
- ret = sysdb_search_groups(tmp_ctx, state->sysdb, filter, attrs,
- &reply_count, &replies);
- if (ret != EOK && ret != ENOENT) {
- goto error;
- } else if (ret == ENOENT) {
- reply_count = 0;
- }
-
- if (reply_count == 0) {
- DEBUG(6, ("Group [%s] is not a direct member of any groups\n", name));
- sysdb_grouplist = NULL;
- } else {
- sysdb_grouplist = talloc_array(tmp_ctx, char *, reply_count+1);
- if (!sysdb_grouplist) {
- ret = ENOMEM;
- goto error;
- }
-
- for (i = 0; i < reply_count; i++) {
- tmp_str = ldb_msg_find_attr_as_string(replies[i],
- SYSDB_NAME,
- NULL);
- if (!tmp_str) {
- /* This should never happen, but if it
- * does, just skip it.
- */
- continue;
- }
-
- sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);
- if (!sysdb_grouplist[i]) {
- ret = ENOMEM;
- goto error;
- }
- }
- sysdb_grouplist[i] = NULL;
- }
-
- if (state->ldap_groups_count == 0) {
- ldap_grouplist = NULL;
- }
- else {
- ret = sysdb_attrs_primary_name_list(
- state->sysdb, tmp_ctx,
- state->ldap_groups, state->ldap_groups_count,
- state->opts->group_map[SDAP_AT_GROUP_NAME].name,
- &ldap_grouplist);
- if (ret != EOK) {
- goto error;
- }
- }
-
- /* Find the differences between the sysdb and ldap lists
- * Groups in ldap only must be added to the sysdb;
- * groups in the sysdb only must be removed.
- */
- ret = diff_string_lists(state,
- ldap_grouplist, sysdb_grouplist,
- &add_groups, &del_groups, NULL);
- if (ret != EOK) {
- goto error;
- }
- talloc_free(ldap_grouplist);
- talloc_free(sysdb_grouplist);
-
- DEBUG(8, ("Updating memberships for %s\n", name));
- ret = sysdb_update_members(state->sysdb, name, SYSDB_MEMBER_GROUP,
- (const char *const *)add_groups,
- (const char *const *)del_groups);
- if (ret != EOK) {
- goto error;
- }
-
- ret = sysdb_transaction_commit(state->sysdb);
- if (ret != EOK) {
- goto error;
- }
- in_transaction = false;
-
- ret = EOK;
-
-error:
- if (in_transaction) {
- tret = sysdb_transaction_cancel(state->sysdb);
- if (tret != EOK) {
- DEBUG(1, ("Failed to cancel transaction\n"));
- }
- }
- talloc_free(tmp_ctx);
- return ret;
-}
-
-static int sdap_initgr_rfc2307bis_recv(struct tevent_req *req)
-{
- TEVENT_REQ_RETURN_ON_ERROR(req);
- return EOK;
-}
diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c
new file mode 100644
index 00000000..8edda2e3
--- /dev/null
+++ b/src/providers/ldap/sdap_async_initgroups.c
@@ -0,0 +1,2049 @@
+/*
+ SSSD
+
+ Async LDAP Helper routines - initgroups operation
+
+ Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
+ Copyright (C) 2010, Ralf Haferkamp <rhafer@suse.de>, Novell Inc.
+ Copyright (C) Jan Zeleny <jzeleny@redhat.com> - 2011
+
+ 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 "util/util.h"
+#include "db/sysdb.h"
+#include "providers/ldap/sdap_async_private.h"
+#include "providers/ldap/ldap_common.h"
+
+/* ==Save-fake-group-list=====================================*/
+static errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
+ struct sdap_options *opts,
+ struct sss_domain_info *dom,
+ char **groupnames,
+ struct sysdb_attrs **ldap_groups,
+ int ldap_groups_count)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message *msg;
+ int i, mi, ai;
+ const char *name;
+ const char *original_dn;
+ char **missing;
+ gid_t gid;
+ int ret;
+ bool in_transaction = false;
+ bool posix;
+
+ /* There are no groups in LDAP but we should add user to groups ?? */
+ if (ldap_groups_count == 0) return EOK;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) return ENOMEM;
+
+ missing = talloc_array(tmp_ctx, char *, ldap_groups_count+1);
+ if (!missing) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ mi = 0;
+
+ ret = sysdb_transaction_start(sysdb);
+ if (ret != EOK) {
+ DEBUG(1, ("Cannot start sysdb transaction [%d]: %s\n",
+ ret, strerror(ret)));
+ goto fail;
+ }
+ in_transaction = true;
+
+ for (i=0; groupnames[i]; i++) {
+ ret = sysdb_search_group_by_name(tmp_ctx, sysdb, groupnames[i], NULL, &msg);
+ if (ret == EOK) {
+ continue;
+ } else if (ret == ENOENT) {
+ DEBUG(7, ("Group #%d [%s] is not cached, need to add a fake entry\n",
+ i, groupnames[i]));
+ missing[mi] = groupnames[i];
+ mi++;
+ continue;
+ } else if (ret != ENOENT) {
+ DEBUG(1, ("search for group failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto fail;
+ }
+ }
+ missing[mi] = NULL;
+
+ /* All groups are cached, nothing to do */
+ if (mi == 0) {
+ talloc_zfree(tmp_ctx);
+ goto done;
+ }
+
+ for (i=0; missing[i]; i++) {
+ /* The group is not in sysdb, need to add a fake entry */
+ for (ai=0; ai < ldap_groups_count; ai++) {
+ ret = sysdb_attrs_primary_name(sysdb, ldap_groups[ai],
+ opts->group_map[SDAP_AT_GROUP_NAME].name,
+ &name);
+ if (ret != EOK) {
+ DEBUG(1, ("The group has no name attribute\n"));
+ goto fail;
+ }
+
+ if (strcmp(name, missing[i]) == 0) {
+ posix = true;
+ ret = sysdb_attrs_get_uint32_t(ldap_groups[ai],
+ SYSDB_GIDNUM,
+ &gid);
+ if (ret == ENOENT || (ret == EOK && gid == 0)) {
+ DEBUG(9, ("The group %s gid was %s\n",
+ name, ret == ENOENT ? "missing" : "zero"));
+ DEBUG(8, ("Marking group %s as non-posix and setting GID=0!\n", name));
+ gid = 0;
+ posix = false;
+ } else if (ret) {
+ DEBUG(1, ("The GID attribute is malformed\n"));
+ goto fail;
+ }
+
+ ret = sysdb_attrs_get_string(ldap_groups[ai],
+ SYSDB_ORIG_DN,
+ &original_dn);
+ if (ret) {
+ DEBUG(5, ("The group has no name original DN\n"));
+ original_dn = NULL;
+ }
+
+ DEBUG(8, ("Adding fake group %s to sysdb\n", name));
+ ret = sysdb_add_incomplete_group(sysdb, name, gid, original_dn,
+ posix);
+ if (ret != EOK) {
+ goto fail;
+ }
+ break;
+ }
+ }
+
+ if (ai == ldap_groups_count) {
+ DEBUG(2, ("Group %s not present in LDAP\n", missing[i]));
+ ret = EINVAL;
+ goto fail;
+ }
+ }
+
+done:
+ ret = sysdb_transaction_commit(sysdb);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_transaction_commit failed.\n"));
+ goto fail;
+ }
+ in_transaction = false;
+ ret = EOK;
+fail:
+ if (in_transaction) {
+ sysdb_transaction_cancel(sysdb);
+ }
+ return ret;
+}
+
+static int sdap_initgr_common_store(struct sysdb_ctx *sysdb,
+ struct sdap_options *opts,
+ struct sss_domain_info *dom,
+ const char *name,
+ enum sysdb_member_type type,
+ char **sysdb_grouplist,
+ struct sysdb_attrs **ldap_groups,
+ int ldap_groups_count,
+ bool add_fake)
+{
+ TALLOC_CTX *tmp_ctx;
+ char **ldap_grouplist = NULL;
+ char **add_groups;
+ char **del_groups;
+ int ret;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) return ENOMEM;
+
+ if (ldap_groups_count == 0) {
+ /* No groups for this user in LDAP.
+ * We need to ensure that there are no groups
+ * in the sysdb either.
+ */
+ ldap_grouplist = NULL;
+ } else {
+ ret = sysdb_attrs_primary_name_list(
+ sysdb, tmp_ctx,
+ ldap_groups, ldap_groups_count,
+ opts->group_map[SDAP_AT_GROUP_NAME].name,
+ &ldap_grouplist);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ }
+
+ /* Find the differences between the sysdb and LDAP lists
+ * Groups in the sysdb only must be removed.
+ */
+ ret = diff_string_lists(tmp_ctx, ldap_grouplist, sysdb_grouplist,
+ &add_groups, &del_groups, NULL);
+ if (ret != EOK) goto done;
+
+ /* Add fake entries for any groups the user should be added as
+ * member of but that are not cached in sysdb
+ */
+ if (add_fake && add_groups && add_groups[0]) {
+ ret = sdap_add_incomplete_groups(sysdb, opts, dom,
+ add_groups, ldap_groups,
+ ldap_groups_count);
+ if (ret != EOK) {
+ DEBUG(1, ("Adding incomplete users failed\n"));
+ goto done;
+ }
+ }
+
+ DEBUG(8, ("Updating memberships for %s\n", name));
+ ret = sysdb_update_members(sysdb, name, type,
+ (const char *const *) add_groups,
+ (const char *const *) del_groups);
+ if (ret != EOK) {
+ DEBUG(1, ("Membership update failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ ret = EOK;
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
+/* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307-Classic/BIS========= */
+
+struct sdap_initgr_rfc2307_state {
+ struct tevent_context *ev;
+ struct sysdb_ctx *sysdb;
+ struct sdap_options *opts;
+ struct sss_domain_info *dom;
+ struct sdap_handle *sh;
+ const char *name;
+
+ struct sdap_op *op;
+
+ struct sysdb_attrs **ldap_groups;
+ size_t ldap_groups_count;
+};
+
+static void sdap_initgr_rfc2307_process(struct tevent_req *subreq);
+struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sysdb_ctx *sysdb,
+ struct sss_domain_info *dom,
+ struct sdap_handle *sh,
+ const char *base_dn,
+ const char *name)
+{
+ struct tevent_req *req, *subreq;
+ struct sdap_initgr_rfc2307_state *state;
+ const char *filter;
+ const char **attrs;
+ char *clean_name;
+ errno_t ret;
+
+ req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = opts;
+ state->sysdb = sysdb;
+ state->dom = dom;
+ state->sh = sh;
+ state->op = NULL;
+ state->name = talloc_strdup(state, name);
+ if (!state->name) {
+ talloc_zfree(req);
+ return NULL;
+ }
+
+ ret = build_attrs_from_map(state, opts->group_map,
+ SDAP_OPTS_GROUP, &attrs);
+ if (ret != EOK) {
+ talloc_free(req);
+ return NULL;
+ }
+
+ ret = sss_filter_sanitize(state, name, &clean_name);
+ if (ret != EOK) {
+ talloc_free(req);
+ return NULL;
+ }
+
+ filter = talloc_asprintf(state,
+ "(&(%s=%s)(objectclass=%s)(%s=*)(&(%s=*)(!(%s=0))))",
+ opts->group_map[SDAP_AT_GROUP_MEMBER].name,
+ clean_name,
+ opts->group_map[SDAP_OC_GROUP].name,
+ opts->group_map[SDAP_AT_GROUP_NAME].name,
+ opts->group_map[SDAP_AT_GROUP_GID].name,
+ opts->group_map[SDAP_AT_GROUP_GID].name);
+ if (!filter) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ talloc_zfree(clean_name);
+
+ subreq = sdap_get_generic_send(state, state->ev, state->opts,
+ state->sh, base_dn, LDAP_SCOPE_SUBTREE,
+ filter, attrs,
+ state->opts->group_map, SDAP_OPTS_GROUP,
+ dp_opt_get_int(state->opts->basic,
+ SDAP_SEARCH_TIMEOUT));
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, sdap_initgr_rfc2307_process, req);
+
+ return req;
+}
+
+static void sdap_initgr_rfc2307_process(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct sdap_initgr_rfc2307_state *state;
+ struct sysdb_attrs **ldap_groups;
+ char **sysdb_grouplist = NULL;
+ struct ldb_message *msg;
+ struct ldb_message_element *groups;
+ size_t count;
+ const char *attrs[2];
+ int ret;
+ int i;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
+
+ ret = sdap_get_generic_recv(subreq, state, &count, &ldap_groups);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ /* Search for all groups for which this user is a member */
+ attrs[0] = SYSDB_MEMBEROF;
+ attrs[1] = NULL;
+ ret = sysdb_search_user_by_name(state, state->sysdb, state->name, attrs,
+ &msg);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ groups = ldb_msg_find_element(msg, SYSDB_MEMBEROF);
+ if (!groups || groups->num_values == 0) {
+ /* No groups for this user in sysdb currently */
+ sysdb_grouplist = NULL;
+ } else {
+ sysdb_grouplist = talloc_array(state, char *, groups->num_values+1);
+ if (!sysdb_grouplist) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ /* Get a list of the groups by groupname only */
+ for (i=0; i < groups->num_values; i++) {
+ ret = sysdb_group_dn_name(state->sysdb,
+ sysdb_grouplist,
+ (const char *)groups->values[i].data,
+ &sysdb_grouplist[i]);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+ }
+ sysdb_grouplist[groups->num_values] = NULL;
+ }
+
+ /* There are no nested groups here so we can just update the
+ * memberships */
+ ret = sdap_initgr_common_store(state->sysdb, state->opts,
+ state->dom, state->name,
+ SYSDB_MEMBER_USER, sysdb_grouplist,
+ ldap_groups, count, true);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static int sdap_initgr_rfc2307_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+
+/* ==Initgr-call-(groups-a-user-is-member-of)-nested-groups=============== */
+
+struct sdap_initgr_nested_state {
+ struct tevent_context *ev;
+ struct sysdb_ctx *sysdb;
+ struct sdap_options *opts;
+ struct sss_domain_info *dom;
+ struct sdap_handle *sh;
+
+ struct sysdb_attrs *user;
+ const char *username;
+
+ const char **grp_attrs;
+
+ char *filter;
+ char **group_dns;
+ int count;
+ int cur;
+
+ struct sdap_op *op;
+
+ struct sysdb_attrs **groups;
+ int groups_cur;
+};
+
+static void sdap_initgr_nested_search(struct tevent_req *subreq);
+static void sdap_initgr_nested_store(struct tevent_req *req);
+static struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sysdb_ctx *sysdb,
+ struct sss_domain_info *dom,
+ struct sdap_handle *sh,
+ struct sysdb_attrs *user,
+ const char **grp_attrs)
+{
+ struct tevent_req *req, *subreq;
+ struct sdap_initgr_nested_state *state;
+ struct ldb_message_element *el;
+ int i;
+ errno_t ret;
+
+ req = tevent_req_create(memctx, &state, struct sdap_initgr_nested_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = opts;
+ state->sysdb = sysdb;
+ state->dom = dom;
+ state->sh = sh;
+ state->grp_attrs = grp_attrs;
+ state->user = user;
+ state->op = NULL;
+
+ ret = sysdb_attrs_primary_name(sysdb, user,
+ opts->user_map[SDAP_AT_USER_NAME].name,
+ &state->username);
+ if (ret != EOK) {
+ DEBUG(1, ("User entry had no username\n"));
+ talloc_free(req);
+ return NULL;
+ }
+
+ state->filter = talloc_asprintf(state, "(&(objectclass=%s)(%s=*))",
+ opts->group_map[SDAP_OC_GROUP].name,
+ opts->group_map[SDAP_AT_GROUP_NAME].name);
+ if (!state->filter) {
+ talloc_zfree(req);
+ return NULL;
+ }
+
+ /* TODO: test rootDSE for deref support and use it if available */
+ /* TODO: or test rootDSE for ASQ support and use it if available */
+
+ ret = sysdb_attrs_get_el(user, SYSDB_MEMBEROF, &el);
+ if (ret || !el || el->num_values == 0) {
+ DEBUG(4, ("User entry lacks original memberof ?\n"));
+ /* We can't find any groups for this user, so we'll
+ * have to assume there aren't any. Just return
+ * success here.
+ */
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ return req;
+ }
+ state->count = el->num_values;
+
+ state->groups = talloc_zero_array(state, struct sysdb_attrs *,
+ state->count + 1);;
+ if (!state->groups) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ state->groups_cur = 0;
+
+ state->group_dns = talloc_array(state, char *, state->count + 1);
+ if (!state->group_dns) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ for (i = 0; i < state->count; i++) {
+ state->group_dns[i] = talloc_strdup(state->group_dns,
+ (char *)el->values[i].data);
+ if (!state->group_dns[i]) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ }
+ state->group_dns[i] = NULL; /* terminate */
+ state->cur = 0;
+
+ subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
+ state->group_dns[state->cur],
+ LDAP_SCOPE_BASE,
+ state->filter, state->grp_attrs,
+ state->opts->group_map, SDAP_OPTS_GROUP,
+ dp_opt_get_int(state->opts->basic,
+ SDAP_SEARCH_TIMEOUT));
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
+
+ return req;
+}
+
+static void sdap_initgr_nested_search(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct sdap_initgr_nested_state *state;
+ struct sysdb_attrs **groups;
+ size_t count;
+ int ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_initgr_nested_state);
+
+ ret = sdap_get_generic_recv(subreq, state, &count, &groups);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (count == 1) {
+ state->groups[state->groups_cur] = groups[0];
+ state->groups_cur++;
+ } else {
+ DEBUG(2, ("Search for group %s, returned %d results. Skipping\n",
+ state->group_dns[state->cur], count));
+ }
+
+ state->cur++;
+ if (state->cur < state->count) {
+ subreq = sdap_get_generic_send(state, state->ev,
+ state->opts, state->sh,
+ state->group_dns[state->cur],
+ LDAP_SCOPE_BASE,
+ state->filter, state->grp_attrs,
+ state->opts->group_map,
+ SDAP_OPTS_GROUP,
+ dp_opt_get_int(state->opts->basic,
+ SDAP_SEARCH_TIMEOUT));
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
+ } else {
+ sdap_initgr_nested_store(req);
+ }
+}
+
+static int sdap_initgr_nested_store_group(struct sysdb_ctx *sysdb,
+ struct sdap_options *opts,
+ struct sss_domain_info *dom,
+ struct sysdb_attrs *group,
+ struct sysdb_attrs **groups,
+ int ngroups);
+
+static void sdap_initgr_nested_store(struct tevent_req *req)
+{
+ struct sdap_initgr_nested_state *state;
+
+ struct ldb_message_element *el;
+ errno_t ret;
+ int i, mi;
+ struct ldb_message **direct_sysdb_groups = NULL;
+ size_t direct_sysdb_count = 0;
+
+ const char *orig_dn;
+ const char *user_dn;
+ struct ldb_dn *basedn;
+ static const char *group_attrs[] = { SYSDB_NAME, NULL };
+ const char *member_filter;
+ char **sysdb_grouplist = NULL;
+ char **ldap_grouplist = NULL;
+ const char *tmp_str;
+
+ int ndirect;
+ struct sysdb_attrs **direct_groups;
+
+ state = tevent_req_data(req, struct sdap_initgr_nested_state);
+
+ /* Get direct LDAP parents */
+ ret = sysdb_attrs_get_string(state->user, SYSDB_ORIG_DN, &orig_dn);
+ if (ret != EOK) {
+ DEBUG(2, ("The user has no original DN\n"));
+ goto done;
+ }
+
+ direct_groups = talloc_zero_array(state, struct sysdb_attrs *,
+ state->count + 1);
+ if (!direct_groups) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ndirect = 0;
+
+ for (i=0; i < state->groups_cur ; i++) {
+ ret = sysdb_attrs_get_el(state->groups[i], SYSDB_MEMBER, &el);
+ if (ret) {
+ DEBUG(3, ("A group with no members during initgroups?\n"));
+ goto done;
+ }
+
+ for (mi = 0; mi < el->num_values; mi++) {
+ if (strcasecmp((const char *) el->values[mi].data, orig_dn) != 0) {
+ continue;
+ }
+
+ direct_groups[ndirect] = state->groups[i];
+ ndirect++;
+ }
+ }
+
+ DEBUG(7, ("The user %s is a direct member of %d LDAP groups\n",
+ state->username, ndirect));
+
+ /* Get direct sysdb parents */
+ user_dn = sysdb_user_strdn(state, state->dom->name, state->username);
+ if (!user_dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ member_filter = talloc_asprintf(state, "(&(%s=%s)(%s=%s))",
+ SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS,
+ SYSDB_MEMBER, user_dn);
+ if (!member_filter) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ basedn = ldb_dn_new_fmt(state, sysdb_ctx_get_ldb(state->sysdb),
+ SYSDB_TMPL_GROUP_BASE,
+ state->dom->name);
+ if (!basedn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ DEBUG(8, ("searching sysdb with filter [%s]\n", member_filter));
+
+ ret = sysdb_search_entry(state, state->sysdb, basedn,
+ LDB_SCOPE_SUBTREE, member_filter, group_attrs,
+ &direct_sysdb_count, &direct_sysdb_groups);
+ if (ret == EOK) {
+ /* Get the list of sysdb groups by name */
+ sysdb_grouplist = talloc_array(state, char *, direct_sysdb_count+1);
+ if (!sysdb_grouplist) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for(i = 0; i < direct_sysdb_count; i++) {
+ tmp_str = ldb_msg_find_attr_as_string(direct_sysdb_groups[i],
+ SYSDB_NAME, NULL);
+ if (!tmp_str) {
+ /* This should never happen, but if it does, just continue */
+ continue;
+ }
+
+ sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);
+ if (!sysdb_grouplist[i]) {
+ DEBUG(1, ("A group with no name?\n"));
+ ret = EIO;
+ goto done;
+ }
+ }
+ sysdb_grouplist[i] = NULL;
+ } else if (ret == ENOENT) {
+ direct_sysdb_groups = NULL;
+ direct_sysdb_count = 0;
+ } else {
+ DEBUG(2, ("sysdb_search_entry failed: [%d]: %s\n", ret, strerror(ret)));
+ goto done;
+ }
+ DEBUG(7, ("The user %s is a member of %d sysdb groups\n",
+ state->username, direct_sysdb_count));
+
+ /* Store the direct parents with full member/memberof pairs */
+ ret = sdap_initgr_common_store(state->sysdb, state->opts,
+ state->dom,
+ state->username,
+ SYSDB_MEMBER_USER,
+ sysdb_grouplist,
+ direct_groups,
+ ndirect, true);
+ if (ret != EOK) {
+ DEBUG(1, ("sdap_initgr_common_store failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ /* Not all indirect groups may be cached.
+ * Add fake entries for those that are not */
+ ret = sysdb_attrs_primary_name_list(
+ state->sysdb, state,
+ state->groups, state->groups_cur,
+ state->opts->group_map[SDAP_AT_GROUP_NAME].name,
+ &ldap_grouplist);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ ret = sdap_add_incomplete_groups(state->sysdb, state->opts,
+ state->dom, ldap_grouplist,
+ state->groups, state->groups_cur);
+ if (ret != EOK) {
+ DEBUG(1, ("adding incomplete groups failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ /* Set the indirect memberships */
+ for (i=0; i < state->groups_cur ; i++) {
+ ret = sdap_initgr_nested_store_group(state->sysdb, state->opts,
+ state->dom, state->groups[i],
+ state->groups, state->groups_cur);
+ if (ret != EOK) {
+ DEBUG(2, ("Cannot fix nested group membership\n"));
+ goto done;
+ }
+ }
+
+done:
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static int sdap_initgr_nested_get_direct_parents(TALLOC_CTX *mem_ctx,
+ struct sysdb_attrs *attrs,
+ struct sysdb_attrs **groups,
+ int ngroups,
+ struct sysdb_attrs ***_direct_parents,
+ int *_ndirect);
+
+static int sdap_initgr_nested_store_group(struct sysdb_ctx *sysdb,
+ struct sdap_options *opts,
+ struct sss_domain_info *dom,
+ struct sysdb_attrs *group,
+ struct sysdb_attrs **groups,
+ int ngroups)
+{
+ TALLOC_CTX *tmp_ctx;
+ const char *member_filter;
+ const char *group_orig_dn;
+ const char *group_name;
+ const char *group_dn;
+ int ret;
+ int i;
+ struct ldb_message **direct_sysdb_groups = NULL;
+ size_t direct_sysdb_count = 0;
+ static const char *group_attrs[] = { SYSDB_NAME, NULL };
+ struct ldb_dn *basedn;
+ int ndirect;
+ struct sysdb_attrs **direct_groups;
+ char **sysdb_grouplist = NULL;
+ const char *tmp_str;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) return ENOMEM;
+
+ basedn = ldb_dn_new_fmt(tmp_ctx, sysdb_ctx_get_ldb(sysdb),
+ SYSDB_TMPL_GROUP_BASE,
+ dom->name);
+ if (!basedn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = sysdb_attrs_get_string(group, SYSDB_ORIG_DN, &group_orig_dn);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ ret = sysdb_attrs_primary_name(sysdb, group,
+ opts->group_map[SDAP_AT_GROUP_NAME].name,
+ &group_name);
+ if (ret != EOK) {
+ goto done;
+ }
+
+ /* Get direct sysdb parents */
+ group_dn = sysdb_group_strdn(tmp_ctx, dom->name, group_name);
+ if (!group_dn) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ member_filter = talloc_asprintf(tmp_ctx, "(&(%s=%s)(%s=%s))",
+ SYSDB_OBJECTCLASS, SYSDB_GROUP_CLASS,
+ SYSDB_MEMBER, group_dn);
+ if (!member_filter) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ DEBUG(8, ("searching sysdb with filter %s\n", member_filter));
+
+ ret = sysdb_search_entry(tmp_ctx, sysdb, basedn,
+ LDB_SCOPE_SUBTREE, member_filter, group_attrs,
+ &direct_sysdb_count, &direct_sysdb_groups);
+ if (ret == EOK) {
+ /* Get the list of sysdb groups by name */
+ sysdb_grouplist = talloc_array(tmp_ctx, char *, direct_sysdb_count+1);
+ if (!sysdb_grouplist) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ for(i = 0; i < direct_sysdb_count; i++) {
+ tmp_str = ldb_msg_find_attr_as_string(direct_sysdb_groups[i],
+ SYSDB_NAME, NULL);
+ if (!tmp_str) {
+ /* This should never happen, but if it does, just continue */
+ continue;
+ }
+
+ sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);
+ if (!sysdb_grouplist[i]) {
+ DEBUG(1, ("A group with no name?\n"));
+ ret = EIO;
+ goto done;
+ }
+ }
+ sysdb_grouplist[i] = NULL;
+ } else if (ret == ENOENT) {
+ sysdb_grouplist = NULL;
+ direct_sysdb_count = 0;
+ } else {
+ DEBUG(2, ("sysdb_search_entry failed: [%d]: %s\n", ret, strerror(ret)));
+ goto done;
+ }
+ DEBUG(7, ("The group %s is a member of %d sysdb groups\n",
+ group_name, direct_sysdb_count));
+
+ /* Filter only parents from full set */
+ ret = sdap_initgr_nested_get_direct_parents(tmp_ctx, group, groups,
+ ngroups, &direct_groups,
+ &ndirect);
+ if (ret != EOK) {
+ DEBUG(1, ("Cannot get parent groups [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+ DEBUG(7, ("The group %s is a direct member of %d LDAP groups\n",
+ group_name, ndirect));
+
+ /* Store the direct parents with full member/memberof pairs */
+ ret = sdap_initgr_common_store(sysdb, opts, dom, group_name,
+ SYSDB_MEMBER_GROUP, sysdb_grouplist,
+ direct_groups, ndirect, false);
+ if (ret != EOK) {
+ DEBUG(1, ("sdap_initgr_common_store failed [%d]: %s\n",
+ ret, strerror(ret)));
+ goto done;
+ }
+
+ ret = EOK;
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
+static int sdap_initgr_nested_get_direct_parents(TALLOC_CTX *mem_ctx,
+ struct sysdb_attrs *attrs,
+ struct sysdb_attrs **groups,
+ int ngroups,
+ struct sysdb_attrs ***_direct_parents,
+ int *_ndirect)
+{
+ TALLOC_CTX *tmp_ctx;
+ struct ldb_message_element *member;
+ int i, mi;
+ int ret;
+ const char *orig_dn;
+
+ int ndirect;
+ struct sysdb_attrs **direct_groups;
+
+ tmp_ctx = talloc_new(NULL);
+ if (!tmp_ctx) return ENOMEM;
+
+
+ direct_groups = talloc_zero_array(tmp_ctx, struct sysdb_attrs *,
+ ngroups + 1);
+ if (!direct_groups) {
+ ret = ENOMEM;
+ goto done;
+ }
+ ndirect = 0;
+
+ ret = sysdb_attrs_get_string(attrs, SYSDB_ORIG_DN, &orig_dn);
+ if (ret != EOK) {
+ DEBUG(3, ("Missing originalDN\n"));
+ goto done;
+ }
+ DEBUG(9, ("Looking up direct parents for group [%s]\n", orig_dn));
+
+ /* FIXME - Filter only parents from full set to avoid searching
+ * through all members of huge groups. That requires asking for memberOf
+ * with the group LDAP search
+ */
+
+ /* Filter only direct parents from the list of all groups */
+ for (i=0; i < ngroups; i++) {
+ ret = sysdb_attrs_get_el(groups[i], SYSDB_MEMBER, &member);
+ if (ret) {
+ DEBUG(7, ("A group with no members during initgroups?\n"));
+ continue;
+ }
+
+ for (mi = 0; mi < member->num_values; mi++) {
+ if (strcasecmp((const char *) member->values[mi].data, orig_dn) != 0) {
+ continue;
+ }
+
+ direct_groups[ndirect] = groups[i];
+ ndirect++;
+ }
+ }
+ direct_groups[ndirect] = NULL;
+
+ DEBUG(9, ("The group [%s] has %d direct parents\n", orig_dn, ndirect));
+
+ *_direct_parents = direct_groups;
+ *_ndirect = ndirect;
+ ret = EOK;
+done:
+ talloc_zfree(tmp_ctx);
+ return ret;
+}
+
+static int sdap_initgr_nested_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+
+/* ==Initgr-call-(groups-a-user-is-member-of)============================= */
+
+struct sdap_get_initgr_state {
+ struct tevent_context *ev;
+ struct sysdb_ctx *sysdb;
+ struct sdap_options *opts;
+ struct sss_domain_info *dom;
+ struct sdap_handle *sh;
+ struct sdap_id_ctx *id_ctx;
+ const char *name;
+ const char **grp_attrs;
+ const char **ldap_attrs;
+
+ struct sysdb_attrs *orig_user;
+};
+
+static void sdap_get_initgr_user(struct tevent_req *subreq);
+static void sdap_get_initgr_done(struct tevent_req *subreq);
+
+struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_handle *sh,
+ struct sdap_id_ctx *id_ctx,
+ const char *name,
+ const char **grp_attrs)
+{
+ struct tevent_req *req, *subreq;
+ struct sdap_get_initgr_state *state;
+ const char *base_dn;
+ char *filter;
+ int ret;
+ char *clean_name;
+
+ DEBUG(9, ("Retrieving info for initgroups call\n"));
+
+ req = tevent_req_create(memctx, &state, struct sdap_get_initgr_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = id_ctx->opts;
+ state->sysdb = id_ctx->be->sysdb;
+ state->dom = id_ctx->be->domain;
+ state->sh = sh;
+ state->id_ctx = id_ctx;
+ state->name = name;
+ state->grp_attrs = grp_attrs;
+ state->orig_user = NULL;
+
+ ret = sss_filter_sanitize(state, name, &clean_name);
+ if (ret != EOK) {
+ return NULL;
+ }
+
+ filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
+ state->opts->user_map[SDAP_AT_USER_NAME].name,
+ clean_name,
+ state->opts->user_map[SDAP_OC_USER].name);
+ if (!filter) {
+ talloc_zfree(req);
+ return NULL;
+ }
+
+ base_dn = dp_opt_get_string(state->opts->basic,
+ SDAP_USER_SEARCH_BASE);
+ if (!base_dn) {
+ talloc_zfree(req);
+ return NULL;
+ }
+
+ ret = build_attrs_from_map(state, state->opts->user_map,
+ SDAP_OPTS_USER, &state->ldap_attrs);
+ if (ret) {
+ talloc_zfree(req);
+ return NULL;
+ }
+
+ subreq = sdap_get_generic_send(state, state->ev,
+ state->opts, state->sh,
+ base_dn, LDAP_SCOPE_SUBTREE,
+ filter, state->ldap_attrs,
+ state->opts->user_map, SDAP_OPTS_USER,
+ dp_opt_get_int(state->opts->basic,
+ SDAP_SEARCH_TIMEOUT));
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, sdap_get_initgr_user, req);
+
+ return req;
+}
+
+static struct tevent_req *sdap_initgr_rfc2307bis_send(
+ TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sysdb_ctx *sysdb,
+ struct sss_domain_info *dom,
+ struct sdap_handle *sh,
+ const char *base_dn,
+ const char *name,
+ const char *orig_dn);
+static void sdap_get_initgr_user(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_get_initgr_state *state = tevent_req_data(req,
+ struct sdap_get_initgr_state);
+ struct sysdb_attrs **usr_attrs;
+ size_t count;
+ int ret;
+ const char *orig_dn;
+
+ DEBUG(9, ("Receiving info for the user\n"));
+
+ ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (count != 1) {
+ DEBUG(2, ("Expected one user entry and got %d\n", count));
+ tevent_req_error(req, ENOENT);
+ return;
+ }
+
+ state->orig_user = usr_attrs[0];
+
+ ret = sysdb_transaction_start(state->sysdb);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(9, ("Storing the user\n"));
+
+ ret = sdap_save_user(state, state->sysdb,
+ state->opts, state->dom,
+ state->orig_user, state->ldap_attrs,
+ true, NULL);
+ if (ret) {
+ sysdb_transaction_cancel(state->sysdb);
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(9, ("Commit change\n"));
+
+ ret = sysdb_transaction_commit(state->sysdb);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(9, ("Process user's groups\n"));
+
+ switch (state->opts->schema_type) {
+ case SDAP_SCHEMA_RFC2307:
+ subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts,
+ state->sysdb, state->dom, state->sh,
+ dp_opt_get_string(state->opts->basic,
+ SDAP_GROUP_SEARCH_BASE),
+ state->name);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
+ break;
+
+ case SDAP_SCHEMA_RFC2307BIS:
+ ret = sysdb_attrs_get_string(state->orig_user,
+ SYSDB_ORIG_DN,
+ &orig_dn);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = sdap_initgr_rfc2307bis_send(
+ state, state->ev, state->opts, state->sysdb,
+ state->dom, state->sh,
+ dp_opt_get_string(state->opts->basic,
+ SDAP_GROUP_SEARCH_BASE),
+ state->name, orig_dn);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ talloc_steal(subreq, orig_dn);
+ tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
+ break;
+ case SDAP_SCHEMA_IPA_V1:
+ case SDAP_SCHEMA_AD:
+ /* TODO: AD uses a different member/memberof schema
+ * We need an AD specific call that is able to unroll
+ * nested groups by doing extensive recursive searches */
+
+ subreq = sdap_initgr_nested_send(state, state->ev, state->opts,
+ state->sysdb, state->dom, state->sh,
+ state->orig_user, state->grp_attrs);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
+ return;
+
+ default:
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+}
+
+static int sdap_initgr_rfc2307bis_recv(struct tevent_req *req);
+static void sdap_get_initgr_pgid(struct tevent_req *req);
+static void sdap_get_initgr_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_get_initgr_state *state = tevent_req_data(req,
+ struct sdap_get_initgr_state);
+ int ret;
+ gid_t primary_gid;
+ char *gid;
+
+ DEBUG(9, ("Initgroups done\n"));
+
+ switch (state->opts->schema_type) {
+ case SDAP_SCHEMA_RFC2307:
+ ret = sdap_initgr_rfc2307_recv(subreq);
+ break;
+
+ case SDAP_SCHEMA_RFC2307BIS:
+ ret = sdap_initgr_rfc2307bis_recv(subreq);
+ break;
+
+ case SDAP_SCHEMA_IPA_V1:
+ case SDAP_SCHEMA_AD:
+ ret = sdap_initgr_nested_recv(subreq);
+ break;
+
+ default:
+
+ ret = EINVAL;
+ break;
+ }
+
+ talloc_zfree(subreq);
+ if (ret) {
+ DEBUG(9, ("Error in initgroups: [%d][%s]\n",
+ ret, strerror(ret)));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ /* We also need to update the user's primary group, since
+ * the user may not be an explicit member of that group
+ */
+ ret = sysdb_attrs_get_uint32_t(state->orig_user, SYSDB_GIDNUM, &primary_gid);
+ if (ret != EOK) {
+ DEBUG(6, ("Could not find user's primary GID\n"));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ gid = talloc_asprintf(state, "%lu", (unsigned long)primary_gid);
+ if (gid == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+
+ subreq = groups_get_send(req, state->ev, state->id_ctx, gid,
+ BE_FILTER_IDNUM, BE_ATTR_ALL);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, sdap_get_initgr_pgid, req);
+
+ tevent_req_done(req);
+}
+
+static void sdap_get_initgr_pgid(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ errno_t ret;
+
+ ret = groups_get_recv(subreq, NULL);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+int sdap_get_initgr_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
+
+static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq);
+static struct tevent_req *sdap_initgr_rfc2307bis_send(
+ TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sysdb_ctx *sysdb,
+ struct sss_domain_info *dom,
+ struct sdap_handle *sh,
+ const char *base_dn,
+ const char *name,
+ const char *orig_dn)
+{
+ errno_t ret;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct sdap_initgr_rfc2307_state *state;
+ const char *filter;
+ const char **attrs;
+ char *clean_orig_dn;
+
+ req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = opts;
+ state->sysdb = sysdb;
+ state->dom = dom;
+ state->sh = sh;
+ state->op = NULL;
+ state->name = name;
+
+ ret = build_attrs_from_map(state, opts->group_map,
+ SDAP_OPTS_GROUP, &attrs);
+ if (ret != EOK) {
+ talloc_free(req);
+ return NULL;
+ }
+
+ ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn);
+ if (ret != EOK) {
+ talloc_free(req);
+ return NULL;
+ }
+
+ filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s)(%s=*))",
+ opts->group_map[SDAP_AT_GROUP_MEMBER].name,
+ clean_orig_dn,
+ opts->group_map[SDAP_OC_GROUP].name,
+ opts->group_map[SDAP_AT_GROUP_NAME].name);
+ if (!filter) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ talloc_zfree(clean_orig_dn);
+
+ DEBUG(6, ("Looking up parent groups for user [%s]\n", orig_dn));
+ subreq = sdap_get_generic_send(state, state->ev, state->opts,
+ state->sh, base_dn, LDAP_SCOPE_SUBTREE,
+ filter, attrs,
+ state->opts->group_map, SDAP_OPTS_GROUP,
+ dp_opt_get_int(state->opts->basic,
+ SDAP_SEARCH_TIMEOUT));
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, sdap_initgr_rfc2307bis_process, req);
+
+ return req;
+
+}
+
+errno_t save_rfc2307bis_user_memberships(
+ struct sdap_initgr_rfc2307_state *state);
+struct tevent_req *rfc2307bis_nested_groups_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct sdap_options *opts, struct sysdb_ctx *sysdb,
+ struct sss_domain_info *dom, struct sdap_handle *sh,
+ struct sysdb_attrs **groups, size_t num_groups,
+ size_t nesting);
+static void sdap_initgr_rfc2307bis_done(struct tevent_req *subreq);
+static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq)
+{
+ struct tevent_req *req;
+ struct sdap_initgr_rfc2307_state *state;
+ int ret;
+
+ req = tevent_req_callback_data(subreq, struct tevent_req);
+ state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
+
+ ret = sdap_get_generic_recv(subreq, state,
+ &state->ldap_groups_count,
+ &state->ldap_groups);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (state->ldap_groups_count == 0) {
+ /* Start a transaction to look up the groups in the sysdb
+ * and update them with LDAP data
+ */
+ ret = save_rfc2307bis_user_memberships(state);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ } else {
+ tevent_req_done(req);
+ }
+ return;
+ }
+
+ subreq = rfc2307bis_nested_groups_send(state, state->ev, state->opts,
+ state->sysdb, state->dom,
+ state->sh, state->ldap_groups,
+ state->ldap_groups_count, 0);
+ if (!subreq) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+ tevent_req_set_callback(subreq, sdap_initgr_rfc2307bis_done, req);
+}
+
+errno_t save_rfc2307bis_user_memberships(
+ struct sdap_initgr_rfc2307_state *state)
+{
+ errno_t ret, tret;
+ char *member_dn;
+ char *sanitized_dn;
+ char *filter;
+ const char **attrs;
+ size_t reply_count, i;
+ struct ldb_message **replies;
+ char **ldap_grouplist;
+ char **sysdb_grouplist;
+ char **add_groups;
+ char **del_groups;
+ const char *tmp_str;
+ bool in_transaction = false;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+ if(!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ DEBUG(7, ("Save parent groups to sysdb\n"));
+ ret = sysdb_transaction_start(state->sysdb);
+ if (ret != EOK) {
+ goto error;
+ }
+ in_transaction = true;
+
+ /* Save this user and their memberships */
+ attrs = talloc_array(tmp_ctx, const char *, 2);
+ if (!attrs) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ attrs[0] = SYSDB_NAME;
+ attrs[1] = NULL;
+
+ member_dn = sysdb_user_strdn(tmp_ctx, state->dom->name, state->name);
+ if (!member_dn) {
+ ret = ENOMEM;
+ goto error;
+ }
+ ret = sss_filter_sanitize(tmp_ctx, member_dn, &sanitized_dn);
+ if (ret != EOK) {
+ goto error;
+ }
+ talloc_free(member_dn);
+
+ filter = talloc_asprintf(tmp_ctx, "(member=%s)", sanitized_dn);
+ if (!filter) {
+ ret = ENOMEM;
+ goto error;
+ }
+ talloc_free(sanitized_dn);
+
+ ret = sysdb_search_groups(tmp_ctx, state->sysdb, filter, attrs,
+ &reply_count, &replies);
+ if (ret != EOK && ret != ENOENT) {
+ goto error;
+ } if (ret == ENOENT) {
+ reply_count = 0;
+ }
+
+ if (reply_count == 0) {
+ DEBUG(6, ("User [%s] is not a direct member of any groups\n",
+ state->name));
+ sysdb_grouplist = NULL;
+ } else {
+ sysdb_grouplist = talloc_array(tmp_ctx, char *, reply_count+1);
+ if (!sysdb_grouplist) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ for (i = 0; i < reply_count; i++) {
+ tmp_str = ldb_msg_find_attr_as_string(replies[i],
+ SYSDB_NAME,
+ NULL);
+ if (!tmp_str) {
+ /* This should never happen, but if it
+ * does, just skip it.
+ */
+ continue;
+ }
+
+ sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);
+ if (!sysdb_grouplist[i]) {
+ ret = ENOMEM;
+ goto error;
+ }
+ }
+ sysdb_grouplist[i] = NULL;
+ }
+
+ if (state->ldap_groups_count == 0) {
+ ldap_grouplist = NULL;
+ }
+ else {
+ ret = sysdb_attrs_primary_name_list(
+ state->sysdb, tmp_ctx,
+ state->ldap_groups, state->ldap_groups_count,
+ state->opts->group_map[SDAP_AT_GROUP_NAME].name,
+ &ldap_grouplist);
+ if (ret != EOK) {
+ goto error;
+ }
+ }
+
+ /* Find the differences between the sysdb and ldap lists
+ * Groups in ldap only must be added to the sysdb;
+ * groups in the sysdb only must be removed.
+ */
+ ret = diff_string_lists(tmp_ctx,
+ ldap_grouplist, sysdb_grouplist,
+ &add_groups, &del_groups, NULL);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ DEBUG(8, ("Updating memberships for %s\n", state->name));
+ ret = sysdb_update_members(state->sysdb, state->name, SYSDB_MEMBER_USER,
+ (const char *const *)add_groups,
+ (const char *const *)del_groups);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ ret = sysdb_transaction_commit(state->sysdb);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ return EOK;
+
+error:
+ if (in_transaction) {
+ tret = sysdb_transaction_cancel(state->sysdb);
+ if (tret != EOK) {
+ DEBUG(1, ("Failed to cancel transaction\n"));
+ }
+ }
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req);
+static void sdap_initgr_rfc2307bis_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct sdap_initgr_rfc2307_state *state =
+ tevent_req_data(req, struct sdap_initgr_rfc2307_state);
+
+ ret = rfc2307bis_nested_groups_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ /* save the user memberships */
+ ret = save_rfc2307bis_user_memberships(state);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ } else {
+ tevent_req_done(req);
+ }
+ return;
+}
+
+struct sdap_rfc2307bis_nested_ctx {
+ struct tevent_context *ev;
+ struct sdap_options *opts;
+ struct sysdb_ctx *sysdb;
+ struct sss_domain_info *dom;
+ struct sdap_handle *sh;
+ struct sysdb_attrs **groups;
+ size_t num_groups;
+
+ size_t nesting_level;
+
+ size_t group_iter;
+ struct sysdb_attrs **ldap_groups;
+ size_t ldap_groups_count;
+
+ struct sysdb_handle *handle;
+};
+
+static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req);
+struct tevent_req *rfc2307bis_nested_groups_send(
+ TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+ struct sdap_options *opts, struct sysdb_ctx *sysdb,
+ struct sss_domain_info *dom, struct sdap_handle *sh,
+ struct sysdb_attrs **groups, size_t num_groups,
+ size_t nesting)
+{
+ errno_t ret;
+ struct tevent_req *req;
+ struct sdap_rfc2307bis_nested_ctx *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct sdap_rfc2307bis_nested_ctx);
+ if (!req) return NULL;
+
+ if ((num_groups == 0) ||
+ (nesting > dp_opt_get_int(opts->basic, SDAP_NESTING_LEVEL))) {
+ /* No parent groups to process or too deep*/
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ return req;
+ }
+
+ state->ev = ev;
+ state->opts = opts;
+ state->sysdb = sysdb;
+ state->dom = dom;
+ state->sh = sh;
+ state->groups = groups;
+ state->num_groups = num_groups;
+ state->group_iter = 0;
+ state->nesting_level = nesting;
+
+ ret = rfc2307bis_nested_groups_step(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ }
+ return req;
+}
+
+static void rfc2307bis_nested_groups_process(struct tevent_req *subreq);
+static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req)
+{
+ errno_t ret, tret;
+ struct tevent_req *subreq;
+ const char *name;
+ struct sysdb_attrs **grouplist;
+ char **groupnamelist;
+ bool in_transaction = false;
+ TALLOC_CTX *tmp_ctx = NULL;
+ char *filter;
+ const char *orig_dn;
+ const char **attrs;
+ char *clean_orig_dn;
+ struct sdap_rfc2307bis_nested_ctx *state =
+ tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
+
+ tmp_ctx = talloc_new(state);
+ if (!tmp_ctx) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ ret = sysdb_attrs_primary_name(
+ state->sysdb,
+ state->groups[state->group_iter],
+ state->opts->group_map[SDAP_AT_GROUP_NAME].name,
+ &name);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ DEBUG(6, ("Processing group [%s]\n", name));
+
+ ret = sysdb_transaction_start(state->sysdb);
+ if (ret != EOK) {
+ goto error;
+ }
+ in_transaction = true;
+
+ /* First, save the group we're processing to the sysdb
+ * sdap_add_incomplete_groups_send will add them if needed
+ */
+
+ /* sdap_add_incomplete_groups_send expects a list of groups */
+ grouplist = talloc_array(tmp_ctx, struct sysdb_attrs *, 1);
+ if (!grouplist) {
+ ret = ENOMEM;
+ goto error;
+ }
+ grouplist[0] = state->groups[state->group_iter];
+
+ groupnamelist = talloc_array(tmp_ctx, char *, 2);
+ if (!groupnamelist) {
+ ret = ENOMEM;
+ goto error;
+ }
+ groupnamelist[0] = talloc_strdup(groupnamelist, name);
+ if (!groupnamelist[0]) {
+ ret = ENOMEM;
+ goto error;
+ }
+ groupnamelist[1] = NULL;
+
+ DEBUG(6, ("Saving incomplete group [%s] to the sysdb\n",
+ groupnamelist[0]));
+ ret = sdap_add_incomplete_groups(state->sysdb, state->opts,
+ state->dom, groupnamelist,
+ grouplist, 1);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ ret = sysdb_transaction_commit(state->sysdb);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ /* Get any parent groups for this group */
+ ret = sysdb_attrs_get_string(state->groups[state->group_iter],
+ SYSDB_ORIG_DN,
+ &orig_dn);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ ret = build_attrs_from_map(tmp_ctx, state->opts->group_map,
+ SDAP_OPTS_GROUP, &attrs);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ filter = talloc_asprintf(
+ tmp_ctx, "(&(%s=%s)(objectclass=%s)(%s=*))",
+ state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
+ clean_orig_dn,
+ state->opts->group_map[SDAP_OC_GROUP].name,
+ state->opts->group_map[SDAP_AT_GROUP_NAME].name);
+ if (!filter) {
+ ret = ENOMEM;
+ goto error;
+ }
+ talloc_zfree(clean_orig_dn);
+
+ DEBUG(6, ("Looking up parent groups for group [%s]\n", orig_dn));
+ subreq = sdap_get_generic_send(state, state->ev, state->opts,
+ state->sh,
+ dp_opt_get_string(state->opts->basic,
+ SDAP_GROUP_SEARCH_BASE),
+ LDAP_SCOPE_SUBTREE,
+ filter, attrs,
+ state->opts->group_map, SDAP_OPTS_GROUP,
+ dp_opt_get_int(state->opts->basic,
+ SDAP_SEARCH_TIMEOUT));
+ if (!subreq) {
+ ret = EIO;
+ goto error;
+ }
+ talloc_steal(subreq, tmp_ctx);
+ tevent_req_set_callback(subreq,
+ rfc2307bis_nested_groups_process,
+ req);
+
+ return EOK;
+
+error:
+ if (in_transaction) {
+ tret = sysdb_transaction_cancel(state->sysdb);
+ if (tret != EOK) {
+ DEBUG(1, ("Failed to cancel transaction\n"));
+ }
+ }
+
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static errno_t rfc2307bis_nested_groups_update_sysdb(
+ struct sdap_rfc2307bis_nested_ctx *state);
+static void rfc2307bis_nested_groups_done(struct tevent_req *subreq);
+static void rfc2307bis_nested_groups_process(struct tevent_req *subreq)
+{
+ errno_t ret;
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct sdap_rfc2307bis_nested_ctx *state =
+ tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
+
+ ret = sdap_get_generic_recv(subreq, state,
+ &state->ldap_groups_count,
+ &state->ldap_groups);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (state->ldap_groups_count == 0) {
+ /* No parent groups for this group in LDAP
+ * We need to ensure that there are no groups
+ * in the sysdb either.
+ */
+
+ ret = rfc2307bis_nested_groups_update_sysdb(state);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ state->group_iter++;
+ if (state->group_iter < state->num_groups) {
+ ret = rfc2307bis_nested_groups_step(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+ } else {
+ tevent_req_done(req);
+ }
+ return;
+ }
+
+ /* Otherwise, recurse into the groups */
+ subreq = rfc2307bis_nested_groups_send(
+ state, state->ev, state->opts, state->sysdb,
+ state->dom, state->sh,
+ state->ldap_groups,
+ state->ldap_groups_count,
+ state->nesting_level+1);
+ if (!subreq) {
+ tevent_req_error(req, EIO);
+ return;
+ }
+ tevent_req_set_callback(subreq, rfc2307bis_nested_groups_done, req);
+}
+
+static errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ return EOK;
+}
+
+static void rfc2307bis_nested_groups_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct sdap_rfc2307bis_nested_ctx *state =
+ tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
+
+ ret = rfc2307bis_nested_groups_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(6, ("rfc2307bis_nested failed [%d][%s]\n",
+ ret, strerror(ret)));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ /* All of the parent groups have been added
+ * Now add the memberships
+ */
+
+ ret = rfc2307bis_nested_groups_update_sysdb(state);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ state->group_iter++;
+ if (state->group_iter < state->num_groups) {
+ ret = rfc2307bis_nested_groups_step(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ }
+ } else {
+ tevent_req_done(req);
+ }
+}
+
+static errno_t rfc2307bis_nested_groups_update_sysdb(
+ struct sdap_rfc2307bis_nested_ctx *state)
+{
+ errno_t ret, tret;
+ const char *name;
+ bool in_transaction = false;
+ char *member_dn;
+ char *sanitized_dn;
+ char *filter;
+ const char **attrs;
+ size_t reply_count, i;
+ struct ldb_message **replies;
+ char **sysdb_grouplist;
+ char **ldap_grouplist;
+ char **add_groups;
+ char **del_groups;
+ const char *tmp_str;
+
+ TALLOC_CTX *tmp_ctx = talloc_new(state);
+ if (!tmp_ctx) {
+ return ENOMEM;
+ }
+
+ /* Start a transaction to look up the groups in the sysdb
+ * and update them with LDAP data
+ */
+ ret = sysdb_transaction_start(state->sysdb);
+ if (ret != EOK) {
+ goto error;
+ }
+ in_transaction = true;
+
+ ret = sysdb_attrs_primary_name(
+ state->sysdb,
+ state->groups[state->group_iter],
+ state->opts->group_map[SDAP_AT_GROUP_NAME].name,
+ &name);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ DEBUG(6, ("Processing group [%s]\n", name));
+
+ attrs = talloc_array(tmp_ctx, const char *, 2);
+ if (!attrs) {
+ ret = ENOMEM;
+ goto error;
+ }
+ attrs[0] = SYSDB_NAME;
+ attrs[1] = NULL;
+
+ member_dn = sysdb_group_strdn(tmp_ctx, state->dom->name, name);
+ if (!member_dn) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ ret = sss_filter_sanitize(tmp_ctx, member_dn, &sanitized_dn);
+ if (ret != EOK) {
+ goto error;
+ }
+ talloc_free(member_dn);
+
+ filter = talloc_asprintf(tmp_ctx, "(member=%s)", sanitized_dn);
+ if (!filter) {
+ ret = ENOMEM;
+ goto error;
+ }
+ talloc_free(sanitized_dn);
+
+ ret = sysdb_search_groups(tmp_ctx, state->sysdb, filter, attrs,
+ &reply_count, &replies);
+ if (ret != EOK && ret != ENOENT) {
+ goto error;
+ } else if (ret == ENOENT) {
+ reply_count = 0;
+ }
+
+ if (reply_count == 0) {
+ DEBUG(6, ("Group [%s] is not a direct member of any groups\n", name));
+ sysdb_grouplist = NULL;
+ } else {
+ sysdb_grouplist = talloc_array(tmp_ctx, char *, reply_count+1);
+ if (!sysdb_grouplist) {
+ ret = ENOMEM;
+ goto error;
+ }
+
+ for (i = 0; i < reply_count; i++) {
+ tmp_str = ldb_msg_find_attr_as_string(replies[i],
+ SYSDB_NAME,
+ NULL);
+ if (!tmp_str) {
+ /* This should never happen, but if it
+ * does, just skip it.
+ */
+ continue;
+ }
+
+ sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);
+ if (!sysdb_grouplist[i]) {
+ ret = ENOMEM;
+ goto error;
+ }
+ }
+ sysdb_grouplist[i] = NULL;
+ }
+
+ if (state->ldap_groups_count == 0) {
+ ldap_grouplist = NULL;
+ }
+ else {
+ ret = sysdb_attrs_primary_name_list(
+ state->sysdb, tmp_ctx,
+ state->ldap_groups, state->ldap_groups_count,
+ state->opts->group_map[SDAP_AT_GROUP_NAME].name,
+ &ldap_grouplist);
+ if (ret != EOK) {
+ goto error;
+ }
+ }
+
+ /* Find the differences between the sysdb and ldap lists
+ * Groups in ldap only must be added to the sysdb;
+ * groups in the sysdb only must be removed.
+ */
+ ret = diff_string_lists(state,
+ ldap_grouplist, sysdb_grouplist,
+ &add_groups, &del_groups, NULL);
+ if (ret != EOK) {
+ goto error;
+ }
+ talloc_free(ldap_grouplist);
+ talloc_free(sysdb_grouplist);
+
+ DEBUG(8, ("Updating memberships for %s\n", name));
+ ret = sysdb_update_members(state->sysdb, name, SYSDB_MEMBER_GROUP,
+ (const char *const *)add_groups,
+ (const char *const *)del_groups);
+ if (ret != EOK) {
+ goto error;
+ }
+
+ ret = sysdb_transaction_commit(state->sysdb);
+ if (ret != EOK) {
+ goto error;
+ }
+ in_transaction = false;
+
+ ret = EOK;
+
+error:
+ if (in_transaction) {
+ tret = sysdb_transaction_cancel(state->sysdb);
+ if (tret != EOK) {
+ DEBUG(1, ("Failed to cancel transaction\n"));
+ }
+ }
+ talloc_free(tmp_ctx);
+ return ret;
+}
+
+static int sdap_initgr_rfc2307bis_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+ return EOK;
+}
diff --git a/src/providers/ldap/sdap_async_private.h b/src/providers/ldap/sdap_async_private.h
index b29b18df..5b041716 100644
--- a/src/providers/ldap/sdap_async_private.h
+++ b/src/providers/ldap/sdap_async_private.h
@@ -74,4 +74,21 @@ int sdap_get_tgt_recv(struct tevent_req *req,
char **ccname,
time_t *expire_time_out);
+int sdap_save_user(TALLOC_CTX *memctx,
+ struct sysdb_ctx *ctx,
+ struct sdap_options *opts,
+ struct sss_domain_info *dom,
+ struct sysdb_attrs *attrs,
+ const char **ldap_attrs,
+ bool is_initgr,
+ char **_usn_value);
+
+int sdap_save_users(TALLOC_CTX *memctx,
+ struct sysdb_ctx *sysdb,
+ const char **attrs,
+ struct sss_domain_info *dom,
+ struct sdap_options *opts,
+ struct sysdb_attrs **users,
+ int num_users,
+ char **_usn_value);
#endif /* _SDAP_ASYNC_PRIVATE_H_ */
diff --git a/src/providers/ldap/sdap_async_users.c b/src/providers/ldap/sdap_async_users.c
new file mode 100644
index 00000000..82338dc1
--- /dev/null
+++ b/src/providers/ldap/sdap_async_users.c
@@ -0,0 +1,513 @@
+/*
+ SSSD
+
+ Async LDAP Helper routines - retrieving users
+
+ Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
+ Copyright (C) 2010, Ralf Haferkamp <rhafer@suse.de>, Novell Inc.
+ Copyright (C) Jan Zeleny <jzeleny@redhat.com> - 2011
+
+ 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 "util/util.h"
+#include "db/sysdb.h"
+#include "providers/ldap/sdap_async_private.h"
+#include "providers/ldap/ldap_common.h"
+
+/* ==Save-User-Entry====================================================== */
+
+/* FIXME: support storing additional attributes */
+
+int sdap_save_user(TALLOC_CTX *memctx,
+ struct sysdb_ctx *ctx,
+ struct sdap_options *opts,
+ struct sss_domain_info *dom,
+ struct sysdb_attrs *attrs,
+ const char **ldap_attrs,
+ bool is_initgr,
+ char **_usn_value)
+{
+ struct ldb_message_element *el;
+ int ret;
+ const char *name = NULL;
+ const char *pwd;
+ const char *gecos;
+ const char *homedir;
+ const char *shell;
+ uid_t uid;
+ gid_t gid;
+ struct sysdb_attrs *user_attrs;
+ char *upn = NULL;
+ size_t i;
+ char *val = NULL;
+ int cache_timeout;
+ char *usn_value = NULL;
+ size_t c;
+ char **missing = NULL;
+ TALLOC_CTX *tmpctx = NULL;
+
+ DEBUG(9, ("Save user\n"));
+
+ tmpctx = talloc_new(memctx);
+ if (!tmpctx) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ user_attrs = sysdb_new_attrs(tmpctx);
+ if (user_attrs == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = sysdb_attrs_primary_name(ctx, attrs,
+ opts->user_map[SDAP_AT_USER_NAME].name,
+ &name);
+ if (ret != EOK) {
+ DEBUG(1, ("Failed to save the user - entry has no name attribute\n"));
+ goto fail;
+ }
+
+ ret = sysdb_attrs_get_el(attrs,
+ opts->user_map[SDAP_AT_USER_PWD].sys_name, &el);
+ if (ret) goto fail;
+ if (el->num_values == 0) pwd = NULL;
+ else pwd = (const char *)el->values[0].data;
+
+ ret = sysdb_attrs_get_el(attrs,
+ opts->user_map[SDAP_AT_USER_GECOS].sys_name, &el);
+ if (ret) goto fail;
+ if (el->num_values == 0) gecos = NULL;
+ else gecos = (const char *)el->values[0].data;
+
+ if (!gecos) {
+ /* Fall back to the user's full name */
+ ret = sysdb_attrs_get_el(
+ attrs,
+ opts->user_map[SDAP_AT_USER_FULLNAME].sys_name, &el);
+ if (ret) goto fail;
+ if (el->num_values > 0) gecos = (const char *)el->values[0].data;
+ }
+
+ ret = sysdb_attrs_get_el(attrs,
+ opts->user_map[SDAP_AT_USER_HOME].sys_name, &el);
+ if (ret) goto fail;
+ if (el->num_values == 0) homedir = NULL;
+ else homedir = (const char *)el->values[0].data;
+
+ ret = sysdb_attrs_get_el(attrs,
+ opts->user_map[SDAP_AT_USER_SHELL].sys_name, &el);
+ if (ret) goto fail;
+ if (el->num_values == 0) shell = NULL;
+ else shell = (const char *)el->values[0].data;
+
+ ret = sysdb_attrs_get_uint32_t(attrs,
+ opts->user_map[SDAP_AT_USER_UID].sys_name,
+ &uid);
+ if (ret != EOK) {
+ DEBUG(1, ("no uid provided for [%s] in domain [%s].\n",
+ name, dom->name));
+ ret = EINVAL;
+ goto fail;
+ }
+
+ /* check that the uid is valid for this domain */
+ if (OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) {
+ DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
+ name));
+ ret = EINVAL;
+ goto fail;
+ }
+
+ ret = sysdb_attrs_get_uint32_t(attrs,
+ opts->user_map[SDAP_AT_USER_GID].sys_name,
+ &gid);
+ if (ret != EOK) {
+ DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",
+ name, dom->name));
+ ret = EINVAL;
+ goto fail;
+ }
+
+ /* check that the gid is valid for this domain */
+ if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
+ DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
+ name));
+ ret = EINVAL;
+ goto fail;
+ }
+
+ ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
+ if (ret) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("Original DN is not available for [%s].\n", name));
+ } else {
+ DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n",
+ el->values[0].data, name));
+ ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_DN,
+ (const char *) el->values[0].data);
+ if (ret) {
+ goto fail;
+ }
+ }
+
+ ret = sysdb_attrs_get_el(attrs, SYSDB_MEMBEROF, &el);
+ if (ret) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("Original memberOf is not available for [%s].\n",
+ name));
+ } else {
+ DEBUG(7, ("Adding original memberOf attributes to [%s].\n",
+ name));
+ for (i = 0; i < el->num_values; i++) {
+ ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF,
+ (const char *) el->values[i].data);
+ if (ret) {
+ goto fail;
+ }
+ }
+ }
+
+ ret = sysdb_attrs_get_el(attrs,
+ opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name, &el);
+ if (ret) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
+ name));
+ } else {
+ ret = sysdb_attrs_add_string(user_attrs,
+ opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name,
+ (const char*)el->values[0].data);
+ if (ret) {
+ goto fail;
+ }
+ }
+
+ ret = sysdb_attrs_get_el(attrs,
+ opts->user_map[SDAP_AT_USER_USN].sys_name, &el);
+ if (ret) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("Original USN value is not available for [%s].\n",
+ name));
+ } else {
+ ret = sysdb_attrs_add_string(user_attrs,
+ opts->user_map[SDAP_AT_USER_USN].sys_name,
+ (const char*)el->values[0].data);
+ if (ret) {
+ goto fail;
+ }
+ usn_value = talloc_strdup(memctx, (const char*)el->values[0].data);
+ if (!usn_value) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ }
+
+ ret = sysdb_attrs_get_el(attrs,
+ opts->user_map[SDAP_AT_USER_PRINC].sys_name, &el);
+ if (ret) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("User principal is not available for [%s].\n", name));
+ } else {
+ upn = talloc_strdup(user_attrs, (const char*) el->values[0].data);
+ if (!upn) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) {
+ make_realm_upper_case(upn);
+ }
+ DEBUG(7, ("Adding user principal [%s] to attributes of [%s].\n",
+ upn, name));
+ ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn);
+ if (ret) {
+ goto fail;
+ }
+ }
+
+ for (i = SDAP_FIRST_EXTRA_USER_AT; i < SDAP_OPTS_USER; i++) {
+ ret = sysdb_attrs_get_el(attrs, opts->user_map[i].sys_name, &el);
+ if (ret) {
+ goto fail;
+ }
+ if (el->num_values > 0) {
+ for (c = 0; c < el->num_values; c++) {
+ DEBUG(9, ("Adding [%s]=[%s] to user attributes.\n",
+ opts->user_map[i].sys_name,
+ (const char*) el->values[c].data));
+ val = talloc_strdup(user_attrs, (const char*) el->values[c].data);
+ if (val == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ ret = sysdb_attrs_add_string(user_attrs,
+ opts->user_map[i].sys_name, val);
+ if (ret) {
+ goto fail;
+ }
+ }
+ }
+ }
+
+ cache_timeout = dp_opt_get_int(opts->basic, SDAP_ENTRY_CACHE_TIMEOUT);
+
+ if (is_initgr) {
+ ret = sysdb_attrs_add_time_t(user_attrs, SYSDB_INITGR_EXPIRE,
+ (cache_timeout ?
+ (time(NULL) + cache_timeout) : 0));
+ if (ret) {
+ goto fail;
+ }
+ }
+
+ /* Make sure that any attributes we requested from LDAP that we
+ * did not receive are also removed from the sysdb
+ */
+ ret = list_missing_attrs(user_attrs, opts->user_map, SDAP_OPTS_USER,
+ ldap_attrs, attrs, &missing);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ /* Remove missing attributes */
+ if (missing && !missing[0]) {
+ /* Nothing to remove */
+ talloc_zfree(missing);
+ }
+
+ DEBUG(6, ("Storing info for user %s\n", name));
+
+ ret = sysdb_store_user(ctx, name, pwd, uid, gid, gecos, homedir, shell,
+ user_attrs, missing, cache_timeout);
+ if (ret) goto fail;
+
+ if (_usn_value) {
+ *_usn_value = usn_value;
+ }
+
+ talloc_steal(memctx, user_attrs);
+ talloc_free(tmpctx);
+ return EOK;
+
+fail:
+ DEBUG(2, ("Failed to save user [%s]\n",
+ name ? name : "Unknown"));
+ talloc_free(tmpctx);
+ return ret;
+}
+
+
+/* ==Generic-Function-to-save-multiple-users============================= */
+
+int sdap_save_users(TALLOC_CTX *memctx,
+ struct sysdb_ctx *sysdb,
+ const char **attrs,
+ struct sss_domain_info *dom,
+ struct sdap_options *opts,
+ struct sysdb_attrs **users,
+ int num_users,
+ char **_usn_value)
+{
+ TALLOC_CTX *tmpctx;
+ char *higher_usn = NULL;
+ char *usn_value;
+ int ret;
+ int i;
+
+ if (num_users == 0) {
+ /* Nothing to do if there are no users */
+ return EOK;
+ }
+
+ tmpctx = talloc_new(memctx);
+ if (!tmpctx) {
+ return ENOMEM;
+ }
+
+ ret = sysdb_transaction_start(sysdb);
+ if (ret) {
+ goto done;
+ }
+
+ for (i = 0; i < num_users; i++) {
+ usn_value = NULL;
+
+ ret = sdap_save_user(tmpctx, sysdb, opts, dom,
+ users[i], attrs, false,
+ &usn_value);
+
+ /* Do not fail completely on errors.
+ * Just report the failure to save and go on */
+ if (ret) {
+ DEBUG(2, ("Failed to store user %d. Ignoring.\n", i));
+ } else {
+ DEBUG(9, ("User %d processed!\n", i));
+ }
+
+ if (usn_value) {
+ if (higher_usn) {
+ if ((strlen(usn_value) > strlen(higher_usn)) ||
+ (strcmp(usn_value, higher_usn) > 0)) {
+ talloc_zfree(higher_usn);
+ higher_usn = usn_value;
+ } else {
+ talloc_zfree(usn_value);
+ }
+ } else {
+ higher_usn = usn_value;
+ }
+ }
+ }
+
+ ret = sysdb_transaction_commit(sysdb);
+ if (ret) {
+ DEBUG(1, ("Failed to commit transaction!\n"));
+ goto done;
+ }
+
+ if (_usn_value) {
+ *_usn_value = talloc_steal(memctx, higher_usn);
+ }
+
+done:
+ talloc_zfree(tmpctx);
+ return ret;
+}
+
+
+/* ==Search-Users-with-filter============================================= */
+
+struct sdap_get_users_state {
+ struct tevent_context *ev;
+ struct sdap_options *opts;
+ struct sdap_handle *sh;
+ struct sss_domain_info *dom;
+ struct sysdb_ctx *sysdb;
+ const char **attrs;
+ const char *filter;
+
+ char *higher_usn;
+ struct sysdb_attrs **users;
+ size_t count;
+};
+
+static void sdap_get_users_process(struct tevent_req *subreq);
+
+struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sss_domain_info *dom,
+ struct sysdb_ctx *sysdb,
+ struct sdap_options *opts,
+ struct sdap_handle *sh,
+ const char **attrs,
+ const char *filter,
+ int timeout)
+{
+ struct tevent_req *req, *subreq;
+ struct sdap_get_users_state *state;
+
+ req = tevent_req_create(memctx, &state, struct sdap_get_users_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = opts;
+ state->dom = dom;
+ state->sh = sh;
+ state->sysdb = sysdb;
+ state->filter = filter;
+ state->attrs = attrs;
+ state->higher_usn = NULL;
+ state->users = NULL;
+ state->count = 0;
+
+ subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
+ dp_opt_get_string(state->opts->basic,
+ SDAP_USER_SEARCH_BASE),
+ LDAP_SCOPE_SUBTREE,
+ state->filter, state->attrs,
+ state->opts->user_map, SDAP_OPTS_USER,
+ timeout);
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, sdap_get_users_process, req);
+
+ return req;
+}
+
+static void sdap_get_users_process(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_get_users_state *state = tevent_req_data(req,
+ struct sdap_get_users_state);
+ int ret;
+
+ ret = sdap_get_generic_recv(subreq, state,
+ &state->count, &state->users);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(6, ("Search for users, returned %d results.\n", state->count));
+
+ if (state->count == 0) {
+ tevent_req_error(req, ENOENT);
+ return;
+ }
+
+ ret = sdap_save_users(state, state->sysdb,
+ state->attrs,
+ state->dom, state->opts,
+ state->users, state->count,
+ &state->higher_usn);
+ if (ret) {
+ DEBUG(2, ("Failed to store users.\n"));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(9, ("Saving %d Users - Done\n", state->count));
+
+ tevent_req_done(req);
+}
+
+int sdap_get_users_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx, char **usn_value)
+{
+ struct sdap_get_users_state *state = tevent_req_data(req,
+ struct sdap_get_users_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (usn_value) {
+ *usn_value = talloc_steal(mem_ctx, state->higher_usn);
+ }
+
+ return EOK;
+}