summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2009-11-05 17:00:03 -0500
committerSimo Sorce <ssorce@redhat.com>2009-11-06 17:26:09 -0500
commit1ee2b5ee491eed2bce2df3606a7a570c7ebac8ce (patch)
tree9569072485330f31855d40e58846174a944b706c
parenta6706a28c6a48d6d34a3086963bfc519de7d3f68 (diff)
downloadsssd-1ee2b5ee491eed2bce2df3606a7a570c7ebac8ce.tar.gz
sssd-1ee2b5ee491eed2bce2df3606a7a570c7ebac8ce.tar.bz2
sssd-1ee2b5ee491eed2bce2df3606a7a570c7ebac8ce.zip
Reorganize ldap id provider files
Split enum task in a separate file.
-rw-r--r--server/Makefile.am1
-rw-r--r--server/providers/ldap/ldap_common.c41
-rw-r--r--server/providers/ldap/ldap_common.h7
-rw-r--r--server/providers/ldap/ldap_id.c553
-rw-r--r--server/providers/ldap/ldap_id_enum.c529
5 files changed, 584 insertions, 547 deletions
diff --git a/server/Makefile.am b/server/Makefile.am
index 48368451..9b29350b 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -511,6 +511,7 @@ libsss_ipa_la_SOURCES = \
providers/ipa/ipa_init.c \
providers/ipa/ipa_common.c \
providers/ldap/ldap_id.c \
+ providers/ldap/ldap_id_enum.c \
providers/ldap/ldap_auth.c \
providers/ldap/ldap_common.c \
providers/ldap/sdap_async.c \
diff --git a/server/providers/ldap/ldap_common.c b/server/providers/ldap/ldap_common.c
index f7cdf75e..d8e73f71 100644
--- a/server/providers/ldap/ldap_common.c
+++ b/server/providers/ldap/ldap_common.c
@@ -264,3 +264,44 @@ void sdap_handler_done(struct be_req *req, int dp_err,
return req->fn(req, dp_err, error, errstr);
}
+bool sdap_connected(struct sdap_id_ctx *ctx)
+{
+ if (ctx->gsh) {
+ return ctx->gsh->connected;
+ }
+
+ return false;
+}
+
+void sdap_mark_offline(struct sdap_id_ctx *ctx)
+{
+ if (ctx->gsh) {
+ /* make sure we mark the connection as gone when we go offline so that
+ * we do not try to reuse a bad connection by mistale later */
+ talloc_zfree(ctx->gsh);
+ }
+
+ be_mark_offline(ctx->be);
+}
+
+
+int sdap_id_setup_tasks(struct sdap_id_ctx *ctx)
+{
+ struct tevent_timer *enum_task;
+ int ret = EOK;
+
+ /* set up enumeration task */
+ if (ctx->be->domain->enumerate) {
+ /* run the first one in a couple of seconds so that we have time to
+ * finish initializations first*/
+ ctx->last_run = tevent_timeval_current_ofs(2, 0);
+ enum_task = tevent_add_timer(ctx->be->ev, ctx, ctx->last_run,
+ ldap_id_enumerate, ctx);
+ if (!enum_task) {
+ DEBUG(0, ("FATAL: failed to setup enumeration task!\n"));
+ ret = EFAULT;
+ }
+ }
+
+ return ret;
+}
diff --git a/server/providers/ldap/ldap_common.h b/server/providers/ldap/ldap_common.h
index c9d85786..0c51428d 100644
--- a/server/providers/ldap/ldap_common.h
+++ b/server/providers/ldap/ldap_common.h
@@ -69,4 +69,11 @@ int ldap_get_options(TALLOC_CTX *memctx,
const char *conf_path,
struct sdap_options **_opts);
+void ldap_id_enumerate(struct tevent_context *ev,
+ struct tevent_timer *tt,
+ struct timeval tv, void *pvt);
+
+bool sdap_connected(struct sdap_id_ctx *ctx);
+void sdap_mark_offline(struct sdap_id_ctx *ctx);
+
#endif /* _LDAP_COMMON_H_ */
diff --git a/server/providers/ldap/ldap_id.c b/server/providers/ldap/ldap_id.c
index ba7cdab4..307f1e70 100644
--- a/server/providers/ldap/ldap_id.c
+++ b/server/providers/ldap/ldap_id.c
@@ -28,32 +28,9 @@
#include "util/util.h"
#include "db/sysdb.h"
-#include "providers/dp_backend.h"
#include "providers/ldap/ldap_common.h"
#include "providers/ldap/sdap_async.h"
-/* =Connection-handling-functions========================================= */
-
-static bool connected(struct sdap_id_ctx *ctx)
-{
- if (ctx->gsh) {
- return ctx->gsh->connected;
- }
-
- return false;
-}
-
-static void mark_offline(struct sdap_id_ctx *ctx)
-{
- if (ctx->gsh) {
- /* make sure we mark the connection as gone when we go offline so that
- * we do not try to reuse a bad connection by mistale later */
- talloc_zfree(ctx->gsh);
- }
-
- be_mark_offline(ctx->be);
-}
-
/* =Users-Related-Functions-(by-name,by-uid)============================== */
struct users_get_state {
@@ -111,7 +88,7 @@ static struct tevent_req *users_get_send(TALLOC_CTX *memctx,
SDAP_OPTS_USER, &state->attrs);
if (ret != EOK) goto fail;
- if (!connected(ctx)) {
+ if (!sdap_connected(ctx)) {
if (ctx->gsh) talloc_zfree(ctx->gsh);
@@ -218,7 +195,7 @@ static void users_get_done(struct tevent_req *req)
if (ret == ETIMEDOUT || ret == EFAULT) {
ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
struct sdap_id_ctx);
- mark_offline(ctx);
+ sdap_mark_offline(ctx);
}
}
@@ -282,7 +259,7 @@ static struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
SDAP_OPTS_GROUP, &state->attrs);
if (ret != EOK) goto fail;
- if (!connected(ctx)) {
+ if (!sdap_connected(ctx)) {
if (ctx->gsh) talloc_zfree(ctx->gsh);
@@ -389,7 +366,7 @@ static void groups_get_done(struct tevent_req *req)
if (ret == ETIMEDOUT || ret == EFAULT) {
ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
struct sdap_id_ctx);
- mark_offline(ctx);
+ sdap_mark_offline(ctx);
}
}
@@ -428,7 +405,7 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
SDAP_OPTS_GROUP, &state->attrs);
if (ret != EOK) goto fail;
- if (!connected(ctx)) {
+ if (!sdap_connected(ctx)) {
if (ctx->gsh) talloc_zfree(ctx->gsh);
@@ -535,7 +512,7 @@ static void groups_by_user_done(struct tevent_req *req)
if (ret == ETIMEDOUT || ret == EFAULT) {
ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
struct sdap_id_ctx);
- mark_offline(ctx);
+ sdap_mark_offline(ctx);
}
}
@@ -636,521 +613,3 @@ void sdap_account_info_handler(struct be_req *breq)
if (ret != EOK) return sdap_handler_done(breq, DP_ERR_FATAL, ret, err);
}
-
-/* ==Enumeration-Task===================================================== */
-
-static struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev,
- struct sdap_id_ctx *ctx);
-static void ldap_id_enumerate_reschedule(struct tevent_req *req);
-static void ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx,
- struct timeval tv);
-
-static void ldap_id_enumerate_timeout(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval tv, void *pvt);
-
-static void ldap_id_enumerate(struct tevent_context *ev,
- struct tevent_timer *tt,
- struct timeval tv, void *pvt)
-{
- struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx);
- struct tevent_timer *timeout;
- struct tevent_req *req;
- int ert;
-
- if (be_is_offline(ctx->be)) {
- DEBUG(4, ("Backend is marked offline, retry later!\n"));
- /* schedule starting from now, not the last run */
- ldap_id_enumerate_set_timer(ctx, tevent_timeval_current());
- return;
- }
-
- ctx->last_run = tv;
-
- req = ldap_id_enumerate_send(ev, ctx);
- if (!req) {
- DEBUG(1, ("Failed to schedule enumeration, retrying later!\n"));
- /* schedule starting from now, not the last run */
- ldap_id_enumerate_set_timer(ctx, tevent_timeval_current());
- return;
- }
- tevent_req_set_callback(req, ldap_id_enumerate_reschedule, ctx);
-
- /* if enumeration takes so long, either we try to enumerate too
- * frequently, or something went seriously wrong */
- tv = tevent_timeval_current();
- ert = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
- tv = tevent_timeval_add(&tv, ert, 0);
- timeout = tevent_add_timer(ctx->be->ev, req, tv,
- ldap_id_enumerate_timeout, req);
- return;
-}
-
-static void ldap_id_enumerate_timeout(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval tv, void *pvt)
-{
- struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
- struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
- struct sdap_id_ctx);
- int ert;
-
- ert = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
- DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n", ert));
- ldap_id_enumerate_set_timer(ctx, tevent_timeval_current());
-
- talloc_zfree(req);
-}
-
-static void ldap_id_enumerate_reschedule(struct tevent_req *req)
-{
- struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
- struct sdap_id_ctx);
- struct timeval tv;
- enum tevent_req_state tstate;
- uint64_t err;
-
- if (tevent_req_is_error(req, &tstate, &err)) {
- /* On error schedule starting from now, not the last run */
- tv = tevent_timeval_current();
- } else {
- tv = ctx->last_run;
- }
- talloc_zfree(req);
-
- ldap_id_enumerate_set_timer(ctx, ctx->last_run);
-}
-
-static void ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx,
- struct timeval tv)
-{
- struct tevent_timer *enum_task;
- int ert;
-
- ert = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
- tv = tevent_timeval_add(&tv, ert, 0);
- enum_task = tevent_add_timer(ctx->be->ev, ctx, tv, ldap_id_enumerate, ctx);
- if (!enum_task) {
- DEBUG(0, ("FATAL: failed to setup enumeration task!\n"));
- /* shutdown! */
- exit(1);
- }
-}
-
-
-
-struct global_enum_state {
- struct tevent_context *ev;
- struct sdap_id_ctx *ctx;
-};
-
-static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sdap_id_ctx *ctx);
-static void ldap_id_enum_users_done(struct tevent_req *subreq);
-static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sdap_id_ctx *ctx);
-static void ldap_id_enum_groups_done(struct tevent_req *subreq);
-
-static struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev,
- struct sdap_id_ctx *ctx)
-{
- struct global_enum_state *state;
- struct tevent_req *req, *subreq;
-
- req = tevent_req_create(ctx, &state, struct global_enum_state);
- if (!req) return NULL;
-
- state->ev = ev;
- state->ctx = ctx;
-
- subreq = enum_users_send(state, ev, ctx);
- if (!subreq) {
- talloc_zfree(req);
- return NULL;
- }
- tevent_req_set_callback(subreq, ldap_id_enum_users_done, req);
-
- return req;
-}
-
-static void ldap_id_enum_users_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(subreq,
- struct tevent_req);
- struct global_enum_state *state = tevent_req_data(req,
- struct global_enum_state);
- enum tevent_req_state tstate;
- uint64_t err = 0;
-
- if (tevent_req_is_error(subreq, &tstate, &err)) {
- goto fail;
- }
- talloc_zfree(subreq);
-
- subreq = enum_groups_send(state, state->ev, state->ctx);
- if (!subreq) {
- goto fail;
- }
- tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);
-
- return;
-
-fail:
- if (err) {
- DEBUG(9, ("User enumeration failed with: (%d)[%s]\n",
- (int)err, strerror(err)));
-
- mark_offline(state->ctx);
- }
-
- DEBUG(1, ("Failed to enumerate users, retrying later!\n"));
- tevent_req_done(req);
-}
-
-static void ldap_id_enum_groups_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(subreq,
- struct tevent_req);
- struct global_enum_state *state = tevent_req_data(req,
- struct global_enum_state);
- enum tevent_req_state tstate;
- uint64_t err;
-
- if (tevent_req_is_error(subreq, &tstate, &err)) {
- goto fail;
- }
- talloc_zfree(subreq);
-
- tevent_req_done(req);
- return;
-
-fail:
- /* always go offline on failures */
- mark_offline(state->ctx);
- DEBUG(1, ("Failed to enumerate groups (%d [%s]), retrying later!\n",
- (int)err, strerror(err)));
- tevent_req_done(req);
-}
-
-
-/* ==User-Enumeration===================================================== */
-
-struct enum_users_state {
- struct tevent_context *ev;
- struct sdap_id_ctx *ctx;
-
- char *filter;
- const char **attrs;
-};
-
-static void enum_users_connect_done(struct tevent_req *subreq);
-static void enum_users_op_done(struct tevent_req *subreq);
-
-static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sdap_id_ctx *ctx)
-{
- struct tevent_req *req, *subreq;
- struct enum_users_state *state;
- int ret;
-
- req = tevent_req_create(memctx, &state, struct enum_users_state);
- if (!req) return NULL;
-
- state->ev = ev;
- state->ctx = ctx;
-
- if (ctx->max_user_timestamp) {
- state->filter = talloc_asprintf(state,
- "(&(%s=*)(objectclass=%s)(%s>=%s)(!(%s=%s)))",
- ctx->opts->user_map[SDAP_AT_USER_NAME].name,
- ctx->opts->user_map[SDAP_OC_USER].name,
- ctx->opts->user_map[SDAP_AT_USER_MODSTAMP].name,
- ctx->max_user_timestamp,
- ctx->opts->user_map[SDAP_AT_USER_MODSTAMP].name,
- ctx->max_user_timestamp);
- } else {
- state->filter = talloc_asprintf(state,
- "(&(%s=*)(objectclass=%s))",
- ctx->opts->user_map[SDAP_AT_USER_NAME].name,
- ctx->opts->user_map[SDAP_OC_USER].name);
- }
- if (!state->filter) {
- DEBUG(2, ("Failed to build filter\n"));
- ret = ENOMEM;
- goto fail;
- }
-
- /* TODO: handle attrs_type */
- ret = build_attrs_from_map(state, ctx->opts->user_map,
- SDAP_OPTS_USER, &state->attrs);
- if (ret != EOK) goto fail;
-
- if (!connected(ctx)) {
-
- if (ctx->gsh) talloc_zfree(ctx->gsh);
-
- /* FIXME: add option to decide if tls should be used
- * or SASL/GSSAPI, etc ... */
- subreq = sdap_cli_connect_send(state, ev, ctx->opts, &ctx->rootDSE);
- if (!subreq) {
- ret = ENOMEM;
- goto fail;
- }
-
- tevent_req_set_callback(subreq, enum_users_connect_done, req);
-
- return req;
- }
-
- subreq = sdap_get_users_send(state, state->ev,
- state->ctx->be->domain,
- state->ctx->be->sysdb,
- state->ctx->opts,
- state->ctx->gsh,
- state->attrs, state->filter);
- if (!subreq) {
- ret = ENOMEM;
- goto fail;
- }
- tevent_req_set_callback(subreq, enum_users_op_done, req);
-
- return req;
-
-fail:
- tevent_req_error(req, ret);
- tevent_req_post(req, ev);
- return req;
-}
-
-static void enum_users_connect_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(subreq,
- struct tevent_req);
- struct enum_users_state *state = tevent_req_data(req,
- struct enum_users_state);
- int ret;
-
- ret = sdap_cli_connect_recv(subreq, state->ctx,
- &state->ctx->gsh, &state->ctx->rootDSE);
- talloc_zfree(subreq);
- if (ret) {
- if (ret == ENOTSUP) {
- DEBUG(0, ("Authentication mechanism not Supported by server"));
- }
- tevent_req_error(req, ret);
- return;
- }
-
- subreq = sdap_get_users_send(state, state->ev,
- state->ctx->be->domain,
- state->ctx->be->sysdb,
- state->ctx->opts, state->ctx->gsh,
- state->attrs, state->filter);
- if (!subreq) {
- tevent_req_error(req, ENOMEM);
- return;
- }
- tevent_req_set_callback(subreq, enum_users_op_done, req);
-}
-
-static void enum_users_op_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(subreq,
- struct tevent_req);
- struct enum_users_state *state = tevent_req_data(req,
- struct enum_users_state);
- char *timestamp;
- int ret;
-
- ret = sdap_get_users_recv(subreq, state, &timestamp);
- talloc_zfree(subreq);
- if (ret) {
- tevent_req_error(req, ret);
- return;
- }
-
- if (timestamp) {
- talloc_zfree(state->ctx->max_user_timestamp);
- state->ctx->max_user_timestamp = talloc_steal(state->ctx, timestamp);
- }
-
- DEBUG(4, ("Users higher timestamp: [%s]\n",
- state->ctx->max_user_timestamp));
-
- tevent_req_done(req);
-}
-
-/* =Group-Enumeration===================================================== */
-
-struct enum_groups_state {
- struct tevent_context *ev;
- struct sdap_id_ctx *ctx;
-
- char *filter;
- const char **attrs;
-};
-
-static void enum_groups_connect_done(struct tevent_req *subreq);
-static void enum_groups_op_done(struct tevent_req *subreq);
-
-static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sdap_id_ctx *ctx)
-{
- struct tevent_req *req, *subreq;
- struct enum_groups_state *state;
- const char *attr_name;
- int ret;
-
- req = tevent_req_create(memctx, &state, struct enum_groups_state);
- if (!req) return NULL;
-
- state->ev = ev;
- state->ctx = ctx;
-
- attr_name = ctx->opts->group_map[SDAP_AT_GROUP_NAME].name;
-
- if (ctx->max_group_timestamp) {
- state->filter = talloc_asprintf(state,
- "(&(%s=*)(objectclass=%s)(%s>=%s)(!(%s=%s)))",
- ctx->opts->group_map[SDAP_AT_GROUP_NAME].name,
- ctx->opts->group_map[SDAP_OC_GROUP].name,
- ctx->opts->group_map[SDAP_AT_GROUP_MODSTAMP].name,
- ctx->max_group_timestamp,
- ctx->opts->group_map[SDAP_AT_GROUP_MODSTAMP].name,
- ctx->max_group_timestamp);
- } else {
- state->filter = talloc_asprintf(state,
- "(&(%s=*)(objectclass=%s))",
- ctx->opts->group_map[SDAP_AT_GROUP_NAME].name,
- ctx->opts->group_map[SDAP_OC_GROUP].name);
- }
- if (!state->filter) {
- DEBUG(2, ("Failed to build filter\n"));
- ret = ENOMEM;
- goto fail;
- }
-
- /* TODO: handle attrs_type */
- ret = build_attrs_from_map(state, ctx->opts->group_map,
- SDAP_OPTS_GROUP, &state->attrs);
- if (ret != EOK) goto fail;
-
- if (!connected(ctx)) {
-
- if (ctx->gsh) talloc_zfree(ctx->gsh);
-
- /* FIXME: add option to decide if tls should be used
- * or SASL/GSSAPI, etc ... */
- subreq = sdap_cli_connect_send(state, ev, ctx->opts, &ctx->rootDSE);
- if (!subreq) {
- ret = ENOMEM;
- goto fail;
- }
-
- tevent_req_set_callback(subreq, enum_groups_connect_done, req);
-
- return req;
- }
-
- subreq = sdap_get_groups_send(state, state->ev,
- state->ctx->be->domain,
- state->ctx->be->sysdb,
- state->ctx->opts, state->ctx->gsh,
- state->attrs, state->filter);
- if (!subreq) {
- ret = ENOMEM;
- goto fail;
- }
- tevent_req_set_callback(subreq, enum_groups_op_done, req);
-
- return req;
-
-fail:
- tevent_req_error(req, ret);
- tevent_req_post(req, ev);
- return req;
-}
-
-static void enum_groups_connect_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(subreq,
- struct tevent_req);
- struct enum_groups_state *state = tevent_req_data(req,
- struct enum_groups_state);
- int ret;
-
- ret = sdap_cli_connect_recv(subreq, state->ctx,
- &state->ctx->gsh, &state->ctx->rootDSE);
- talloc_zfree(subreq);
- if (ret) {
- if (ret == ENOTSUP) {
- DEBUG(0, ("Authentication mechanism not Supported by server"));
- }
- tevent_req_error(req, ret);
- return;
- }
-
- subreq = sdap_get_groups_send(state, state->ev,
- state->ctx->be->domain,
- state->ctx->be->sysdb,
- state->ctx->opts, state->ctx->gsh,
- state->attrs, state->filter);
- if (!subreq) {
- tevent_req_error(req, ENOMEM);
- return;
- }
- tevent_req_set_callback(subreq, enum_groups_op_done, req);
-}
-
-static void enum_groups_op_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(subreq,
- struct tevent_req);
- struct enum_groups_state *state = tevent_req_data(req,
- struct enum_groups_state);
- char *timestamp;
- int ret;
-
- ret = sdap_get_groups_recv(subreq, state, &timestamp);
- talloc_zfree(subreq);
- if (ret) {
- tevent_req_error(req, ret);
- return;
- }
-
- if (timestamp) {
- talloc_zfree(state->ctx->max_group_timestamp);
- state->ctx->max_group_timestamp = talloc_steal(state->ctx, timestamp);
- }
-
- DEBUG(4, ("Groups higher timestamp: [%s]\n",
- state->ctx->max_group_timestamp));
-
- tevent_req_done(req);
-}
-
-int sdap_id_setup_tasks(struct sdap_id_ctx *ctx)
-{
- struct tevent_timer *enum_task;
- int ret = EOK;
-
- /* set up enumeration task */
- if (ctx->be->domain->enumerate) {
- /* run the first one in a couple of seconds so that we have time to
- * finish initializations first*/
- ctx->last_run = tevent_timeval_current_ofs(2, 0);
- enum_task = tevent_add_timer(ctx->be->ev, ctx, ctx->last_run,
- ldap_id_enumerate, ctx);
- if (!enum_task) {
- DEBUG(0, ("FATAL: failed to setup enumeration task!\n"));
- ret = EFAULT;
- }
- }
-
- return ret;
-}
-
diff --git a/server/providers/ldap/ldap_id_enum.c b/server/providers/ldap/ldap_id_enum.c
new file mode 100644
index 00000000..39b24243
--- /dev/null
+++ b/server/providers/ldap/ldap_id_enum.c
@@ -0,0 +1,529 @@
+/*
+ SSSD
+
+ LDAP Identity Enumeration
+
+ Authors:
+ Simo Sorce <ssorce@redhat.com>
+
+ Copyright (C) 2009 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 <time.h>
+#include <sys/time.h>
+
+#include "util/util.h"
+#include "db/sysdb.h"
+#include "providers/ldap/ldap_common.h"
+#include "providers/ldap/sdap_async.h"
+
+/* ==Enumeration-Task===================================================== */
+
+static struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev,
+ struct sdap_id_ctx *ctx);
+static void ldap_id_enumerate_reschedule(struct tevent_req *req);
+static void ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx,
+ struct timeval tv);
+
+static void ldap_id_enumerate_timeout(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv, void *pvt);
+
+void ldap_id_enumerate(struct tevent_context *ev,
+ struct tevent_timer *tt,
+ struct timeval tv, void *pvt)
+{
+ struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx);
+ struct tevent_timer *timeout;
+ struct tevent_req *req;
+ int ert;
+
+ if (be_is_offline(ctx->be)) {
+ DEBUG(4, ("Backend is marked offline, retry later!\n"));
+ /* schedule starting from now, not the last run */
+ ldap_id_enumerate_set_timer(ctx, tevent_timeval_current());
+ return;
+ }
+
+ ctx->last_run = tv;
+
+ req = ldap_id_enumerate_send(ev, ctx);
+ if (!req) {
+ DEBUG(1, ("Failed to schedule enumeration, retrying later!\n"));
+ /* schedule starting from now, not the last run */
+ ldap_id_enumerate_set_timer(ctx, tevent_timeval_current());
+ return;
+ }
+ tevent_req_set_callback(req, ldap_id_enumerate_reschedule, ctx);
+
+ /* if enumeration takes so long, either we try to enumerate too
+ * frequently, or something went seriously wrong */
+ tv = tevent_timeval_current();
+ ert = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+ tv = tevent_timeval_add(&tv, ert, 0);
+ timeout = tevent_add_timer(ctx->be->ev, req, tv,
+ ldap_id_enumerate_timeout, req);
+ return;
+}
+
+static void ldap_id_enumerate_timeout(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv, void *pvt)
+{
+ struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
+ struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
+ struct sdap_id_ctx);
+ int ert;
+
+ ert = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+ DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n", ert));
+ ldap_id_enumerate_set_timer(ctx, tevent_timeval_current());
+
+ talloc_zfree(req);
+}
+
+static void ldap_id_enumerate_reschedule(struct tevent_req *req)
+{
+ struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
+ struct sdap_id_ctx);
+ struct timeval tv;
+ enum tevent_req_state tstate;
+ uint64_t err;
+
+ if (tevent_req_is_error(req, &tstate, &err)) {
+ /* On error schedule starting from now, not the last run */
+ tv = tevent_timeval_current();
+ } else {
+ tv = ctx->last_run;
+ }
+ talloc_zfree(req);
+
+ ldap_id_enumerate_set_timer(ctx, ctx->last_run);
+}
+
+static void ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx,
+ struct timeval tv)
+{
+ struct tevent_timer *enum_task;
+ int ert;
+
+ ert = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+ tv = tevent_timeval_add(&tv, ert, 0);
+ enum_task = tevent_add_timer(ctx->be->ev, ctx, tv, ldap_id_enumerate, ctx);
+ if (!enum_task) {
+ DEBUG(0, ("FATAL: failed to setup enumeration task!\n"));
+ /* shutdown! */
+ exit(1);
+ }
+}
+
+
+
+struct global_enum_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *ctx;
+};
+
+static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx);
+static void ldap_id_enum_users_done(struct tevent_req *subreq);
+static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx);
+static void ldap_id_enum_groups_done(struct tevent_req *subreq);
+
+static struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev,
+ struct sdap_id_ctx *ctx)
+{
+ struct global_enum_state *state;
+ struct tevent_req *req, *subreq;
+
+ req = tevent_req_create(ctx, &state, struct global_enum_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->ctx = ctx;
+
+ subreq = enum_users_send(state, ev, ctx);
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, ldap_id_enum_users_done, req);
+
+ return req;
+}
+
+static void ldap_id_enum_users_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct global_enum_state *state = tevent_req_data(req,
+ struct global_enum_state);
+ enum tevent_req_state tstate;
+ uint64_t err = 0;
+
+ if (tevent_req_is_error(subreq, &tstate, &err)) {
+ goto fail;
+ }
+ talloc_zfree(subreq);
+
+ subreq = enum_groups_send(state, state->ev, state->ctx);
+ if (!subreq) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);
+
+ return;
+
+fail:
+ if (err) {
+ DEBUG(9, ("User enumeration failed with: (%d)[%s]\n",
+ (int)err, strerror(err)));
+
+ sdap_mark_offline(state->ctx);
+ }
+
+ DEBUG(1, ("Failed to enumerate users, retrying later!\n"));
+ tevent_req_done(req);
+}
+
+static void ldap_id_enum_groups_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct global_enum_state *state = tevent_req_data(req,
+ struct global_enum_state);
+ enum tevent_req_state tstate;
+ uint64_t err;
+
+ if (tevent_req_is_error(subreq, &tstate, &err)) {
+ goto fail;
+ }
+ talloc_zfree(subreq);
+
+ tevent_req_done(req);
+ return;
+
+fail:
+ /* always go offline on failures */
+ sdap_mark_offline(state->ctx);
+ DEBUG(1, ("Failed to enumerate groups (%d [%s]), retrying later!\n",
+ (int)err, strerror(err)));
+ tevent_req_done(req);
+}
+
+
+/* ==User-Enumeration===================================================== */
+
+struct enum_users_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *ctx;
+
+ char *filter;
+ const char **attrs;
+};
+
+static void enum_users_connect_done(struct tevent_req *subreq);
+static void enum_users_op_done(struct tevent_req *subreq);
+
+static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx)
+{
+ struct tevent_req *req, *subreq;
+ struct enum_users_state *state;
+ int ret;
+
+ req = tevent_req_create(memctx, &state, struct enum_users_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->ctx = ctx;
+
+ if (ctx->max_user_timestamp) {
+ state->filter = talloc_asprintf(state,
+ "(&(%s=*)(objectclass=%s)(%s>=%s)(!(%s=%s)))",
+ ctx->opts->user_map[SDAP_AT_USER_NAME].name,
+ ctx->opts->user_map[SDAP_OC_USER].name,
+ ctx->opts->user_map[SDAP_AT_USER_MODSTAMP].name,
+ ctx->max_user_timestamp,
+ ctx->opts->user_map[SDAP_AT_USER_MODSTAMP].name,
+ ctx->max_user_timestamp);
+ } else {
+ state->filter = talloc_asprintf(state,
+ "(&(%s=*)(objectclass=%s))",
+ ctx->opts->user_map[SDAP_AT_USER_NAME].name,
+ ctx->opts->user_map[SDAP_OC_USER].name);
+ }
+ if (!state->filter) {
+ DEBUG(2, ("Failed to build filter\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ /* TODO: handle attrs_type */
+ ret = build_attrs_from_map(state, ctx->opts->user_map,
+ SDAP_OPTS_USER, &state->attrs);
+ if (ret != EOK) goto fail;
+
+ if (!sdap_connected(ctx)) {
+
+ if (ctx->gsh) talloc_zfree(ctx->gsh);
+
+ /* FIXME: add option to decide if tls should be used
+ * or SASL/GSSAPI, etc ... */
+ subreq = sdap_cli_connect_send(state, ev, ctx->opts, &ctx->rootDSE);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, enum_users_connect_done, req);
+
+ return req;
+ }
+
+ subreq = sdap_get_users_send(state, state->ev,
+ state->ctx->be->domain,
+ state->ctx->be->sysdb,
+ state->ctx->opts,
+ state->ctx->gsh,
+ state->attrs, state->filter);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, enum_users_op_done, req);
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void enum_users_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct enum_users_state *state = tevent_req_data(req,
+ struct enum_users_state);
+ int ret;
+
+ ret = sdap_cli_connect_recv(subreq, state->ctx,
+ &state->ctx->gsh, &state->ctx->rootDSE);
+ talloc_zfree(subreq);
+ if (ret) {
+ if (ret == ENOTSUP) {
+ DEBUG(0, ("Authentication mechanism not Supported by server"));
+ }
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = sdap_get_users_send(state, state->ev,
+ state->ctx->be->domain,
+ state->ctx->be->sysdb,
+ state->ctx->opts, state->ctx->gsh,
+ state->attrs, state->filter);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, enum_users_op_done, req);
+}
+
+static void enum_users_op_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct enum_users_state *state = tevent_req_data(req,
+ struct enum_users_state);
+ char *timestamp;
+ int ret;
+
+ ret = sdap_get_users_recv(subreq, state, &timestamp);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (timestamp) {
+ talloc_zfree(state->ctx->max_user_timestamp);
+ state->ctx->max_user_timestamp = talloc_steal(state->ctx, timestamp);
+ }
+
+ DEBUG(4, ("Users higher timestamp: [%s]\n",
+ state->ctx->max_user_timestamp));
+
+ tevent_req_done(req);
+}
+
+/* =Group-Enumeration===================================================== */
+
+struct enum_groups_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *ctx;
+
+ char *filter;
+ const char **attrs;
+};
+
+static void enum_groups_connect_done(struct tevent_req *subreq);
+static void enum_groups_op_done(struct tevent_req *subreq);
+
+static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx)
+{
+ struct tevent_req *req, *subreq;
+ struct enum_groups_state *state;
+ const char *attr_name;
+ int ret;
+
+ req = tevent_req_create(memctx, &state, struct enum_groups_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->ctx = ctx;
+
+ attr_name = ctx->opts->group_map[SDAP_AT_GROUP_NAME].name;
+
+ if (ctx->max_group_timestamp) {
+ state->filter = talloc_asprintf(state,
+ "(&(%s=*)(objectclass=%s)(%s>=%s)(!(%s=%s)))",
+ ctx->opts->group_map[SDAP_AT_GROUP_NAME].name,
+ ctx->opts->group_map[SDAP_OC_GROUP].name,
+ ctx->opts->group_map[SDAP_AT_GROUP_MODSTAMP].name,
+ ctx->max_group_timestamp,
+ ctx->opts->group_map[SDAP_AT_GROUP_MODSTAMP].name,
+ ctx->max_group_timestamp);
+ } else {
+ state->filter = talloc_asprintf(state,
+ "(&(%s=*)(objectclass=%s))",
+ ctx->opts->group_map[SDAP_AT_GROUP_NAME].name,
+ ctx->opts->group_map[SDAP_OC_GROUP].name);
+ }
+ if (!state->filter) {
+ DEBUG(2, ("Failed to build filter\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ /* TODO: handle attrs_type */
+ ret = build_attrs_from_map(state, ctx->opts->group_map,
+ SDAP_OPTS_GROUP, &state->attrs);
+ if (ret != EOK) goto fail;
+
+ if (!sdap_connected(ctx)) {
+
+ if (ctx->gsh) talloc_zfree(ctx->gsh);
+
+ /* FIXME: add option to decide if tls should be used
+ * or SASL/GSSAPI, etc ... */
+ subreq = sdap_cli_connect_send(state, ev, ctx->opts, &ctx->rootDSE);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ tevent_req_set_callback(subreq, enum_groups_connect_done, req);
+
+ return req;
+ }
+
+ subreq = sdap_get_groups_send(state, state->ev,
+ state->ctx->be->domain,
+ state->ctx->be->sysdb,
+ state->ctx->opts, state->ctx->gsh,
+ state->attrs, state->filter);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, enum_groups_op_done, req);
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void enum_groups_connect_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct enum_groups_state *state = tevent_req_data(req,
+ struct enum_groups_state);
+ int ret;
+
+ ret = sdap_cli_connect_recv(subreq, state->ctx,
+ &state->ctx->gsh, &state->ctx->rootDSE);
+ talloc_zfree(subreq);
+ if (ret) {
+ if (ret == ENOTSUP) {
+ DEBUG(0, ("Authentication mechanism not Supported by server"));
+ }
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ subreq = sdap_get_groups_send(state, state->ev,
+ state->ctx->be->domain,
+ state->ctx->be->sysdb,
+ state->ctx->opts, state->ctx->gsh,
+ state->attrs, state->filter);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, enum_groups_op_done, req);
+}
+
+static void enum_groups_op_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct enum_groups_state *state = tevent_req_data(req,
+ struct enum_groups_state);
+ char *timestamp;
+ int ret;
+
+ ret = sdap_get_groups_recv(subreq, state, &timestamp);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (timestamp) {
+ talloc_zfree(state->ctx->max_group_timestamp);
+ state->ctx->max_group_timestamp = talloc_steal(state->ctx, timestamp);
+ }
+
+ DEBUG(4, ("Groups higher timestamp: [%s]\n",
+ state->ctx->max_group_timestamp));
+
+ tevent_req_done(req);
+}
+