sdap_async_accounts.c revision 86d77907310fa939fe89884fbbdf2142c06a420e
2d2eda71267231c2526be701fe655db125852c1ffielding/*
f062ed7bd262a37a909dd77ce5fc23b446818823fielding SSSD
f062ed7bd262a37a909dd77ce5fc23b446818823fielding
f062ed7bd262a37a909dd77ce5fc23b446818823fielding Async LDAP Helper routines
f062ed7bd262a37a909dd77ce5fc23b446818823fielding
2d2eda71267231c2526be701fe655db125852c1ffielding Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
2d2eda71267231c2526be701fe655db125852c1ffielding Copyright (C) 2010, Ralf Haferkamp <rhafer@suse.de>, Novell Inc.
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding This program is free software; you can redistribute it and/or modify
2d2eda71267231c2526be701fe655db125852c1ffielding it under the terms of the GNU General Public License as published by
2d2eda71267231c2526be701fe655db125852c1ffielding the Free Software Foundation; either version 3 of the License, or
f062ed7bd262a37a909dd77ce5fc23b446818823fielding (at your option) any later version.
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding This program is distributed in the hope that it will be useful,
2d2eda71267231c2526be701fe655db125852c1ffielding but WITHOUT ANY WARRANTY; without even the implied warranty of
2d2eda71267231c2526be701fe655db125852c1ffielding MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2d2eda71267231c2526be701fe655db125852c1ffielding GNU General Public License for more details.
2d2eda71267231c2526be701fe655db125852c1ffielding
f062ed7bd262a37a909dd77ce5fc23b446818823fielding You should have received a copy of the GNU General Public License
f062ed7bd262a37a909dd77ce5fc23b446818823fielding along with this program. If not, see <http://www.gnu.org/licenses/>.
f062ed7bd262a37a909dd77ce5fc23b446818823fielding*/
f062ed7bd262a37a909dd77ce5fc23b446818823fielding
f062ed7bd262a37a909dd77ce5fc23b446818823fielding#include "util/util.h"
f062ed7bd262a37a909dd77ce5fc23b446818823fielding#include "db/sysdb.h"
2d2eda71267231c2526be701fe655db125852c1ffielding#include "providers/ldap/sdap_async_private.h"
f062ed7bd262a37a909dd77ce5fc23b446818823fielding#include "providers/ldap/ldap_common.h"
f062ed7bd262a37a909dd77ce5fc23b446818823fielding
f062ed7bd262a37a909dd77ce5fc23b446818823fielding/* ==Save-User-Entry====================================================== */
f062ed7bd262a37a909dd77ce5fc23b446818823fielding
2d2eda71267231c2526be701fe655db125852c1ffielding/* FIXME: support storing additional attributes */
f062ed7bd262a37a909dd77ce5fc23b446818823fielding
f062ed7bd262a37a909dd77ce5fc23b446818823fieldingstatic int sdap_save_user(TALLOC_CTX *memctx,
64185f9824e42f21ca7b9ae6c004484215c031a7rbb struct sysdb_ctx *ctx,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sdap_options *opts,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding struct sss_domain_info *dom,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding struct sysdb_attrs *attrs,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding const char **ldap_attrs,
f062ed7bd262a37a909dd77ce5fc23b446818823fielding bool is_initgr,
2d2eda71267231c2526be701fe655db125852c1ffielding char **_usn_value)
f062ed7bd262a37a909dd77ce5fc23b446818823fielding{
f062ed7bd262a37a909dd77ce5fc23b446818823fielding struct ldb_message_element *el;
f062ed7bd262a37a909dd77ce5fc23b446818823fielding int ret;
f062ed7bd262a37a909dd77ce5fc23b446818823fielding const char *name = NULL;
f062ed7bd262a37a909dd77ce5fc23b446818823fielding const char *pwd;
f062ed7bd262a37a909dd77ce5fc23b446818823fielding const char *gecos;
f062ed7bd262a37a909dd77ce5fc23b446818823fielding const char *homedir;
2d2eda71267231c2526be701fe655db125852c1ffielding const char *shell;
2d2eda71267231c2526be701fe655db125852c1ffielding uid_t uid;
2d2eda71267231c2526be701fe655db125852c1ffielding gid_t gid;
f062ed7bd262a37a909dd77ce5fc23b446818823fielding struct sysdb_attrs *user_attrs;
f062ed7bd262a37a909dd77ce5fc23b446818823fielding char *upn = NULL;
f062ed7bd262a37a909dd77ce5fc23b446818823fielding size_t i;
2d2eda71267231c2526be701fe655db125852c1ffielding char *val = NULL;
f062ed7bd262a37a909dd77ce5fc23b446818823fielding int cache_timeout;
f062ed7bd262a37a909dd77ce5fc23b446818823fielding char *usn_value = NULL;
f062ed7bd262a37a909dd77ce5fc23b446818823fielding size_t c;
2d2eda71267231c2526be701fe655db125852c1ffielding char **missing = NULL;
2d2eda71267231c2526be701fe655db125852c1ffielding TALLOC_CTX *tmpctx = NULL;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(9, ("Save user\n"));
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding tmpctx = talloc_new(memctx);
2d2eda71267231c2526be701fe655db125852c1ffielding if (!tmpctx) {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = ENOMEM;
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding user_attrs = sysdb_new_attrs(tmpctx);
2d2eda71267231c2526be701fe655db125852c1ffielding if (user_attrs == NULL) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb ret = ENOMEM;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb goto fail;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_attrs_primary_name(ctx, attrs,
952908500d5f99f35afc5ed510391b9bdc3833farbb opts->user_map[SDAP_AT_USER_NAME].name,
952908500d5f99f35afc5ed510391b9bdc3833farbb &name);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (ret != EOK) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(1, ("Failed to save the user - entry has no name attribute\n"));
30c289e6bc6d28d210b21edd800ab2cfc78a8381wrowe goto fail;
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein }
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein
bd53cb2bf4d77574fd502e1c02d8c3c0d5431967stoddard ret = sysdb_attrs_get_el(attrs,
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein opts->user_map[SDAP_AT_USER_PWD].sys_name, &el);
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein if (ret) goto fail;
cccd31fa4a72fe23cc3249c06db181b274a55a69gstein if (el->num_values == 0) pwd = NULL;
44c46ef733836b32585d135d2d90856e7cfd9929rbb else pwd = (const char *)el->values[0].data;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb ret = sysdb_attrs_get_el(attrs,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb opts->user_map[SDAP_AT_USER_GECOS].sys_name, &el);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding if (el->num_values == 0) gecos = NULL;
2d2eda71267231c2526be701fe655db125852c1ffielding else gecos = (const char *)el->values[0].data;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (!gecos) {
2d2eda71267231c2526be701fe655db125852c1ffielding /* Fall back to the user's full name */
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_el(
2d2eda71267231c2526be701fe655db125852c1ffielding attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->user_map[SDAP_AT_USER_FULLNAME].sys_name, &el);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding if (el->num_values > 0) gecos = (const char *)el->values[0].data;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2e123e8beedc9f921448c113e2d6823a92fd5261fielding ret = sysdb_attrs_get_el(attrs,
2e123e8beedc9f921448c113e2d6823a92fd5261fielding opts->user_map[SDAP_AT_USER_HOME].sys_name, &el);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding if (el->num_values == 0) homedir = NULL;
2d2eda71267231c2526be701fe655db125852c1ffielding else homedir = (const char *)el->values[0].data;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_el(attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->user_map[SDAP_AT_USER_SHELL].sys_name, &el);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (ret) goto fail;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (el->num_values == 0) shell = NULL;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb else shell = (const char *)el->values[0].data;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
72a4ef8eac1adef882246c5bfb9b8bbd82d613c4coar ret = sysdb_attrs_get_uint32_t(attrs,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb opts->user_map[SDAP_AT_USER_UID].sys_name,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb &uid);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (ret != EOK) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(1, ("no uid provided for [%s] in domain [%s].\n",
2d2eda71267231c2526be701fe655db125852c1ffielding name, dom->name));
2d2eda71267231c2526be701fe655db125852c1ffielding ret = EINVAL;
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* check that the uid is valid for this domain */
2d2eda71267231c2526be701fe655db125852c1ffielding if (OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
2d2eda71267231c2526be701fe655db125852c1ffielding name));
2d2eda71267231c2526be701fe655db125852c1ffielding ret = EINVAL;
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
57edbe3cb9356a0b599c7b07f3aae0e721ee57e2coar }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_uint32_t(attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->user_map[SDAP_AT_USER_GID].sys_name,
2d2eda71267231c2526be701fe655db125852c1ffielding &gid);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret != EOK) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",
2d2eda71267231c2526be701fe655db125852c1ffielding name, dom->name));
2d2eda71267231c2526be701fe655db125852c1ffielding ret = EINVAL;
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /* check that the gid is valid for this domain */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
2d2eda71267231c2526be701fe655db125852c1ffielding name));
2d2eda71267231c2526be701fe655db125852c1ffielding ret = EINVAL;
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding if (el->num_values == 0) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(7, ("Original DN is not available for [%s].\n", name));
2d2eda71267231c2526be701fe655db125852c1ffielding } else {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n",
2d2eda71267231c2526be701fe655db125852c1ffielding el->values[0].data, name));
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_DN,
2d2eda71267231c2526be701fe655db125852c1ffielding (const char *) el->values[0].data);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_el(attrs, SYSDB_MEMBEROF, &el);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding if (el->num_values == 0) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(7, ("Original memberOf is not available for [%s].\n",
2d2eda71267231c2526be701fe655db125852c1ffielding name));
2d2eda71267231c2526be701fe655db125852c1ffielding } else {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(7, ("Adding original memberOf attributes to [%s].\n",
2d2eda71267231c2526be701fe655db125852c1ffielding name));
2d2eda71267231c2526be701fe655db125852c1ffielding for (i = 0; i < el->num_values; i++) {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF,
2d2eda71267231c2526be701fe655db125852c1ffielding (const char *) el->values[i].data);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_el(attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name, &el);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding if (el->num_values == 0) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
2d2eda71267231c2526be701fe655db125852c1ffielding name));
2d2eda71267231c2526be701fe655db125852c1ffielding } else {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_add_string(user_attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name,
2d2eda71267231c2526be701fe655db125852c1ffielding (const char*)el->values[0].data);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
e44e11f9fece12c783f18d033923bfc0d6b4289aake ret = sysdb_attrs_get_el(attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->user_map[SDAP_AT_USER_USN].sys_name, &el);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
e44e11f9fece12c783f18d033923bfc0d6b4289aake if (el->num_values == 0) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(7, ("Original USN value is not available for [%s].\n",
2d2eda71267231c2526be701fe655db125852c1ffielding name));
2d2eda71267231c2526be701fe655db125852c1ffielding } else {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_add_string(user_attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->user_map[SDAP_AT_USER_USN].sys_name,
2d2eda71267231c2526be701fe655db125852c1ffielding (const char*)el->values[0].data);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding usn_value = talloc_strdup(memctx, (const char*)el->values[0].data);
2d2eda71267231c2526be701fe655db125852c1ffielding if (!usn_value) {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = ENOMEM;
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_el(attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->user_map[SDAP_AT_USER_PRINC].sys_name, &el);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding if (el->num_values == 0) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(7, ("User principal is not available for [%s].\n", name));
2d2eda71267231c2526be701fe655db125852c1ffielding } else {
2d2eda71267231c2526be701fe655db125852c1ffielding upn = talloc_strdup(user_attrs, (const char*) el->values[0].data);
2d2eda71267231c2526be701fe655db125852c1ffielding if (!upn) {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = ENOMEM;
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) {
2d2eda71267231c2526be701fe655db125852c1ffielding make_realm_upper_case(upn);
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(7, ("Adding user principal [%s] to attributes of [%s].\n",
2d2eda71267231c2526be701fe655db125852c1ffielding upn, name));
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding for (i = SDAP_FIRST_EXTRA_USER_AT; i < SDAP_OPTS_USER; i++) {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_el(attrs, opts->user_map[i].sys_name, &el);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding if (el->num_values > 0) {
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet for (c = 0; c < el->num_values; c++) {
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet DEBUG(9, ("Adding [%s]=[%s] to user attributes.\n",
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet opts->user_map[i].sys_name,
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet (const char*) el->values[c].data));
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet val = talloc_strdup(user_attrs, (const char*) el->values[c].data);
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet if (val == NULL) {
2efb935ae8fe12d5192a3bf2c52c28461b6c68afdgaudet ret = ENOMEM;
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_add_string(user_attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->user_map[i].sys_name, val);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding cache_timeout = dp_opt_get_int(opts->basic, SDAP_ENTRY_CACHE_TIMEOUT);
2d2eda71267231c2526be701fe655db125852c1ffielding
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (is_initgr) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb ret = sysdb_attrs_add_time_t(user_attrs, SYSDB_INITGR_EXPIRE,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb (cache_timeout ?
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb (time(NULL) + cache_timeout) : 0));
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (ret) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb goto fail;
32644678e889a3253f71bde0b3d6daea6d9dc21awrowe }
32644678e889a3253f71bde0b3d6daea6d9dc21awrowe }
3c4046a56f25e3c4f263ad5545575887c1c5a905rbb
32644678e889a3253f71bde0b3d6daea6d9dc21awrowe /* Make sure that any attributes we requested from LDAP that we
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * did not receive are also removed from the sysdb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb ret = list_missing_attrs(user_attrs, opts->user_map, SDAP_OPTS_USER,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb ldap_attrs, attrs, &missing);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (ret != EOK) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb goto fail;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* Remove missing attributes */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (missing && !missing[0]) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* Nothing to remove */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb talloc_zfree(missing);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb DEBUG(6, ("Storing info for user %s\n", name));
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb ret = sysdb_store_user(user_attrs, ctx, dom,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb name, pwd, uid, gid, gecos, homedir, shell,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb user_attrs, missing, cache_timeout);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (ret) goto fail;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (_usn_value) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb *_usn_value = usn_value;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb talloc_steal(memctx, user_attrs);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb talloc_free(tmpctx);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb return EOK;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbbfail:
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb DEBUG(2, ("Failed to save user [%s]\n",
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb name ? name : "Unknown"));
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb talloc_free(tmpctx);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb return ret;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb}
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb/* ==Generic-Function-to-save-multiple-users============================= */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbbstatic int sdap_save_users(TALLOC_CTX *memctx,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb struct sysdb_ctx *sysdb,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb const char **attrs,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb struct sss_domain_info *dom,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb struct sdap_options *opts,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb struct sysdb_attrs **users,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb int num_users,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb char **_usn_value)
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb{
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb TALLOC_CTX *tmpctx;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb char *higher_usn = NULL;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb char *usn_value;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb int ret;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb int i;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (num_users == 0) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* Nothing to do if there are no users */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb return EOK;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb tmpctx = talloc_new(memctx);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (!tmpctx) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb return ENOMEM;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb ret = sysdb_transaction_start(sysdb);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (ret) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb goto done;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb for (i = 0; i < num_users; i++) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb usn_value = NULL;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb ret = sdap_save_user(tmpctx, sysdb, opts, dom,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb users[i], attrs, false,
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb &usn_value);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb /* Do not fail completely on errors.
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb * Just report the failure to save and go on */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (ret) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb DEBUG(2, ("Failed to store user %d. Ignoring.\n", i));
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb } else {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb DEBUG(9, ("User %d processed!\n", i));
2e123e8beedc9f921448c113e2d6823a92fd5261fielding }
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb if (usn_value) {
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb if (higher_usn) {
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb if ((strlen(usn_value) > strlen(higher_usn)) ||
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb (strcmp(usn_value, higher_usn) > 0)) {
3d96ee83babeec32482c9082c9426340cee8c44dwrowe talloc_zfree(higher_usn);
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb higher_usn = usn_value;
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb } else {
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb talloc_zfree(usn_value);
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb }
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb } else {
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb higher_usn = usn_value;
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb }
3d96ee83babeec32482c9082c9426340cee8c44dwrowe }
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb }
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb ret = sysdb_transaction_commit(sysdb);
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb if (ret) {
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb DEBUG(1, ("Failed to commit transaction!\n"));
3d96ee83babeec32482c9082c9426340cee8c44dwrowe goto done;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding if (_usn_value) {
2d2eda71267231c2526be701fe655db125852c1ffielding *_usn_value = talloc_steal(memctx, higher_usn);
2d2eda71267231c2526be701fe655db125852c1ffielding }
654ecb3a7697ce4e7c2a354597ff78b8a48576a8rbb
2d2eda71267231c2526be701fe655db125852c1ffieldingdone:
2d2eda71267231c2526be701fe655db125852c1ffielding talloc_zfree(tmpctx);
2d2eda71267231c2526be701fe655db125852c1ffielding return ret;
2d2eda71267231c2526be701fe655db125852c1ffielding}
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding
7463de0c603f07c9e1820e812d2f1a73661843e6rbb/* ==Search-Users-with-filter============================================= */
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffieldingstruct sdap_get_users_state {
2d2eda71267231c2526be701fe655db125852c1ffielding struct tevent_context *ev;
2d2eda71267231c2526be701fe655db125852c1ffielding struct sdap_options *opts;
2d2eda71267231c2526be701fe655db125852c1ffielding struct sdap_handle *sh;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm struct sss_domain_info *dom;
2d2eda71267231c2526be701fe655db125852c1ffielding struct sysdb_ctx *sysdb;
2d2eda71267231c2526be701fe655db125852c1ffielding const char **attrs;
2d2eda71267231c2526be701fe655db125852c1ffielding const char *filter;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding char *higher_usn;
2d2eda71267231c2526be701fe655db125852c1ffielding struct sysdb_attrs **users;
2d2eda71267231c2526be701fe655db125852c1ffielding size_t count;
2d2eda71267231c2526be701fe655db125852c1ffielding};
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic void sdap_get_users_process(struct tevent_req *subreq);
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffieldingstruct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
2d2eda71267231c2526be701fe655db125852c1ffielding struct tevent_context *ev,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sss_domain_info *dom,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sysdb_ctx *sysdb,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sdap_options *opts,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sdap_handle *sh,
2d2eda71267231c2526be701fe655db125852c1ffielding const char **attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding const char *filter,
2d2eda71267231c2526be701fe655db125852c1ffielding int timeout)
2d2eda71267231c2526be701fe655db125852c1ffielding{
2d2eda71267231c2526be701fe655db125852c1ffielding struct tevent_req *req, *subreq;
2d2eda71267231c2526be701fe655db125852c1ffielding struct sdap_get_users_state *state;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding req = tevent_req_create(memctx, &state, struct sdap_get_users_state);
2d2eda71267231c2526be701fe655db125852c1ffielding if (!req) return NULL;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding state->ev = ev;
2d2eda71267231c2526be701fe655db125852c1ffielding state->opts = opts;
2d2eda71267231c2526be701fe655db125852c1ffielding state->dom = dom;
2d2eda71267231c2526be701fe655db125852c1ffielding state->sh = sh;
2d2eda71267231c2526be701fe655db125852c1ffielding state->sysdb = sysdb;
2d2eda71267231c2526be701fe655db125852c1ffielding state->filter = filter;
2d2eda71267231c2526be701fe655db125852c1ffielding state->attrs = attrs;
2d2eda71267231c2526be701fe655db125852c1ffielding state->higher_usn = NULL;
2d2eda71267231c2526be701fe655db125852c1ffielding state->users = NULL;
2d2eda71267231c2526be701fe655db125852c1ffielding state->count = 0;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
2d2eda71267231c2526be701fe655db125852c1ffielding dp_opt_get_string(state->opts->basic,
2d2eda71267231c2526be701fe655db125852c1ffielding SDAP_USER_SEARCH_BASE),
2d2eda71267231c2526be701fe655db125852c1ffielding LDAP_SCOPE_SUBTREE,
2d2eda71267231c2526be701fe655db125852c1ffielding state->filter, state->attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding state->opts->user_map, SDAP_OPTS_USER,
2d2eda71267231c2526be701fe655db125852c1ffielding timeout);
2d2eda71267231c2526be701fe655db125852c1ffielding if (!subreq) {
2d2eda71267231c2526be701fe655db125852c1ffielding talloc_zfree(req);
2d2eda71267231c2526be701fe655db125852c1ffielding return NULL;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding tevent_req_set_callback(subreq, sdap_get_users_process, req);
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding return req;
2d2eda71267231c2526be701fe655db125852c1ffielding}
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic void sdap_get_users_process(struct tevent_req *subreq)
2d2eda71267231c2526be701fe655db125852c1ffielding{
2d2eda71267231c2526be701fe655db125852c1ffielding struct tevent_req *req = tevent_req_callback_data(subreq,
2d2eda71267231c2526be701fe655db125852c1ffielding struct tevent_req);
2d2eda71267231c2526be701fe655db125852c1ffielding struct sdap_get_users_state *state = tevent_req_data(req,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sdap_get_users_state);
2d2eda71267231c2526be701fe655db125852c1ffielding int ret;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sdap_get_generic_recv(subreq, state,
2d2eda71267231c2526be701fe655db125852c1ffielding &state->count, &state->users);
2d2eda71267231c2526be701fe655db125852c1ffielding talloc_zfree(subreq);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding tevent_req_error(req, ret);
2d2eda71267231c2526be701fe655db125852c1ffielding return;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(6, ("Search for users, returned %d results.\n", state->count));
2d2eda71267231c2526be701fe655db125852c1ffielding
763f7b125b6d3dd1e4992a3822005efa2616f983coar if (state->count == 0) {
763f7b125b6d3dd1e4992a3822005efa2616f983coar tevent_req_error(req, ENOENT);
2d2eda71267231c2526be701fe655db125852c1ffielding return;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sdap_save_users(state, state->sysdb,
2d2eda71267231c2526be701fe655db125852c1ffielding state->attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding state->dom, state->opts,
2d2eda71267231c2526be701fe655db125852c1ffielding state->users, state->count,
2d2eda71267231c2526be701fe655db125852c1ffielding &state->higher_usn);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(2, ("Failed to store users.\n"));
2d2eda71267231c2526be701fe655db125852c1ffielding tevent_req_error(req, ret);
2d2eda71267231c2526be701fe655db125852c1ffielding return;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(9, ("Saving %d Users - Done\n", state->count));
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding tevent_req_done(req);
2d2eda71267231c2526be701fe655db125852c1ffielding}
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffieldingint sdap_get_users_recv(struct tevent_req *req,
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb TALLOC_CTX *mem_ctx, char **usn_value)
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb{
91f0d8da77152d24e4bbb31ce199282b3fd6e3b2coar struct sdap_get_users_state *state = tevent_req_data(req,
91f0d8da77152d24e4bbb31ce199282b3fd6e3b2coar struct sdap_get_users_state);
91f0d8da77152d24e4bbb31ce199282b3fd6e3b2coar
91f0d8da77152d24e4bbb31ce199282b3fd6e3b2coar TEVENT_REQ_RETURN_ON_ERROR(req);
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb if (usn_value) {
91f0d8da77152d24e4bbb31ce199282b3fd6e3b2coar *usn_value = talloc_steal(mem_ctx, state->higher_usn);
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb }
91f0d8da77152d24e4bbb31ce199282b3fd6e3b2coar
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb return EOK;
91f0d8da77152d24e4bbb31ce199282b3fd6e3b2coar}
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding/* ==Group-Parsing Routines=============================================== */
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int sdap_find_entry_by_origDN(TALLOC_CTX *memctx,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sysdb_ctx *ctx,
54e94821097724bf413d2d4cc70711760f7494e1trawick struct sss_domain_info *domain,
54e94821097724bf413d2d4cc70711760f7494e1trawick const char *orig_dn,
2d2eda71267231c2526be701fe655db125852c1ffielding char **localdn)
2d2eda71267231c2526be701fe655db125852c1ffielding{
54e94821097724bf413d2d4cc70711760f7494e1trawick TALLOC_CTX *tmpctx;
54e94821097724bf413d2d4cc70711760f7494e1trawick const char *no_attrs[] = { NULL };
54e94821097724bf413d2d4cc70711760f7494e1trawick struct ldb_dn *base_dn;
54e94821097724bf413d2d4cc70711760f7494e1trawick char *filter;
54e94821097724bf413d2d4cc70711760f7494e1trawick struct ldb_message **msgs;
54e94821097724bf413d2d4cc70711760f7494e1trawick size_t num_msgs;
54e94821097724bf413d2d4cc70711760f7494e1trawick int ret;
54e94821097724bf413d2d4cc70711760f7494e1trawick char *sanitized_dn;
54e94821097724bf413d2d4cc70711760f7494e1trawick
54e94821097724bf413d2d4cc70711760f7494e1trawick tmpctx = talloc_new(NULL);
54e94821097724bf413d2d4cc70711760f7494e1trawick if (!tmpctx) {
54e94821097724bf413d2d4cc70711760f7494e1trawick return ENOMEM;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sss_filter_sanitize(tmpctx, orig_dn, &sanitized_dn);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret != EOK) {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = ENOMEM;
2d2eda71267231c2526be701fe655db125852c1ffielding goto done;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding filter = talloc_asprintf(tmpctx, "%s=%s", SYSDB_ORIG_DN, sanitized_dn);
2d2eda71267231c2526be701fe655db125852c1ffielding if (!filter) {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = ENOMEM;
2d2eda71267231c2526be701fe655db125852c1ffielding goto done;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding base_dn = sysdb_domain_dn(ctx, tmpctx, domain->name);
2d2eda71267231c2526be701fe655db125852c1ffielding if (!base_dn) {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = ENOMEM;
2d2eda71267231c2526be701fe655db125852c1ffielding goto done;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(9, ("Searching cache for [%s].\n", sanitized_dn));
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_search_entry(tmpctx, ctx,
2d2eda71267231c2526be701fe655db125852c1ffielding base_dn, LDB_SCOPE_SUBTREE, filter, no_attrs,
952908500d5f99f35afc5ed510391b9bdc3833farbb &num_msgs, &msgs);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto done;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding if (num_msgs != 1) {
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = ENOENT;
952908500d5f99f35afc5ed510391b9bdc3833farbb goto done;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb *localdn = talloc_strdup(memctx, ldb_dn_get_linearized(msgs[0]->dn));
952908500d5f99f35afc5ed510391b9bdc3833farbb if (!*localdn) {
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = ENOENT;
2d2eda71267231c2526be701fe655db125852c1ffielding goto done;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
3887202241db08986e94b252fbd06a55e55d4b2dbhyde ret = EOK;
3887202241db08986e94b252fbd06a55e55d4b2dbhyde
3887202241db08986e94b252fbd06a55e55d4b2dbhydedone:
3887202241db08986e94b252fbd06a55e55d4b2dbhyde talloc_zfree(tmpctx);
3887202241db08986e94b252fbd06a55e55d4b2dbhyde return ret;
3887202241db08986e94b252fbd06a55e55d4b2dbhyde}
3887202241db08986e94b252fbd06a55e55d4b2dbhyde
3887202241db08986e94b252fbd06a55e55d4b2dbhydestatic int sdap_fill_memberships(struct sysdb_attrs *group_attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sysdb_ctx *ctx,
3887202241db08986e94b252fbd06a55e55d4b2dbhyde struct sdap_options *opts,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sss_domain_info *domain,
2d2eda71267231c2526be701fe655db125852c1ffielding struct ldb_val *values,
2d2eda71267231c2526be701fe655db125852c1ffielding int num_values)
2d2eda71267231c2526be701fe655db125852c1ffielding{
952908500d5f99f35afc5ed510391b9bdc3833farbb struct ldb_message_element *el;
3887202241db08986e94b252fbd06a55e55d4b2dbhyde int i, j;
952908500d5f99f35afc5ed510391b9bdc3833farbb int ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb switch (opts->schema_type) {
952908500d5f99f35afc5ed510391b9bdc3833farbb case SDAP_SCHEMA_RFC2307:
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(9, ("[RFC2307 Schema]\n"));
3887202241db08986e94b252fbd06a55e55d4b2dbhyde
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_attrs_users_from_ldb_vals(group_attrs, SYSDB_MEMBER,
50cf9b8da68bea71ce5a49b4cb4be3be516486bdgstein domain->name,
952908500d5f99f35afc5ed510391b9bdc3833farbb values, num_values);
3887202241db08986e94b252fbd06a55e55d4b2dbhyde if (ret) {
3887202241db08986e94b252fbd06a55e55d4b2dbhyde goto done;
3887202241db08986e94b252fbd06a55e55d4b2dbhyde }
952908500d5f99f35afc5ed510391b9bdc3833farbb
2d2eda71267231c2526be701fe655db125852c1ffielding break;
952908500d5f99f35afc5ed510391b9bdc3833farbb
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm case SDAP_SCHEMA_RFC2307BIS:
952908500d5f99f35afc5ed510391b9bdc3833farbb case SDAP_SCHEMA_IPA_V1:
2d2eda71267231c2526be701fe655db125852c1ffielding case SDAP_SCHEMA_AD:
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(9, ("[IPA or AD Schema]\n"));
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_el(group_attrs, SYSDB_MEMBER, &el);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) {
952908500d5f99f35afc5ed510391b9bdc3833farbb goto done;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb /* Just allocate both big enough to contain all members for now */
952908500d5f99f35afc5ed510391b9bdc3833farbb el->values = talloc_realloc(el, el->values, struct ldb_val,
2d2eda71267231c2526be701fe655db125852c1ffielding el->num_values + num_values);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (!el->values) {
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = ENOMEM;
952908500d5f99f35afc5ed510391b9bdc3833farbb goto done;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding for (i = 0, j = el->num_values; i < num_values; i++) {
2d2eda71267231c2526be701fe655db125852c1ffielding
952908500d5f99f35afc5ed510391b9bdc3833farbb /* sync search entry with this as origDN */
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sdap_find_entry_by_origDN(el->values, ctx, domain,
952908500d5f99f35afc5ed510391b9bdc3833farbb (char *)values[i].data,
952908500d5f99f35afc5ed510391b9bdc3833farbb (char **)&el->values[j].data);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret != EOK) {
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret != ENOENT) {
952908500d5f99f35afc5ed510391b9bdc3833farbb goto done;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(7, (" member #%d (%s): not found!\n",
952908500d5f99f35afc5ed510391b9bdc3833farbb i, (char *)values[i].data));
952908500d5f99f35afc5ed510391b9bdc3833farbb } else {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(7, (" member #%d (%s): [%s]\n",
952908500d5f99f35afc5ed510391b9bdc3833farbb i, (char *)values[i].data,
952908500d5f99f35afc5ed510391b9bdc3833farbb (char *)el->values[j].data));
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb el->values[j].length = strlen((char *)el->values[j].data);
952908500d5f99f35afc5ed510391b9bdc3833farbb j++;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb el->num_values = j;
952908500d5f99f35afc5ed510391b9bdc3833farbb
2d2eda71267231c2526be701fe655db125852c1ffielding break;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding default:
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(0, ("FATAL ERROR: Unhandled schema type! (%d)\n",
2d2eda71267231c2526be701fe655db125852c1ffielding opts->schema_type));
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = EFAULT;
952908500d5f99f35afc5ed510391b9bdc3833farbb goto done;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = EOK;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbbdone:
952908500d5f99f35afc5ed510391b9bdc3833farbb return ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb}
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb/* ==Save-Group-Entry===================================================== */
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb /* FIXME: support non legacy */
952908500d5f99f35afc5ed510391b9bdc3833farbb /* FIXME: support storing additional attributes */
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic errno_t
952908500d5f99f35afc5ed510391b9bdc3833farbbsdap_store_group_with_gid(TALLOC_CTX *mem_ctx,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_ctx *ctx,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sss_domain_info *domain,
952908500d5f99f35afc5ed510391b9bdc3833farbb const char *name,
952908500d5f99f35afc5ed510391b9bdc3833farbb gid_t gid,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_attrs *group_attrs,
952908500d5f99f35afc5ed510391b9bdc3833farbb uint64_t cache_timeout,
952908500d5f99f35afc5ed510391b9bdc3833farbb bool posix_group)
952908500d5f99f35afc5ed510391b9bdc3833farbb{
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb errno_t ret;
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb /* make sure that non-posix (empty or explicit gid=0) groups have the
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb * gidNumber set to zero even if updating existing group */
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb if (!posix_group) {
a520b923984f45daeaf0741d5c7e3de1f2d24509rbb ret = sysdb_attrs_add_uint32(group_attrs, SYSDB_GIDNUM, 0);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(2, ("Could not set explicit GID 0 for %s\n", name));
952908500d5f99f35afc5ed510391b9bdc3833farbb return ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_store_group(mem_ctx, ctx, domain,
2d2eda71267231c2526be701fe655db125852c1ffielding name, gid, group_attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding cache_timeout);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(2, ("Could not store group %s\n", name));
952908500d5f99f35afc5ed510391b9bdc3833farbb return ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
4ce5967e9d2458203afca93ee350394891a5f6c4gstein
952908500d5f99f35afc5ed510391b9bdc3833farbb return ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb}
952908500d5f99f35afc5ed510391b9bdc3833farbb
7bdef86e15d47d16dcbe7a5611683191774bd5fbgsteinstatic int sdap_save_group(TALLOC_CTX *memctx,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_ctx *ctx,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sdap_options *opts,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sss_domain_info *dom,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_attrs *attrs,
952908500d5f99f35afc5ed510391b9bdc3833farbb bool store_members,
952908500d5f99f35afc5ed510391b9bdc3833farbb bool populate_members,
952908500d5f99f35afc5ed510391b9bdc3833farbb char **_usn_value)
952908500d5f99f35afc5ed510391b9bdc3833farbb{
952908500d5f99f35afc5ed510391b9bdc3833farbb struct ldb_message_element *el;
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_attrs *group_attrs;
952908500d5f99f35afc5ed510391b9bdc3833farbb const char *name = NULL;
2d2eda71267231c2526be701fe655db125852c1ffielding gid_t gid;
2d2eda71267231c2526be701fe655db125852c1ffielding int ret;
2d2eda71267231c2526be701fe655db125852c1ffielding char *usn_value = NULL;
2d2eda71267231c2526be701fe655db125852c1ffielding TALLOC_CTX *tmpctx = NULL;
2d2eda71267231c2526be701fe655db125852c1ffielding bool posix_group;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding tmpctx = talloc_new(memctx);
2d2eda71267231c2526be701fe655db125852c1ffielding if (!tmpctx) {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = ENOMEM;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding group_attrs = sysdb_new_attrs(tmpctx);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (group_attrs == NULL) {
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm ret = ENOMEM;
952908500d5f99f35afc5ed510391b9bdc3833farbb goto fail;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_attrs_primary_name(ctx, attrs,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm opts->group_map[SDAP_AT_GROUP_NAME].name,
952908500d5f99f35afc5ed510391b9bdc3833farbb &name);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm if (ret != EOK) {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(1, ("Failed to save the group - entry has no name attribute\n"));
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix_group);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret == ENOENT) {
2d2eda71267231c2526be701fe655db125852c1ffielding posix_group = true;
952908500d5f99f35afc5ed510391b9bdc3833farbb } else if (ret != EOK) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(8, ("This is%s a posix group\n", (posix_group)?"":" not"));
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, posix_group);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret != EOK) {
952908500d5f99f35afc5ed510391b9bdc3833farbb goto fail;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_attrs_get_uint32_t(attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->group_map[SDAP_AT_GROUP_GID].sys_name,
952908500d5f99f35afc5ed510391b9bdc3833farbb &gid);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret != EOK) {
2e123e8beedc9f921448c113e2d6823a92fd5261fielding DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",
952908500d5f99f35afc5ed510391b9bdc3833farbb name, dom->name));
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = EINVAL;
952908500d5f99f35afc5ed510391b9bdc3833farbb goto fail;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
2d2eda71267231c2526be701fe655db125852c1ffielding
952908500d5f99f35afc5ed510391b9bdc3833farbb /* check that the gid is valid for this domain */
2d2eda71267231c2526be701fe655db125852c1ffielding if (posix_group) {
952908500d5f99f35afc5ed510391b9bdc3833farbb if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
2d2eda71267231c2526be701fe655db125852c1ffielding name));
2d2eda71267231c2526be701fe655db125852c1ffielding ret = EINVAL;
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding /* Group ID OK */
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) {
952908500d5f99f35afc5ed510391b9bdc3833farbb goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
952908500d5f99f35afc5ed510391b9bdc3833farbb if (el->num_values == 0) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(7, ("Original DN is not available for [%s].\n", name));
952908500d5f99f35afc5ed510391b9bdc3833farbb } else {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n",
952908500d5f99f35afc5ed510391b9bdc3833farbb el->values[0].data, name));
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_attrs_add_string(group_attrs, SYSDB_ORIG_DN,
952908500d5f99f35afc5ed510391b9bdc3833farbb (const char *) el->values[0].data);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_el(attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name, &el);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) {
952908500d5f99f35afc5ed510391b9bdc3833farbb goto fail;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb if (el->num_values == 0) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
952908500d5f99f35afc5ed510391b9bdc3833farbb name));
2d2eda71267231c2526be701fe655db125852c1ffielding } else {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_add_string(group_attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name,
2d2eda71267231c2526be701fe655db125852c1ffielding (const char*)el->values[0].data);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
4b86db47932a21da10cd35317b3da737f2b073c4rbb
5fac642ef2ee110540c3a391e4cf1d166ba57d0ftrawick ret = sysdb_attrs_get_el(attrs,
4b86db47932a21da10cd35317b3da737f2b073c4rbb opts->group_map[SDAP_AT_GROUP_USN].sys_name, &el);
5fac642ef2ee110540c3a391e4cf1d166ba57d0ftrawick if (ret) {
6dc0127996050178a9f01014f5be68cdd7f506basascha goto fail;
5fac642ef2ee110540c3a391e4cf1d166ba57d0ftrawick }
4b86db47932a21da10cd35317b3da737f2b073c4rbb if (el->num_values == 0) {
4b86db47932a21da10cd35317b3da737f2b073c4rbb DEBUG(7, ("Original USN value is not available for [%s].\n",
da76b1004afd7a8785684c84e4d4b5c893c65572rbb name));
777a2b42697cb8cb94ac4e73774862f879259c45rbb } else {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_add_string(group_attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->group_map[SDAP_AT_GROUP_USN].sys_name,
2d2eda71267231c2526be701fe655db125852c1ffielding (const char*)el->values[0].data);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding usn_value = talloc_strdup(tmpctx, (const char*)el->values[0].data);
2d2eda71267231c2526be701fe655db125852c1ffielding if (!usn_value) {
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = ENOMEM;
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb if (populate_members) {
952908500d5f99f35afc5ed510391b9bdc3833farbb struct ldb_message_element *el1;
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_attrs_get_el(attrs, opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el1);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret != EOK) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_attrs_get_el(group_attrs, SYSDB_MEMBER, &el);
0ff36975b1f5fef1ccc0429bb76bcdaccd5d122brbb if (ret != EOK) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding el->values = el1->values;
952908500d5f99f35afc5ed510391b9bdc3833farbb el->num_values = el1->num_values;
91644a5f4d3e992dc208304b50e80bbb236fca89trawick } else if (store_members) {
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_attrs_get_el(attrs,
91644a5f4d3e992dc208304b50e80bbb236fca89trawick opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret != EOK) {
952908500d5f99f35afc5ed510391b9bdc3833farbb goto fail;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb if (el->num_values == 0) {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(7, ("No members for group [%s]\n", name));
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb } else {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(7, ("Adding member users to group [%s]\n", name));
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sdap_fill_memberships(group_attrs, ctx, opts, dom,
952908500d5f99f35afc5ed510391b9bdc3833farbb el->values, el->num_values);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) {
952908500d5f99f35afc5ed510391b9bdc3833farbb goto fail;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(6, ("Storing info for group %s\n", name));
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sdap_store_group_with_gid(group_attrs, ctx, dom,
952908500d5f99f35afc5ed510391b9bdc3833farbb name, gid, group_attrs,
952908500d5f99f35afc5ed510391b9bdc3833farbb dp_opt_get_int(opts->basic,
952908500d5f99f35afc5ed510391b9bdc3833farbb SDAP_ENTRY_CACHE_TIMEOUT),
952908500d5f99f35afc5ed510391b9bdc3833farbb posix_group);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) goto fail;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb if (_usn_value) {
952908500d5f99f35afc5ed510391b9bdc3833farbb *_usn_value = talloc_steal(memctx, usn_value);
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb talloc_steal(memctx, group_attrs);
952908500d5f99f35afc5ed510391b9bdc3833farbb talloc_free(tmpctx);
952908500d5f99f35afc5ed510391b9bdc3833farbb return EOK;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbbfail:
6dc0127996050178a9f01014f5be68cdd7f506basascha DEBUG(2, ("Failed to save group [%s]\n",
6dc0127996050178a9f01014f5be68cdd7f506basascha name ? name : "Unknown"));
1296b2d30150ccb4ae9f6d690846b4e8f8571fd2rbb talloc_free(tmpctx);
c43223fef00e5fa98a54c37a21175ff788b76f43rbb return ret;
c43223fef00e5fa98a54c37a21175ff788b76f43rbb}
c43223fef00e5fa98a54c37a21175ff788b76f43rbb
b791a95f25326cffa9265d1b7d4f6a2531fa0acarbb
b791a95f25326cffa9265d1b7d4f6a2531fa0acarbb/* ==Save-Group-Memebrs=================================================== */
b791a95f25326cffa9265d1b7d4f6a2531fa0acarbb
2d2eda71267231c2526be701fe655db125852c1ffielding /* FIXME: support non legacy */
2d2eda71267231c2526be701fe655db125852c1ffielding /* FIXME: support storing additional attributes */
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int sdap_save_grpmem(TALLOC_CTX *memctx,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sysdb_ctx *ctx,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sdap_options *opts,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sss_domain_info *dom,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sysdb_attrs *attrs)
2d2eda71267231c2526be701fe655db125852c1ffielding{
2d2eda71267231c2526be701fe655db125852c1ffielding struct ldb_message_element *el;
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_attrs *group_attrs = NULL;
952908500d5f99f35afc5ed510391b9bdc3833farbb const char *name;
2d2eda71267231c2526be701fe655db125852c1ffielding int ret;
169f62b04de69074b561b4e6dcf6f82572a5e367trawick
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_primary_name(ctx, attrs,
952908500d5f99f35afc5ed510391b9bdc3833farbb opts->group_map[SDAP_AT_GROUP_NAME].name,
35ecf536dec58844b65e1edfd1633d36ea091acbdreid &name);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret != EOK) {
dad234382d8424e1c5a30af2838e172aec9d6d1bdreid goto fail;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_el(attrs,
2d2eda71267231c2526be701fe655db125852c1ffielding opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret != EOK) {
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
3887202241db08986e94b252fbd06a55e55d4b2dbhyde if (el->num_values == 0) {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(7, ("No members for group [%s]\n", name));
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding } else {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(7, ("Adding member users to group [%s]\n", name));
2d2eda71267231c2526be701fe655db125852c1ffielding
952908500d5f99f35afc5ed510391b9bdc3833farbb group_attrs = sysdb_new_attrs(memctx);
2d2eda71267231c2526be701fe655db125852c1ffielding if (!group_attrs) {
2d2eda71267231c2526be701fe655db125852c1ffielding ret = ENOMEM;
2d2eda71267231c2526be701fe655db125852c1ffielding goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding }
952908500d5f99f35afc5ed510391b9bdc3833farbb
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sdap_fill_memberships(group_attrs, ctx, opts, dom,
952908500d5f99f35afc5ed510391b9bdc3833farbb el->values, el->num_values);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
952908500d5f99f35afc5ed510391b9bdc3833farbb goto fail;
dad234382d8424e1c5a30af2838e172aec9d6d1bdreid }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(6, ("Storing members for group %s\n", name));
952908500d5f99f35afc5ed510391b9bdc3833farbb
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_store_group(memctx, ctx, dom,
952908500d5f99f35afc5ed510391b9bdc3833farbb name, 0, group_attrs,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm dp_opt_get_int(opts->basic,
952908500d5f99f35afc5ed510391b9bdc3833farbb SDAP_ENTRY_CACHE_TIMEOUT));
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) goto fail;
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding return EOK;
2d2eda71267231c2526be701fe655db125852c1ffielding
952908500d5f99f35afc5ed510391b9bdc3833farbbfail:
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(2, ("Failed to save user %s\n", name));
952908500d5f99f35afc5ed510391b9bdc3833farbb return ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb}
169f62b04de69074b561b4e6dcf6f82572a5e367trawick
169f62b04de69074b561b4e6dcf6f82572a5e367trawick
169f62b04de69074b561b4e6dcf6f82572a5e367trawick/* ==Generic-Function-to-save-multiple-groups============================= */
952908500d5f99f35afc5ed510391b9bdc3833farbb
2d2eda71267231c2526be701fe655db125852c1ffieldingstatic int sdap_save_groups(TALLOC_CTX *memctx,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sysdb_ctx *sysdb,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sss_domain_info *dom,
2d2eda71267231c2526be701fe655db125852c1ffielding struct sdap_options *opts,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_attrs **groups,
952908500d5f99f35afc5ed510391b9bdc3833farbb int num_groups,
952908500d5f99f35afc5ed510391b9bdc3833farbb bool populate_members,
952908500d5f99f35afc5ed510391b9bdc3833farbb char **_usn_value)
952908500d5f99f35afc5ed510391b9bdc3833farbb{
952908500d5f99f35afc5ed510391b9bdc3833farbb TALLOC_CTX *tmpctx;
952908500d5f99f35afc5ed510391b9bdc3833farbb char *higher_usn = NULL;
952908500d5f99f35afc5ed510391b9bdc3833farbb char *usn_value;
952908500d5f99f35afc5ed510391b9bdc3833farbb bool twopass;
952908500d5f99f35afc5ed510391b9bdc3833farbb int ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb int i;
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_attrs **saved_groups = NULL;
952908500d5f99f35afc5ed510391b9bdc3833farbb int nsaved_groups = 0;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb switch (opts->schema_type) {
952908500d5f99f35afc5ed510391b9bdc3833farbb case SDAP_SCHEMA_RFC2307:
952908500d5f99f35afc5ed510391b9bdc3833farbb twopass = false;
952908500d5f99f35afc5ed510391b9bdc3833farbb break;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb case SDAP_SCHEMA_RFC2307BIS:
952908500d5f99f35afc5ed510391b9bdc3833farbb case SDAP_SCHEMA_IPA_V1:
952908500d5f99f35afc5ed510391b9bdc3833farbb case SDAP_SCHEMA_AD:
952908500d5f99f35afc5ed510391b9bdc3833farbb twopass = true;
952908500d5f99f35afc5ed510391b9bdc3833farbb break;
952908500d5f99f35afc5ed510391b9bdc3833farbb
2d2eda71267231c2526be701fe655db125852c1ffielding default:
2d2eda71267231c2526be701fe655db125852c1ffielding return EINVAL;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb tmpctx = talloc_new(memctx);
3d96ee83babeec32482c9082c9426340cee8c44dwrowe if (!tmpctx) {
3d96ee83babeec32482c9082c9426340cee8c44dwrowe return ENOMEM;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
3d96ee83babeec32482c9082c9426340cee8c44dwrowe ret = sysdb_transaction_start(sysdb);
3d96ee83babeec32482c9082c9426340cee8c44dwrowe if (ret) {
3d96ee83babeec32482c9082c9426340cee8c44dwrowe goto done;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (twopass && !populate_members) {
3d96ee83babeec32482c9082c9426340cee8c44dwrowe saved_groups = talloc_array(tmpctx, struct sysdb_attrs *,
3d96ee83babeec32482c9082c9426340cee8c44dwrowe num_groups);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (!saved_groups) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb ret = ENOMEM;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe goto done;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
3d96ee83babeec32482c9082c9426340cee8c44dwrowe
3d96ee83babeec32482c9082c9426340cee8c44dwrowe for (i = 0; i < num_groups; i++) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb usn_value = NULL;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
3d96ee83babeec32482c9082c9426340cee8c44dwrowe /* if 2 pass savemembers = false */
3d96ee83babeec32482c9082c9426340cee8c44dwrowe ret = sdap_save_group(tmpctx, sysdb,
3d96ee83babeec32482c9082c9426340cee8c44dwrowe opts, dom, groups[i],
3d96ee83babeec32482c9082c9426340cee8c44dwrowe (!twopass), populate_members, &usn_value);
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
3d96ee83babeec32482c9082c9426340cee8c44dwrowe /* Do not fail completely on errors.
3d96ee83babeec32482c9082c9426340cee8c44dwrowe * Just report the failure to save and go on */
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(2, ("Failed to store group %d. Ignoring.\n", i));
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb } else {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb DEBUG(9, ("Group %d processed!\n", i));
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (twopass && !populate_members) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb saved_groups[nsaved_groups] = groups[i];
2d2eda71267231c2526be701fe655db125852c1ffielding nsaved_groups++;
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb }
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (usn_value) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if (higher_usn) {
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb if ((strlen(usn_value) > strlen(higher_usn)) ||
b0f20a4a26bcfa85724b1c2e5ec6a077f12ef44crbb (strcmp(usn_value, higher_usn) > 0)) {
2d2eda71267231c2526be701fe655db125852c1ffielding talloc_zfree(higher_usn);
952908500d5f99f35afc5ed510391b9bdc3833farbb higher_usn = usn_value;
952908500d5f99f35afc5ed510391b9bdc3833farbb } else {
952908500d5f99f35afc5ed510391b9bdc3833farbb talloc_zfree(usn_value);
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb } else {
952908500d5f99f35afc5ed510391b9bdc3833farbb higher_usn = usn_value;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb }
3d96ee83babeec32482c9082c9426340cee8c44dwrowe }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb if (twopass && !populate_members) {
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb for (i = 0; i < nsaved_groups; i++) {
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sdap_save_grpmem(tmpctx, sysdb, opts, dom, saved_groups[i]);
952908500d5f99f35afc5ed510391b9bdc3833farbb /* Do not fail completely on errors.
952908500d5f99f35afc5ed510391b9bdc3833farbb * Just report the failure to save and go on */
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(2, ("Failed to store group %d members.\n", i));
3d96ee83babeec32482c9082c9426340cee8c44dwrowe } else {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(9, ("Group %d members processed!\n", i));
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_transaction_commit(sysdb);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(1, ("Failed to commit transaction!\n"));
952908500d5f99f35afc5ed510391b9bdc3833farbb goto done;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb if (_usn_value) {
952908500d5f99f35afc5ed510391b9bdc3833farbb *_usn_value = talloc_steal(memctx, higher_usn);
3d96ee83babeec32482c9082c9426340cee8c44dwrowe }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbbdone:
952908500d5f99f35afc5ed510391b9bdc3833farbb talloc_zfree(tmpctx);
952908500d5f99f35afc5ed510391b9bdc3833farbb return ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb}
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb/* ==Process-Groups======================================================= */
952908500d5f99f35afc5ed510391b9bdc3833farbb
3d96ee83babeec32482c9082c9426340cee8c44dwrowestruct sdap_process_group_state {
952908500d5f99f35afc5ed510391b9bdc3833farbb struct tevent_context *ev;
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sdap_options *opts;
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sdap_handle *sh;
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sss_domain_info *dom;
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_ctx *sysdb;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_attrs *group;
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_attrs **new_members;
952908500d5f99f35afc5ed510391b9bdc3833farbb struct ldb_message_element* sysdb_dns;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe char **queued_members;
952908500d5f99f35afc5ed510391b9bdc3833farbb int queue_len;
952908500d5f99f35afc5ed510391b9bdc3833farbb const char **attrs;
952908500d5f99f35afc5ed510391b9bdc3833farbb const char *filter;
952908500d5f99f35afc5ed510391b9bdc3833farbb size_t member_idx;
952908500d5f99f35afc5ed510391b9bdc3833farbb size_t queue_idx;
952908500d5f99f35afc5ed510391b9bdc3833farbb size_t count;
952908500d5f99f35afc5ed510391b9bdc3833farbb size_t check_count;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb bool enumeration;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe};
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb#define GROUPMEMBER_REQ_PARALLEL 50
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic void sdap_process_group_members(struct tevent_req *subreq);
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic int sdap_process_group_members_2307bis(struct tevent_req *req,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sdap_process_group_state *state,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct ldb_message_element *memberel);
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic int sdap_process_group_members_2307(struct sdap_process_group_state *state,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct ldb_message_element *memberel);
952908500d5f99f35afc5ed510391b9bdc3833farbb
3d96ee83babeec32482c9082c9426340cee8c44dwrowestruct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct tevent_context *ev,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sss_domain_info *dom,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_ctx *sysdb,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sdap_options *opts,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sdap_handle *sh,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_attrs *group,
952908500d5f99f35afc5ed510391b9bdc3833farbb bool enumeration)
952908500d5f99f35afc5ed510391b9bdc3833farbb{
952908500d5f99f35afc5ed510391b9bdc3833farbb struct ldb_message_element *el;
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sdap_process_group_state *grp_state;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe struct tevent_req *req = NULL;
952908500d5f99f35afc5ed510391b9bdc3833farbb const char **attrs;
952908500d5f99f35afc5ed510391b9bdc3833farbb char* filter;
952908500d5f99f35afc5ed510391b9bdc3833farbb int ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb req = tevent_req_create(memctx, &grp_state,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sdap_process_group_state);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (!req) return NULL;
952908500d5f99f35afc5ed510391b9bdc3833farbb
3d96ee83babeec32482c9082c9426340cee8c44dwrowe ret = build_attrs_from_map(grp_state, opts->user_map, SDAP_OPTS_USER, &attrs);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) {
952908500d5f99f35afc5ed510391b9bdc3833farbb goto done;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb /* FIXME: we ignore nested rfc2307bis groups for now */
952908500d5f99f35afc5ed510391b9bdc3833farbb filter = talloc_asprintf(grp_state, "(objectclass=%s)",
952908500d5f99f35afc5ed510391b9bdc3833farbb opts->user_map[SDAP_OC_USER].name);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (!filter) {
3d96ee83babeec32482c9082c9426340cee8c44dwrowe talloc_zfree(req);
952908500d5f99f35afc5ed510391b9bdc3833farbb return NULL;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->ev = ev;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->opts = opts;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->dom = dom;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->sh = sh;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->sysdb = sysdb;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->group = group;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->check_count = 0;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->new_members = NULL;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe grp_state->member_idx = 0;
2d2eda71267231c2526be701fe655db125852c1ffielding grp_state->queue_idx = 0;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->queued_members = NULL;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->queue_len = 0;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->filter = filter;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->attrs = attrs;
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->enumeration = enumeration;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sysdb_attrs_get_el(group,
952908500d5f99f35afc5ed510391b9bdc3833farbb opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,
952908500d5f99f35afc5ed510391b9bdc3833farbb &el);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret) {
3d96ee83babeec32482c9082c9426340cee8c44dwrowe goto done;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb /* Group without members */
952908500d5f99f35afc5ed510391b9bdc3833farbb if (el->num_values == 0) {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(2, ("No Members. Done!\n"));
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = EOK;
952908500d5f99f35afc5ed510391b9bdc3833farbb goto done;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->sysdb_dns = talloc(grp_state, struct ldb_message_element);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (!grp_state->sysdb_dns) {
952908500d5f99f35afc5ed510391b9bdc3833farbb talloc_zfree(req);
3d96ee83babeec32482c9082c9426340cee8c44dwrowe return NULL;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->sysdb_dns->values = talloc_array(grp_state, struct ldb_val,
952908500d5f99f35afc5ed510391b9bdc3833farbb el->num_values);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (!grp_state->sysdb_dns->values) {
952908500d5f99f35afc5ed510391b9bdc3833farbb talloc_zfree(req);
952908500d5f99f35afc5ed510391b9bdc3833farbb return NULL;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb grp_state->sysdb_dns->num_values = 0;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb switch (opts->schema_type) {
3d96ee83babeec32482c9082c9426340cee8c44dwrowe case SDAP_SCHEMA_RFC2307:
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sdap_process_group_members_2307(grp_state, el);
952908500d5f99f35afc5ed510391b9bdc3833farbb break;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb case SDAP_SCHEMA_IPA_V1:
952908500d5f99f35afc5ed510391b9bdc3833farbb case SDAP_SCHEMA_AD:
952908500d5f99f35afc5ed510391b9bdc3833farbb case SDAP_SCHEMA_RFC2307BIS:
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sdap_process_group_members_2307bis(req, grp_state, el);
952908500d5f99f35afc5ed510391b9bdc3833farbb break;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb default:
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(1, ("Unknown schema type %d\n", opts->schema_type));
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = EINVAL;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe break;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbbdone:
952908500d5f99f35afc5ed510391b9bdc3833farbb /* We managed to process all the entries */
952908500d5f99f35afc5ed510391b9bdc3833farbb /* EBUSY means we need to wait for entries in LDAP */
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret == EOK) {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(7, ("All group members processed\n"));
952908500d5f99f35afc5ed510391b9bdc3833farbb tevent_req_done(req);
952908500d5f99f35afc5ed510391b9bdc3833farbb tevent_req_post(req, ev);
3d96ee83babeec32482c9082c9426340cee8c44dwrowe }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret != EOK && ret != EBUSY) {
952908500d5f99f35afc5ed510391b9bdc3833farbb tevent_req_error(req, ret);
952908500d5f99f35afc5ed510391b9bdc3833farbb tevent_req_post(req, ev);
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb return req;
952908500d5f99f35afc5ed510391b9bdc3833farbb}
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic int
3d96ee83babeec32482c9082c9426340cee8c44dwrowesdap_process_missing_member_2307bis(struct tevent_req *req,
2d2eda71267231c2526be701fe655db125852c1ffielding char *user_dn,
952908500d5f99f35afc5ed510391b9bdc3833farbb int num_users);
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic int
952908500d5f99f35afc5ed510391b9bdc3833farbbsdap_process_group_members_2307bis(struct tevent_req *req,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sdap_process_group_state *state,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct ldb_message_element *memberel)
3d96ee83babeec32482c9082c9426340cee8c44dwrowe{
952908500d5f99f35afc5ed510391b9bdc3833farbb char *member_dn;
952908500d5f99f35afc5ed510391b9bdc3833farbb char *strdn;
952908500d5f99f35afc5ed510391b9bdc3833farbb int ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb int i;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb for (i=0; i < memberel->num_values; i++) {
952908500d5f99f35afc5ed510391b9bdc3833farbb member_dn = (char *)memberel->values[i].data;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sdap_find_entry_by_origDN(state->sysdb_dns->values,
952908500d5f99f35afc5ed510391b9bdc3833farbb state->sysdb,
952908500d5f99f35afc5ed510391b9bdc3833farbb state->dom,
952908500d5f99f35afc5ed510391b9bdc3833farbb member_dn,
952908500d5f99f35afc5ed510391b9bdc3833farbb &strdn);
3d96ee83babeec32482c9082c9426340cee8c44dwrowe if (ret == EOK) {
952908500d5f99f35afc5ed510391b9bdc3833farbb /*
952908500d5f99f35afc5ed510391b9bdc3833farbb * User already cached in sysdb. Remember the sysdb DN for later
952908500d5f99f35afc5ed510391b9bdc3833farbb * use by sdap_save_groups()
952908500d5f99f35afc5ed510391b9bdc3833farbb */
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(7, ("sysdbdn: %s\n", strdn));
952908500d5f99f35afc5ed510391b9bdc3833farbb state->sysdb_dns->values[state->sysdb_dns->num_values].data =
3d96ee83babeec32482c9082c9426340cee8c44dwrowe (uint8_t*) strdn;
952908500d5f99f35afc5ed510391b9bdc3833farbb state->sysdb_dns->values[state->sysdb_dns->num_values].length =
952908500d5f99f35afc5ed510391b9bdc3833farbb strlen(strdn);
952908500d5f99f35afc5ed510391b9bdc3833farbb state->sysdb_dns->num_values++;
952908500d5f99f35afc5ed510391b9bdc3833farbb } else if (ret == ENOENT) {
952908500d5f99f35afc5ed510391b9bdc3833farbb if (!state->enumeration) {
952908500d5f99f35afc5ed510391b9bdc3833farbb /* The user is not in sysdb, need to add it
952908500d5f99f35afc5ed510391b9bdc3833farbb * We don't need to do this if we're in an enumeration,
952908500d5f99f35afc5ed510391b9bdc3833farbb * because all real members should all be populated
3d96ee83babeec32482c9082c9426340cee8c44dwrowe * already by the first pass of the enumeration.
952908500d5f99f35afc5ed510391b9bdc3833farbb * Also, we don't want to be holding the sysdb
952908500d5f99f35afc5ed510391b9bdc3833farbb * transaction while we're performing LDAP lookups.
952908500d5f99f35afc5ed510391b9bdc3833farbb */
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(7, ("Searching LDAP for missing user entry\n"));
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = sdap_process_missing_member_2307bis(req,
952908500d5f99f35afc5ed510391b9bdc3833farbb member_dn,
952908500d5f99f35afc5ed510391b9bdc3833farbb memberel->num_values);
952908500d5f99f35afc5ed510391b9bdc3833farbb if (ret != EOK) {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(1, ("Error processing missing member #%d (%s):\n",
3d96ee83babeec32482c9082c9426340cee8c44dwrowe i, member_dn));
2d2eda71267231c2526be701fe655db125852c1ffielding return ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb } else {
952908500d5f99f35afc5ed510391b9bdc3833farbb DEBUG(1, ("Error checking cache for member #%d (%s):\n",
952908500d5f99f35afc5ed510391b9bdc3833farbb i, (char *)memberel->values[i].data));
952908500d5f99f35afc5ed510391b9bdc3833farbb return ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb }
3d96ee83babeec32482c9082c9426340cee8c44dwrowe
952908500d5f99f35afc5ed510391b9bdc3833farbb if (state->queue_len > 0) {
952908500d5f99f35afc5ed510391b9bdc3833farbb state->queued_members[state->queue_len]=NULL;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb if (state->check_count == 0) {
952908500d5f99f35afc5ed510391b9bdc3833farbb /*
952908500d5f99f35afc5ed510391b9bdc3833farbb * All group members are already cached in sysdb, we are done
952908500d5f99f35afc5ed510391b9bdc3833farbb * with this group. To avoid redundant sysdb lookups, populate the
dad234382d8424e1c5a30af2838e172aec9d6d1bdreid * "member" attribute of the group entry with the sysdb DNs of
952908500d5f99f35afc5ed510391b9bdc3833farbb * the members.
3d96ee83babeec32482c9082c9426340cee8c44dwrowe */
dad234382d8424e1c5a30af2838e172aec9d6d1bdreid ret = EOK;
952908500d5f99f35afc5ed510391b9bdc3833farbb memberel->values = talloc_steal(state->group, state->sysdb_dns->values);
952908500d5f99f35afc5ed510391b9bdc3833farbb memberel->num_values = state->sysdb_dns->num_values;
952908500d5f99f35afc5ed510391b9bdc3833farbb } else {
952908500d5f99f35afc5ed510391b9bdc3833farbb state->count = state->check_count;
952908500d5f99f35afc5ed510391b9bdc3833farbb state->new_members = talloc_zero_array(state,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct sysdb_attrs *,
952908500d5f99f35afc5ed510391b9bdc3833farbb state->count + 1);
3d96ee83babeec32482c9082c9426340cee8c44dwrowe if (!state->new_members) {
2d2eda71267231c2526be701fe655db125852c1ffielding return ENOMEM;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb ret = EBUSY;
952908500d5f99f35afc5ed510391b9bdc3833farbb }
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb return ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb}
3d96ee83babeec32482c9082c9426340cee8c44dwrowe
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic int
59ae852bea7d507f61999f982ded8219d2c0ec15wrowesdap_process_missing_member_2307(struct sdap_process_group_state *state,
59ae852bea7d507f61999f982ded8219d2c0ec15wrowe char *username, bool *in_transaction);
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbbstatic int
952908500d5f99f35afc5ed510391b9bdc3833farbbsdap_process_group_members_2307(struct sdap_process_group_state *state,
952908500d5f99f35afc5ed510391b9bdc3833farbb struct ldb_message_element *memberel)
952908500d5f99f35afc5ed510391b9bdc3833farbb{
59ae852bea7d507f61999f982ded8219d2c0ec15wrowe struct ldb_message *msg;
59ae852bea7d507f61999f982ded8219d2c0ec15wrowe bool in_transaction = false;
59ae852bea7d507f61999f982ded8219d2c0ec15wrowe char *member_name;
952908500d5f99f35afc5ed510391b9bdc3833farbb char *strdn;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe int ret;
952908500d5f99f35afc5ed510391b9bdc3833farbb errno_t sret;
952908500d5f99f35afc5ed510391b9bdc3833farbb int i;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb for (i=0; i < memberel->num_values; i++) {
952908500d5f99f35afc5ed510391b9bdc3833farbb member_name = (char *)memberel->values[i].data;
952908500d5f99f35afc5ed510391b9bdc3833farbb
952908500d5f99f35afc5ed510391b9bdc3833farbb /* We need to skip over zero-length usernames */
3d96ee83babeec32482c9082c9426340cee8c44dwrowe if (member_name[0] == '\0') continue;
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb ret = sysdb_search_user_by_name(state, state->sysdb,
58619148951981bcfa5c506ad8ce745aa8831980rbb state->dom, member_name,
58619148951981bcfa5c506ad8ce745aa8831980rbb NULL, &msg);
58619148951981bcfa5c506ad8ce745aa8831980rbb if (ret == EOK) {
58619148951981bcfa5c506ad8ce745aa8831980rbb strdn = sysdb_user_strdn(state->sysdb_dns->values,
58619148951981bcfa5c506ad8ce745aa8831980rbb state->dom->name,
58619148951981bcfa5c506ad8ce745aa8831980rbb member_name);
58619148951981bcfa5c506ad8ce745aa8831980rbb if (!strdn) {
58619148951981bcfa5c506ad8ce745aa8831980rbb ret = ENOMEM;
58619148951981bcfa5c506ad8ce745aa8831980rbb goto done;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe }
2d2eda71267231c2526be701fe655db125852c1ffielding /*
58619148951981bcfa5c506ad8ce745aa8831980rbb * User already cached in sysdb. Remember the sysdb DN for later
58619148951981bcfa5c506ad8ce745aa8831980rbb * use by sdap_save_groups()
58619148951981bcfa5c506ad8ce745aa8831980rbb */
58619148951981bcfa5c506ad8ce745aa8831980rbb DEBUG(7,("Member already cached in sysdb: %s\n", strdn));
58619148951981bcfa5c506ad8ce745aa8831980rbb state->sysdb_dns->values[state->sysdb_dns->num_values].data =
58619148951981bcfa5c506ad8ce745aa8831980rbb (uint8_t *) strdn;
58619148951981bcfa5c506ad8ce745aa8831980rbb state->sysdb_dns->values[state->sysdb_dns->num_values].length =
58619148951981bcfa5c506ad8ce745aa8831980rbb strlen(strdn);
3d96ee83babeec32482c9082c9426340cee8c44dwrowe state->sysdb_dns->num_values++;
58619148951981bcfa5c506ad8ce745aa8831980rbb } else if (ret == ENOENT) {
58619148951981bcfa5c506ad8ce745aa8831980rbb /* The user is not in sysdb, need to add it */
58619148951981bcfa5c506ad8ce745aa8831980rbb DEBUG(7, ("member #%d (%s): not found in sysdb\n",
58619148951981bcfa5c506ad8ce745aa8831980rbb i, member_name));
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb ret = sdap_process_missing_member_2307(state, member_name,
58619148951981bcfa5c506ad8ce745aa8831980rbb &in_transaction);
58619148951981bcfa5c506ad8ce745aa8831980rbb if (ret != EOK) {
3d96ee83babeec32482c9082c9426340cee8c44dwrowe DEBUG(1, ("Error processing missing member #%d (%s):\n",
58619148951981bcfa5c506ad8ce745aa8831980rbb i, member_name));
58619148951981bcfa5c506ad8ce745aa8831980rbb goto done;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb } else {
58619148951981bcfa5c506ad8ce745aa8831980rbb DEBUG(1, ("Error checking cache for member #%d (%s):\n",
58619148951981bcfa5c506ad8ce745aa8831980rbb i, (char *) memberel->values[i].data));
58619148951981bcfa5c506ad8ce745aa8831980rbb goto done;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
3d96ee83babeec32482c9082c9426340cee8c44dwrowe }
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb /* sdap_process_missing_member_2307 starts transaction */
58619148951981bcfa5c506ad8ce745aa8831980rbb if (in_transaction) {
58619148951981bcfa5c506ad8ce745aa8831980rbb ret = sysdb_transaction_commit(state->sysdb);
58619148951981bcfa5c506ad8ce745aa8831980rbb if (ret) {
58619148951981bcfa5c506ad8ce745aa8831980rbb DEBUG(2, ("Cannot commit sysdb transaction\n"));
58619148951981bcfa5c506ad8ce745aa8831980rbb goto done;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
3d96ee83babeec32482c9082c9426340cee8c44dwrowe in_transaction = false;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
30c095035b1d5910cc239a1384c816aef228beb5jim
30c095035b1d5910cc239a1384c816aef228beb5jim ret = EOK;
30c095035b1d5910cc239a1384c816aef228beb5jim memberel->values = talloc_steal(state->group, state->sysdb_dns->values);
30c095035b1d5910cc239a1384c816aef228beb5jim memberel->num_values = state->sysdb_dns->num_values;
30c095035b1d5910cc239a1384c816aef228beb5jim
bdadc326446cae4a51bf75811fbe01a3a362df64gsteindone:
30c095035b1d5910cc239a1384c816aef228beb5jim if (in_transaction) {
bdadc326446cae4a51bf75811fbe01a3a362df64gstein /* If the transaction is still active here, we need to cancel it */
bdadc326446cae4a51bf75811fbe01a3a362df64gstein sret = sysdb_transaction_cancel(state->sysdb);
30c095035b1d5910cc239a1384c816aef228beb5jim if (sret != EOK) {
58619148951981bcfa5c506ad8ce745aa8831980rbb DEBUG(0, ("Unable to cancel transaction! [%d][%s]\n",
58619148951981bcfa5c506ad8ce745aa8831980rbb sret, strerror(sret)));
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb return ret;
58619148951981bcfa5c506ad8ce745aa8831980rbb}
58619148951981bcfa5c506ad8ce745aa8831980rbb
3d96ee83babeec32482c9082c9426340cee8c44dwrowe
58619148951981bcfa5c506ad8ce745aa8831980rbbstatic int
58619148951981bcfa5c506ad8ce745aa8831980rbbsdap_process_missing_member_2307bis(struct tevent_req *req,
58619148951981bcfa5c506ad8ce745aa8831980rbb char *user_dn,
58619148951981bcfa5c506ad8ce745aa8831980rbb int num_users)
58619148951981bcfa5c506ad8ce745aa8831980rbb{
58619148951981bcfa5c506ad8ce745aa8831980rbb struct sdap_process_group_state *grp_state =
58619148951981bcfa5c506ad8ce745aa8831980rbb tevent_req_data(req, struct sdap_process_group_state);
58619148951981bcfa5c506ad8ce745aa8831980rbb struct tevent_req *subreq;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe
58619148951981bcfa5c506ad8ce745aa8831980rbb /*
06924437019f9871bc4ee49748511130548b7d35rbb * Issue at most GROUPMEMBER_REQ_PARALLEL LDAP searches at once.
2d2eda71267231c2526be701fe655db125852c1ffielding * The rest is sent while the results are being processed.
58619148951981bcfa5c506ad8ce745aa8831980rbb * We limit the number as of request here, as the Server might
58619148951981bcfa5c506ad8ce745aa8831980rbb * enforce limits on the number of pending operations per
58619148951981bcfa5c506ad8ce745aa8831980rbb * connection.
58619148951981bcfa5c506ad8ce745aa8831980rbb */
58619148951981bcfa5c506ad8ce745aa8831980rbb if (grp_state->check_count > GROUPMEMBER_REQ_PARALLEL) {
58619148951981bcfa5c506ad8ce745aa8831980rbb DEBUG(7, (" queueing search for: %s\n", user_dn));
58619148951981bcfa5c506ad8ce745aa8831980rbb if (!grp_state->queued_members) {
58619148951981bcfa5c506ad8ce745aa8831980rbb DEBUG(7, ("Allocating queue for %d members\n",
58619148951981bcfa5c506ad8ce745aa8831980rbb num_users - grp_state->check_count));
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb grp_state->queued_members = talloc_array(grp_state, char *,
58619148951981bcfa5c506ad8ce745aa8831980rbb num_users - grp_state->check_count + 1);
58619148951981bcfa5c506ad8ce745aa8831980rbb if (!grp_state->queued_members) {
58619148951981bcfa5c506ad8ce745aa8831980rbb return ENOMEM;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe }
ffba30a2a49b298bfa65151bdf61ce3e3d4636d1manoj }
58619148951981bcfa5c506ad8ce745aa8831980rbb grp_state->queued_members[grp_state->queue_len] = user_dn;
58619148951981bcfa5c506ad8ce745aa8831980rbb grp_state->queue_len++;
58619148951981bcfa5c506ad8ce745aa8831980rbb } else {
58619148951981bcfa5c506ad8ce745aa8831980rbb subreq = sdap_get_generic_send(grp_state,
58619148951981bcfa5c506ad8ce745aa8831980rbb grp_state->ev,
58619148951981bcfa5c506ad8ce745aa8831980rbb grp_state->opts,
3d96ee83babeec32482c9082c9426340cee8c44dwrowe grp_state->sh,
58619148951981bcfa5c506ad8ce745aa8831980rbb user_dn,
58619148951981bcfa5c506ad8ce745aa8831980rbb LDAP_SCOPE_BASE,
58619148951981bcfa5c506ad8ce745aa8831980rbb grp_state->filter,
58619148951981bcfa5c506ad8ce745aa8831980rbb grp_state->attrs,
58619148951981bcfa5c506ad8ce745aa8831980rbb grp_state->opts->user_map,
58619148951981bcfa5c506ad8ce745aa8831980rbb SDAP_OPTS_USER,
58619148951981bcfa5c506ad8ce745aa8831980rbb dp_opt_get_int(grp_state->opts->basic,
58619148951981bcfa5c506ad8ce745aa8831980rbb SDAP_SEARCH_TIMEOUT));
58619148951981bcfa5c506ad8ce745aa8831980rbb if (!subreq) {
58619148951981bcfa5c506ad8ce745aa8831980rbb return ENOMEM;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb tevent_req_set_callback(subreq, sdap_process_group_members, req);
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb grp_state->check_count++;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe return EOK;
2d2eda71267231c2526be701fe655db125852c1ffielding}
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbbstatic int
58619148951981bcfa5c506ad8ce745aa8831980rbbsdap_process_missing_member_2307(struct sdap_process_group_state *state,
58619148951981bcfa5c506ad8ce745aa8831980rbb char *username, bool *in_transaction)
58619148951981bcfa5c506ad8ce745aa8831980rbb{
58619148951981bcfa5c506ad8ce745aa8831980rbb int ret, sret;
58619148951981bcfa5c506ad8ce745aa8831980rbb struct ldb_dn *dn;
58619148951981bcfa5c506ad8ce745aa8831980rbb char* dn_string;
58619148951981bcfa5c506ad8ce745aa8831980rbb
3d96ee83babeec32482c9082c9426340cee8c44dwrowe DEBUG(7, ("Adding a dummy entry\n"));
2d2eda71267231c2526be701fe655db125852c1ffielding
58619148951981bcfa5c506ad8ce745aa8831980rbb if (!in_transaction) return EINVAL;
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb if (!*in_transaction) {
58619148951981bcfa5c506ad8ce745aa8831980rbb ret = sysdb_transaction_start(state->sysdb);
58619148951981bcfa5c506ad8ce745aa8831980rbb if (ret != EOK) {
58619148951981bcfa5c506ad8ce745aa8831980rbb DEBUG(1, ("Cannot start sysdb transaction: [%d]: %s\n",
58619148951981bcfa5c506ad8ce745aa8831980rbb ret, strerror(ret)));
58619148951981bcfa5c506ad8ce745aa8831980rbb return ret;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb *in_transaction = true;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb ret = sysdb_add_fake_user(state->sysdb, state->dom, username, NULL);
3d96ee83babeec32482c9082c9426340cee8c44dwrowe if (ret != EOK) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(1, ("Cannot store fake user entry: [%d]: %s\n",
2d2eda71267231c2526be701fe655db125852c1ffielding ret, strerror(ret)));
58619148951981bcfa5c506ad8ce745aa8831980rbb goto fail;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb /*
58619148951981bcfa5c506ad8ce745aa8831980rbb * Convert the just received DN into the corresponding sysdb DN
58619148951981bcfa5c506ad8ce745aa8831980rbb * for saving into member attribute of the group
3d96ee83babeec32482c9082c9426340cee8c44dwrowe */
58619148951981bcfa5c506ad8ce745aa8831980rbb dn = sysdb_user_dn(state->sysdb, state, state->dom->name,
58619148951981bcfa5c506ad8ce745aa8831980rbb (char*) username);
58619148951981bcfa5c506ad8ce745aa8831980rbb if (!dn) {
58619148951981bcfa5c506ad8ce745aa8831980rbb ret = ENOMEM;
58619148951981bcfa5c506ad8ce745aa8831980rbb goto fail;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe }
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb dn_string = ldb_dn_alloc_linearized(state->sysdb_dns->values, dn);
58619148951981bcfa5c506ad8ce745aa8831980rbb if (!dn_string) {
58619148951981bcfa5c506ad8ce745aa8831980rbb ret = ENOMEM;
58619148951981bcfa5c506ad8ce745aa8831980rbb goto fail;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb state->sysdb_dns->values[state->sysdb_dns->num_values].data =
58619148951981bcfa5c506ad8ce745aa8831980rbb (uint8_t *) dn_string;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe state->sysdb_dns->values[state->sysdb_dns->num_values].length =
58619148951981bcfa5c506ad8ce745aa8831980rbb strlen(dn_string);
58619148951981bcfa5c506ad8ce745aa8831980rbb state->sysdb_dns->num_values++;
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb return EOK;
58619148951981bcfa5c506ad8ce745aa8831980rbbfail:
58619148951981bcfa5c506ad8ce745aa8831980rbb if (*in_transaction) {
58619148951981bcfa5c506ad8ce745aa8831980rbb sret = sysdb_transaction_cancel(state->sysdb);
58619148951981bcfa5c506ad8ce745aa8831980rbb if (sret == EOK) {
58619148951981bcfa5c506ad8ce745aa8831980rbb *in_transaction = false;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe } else {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(0, ("Unable to cancel transaction! [%d][%s]\n",
58619148951981bcfa5c506ad8ce745aa8831980rbb sret, strerror(sret)));
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb return ret;
58619148951981bcfa5c506ad8ce745aa8831980rbb}
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbbstatic void sdap_process_group_members(struct tevent_req *subreq)
3d96ee83babeec32482c9082c9426340cee8c44dwrowe{
2d2eda71267231c2526be701fe655db125852c1ffielding struct sysdb_attrs **usr_attrs;
2d2eda71267231c2526be701fe655db125852c1ffielding size_t count;
58619148951981bcfa5c506ad8ce745aa8831980rbb int ret;
58619148951981bcfa5c506ad8ce745aa8831980rbb struct tevent_req *req =
58619148951981bcfa5c506ad8ce745aa8831980rbb tevent_req_callback_data(subreq, struct tevent_req);
58619148951981bcfa5c506ad8ce745aa8831980rbb struct sdap_process_group_state *state =
58619148951981bcfa5c506ad8ce745aa8831980rbb tevent_req_data(req, struct sdap_process_group_state);
58619148951981bcfa5c506ad8ce745aa8831980rbb struct ldb_message_element *el;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe struct ldb_dn *dn;
58619148951981bcfa5c506ad8ce745aa8831980rbb char* dn_string;
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb state->check_count--;
58619148951981bcfa5c506ad8ce745aa8831980rbb DEBUG(9, ("Members remaining: %d\n", state->check_count));
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs);
3d96ee83babeec32482c9082c9426340cee8c44dwrowe talloc_zfree(subreq);
58619148951981bcfa5c506ad8ce745aa8831980rbb if (ret) {
58619148951981bcfa5c506ad8ce745aa8831980rbb goto next;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb if (count != 1) {
30c095035b1d5910cc239a1384c816aef228beb5jim ret = EINVAL;
30c095035b1d5910cc239a1384c816aef228beb5jim DEBUG(7, ("Expected one user entry and got %d\n", count));
3d96ee83babeec32482c9082c9426340cee8c44dwrowe goto next;
30c095035b1d5910cc239a1384c816aef228beb5jim }
30c095035b1d5910cc239a1384c816aef228beb5jim ret = sysdb_attrs_get_el(usr_attrs[0],
30c095035b1d5910cc239a1384c816aef228beb5jim state->opts->user_map[SDAP_AT_USER_NAME].sys_name, &el);
30c095035b1d5910cc239a1384c816aef228beb5jim if (el->num_values == 0) {
58619148951981bcfa5c506ad8ce745aa8831980rbb ret = EINVAL;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
3d96ee83babeec32482c9082c9426340cee8c44dwrowe if (ret) {
58619148951981bcfa5c506ad8ce745aa8831980rbb DEBUG(2, ("Failed to get the member's name\n"));
58619148951981bcfa5c506ad8ce745aa8831980rbb goto next;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb /*
3d96ee83babeec32482c9082c9426340cee8c44dwrowe * Convert the just received DN into the corresponding sysdb DN
58619148951981bcfa5c506ad8ce745aa8831980rbb * for later usage by sdap_save_groups()
58619148951981bcfa5c506ad8ce745aa8831980rbb */
58619148951981bcfa5c506ad8ce745aa8831980rbb dn = sysdb_user_dn(state->sysdb, state, state->dom->name,
58619148951981bcfa5c506ad8ce745aa8831980rbb (char*)el[0].values[0].data);
58619148951981bcfa5c506ad8ce745aa8831980rbb if (!dn) {
3d96ee83babeec32482c9082c9426340cee8c44dwrowe tevent_req_error(req, ENOMEM);
2d2eda71267231c2526be701fe655db125852c1ffielding return;
2d2eda71267231c2526be701fe655db125852c1ffielding }
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm
2d2eda71267231c2526be701fe655db125852c1ffielding dn_string = ldb_dn_alloc_linearized(state->group, dn);
2d2eda71267231c2526be701fe655db125852c1ffielding if (!dn_string) {
2d2eda71267231c2526be701fe655db125852c1ffielding tevent_req_error(req, ENOMEM);
58619148951981bcfa5c506ad8ce745aa8831980rbb return;
58619148951981bcfa5c506ad8ce745aa8831980rbb }
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb state->sysdb_dns->values[state->sysdb_dns->num_values].data =
58619148951981bcfa5c506ad8ce745aa8831980rbb (uint8_t*)dn_string;
c861a36fe9c9a78c4fcb97e29fc1099a5ea81173rbb state->sysdb_dns->values[state->sysdb_dns->num_values].length =
58619148951981bcfa5c506ad8ce745aa8831980rbb strlen(dn_string);
2d2eda71267231c2526be701fe655db125852c1ffielding state->sysdb_dns->num_values++;
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbb state->new_members[state->member_idx] = usr_attrs[0];
58619148951981bcfa5c506ad8ce745aa8831980rbb state->member_idx++;
58619148951981bcfa5c506ad8ce745aa8831980rbb
58619148951981bcfa5c506ad8ce745aa8831980rbbnext:
58619148951981bcfa5c506ad8ce745aa8831980rbb if (ret) {
dad234382d8424e1c5a30af2838e172aec9d6d1bdreid DEBUG(7, ("Error reading group member. Skipping\n", ret));
58619148951981bcfa5c506ad8ce745aa8831980rbb state->count--;
dad234382d8424e1c5a30af2838e172aec9d6d1bdreid }
2d2eda71267231c2526be701fe655db125852c1ffielding /* Are there more searches for uncached users to submit ? */
2d2eda71267231c2526be701fe655db125852c1ffielding if (state->queued_members && state->queued_members[state->queue_idx]) {
2d2eda71267231c2526be701fe655db125852c1ffielding subreq = sdap_get_generic_send(state,
0186cb43574836fc95a0506456210c94cfc3ea6ftrawick state->ev, state->opts, state->sh,
0186cb43574836fc95a0506456210c94cfc3ea6ftrawick state->queued_members[state->queue_idx],
6e70165f24ec2e664764a9402e358eb0f6e99a3dtrawick LDAP_SCOPE_BASE,
0186cb43574836fc95a0506456210c94cfc3ea6ftrawick state->filter,
2d2eda71267231c2526be701fe655db125852c1ffielding state->attrs,
58619148951981bcfa5c506ad8ce745aa8831980rbb state->opts->user_map,
58619148951981bcfa5c506ad8ce745aa8831980rbb SDAP_OPTS_USER,
58619148951981bcfa5c506ad8ce745aa8831980rbb dp_opt_get_int(state->opts->basic,
58619148951981bcfa5c506ad8ce745aa8831980rbb SDAP_SEARCH_TIMEOUT));
58619148951981bcfa5c506ad8ce745aa8831980rbb if (!subreq) {
58619148951981bcfa5c506ad8ce745aa8831980rbb tevent_req_error(req, ENOMEM);
58619148951981bcfa5c506ad8ce745aa8831980rbb return;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding tevent_req_set_callback(subreq,
2d2eda71267231c2526be701fe655db125852c1ffielding sdap_process_group_members, req);
0186cb43574836fc95a0506456210c94cfc3ea6ftrawick state->queue_idx++;
6e70165f24ec2e664764a9402e358eb0f6e99a3dtrawick }
0186cb43574836fc95a0506456210c94cfc3ea6ftrawick
6e70165f24ec2e664764a9402e358eb0f6e99a3dtrawick if (state->check_count == 0) {
0186cb43574836fc95a0506456210c94cfc3ea6ftrawick ret = sdap_save_users(state, state->sysdb, state->attrs,
0186cb43574836fc95a0506456210c94cfc3ea6ftrawick state->dom, state->opts,
2d2eda71267231c2526be701fe655db125852c1ffielding state->new_members, state->count, NULL);
2d2eda71267231c2526be701fe655db125852c1ffielding if (ret) {
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(2, ("Failed to store users.\n"));
2d2eda71267231c2526be701fe655db125852c1ffielding tevent_req_error(req, ret);
2d2eda71267231c2526be701fe655db125852c1ffielding return;
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding /*
2d2eda71267231c2526be701fe655db125852c1ffielding * To avoid redundant sysdb lookups, populate the "member" attribute
2d2eda71267231c2526be701fe655db125852c1ffielding * of the group entry with the sysdb DNs of the members.
2d2eda71267231c2526be701fe655db125852c1ffielding */
2d2eda71267231c2526be701fe655db125852c1ffielding ret = sysdb_attrs_get_el(state->group,
2d2eda71267231c2526be701fe655db125852c1ffielding state->opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el);
2d2eda71267231c2526be701fe655db125852c1ffielding el->values = talloc_steal(state->group, state->sysdb_dns->values);
2d2eda71267231c2526be701fe655db125852c1ffielding el->num_values = state->sysdb_dns->num_values;
2d2eda71267231c2526be701fe655db125852c1ffielding DEBUG(9, ("Processed Group - Done\n"));
2d2eda71267231c2526be701fe655db125852c1ffielding tevent_req_done(req);
2d2eda71267231c2526be701fe655db125852c1ffielding }
2d2eda71267231c2526be701fe655db125852c1ffielding}
2d2eda71267231c2526be701fe655db125852c1ffielding
3d96ee83babeec32482c9082c9426340cee8c44dwrowestatic int sdap_process_group_recv(struct tevent_req *req)
2d2eda71267231c2526be701fe655db125852c1ffielding{
2d2eda71267231c2526be701fe655db125852c1ffielding TEVENT_REQ_RETURN_ON_ERROR(req);
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding return EOK;
2d2eda71267231c2526be701fe655db125852c1ffielding}
2d2eda71267231c2526be701fe655db125852c1ffielding
2d2eda71267231c2526be701fe655db125852c1ffielding
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben/* ==Search-Groups-with-filter============================================ */
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben
9521cafc02c2caafc8f9594006994ed1f62540a4dreidstruct sdap_get_groups_state {
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben struct tevent_context *ev;
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben struct sdap_options *opts;
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben struct sdap_handle *sh;
5f7c351eb2a69d8cef6c3e98e27ce6158a0b1780rbb struct sss_domain_info *dom;
66d349e02d1a5a599a01c977d2c5b0009181f7deben struct sysdb_ctx *sysdb;
5f7c351eb2a69d8cef6c3e98e27ce6158a0b1780rbb const char **attrs;
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben const char *filter;
dca927eafb338b9de9d0214818136c16d436e3fdrbb
dca927eafb338b9de9d0214818136c16d436e3fdrbb char *higher_usn;
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben struct sysdb_attrs **groups;
66d349e02d1a5a599a01c977d2c5b0009181f7deben size_t count;
66d349e02d1a5a599a01c977d2c5b0009181f7deben size_t check_count;
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben hash_table_t *user_hash;
dca927eafb338b9de9d0214818136c16d436e3fdrbb hash_table_t *group_hash;
dca927eafb338b9de9d0214818136c16d436e3fdrbb};
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben
0e6e93183d91142d7cf9ffbf502114ff77bd9e19benstatic void sdap_get_groups_process(struct tevent_req *subreq);
0e6e93183d91142d7cf9ffbf502114ff77bd9e19benstatic void sdap_get_groups_done(struct tevent_req *subreq);
66d349e02d1a5a599a01c977d2c5b0009181f7deben
66d349e02d1a5a599a01c977d2c5b0009181f7debenstruct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben struct tevent_context *ev,
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben struct sss_domain_info *dom,
dca927eafb338b9de9d0214818136c16d436e3fdrbb struct sysdb_ctx *sysdb,
dca927eafb338b9de9d0214818136c16d436e3fdrbb struct sdap_options *opts,
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben struct sdap_handle *sh,
0e6e93183d91142d7cf9ffbf502114ff77bd9e19ben const char **attrs,
0a09a4a642f7c0d367598394411dbdd4a6d8cd09fielding const char *filter,
2d2eda71267231c2526be701fe655db125852c1ffielding int timeout)
2d2eda71267231c2526be701fe655db125852c1ffielding{
2d2eda71267231c2526be701fe655db125852c1ffielding struct tevent_req *req, *subreq;
2d2eda71267231c2526be701fe655db125852c1ffielding struct sdap_get_groups_state *state;
2d2eda71267231c2526be701fe655db125852c1ffielding
req = tevent_req_create(memctx, &state, struct sdap_get_groups_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->groups = NULL;
state->count = 0;
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,
state->filter, state->attrs,
state->opts->group_map, SDAP_OPTS_GROUP,
timeout);
if (!subreq) {
talloc_zfree(req);
return NULL;
}
tevent_req_set_callback(subreq, sdap_get_groups_process, req);
return req;
}
static struct tevent_req *sdap_nested_group_process_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev,
struct sss_domain_info *domain,
struct sysdb_ctx *sysdb, struct sysdb_attrs *group,
hash_table_t *users, hash_table_t *groups,
struct sdap_options *opts, struct sdap_handle *sh,
uint32_t nesting);
static void sdap_nested_done(struct tevent_req *req);
static errno_t sdap_nested_group_process_recv(struct tevent_req *req);
static void sdap_get_groups_process(struct tevent_req *subreq)
{
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
struct sdap_get_groups_state *state =
tevent_req_data(req, struct sdap_get_groups_state);
int ret;
int i;
bool enumeration = false;
ret = sdap_get_generic_recv(subreq, state,
&state->count, &state->groups);
talloc_zfree(subreq);
if (ret) {
tevent_req_error(req, ret);
return;
}
DEBUG(6, ("Search for groups, returned %d results.\n", state->count));
switch(state->count) {
case 0:
tevent_req_error(req, ENOENT);
return;
case 1:
/* Single group search */
if ((state->opts->schema_type == SDAP_SCHEMA_RFC2307) ||
(dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) == 0)) {
/* Either this is RFC2307 or we have disabled nested group
* support for RFC2307bis. Either way, we'll process the
* groups in single-level, multiple-request mode.
*/
break;
}
/* Prepare hashes for nested user processing */
ret = sss_hash_create(state, 32, &state->user_hash);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
ret = sss_hash_create(state, 32, &state->group_hash);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
subreq = sdap_nested_group_process_send(state,
state->ev,
state->dom,
state->sysdb,
state->groups[0],
state->user_hash,
state->group_hash,
state->opts,
state->sh,
0);
if (!subreq) {
tevent_req_error(req, EIO);
return;
}
tevent_req_set_callback(subreq, sdap_nested_done, req);
return;
default:
/* Enumeration */
enumeration = true;
break;
}
state->check_count = state->count;
ret = sysdb_transaction_start(state->sysdb);
if (ret != EOK) {
DEBUG(0, ("Failed to start transaction\n"));
tevent_req_error(req, ret);
return;
}
if (enumeration && (state->opts->schema_type != SDAP_SCHEMA_RFC2307) &&
(dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0)) {
DEBUG(9, ("Saving groups without members first "
"to allow unrolling of nested groups.\n"));
ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
state->groups, state->count, false, NULL);
if (ret) {
DEBUG(2, ("Failed to store groups.\n"));
tevent_req_error(req, ret);
return;
}
}
for (i = 0; i < state->count; i++) {
subreq = sdap_process_group_send(state, state->ev, state->dom,
state->sysdb, state->opts,
state->sh, state->groups[i],
enumeration);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
}
tevent_req_set_callback(subreq, sdap_get_groups_done, req);
}
}
static void sdap_get_groups_done(struct tevent_req *subreq)
{
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
struct sdap_get_groups_state *state =
tevent_req_data(req, struct sdap_get_groups_state);
int ret;
errno_t sysret;
ret = sdap_process_group_recv(subreq);
talloc_zfree(subreq);
if (ret) {
sysret = sysdb_transaction_cancel(state->sysdb);
if (sysret != EOK) {
DEBUG(0, ("Could not cancel sysdb transaction\n"));
}
tevent_req_error(req, ret);
return;
}
state->check_count--;
DEBUG(9, ("Groups remaining: %d\n", state->check_count));
if (state->check_count == 0) {
DEBUG(9, ("All groups processed\n"));
ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
state->groups, state->count, true,
&state->higher_usn);
if (ret) {
DEBUG(2, ("Failed to store groups.\n"));
tevent_req_error(req, ret);
return;
}
DEBUG(9, ("Saving %d Groups - Done\n", state->count));
sysret = sysdb_transaction_commit(state->sysdb);
if (sysret != EOK) {
DEBUG(0, ("Couldn't commit transaction\n"));
tevent_req_error(req, sysret);
} else {
tevent_req_done(req);
}
}
}
int sdap_get_groups_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx, char **usn_value)
{
struct sdap_get_groups_state *state = tevent_req_data(req,
struct sdap_get_groups_state);
TEVENT_REQ_RETURN_ON_ERROR(req);
if (usn_value) {
*usn_value = talloc_steal(mem_ctx, state->higher_usn);
}
return EOK;
}
static errno_t sdap_nested_group_populate_users(struct sysdb_ctx *sysdb,
struct sss_domain_info *dom,
struct sdap_options *opts,
struct sysdb_attrs **users,
int num_users);
static void sdap_nested_done(struct tevent_req *subreq)
{
errno_t ret;
int hret;
unsigned long i;
unsigned long count;
hash_value_t *values;
struct sysdb_attrs **users = NULL;
struct sysdb_attrs **groups = NULL;
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct sdap_get_groups_state *state = tevent_req_data(req,
struct sdap_get_groups_state);
ret = sdap_nested_group_process_recv(subreq);
talloc_zfree(subreq);
if (ret != EOK) {
DEBUG(1, ("Nested group processing failed: [%d][%s]\n",
ret, strerror(ret)));
tevent_req_error(req, ret);
return;
}
hret = hash_values(state->user_hash, &count, &values);
if (hret != HASH_SUCCESS) {
tevent_req_error(req, EIO);
}
if (count) {
users = talloc_array(state, struct sysdb_attrs *, count);
if (!users) {
talloc_free(values);
tevent_req_error(req, ENOMEM);
return;
}
for (i = 0; i < count; i++) {
users[i] = talloc_get_type(values[i].ptr, struct sysdb_attrs);
}
talloc_zfree(values);
}
/* Save all of the users first so that they are in
* place for the groups to add them.
*/
ret = sdap_nested_group_populate_users(state->sysdb, state->dom,
state->opts, users, count);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
/* Users are all saved. Now save groups */
hret = hash_values(state->group_hash, &count, &values);
if (hret != HASH_SUCCESS) {
tevent_req_error(req, EIO);
return;
}
groups = talloc_array(state, struct sysdb_attrs *, count);
if (!groups) {
talloc_free(values);
tevent_req_error(req, ENOMEM);
return;
}
for (i = 0; i < count; i++) {
groups[i] = talloc_get_type(values[i].ptr, struct sysdb_attrs);
}
talloc_zfree(values);
ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
groups, count, false, &state->higher_usn);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
/* Processing complete */
tevent_req_done(req);
}
static errno_t sdap_nested_group_populate_users(struct sysdb_ctx *sysdb,
struct sss_domain_info *dom,
struct sdap_options *opts,
struct sysdb_attrs **users,
int num_users)
{
int i;
errno_t ret, sret;
struct ldb_message_element *el;
const char *username;
char *clean_orig_dn;
const char *original_dn;
TALLOC_CTX *tmp_ctx;
struct ldb_message **msgs;
char *filter;
const char *sysdb_name;
struct sysdb_attrs *attrs;
static const char *search_attrs[] = { SYSDB_NAME, NULL };
size_t count;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
if (num_users == 0) {
/* Nothing to do if there are no users */
return EOK;
}
ret = sysdb_transaction_start(sysdb);
if (ret) {
DEBUG(1, ("Failed to start transaction!\n"));
goto done;
}
for (i = 0; i < num_users; i++) {
ret = sysdb_attrs_primary_name(sysdb, users[i],
opts->user_map[SDAP_AT_USER_NAME].name,
&username);
if (ret != EOK) {
DEBUG(1, ("User entry %d has no name attribute\n", i));
goto done;
}
ret = sysdb_attrs_get_el(users[i], SYSDB_ORIG_DN, &el);
if (el->num_values == 0) {
ret = EINVAL;
}
if (ret != EOK) {
DEBUG(1, ("User entry %s has no originalDN attribute\n", i));
goto done;
}
original_dn = (const char *) el->values[0].data;
ret = sss_filter_sanitize(tmp_ctx, original_dn,
&clean_orig_dn);
if (ret != EOK) {
DEBUG(1, ("Cannot sanitize originalDN\n", i));
goto done;
}
/* Check for the specified origDN in the sysdb */
filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
SYSDB_ORIG_DN,
clean_orig_dn);
if (!filter) {
ret = ENOMEM;
goto done;
}
ret = sysdb_search_users(tmp_ctx, sysdb, dom, filter,
search_attrs, &count, &msgs);
talloc_zfree(filter);
talloc_zfree(clean_orig_dn);
if (ret != EOK && ret != ENOENT) {
DEBUG(1, ("Error checking cache for user entry\n"));
goto done;
}
if (ret == EOK) {
/* The entry is cached but expired. Update the username
* if needed. */
if (count != 1) {
DEBUG(1, ("More than one entry with this origDN? Skipping\n"));
continue;
}
sysdb_name = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL);
if (strcmp(sysdb_name, username) == 0) {
/* Username is correct, continue */
continue;
}
attrs = sysdb_new_attrs(tmp_ctx);
if (!attrs) {
ret = ENOMEM;
goto done;
}
ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, username);
if (ret) goto done;
ret = sysdb_set_user_attr(tmp_ctx, sysdb,
dom, sysdb_name, attrs, SYSDB_MOD_REP);
if (ret != EOK) goto done;
}
/* If the entry does not exist add a fake user record */
ret = sysdb_add_fake_user(sysdb, dom, username, original_dn);
if (ret != EOK) {
DEBUG(1, ("Cannot store fake user entry, ignoring: [%d]: %s\n",
ret, strerror(ret)));
continue;
} else {
DEBUG(9, ("Added incomplete user %s!\n", username));
}
}
ret = sysdb_transaction_commit(sysdb);
if (ret) {
DEBUG(1, ("Failed to commit transaction!\n"));
goto done;
}
ret = EOK;
done:
talloc_zfree(tmp_ctx);
if (ret != EOK) {
sret = sysdb_transaction_cancel(sysdb);
if (sret != EOK) {
DEBUG(2, ("Could not cancel transaction\n"));
}
}
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, dom,
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, dom, 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, dom, 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->dom,
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;
size_t expired_users_num;
uint32_t expired_users_index;
char **expired_users;
size_t expired_groups_num;
uint32_t expired_groups_index;
char **expired_groups;
size_t missing_dns_num;
uint32_t missing_dns_index;
char **missing_dns;
struct sdap_deref_attrs **deref_result;
size_t num_results;
uint32_t result_index;
int deref_threshold;
};
struct sdap_nested_group_ctx {
struct tevent_context *ev;
struct sysdb_ctx *sysdb;
struct sss_domain_info *domain;
hash_table_t *users;
hash_table_t *groups;
struct sdap_options *opts;
struct sdap_handle *sh;
uint32_t nesting_level;
struct ldb_message_element *members;
uint32_t member_index;
char *member_dn;
struct sdap_deref_ctx *derefctx;
};
static errno_t sdap_nested_group_process_deref_step(struct tevent_req *req);
static errno_t sdap_nested_group_process_step(struct tevent_req *req);
static struct tevent_req *sdap_nested_group_process_send(
TALLOC_CTX *mem_ctx, struct tevent_context *ev,
struct sss_domain_info *domain,
struct sysdb_ctx *sysdb, struct sysdb_attrs *group,
hash_table_t *users, hash_table_t *groups,
struct sdap_options *opts, struct sdap_handle *sh,
uint32_t nesting)
{
errno_t ret;
int hret;
struct tevent_req *req;
struct sdap_nested_group_ctx *state;
const char *groupname;
hash_key_t key;
hash_value_t value;
gid_t gid;
req = tevent_req_create(mem_ctx, &state, struct sdap_nested_group_ctx);
if (!req) {
return NULL;
}
state->ev = ev;
state->sysdb = sysdb;
state->domain = domain;
state->users = users;
state->groups = groups;
state->opts = opts;
state->sh = sh;
state->nesting_level = nesting;
/* If this is too many levels deep, just return success */
if (nesting > dp_opt_get_int(opts->basic, SDAP_NESTING_LEVEL)) {
ret = EOK;
goto immediate;
}
/* Add the current group to the groups hash so we don't
* look it up more than once
*/
key.type = HASH_KEY_STRING;
ret = sysdb_attrs_primary_name(sysdb, group,
opts->group_map[SDAP_AT_GROUP_NAME].name,
&groupname);
if (ret != EOK) {
goto immediate;
}
key.str = talloc_strdup(state, groupname);
if (!key.str) {
ret = ENOMEM;
goto immediate;
}
if (hash_has_key(groups, &key)) {
/* This group has already been processed
* (or is in progress)
* Skip it and just return success
*/
ret = EOK;
goto immediate;
}
ret = sysdb_attrs_get_uint32_t(group,
opts->group_map[SDAP_AT_GROUP_GID].name,
&gid);
if (ret == ENOENT || (ret == EOK && gid == 0)) {
DEBUG(9, ("The group's gid was %s\n", ret == ENOENT ? "missing" : "zero"));
DEBUG(8, ("Marking group as non-posix and setting GID=0!\n"));
if (ret == ENOENT) {
ret = sysdb_attrs_add_uint32(group,
opts->group_map[SDAP_AT_GROUP_GID].name,
0);
if (ret != EOK) {
DEBUG(1, ("Failed to add a GID to non-posix group!\n"));
goto immediate;
}
}
ret = sysdb_attrs_add_bool(group, SYSDB_POSIX, false);
if (ret != EOK) {
DEBUG(2, ("Error: Failed to mark group as non-posix!\n"));
goto immediate;
}
} else if (ret) {
goto immediate;
}
value.type = HASH_VALUE_PTR;
value.ptr = talloc_steal(groups, group);
hret = hash_enter(groups, &key, &value);
if (hret != HASH_SUCCESS) {
ret = EIO;
goto immediate;
}
talloc_free(key.str);
/* Process group memberships */
/* TODO: future enhancement, check for memberuid as well
* See https://fedorahosted.org/sssd/ticket/445
*/
ret = sysdb_attrs_get_el(
group,
opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,
&state->members);
if (ret != EOK) {
if (ret == ENOENT) {
/* No members to process */
ret = EOK;
}
goto immediate;
}
state->member_index = 0;
if (sdap_has_deref_support(state->sh)) {
state->derefctx = talloc_zero(state, struct sdap_deref_ctx);
if (!state->derefctx) goto immediate;
ret = sysdb_attrs_get_string(group, SYSDB_ORIG_DN,
&state->derefctx->orig_dn);
if (ret != EOK) goto immediate;
ret = sdap_nested_group_process_deref_step(req);
if (ret != EAGAIN) goto immediate;
} else {
ret = sdap_nested_group_process_step(req);
if (ret != EAGAIN) goto immediate;
}
return req;
immediate:
if (ret == EOK) {
tevent_req_done(req);
} else {
tevent_req_error(req, ret);
}
tevent_req_post(req, ev);
return req;
}
static errno_t sdap_nested_group_check_hash(struct sdap_nested_group_ctx *);
static errno_t sdap_nested_group_check_cache(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
struct sdap_options *opts,
char *member_dn,
struct ldb_message ***_msgs,
enum sysdb_member_type *_mtype);
static void sdap_nested_group_process_ldap_user(struct tevent_req *subreq);
static void sdap_nested_group_process_user(struct tevent_req *subreq);
static errno_t sdap_nested_group_lookup_user(struct tevent_req *req,
tevent_req_fn fn);
static errno_t sdap_nested_group_lookup_group(struct tevent_req *req);
static errno_t sdap_nested_group_process_deref_call(struct tevent_req *req);
static errno_t sdap_nested_group_process_noderef(struct tevent_req *req);
static errno_t sdap_nested_group_process_deref_step(struct tevent_req *req)
{
errno_t ret;
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
size_t missing = 0;
struct ldb_message **msgs = NULL;
enum sysdb_member_type mtype;
struct sdap_deref_ctx *dctx = state->derefctx;
dctx->deref_threshold = dp_opt_get_int(state->opts->basic,
SDAP_DEREF_THRESHOLD);
dctx->expired_users = talloc_array(dctx, char *,
state->members->num_values + 1);
dctx->expired_groups = talloc_array(dctx, char *,
state->members->num_values + 1);
dctx->missing_dns = talloc_array(dctx, char *,
state->members->num_values + 1);
if (!dctx->expired_users ||
!dctx->expired_groups ||
!dctx->missing_dns) return ENOMEM;
while (true) {
if (state->member_index >= state->members->num_values) {
/* No more entries to check. Return success */
talloc_zfree(state->member_dn);
ret = EOK;
break;
}
/* Continue to loop through until all entries have been
* processed.
*/
ret = sdap_nested_group_check_hash(state);
if (ret == EOK) {
talloc_zfree(state->member_dn);
break; /* All remaining members in hash, check missing */
} else if (ret != ENOENT) {
goto done; /* Unexpected error */
}
ret = sdap_nested_group_check_cache(state, state->sysdb,
state->domain, state->opts,
state->member_dn,
&msgs, &mtype);
if (ret == EOK) {
/* The entry is cached and valid */
state->member_index++;
talloc_zfree(state->member_dn);
continue;
} else if (ret == EAGAIN) {
/* The entry is cached but needs refresh */
switch(mtype) {
case SYSDB_MEMBER_GROUP:
DEBUG(8, ("Cached LDAP group [%s] needs refresh\n",
state->member_dn));
missing++;
dctx->expired_groups[dctx->expired_groups_num] =
talloc_move(dctx, &state->member_dn);
dctx->expired_groups_num++;
state->member_index++;
continue;
case SYSDB_MEMBER_USER:
DEBUG(8, ("Cached LDAP user [%s] needs refresh\n",
state->member_dn));
missing++;
dctx->expired_users[dctx->expired_users_num] =
talloc_move(dctx, &state->member_dn);
dctx->expired_users_num++;
state->member_index++;
continue;
default:
DEBUG(2, ("Unknown member value\n"));
ret = EINVAL;
goto done;
}
} else if (ret == ENOENT) {
/* The entry is missing. It is unclear whether it
* is a user or a group so we'll need to try looking
* it up */
missing++;
dctx->missing_dns[dctx->missing_dns_num] =
talloc_move(dctx, &state->member_dn);
dctx->missing_dns_num++;
state->member_index++;
continue;
}
/* Unexpected error, skip this entry */
state->member_index++;
continue;
} /* while (true) */
dctx->expired_users[dctx->expired_users_num] = NULL;
dctx->expired_groups[dctx->expired_groups_num] = NULL;
dctx->missing_dns[dctx->missing_dns_num] = NULL;
if (missing == 0) {
ret = EOK;
goto done;
}
if (missing > dctx->deref_threshold) {
DEBUG(6, ("Missing data past threshold, doing a full deref\n"));
ret = sdap_nested_group_process_deref_call(req);
} else {
DEBUG(6, ("Falling back to individual lookups\n"));
ret = sdap_nested_group_process_noderef(req);
}
if (ret != EOK && ret != EAGAIN) goto done;
return EAGAIN;
done:
talloc_zfree(state->member_dn);
return ret;
}
static errno_t sdap_nested_group_process_step(struct tevent_req *req)
{
errno_t ret;
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
struct ldb_message **msgs = NULL;
enum sysdb_member_type mtype;
while (true) {
/* Continue to loop through until all entries have been
* processed.
*/
ret = sdap_nested_group_check_hash(state);
if (ret == EOK) {
talloc_zfree(state->member_dn);
return EOK; /* All members in hash */
} else if (ret != ENOENT) {
goto error; /* Unexpected error */
}
ret = sdap_nested_group_check_cache(state, state->sysdb,
state->domain, state->opts,
state->member_dn,
&msgs, &mtype);
if (ret == EOK) {
/* The entry is cached and valid */
state->member_index++;
talloc_zfree(state->member_dn);
continue;
} else if (ret == EAGAIN) {
/* The entry is cached but needs refresh */
switch(mtype) {
case SYSDB_MEMBER_GROUP:
DEBUG(6, ("Refreshing cached group from LDAP\n"));
ret = sdap_nested_group_lookup_group(req);
if (ret != EOK) goto error;
break;
case SYSDB_MEMBER_USER:
DEBUG(6, ("Refreshing cached user from LDAP\n"));
ret = sdap_nested_group_lookup_user(
req, sdap_nested_group_process_user);
if (ret != EOK) goto error;
break;
default:
DEBUG(2, ("Unknown member value\n"));
ret = EINVAL;
goto error;
}
return EAGAIN;
} else if (ret == ENOENT) {
/* It wasn't found in the cache either
* We'll have to do a blind lookup in LDAP
*/
/* Try users first */
ret = sdap_nested_group_lookup_user(
req, sdap_nested_group_process_ldap_user);
if (ret != EOK) {
goto error;
}
return EAGAIN;
}
/* Unexpected error, skip this entry */
state->member_index++;
talloc_zfree(state->member_dn);
continue;
} /* while (true) */
error:
talloc_zfree(state->member_dn);
return ret;
}
static errno_t
sdap_nested_group_check_hash(struct sdap_nested_group_ctx *state)
{
hash_key_t key;
bool has_key = false;
uint8_t *data;
do {
if (state->member_index >= state->members->num_values) {
/* No more entries to check. Return success */
return EOK;
}
data = state->members->values[state->member_index].data;
state->member_dn = talloc_strdup(state, (const char *)data);
if (!state->member_dn) {
return ENOMEM;
}
/* Check the user hash
* If it's there, we can save ourselves a trip to the
* sysdb and possibly LDAP as well
*/
key.type = HASH_KEY_STRING;
key.str = state->member_dn;
has_key = hash_has_key(state->users, &key);
if (has_key) {
talloc_zfree(state->member_dn);
state->member_index++;
continue;
}
} while (has_key);
return ENOENT;
}
static errno_t
sdap_nested_group_check_cache(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
struct sdap_options *opts,
char *dn,
struct ldb_message ***_msgs,
enum sysdb_member_type *_mtype)
{
TALLOC_CTX *tmp_ctx;
errno_t ret;
struct ldb_message **msgs = NULL;
char *member_dn;
uint64_t expiration;
uint64_t create_time;
uid_t user_uid;
time_t now = time(NULL);
static const char *attrs[] = { SYSDB_CACHE_EXPIRE, SYSDB_UIDNUM,
SYSDB_CREATE_TIME, SYSDB_NAME,
NULL };
char *filter;
enum sysdb_member_type mtype;
size_t count;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
ret = sss_filter_sanitize(tmp_ctx, dn, &member_dn);
if (ret != EOK) {
goto fail;
}
/* Check for the specified origDN in the sysdb */
filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
SYSDB_ORIG_DN,
member_dn);
if (!filter) {
ret = ENOMEM;
goto fail;
}
/* Try users first */
ret = sysdb_search_users(tmp_ctx, sysdb, domain, filter,
attrs, &count, &msgs);
if (ret != EOK && ret != ENOENT) {
ret = EIO;
goto fail;
} else if (ret == EOK && count > 0) {
/* We found a user with this origDN in the sysdb. Check if it is valid
*/
mtype = SYSDB_MEMBER_USER;
/* Check whether the entry is valid */
if (count != 1) {
DEBUG(1, ("More than one entry with this origDN? Skipping\n"));
ret = EIO;
goto fail;
}
user_uid = ldb_msg_find_attr_as_uint64(msgs[0], SYSDB_UIDNUM, 0);
if (!user_uid) {
/* Refresh the fake user if he was created before cache_timeout */
create_time = ldb_msg_find_attr_as_uint64(msgs[0],
SYSDB_CREATE_TIME,
0);
expiration = create_time +
dp_opt_get_int(opts->basic,
SDAP_ENTRY_CACHE_TIMEOUT);
} else {
/* Regular user, check if we need a refresh */
expiration = ldb_msg_find_attr_as_uint64(msgs[0],
SYSDB_CACHE_EXPIRE,
0);
}
if (expiration && expiration > now) {
DEBUG(6, ("Cached values are still valid. Skipping\n"));
ret = EOK;
goto done;
}
/* Refresh the user from LDAP */
ret = EAGAIN;
goto done;
}
/* It wasn't a user. Check whether it's a group */
if (ret == EOK) talloc_zfree(msgs);
ret = sysdb_search_groups(tmp_ctx, sysdb, domain,
filter, attrs, &count, &msgs);
if (ret != EOK && ret != ENOENT) {
ret = EIO;
goto fail;
} else if (ret == EOK && count > 0) {
/* We found a group with this origDN in the sysdb */
mtype = SYSDB_MEMBER_GROUP;
/* Check whether the entry is valid */
if (count != 1) {
DEBUG(1, ("More than one entry with this origDN? Skipping\n"));
ret = EIO;
goto fail;
}
expiration = ldb_msg_find_attr_as_uint64(msgs[0],
SYSDB_CACHE_EXPIRE,
0);
if (expiration && expiration > now) {
DEBUG(6, ("Cached values are still valid.\n"));
ret = EOK;
goto done;
}
/* Refresh the group from LDAP */
ret = EAGAIN;
goto done;
}
/* It wasn't found in the groups either */
ret = ENOENT;
done:
if (ret == EOK || ret == EAGAIN) {
*_msgs = talloc_steal(mem_ctx, msgs);
*_mtype = mtype;
}
talloc_zfree(tmp_ctx);
return ret;
fail:
talloc_zfree(tmp_ctx);
return ret;
}
static void sdap_nested_group_process_deref(struct tevent_req *subreq);
static errno_t
sdap_nested_group_process_deref_call(struct tevent_req *req)
{
struct tevent_req *subreq;
struct sdap_attr_map_info *maps;
const char **sdap_attrs;
int ret;
int timeout;
const int num_maps = 2;
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
maps = talloc_array(state, struct sdap_attr_map_info, num_maps+1);
if (!maps) return ENOMEM;
maps[0].map = state->opts->user_map;
maps[0].num_attrs = SDAP_OPTS_USER;
maps[1].map = state->opts->group_map;
maps[1].num_attrs = SDAP_OPTS_GROUP;
maps[2].map = NULL;
/* Pull down the whole group map, but only pull down username
* and originalDN for users. */
ret = build_attrs_from_map(state, state->opts->group_map,
SDAP_OPTS_GROUP, &sdap_attrs);
if (ret != EOK) goto fail;
sdap_attrs = talloc_realloc(NULL, sdap_attrs, const char *,
SDAP_OPTS_GROUP + 2);
if (!sdap_attrs) {
ret = ENOMEM;
goto fail;
}
sdap_attrs[SDAP_OPTS_GROUP] = \
state->opts->user_map[SDAP_AT_USER_NAME].name;
sdap_attrs[SDAP_OPTS_GROUP + 1] = NULL;
timeout = dp_opt_get_int(state->opts->basic, SDAP_ENTRY_CACHE_TIMEOUT);
subreq = sdap_deref_search_send(state, state->ev, state->opts,
state->sh, state->derefctx->orig_dn,
state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,
sdap_attrs, num_maps, maps, timeout);
if (!subreq) {
ret = EIO;
goto fail;
}
talloc_steal(subreq, sdap_attrs);
talloc_steal(subreq, maps);
tevent_req_set_callback(subreq, sdap_nested_group_process_deref, req);
return EOK;
fail:
talloc_free(sdap_attrs);
talloc_free(maps);
return ret;
}
static errno_t sdap_nested_group_process_noderef(struct tevent_req *req)
{
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
struct sdap_deref_ctx *dctx = state->derefctx;
errno_t ret;
if (dctx->expired_users_index < dctx->expired_users_num) {
state->member_dn = dctx->expired_users[dctx->expired_users_index];
DEBUG(8, ("Refreshing expired user [%s]\n", state->member_dn));
ret = sdap_nested_group_lookup_user(
req, sdap_nested_group_process_user);
if (ret != EOK) goto done;
return EAGAIN;
}
if (dctx->expired_groups_index < dctx->expired_groups_num) {
state->member_dn = dctx->expired_groups[dctx->expired_groups_index];
DEBUG(8, ("Refreshing expired group [%s]\n", state->member_dn));
ret = sdap_nested_group_lookup_group(req);
if (ret != EOK) goto done;
return EAGAIN;
}
if (dctx->missing_dns_index < dctx->missing_dns_num) {
state->member_dn = dctx->missing_dns[dctx->missing_dns_index];
DEBUG(8, ("Looking up missing DN [%s]\n", state->member_dn));
/* Try users first for generic missing DNs */
ret = sdap_nested_group_lookup_user(
req, sdap_nested_group_process_ldap_user);
if (ret != EOK) goto done;
return EAGAIN;
}
ret = EOK;
done:
return ret;
}
static errno_t sdap_nested_group_lookup_user(struct tevent_req *req,
tevent_req_fn fn)
{
const char **sdap_attrs;
char *filter;
struct tevent_req *subreq;
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
/* Only pull down username and originalDN */
sdap_attrs = talloc_array(state, const char *, 3);
if (!sdap_attrs) return ENOMEM;
sdap_attrs[0] = "objectClass";
sdap_attrs[1] = state->opts->user_map[SDAP_AT_USER_NAME].name;
sdap_attrs[2] = NULL;
filter = talloc_asprintf(
sdap_attrs, "(objectclass=%s)",
state->opts->user_map[SDAP_OC_USER].name);
if (!filter) {
talloc_free(sdap_attrs);
return ENOMEM;
}
subreq = sdap_get_generic_send(state, state->ev, state->opts,
state->sh, state->member_dn,
LDAP_SCOPE_BASE,
filter, sdap_attrs,
state->opts->user_map,
SDAP_OPTS_USER,
dp_opt_get_int(state->opts->basic,
SDAP_SEARCH_TIMEOUT));
if (!subreq) {
talloc_free(sdap_attrs);
return EIO;
}
talloc_steal(subreq, sdap_attrs);
tevent_req_set_callback(subreq, fn, req);
return EOK;
}
static void sdap_nested_group_process_group(struct tevent_req *subreq);
static errno_t sdap_nested_group_lookup_group(struct tevent_req *req)
{
errno_t ret;
const char **sdap_attrs;
char *filter;
struct tevent_req *subreq;
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
ret = build_attrs_from_map(state, state->opts->group_map,
SDAP_OPTS_GROUP, &sdap_attrs);
if (ret != EOK) {
return ret;
}
filter = talloc_asprintf(
sdap_attrs, "(&(objectclass=%s)(%s=*))",
state->opts->group_map[SDAP_OC_GROUP].name,
state->opts->group_map[SDAP_AT_GROUP_NAME].name);
if (!filter) {
talloc_free(sdap_attrs);
return ENOMEM;
}
subreq = sdap_get_generic_send(state, state->ev, state->opts,
state->sh, state->member_dn,
LDAP_SCOPE_BASE,
filter, sdap_attrs,
state->opts->group_map,
SDAP_OPTS_GROUP,
dp_opt_get_int(state->opts->basic,
SDAP_SEARCH_TIMEOUT));
if (!subreq) {
talloc_free(sdap_attrs);
return EIO;
}
talloc_steal(subreq, sdap_attrs);
tevent_req_set_callback(subreq, sdap_nested_group_process_group, req);
return EOK;
}
static void sdap_nested_group_process_user(struct tevent_req *subreq)
{
errno_t ret;
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
TALLOC_CTX *tmp_ctx;
size_t count;
struct sysdb_attrs **replies;
int hret;
hash_key_t key;
hash_value_t value;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
tevent_req_error(req, ENOMEM);
return;
}
ret = sdap_get_generic_recv(subreq, tmp_ctx, &count, &replies);
talloc_zfree(subreq);
if (ret != EOK && ret != ENOENT) {
tevent_req_error(req, ret);
goto done;
} else if (ret == ENOENT || count == 0) {
/* Nothing to do if the user doesn't exist */
goto skip;
}
if (count != 1) {
/* There should only ever be one reply for a
* BASE search. If otherwise, it's a serious
* error.
*/
DEBUG(1,("Received multiple replies for a BASE search!\n"));
tevent_req_error(req, EIO);
goto done;
}
/* Save the user attributes to the user hash so we can store
* them all at once later.
*/
key.type = HASH_KEY_STRING;
key.str = state->member_dn;
value.type = HASH_VALUE_PTR;
value.ptr = replies[0];
hret = hash_enter(state->users, &key, &value);
if (hret != HASH_SUCCESS) {
tevent_req_error(req, EIO);
goto done;
}
talloc_steal(state->users, replies[0]);
skip:
if (state->derefctx) {
state->derefctx->expired_users_index++;
ret = sdap_nested_group_process_noderef(req);
} else {
state->member_index++;
talloc_zfree(state->member_dn);
ret = sdap_nested_group_process_step(req);
}
if (ret == EOK) {
/* EOK means it's complete */
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
/* EAGAIN means that we should re-enter
* the mainloop
*/
done:
talloc_free(tmp_ctx);
}
static void sdap_group_internal_nesting_done(struct tevent_req *subreq);
static void sdap_nested_group_process_group(struct tevent_req *subreq)
{
errno_t ret;
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
TALLOC_CTX *tmp_ctx;
size_t count;
struct sysdb_attrs **replies;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
tevent_req_error(req, ENOMEM);
return;
}
ret = sdap_get_generic_recv(subreq, tmp_ctx, &count, &replies);
talloc_zfree(subreq);
if (ret != EOK && ret != ENOENT) {
tevent_req_error(req, ret);
goto done;
} else if (ret == ENOENT || count == 0) {
/* Nothing to do if the group doesn't exist */
goto skip;
}
if (count != 1) {
/* There should only ever be one reply for a
* BASE search. If otherwise, it's a serious
* error.
*/
DEBUG(1,("Received multiple replies for a BASE search!\n"));
tevent_req_error(req, EIO);
goto done;
}
/* Recurse down into the member group */
subreq = sdap_nested_group_process_send(state, state->ev, state->domain,
state->sysdb, replies[0],
state->users, state->groups,
state->opts, state->sh,
state->nesting_level + 1);
if (!subreq) {
tevent_req_error(req, EIO);
goto done;
}
tevent_req_set_callback(subreq, sdap_group_internal_nesting_done, req);
talloc_free(tmp_ctx);
return;
skip:
if (state->derefctx) {
state->derefctx->expired_groups_index++;
ret = sdap_nested_group_process_noderef(req);
} else {
state->member_index++;
talloc_zfree(state->member_dn);
ret = sdap_nested_group_process_step(req);
}
if (ret == EOK) {
/* EOK means it's complete */
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
/* EAGAIN means that we should re-enter
* the mainloop
*/
done:
talloc_free(tmp_ctx);
}
static void sdap_group_internal_nesting_done(struct tevent_req *subreq)
{
errno_t ret;
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
ret = sdap_nested_group_process_recv(subreq);
talloc_zfree(subreq);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
if (state->derefctx) {
if (state->derefctx->expired_groups_index <
state->derefctx->expired_groups_num) {
state->derefctx->expired_groups_index++;
} else {
state->derefctx->missing_dns_index++;
}
state->derefctx->expired_users_index++;
ret = sdap_nested_group_process_noderef(req);
} else {
state->member_index++;
talloc_zfree(state->member_dn);
ret = sdap_nested_group_process_step(req);
}
if (ret == EOK) {
/* EOK means it's complete */
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
/* EAGAIN means that we should re-enter
* the mainloop
*/
}
static void sdap_nested_group_process_ldap_user(struct tevent_req *subreq)
{
errno_t ret;
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
TALLOC_CTX *tmp_ctx;
size_t count;
struct sysdb_attrs **replies;
int hret;
hash_key_t key;
hash_value_t value;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
tevent_req_error(req, ENOMEM);
return;
}
ret = sdap_get_generic_recv(subreq, tmp_ctx, &count, &replies);
talloc_zfree(subreq);
if (ret != EOK && ret != ENOENT) {
tevent_req_error(req, ret);
goto done;
} else if (ret == ENOENT || count == 0) {
/* No user found. Assume it's a group */
ret = sdap_nested_group_lookup_group(req);
if (ret != EOK) {
tevent_req_error(req, ret);
}
goto done;
}
if (count != 1) {
/* There should only ever be one reply for a
* BASE search. If otherwise, it's a serious
* error.
*/
DEBUG(1,("Received multiple replies for a BASE search!\n"));
tevent_req_error(req, EIO);
goto done;
}
/* Save the user attributes to the user hash so we can store
* them all at once later.
*/
key.type = HASH_KEY_STRING;
key.str = state->member_dn;
value.type = HASH_VALUE_PTR;
value.ptr = replies[0];
hret = hash_enter(state->users, &key, &value);
if (hret != HASH_SUCCESS) {
tevent_req_error(req, EIO);
goto done;
}
talloc_steal(state->users, replies[0]);
/* Move on to the next member */
if (state->derefctx) {
state->derefctx->missing_dns_index++;
ret = sdap_nested_group_process_noderef(req);
} else {
state->member_index++;
talloc_zfree(state->member_dn);
ret = sdap_nested_group_process_step(req);
}
if (ret == EOK) {
/* EOK means it's complete */
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
/* EAGAIN means that we should re-enter
* the mainloop
*/
done:
talloc_free(tmp_ctx);
}
static errno_t
sdap_nested_group_process_deref_result(struct tevent_req *req);
static void sdap_nested_group_process_deref(struct tevent_req *subreq)
{
errno_t ret;
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
ret = sdap_deref_search_recv(subreq, state->derefctx,
&state->derefctx->num_results,
&state->derefctx->deref_result);
talloc_zfree(subreq);
if (ret != EOK && ret != ENOENT) {
tevent_req_error(req, ret);
return;
} else if (ret == ENOENT || state->derefctx->deref_result == 0) {
/* Nothing could be dereferenced. Done. */
tevent_req_done(req);
return;
}
state->derefctx->result_index = 0;
DEBUG(8, ("Received %d dereference results, about to process them\n",
state->derefctx->num_results));
ret = sdap_nested_group_process_deref_result(req);
if (ret == EOK) {
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
/* EAGAIN means a recursive search is in progress */
}
static void
sdap_nested_group_process_deref_recurse_done(struct tevent_req *subreq);
static errno_t
sdap_nested_group_process_deref_result(struct tevent_req *req)
{
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
struct tevent_req *subreq;
hash_key_t key;
hash_value_t value;
int hret;
const char *orig_dn;
errno_t ret;
struct sdap_deref_ctx *dctx = state->derefctx;
const char *tmp_name;
while (dctx->result_index < dctx->num_results) {
if (dctx->deref_result[dctx->result_index]->map == \
state->opts->user_map) {
/* Add to appropriate hash table */
ret = sysdb_attrs_get_string(
dctx->deref_result[dctx->result_index]->attrs,
SYSDB_ORIG_DN, &orig_dn);
if (ret != EOK) {
DEBUG(2, ("The entry has no originalDN\n"));
return ret;
}
DEBUG(9, ("Found member user [%s]\n", orig_dn));
key.type = HASH_KEY_STRING;
key.str = talloc_strdup(state, orig_dn);
value.type = HASH_VALUE_PTR;
value.ptr = dctx->deref_result[dctx->result_index]->attrs;
hret = hash_enter(state->users, &key, &value);
if (hret != HASH_SUCCESS) return EIO;
talloc_steal(state->users,
dctx->deref_result[dctx->result_index]->attrs);
dctx->result_index++;
} else if (dctx->deref_result[dctx->result_index]->map == \
state->opts->group_map) {
ret = sysdb_attrs_get_string(dctx->deref_result[dctx->result_index]->attrs,
state->opts->group_map[SDAP_AT_GROUP_NAME].name,
&tmp_name);
if (ret == ENOENT) {
DEBUG(7, ("Dereferenced a group without name, skipping ...\n"));
} else if (ret) {
return EIO;
}
DEBUG(6, ("Recursing down a nested group\n"));
subreq = sdap_nested_group_process_send(state, state->ev,
state->domain, state->sysdb,
dctx->deref_result[dctx->result_index]->attrs,
state->users, state->groups,
state->opts, state->sh,
state->nesting_level + 1);
if (!subreq) return EIO;
tevent_req_set_callback(subreq,
sdap_nested_group_process_deref_recurse_done,
req);
return EAGAIN;
} else {
/* This should never happen, but if it does,
* do not loop forever */
DEBUG(2, ("Entry does not match any known map, skipping\n"));
dctx->result_index++;
continue;
}
}
/* All deref results processed */
DEBUG(8, ("All dereference results processed\n"));
return EOK;
}
static void
sdap_nested_group_process_deref_recurse_done(struct tevent_req *subreq)
{
errno_t ret;
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
struct sdap_nested_group_ctx *state =
tevent_req_data(req, struct sdap_nested_group_ctx);
ret = sdap_nested_group_process_recv(subreq);
talloc_zfree(subreq);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
state->derefctx->result_index++;
ret = sdap_nested_group_process_deref_result(req);
if (ret == EOK) {
tevent_req_done(req);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
}
/* EAGAIN means a recursive search is in progress */
}
static errno_t sdap_nested_group_process_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, state->dom,
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->dom, 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, state->dom,
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, state->dom, 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;
}