sdap_async_initgroups.c revision 2ce00e0d3896bb42db169d1e79553a81ca837a22
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/*
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher SSSD
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher Async LDAP Helper routines - initgroups operation
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher Copyright (C) 2010, Ralf Haferkamp <rhafer@suse.de>, Novell Inc.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher Copyright (C) Jan Zeleny <jzeleny@redhat.com> - 2011
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher This program is free software; you can redistribute it and/or modify
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher it under the terms of the GNU General Public License as published by
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher the Free Software Foundation; either version 3 of the License, or
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher (at your option) any later version.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher This program is distributed in the hope that it will be useful,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher but WITHOUT ANY WARRANTY; without even the implied warranty of
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher GNU General Public License for more details.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher You should have received a copy of the GNU General Public License
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher along with this program. If not, see <http://www.gnu.org/licenses/>.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher*/
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "util/util.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "db/sysdb.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "providers/ldap/sdap_async_private.h"
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce#include "providers/ldap/ldap_common.h"
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce#include "providers/ldap/sdap_idmap.h"
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* ==Save-fake-group-list=====================================*/
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_options *opts,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char **groupnames,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sysdb_attrs **ldap_groups,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int ldap_groups_count)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher TALLOC_CTX *tmp_ctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct ldb_message *msg;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int i, mi, ai;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *name;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *original_dn;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char **missing;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher gid_t gid;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher errno_t sret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool in_transaction = false;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce bool posix;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce time_t now;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char *sid_str;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool use_id_mapping = dp_opt_get_bool(opts->basic, SDAP_ID_MAPPING);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* There are no groups in LDAP but we should add user to groups ?? */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ldap_groups_count == 0) return EOK;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tmp_ctx = talloc_new(NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!tmp_ctx) return ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher missing = talloc_array(tmp_ctx, char *, ldap_groups_count+1);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!missing) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher mi = 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (i=0; groupnames[i]; i++) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_search_group_by_name(tmp_ctx, sysdb, groupnames[i], NULL, &msg);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret == EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher continue;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher } else if (ret == ENOENT) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(7, ("Group #%d [%s] is not cached, need to add a fake entry\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i, groupnames[i]));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher missing[mi] = groupnames[i];
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher mi++;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher continue;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher } else if (ret != ENOENT) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("search for group failed [%d]: %s\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret, strerror(ret)));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce missing[mi] = NULL;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* All groups are cached, nothing to do */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (mi == 0) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_transaction_start(sysdb);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CRIT_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ("Cannot start sysdb transaction [%d]: %s\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret, strerror(ret)));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher in_transaction = true;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher now = time(NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (i=0; missing[i]; i++) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* The group is not in sysdb, need to add a fake entry */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (ai=0; ai < ldap_groups_count; ai++) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_attrs_primary_name(sysdb, ldap_groups[ai],
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher opts->group_map[SDAP_AT_GROUP_NAME].name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher &name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("The group has no name attribute\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (strcmp(name, missing[i]) == 0) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher posix = true;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (use_id_mapping) {
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce DEBUG(SSSDBG_TRACE_LIBS,
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek ("Mapping group [%s] objectSID to unix ID\n", name));
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek ret = sdap_attrs_get_sid_str(
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek tmp_ctx, opts->idmap_ctx, ldap_groups[ai],
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher opts->group_map[SDAP_AT_GROUP_OBJECTSID].sys_name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher &sid_str);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) goto done;
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce DEBUG(SSSDBG_TRACE_INTERNAL,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ("Group [%s] has objectSID [%s]\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher name, sid_str));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Convert the SID into a UNIX group ID */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, sid_str,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher &gid);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret == EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_TRACE_INTERNAL,
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce ("Group [%s] has mapped gid [%lu]\n",
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce name, (unsigned long)gid));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher } else {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher posix = false;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher gid = 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_TRACE_INTERNAL,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ("Group [%s] cannot be mapped. "
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "Treating as a non-POSIX group\n",
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce name));
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek }
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek } else {
21d485184df986e1a123f70c689517386e51a5ceMichal Zidek ret = sysdb_attrs_get_uint32_t(ldap_groups[ai],
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher SYSDB_GIDNUM,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher &gid);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret == ENOENT || (ret == EOK && gid == 0)) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(9, ("The group %s gid was %s\n",
e0404de84c31d2387bb244d018a5cac8d01f8b19Simo Sorce name, ret == ENOENT ? "missing" : "zero"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(8, ("Marking group %s as non-posix and setting GID=0!\n", name));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher gid = 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher posix = false;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher } else if (ret) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("The GID attribute is malformed\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_attrs_get_string(ldap_groups[ai],
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher SYSDB_ORIG_DN,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher &original_dn);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(5, ("The group has no name original DN\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher original_dn = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(8, ("Adding fake group %s to sysdb\n", name));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_add_incomplete_group(sysdb, name, gid, original_dn,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher posix, now);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher break;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ai == ldap_groups_count) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(2, ("Group %s not present in LDAP\n", missing[i]));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = EINVAL;
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek goto done;
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek }
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek }
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek ret = sysdb_transaction_commit(sysdb);
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek if (ret != EOK) {
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, ("sysdb_transaction_commit failed.\n"));
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek goto done;
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher in_transaction = false;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherdone:
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (in_transaction) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher sret = sysdb_transaction_cancel(sysdb);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (sret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to cancel transaction\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_free(tmp_ctx);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherint sdap_initgr_common_store(struct sysdb_ctx *sysdb,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_options *opts,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher enum sysdb_member_type type,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char **sysdb_grouplist,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sysdb_attrs **ldap_groups,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int ldap_groups_count)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher TALLOC_CTX *tmp_ctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char **ldap_grouplist = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char **add_groups;
9f37bb2012faa136ef7c1f9fe93689ce2be85637Ondrej Kos char **del_groups;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int ret, tret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool in_transaction = false;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tmp_ctx = talloc_new(NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!tmp_ctx) return ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ldap_groups_count == 0) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* No groups for this user in LDAP.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * We need to ensure that there are no groups
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * in the sysdb either.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ldap_grouplist = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher } else {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_attrs_primary_name_list(
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher sysdb, tmp_ctx,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ldap_groups, ldap_groups_count,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher opts->group_map[SDAP_AT_GROUP_NAME].name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher &ldap_grouplist);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret, strerror(ret)));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
4a6a5421113ab662a665c62ed6a24b61a5a36950Jakub Hrozek }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Find the differences between the sysdb and LDAP lists
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * Groups in the sysdb only must be removed.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = diff_string_lists(tmp_ctx, ldap_grouplist, sysdb_grouplist,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher &add_groups, &del_groups, NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_transaction_start(sysdb);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("Failed to start transaction\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher in_transaction = true;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Add fake entries for any groups the user should be added as
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * member of but that are not cached in sysdb
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (add_groups && add_groups[0]) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sdap_add_incomplete_groups(sysdb, opts,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher add_groups, ldap_groups,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ldap_groups_count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("Adding incomplete users failed\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(8, ("Updating memberships for %s\n", name));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_update_members(sysdb, name, type,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher (const char *const *) add_groups,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher (const char *const *) del_groups);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("Membership update failed [%d]: %s\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret, strerror(ret)));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_transaction_commit(sysdb);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("Failed to commit transaction\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher in_transaction = false;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherdone:
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (in_transaction) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tret = sysdb_transaction_cancel(sysdb);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (tret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("Failed to cancel transaction\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_zfree(tmp_ctx);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307===================== */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstruct sdap_initgr_rfc2307_state {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_context *ev;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sysdb_ctx *sysdb;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sss_domain_info *domain;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_options *opts;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_handle *sh;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char **attrs;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *name;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *base_filter;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *orig_dn;
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce char *filter;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int timeout;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_op *op;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sysdb_attrs **ldap_groups;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher size_t ldap_groups_count;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher size_t base_iter;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_search_base **search_bases;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher};
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic errno_t sdap_initgr_rfc2307_next_base(struct tevent_req *req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic void sdap_initgr_rfc2307_process(struct tevent_req *subreq);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstruct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_context *ev,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_options *opts,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sysdb_ctx *sysdb,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sss_domain_info *domain,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_handle *sh,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *name)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce struct tevent_req *req;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_initgr_rfc2307_state *state;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char **attr_filter;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char *clean_name;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher errno_t ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!req) return NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->ev = ev;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->opts = opts;
6fb75e297bf7fc83e3db1f5ae8560624656ef319Jan Zeleny state->sysdb = sysdb;
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce state->domain = domain;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->sh = sh;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->op = NULL;
6fb75e297bf7fc83e3db1f5ae8560624656ef319Jan Zeleny state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
6fb75e297bf7fc83e3db1f5ae8560624656ef319Jan Zeleny state->ldap_groups = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->ldap_groups_count = 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->base_iter = 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->search_bases = opts->group_search_bases;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!state->search_bases) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_CRIT_FAILURE,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ("Initgroups lookup request without a group search base\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = EINVAL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->name = talloc_strdup(state, name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!state->name) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_zfree(req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher attr_filter = talloc_array(state, const char *, 2);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!attr_filter) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_free(req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher attr_filter[0] = opts->group_map[SDAP_AT_GROUP_MEMBER].name;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher attr_filter[1] = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = build_attrs_from_map(state, opts->group_map, SDAP_OPTS_GROUP,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher attr_filter, &state->attrs, NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_free(req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sss_filter_sanitize(state, name, &clean_name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_free(req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->base_filter = talloc_asprintf(state,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "(&(%s=%s)(objectclass=%s)(%s=*)(&(%s=*)(!(%s=0))))",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher opts->group_map[SDAP_AT_GROUP_MEMBER].name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher clean_name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher opts->group_map[SDAP_OC_GROUP].name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher opts->group_map[SDAP_AT_GROUP_NAME].name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher opts->group_map[SDAP_AT_GROUP_GID].name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher opts->group_map[SDAP_AT_GROUP_GID].name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!state->base_filter) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_zfree(req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_zfree(clean_name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sdap_initgr_rfc2307_next_base(req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
2ce00e0d3896bb42db169d1e79553a81ca837a22Simo Sorcedone:
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tevent_req_error(req, ret);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tevent_req_post(req, ev);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return req;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic errno_t sdap_initgr_rfc2307_next_base(struct tevent_req *req)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_req *subreq;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_initgr_rfc2307_state *state;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_zfree(state->filter);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->filter = sdap_get_id_specific_filter(
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state, state->base_filter,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->search_bases[state->base_iter]->filter);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!state->filter) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(SSSDBG_TRACE_FUNC,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ("Searching for groups with base [%s]\n",
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce state->search_bases[state->base_iter]->basedn));
03abdaa21ecf562b714f204ca42379ff08626f75Simo Sorce
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher subreq = sdap_get_generic_send(
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state, state->ev, state->opts, state->sh,
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose state->search_bases[state->base_iter]->basedn,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->search_bases[state->base_iter]->scope,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->filter, state->attrs,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->opts->group_map, SDAP_OPTS_GROUP,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->timeout,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher true);
1ea2e8bd370e0dc2f2c3fa09232cf67082ef748dStephen Gallagher if (!subreq) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tevent_req_set_callback(subreq, sdap_initgr_rfc2307_process, req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return EOK;
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose}
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bosestatic void sdap_initgr_rfc2307_process(struct tevent_req *subreq)
b8dcd1216e5ea7065213c750a92dabfe01fa3b70Simo Sorce{
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose struct tevent_req *req;
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose struct sdap_initgr_rfc2307_state *state;
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose struct sysdb_attrs **ldap_groups;
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose char **sysdb_grouplist = NULL;
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose size_t count;
2ce00e0d3896bb42db169d1e79553a81ca837a22Simo Sorce int ret;
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose int i;
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose
b860f8b6b6b03982c80268e9f6fd35f6455b6b37Simo Sorce req = tevent_req_callback_data(subreq, struct tevent_req);
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
94a66f84bd3c28fcabffeb84c682dccf89d89c2bSumit Bose
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sdap_get_generic_recv(subreq, state, &count, &ldap_groups);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_zfree(subreq);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret) {
b860f8b6b6b03982c80268e9f6fd35f6455b6b37Simo Sorce tevent_req_error(req, ret);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Add this batch of groups to the list */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (count > 0) {
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher state->ldap_groups =
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher talloc_realloc(state,
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher state->ldap_groups,
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher struct sysdb_attrs *,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->ldap_groups_count + count + 1);
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher if (!state->ldap_groups) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tevent_req_error(req, ENOMEM);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
b860f8b6b6b03982c80268e9f6fd35f6455b6b37Simo Sorce /* Copy the new groups into the list.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (i = 0; i < count; i++) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->ldap_groups[state->ldap_groups_count + i] =
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_steal(state->ldap_groups, ldap_groups[i]);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->ldap_groups_count += count;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->ldap_groups[state->ldap_groups_count] = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
b860f8b6b6b03982c80268e9f6fd35f6455b6b37Simo Sorce state->base_iter++;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Check for additional search bases, and iterate
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * through again.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (state->search_bases[state->base_iter] != NULL) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sdap_initgr_rfc2307_next_base(req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tevent_req_error(req, ret);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* Search for all groups for which this user is a member */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = get_sysdb_grouplist(state, state->sysdb, state->domain,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->name, &sysdb_grouplist);
2ce00e0d3896bb42db169d1e79553a81ca837a22Simo Sorce if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tevent_req_error(req, ret);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* There are no nested groups here so we can just update the
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * memberships */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sdap_initgr_common_store(state->sysdb, state->opts,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher SYSDB_MEMBER_USER,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher sysdb_grouplist,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->ldap_groups,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->ldap_groups_count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tevent_req_error(req, ret);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tevent_req_done(req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int sdap_initgr_rfc2307_recv(struct tevent_req *req)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher TEVENT_REQ_RETURN_ON_ERROR(req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/* ==Common code for pure RFC2307bis and IPA/AD========================= */
2ce00e0d3896bb42db169d1e79553a81ca837a22Simo Sorcestatic errno_t
2ce00e0d3896bb42db169d1e79553a81ca837a22Simo Sorcesdap_nested_groups_store(struct sysdb_ctx *sysdb,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_options *opts,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sysdb_attrs **groups,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher unsigned long count)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher errno_t ret, tret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher TALLOC_CTX *tmp_ctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char **groupnamelist = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool in_transaction = false;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek tmp_ctx = talloc_new(NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!tmp_ctx) return ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (count > 0) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_attrs_primary_name_list(sysdb, tmp_ctx,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher groups, count,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher opts->group_map[SDAP_AT_GROUP_NAME].name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher &groupnamelist);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(3, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret, strerror(ret)));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_transaction_start(sysdb);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("Failed to start transaction\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher in_transaction = true;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sdap_add_incomplete_groups(sysdb, opts, groupnamelist,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher groups, count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(6, ("Could not add incomplete groups [%d]: %s\n",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret, strerror(ret)));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_transaction_commit(sysdb);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("Failed to commit transaction\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher in_transaction = false;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherdone:
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (in_transaction) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tret = sysdb_transaction_cancel(sysdb);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (tret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("Failed to cancel transaction\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_free(tmp_ctx);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstruct membership_diff {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct membership_diff *prev;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct membership_diff *next;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *name;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char **add;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char **del;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher};
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic errno_t
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherbuild_membership_diff(TALLOC_CTX *mem_ctx, const char *name,
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher char **ldap_parent_names, char **sysdb_parent_names,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct membership_diff **_mdiff)
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher{
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher TALLOC_CTX *tmp_ctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct membership_diff *mdiff;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher errno_t ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char **add_groups;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher char **del_groups;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tmp_ctx = talloc_new(NULL);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!tmp_ctx) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher mdiff = talloc_zero(tmp_ctx, struct membership_diff);
de526c8425886ca3bed8f07a0f092ba5ac325654Simo Sorce if (!mdiff) {
de526c8425886ca3bed8f07a0f092ba5ac325654Simo Sorce ret = ENOMEM;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto done;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher mdiff->name = talloc_strdup(mdiff, name);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!mdiff->name) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = ENOMEM;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher goto done;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher }
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher /* Find the differences between the sysdb and ldap lists
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher * Groups in ldap only must be added to the sysdb;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher * groups in the sysdb only must be removed.
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher */
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher ret = diff_string_lists(tmp_ctx,
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher ldap_parent_names, sysdb_parent_names,
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher &add_groups, &del_groups, NULL);
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek if (ret != EOK) {
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher goto done;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher }
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher mdiff->add = talloc_steal(mdiff, add_groups);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher mdiff->del = talloc_steal(mdiff, del_groups);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher ret = EOK;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher *_mdiff = talloc_steal(mem_ctx, mdiff);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherdone:
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher talloc_free(tmp_ctx);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher return ret;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher}
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher/* ==Initgr-call-(groups-a-user-is-member-of)-nested-groups=============== */
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagherstruct sdap_initgr_nested_state {
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek struct tevent_context *ev;
c3d09c0095a45de1973f320ce2045ac74d4e4f83Jakub Hrozek struct sysdb_ctx *sysdb;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher struct sdap_options *opts;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher struct sss_domain_info *dom;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher struct sdap_handle *sh;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sysdb_attrs *user;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *username;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char *orig_dn;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const char **grp_attrs;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher struct ldb_message_element *memberof;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher char *filter;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher char **group_dns;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher int cur;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher struct sdap_op *op;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher struct sysdb_attrs **groups;
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher int groups_cur;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher};
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagherstatic errno_t sdap_initgr_nested_deref_search(struct tevent_req *req);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagherstatic errno_t sdap_initgr_nested_noderef_search(struct tevent_req *req);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagherstatic void sdap_initgr_nested_search(struct tevent_req *subreq);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic void sdap_initgr_nested_store(struct tevent_req *req);
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagherstatic struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_context *ev,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_options *opts,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sysdb_ctx *sysdb,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sss_domain_info *dom,
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher struct sdap_handle *sh,
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher struct sysdb_attrs *user,
f5e22261a2ff95f2a61f4f199fffb8de79668110Stephen Gallagher const char **grp_attrs)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_req *req;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_initgr_nested_state *state;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher errno_t ret;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int deref_threshold;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher req = tevent_req_create(memctx, &state, struct sdap_initgr_nested_state);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!req) return NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->ev = ev;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->opts = opts;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->sysdb = sysdb;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher state->dom = dom;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->sh = sh;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->grp_attrs = grp_attrs;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->user = user;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher state->op = NULL;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher ret = sysdb_attrs_primary_name(sysdb, user,
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher opts->user_map[SDAP_AT_USER_NAME].name,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher &state->username);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret != EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(1, ("User entry had no username\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher goto immediate;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = sysdb_attrs_get_el(state->user, SYSDB_MEMBEROF, &state->memberof);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret || !state->memberof || state->memberof->num_values == 0) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher DEBUG(4, ("User entry lacks original memberof ?\n"));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* We can't find any groups for this user, so we'll
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * have to assume there aren't any. Just return
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * success here.
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher */
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher ret = EOK;
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher goto immediate;
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher }
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher state->groups = talloc_zero_array(state, struct sysdb_attrs *,
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher state->memberof->num_values + 1);;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!state->groups) {
de526c8425886ca3bed8f07a0f092ba5ac325654Simo Sorce ret = ENOMEM;
de526c8425886ca3bed8f07a0f092ba5ac325654Simo Sorce goto immediate;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->groups_cur = 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher deref_threshold = dp_opt_get_int(state->opts->basic,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher SDAP_DEREF_THRESHOLD);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher if (sdap_has_deref_support(state->sh, state->opts) &&
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher deref_threshold < state->memberof->num_values) {
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher ret = sysdb_attrs_get_string(user, SYSDB_ORIG_DN,
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher &state->orig_dn);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher if (ret != EOK) goto immediate;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher ret = sdap_initgr_nested_deref_search(req);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher if (ret != EAGAIN) goto immediate;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher } else {
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher ret = sdap_initgr_nested_noderef_search(req);
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek if (ret != EAGAIN) goto immediate;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher }
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher return req;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagherimmediate:
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher if (ret == EOK) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tevent_req_done(req);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher } else {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher tevent_req_error(req, ret);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher }
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher tevent_req_post(req, ev);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher return req;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher}
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagherstatic errno_t sdap_initgr_nested_noderef_search(struct tevent_req *req)
3d8a87081a6cd197acbd355b5a39111669ec2aa6Jakub Hrozek{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int i;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct tevent_req *subreq;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct sdap_initgr_nested_state *state;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher state = tevent_req_data(req, struct sdap_initgr_nested_state);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->group_dns = talloc_array(state, char *,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->memberof->num_values + 1);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!state->group_dns) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ENOMEM;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher }
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher for (i = 0; i < state->memberof->num_values; i++) {
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher state->group_dns[i] = talloc_strdup(state->group_dns,
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher (char *)state->memberof->values[i].data);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher if (!state->group_dns[i]) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ENOMEM;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher }
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher }
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher state->group_dns[i] = NULL; /* terminate */
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher state->cur = 0;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher state->filter = talloc_asprintf(state, "(&(objectclass=%s)(%s=*))",
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher state->opts->group_map[SDAP_OC_GROUP].name,
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher state->opts->group_map[SDAP_AT_GROUP_NAME].name);
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher if (!state->filter) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return ENOMEM;
c1fcc832ccfc237caac8b99be238cf2d598f908cStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher state->group_dns[state->cur],
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher LDAP_SCOPE_BASE,
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher state->filter, state->grp_attrs,
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher state->opts->group_map, SDAP_OPTS_GROUP,
9b72b00ebcfd6225a4e139619c8e18d44a448f87Stephen Gallagher dp_opt_get_int(state->opts->basic,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher SDAP_SEARCH_TIMEOUT),
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher false);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!subreq) {
return ENOMEM;
}
tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
return EAGAIN;
}
static void sdap_initgr_nested_deref_done(struct tevent_req *subreq);
static errno_t sdap_initgr_nested_deref_search(struct tevent_req *req)
{
struct tevent_req *subreq;
struct sdap_attr_map_info *maps;
const int num_maps = 1;
const char **sdap_attrs;
errno_t ret;
int timeout;
struct sdap_initgr_nested_state *state;
state = tevent_req_data(req, struct sdap_initgr_nested_state);
maps = talloc_array(state, struct sdap_attr_map_info, num_maps+1);
if (!maps) return ENOMEM;
maps[0].map = state->opts->group_map;
maps[0].num_attrs = SDAP_OPTS_GROUP;
maps[1].map = NULL;
ret = build_attrs_from_map(state, state->opts->group_map, SDAP_OPTS_GROUP,
NULL, &sdap_attrs, NULL);
if (ret != EOK) goto fail;
timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
subreq = sdap_deref_search_send(state, state->ev, state->opts,
state->sh, state->orig_dn,
state->opts->user_map[SDAP_AT_USER_MEMBEROF].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_initgr_nested_deref_done, req);
return EAGAIN;
fail:
talloc_free(sdap_attrs);
talloc_free(maps);
return ret;
}
static void sdap_initgr_nested_deref_done(struct tevent_req *subreq)
{
errno_t ret;
struct tevent_req *req;
struct sdap_initgr_nested_state *state;
size_t num_results;
size_t i;
struct sdap_deref_attrs **deref_result;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct sdap_initgr_nested_state);
ret = sdap_deref_search_recv(subreq, state,
&num_results,
&deref_result);
talloc_zfree(subreq);
if (ret != EOK && ret != ENOENT) {
tevent_req_error(req, ret);
return;
} else if (ret == ENOENT || deref_result == NULL) {
/* Nothing could be dereferenced. Done. */
tevent_req_done(req);
return;
}
for (i=0; i < num_results; i++) {
state->groups[i] = talloc_steal(state->groups,
deref_result[i]->attrs);
}
state->groups_cur = num_results;
sdap_initgr_nested_store(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] = talloc_steal(state->groups,
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++;
/* note that state->memberof->num_values is the count of original
* memberOf which might not be only groups, but permissions, etc.
* Use state->groups_cur for group index cap */
if (state->cur < state->memberof->num_values) {
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),
false);
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 errno_t
sdap_initgr_store_groups(struct sdap_initgr_nested_state *state);
static errno_t
sdap_initgr_store_group_memberships(struct sdap_initgr_nested_state *state);
static errno_t
sdap_initgr_store_user_memberships(struct sdap_initgr_nested_state *state);
static void sdap_initgr_nested_store(struct tevent_req *req)
{
errno_t ret;
struct sdap_initgr_nested_state *state;
bool in_transaction = false;
errno_t tret;
state = tevent_req_data(req, struct sdap_initgr_nested_state);
ret = sysdb_transaction_start(state->sysdb);
if (ret != EOK) {
DEBUG(1, ("Failed to start transaction\n"));
goto fail;
}
in_transaction = true;
/* save the groups if they are not already */
ret = sdap_initgr_store_groups(state);
if (ret != EOK) {
DEBUG(3, ("Could not save groups [%d]: %s\n",
ret, strerror(ret)));
goto fail;
}
/* save the group memberships */
ret = sdap_initgr_store_group_memberships(state);
if (ret != EOK) {
DEBUG(3, ("Could not save group memberships [%d]: %s\n",
ret, strerror(ret)));
goto fail;
}
/* save the user memberships */
ret = sdap_initgr_store_user_memberships(state);
if (ret != EOK) {
DEBUG(3, ("Could not save user memberships [%d]: %s\n",
ret, strerror(ret)));
goto fail;
}
ret = sysdb_transaction_commit(state->sysdb);
if (ret != EOK) {
DEBUG(1, ("Failed to commit transaction\n"));
goto fail;
}
in_transaction = false;
tevent_req_done(req);
return;
fail:
if (in_transaction) {
tret = sysdb_transaction_cancel(state->sysdb);
if (tret != EOK) {
DEBUG(1, ("Failed to cancel transaction\n"));
}
}
tevent_req_error(req, ret);
return;
}
static errno_t
sdap_initgr_store_groups(struct sdap_initgr_nested_state *state)
{
return sdap_nested_groups_store(state->sysdb,
state->opts, state->groups,
state->groups_cur);
}
static errno_t
sdap_initgr_nested_get_membership_diff(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct sdap_options *opts,
struct sss_domain_info *dom,
struct sysdb_attrs *group,
struct sysdb_attrs **all_groups,
int groups_count,
struct membership_diff **mdiff);
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 errno_t
sdap_initgr_store_group_memberships(struct sdap_initgr_nested_state *state)
{
errno_t ret;
int i, tret;
TALLOC_CTX *tmp_ctx;
struct membership_diff *miter;
struct membership_diff *memberships = NULL;
bool in_transaction = false;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
/* Compute the diffs first in order to keep the transaction as small
* as possible
*/
for (i=0; i < state->groups_cur; i++) {
ret = sdap_initgr_nested_get_membership_diff(tmp_ctx, state->sysdb,
state->opts, state->dom,
state->groups[i],
state->groups,
state->groups_cur,
&miter);
if (ret) {
DEBUG(3, ("Could not compute memberships for group %d [%d]: %s\n",
i, ret, strerror(ret)));
goto done;
}
DLIST_ADD(memberships, miter);
}
ret = sysdb_transaction_start(state->sysdb);
if (ret != EOK) {
DEBUG(1, ("Failed to start transaction\n"));
goto done;
}
in_transaction = true;
DLIST_FOR_EACH(miter, memberships) {
ret = sysdb_update_members(state->sysdb, miter->name,
SYSDB_MEMBER_GROUP,
(const char *const *) miter->add,
(const char *const *) miter->del);
if (ret != EOK) {
DEBUG(3, ("Failed to update memberships\n"));
goto done;
}
}
ret = sysdb_transaction_commit(state->sysdb);
if (ret != EOK) {
DEBUG(1, ("Failed to commit transaction\n"));
goto done;
}
in_transaction = false;
ret = EOK;
done:
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
sdap_initgr_store_user_memberships(struct sdap_initgr_nested_state *state)
{
errno_t ret;
int tret;
const char *orig_dn;
char **sysdb_parent_name_list = NULL;
char **ldap_parent_name_list = NULL;
int nparents;
struct sysdb_attrs **ldap_parentlist;
struct ldb_message_element *el;
int i, mi;
char **add_groups;
char **del_groups;
TALLOC_CTX *tmp_ctx;
bool in_transaction = false;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
ret = ENOMEM;
goto done;
}
/* 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;
}
ldap_parentlist = talloc_zero_array(tmp_ctx, struct sysdb_attrs *,
state->groups_cur + 1);
if (!ldap_parentlist) {
ret = ENOMEM;
goto done;
}
nparents = 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;
}
ldap_parentlist[nparents] = state->groups[i];
nparents++;
}
}
DEBUG(7, ("The user %s is a direct member of %d LDAP groups\n",
state->username, nparents));
if (nparents == 0) {
ldap_parent_name_list = NULL;
} else {
ret = sysdb_attrs_primary_name_list(state->sysdb, tmp_ctx,
ldap_parentlist,
nparents,
state->opts->group_map[SDAP_AT_GROUP_NAME].name,
&ldap_parent_name_list);
if (ret != EOK) {
DEBUG(1, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
ret, strerror(ret)));
goto done;
}
}
ret = sysdb_get_direct_parents(tmp_ctx, state->sysdb, state->dom,
SYSDB_MEMBER_USER,
state->username, &sysdb_parent_name_list);
if (ret) {
DEBUG(1, ("Could not get direct sysdb parents for %s: %d [%s]\n",
state->username, ret, strerror(ret)));
goto done;
}
ret = diff_string_lists(tmp_ctx,
ldap_parent_name_list, sysdb_parent_name_list,
&add_groups, &del_groups, NULL);
if (ret != EOK) {
goto done;
}
ret = sysdb_transaction_start(state->sysdb);
if (ret != EOK) {
DEBUG(1, ("Failed to start transaction\n"));
goto done;
}
in_transaction = true;
DEBUG(8, ("Updating memberships for %s\n", state->username));
ret = sysdb_update_members(state->sysdb, state->username, SYSDB_MEMBER_USER,
(const char *const *) add_groups,
(const char *const *) del_groups);
if (ret != EOK) {
DEBUG(1, ("Could not update sysdb memberships for %s: %d [%s]\n",
state->username, ret, strerror(ret)));
goto done;
}
ret = sysdb_transaction_commit(state->sysdb);
if (ret != EOK) {
goto done;
}
in_transaction = false;
ret = EOK;
done:
if (in_transaction) {
tret = sysdb_transaction_cancel(state->sysdb);
if (tret != EOK) {
DEBUG(1, ("Failed to cancel transaction\n"));
}
}
talloc_zfree(tmp_ctx);
return ret;
}
static errno_t
sdap_initgr_nested_get_membership_diff(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct sdap_options *opts,
struct sss_domain_info *dom,
struct sysdb_attrs *group,
struct sysdb_attrs **all_groups,
int groups_count,
struct membership_diff **_mdiff)
{
errno_t ret;
struct membership_diff *mdiff;
const char *group_name;
struct sysdb_attrs **ldap_parentlist;
int parents_count;
char **ldap_parent_names_list = NULL;
char **sysdb_parents_names_list = NULL;
TALLOC_CTX *tmp_ctx;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
ret = ENOMEM;
goto done;
}
/* Get direct sysdb parents */
ret = sysdb_attrs_primary_name(sysdb, group,
opts->group_map[SDAP_AT_GROUP_NAME].name,
&group_name);
if (ret != EOK) {
goto done;
}
ret = sysdb_get_direct_parents(tmp_ctx, sysdb, dom,
SYSDB_MEMBER_GROUP,
group_name, &sysdb_parents_names_list);
if (ret) {
DEBUG(1, ("Could not get direct sysdb parents for %s: %d [%s]\n",
group_name, ret, strerror(ret)));
goto done;
}
/* For each group, filter only parents from full set */
ret = sdap_initgr_nested_get_direct_parents(tmp_ctx,
group,
all_groups,
groups_count,
&ldap_parentlist,
&parents_count);
if (ret != EOK) {
DEBUG(1, ("Cannot get parent groups for %s [%d]: %s\n",
group_name, ret, strerror(ret)));
goto done;
}
DEBUG(7, ("The group %s is a direct member of %d LDAP groups\n",
group_name, parents_count));
if (parents_count > 0) {
ret = sysdb_attrs_primary_name_list(sysdb, tmp_ctx,
ldap_parentlist,
parents_count,
opts->group_map[SDAP_AT_GROUP_NAME].name,
&ldap_parent_names_list);
if (ret != EOK) {
DEBUG(1, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
ret, strerror(ret)));
goto done;
}
}
ret = build_membership_diff(tmp_ctx, group_name, ldap_parent_names_list,
sysdb_parents_names_list, &mdiff);
if (ret != EOK) {
DEBUG(3, ("Could not build membership diff for %s [%d]: %s\n",
group_name, ret, strerror(ret)));
goto done;
}
ret = EOK;
*_mdiff = talloc_steal(mem_ctx, mdiff);
done:
talloc_free(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 = talloc_steal(mem_ctx, 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)-RFC2307-BIS================= */
struct sdap_initgr_rfc2307bis_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;
const char *base_filter;
char *filter;
const char **attrs;
const char *orig_dn;
int timeout;
size_t base_iter;
struct sdap_search_base **search_bases;
struct sdap_op *op;
hash_table_t *group_hash;
size_t num_direct_parents;
struct sysdb_attrs **direct_groups;
};
struct sdap_nested_group {
struct sysdb_attrs *group;
struct sysdb_attrs **ldap_parents;
size_t parents_count;
};
static errno_t sdap_initgr_rfc2307bis_next_base(struct tevent_req *req);
static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq);
static void sdap_initgr_rfc2307bis_done(struct tevent_req *subreq);
errno_t save_rfc2307bis_user_memberships(
struct sdap_initgr_rfc2307bis_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,
hash_table_t *group_hash, size_t nesting);
static errno_t rfc2307bis_nested_groups_recv(struct tevent_req *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 *name,
const char *orig_dn)
{
errno_t ret;
struct tevent_req *req;
struct sdap_initgr_rfc2307bis_state *state;
const char **attr_filter;
char *clean_orig_dn;
req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307bis_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;
state->direct_groups = NULL;
state->num_direct_parents = 0;
state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
state->base_iter = 0;
state->search_bases = opts->group_search_bases;
state->orig_dn = orig_dn;
if (!state->search_bases) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Initgroups lookup request without a group search base\n"));
ret = EINVAL;
goto done;
}
ret = sss_hash_create(state, 32, &state->group_hash);
if (ret != EOK) {
talloc_free(req);
return NULL;
}
attr_filter = talloc_array(state, const char *, 2);
if (!attr_filter) {
ret = ENOMEM;
goto done;
}
attr_filter[0] = opts->group_map[SDAP_AT_GROUP_MEMBER].name;
attr_filter[1] = NULL;
ret = build_attrs_from_map(state, opts->group_map, SDAP_OPTS_GROUP,
attr_filter, &state->attrs, NULL);
if (ret != EOK) goto done;
ret = sss_filter_sanitize(state, orig_dn, &clean_orig_dn);
if (ret != EOK) goto done;
state->base_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 (!state->base_filter) {
ret = ENOMEM;
goto done;
}
talloc_zfree(clean_orig_dn);
ret = sdap_initgr_rfc2307bis_next_base(req);
done:
if (ret != EOK) {
tevent_req_error(req, ret);
tevent_req_post(req, ev);
}
return req;
}
static errno_t sdap_initgr_rfc2307bis_next_base(struct tevent_req *req)
{
struct tevent_req *subreq;
struct sdap_initgr_rfc2307bis_state *state;
state = tevent_req_data(req, struct sdap_initgr_rfc2307bis_state);
talloc_zfree(state->filter);
state->filter = sdap_get_id_specific_filter(
state,
state->base_filter,
state->search_bases[state->base_iter]->filter);
if (!state->filter) {
return ENOMEM;
}
DEBUG(SSSDBG_TRACE_FUNC,
("Searching for parent groups for user [%s] with base [%s]\n",
state->orig_dn, state->search_bases[state->base_iter]->basedn));
subreq = sdap_get_generic_send(
state, state->ev, state->opts, state->sh,
state->search_bases[state->base_iter]->basedn,
state->search_bases[state->base_iter]->scope,
state->filter, state->attrs,
state->opts->group_map, SDAP_OPTS_GROUP,
state->timeout,
true);
if (!subreq) {
talloc_zfree(req);
return ENOMEM;
}
tevent_req_set_callback(subreq, sdap_initgr_rfc2307bis_process, req);
return EOK;
}
static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq)
{
struct tevent_req *req;
struct sdap_initgr_rfc2307bis_state *state;
struct sysdb_attrs **ldap_groups;
size_t count;
size_t i;
int ret;
req = tevent_req_callback_data(subreq, struct tevent_req);
state = tevent_req_data(req, struct sdap_initgr_rfc2307bis_state);
ret = sdap_get_generic_recv(subreq, state,
&count,
&ldap_groups);
talloc_zfree(subreq);
if (ret) {
tevent_req_error(req, ret);
return;
}
DEBUG(SSSDBG_TRACE_LIBS,
("Found %d parent groups for user [%s]\n", count, state->name));
/* Add this batch of groups to the list */
if (count > 0) {
state->direct_groups =
talloc_realloc(state,
state->direct_groups,
struct sysdb_attrs *,
state->num_direct_parents + count + 1);
if (!state->direct_groups) {
tevent_req_error(req, ENOMEM);
return;
}
/* Copy the new groups into the list.
*/
for (i = 0; i < count; i++) {
state->direct_groups[state->num_direct_parents + i] =
talloc_steal(state->direct_groups, ldap_groups[i]);
}
state->num_direct_parents += count;
state->direct_groups[state->num_direct_parents] = NULL;
}
state->base_iter++;
/* Check for additional search bases, and iterate
* through again.
*/
if (state->search_bases[state->base_iter] != NULL) {
ret = sdap_initgr_rfc2307bis_next_base(req);
if (ret != EOK) {
tevent_req_error(req, ret);
}
return;
}
if (state->num_direct_parents == 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->direct_groups,
state->num_direct_parents,
state->group_hash, 0);
if (!subreq) {
tevent_req_error(req, EIO);
return;
}
tevent_req_set_callback(subreq, sdap_initgr_rfc2307bis_done, req);
}
static errno_t
save_rfc2307bis_groups(struct sdap_initgr_rfc2307bis_state *state);
static errno_t
save_rfc2307bis_group_memberships(struct sdap_initgr_rfc2307bis_state *state);
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_rfc2307bis_state *state =
tevent_req_data(req, struct sdap_initgr_rfc2307bis_state);
bool in_transaction = false;
errno_t tret;
ret = rfc2307bis_nested_groups_recv(subreq);
talloc_zfree(subreq);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
ret = sysdb_transaction_start(state->sysdb);
if (ret != EOK) {
DEBUG(1, ("Failed to start transaction\n"));
goto fail;
}
in_transaction = true;
/* save the groups if they are not cached */
ret = save_rfc2307bis_groups(state);
if (ret != EOK) {
DEBUG(3, ("Could not save groups memberships [%d]", ret));
goto fail;
}
/* save the group membership */
ret = save_rfc2307bis_group_memberships(state);
if (ret != EOK) {
DEBUG(3, ("Could not save group memberships [%d]", ret));
goto fail;
}
/* save the user memberships */
ret = save_rfc2307bis_user_memberships(state);
if (ret != EOK) {
DEBUG(3, ("Could not save user memberships [%d]", ret));
goto fail;
}
ret = sysdb_transaction_commit(state->sysdb);
if (ret != EOK) {
DEBUG(1, ("Failed to commit transaction\n"));
goto fail;
}
in_transaction = false;
tevent_req_done(req);
return;
fail:
if (in_transaction) {
tret = sysdb_transaction_cancel(state->sysdb);
if (tret != EOK) {
DEBUG(1, ("Failed to cancel transaction\n"));
}
}
tevent_req_error(req, ret);
return;
}
static int sdap_initgr_rfc2307bis_recv(struct tevent_req *req)
{
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
struct rfc2307bis_group_memberships_state {
struct sysdb_ctx *sysdb;
struct sdap_options *opts;
struct sss_domain_info *dom;
hash_table_t *group_hash;
struct membership_diff *memberships;
int ret;
};
static errno_t
save_rfc2307bis_groups(struct sdap_initgr_rfc2307bis_state *state)
{
struct sysdb_attrs **groups = NULL;
unsigned long count;
hash_value_t *values;
int hret, i;
errno_t ret;
TALLOC_CTX *tmp_ctx;
struct sdap_nested_group *gr;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
hret = hash_values(state->group_hash, &count, &values);
if (hret != HASH_SUCCESS) {
ret = EIO;
goto done;
}
groups = talloc_array(tmp_ctx, struct sysdb_attrs *, count);
if (!groups) {
ret = ENOMEM;
goto done;
}
for (i = 0; i < count; i++) {
gr = talloc_get_type(values[i].ptr,
struct sdap_nested_group);
groups[i] = gr->group;
}
talloc_zfree(values);
ret = sdap_nested_groups_store(state->sysdb, state->opts,
groups, count);
if (ret != EOK) {
DEBUG(3, ("Could not save groups [%d]: %s\n",
ret, strerror(ret)));
goto done;
}
ret = EOK;
done:
talloc_free(tmp_ctx);
return ret;
}
static bool rfc2307bis_group_memberships_build(hash_entry_t *item, void *user_data);
static errno_t
save_rfc2307bis_group_memberships(struct sdap_initgr_rfc2307bis_state *state)
{
errno_t ret, tret;
int hret;
TALLOC_CTX *tmp_ctx;
struct rfc2307bis_group_memberships_state *membership_state;
struct membership_diff *iter;
struct membership_diff *iter_start;
struct membership_diff *iter_tmp;
bool in_transaction = false;
int num_added;
int i;
int grp_count;
int grp_count_old = 0;
char **add = NULL;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
membership_state = talloc_zero(tmp_ctx,
struct rfc2307bis_group_memberships_state);
if (!membership_state) {
ret = ENOMEM;
goto done;
}
membership_state->sysdb = state->sysdb;
membership_state->dom = state->dom;
membership_state->opts = state->opts;
membership_state->group_hash = state->group_hash;
hret = hash_iterate(state->group_hash,
rfc2307bis_group_memberships_build,
membership_state);
if (hret != HASH_SUCCESS) {
ret = membership_state->ret;
goto done;
}
ret = sysdb_transaction_start(state->sysdb);
if (ret != EOK) {
DEBUG(1, ("Failed to start transaction\n"));
goto done;
}
in_transaction = true;
iter_start = membership_state->memberships;
DLIST_FOR_EACH(iter, membership_state->memberships) {
/* Create a copy of iter->add array but do not include groups outside
* nesting limit. This array must be NULL terminated.
*/
for (grp_count = 0; iter->add[grp_count]; grp_count++);
if (grp_count > grp_count_old) {
add = talloc_realloc(tmp_ctx, add, char*, grp_count + 1);
if (add == NULL) {
ret = ENOMEM;
goto done;
}
}
num_added = 0;
for (i = 0; i < grp_count; i++) {
DLIST_FOR_EACH(iter_tmp, iter_start) {
if (!strcmp(iter_tmp->name,iter->add[i])) {
add[num_added] = iter->add[i];
num_added++;
break;
}
}
}
/* Swap old and new group counter. */
grp_count ^= grp_count_old;
grp_count_old ^= grp_count;
grp_count ^= grp_count_old;
if (num_added == 0) {
add = NULL;
} else {
add[num_added] = NULL;
}
ret = sysdb_update_members(state->sysdb, iter->name,
SYSDB_MEMBER_GROUP,
(const char *const *) add,
(const char *const *) iter->del);
if (ret != EOK) {
DEBUG(3, ("Failed to update memberships\n"));
goto done;
}
}
ret = sysdb_transaction_commit(state->sysdb);
if (ret != EOK) {
DEBUG(1, ("Failed to commit transaction\n"));
goto done;
}
in_transaction = false;
ret = EOK;
done:
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 bool
rfc2307bis_group_memberships_build(hash_entry_t *item, void *user_data)
{
struct rfc2307bis_group_memberships_state *mstate = talloc_get_type(
user_data, struct rfc2307bis_group_memberships_state);
struct sdap_nested_group *group;
char *group_name;
TALLOC_CTX *tmp_ctx;
errno_t ret;
char **sysdb_parents_names_list;
char **ldap_parents_names_list = NULL;
struct membership_diff *mdiff;
group_name = (char *) item->key.str;
group = (struct sdap_nested_group *) item->value.ptr;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
ret = ENOMEM;
goto done;
}
ret = sysdb_get_direct_parents(tmp_ctx, mstate->sysdb, mstate->dom,
SYSDB_MEMBER_GROUP,
group_name, &sysdb_parents_names_list);
if (ret) {
DEBUG(1, ("Could not get direct sysdb parents for %s: %d [%s]\n",
group_name, ret, strerror(ret)));
goto done;
}
if (group->parents_count > 0) {
ret = sysdb_attrs_primary_name_list(mstate->sysdb, tmp_ctx,
group->ldap_parents, group->parents_count,
mstate->opts->group_map[SDAP_AT_GROUP_NAME].name,
&ldap_parents_names_list);
if (ret != EOK) {
goto done;
}
}
ret = build_membership_diff(tmp_ctx, group_name, ldap_parents_names_list,
sysdb_parents_names_list, &mdiff);
if (ret != EOK) {
DEBUG(3, ("Could not build membership diff for %s [%d]: %s\n",
group_name, ret, strerror(ret)));
goto done;
}
talloc_steal(mstate, mdiff);
DLIST_ADD(mstate->memberships, mdiff);
ret = EOK;
done:
talloc_free(tmp_ctx);
mstate->ret = ret;
return ret == EOK ? true : false;
}
errno_t save_rfc2307bis_user_memberships(
struct sdap_initgr_rfc2307bis_state *state)
{
errno_t ret, tret;
char **ldap_grouplist;
char **sysdb_parent_name_list;
char **add_groups;
char **del_groups;
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) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
goto error;
}
in_transaction = true;
ret = sysdb_get_direct_parents(tmp_ctx, state->sysdb, state->dom,
SYSDB_MEMBER_USER,
state->name, &sysdb_parent_name_list);
if (ret) {
DEBUG(1, ("Could not get direct sysdb parents for %s: %d [%s]\n",
state->name, ret, strerror(ret)));
goto error;
}
if (state->num_direct_parents == 0) {
ldap_grouplist = NULL;
}
else {
ret = sysdb_attrs_primary_name_list(
state->sysdb, tmp_ctx,
state->direct_groups, state->num_direct_parents,
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_parent_name_list,
&add_groups, &del_groups, NULL);
if (ret != EOK) {
goto error;
}
DEBUG(8, ("Updating memberships for %s\n", state->name));
ret = sysdb_update_members(state->sysdb, state->name, SYSDB_MEMBER_USER,
(const char *const *)add_groups,
(const char *const *)del_groups);
if (ret != EOK) {
goto error;
}
ret = sysdb_transaction_commit(state->sysdb);
if (ret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n"));
goto error;
}
in_transaction = false;
talloc_free(tmp_ctx);
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;
}
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;
int timeout;
const char *base_filter;
char *filter;
const char *orig_dn;
const char **attrs;
struct sysdb_attrs **groups;
size_t num_groups;
size_t nesting_level;
size_t group_iter;
struct sdap_nested_group **processed_groups;
hash_table_t *group_hash;
const char *primary_name;
struct sysdb_handle *handle;
size_t base_iter;
struct sdap_search_base **search_bases;
};
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,
hash_table_t *group_hash, size_t nesting)
{
errno_t ret;
struct tevent_req *req;
struct sdap_rfc2307bis_nested_ctx *state;
DEBUG(SSSDBG_TRACE_INTERNAL,
("About to process %d groups in nesting level %d\n", num_groups, nesting));
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*/
ret = EOK;
goto done;
}
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;
state->group_hash = group_hash;
state->filter = NULL;
state->timeout = dp_opt_get_int(state->opts->basic,
SDAP_SEARCH_TIMEOUT);
state->base_iter = 0;
state->search_bases = opts->group_search_bases;
if (!state->search_bases) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Initgroups nested lookup request "
"without a group search base\n"));
ret = EINVAL;
goto done;
}
state->processed_groups = talloc_array(state,
struct sdap_nested_group *,
state->num_groups);
if (state->processed_groups == NULL) {
ret = ENOMEM;
goto done;
}
while (state->group_iter < state->num_groups) {
ret = rfc2307bis_nested_groups_step(req);
if (ret == EOK) {
/* This group had already been looked up. Continue to
* another group in the same level
*/
state->group_iter++;
continue;
} else {
goto done;
}
}
ret = EOK;
done:
if (ret == EOK) {
/* All parent groups were already processed */
tevent_req_done(req);
tevent_req_post(req, ev);
} else if (ret != EAGAIN) {
tevent_req_error(req, ret);
tevent_req_post(req, ev);
}
/* EAGAIN means a lookup is in progress */
return req;
}
static errno_t rfc2307bis_nested_groups_next_base(struct tevent_req *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;
TALLOC_CTX *tmp_ctx = NULL;
const char **attr_filter;
char *clean_orig_dn;
hash_key_t key;
hash_value_t value;
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 done;
}
ret = sysdb_attrs_primary_name(
state->sysdb,
state->groups[state->group_iter],
state->opts->group_map[SDAP_AT_GROUP_NAME].name,
&state->primary_name);
if (ret != EOK) {
goto done;
}
key.type = HASH_KEY_STRING;
key.str = talloc_strdup(state, state->primary_name);
if (!key.str) {
ret = ENOMEM;
goto done;
}
DEBUG(SSSDBG_TRACE_LIBS, ("Processing group [%s]\n", state->primary_name));
ret = hash_lookup(state->group_hash, &key, &value);
if (ret == HASH_SUCCESS) {
DEBUG(SSSDBG_TRACE_INTERNAL, ("Group [%s] was already processed, "
"taking a shortcut\n", state->primary_name));
state->processed_groups[state->group_iter] =
talloc_get_type(value.ptr, struct sdap_nested_group);
talloc_free(key.str);
ret = EOK;
goto done;
}
/* Need to try to find parent groups for this group. */
state->processed_groups[state->group_iter] =
talloc_zero(state->processed_groups, struct sdap_nested_group);
if (!state->processed_groups[state->group_iter]) {
ret = ENOMEM;
goto done;
}
/* this steal doesn't change much now, but will be helpful later on
* if we steal the whole processed_group on the hash table */
state->processed_groups[state->group_iter]->group =
talloc_steal(state->processed_groups[state->group_iter],
state->groups[state->group_iter]);
/* Get any parent groups for this group */
ret = sysdb_attrs_get_string(state->groups[state->group_iter],
SYSDB_ORIG_DN,
&state->orig_dn);
if (ret != EOK) {
goto done;
}
attr_filter = talloc_array(state, const char *, 2);
if (!attr_filter) {
ret = ENOMEM;
goto done;
}
attr_filter[0] = state->opts->group_map[SDAP_AT_GROUP_MEMBER].name;
attr_filter[1] = NULL;
ret = build_attrs_from_map(state, state->opts->group_map, SDAP_OPTS_GROUP,
attr_filter, &state->attrs, NULL);
if (ret != EOK) {
goto done;
}
ret = sss_filter_sanitize(tmp_ctx, state->orig_dn, &clean_orig_dn);
if (ret != EOK) {
goto done;
}
state->base_filter = talloc_asprintf(
state, "(&(%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 (!state->base_filter) {
ret = ENOMEM;
goto done;
}
ret = rfc2307bis_nested_groups_next_base(req);
if (ret != EOK) goto done;
/* Still processing parent groups */
ret = EAGAIN;
done:
talloc_free(tmp_ctx);
return ret;
}
static errno_t rfc2307bis_nested_groups_next_base(struct tevent_req *req)
{
struct tevent_req *subreq;
struct sdap_rfc2307bis_nested_ctx *state;
state = tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);
talloc_zfree(state->filter);
state->filter = sdap_get_id_specific_filter(
state, state->base_filter,
state->search_bases[state->base_iter]->filter);
if (!state->filter) {
return ENOMEM;
}
DEBUG(SSSDBG_TRACE_FUNC,
("Searching for parent groups of group [%s] with base [%s]\n",
state->orig_dn,
state->search_bases[state->base_iter]->basedn));
subreq = sdap_get_generic_send(
state, state->ev, state->opts, state->sh,
state->search_bases[state->base_iter]->basedn,
state->search_bases[state->base_iter]->scope,
state->filter, state->attrs,
state->opts->group_map, SDAP_OPTS_GROUP,
state->timeout,
true);
if (!subreq) {
return ENOMEM;
}
tevent_req_set_callback(subreq,
rfc2307bis_nested_groups_process,
req);
return EOK;
}
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);
size_t count;
size_t i;
struct sysdb_attrs **ldap_groups;
struct sdap_nested_group *ngr;
hash_value_t value;
hash_key_t key;
int hret;
ret = sdap_get_generic_recv(subreq, state,
&count,
&ldap_groups);
talloc_zfree(subreq);
if (ret) {
tevent_req_error(req, ret);
return;
}
DEBUG(SSSDBG_TRACE_LIBS,
("Found %d parent groups of [%s]\n", count, state->orig_dn));
ngr = state->processed_groups[state->group_iter];
/* Add this batch of groups to the list */
if (count > 0) {
ngr->ldap_parents =
talloc_realloc(ngr,
ngr->ldap_parents,
struct sysdb_attrs *,
ngr->parents_count + count + 1);
if (!ngr->ldap_parents) {
tevent_req_error(req, ENOMEM);
return;
}
/* Copy the new groups into the list.
* They're allocated on 'state' so we need to move them
* onto ldap_parents so that the data won't disappear when
* we finish this nesting level.
*/
for (i = 0; i < count; i++) {
ngr->ldap_parents[ngr->parents_count + i] =
talloc_steal(ngr->ldap_parents, ldap_groups[i]);
}
ngr->parents_count += count;
ngr->ldap_parents[ngr->parents_count] = NULL;
DEBUG(SSSDBG_TRACE_INTERNAL,
("Total of %d direct parents after this iteration\n",
ngr->parents_count));
}
state->base_iter++;
/* Check for additional search bases, and iterate
* through again.
*/
if (state->search_bases[state->base_iter] != NULL) {
ret = rfc2307bis_nested_groups_next_base(req);
if (ret != EOK) {
tevent_req_error(req, ret);
}
return;
}
/* Reset the base iterator for future lookups */
state->base_iter = 0;
/* Save the group into the hash table */
key.type = HASH_KEY_STRING;
key.str = talloc_strdup(state, state->primary_name);
if (!key.str) {
tevent_req_error(req, ENOMEM);
return;
}
/* Steal the nested group entry on the group_hash context so it can
* outlive this request */
talloc_steal(state->group_hash, ngr);
value.type = HASH_VALUE_PTR;
value.ptr = ngr;
hret = hash_enter(state->group_hash, &key, &value);
if (hret != HASH_SUCCESS) {
talloc_free(key.str);
tevent_req_error(req, EIO);
return;
}
talloc_free(key.str);
if (ngr->parents_count == 0) {
/* No parent groups for this group in LDAP
* Move on to the next group
*/
state->group_iter++;
while (state->group_iter < state->num_groups) {
ret = rfc2307bis_nested_groups_step(req);
if (ret == EAGAIN) {
/* Looking up parent groups.. */
return;
} else if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
/* EOK means this group has already been processed
* in another nesting level */
state->group_iter++;
}
if (state->group_iter == state->num_groups) {
/* All groups processed. Done. */
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,
ngr->ldap_parents,
ngr->parents_count,
state->group_hash,
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;
}
state->group_iter++;
while (state->group_iter < state->num_groups) {
ret = rfc2307bis_nested_groups_step(req);
if (ret == EAGAIN) {
/* Looking up parent groups.. */
return;
} else if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
/* EOK means this group has already been processed
* in another nesting level */
state->group_iter++;
}
if (state->group_iter == state->num_groups) {
/* All groups processed. Done. */
tevent_req_done(req);
return;
}
}
/* ==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 **user_attrs;
const char *user_base_filter;
char *filter;
int timeout;
struct sysdb_attrs *orig_user;
size_t user_base_iter;
struct sdap_search_base **user_search_bases;
};
static errno_t sdap_get_initgr_next_base(struct tevent_req *req);
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;
struct sdap_get_initgr_state *state;
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;
state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
state->user_base_iter = 0;
state->user_search_bases = id_ctx->opts->user_search_bases;
if (!state->user_search_bases) {
DEBUG(SSSDBG_CRIT_FAILURE,
("Initgroups lookup request without a user search base\n"));
ret = EINVAL;
goto done;
}
ret = sss_filter_sanitize(state, name, &clean_name);
if (ret != EOK) {
talloc_zfree(req);
return NULL;
}
state->user_base_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 (!state->user_base_filter) {
talloc_zfree(req);
return NULL;
}
ret = build_attrs_from_map(state, state->opts->user_map, SDAP_OPTS_USER,
NULL, &state->user_attrs, NULL);
if (ret) {
talloc_zfree(req);
return NULL;
}
ret = sdap_get_initgr_next_base(req);
done:
if (ret != EOK) {
tevent_req_error(req, ret);
tevent_req_post(req, ev);
}
return req;
}
static errno_t sdap_get_initgr_next_base(struct tevent_req *req)
{
struct tevent_req *subreq;
struct sdap_get_initgr_state *state;
state = tevent_req_data(req, struct sdap_get_initgr_state);
talloc_zfree(state->filter);
state->filter = sdap_get_id_specific_filter(
state,
state->user_base_filter,
state->user_search_bases[state->user_base_iter]->filter);
if (!state->filter) {
return ENOMEM;
}
DEBUG(SSSDBG_TRACE_FUNC,
("Searching for users with base [%s]\n",
state->user_search_bases[state->user_base_iter]->basedn));
subreq = sdap_get_generic_send(
state, state->ev, state->opts, state->sh,
state->user_search_bases[state->user_base_iter]->basedn,
state->user_search_bases[state->user_base_iter]->scope,
state->filter, state->user_attrs,
state->opts->user_map, SDAP_OPTS_USER,
state->timeout,
false);
if (!subreq) {
return ENOMEM;
}
tevent_req_set_callback(subreq, sdap_get_initgr_user, req);
return EOK;
}
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 *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;
errno_t sret;
const char *orig_dn;
const char *cname;
bool in_transaction = false;
bool use_id_mapping =
dp_opt_get_bool(state->opts->basic, SDAP_ID_MAPPING);
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 == 0) {
/* No users found in this search */
state->user_base_iter++;
if (state->user_search_bases[state->user_base_iter]) {
/* There are more search bases to try */
ret = sdap_get_initgr_next_base(req);
if (ret != EOK) {
tevent_req_error(req, ret);
}
return;
}
tevent_req_error(req, ENOENT);
return;
} else if (count != 1) {
DEBUG(2, ("Expected one user entry and got %d\n", count));
tevent_req_error(req, EINVAL);
return;
}
state->orig_user = usr_attrs[0];
ret = sysdb_transaction_start(state->sysdb);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
goto fail;
}
in_transaction = true;
DEBUG(9, ("Storing the user\n"));
ret = sdap_save_user(state, state->sysdb,
state->opts, state->dom,
state->orig_user,
true, NULL, 0);
if (ret) {
goto fail;
}
DEBUG(9, ("Commit change\n"));
ret = sysdb_transaction_commit(state->sysdb);
if (ret) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n"));
goto fail;
}
in_transaction = false;
ret = sysdb_get_real_name(state, state->sysdb, state->name, &cname);
if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, ("Cannot canonicalize username\n"));
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,
cname);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
}
tevent_req_set_callback(subreq, sdap_get_initgr_done, req);
break;
case SDAP_SCHEMA_RFC2307BIS:
case SDAP_SCHEMA_AD:
ret = sysdb_attrs_get_string(state->orig_user,
SYSDB_ORIG_DN,
&orig_dn);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
if (use_id_mapping
&& state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
/* Take advantage of AD's tokenGroups mechanism to look up all
* parent groups in a single request.
*/
subreq = sdap_get_ad_tokengroups_initgroups_send(state, state->ev,
state->opts,
state->sysdb,
state->dom,
state->sh,
cname, orig_dn,
state->timeout);
} else if (state->opts->support_matching_rule
&& dp_opt_get_bool(state->opts->basic,
SDAP_AD_MATCHING_RULE_INITGROUPS)) {
/* Take advantage of AD's extensibleMatch filter to look up
* all parent groups in a single request.
*/
subreq = sdap_get_ad_match_rule_initgroups_send(state, state->ev,
state->opts,
state->sysdb,
state->dom,
state->sh,
cname, orig_dn,
state->timeout);
} else {
subreq = sdap_initgr_rfc2307bis_send(
state, state->ev, state->opts, state->sysdb,
state->dom, state->sh,
cname, 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:
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;
}
return;
fail:
if (in_transaction) {
sret = sysdb_transaction_cancel(state->sysdb);
if (sret != EOK) {
DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to cancel transaction\n"));
}
}
tevent_req_error(req, ret);
}
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;
TALLOC_CTX *tmp_ctx;
gid_t primary_gid;
char *gid;
char *sid_str;
char *dom_sid_str;
char *group_sid_str;
struct sdap_options *opts = state->opts;
bool use_id_mapping = dp_opt_get_bool(opts->basic, SDAP_ID_MAPPING);
DEBUG(9, ("Initgroups done\n"));
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) {
tevent_req_error(req, ENOMEM);
return;
}
switch (state->opts->schema_type) {
case SDAP_SCHEMA_RFC2307:
ret = sdap_initgr_rfc2307_recv(subreq);
break;
case SDAP_SCHEMA_RFC2307BIS:
case SDAP_SCHEMA_AD:
if (use_id_mapping
&& state->opts->dc_functional_level >= DS_BEHAVIOR_WIN2008) {
ret = sdap_get_ad_tokengroups_initgroups_recv(subreq);
}
else if (state->opts->support_matching_rule
&& dp_opt_get_bool(state->opts->basic,
SDAP_AD_MATCHING_RULE_INITGROUPS)) {
ret = sdap_get_ad_match_rule_initgroups_recv(subreq);
} else {
ret = sdap_initgr_rfc2307bis_recv(subreq);
}
break;
case SDAP_SCHEMA_IPA_V1:
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)));
goto fail;
}
/* We also need to update the user's primary group, since
* the user may not be an explicit member of that group
*/
if (use_id_mapping) {
DEBUG(SSSDBG_TRACE_LIBS,
("Mapping primary group to unix ID\n"));
/* The primary group ID is just the RID part of the objectSID
* of the group. Generate the GID by adding this to the domain
* SID value.
*/
/* Get the user SID so we can extract the domain SID
* from it.
*/
ret = sdap_attrs_get_sid_str(
tmp_ctx, opts->idmap_ctx, state->orig_user,
opts->user_map[SDAP_AT_USER_OBJECTSID].sys_name,
&sid_str);
if (ret != EOK) goto fail;
/* Get the domain SID from the user SID */
ret = sdap_idmap_get_dom_sid_from_object(tmp_ctx, sid_str,
&dom_sid_str);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
("Could not parse domain SID from [%s]\n", sid_str));
goto fail;
}
ret = sysdb_attrs_get_uint32_t(
state->orig_user,
opts->user_map[SDAP_AT_USER_PRIMARY_GROUP].sys_name,
&primary_gid);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
("no primary group ID provided\n"));
ret = EINVAL;
goto fail;
}
/* Add the RID to the end */
group_sid_str = talloc_asprintf(tmp_ctx, "%s-%lu",
dom_sid_str,
(unsigned long)primary_gid);
if (!group_sid_str) {
ret = ENOMEM;
goto fail;
}
/* Convert the SID into a UNIX group ID */
ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, sid_str, &primary_gid);
if (ret != EOK) goto fail;
} else {
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"));
goto fail;
}
}
gid = talloc_asprintf(state, "%lu", (unsigned long)primary_gid);
if (gid == NULL) {
ret = ENOMEM;
goto fail;
}
subreq = groups_get_send(req, state->ev, state->id_ctx, gid,
BE_FILTER_IDNUM, BE_ATTR_ALL);
if (!subreq) {
ret = ENOMEM;
goto fail;
}
tevent_req_set_callback(subreq, sdap_get_initgr_pgid, req);
talloc_free(tmp_ctx);
tevent_req_done(req);
return;
fail:
talloc_free(tmp_ctx);
tevent_req_error(req, ret);
return;
}
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;
}
errno_t get_sysdb_grouplist(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
const char *name,
char ***grouplist)
{
errno_t ret;
const char *attrs[2];
struct ldb_message *msg;
TALLOC_CTX *tmp_ctx;
struct ldb_message_element *groups;
char **sysdb_grouplist = NULL;
unsigned int i;
attrs[0] = SYSDB_MEMBEROF;
attrs[1] = NULL;
tmp_ctx = talloc_new(NULL);
if (!tmp_ctx) return ENOMEM;
ret = sysdb_search_user_by_name(tmp_ctx, sysdb, domain, name,
attrs, &msg);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
("Error searching user [%s] by name: [%s]\n",
name, strerror(ret)));
goto done;
}
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(tmp_ctx, char *, groups->num_values+1);
if (!sysdb_grouplist) {
ret = ENOMEM;
goto done;
}
/* Get a list of the groups by groupname only */
for (i=0; i < groups->num_values; i++) {
ret = sysdb_group_dn_name(sysdb,
sysdb_grouplist,
(const char *)groups->values[i].data,
&sysdb_grouplist[i]);
if (ret != EOK) {
DEBUG(SSSDBG_MINOR_FAILURE,
("Could not determine group name from [%s]: [%s]\n",
(const char *)groups->values[i].data, strerror(ret)));
goto done;
}
}
sysdb_grouplist[groups->num_values] = NULL;
}
*grouplist = talloc_steal(mem_ctx, sysdb_grouplist);
done:
talloc_free(tmp_ctx);
return ret;
}