summaryrefslogtreecommitdiff
path: root/src/providers
diff options
context:
space:
mode:
authorSumit Bose <sbose@redhat.com>2010-10-05 13:51:05 +0200
committerStephen Gallagher <sgallagh@redhat.com>2010-10-13 09:49:38 -0400
commit619bd403265ce0880989ba6f8324b010949851bc (patch)
tree84c7a2373bc26b8b5c42e94814f2933146d76634 /src/providers
parentd9ed57c641b91c9c499a53329d606d5061ed47d1 (diff)
downloadsssd-619bd403265ce0880989ba6f8324b010949851bc.tar.gz
sssd-619bd403265ce0880989ba6f8324b010949851bc.tar.bz2
sssd-619bd403265ce0880989ba6f8324b010949851bc.zip
Implement netgroup support for LDAP provider
Diffstat (limited to 'src/providers')
-rw-r--r--src/providers/ldap/ldap_common.h6
-rw-r--r--src/providers/ldap/ldap_id.c26
-rw-r--r--src/providers/ldap/ldap_id_netgroup.c224
-rw-r--r--src/providers/ldap/sdap_async.h14
-rw-r--r--src/providers/ldap/sdap_async_netgroups.c713
5 files changed, 982 insertions, 1 deletions
diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h
index e2d74e41..63192fb4 100644
--- a/src/providers/ldap/ldap_common.h
+++ b/src/providers/ldap/ldap_common.h
@@ -133,6 +133,12 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
int attrs_type);
int groups_get_recv(struct tevent_req *req, int *dp_error_out);
+
+struct tevent_req *netgroup_get_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx,
+ const char *name);
+int netgroup_get_recv(struct tevent_req *req, int *dp_error_out);
/* setup child logging */
int setup_child(struct sdap_id_ctx *ctx);
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index 0c90773a..be4642aa 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -647,6 +647,7 @@ int groups_by_user_recv(struct tevent_req *req, int *dp_error_out)
static void sdap_account_info_users_done(struct tevent_req *req);
static void sdap_account_info_groups_done(struct tevent_req *req);
static void sdap_account_info_initgr_done(struct tevent_req *req);
+static void sdap_account_info_netgroups_done(struct tevent_req *req);
void sdap_account_info_handler(struct be_req *breq)
{
@@ -728,6 +729,21 @@ void sdap_account_info_handler(struct be_req *breq)
break;
+ case BE_REQ_NETGROUP:
+ if (ar->filter_type != BE_FILTER_NAME) {
+ ret = EINVAL;
+ err = "Invalid filter type";
+ break;
+ }
+
+ req = netgroup_get_send(breq, breq->be_ctx->ev, ctx, ar->filter_value);
+ if (!req) {
+ return sdap_handler_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory");
+ }
+
+ tevent_req_set_callback(req, sdap_account_info_netgroups_done, breq);
+ break;
+
default: /*fail*/
ret = EINVAL;
err = "Invalid request type";
@@ -793,3 +809,13 @@ static void sdap_account_info_initgr_done(struct tevent_req *req)
sdap_account_info_complete(breq, dp_error, ret, "Init Groups Failed");
}
+static void sdap_account_info_netgroups_done(struct tevent_req *req)
+{
+ struct be_req *breq = tevent_req_callback_data(req, struct be_req);
+ int ret, dp_error;
+
+ ret = netgroup_get_recv(req, &dp_error);
+ talloc_zfree(req);
+
+ sdap_account_info_complete(breq, dp_error, ret, "Netgroup lookup failed");
+}
diff --git a/src/providers/ldap/ldap_id_netgroup.c b/src/providers/ldap/ldap_id_netgroup.c
new file mode 100644
index 00000000..c82ccc43
--- /dev/null
+++ b/src/providers/ldap/ldap_id_netgroup.c
@@ -0,0 +1,224 @@
+/*
+ SSSD
+
+ LDAP Identity Backend Module - Netgroup support
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2010 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <errno.h>
+
+#include "util/util.h"
+#include "db/sysdb.h"
+#include "providers/ldap/ldap_common.h"
+#include "providers/ldap/sdap_async.h"
+
+
+struct netgroup_get_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *ctx;
+ struct sdap_id_op *op;
+ struct sysdb_ctx *sysdb;
+ struct sss_domain_info *domain;
+
+ const char *name;
+
+ char *filter;
+ const char **attrs;
+
+ size_t count;
+ struct sysdb_attrs **netgroups;
+
+ int dp_error;
+};
+
+static int netgroup_get_retry(struct tevent_req *req);
+static void netgroup_get_connect_done(struct tevent_req *subreq);
+static void netgroup_get_done(struct tevent_req *subreq);
+
+struct tevent_req *netgroup_get_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx,
+ const char *name)
+{
+ struct tevent_req *req;
+ struct netgroup_get_state *state;
+ int ret;
+
+ req = tevent_req_create(memctx, &state, struct netgroup_get_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->ctx = ctx;
+ state->dp_error = DP_ERR_FATAL;
+
+ state->op = sdap_id_op_create(state, state->ctx->conn_cache);
+ if (!state->op) {
+ DEBUG(2, ("sdap_id_op_create failed\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ state->sysdb = ctx->be->sysdb;
+ state->domain = state->ctx->be->domain;
+ state->name = name;
+
+ state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
+ ctx->opts->netgroup_map[SDAP_AT_NETGROUP_NAME].name,
+ name,
+ ctx->opts->netgroup_map[SDAP_OC_NETGROUP].name);
+ if (!state->filter) {
+ DEBUG(2, ("Failed to build filter\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = build_attrs_from_map(state, ctx->opts->netgroup_map,
+ SDAP_OPTS_NETGROUP, &state->attrs);
+ if (ret != EOK) goto fail;
+
+ ret = netgroup_get_retry(req);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static int netgroup_get_retry(struct tevent_req *req)
+{
+ struct netgroup_get_state *state = tevent_req_data(req,
+ struct netgroup_get_state);
+ struct tevent_req *subreq;
+ int ret = EOK;
+
+ subreq = sdap_id_op_connect_send(state->op, state, &ret);
+ if (!subreq) {
+ return ret;
+ }
+
+ tevent_req_set_callback(subreq, netgroup_get_connect_done, req);
+ return EOK;
+}
+
+static void netgroup_get_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netgroup_get_state *state = tevent_req_data(req,
+ struct netgroup_get_state);
+ int dp_error = DP_ERR_FATAL;
+ int ret;
+
+ ret = sdap_id_op_connect_recv(subreq, &dp_error);
+ talloc_zfree(subreq);
+
+ if (ret != EOK) {
+ state->dp_error = dp_error;
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = sdap_get_netgroups_send(state, state->ev,
+ state->domain, state->sysdb,
+ state->ctx->opts,
+ sdap_id_op_handle(state->op),
+ state->attrs, state->filter);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, netgroup_get_done, req);
+
+ return;
+}
+
+static void netgroup_get_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netgroup_get_state *state = tevent_req_data(req,
+ struct netgroup_get_state);
+ int dp_error = DP_ERR_FATAL;
+ int ret;
+
+ ret = sdap_get_netgroups_recv(subreq, state, NULL, &state->count,
+ &state->netgroups);
+ talloc_zfree(subreq);
+ ret = sdap_id_op_done(state->op, ret, &dp_error);
+
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = netgroup_get_retry(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ return;
+ }
+
+ if (ret && ret != ENOENT) {
+ state->dp_error = dp_error;
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (ret == EOK && state->count > 1) {
+ DEBUG(1, ("Found more than one netgroup with the name [%s].\n",
+ state->name));
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+
+ if (ret == ENOENT) {
+ ret = sysdb_delete_netgroup(state->sysdb, state->domain, state->name);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ state->dp_error = DP_ERR_OK;
+ tevent_req_error(req, ENOENT);
+ return;
+ }
+
+ state->dp_error = DP_ERR_OK;
+ tevent_req_done(req);
+ return;
+}
+
+int netgroup_get_recv(struct tevent_req *req, int *dp_error_out)
+{
+ struct netgroup_get_state *state = tevent_req_data(req,
+ struct netgroup_get_state);
+
+ if (dp_error_out) {
+ *dp_error_out = state->dp_error;
+ }
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 20888011..bf54bbd1 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -59,6 +59,19 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
int sdap_get_groups_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx, char **timestamp);
+struct tevent_req *sdap_get_netgroups_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sss_domain_info *dom,
+ struct sysdb_ctx *sysdb,
+ struct sdap_options *opts,
+ struct sdap_handle *sh,
+ const char **attrs,
+ const char *wildcard);
+int sdap_get_netgroups_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx, char **timestamp,
+ size_t *reply_count,
+ struct sysdb_attrs ***reply);
+
struct tevent_req *sdap_kinit_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
struct be_ctx *be,
@@ -135,5 +148,4 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
int sdap_get_generic_recv(struct tevent_req *req,
TALLOC_CTX *mem_ctx, size_t *reply_count,
struct sysdb_attrs ***reply_list);
-
#endif /* _SDAP_ASYNC_H_ */
diff --git a/src/providers/ldap/sdap_async_netgroups.c b/src/providers/ldap/sdap_async_netgroups.c
new file mode 100644
index 00000000..5f6ad059
--- /dev/null
+++ b/src/providers/ldap/sdap_async_netgroups.c
@@ -0,0 +1,713 @@
+/*
+ SSSD
+
+ Async LDAP Helper routines for netgroups
+
+ Authors:
+ Sumit Bose <sbose@redhat.com>
+
+ Copyright (C) 2010 Red Hat
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "util/util.h"
+#include "db/sysdb.h"
+#include "providers/ldap/sdap_async_private.h"
+
+static bool is_dn(const char *str)
+{
+ int ret;
+ LDAPDN dn;
+
+ ret = ldap_str2dn(str, &dn, LDAP_DN_FORMAT_LDAPV3);
+ return (ret == LDAP_SUCCESS ? true : false);
+}
+
+static errno_t sdap_save_netgroup(TALLOC_CTX *memctx,
+ struct sysdb_ctx *ctx,
+ struct sdap_options *opts,
+ struct sss_domain_info *dom,
+ struct sysdb_attrs *attrs,
+ char **_timestamp)
+{
+ struct ldb_message_element *el;
+ struct sysdb_attrs *netgroup_attrs;
+ const char *name = NULL;
+ int ret;
+ char *timestamp = NULL;
+ size_t c;
+
+ ret = sysdb_attrs_get_el(attrs,
+ opts->netgroup_map[SDAP_AT_NETGROUP_NAME].sys_name,
+ &el);
+ if (ret) goto fail;
+ if (el->num_values == 0) {
+ ret = EINVAL;
+ goto fail;
+ }
+ name = (const char *)el->values[0].data;
+
+ netgroup_attrs = sysdb_new_attrs(memctx);
+ if (!netgroup_attrs) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &el);
+ if (ret) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("Original DN is not available for [%s].\n", name));
+ } else {
+ DEBUG(7, ("Adding original DN [%s] to attributes of [%s].\n",
+ el->values[0].data, name));
+ ret = sysdb_attrs_add_string(netgroup_attrs, SYSDB_ORIG_DN,
+ (const char *)el->values[0].data);
+ if (ret) {
+ goto fail;
+ }
+ }
+
+ ret = sysdb_attrs_get_el(attrs,
+ opts->netgroup_map[SDAP_AT_NETGROUP_MODSTAMP].sys_name,
+ &el);
+ if (ret) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
+ name));
+ } else {
+ ret = sysdb_attrs_add_string(netgroup_attrs,
+ opts->netgroup_map[SDAP_AT_NETGROUP_MODSTAMP].sys_name,
+ (const char*)el->values[0].data);
+ if (ret) {
+ goto fail;
+ }
+ timestamp = talloc_strdup(memctx, (const char*)el->values[0].data);
+ if (!timestamp) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ }
+
+ ret = sysdb_attrs_get_el(attrs,
+ opts->netgroup_map[SDAP_AT_NETGROUP_TRIPLE].sys_name,
+ &el);
+ if (ret) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("No netgroup triples for netgroup [%s].\n", name));
+ } else {
+ for(c = 0; c < el->num_values; c++) {
+ ret = sysdb_attrs_add_string(netgroup_attrs,
+ opts->netgroup_map[SDAP_AT_NETGROUP_TRIPLE].sys_name,
+ (const char*)el->values[c].data);
+ if (ret) {
+ goto fail;
+ }
+ }
+ }
+
+ ret = sysdb_attrs_get_el(attrs,
+ opts->netgroup_map[SDAP_AT_NETGROUP_MEMBER].sys_name,
+ &el);
+ if (ret != EOK) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("No original members for netgroup [%s]\n", name));
+
+ } else {
+ DEBUG(7, ("Adding original members to netgroup [%s]\n", name));
+ for(c = 0; c < el->num_values; c++) {
+ ret = sysdb_attrs_add_string(netgroup_attrs,
+ opts->netgroup_map[SDAP_AT_NETGROUP_MEMBER].sys_name,
+ (const char*)el->values[c].data);
+ if (ret) {
+ goto fail;
+ }
+ }
+ }
+
+
+ ret = sysdb_attrs_get_el(attrs, SYSDB_NETGROUP_MEMBER, &el);
+ if (ret != EOK) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("No members for netgroup [%s]\n", name));
+
+ } else {
+ DEBUG(7, ("Adding members to netgroup [%s]\n", name));
+ for(c = 0; c < el->num_values; c++) {
+ ret = sysdb_attrs_add_string(netgroup_attrs, SYSDB_NETGROUP_MEMBER,
+ (const char*)el->values[c].data);
+ if (ret) {
+ goto fail;
+ }
+ }
+ }
+
+ DEBUG(6, ("Storing info for netgroup %s\n", name));
+
+ ret = sysdb_add_netgroup(ctx, dom, name, NULL, netgroup_attrs,
+ dp_opt_get_int(opts->basic,
+ SDAP_ENTRY_CACHE_TIMEOUT));
+ if (ret) goto fail;
+
+ if (_timestamp) {
+ *_timestamp = timestamp;
+ }
+
+ return EOK;
+
+fail:
+ DEBUG(2, ("Failed to save netgroup %s\n", name));
+ return ret;
+}
+
+struct dn_item {
+ const char *dn;
+ struct sysdb_attrs *netgroup;
+ char *cn;
+ struct dn_item *next;
+ struct dn_item *prev;
+};
+
+static errno_t update_dn_list(struct dn_item *dn_list, const size_t count,
+ struct ldb_message **res, bool *all_resolved)
+{
+ struct dn_item *dn_item;
+ size_t c;
+ const char *dn;
+ const char *cn;
+ bool not_resolved = false;
+
+ *all_resolved = false;
+
+ DLIST_FOR_EACH(dn_item, dn_list) {
+ if (dn_item->cn != NULL) {
+ continue;
+ }
+
+ for(c = 0; c < count; c++) {
+ dn = ldb_msg_find_attr_as_string(res[c], SYSDB_ORIG_DN, NULL);
+ if (dn == NULL) {
+ DEBUG(1, ("Missing original DN.\n"));
+ return EINVAL;
+ }
+ if (strcmp(dn, dn_item->dn) == 0) {
+ DEBUG(9, ("Found matching entry for [%s].\n", dn_item->dn));
+ cn = ldb_msg_find_attr_as_string(res[c], SYSDB_NAME, NULL);
+ if (cn == NULL) {
+ DEBUG(1, ("Missing name.\n"));
+ return EINVAL;
+ }
+ dn_item->cn = talloc_strdup(dn_item, cn);
+ break;
+ }
+ }
+
+ not_resolved = true;
+ }
+
+ *all_resolved = !not_resolved;
+
+ return EOK;
+}
+
+struct netgr_translate_members_state {
+ struct tevent_context *ev;
+ struct sdap_options *opts;
+ struct sdap_handle *sh;
+ struct sss_domain_info *dom;
+ struct sysdb_ctx *sysdb;
+
+ struct sysdb_attrs **netgroups;
+ size_t count;
+ struct dn_item *dn_list;
+ struct dn_item *dn_item;
+ struct dn_item *dn_idx;
+};
+
+static errno_t netgr_translate_members_ldap_step(struct tevent_req *req);
+static void netgr_translate_members_ldap_done(struct tevent_req *subreq);
+
+struct tevent_req *netgr_translate_members_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sdap_handle *sh,
+ struct sss_domain_info *dom,
+ struct sysdb_ctx *sysdb,
+ const size_t count,
+ struct sysdb_attrs **netgroups)
+{
+ struct tevent_req *req;
+ struct netgr_translate_members_state *state;
+ size_t c;
+ size_t mc;
+ const char **member_list;
+ size_t sysdb_count;
+ int ret;
+ struct ldb_message **sysdb_res;
+ struct dn_item *dn_item;
+ char *dn_filter;
+ char *sysdb_filter;
+ struct ldb_dn *netgr_basedn;
+ bool all_resolved;
+ const char *cn_attr[] = { SYSDB_NAME, SYSDB_ORIG_DN, NULL };
+
+ req = tevent_req_create(memctx, &state,
+ struct netgr_translate_members_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->opts = opts;
+ state->dom = dom;
+ state->sh = sh;
+ state->sysdb = sysdb;
+ state->netgroups = netgroups;
+ state->count = count;
+ state->dn_list = NULL;
+ state->dn_item = NULL;
+ state->dn_idx = NULL;
+
+ for (c = 0; c < count; c++) {
+ ret = sysdb_attrs_get_string_array(netgroups[c],
+ SYSDB_ORIG_NETGROUP_MEMBER, state,
+ &member_list);
+ if (ret != EOK) {
+ DEBUG(7, ("Missing netgroup members.\n"));
+ continue;
+ }
+
+ for (mc = 0; member_list[mc] != NULL; mc++) {
+ if (is_dn(member_list[mc])) {
+ dn_item = talloc_zero(state, struct dn_item);
+ if (dn_item == NULL) {
+ DEBUG(1, ("talloc failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ DEBUG(9, ("Adding [%s] to DN list.\n", member_list[mc]));
+ dn_item->netgroup = netgroups[c];
+ dn_item->dn = member_list[mc];
+ DLIST_ADD(state->dn_list, dn_item);
+ } else {
+ ret = sysdb_attrs_add_string(netgroups[c], SYSDB_NETGROUP_MEMBER,
+ member_list[mc]);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_add_string failed.\n"));
+ goto fail;
+ }
+ }
+ }
+ }
+
+ if (state->dn_list == NULL) {
+ DEBUG(9, ("No DNs found among netgroup members.\n"));
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ return req;
+ }
+
+ dn_filter = talloc_strdup(state, "(|");
+ if (dn_filter == NULL) {
+ DEBUG(1, ("talloc_strdup failed.\n"));
+ ret = ENOMEM;;
+ goto fail;
+ }
+
+ DLIST_FOR_EACH(dn_item, state->dn_list) {
+ dn_filter = talloc_asprintf_append(dn_filter, "(%s=%s)",
+ SYSDB_ORIG_DN, dn_item->dn);
+ if (dn_filter == NULL) {
+ DEBUG(1, ("talloc_asprintf_append failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+ }
+
+ dn_filter = talloc_asprintf_append(dn_filter, ")");
+ if (dn_filter == NULL) {
+ DEBUG(1, ("talloc_asprintf_append failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ sysdb_filter = talloc_asprintf(state, "(&(%s)%s)", SYSDB_NC, dn_filter);
+ if (sysdb_filter == NULL) {
+ DEBUG(1, ("talloc_asprintf failed.\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ netgr_basedn = sysdb_netgroup_base_dn(sysdb, state, dom->name);
+ if (netgr_basedn == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = sysdb_search_entry(state, sysdb, netgr_basedn, LDB_SCOPE_BASE,
+ sysdb_filter, cn_attr, &sysdb_count, &sysdb_res);
+ talloc_zfree(netgr_basedn);
+ talloc_zfree(sysdb_filter);
+ if (ret != EOK && ret != ENOENT) {
+ DEBUG(1, ("sysdb_search_entry failed.\n"));
+ goto fail;
+ }
+
+ if (ret == EOK) {
+ ret = update_dn_list(state->dn_list, sysdb_count, sysdb_res,
+ &all_resolved);
+ if (ret != EOK) {
+ DEBUG(1, ("update_dn_list failed.\n"));
+ goto fail;
+ }
+
+ if (all_resolved) {
+ DLIST_FOR_EACH(dn_item, state->dn_list) {
+ ret = sysdb_attrs_add_string(dn_item->netgroup,
+ SYSDB_NETGROUP_MEMBER,
+ dn_item->cn);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_add_string failed.\n"));
+ goto fail;
+ }
+ }
+
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ return req;
+ }
+ }
+
+ state->dn_idx = state->dn_list;
+ ret = netgr_translate_members_ldap_step(req);
+ if (ret != EOK && ret != EAGAIN) {
+ DEBUG(1, ("netgr_translate_members_ldap_step failed.\n"));
+ goto fail;
+ }
+
+ if (ret == EOK) {
+ tevent_req_done(req);
+ tevent_req_post(req, ev);
+ }
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+/* netgr_translate_members_ldap_step() returns
+ * EOK: if everthing is translated, the caller can call tevent_req_done
+ * EAGAIN: if there are still members waiting to be translated, the caller
+ * should return to the mainloop
+ * Exyz: every other return code indicates an error and tevent_req_error
+ * should be called
+ */
+static errno_t netgr_translate_members_ldap_step(struct tevent_req *req)
+{
+ struct netgr_translate_members_state *state = tevent_req_data(req,
+ struct netgr_translate_members_state);
+ const char **cn_attr;
+ struct tevent_req *subreq;
+ int ret;
+
+ DLIST_FOR_EACH(state->dn_item, state->dn_idx) {
+ if (state->dn_item->cn == NULL) {
+ break;
+ }
+ }
+ if (state->dn_item == NULL) {
+ DLIST_FOR_EACH(state->dn_item, state->dn_list) {
+ ret = sysdb_attrs_add_string(state->dn_item->netgroup,
+ SYSDB_NETGROUP_MEMBER,
+ state->dn_item->cn);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_add_string failed.\n"));
+ tevent_req_error(req, ret);
+ return ret;
+ }
+ }
+
+ return EOK;
+ }
+
+ cn_attr = talloc_array(state, const char *, 3);
+ if (cn_attr == NULL) {
+ DEBUG(1, ("talloc_array failed.\n"));
+ return ENOMEM;
+ }
+ cn_attr[0] = state->opts->netgroup_map[SDAP_AT_NETGROUP_NAME].name;
+ cn_attr[1] = "objectclass";
+ cn_attr[2] = NULL;
+
+ DEBUG(9, ("LDAP base search for [%s].\n", state->dn_item->dn));
+ subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
+ state->dn_item->dn, LDAP_SCOPE_BASE, NULL,
+ cn_attr, state->opts->netgroup_map,
+ SDAP_OPTS_NETGROUP);
+ if (!subreq) {
+ DEBUG(1, ("sdap_get_generic_send failed.\n"));
+ return ENOMEM;
+ }
+ talloc_steal(subreq, cn_attr);
+
+ tevent_req_set_callback(subreq, netgr_translate_members_ldap_done, req);
+ return EAGAIN;
+}
+
+static void netgr_translate_members_ldap_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct netgr_translate_members_state *state = tevent_req_data(req,
+ struct netgr_translate_members_state);
+ int ret;
+ size_t count;
+ struct sysdb_attrs **netgroups;
+ const char *str;
+
+ ret = sdap_get_generic_recv(subreq, state, &count, &netgroups);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(1, ("sdap_get_generic request failed.\n"));
+ goto fail;
+ }
+
+ switch (count) {
+ case 0:
+ DEBUG(0, ("sdap_get_generic_recv found no entry for [%s].\n",
+ state->dn_item->dn));
+ break;
+ case 1:
+ ret = sysdb_attrs_get_string(netgroups[0], SYSDB_NAME, &str);
+ if (ret != EOK) {
+ DEBUG(1, ("sysdb_attrs_add_string failed.\n"));
+ break;
+ }
+ state->dn_item->cn = talloc_strdup(state->dn_item, str);
+ if (state->dn_item->cn == NULL) {
+ DEBUG(1, ("talloc_strdup failed.\n"));
+ }
+ break;
+ default:
+ DEBUG(1, ("Unexpected number of results [%d] for base search.\n",
+ count));
+ }
+
+ if (state->dn_item->cn == NULL) {
+ DEBUG(1, ("Failed to resolve netgroup name for DN [%s], using DN.\n",
+ state->dn_item->dn));
+ state->dn_item->cn = talloc_strdup(state->dn_item, state->dn_item->dn);
+ }
+
+ state->dn_idx = state->dn_item->next;
+ ret = netgr_translate_members_ldap_step(req);
+ if (ret != EOK && ret != EAGAIN) {
+ DEBUG(1, ("netgr_translate_members_ldap_step failed.\n"));
+ goto fail;
+ }
+
+ if (ret == EOK) {
+ tevent_req_done(req);
+ }
+ return;
+
+fail:
+ tevent_req_error(req, ret);
+ return;
+}
+
+static errno_t netgroup_translate_ldap_members_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ size_t *count,
+ struct sysdb_attrs ***netgroups)
+{
+ struct netgr_translate_members_state *state = tevent_req_data(req,
+ struct netgr_translate_members_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *count = state->count;
+ *netgroups = talloc_steal(mem_ctx, state->netgroups);
+
+ return EOK;
+}
+
+/* ==Search-Netgroups-with-filter============================================ */
+
+struct sdap_get_netgroups_state {
+ struct tevent_context *ev;
+ struct sdap_options *opts;
+ struct sdap_handle *sh;
+ struct sss_domain_info *dom;
+ struct sysdb_ctx *sysdb;
+ const char **attrs;
+ const char *filter;
+
+ char *higher_timestamp;
+ struct sysdb_attrs **netgroups;
+ size_t count;
+};
+
+static void sdap_get_netgroups_process(struct tevent_req *subreq);
+static void netgr_translate_members_done(struct tevent_req *subreq);
+
+struct tevent_req *sdap_get_netgroups_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sss_domain_info *dom,
+ struct sysdb_ctx *sysdb,
+ struct sdap_options *opts,
+ struct sdap_handle *sh,
+ const char **attrs,
+ const char *filter)
+{
+ struct tevent_req *req, *subreq;
+ struct sdap_get_netgroups_state *state;
+
+ req = tevent_req_create(memctx, &state, struct sdap_get_netgroups_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = opts;
+ state->dom = dom;
+ state->sh = sh;
+ state->sysdb = sysdb;
+ state->filter = filter;
+ state->attrs = attrs;
+ state->higher_timestamp = NULL;
+ state->netgroups = NULL;
+ state->count = 0;
+
+ subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
+ dp_opt_get_string(state->opts->basic,
+ SDAP_SEARCH_BASE),
+ LDAP_SCOPE_SUBTREE,
+ state->filter, state->attrs,
+ state->opts->netgroup_map,
+ SDAP_OPTS_NETGROUP);
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, sdap_get_netgroups_process, req);
+
+ return req;
+}
+
+static void sdap_get_netgroups_process(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_get_netgroups_state *state = tevent_req_data(req,
+ struct sdap_get_netgroups_state);
+ int ret;
+
+ ret = sdap_get_generic_recv(subreq, state,
+ &state->count, &state->netgroups);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(6, ("Search for netgroups, returned %d results.\n", state->count));
+
+ if (state->count == 0) {
+ tevent_req_error(req, ENOENT);
+ return;
+ }
+
+ subreq = netgr_translate_members_send(state, state->ev, state->opts,
+ state->sh, state->dom, state->sysdb,
+ state->count, state->netgroups);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, netgr_translate_members_done, req);
+
+ return;
+
+}
+
+static void netgr_translate_members_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_get_netgroups_state *state = tevent_req_data(req,
+ struct sdap_get_netgroups_state);
+ int ret;
+ size_t c;
+
+ ret = netgroup_translate_ldap_members_recv(subreq, state, &state->count,
+ &state->netgroups);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ for (c = 0; c < state->count; c++) {
+ ret = sdap_save_netgroup(state, state->sysdb,
+ state->opts, state->dom,
+ state->netgroups[c],
+ &state->higher_timestamp);
+ if (ret) {
+ DEBUG(2, ("Failed to store netgroups.\n"));
+ tevent_req_error(req, ret);
+ return;
+ }
+ }
+
+ DEBUG(9, ("Saving %d Netgroups - Done\n", state->count));
+
+ tevent_req_done(req);
+}
+
+int sdap_get_netgroups_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx, char **timestamp,
+ size_t *reply_count,
+ struct sysdb_attrs ***reply)
+{
+ struct sdap_get_netgroups_state *state = tevent_req_data(req,
+ struct sdap_get_netgroups_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ if (timestamp) {
+ *timestamp = talloc_steal(mem_ctx, state->higher_timestamp);
+ }
+
+ if (reply_count) {
+ *reply_count = state->count;
+ }
+
+ if (reply) {
+ *reply = talloc_steal(mem_ctx, state->netgroups);
+ }
+
+ return EOK;
+}