sdap_async_initgroups.c revision fdda4b659fa3be3027df91a2b053835186ec2c59
842ae4bd224140319ae7feec1872b93dfd491143fielding/*
842ae4bd224140319ae7feec1872b93dfd491143fielding SSSD
842ae4bd224140319ae7feec1872b93dfd491143fielding
842ae4bd224140319ae7feec1872b93dfd491143fielding Async LDAP Helper routines - initgroups operation
842ae4bd224140319ae7feec1872b93dfd491143fielding
842ae4bd224140319ae7feec1872b93dfd491143fielding Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding Copyright (C) 2010, Ralf Haferkamp <rhafer@suse.de>, Novell Inc.
04891cf70e0bfc38bfb027541dc821f04c754ff7nd Copyright (C) Jan Zeleny <jzeleny@redhat.com> - 2011
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
04891cf70e0bfc38bfb027541dc821f04c754ff7nd This program is free software; you can redistribute it and/or modify
04891cf70e0bfc38bfb027541dc821f04c754ff7nd it under the terms of the GNU General Public License as published by
04891cf70e0bfc38bfb027541dc821f04c754ff7nd the Free Software Foundation; either version 3 of the License, or
04891cf70e0bfc38bfb027541dc821f04c754ff7nd (at your option) any later version.
04891cf70e0bfc38bfb027541dc821f04c754ff7nd
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding This program is distributed in the hope that it will be useful,
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding but WITHOUT ANY WARRANTY; without even the implied warranty of
3568de757bac0b47256647504c186d17ca272f85rbb MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3568de757bac0b47256647504c186d17ca272f85rbb GNU General Public License for more details.
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb You should have received a copy of the GNU General Public License
3568de757bac0b47256647504c186d17ca272f85rbb along with this program. If not, see <http://www.gnu.org/licenses/>.
3568de757bac0b47256647504c186d17ca272f85rbb*/
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb#include "util/util.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "db/sysdb.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "providers/ldap/sdap_async_private.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "providers/ldap/ldap_common.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "providers/ldap/sdap_idmap.h"
3568de757bac0b47256647504c186d17ca272f85rbb#include "providers/ldap/sdap_users.h"
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb/* ==Save-fake-group-list=====================================*/
3568de757bac0b47256647504c186d17ca272f85rbbstatic errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb,
3568de757bac0b47256647504c186d17ca272f85rbb struct sss_domain_info *domain,
3568de757bac0b47256647504c186d17ca272f85rbb struct sdap_options *opts,
3568de757bac0b47256647504c186d17ca272f85rbb char **groupnames,
3568de757bac0b47256647504c186d17ca272f85rbb struct sysdb_attrs **ldap_groups,
3568de757bac0b47256647504c186d17ca272f85rbb int ldap_groups_count)
3568de757bac0b47256647504c186d17ca272f85rbb{
3568de757bac0b47256647504c186d17ca272f85rbb TALLOC_CTX *tmp_ctx;
3568de757bac0b47256647504c186d17ca272f85rbb struct ldb_message *msg;
3568de757bac0b47256647504c186d17ca272f85rbb int i, mi, ai;
3568de757bac0b47256647504c186d17ca272f85rbb const char *groupname;
3568de757bac0b47256647504c186d17ca272f85rbb const char *original_dn;
3568de757bac0b47256647504c186d17ca272f85rbb char **missing;
3568de757bac0b47256647504c186d17ca272f85rbb gid_t gid;
3568de757bac0b47256647504c186d17ca272f85rbb int ret;
3568de757bac0b47256647504c186d17ca272f85rbb errno_t sret;
3568de757bac0b47256647504c186d17ca272f85rbb bool in_transaction = false;
3568de757bac0b47256647504c186d17ca272f85rbb bool posix;
3568de757bac0b47256647504c186d17ca272f85rbb time_t now;
3568de757bac0b47256647504c186d17ca272f85rbb char *sid_str = NULL;
3568de757bac0b47256647504c186d17ca272f85rbb bool use_id_mapping;
3568de757bac0b47256647504c186d17ca272f85rbb char *tmp_name;
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb /* There are no groups in LDAP but we should add user to groups ?? */
3568de757bac0b47256647504c186d17ca272f85rbb if (ldap_groups_count == 0) return EOK;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tmp_ctx = talloc_new(NULL);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (!tmp_ctx) return ENOMEM;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
3568de757bac0b47256647504c186d17ca272f85rbb missing = talloc_array(tmp_ctx, char *, ldap_groups_count+1);
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick if (!missing) {
3568de757bac0b47256647504c186d17ca272f85rbb ret = ENOMEM;
3568de757bac0b47256647504c186d17ca272f85rbb goto done;
3568de757bac0b47256647504c186d17ca272f85rbb }
3568de757bac0b47256647504c186d17ca272f85rbb mi = 0;
98fb535f829e2a95aabd82420931f476661fa8e3jorton
db12cd62083041bf90945eeb90cc40fbd2340797trawick for (i=0; groupnames[i]; i++) {
db12cd62083041bf90945eeb90cc40fbd2340797trawick tmp_name = sss_get_domain_name(tmp_ctx, groupnames[i], domain);
db12cd62083041bf90945eeb90cc40fbd2340797trawick if (tmp_name == NULL) {
333eac96e4fb7d6901cb75e6ca7bb22b2ccb84cetrawick DEBUG(SSSDBG_OP_FAILURE,
333eac96e4fb7d6901cb75e6ca7bb22b2ccb84cetrawick ("Failed to format original name [%s]\n", groupnames[i]));
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem ret = ENOMEM;
3568de757bac0b47256647504c186d17ca272f85rbb goto done;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz }
3568de757bac0b47256647504c186d17ca272f85rbb
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ret = sysdb_search_group_by_name(tmp_ctx, sysdb, domain,
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz tmp_name, NULL, &msg);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (ret == EOK) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding continue;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz } else if (ret == ENOENT) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding missing[mi] = talloc_steal(missing, tmp_name);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding DEBUG(7, ("Group #%d [%s][%s] is not cached, " \
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding "need to add a fake entry\n",
8f3ec4772d2aeb347cf40e87c77627bb784dd018rbb i, groupnames[i], missing[mi]));
8f3ec4772d2aeb347cf40e87c77627bb784dd018rbb mi++;
3d96ee83babeec32482c9082c9426340cee8c44dwrowe continue;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else if (ret != ENOENT) {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf DEBUG(1, ("search for group failed [%d]: %s\n",
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf ret, strerror(ret)));
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick goto done;
98fb535f829e2a95aabd82420931f476661fa8e3jorton }
f0e395a55abfcad3d2bd7c63470003b08a93d567nd }
f0e395a55abfcad3d2bd7c63470003b08a93d567nd missing[mi] = NULL;
f0e395a55abfcad3d2bd7c63470003b08a93d567nd
f0e395a55abfcad3d2bd7c63470003b08a93d567nd /* All groups are cached, nothing to do */
98fb535f829e2a95aabd82420931f476661fa8e3jorton if (mi == 0) {
7cd5419264796cfeaf8215383cf0f89130a81fectrawick ret = EOK;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick goto done;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick }
7cd5419264796cfeaf8215383cf0f89130a81fectrawick
7cd5419264796cfeaf8215383cf0f89130a81fectrawick use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(opts->idmap_ctx,
7cd5419264796cfeaf8215383cf0f89130a81fectrawick domain->name,
7cd5419264796cfeaf8215383cf0f89130a81fectrawick domain->domain_id);
7cd5419264796cfeaf8215383cf0f89130a81fectrawick
3568de757bac0b47256647504c186d17ca272f85rbb ret = sysdb_transaction_start(sysdb);
41634f717c623556a16b27b25d7d909a66fe20f8wrowe if (ret != EOK) {
3568de757bac0b47256647504c186d17ca272f85rbb DEBUG(SSSDBG_CRIT_FAILURE,
3568de757bac0b47256647504c186d17ca272f85rbb ("Cannot start sysdb transaction [%d]: %s\n",
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ret, strerror(ret)));
3568de757bac0b47256647504c186d17ca272f85rbb goto done;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz }
3568de757bac0b47256647504c186d17ca272f85rbb in_transaction = true;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
3568de757bac0b47256647504c186d17ca272f85rbb
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz now = time(NULL);
3568de757bac0b47256647504c186d17ca272f85rbb for (i=0; missing[i]; i++) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* The group is not in sysdb, need to add a fake entry */
41634f717c623556a16b27b25d7d909a66fe20f8wrowe for (ai=0; ai < ldap_groups_count; ai++) {
3568de757bac0b47256647504c186d17ca272f85rbb ret = sdap_get_group_primary_name(tmp_ctx, opts, ldap_groups[ai],
3568de757bac0b47256647504c186d17ca272f85rbb domain, &groupname);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (ret != EOK) {
3568de757bac0b47256647504c186d17ca272f85rbb DEBUG(SSSDBG_CRIT_FAILURE,
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ("The group has no name attribute\n"));
3568de757bac0b47256647504c186d17ca272f85rbb goto done;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz }
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding if (strcmp(groupname, missing[i]) == 0) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz posix = true;
3568de757bac0b47256647504c186d17ca272f85rbb
fc1efab92032301e317f07e1b3a00082d9d71f3frbb ret = sdap_attrs_get_sid_str(
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz tmp_ctx, opts->idmap_ctx, ldap_groups[ai],
24b534291150023e6b68eca89ddd33e475ccddc0wrowe opts->group_map[SDAP_AT_GROUP_OBJECTSID].sys_name,
3568de757bac0b47256647504c186d17ca272f85rbb &sid_str);
24b534291150023e6b68eca89ddd33e475ccddc0wrowe if (ret != EOK && ret != ENOENT) goto done;
3568de757bac0b47256647504c186d17ca272f85rbb
24b534291150023e6b68eca89ddd33e475ccddc0wrowe if (use_id_mapping) {
24b534291150023e6b68eca89ddd33e475ccddc0wrowe if (sid_str == NULL) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz DEBUG(SSSDBG_MINOR_FAILURE, ("No SID for group [%s] " \
3568de757bac0b47256647504c186d17ca272f85rbb "while id-mapping.\n",
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz groupname));
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ret = EINVAL;
3568de757bac0b47256647504c186d17ca272f85rbb goto done;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz }
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
3568de757bac0b47256647504c186d17ca272f85rbb DEBUG(SSSDBG_TRACE_LIBS,
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ("Mapping group [%s] objectSID to unix ID\n", groupname));
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
3568de757bac0b47256647504c186d17ca272f85rbb DEBUG(SSSDBG_TRACE_INTERNAL,
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ("Group [%s] has objectSID [%s]\n",
3568de757bac0b47256647504c186d17ca272f85rbb groupname, sid_str));
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb /* Convert the SID into a UNIX group ID */
3568de757bac0b47256647504c186d17ca272f85rbb ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, sid_str,
3568de757bac0b47256647504c186d17ca272f85rbb &gid);
3568de757bac0b47256647504c186d17ca272f85rbb if (ret == EOK) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz DEBUG(SSSDBG_TRACE_INTERNAL,
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ("Group [%s] has mapped gid [%lu]\n",
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz groupname, (unsigned long)gid));
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz } else {
3568de757bac0b47256647504c186d17ca272f85rbb posix = false;
3568de757bac0b47256647504c186d17ca272f85rbb gid = 0;
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb DEBUG(SSSDBG_TRACE_INTERNAL,
3568de757bac0b47256647504c186d17ca272f85rbb ("Group [%s] cannot be mapped. "
3568de757bac0b47256647504c186d17ca272f85rbb "Treating as a non-POSIX group\n",
3568de757bac0b47256647504c186d17ca272f85rbb groupname));
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz }
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb } else {
3568de757bac0b47256647504c186d17ca272f85rbb ret = sysdb_attrs_get_uint32_t(ldap_groups[ai],
3568de757bac0b47256647504c186d17ca272f85rbb SYSDB_GIDNUM,
3568de757bac0b47256647504c186d17ca272f85rbb &gid);
3568de757bac0b47256647504c186d17ca272f85rbb if (ret == ENOENT || (ret == EOK && gid == 0)) {
3568de757bac0b47256647504c186d17ca272f85rbb DEBUG(SSSDBG_TRACE_LIBS, ("The group %s gid was %s\n",
3fa816e4832a1c70600bdfd6fc5ef60e9f1c18bbsf groupname, ret == ENOENT ? "missing" : "zero"));
397df70abe0bdd78a84fb6c38c02641bcfeadceasf DEBUG(SSSDBG_TRACE_FUNC,
397df70abe0bdd78a84fb6c38c02641bcfeadceasf ("Marking group %s as non-posix and setting GID=0!\n",
397df70abe0bdd78a84fb6c38c02641bcfeadceasf groupname));
397df70abe0bdd78a84fb6c38c02641bcfeadceasf gid = 0;
3568de757bac0b47256647504c186d17ca272f85rbb posix = false;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding } else if (ret) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding DEBUG(1, ("The GID attribute is malformed\n"));
3568de757bac0b47256647504c186d17ca272f85rbb goto done;
239f998fbee5ac5b114b965bb76e217cce0003edstoddard }
78ae889ffe0fdfab72f56c6993b0f302cb48da55rbb }
d69e1ed15b5db3d832c1f6c8c403ef397248857atrawick
6653a33e820463abd4f81915b7a1eba0f602e200brianp ret = sysdb_attrs_get_string(ldap_groups[ai],
6653a33e820463abd4f81915b7a1eba0f602e200brianp SYSDB_ORIG_DN,
6653a33e820463abd4f81915b7a1eba0f602e200brianp &original_dn);
41634f717c623556a16b27b25d7d909a66fe20f8wrowe if (ret) {
41634f717c623556a16b27b25d7d909a66fe20f8wrowe DEBUG(5, ("The group has no name original DN\n"));
6653a33e820463abd4f81915b7a1eba0f602e200brianp original_dn = NULL;
3568de757bac0b47256647504c186d17ca272f85rbb }
6653a33e820463abd4f81915b7a1eba0f602e200brianp
6653a33e820463abd4f81915b7a1eba0f602e200brianp DEBUG(SSSDBG_TRACE_INTERNAL,
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm ("Adding fake group %s to sysdb\n", groupname));
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm ret = sysdb_add_incomplete_group(sysdb, domain, groupname, gid,
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick original_dn, sid_str, posix,
36c8049de63c446926139936c3d195330a0539cetrawick now);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf if (ret != EOK) {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf goto done;
3568de757bac0b47256647504c186d17ca272f85rbb }
dd028aa8111afb6534fece555e8c2d408894671etrawick break;
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin }
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin }
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin if (ai == ldap_groups_count) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding DEBUG(2, ("Group %s not present in LDAP\n", missing[i]));
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin ret = EINVAL;
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin goto done;
ca53a74f4012a45cbad48e940eddf27d866981f9dougm }
ca53a74f4012a45cbad48e940eddf27d866981f9dougm }
ca53a74f4012a45cbad48e940eddf27d866981f9dougm
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin ret = sysdb_transaction_commit(sysdb);
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin if (ret != EOK) {
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin DEBUG(SSSDBG_CRIT_FAILURE, ("sysdb_transaction_commit failed.\n"));
d90b36a9e6f6ea9a583694f4db5e5edd54a750b3minfrin goto done;
dd028aa8111afb6534fece555e8c2d408894671etrawick }
dd028aa8111afb6534fece555e8c2d408894671etrawick in_transaction = false;
6653a33e820463abd4f81915b7a1eba0f602e200brianp ret = EOK;
6653a33e820463abd4f81915b7a1eba0f602e200brianp
6653a33e820463abd4f81915b7a1eba0f602e200brianpdone:
6653a33e820463abd4f81915b7a1eba0f602e200brianp if (in_transaction) {
6653a33e820463abd4f81915b7a1eba0f602e200brianp sret = sysdb_transaction_cancel(sysdb);
6653a33e820463abd4f81915b7a1eba0f602e200brianp if (sret != EOK) {
6653a33e820463abd4f81915b7a1eba0f602e200brianp DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to cancel transaction\n"));
6653a33e820463abd4f81915b7a1eba0f602e200brianp }
6653a33e820463abd4f81915b7a1eba0f602e200brianp }
6653a33e820463abd4f81915b7a1eba0f602e200brianp talloc_free(tmp_ctx);
6653a33e820463abd4f81915b7a1eba0f602e200brianp return ret;
6653a33e820463abd4f81915b7a1eba0f602e200brianp}
6653a33e820463abd4f81915b7a1eba0f602e200brianp
6653a33e820463abd4f81915b7a1eba0f602e200brianpint sdap_initgr_common_store(struct sysdb_ctx *sysdb,
6653a33e820463abd4f81915b7a1eba0f602e200brianp struct sss_domain_info *domain,
6653a33e820463abd4f81915b7a1eba0f602e200brianp struct sdap_options *opts,
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick const char *name,
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick enum sysdb_member_type type,
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf char **sysdb_grouplist,
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf struct sysdb_attrs **ldap_groups,
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf int ldap_groups_count)
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf{
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick TALLOC_CTX *tmp_ctx;
239f998fbee5ac5b114b965bb76e217cce0003edstoddard char **ldap_grouplist = NULL;
3568de757bac0b47256647504c186d17ca272f85rbb char **add_groups;
3568de757bac0b47256647504c186d17ca272f85rbb char **del_groups;
3568de757bac0b47256647504c186d17ca272f85rbb int ret, tret;
185aa71728867671e105178b4c66fbc22b65ae26sf bool in_transaction = false;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard tmp_ctx = talloc_new(NULL);
3568de757bac0b47256647504c186d17ca272f85rbb if (!tmp_ctx) return ENOMEM;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
48d2edbfb84e5559b5da0f8d614ccab805cc67a8rbb if (ldap_groups_count == 0) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding /* No groups for this user in LDAP.
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * We need to ensure that there are no groups
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding * in the sysdb either.
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton */
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding ldap_grouplist = NULL;
3568de757bac0b47256647504c186d17ca272f85rbb } else {
3568de757bac0b47256647504c186d17ca272f85rbb ret = sysdb_attrs_primary_name_list(
3568de757bac0b47256647504c186d17ca272f85rbb sysdb, tmp_ctx,
3568de757bac0b47256647504c186d17ca272f85rbb ldap_groups, ldap_groups_count,
3568de757bac0b47256647504c186d17ca272f85rbb opts->group_map[SDAP_AT_GROUP_NAME].name,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard &ldap_grouplist);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if (ret != EOK) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz DEBUG(1, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ret, strerror(ret)));
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard goto done;
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem }
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem }
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem /* Find the differences between the sysdb and LDAP lists
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem * Groups in the sysdb only must be removed.
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem */
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem ret = diff_string_lists(tmp_ctx, ldap_grouplist, sysdb_grouplist,
e2de0e939faab767454a164c7d2e8ea710fd1a26sf &add_groups, &del_groups, NULL);
e2de0e939faab767454a164c7d2e8ea710fd1a26sf if (ret != EOK) goto done;
e2de0e939faab767454a164c7d2e8ea710fd1a26sf
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ret = sysdb_transaction_start(sysdb);
9f979f5c8061f6f6f560d1824e0e378ff5b91931rpluem if (ret != EOK) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard DEBUG(1, ("Failed to start transaction\n"));
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard goto done;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard }
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard in_transaction = true;
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard /* Add fake entries for any groups the user should be added as
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard * member of but that are not cached in sysdb
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard */
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if (add_groups && add_groups[0]) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ret = sdap_add_incomplete_groups(sysdb, domain, opts,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard add_groups, ldap_groups,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ldap_groups_count);
3568de757bac0b47256647504c186d17ca272f85rbb if (ret != EOK) {
3568de757bac0b47256647504c186d17ca272f85rbb DEBUG(1, ("Adding incomplete users failed\n"));
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick goto done;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick }
7cd5419264796cfeaf8215383cf0f89130a81fectrawick }
7cd5419264796cfeaf8215383cf0f89130a81fectrawick
7cd5419264796cfeaf8215383cf0f89130a81fectrawick DEBUG(8, ("Updating memberships for %s\n", name));
e8f95a682820a599fe41b22977010636be5c2717jim ret = sysdb_update_members(sysdb, domain, name, type,
98cd3186185bb28ae6c95a3f159899fcf56a663ftrawick (const char *const *) add_groups,
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf (const char *const *) del_groups);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf if (ret != EOK) {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf DEBUG(1, ("Membership update failed [%d]: %s\n",
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf ret, strerror(ret)));
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick goto done;
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick }
3568de757bac0b47256647504c186d17ca272f85rbb
a72ba68ecbbc61e4b513e50d6000245c33f753dcwrowe ret = sysdb_transaction_commit(sysdb);
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm if (ret != EOK) {
397df70abe0bdd78a84fb6c38c02641bcfeadceasf DEBUG(1, ("Failed to commit transaction\n"));
397df70abe0bdd78a84fb6c38c02641bcfeadceasf goto done;
397df70abe0bdd78a84fb6c38c02641bcfeadceasf }
397df70abe0bdd78a84fb6c38c02641bcfeadceasf in_transaction = false;
397df70abe0bdd78a84fb6c38c02641bcfeadceasf
397df70abe0bdd78a84fb6c38c02641bcfeadceasf ret = EOK;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantzdone:
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm if (in_transaction) {
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm tret = sysdb_transaction_cancel(sysdb);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf if (tret != EOK) {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf DEBUG(1, ("Failed to cancel transaction\n"));
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf }
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf }
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf talloc_zfree(tmp_ctx);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf return ret;
3cbd177a6c885562f9ad0cf11695f044489c881dgregames}
3cbd177a6c885562f9ad0cf11695f044489c881dgregames
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf/* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307===================== */
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
49aa87d735a13ae3d04012ee0df91ddb51f7c36esfstruct sdap_initgr_rfc2307_state {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf struct tevent_context *ev;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf struct sysdb_ctx *sysdb;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf struct sss_domain_info *domain;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf struct sdap_options *opts;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf struct sdap_handle *sh;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf const char **attrs;
5a0f707b48da7703cbe6bc087f13a6735b1c742dgregames const char *name;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz const char *base_filter;
5a0f707b48da7703cbe6bc087f13a6735b1c742dgregames const char *orig_dn;
5a0f707b48da7703cbe6bc087f13a6735b1c742dgregames char *filter;
5a0f707b48da7703cbe6bc087f13a6735b1c742dgregames int timeout;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm struct sdap_op *op;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz struct sysdb_attrs **ldap_groups;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard size_t ldap_groups_count;
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddard
7cd5419264796cfeaf8215383cf0f89130a81fectrawick size_t base_iter;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick struct sdap_search_base **search_bases;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick};
7cd5419264796cfeaf8215383cf0f89130a81fectrawick
7cd5419264796cfeaf8215383cf0f89130a81fectrawickstatic errno_t sdap_initgr_rfc2307_next_base(struct tevent_req *req);
7cd5419264796cfeaf8215383cf0f89130a81fectrawickstatic void sdap_initgr_rfc2307_process(struct tevent_req *subreq);
7cd5419264796cfeaf8215383cf0f89130a81fectrawickstruct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,
7cd5419264796cfeaf8215383cf0f89130a81fectrawick struct tevent_context *ev,
7cd5419264796cfeaf8215383cf0f89130a81fectrawick struct sdap_options *opts,
4f017cb91aa6591385966ccaf0c326e6b2f2c2b8sf struct sysdb_ctx *sysdb,
7cd5419264796cfeaf8215383cf0f89130a81fectrawick struct sss_domain_info *domain,
7cd5419264796cfeaf8215383cf0f89130a81fectrawick struct sdap_handle *sh,
7cd5419264796cfeaf8215383cf0f89130a81fectrawick const char *name)
7cd5419264796cfeaf8215383cf0f89130a81fectrawick{
7cd5419264796cfeaf8215383cf0f89130a81fectrawick struct tevent_req *req;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick struct sdap_initgr_rfc2307_state *state;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick const char **attr_filter;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick char *clean_name;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick errno_t ret;
4f017cb91aa6591385966ccaf0c326e6b2f2c2b8sf
7cd5419264796cfeaf8215383cf0f89130a81fectrawick req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);
7cd5419264796cfeaf8215383cf0f89130a81fectrawick if (!req) return NULL;
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddard
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz state->ev = ev;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->opts = opts;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->sysdb = sysdb;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz state->domain = domain;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->sh = sh;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->op = NULL;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->ldap_groups = NULL;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->ldap_groups_count = 0;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->base_iter = 0;
3568de757bac0b47256647504c186d17ca272f85rbb state->search_bases = opts->sdom->group_search_bases;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick
7cd5419264796cfeaf8215383cf0f89130a81fectrawick if (!state->search_bases) {
7cd5419264796cfeaf8215383cf0f89130a81fectrawick DEBUG(SSSDBG_CRIT_FAILURE,
7cd5419264796cfeaf8215383cf0f89130a81fectrawick ("Initgroups lookup request without a group search base\n"));
7cd5419264796cfeaf8215383cf0f89130a81fectrawick ret = EINVAL;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick goto done;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm }
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb state->name = talloc_strdup(state, name);
74fd6d9aeadb9022086259c5c1ae00bc0dda9c9astoddard if (!state->name) {
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp talloc_zfree(req);
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp return NULL;
3568de757bac0b47256647504c186d17ca272f85rbb }
3568de757bac0b47256647504c186d17ca272f85rbb
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard attr_filter = talloc_array(state, const char *, 2);
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf if (!attr_filter) {
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf talloc_free(req);
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf return NULL;
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf }
ddf3c03e4798f13fe6eea22039864261ea09da18sf
b5ffe4f30780fb159db08bd9f628980d2a092711sf attr_filter[0] = opts->group_map[SDAP_AT_GROUP_MEMBER].name;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard attr_filter[1] = NULL;
1ce78cf71b5baaf2c1ab48e818cb1f2397df5010trawick
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ret = build_attrs_from_map(state, opts->group_map, SDAP_OPTS_GROUP,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard attr_filter, &state->attrs, NULL);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if (ret != EOK) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz talloc_free(req);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz return NULL;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard }
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ret = sss_filter_sanitize(state, name, &clean_name);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (ret != EOK) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard talloc_free(req);
01d315c948a50cb511dbaee108b9571ee9a4d287jim return NULL;
01d315c948a50cb511dbaee108b9571ee9a4d287jim }
01d315c948a50cb511dbaee108b9571ee9a4d287jim
dd028aa8111afb6534fece555e8c2d408894671etrawick state->base_filter = talloc_asprintf(state,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard "(&(%s=%s)(objectclass=%s)(%s=*)(&(%s=*)(!(%s=0))))",
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard opts->group_map[SDAP_AT_GROUP_MEMBER].name,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard clean_name,
3568de757bac0b47256647504c186d17ca272f85rbb opts->group_map[SDAP_OC_GROUP].name,
3568de757bac0b47256647504c186d17ca272f85rbb opts->group_map[SDAP_AT_GROUP_NAME].name,
3568de757bac0b47256647504c186d17ca272f85rbb opts->group_map[SDAP_AT_GROUP_GID].name,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard opts->group_map[SDAP_AT_GROUP_GID].name);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (!state->base_filter) {
f714f1a7002928d785e53e70349700a7f595fee3trawick talloc_zfree(req);
f714f1a7002928d785e53e70349700a7f595fee3trawick return NULL;
3568de757bac0b47256647504c186d17ca272f85rbb }
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddard talloc_zfree(clean_name);
4a13940dc2990df0a798718d3a3f9cf1566c2217bjh
4a13940dc2990df0a798718d3a3f9cf1566c2217bjh ret = sdap_initgr_rfc2307_next_base(req);
4a13940dc2990df0a798718d3a3f9cf1566c2217bjh
4a13940dc2990df0a798718d3a3f9cf1566c2217bjhdone:
3568de757bac0b47256647504c186d17ca272f85rbb if (ret != EOK) {
3568de757bac0b47256647504c186d17ca272f85rbb tevent_req_error(req, ret);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard tevent_req_post(req, ev);
663237d6bcc59ac0997d71d48a1baa55fa29a3d8jim }
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard return req;
3568de757bac0b47256647504c186d17ca272f85rbb}
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddardstatic errno_t sdap_initgr_rfc2307_next_base(struct tevent_req *req)
663237d6bcc59ac0997d71d48a1baa55fa29a3d8jim{
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard struct tevent_req *subreq;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard struct sdap_initgr_rfc2307_state *state;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard talloc_zfree(state->filter);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->filter = sdap_get_id_specific_filter(
3568de757bac0b47256647504c186d17ca272f85rbb state, state->base_filter,
ad83978f20c7d1a4323059d9af122e56fcd353bdstoddard state->search_bases[state->base_iter]->filter);
4a13940dc2990df0a798718d3a3f9cf1566c2217bjh if (!state->filter) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard return ENOMEM;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard }
3568de757bac0b47256647504c186d17ca272f85rbb
4a13940dc2990df0a798718d3a3f9cf1566c2217bjh DEBUG(SSSDBG_TRACE_FUNC,
4a13940dc2990df0a798718d3a3f9cf1566c2217bjh ("Searching for groups with base [%s]\n",
4a13940dc2990df0a798718d3a3f9cf1566c2217bjh state->search_bases[state->base_iter]->basedn));
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb subreq = sdap_get_generic_send(
663237d6bcc59ac0997d71d48a1baa55fa29a3d8jim state, state->ev, state->opts, state->sh,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->search_bases[state->base_iter]->basedn,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->search_bases[state->base_iter]->scope,
3568de757bac0b47256647504c186d17ca272f85rbb state->filter, state->attrs,
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz state->opts->group_map, SDAP_OPTS_GROUP,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->timeout,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard true);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard if (!subreq) {
3568de757bac0b47256647504c186d17ca272f85rbb return ENOMEM;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard }
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard tevent_req_set_callback(subreq, sdap_initgr_rfc2307_process, req);
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard return EOK;
3568de757bac0b47256647504c186d17ca272f85rbb}
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantzstatic void sdap_initgr_rfc2307_process(struct tevent_req *subreq)
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz{
3568de757bac0b47256647504c186d17ca272f85rbb struct tevent_req *req;
3568de757bac0b47256647504c186d17ca272f85rbb struct sdap_initgr_rfc2307_state *state;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz struct sysdb_attrs **ldap_groups;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz char **sysdb_grouplist = NULL;
3568de757bac0b47256647504c186d17ca272f85rbb size_t count;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard int ret;
3568de757bac0b47256647504c186d17ca272f85rbb int i;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf req = tevent_req_callback_data(subreq, struct tevent_req);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf ret = sdap_get_generic_recv(subreq, state, &count, &ldap_groups);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf talloc_zfree(subreq);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf if (ret) {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf tevent_req_error(req, ret);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf return;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf }
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf /* Add this batch of groups to the list */
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf if (count > 0) {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf state->ldap_groups =
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf talloc_realloc(state,
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf state->ldap_groups,
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf struct sysdb_attrs *,
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf state->ldap_groups_count + count + 1);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf if (!state->ldap_groups) {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf tevent_req_error(req, ENOMEM);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf return;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf }
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf /* Copy the new groups into the list.
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf */
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf for (i = 0; i < count; i++) {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf state->ldap_groups[state->ldap_groups_count + i] =
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf talloc_steal(state->ldap_groups, ldap_groups[i]);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf }
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf state->ldap_groups_count += count;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf state->ldap_groups[state->ldap_groups_count] = NULL;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf }
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf state->base_iter++;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf /* Check for additional search bases, and iterate
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf * through again.
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf */
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf if (state->search_bases[state->base_iter] != NULL) {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf ret = sdap_initgr_rfc2307_next_base(req);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf if (ret != EOK) {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf tevent_req_error(req, ret);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf }
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf return;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf }
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf /* Search for all groups for which this user is a member */
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf ret = get_sysdb_grouplist(state, state->sysdb, state->domain,
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf state->name, &sysdb_grouplist);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf if (ret != EOK) {
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf tevent_req_error(req, ret);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf return;
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf }
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf /* There are no nested groups here so we can just update the
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf * memberships */
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf ret = sdap_initgr_common_store(state->sysdb,
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf state->domain,
3568de757bac0b47256647504c186d17ca272f85rbb state->opts,
3568de757bac0b47256647504c186d17ca272f85rbb state->name,
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf SYSDB_MEMBER_USER,
3568de757bac0b47256647504c186d17ca272f85rbb sysdb_grouplist,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard state->ldap_groups,
3568de757bac0b47256647504c186d17ca272f85rbb state->ldap_groups_count);
d69e1ed15b5db3d832c1f6c8c403ef397248857atrawick if (ret != EOK) {
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick tevent_req_error(req, ret);
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick return;
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick }
d69e1ed15b5db3d832c1f6c8c403ef397248857atrawick
d69e1ed15b5db3d832c1f6c8c403ef397248857atrawick tevent_req_done(req);
d69e1ed15b5db3d832c1f6c8c403ef397248857atrawick}
d69e1ed15b5db3d832c1f6c8c403ef397248857atrawick
d69e1ed15b5db3d832c1f6c8c403ef397248857atrawickstatic int sdap_initgr_rfc2307_recv(struct tevent_req *req)
d69e1ed15b5db3d832c1f6c8c403ef397248857atrawick{
d69e1ed15b5db3d832c1f6c8c403ef397248857atrawick TEVENT_REQ_RETURN_ON_ERROR(req);
beb70d51e435dc36c56a72b6cd83556c04db9283wrowe
fe6baec9bbcd36f932b71a355120cd7b5a685d6cfielding return EOK;
3568de757bac0b47256647504c186d17ca272f85rbb}
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf
3568de757bac0b47256647504c186d17ca272f85rbb/* ==Common code for pure RFC2307bis and IPA/AD========================= */
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddardstatic errno_t
3568de757bac0b47256647504c186d17ca272f85rbbsdap_nested_groups_store(struct sysdb_ctx *sysdb,
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf struct sss_domain_info *domain,
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf struct sdap_options *opts,
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf struct sysdb_attrs **groups,
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf unsigned long count)
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf{
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf errno_t ret, tret;
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf TALLOC_CTX *tmp_ctx;
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf char **groupnamelist = NULL;
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf bool in_transaction = false;
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf tmp_ctx = talloc_new(NULL);
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf if (!tmp_ctx) return ENOMEM;
ee3abe0378785ceef4780586ca309ef2ef60f431trawick
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf if (count > 0) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ret = sysdb_attrs_primary_name_list(sysdb, tmp_ctx,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard groups, count,
8e9734d1a4af74c141e2a0f880bb51bb061fa03atrawick opts->group_map[SDAP_AT_GROUP_NAME].name,
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf &groupnamelist);
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf if (ret != EOK) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard DEBUG(3, ("sysdb_attrs_primary_name_list failed [%d]: %s\n",
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick ret, strerror(ret)));
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick goto done;
3568de757bac0b47256647504c186d17ca272f85rbb }
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard }
cb97ae2ff6969c2789b8e03f1bc4187fa73b6bafwrowe
0f113d7123e8bd3e3e2e9b6373461a1a773bfccatrawick ret = sysdb_transaction_start(sysdb);
0f113d7123e8bd3e3e2e9b6373461a1a773bfccatrawick if (ret != EOK) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz DEBUG(1, ("Failed to start transaction\n"));
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard goto done;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard }
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard in_transaction = true;
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard ret = sdap_add_incomplete_groups(sysdb, domain, opts, groupnamelist,
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard groups, count);
3568de757bac0b47256647504c186d17ca272f85rbb if (ret != EOK) {
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard DEBUG(6, ("Could not add incomplete groups [%d]: %s\n",
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ret, strerror(ret)));
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf goto done;
8dfa8c6f60f12e0b65eebbb652b629f911f0f84bsf }
c0659e61002e9d6ff77b2dca72540e0af1b2ca64stoddard
3568de757bac0b47256647504c186d17ca272f85rbb ret = sysdb_transaction_commit(sysdb);
3568de757bac0b47256647504c186d17ca272f85rbb if (ret != EOK) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick DEBUG(1, ("Failed to commit transaction\n"));
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick goto done;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick in_transaction = false;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ret = EOK;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawickdone:
f886987cd0bd4220c14043c4d9be77ec22902e73trawick if (in_transaction) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick tret = sysdb_transaction_cancel(sysdb);
f886987cd0bd4220c14043c4d9be77ec22902e73trawick if (tret != EOK) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick DEBUG(1, ("Failed to cancel transaction\n"));
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz talloc_free(tmp_ctx);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz return ret;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz}
a72ba68ecbbc61e4b513e50d6000245c33f753dcwrowe
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawickstruct membership_diff {
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm struct membership_diff *prev;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm struct membership_diff *next;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick const char *name;
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick char **add;
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick char **del;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm};
3568de757bac0b47256647504c186d17ca272f85rbb
64c351fd973428b5bb4c28e983fa86875ea4e60fdougmstatic errno_t
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantzbuild_membership_diff(TALLOC_CTX *mem_ctx, const char *name,
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz char **ldap_parent_names, char **sysdb_parent_names,
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz struct membership_diff **_mdiff)
e8f95a682820a599fe41b22977010636be5c2717jim{
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm TALLOC_CTX *tmp_ctx;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz struct membership_diff *mdiff;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz errno_t ret;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz char **add_groups;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm char **del_groups;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm tmp_ctx = talloc_new(NULL);
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm if (!tmp_ctx) {
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm ret = ENOMEM;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm goto done;
36c8049de63c446926139936c3d195330a0539cetrawick }
36c8049de63c446926139936c3d195330a0539cetrawick
36c8049de63c446926139936c3d195330a0539cetrawick mdiff = talloc_zero(tmp_ctx, struct membership_diff);
36c8049de63c446926139936c3d195330a0539cetrawick if (!mdiff) {
36c8049de63c446926139936c3d195330a0539cetrawick ret = ENOMEM;
36c8049de63c446926139936c3d195330a0539cetrawick goto done;
36c8049de63c446926139936c3d195330a0539cetrawick }
36c8049de63c446926139936c3d195330a0539cetrawick mdiff->name = talloc_strdup(mdiff, name);
e8f95a682820a599fe41b22977010636be5c2717jim if (!mdiff->name) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ret = ENOMEM;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm goto done;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
36c8049de63c446926139936c3d195330a0539cetrawick /* Find the differences between the sysdb and ldap lists
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * Groups in ldap only must be added to the sysdb;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * groups in the sysdb only must be removed.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ret = diff_string_lists(tmp_ctx,
cb97ae2ff6969c2789b8e03f1bc4187fa73b6bafwrowe ldap_parent_names, sysdb_parent_names,
36c8049de63c446926139936c3d195330a0539cetrawick &add_groups, &del_groups, NULL);
36c8049de63c446926139936c3d195330a0539cetrawick if (ret != EOK) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick goto done;
e8f95a682820a599fe41b22977010636be5c2717jim }
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm mdiff->add = talloc_steal(mdiff, add_groups);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick mdiff->del = talloc_steal(mdiff, del_groups);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ret = EOK;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick *_mdiff = talloc_steal(mem_ctx, mdiff);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawickdone:
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick talloc_free(tmp_ctx);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick return ret;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick}
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick/* ==Initgr-call-(groups-a-user-is-member-of)-nested-groups=============== */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawickstruct sdap_initgr_nested_state {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct tevent_context *ev;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct sysdb_ctx *sysdb;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct sdap_options *opts;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct sss_domain_info *dom;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct sdap_handle *sh;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct sysdb_attrs *user;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick const char *username;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick const char *orig_dn;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick const char **grp_attrs;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct ldb_message_element *memberof;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick char *filter;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick char **group_dns;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick int cur;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct sdap_op *op;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct sysdb_attrs **groups;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick int groups_cur;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick};
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawickstatic errno_t sdap_initgr_nested_deref_search(struct tevent_req *req);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawickstatic errno_t sdap_initgr_nested_noderef_search(struct tevent_req *req);
e8f95a682820a599fe41b22977010636be5c2717jimstatic void sdap_initgr_nested_search(struct tevent_req *subreq);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawickstatic void sdap_initgr_nested_store(struct tevent_req *req);
f886987cd0bd4220c14043c4d9be77ec22902e73trawickstatic struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct tevent_context *ev,
f886987cd0bd4220c14043c4d9be77ec22902e73trawick struct sdap_options *opts,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct sysdb_ctx *sysdb,
f886987cd0bd4220c14043c4d9be77ec22902e73trawick struct sss_domain_info *dom,
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm struct sdap_handle *sh,
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm struct sysdb_attrs *user,
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm const char **grp_attrs)
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm{
3568de757bac0b47256647504c186d17ca272f85rbb struct tevent_req *req;
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp struct sdap_initgr_nested_state *state;
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp errno_t ret;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick int deref_threshold;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick req = tevent_req_create(memctx, &state, struct sdap_initgr_nested_state);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (!req) return NULL;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->ev = ev;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->opts = opts;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->sysdb = sysdb;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->dom = dom;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->sh = sh;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->grp_attrs = grp_attrs;
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm state->user = user;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->op = NULL;
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton
f2e009134c7e279f99dfca5bd421f721bf1f7840jorton ret = sdap_get_user_primary_name(memctx, opts, user, dom, &state->username);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (ret != EOK) {
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm DEBUG(SSSDBG_CRIT_FAILURE, ("User entry had no username\n"));
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick goto immediate;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick ret = sysdb_attrs_get_el(state->user, SYSDB_MEMBEROF, &state->memberof);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (ret || !state->memberof || state->memberof->num_values == 0) {
36c8049de63c446926139936c3d195330a0539cetrawick DEBUG(4, ("User entry lacks original memberof ?\n"));
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick /* We can't find any groups for this user, so we'll
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick * have to assume there aren't any. Just return
f886987cd0bd4220c14043c4d9be77ec22902e73trawick * success here.
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick */
cb97ae2ff6969c2789b8e03f1bc4187fa73b6bafwrowe ret = EOK;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick goto immediate;
36c8049de63c446926139936c3d195330a0539cetrawick }
36c8049de63c446926139936c3d195330a0539cetrawick
36c8049de63c446926139936c3d195330a0539cetrawick state->groups = talloc_zero_array(state, struct sysdb_attrs *,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->memberof->num_values + 1);;
e8f95a682820a599fe41b22977010636be5c2717jim if (!state->groups) {
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm ret = ENOMEM;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick goto immediate;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->groups_cur = 0;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick deref_threshold = dp_opt_get_int(state->opts->basic,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick SDAP_DEREF_THRESHOLD);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (sdap_has_deref_support(state->sh, state->opts) &&
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick deref_threshold < state->memberof->num_values) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ret = sysdb_attrs_get_string(user, SYSDB_ORIG_DN,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick &state->orig_dn);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (ret != EOK) goto immediate;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ret = sdap_initgr_nested_deref_search(req);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (ret != EAGAIN) goto immediate;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick } else {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick ret = sdap_initgr_nested_noderef_search(req);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (ret != EAGAIN) goto immediate;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick return req;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawickimmediate:
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (ret == EOK) {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick tevent_req_done(req);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick } else {
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick tevent_req_error(req, ret);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick tevent_req_post(req, ev);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick return req;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick}
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawickstatic errno_t sdap_initgr_nested_noderef_search(struct tevent_req *req)
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick{
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick int i;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct tevent_req *subreq;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick struct sdap_initgr_nested_state *state;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
e8f95a682820a599fe41b22977010636be5c2717jim state = tevent_req_data(req, struct sdap_initgr_nested_state);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->group_dns = talloc_array(state, char *,
f886987cd0bd4220c14043c4d9be77ec22902e73trawick state->memberof->num_values + 1);
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick if (!state->group_dns) {
f886987cd0bd4220c14043c4d9be77ec22902e73trawick return ENOMEM;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
f886987cd0bd4220c14043c4d9be77ec22902e73trawick for (i = 0; i < state->memberof->num_values; i++) {
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm state->group_dns[i] = talloc_strdup(state->group_dns,
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm (char *)state->memberof->values[i].data);
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm if (!state->group_dns[i]) {
64c351fd973428b5bb4c28e983fa86875ea4e60fdougm return ENOMEM;
3568de757bac0b47256647504c186d17ca272f85rbb }
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp }
72b6f1cf3e616473e1c26464b3193b13c2c09e87brianp state->group_dns[i] = NULL; /* terminate */
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->cur = 0;
e8f95a682820a599fe41b22977010636be5c2717jim
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->filter = talloc_asprintf(state, "(&(objectclass=%s)(%s=*))",
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->opts->group_map[SDAP_OC_GROUP].name,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick state->opts->group_map[SDAP_AT_GROUP_NAME].name);
e8f95a682820a599fe41b22977010636be5c2717jim if (!state->filter) {
44d2e75323651320b480d8bc2f098448a08de4fcwrowe return ENOMEM;
44d2e75323651320b480d8bc2f098448a08de4fcwrowe }
44d2e75323651320b480d8bc2f098448a08de4fcwrowe
44d2e75323651320b480d8bc2f098448a08de4fcwrowe subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
44d2e75323651320b480d8bc2f098448a08de4fcwrowe state->group_dns[state->cur],
44d2e75323651320b480d8bc2f098448a08de4fcwrowe LDAP_SCOPE_BASE,
44d2e75323651320b480d8bc2f098448a08de4fcwrowe state->filter, state->grp_attrs,
5bfaaf573bacb45c1cf290ce85ecc676587e8a64jim state->opts->group_map, SDAP_OPTS_GROUP,
44d2e75323651320b480d8bc2f098448a08de4fcwrowe dp_opt_get_int(state->opts->basic,
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick SDAP_SEARCH_TIMEOUT),
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick false);
2e7f1d7da527c09e717251e186deffe55e6fbd0ftrawick if (!subreq) {
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz return ENOMEM;
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick }
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe
3568de757bac0b47256647504c186d17ca272f85rbb return EAGAIN;
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe}
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowestatic void sdap_initgr_nested_deref_done(struct tevent_req *subreq);
f886987cd0bd4220c14043c4d9be77ec22902e73trawick
f886987cd0bd4220c14043c4d9be77ec22902e73trawickstatic errno_t sdap_initgr_nested_deref_search(struct tevent_req *req)
f886987cd0bd4220c14043c4d9be77ec22902e73trawick{
f886987cd0bd4220c14043c4d9be77ec22902e73trawick struct tevent_req *subreq;
f886987cd0bd4220c14043c4d9be77ec22902e73trawick struct sdap_attr_map_info *maps;
f886987cd0bd4220c14043c4d9be77ec22902e73trawick const int num_maps = 1;
f886987cd0bd4220c14043c4d9be77ec22902e73trawick const char **sdap_attrs;
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe errno_t ret;
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe int timeout;
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe struct sdap_initgr_nested_state *state;
1ec8bd0373f11c07688ec9afbbf778cf78a0bc52wrowe
3568de757bac0b47256647504c186d17ca272f85rbb state = tevent_req_data(req, struct sdap_initgr_nested_state);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
8bfe865d8d61be4ba4a89e45427a3c4211ebabdctrawick maps = talloc_array(state, struct sdap_attr_map_info, num_maps+1);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz if (!maps) return ENOMEM;
3568de757bac0b47256647504c186d17ca272f85rbb
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz maps[0].map = state->opts->group_map;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz maps[0].num_attrs = SDAP_OPTS_GROUP;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz maps[1].map = NULL;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ret = build_attrs_from_map(state, state->opts->group_map, SDAP_OPTS_GROUP,
3568de757bac0b47256647504c186d17ca272f85rbb NULL, &sdap_attrs, NULL);
3568de757bac0b47256647504c186d17ca272f85rbb if (ret != EOK) goto fail;
98fb535f829e2a95aabd82420931f476661fa8e3jorton
98fb535f829e2a95aabd82420931f476661fa8e3jorton timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT);
e8f95a682820a599fe41b22977010636be5c2717jim
e8f95a682820a599fe41b22977010636be5c2717jim subreq = sdap_deref_search_send(state, state->ev, state->opts,
98fb535f829e2a95aabd82420931f476661fa8e3jorton state->sh, state->orig_dn,
98fb535f829e2a95aabd82420931f476661fa8e3jorton state->opts->user_map[SDAP_AT_USER_MEMBEROF].name,
e8f95a682820a599fe41b22977010636be5c2717jim sdap_attrs, num_maps, maps, timeout);
98fb535f829e2a95aabd82420931f476661fa8e3jorton if (!subreq) {
98fb535f829e2a95aabd82420931f476661fa8e3jorton ret = EIO;
98fb535f829e2a95aabd82420931f476661fa8e3jorton goto fail;
3568de757bac0b47256647504c186d17ca272f85rbb }
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz talloc_steal(subreq, sdap_attrs);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz talloc_steal(subreq, maps);
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb tevent_req_set_callback(subreq, sdap_initgr_nested_deref_done, req);
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding return EAGAIN;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding
0f081398cf0eef8cc7c66a535d450110a92dc8aefieldingfail:
85c5af648e9f414bd4f157490766d2fd5515a9f5rpluem talloc_free(sdap_attrs);
0cb6873985efbf0cc9644114925df6baa4b32d5awrowe talloc_free(maps);
0cb6873985efbf0cc9644114925df6baa4b32d5awrowe return ret;
0cb6873985efbf0cc9644114925df6baa4b32d5awrowe}
0cb6873985efbf0cc9644114925df6baa4b32d5awrowe
0cb6873985efbf0cc9644114925df6baa4b32d5awrowestatic void sdap_initgr_nested_deref_done(struct tevent_req *subreq)
0cb6873985efbf0cc9644114925df6baa4b32d5awrowe{
0cb6873985efbf0cc9644114925df6baa4b32d5awrowe errno_t ret;
85c5af648e9f414bd4f157490766d2fd5515a9f5rpluem struct tevent_req *req;
0cb6873985efbf0cc9644114925df6baa4b32d5awrowe struct sdap_initgr_nested_state *state;
3568de757bac0b47256647504c186d17ca272f85rbb size_t num_results;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz size_t i;
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz struct sdap_deref_attrs **deref_result;
3568de757bac0b47256647504c186d17ca272f85rbb
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz req = tevent_req_callback_data(subreq, struct tevent_req);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz state = tevent_req_data(req, struct sdap_initgr_nested_state);
3568de757bac0b47256647504c186d17ca272f85rbb
3568de757bac0b47256647504c186d17ca272f85rbb ret = sdap_deref_search_recv(subreq, state,
3568de757bac0b47256647504c186d17ca272f85rbb &num_results,
3568de757bac0b47256647504c186d17ca272f85rbb &deref_result);
3568de757bac0b47256647504c186d17ca272f85rbb talloc_zfree(subreq);
3568de757bac0b47256647504c186d17ca272f85rbb if (ret == ENOTSUP) {
ec020ca384efb30d501a5af796ddc3bb237d7b8fgregames ret = sdap_initgr_nested_noderef_search(req);
3568de757bac0b47256647504c186d17ca272f85rbb if (ret != EAGAIN) {
ce03576b2434cec77f2921db9d5b6a0510581c23rederpj if (ret == EOK) {
397df70abe0bdd78a84fb6c38c02641bcfeadceasf tevent_req_done(req);
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick } else {
cd8f8c995d415473f3bfb0b329b2450f2a722c3atrawick tevent_req_error(req, ret);
397df70abe0bdd78a84fb6c38c02641bcfeadceasf }
397df70abe0bdd78a84fb6c38c02641bcfeadceasf }
397df70abe0bdd78a84fb6c38c02641bcfeadceasf return;
397df70abe0bdd78a84fb6c38c02641bcfeadceasf } else if (ret != EOK && ret != ENOENT) {
397df70abe0bdd78a84fb6c38c02641bcfeadceasf tevent_req_error(req, ret);
49aa87d735a13ae3d04012ee0df91ddb51f7c36esf return;
9d0665da83d1e22c0ea0e5f6f940f70f75bf5237ianh } else if (ret == ENOENT || deref_result == NULL) {
3568de757bac0b47256647504c186d17ca272f85rbb /* Nothing could be dereferenced. Done. */
3568de757bac0b47256647504c186d17ca272f85rbb tevent_req_done(req);
7cd5419264796cfeaf8215383cf0f89130a81fectrawick return;
7cd5419264796cfeaf8215383cf0f89130a81fectrawick }
7cd5419264796cfeaf8215383cf0f89130a81fectrawick
7cd5419264796cfeaf8215383cf0f89130a81fectrawick for (i=0; i < num_results; i++) {
7cd5419264796cfeaf8215383cf0f89130a81fectrawick state->groups[i] = talloc_steal(state->groups,
7cd5419264796cfeaf8215383cf0f89130a81fectrawick deref_result[i]->attrs);
7cd5419264796cfeaf8215383cf0f89130a81fectrawick }
73e8b26287de5c06fa470d36162e103dbac9c7e5wrowe
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding state->groups_cur = num_results;
b980ad7fdc218b4855cde9f75a747527f50c554dwrowe sdap_initgr_nested_store(req);
0cb6873985efbf0cc9644114925df6baa4b32d5awrowe}
3568de757bac0b47256647504c186d17ca272f85rbb
7cd5419264796cfeaf8215383cf0f89130a81fectrawickstatic void sdap_initgr_nested_search(struct tevent_req *subreq)
7cd5419264796cfeaf8215383cf0f89130a81fectrawick{
7cd5419264796cfeaf8215383cf0f89130a81fectrawick struct tevent_req *req;
ca53a74f4012a45cbad48e940eddf27d866981f9dougm struct sdap_initgr_nested_state *state;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding struct sysdb_attrs **groups;
36ef8f77bffe75d1aa327882be1b5bdbe2ff567asf size_t count;
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding int ret;
302dc1f7b3feee23a91ad8f3cf3cb2edd95a557bmanoj
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz req = tevent_req_callback_data(subreq, struct tevent_req);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz state = tevent_req_data(req, struct sdap_initgr_nested_state);
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz
28c170ac8e99644de58cad454c6e0f9b4b359be6jerenkrantz ret = sdap_get_generic_recv(subreq, state, &count, &groups);
0cb6873985efbf0cc9644114925df6baa4b32d5awrowe talloc_zfree(subreq);
3568de757bac0b47256647504c186d17ca272f85rbb if (ret) {
0f081398cf0eef8cc7c66a535d450110a92dc8aefielding tevent_req_error(req, ret);
3568de757bac0b47256647504c186d17ca272f85rbb return;
}
if (count == 1) {
state->groups[state->groups_cur] = talloc_steal(state->groups,
groups[0]);
state->groups_cur++;
} else {
DEBUG(SSSDBG_OP_FAILURE,
("Search for group %s, returned %zu 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->dom,
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 = NULL;
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, state->dom, 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->dom,
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 = sdap_get_group_primary_name(tmp_ctx, opts, group, dom, &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;
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 sdap_domain *sdom,
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;
bool use_id_mapping;
req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307bis_state);
if (!req) return NULL;
state->ev = ev;
state->opts = opts;
state->sysdb = sdom->dom->sysdb;
state->dom = sdom->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 = sdom->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;
use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
opts->idmap_ctx,
sdom->dom->name,
sdom->dom->domain_id);
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;
}
if (use_id_mapping) {
/* When mapping IDs or looking for SIDs, we don't want to limit
* ourselves to groups with a GID value. But there must be a SID to map
* from.
*/
state->base_filter = talloc_asprintf_append(state->base_filter,
"(%s=*))",
opts->group_map[SDAP_AT_GROUP_OBJECTSID].name);
} else {
/* When not ID-mapping, make sure there is a non-NULL UID */
state->base_filter = talloc_asprintf_append(state->base_filter,
"(&(%s=*)(!(%s=0))))",
opts->group_map[SDAP_AT_GROUP_GID].name,
opts->group_map[SDAP_AT_GROUP_GID].name);
}
if (!state->base_filter) {
talloc_zfree(req);
return NULL;
}
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 %zu 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->dom, 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;
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++);
add = talloc_zero_array(tmp_ctx, 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;
}
}
}
if (num_added == 0) {
add = NULL;
} else {
add[num_added] = NULL;
}
ret = sysdb_update_members(state->sysdb, state->dom, 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;
size_t c;
char *tmp_str;
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;
}
if (IS_SUBDOMAIN(state->dom)) {
for (c = 0; ldap_grouplist[c] != NULL; c++) {
tmp_str = sss_tc_fqname(ldap_grouplist, state->dom->names,
state->dom, ldap_grouplist[c]);
if (tmp_str == NULL) {
DEBUG(SSSDBG_OP_FAILURE, ("sss_tc_fqname failed.\n"));
ret = ENOMEM;
goto error;
}
talloc_free(ldap_grouplist[c]);
ldap_grouplist[c] = tmp_str;
}
}
}
/* 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->dom,
state->name, SYSDB_MEMBER_USER,
(const char *const *)add_groups,
(const char *const *)del_groups);
if (ret != EOK) {
goto error;
}
ret = sysdb_transaction_commit(state->sysdb);
if (ret != EOK) {
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 %zu groups in nesting level %zu\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->sdom->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 = sdap_get_group_primary_name(state, state->opts,
state->groups[state->group_iter],
state->dom, &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 %zu 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 %zu 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_domain *sdom;
struct sdap_handle *sh;
struct sdap_id_ctx *id_ctx;
struct sdap_id_conn_ctx *conn;
const char *name;
const char **grp_attrs;
const char **user_attrs;
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;
bool use_id_mapping;
};
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_domain *sdom,
struct sdap_handle *sh,
struct sdap_id_ctx *id_ctx,
struct sdap_id_conn_ctx *conn,
const char *name,
const char **grp_attrs)
{
struct tevent_req *req;
struct sdap_get_initgr_state *state;
int ret;
char *clean_name;
bool use_id_mapping;
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->dom = sdom->dom;
state->sysdb = sdom->dom->sysdb;
state->sdom = sdom;
state->sh = sh;
state->id_ctx = id_ctx;
state->conn = conn;
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 = sdom->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;
}
use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
id_ctx->opts->idmap_ctx,
sdom->dom->name,
sdom->dom->domain_id);
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;
}
if (use_id_mapping) {
/* When mapping IDs or looking for SIDs, we don't want to limit
* ourselves to users with a UID value. But there must be a SID to map
* from.
*/
state->user_base_filter = talloc_asprintf_append(state->user_base_filter,
"(%s=*))",
id_ctx->opts->user_map[SDAP_AT_USER_OBJECTSID].name);
} else {
/* When not ID-mapping, make sure there is a non-NULL UID */
state->user_base_filter = talloc_asprintf_append(state->user_base_filter,
"(&(%s=*)(!(%s=0))))",
id_ctx->opts->user_map[SDAP_AT_USER_UID].name,
id_ctx->opts->user_map[SDAP_AT_USER_UID].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;
}
state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
state->opts->idmap_ctx,
state->dom->name,
state->dom->domain_id);
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 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;
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;
}
/* fallback to fetch a local user if required */
if ((state->opts->schema_type == SDAP_SCHEMA_RFC2307) &&
(dp_opt_get_bool(state->opts->basic,
SDAP_RFC2307_FALLBACK_TO_LOCAL_USERS) == true)) {
ret = sdap_fallback_local_user(state, state->opts,
state->name, -1, &usr_attrs);
} else {
ret = ENOENT;
}
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
} else if (count != 1) {
DEBUG(SSSDBG_OP_FAILURE,
("Expected one user entry and got %zu\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->dom, 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 (state->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->sdom, 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 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;
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 (state->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 (state->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, group_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,
state->id_ctx->opts->sdom, state->conn,
gid, BE_FILTER_IDNUM, BE_ATTR_ALL, NULL);
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, NULL);
talloc_zfree(subreq);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}
tevent_req_done(req);
}
int sdap_get_initgr_recv(struct tevent_req *req)
{
TEVENT_REQ_RETURN_ON_ERROR(req);
return EOK;
}
static errno_t get_sysdb_grouplist_ex(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
const char *name,
char ***grouplist,
bool get_dn)
{
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;
}
if (get_dn) {
/* Get distinguish name */
for (i=0; i < groups->num_values; i++) {
sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist,
(const char *)groups->values[i].data);
if (sysdb_grouplist[i] == NULL) {
ret = ENOMEM;
goto done;
}
}
} else {
/* 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;
}
errno_t get_sysdb_grouplist(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
const char *name,
char ***grouplist)
{
return get_sysdb_grouplist_ex(mem_ctx, sysdb, domain,
name, grouplist, false);
}
errno_t get_sysdb_grouplist_dn(TALLOC_CTX *mem_ctx,
struct sysdb_ctx *sysdb,
struct sss_domain_info *domain,
const char *name,
char ***grouplist)
{
return get_sysdb_grouplist_ex(mem_ctx, sysdb, domain,
name, grouplist, true);
}