summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/Makefile.am2
-rw-r--r--server/config/etc/sssd.api.d/sssd-ldap.conf1
-rw-r--r--server/providers/ipa/ipa_common.c3
-rw-r--r--server/providers/ldap/ldap_common.c20
-rw-r--r--server/providers/ldap/ldap_common.h21
-rw-r--r--server/providers/ldap/ldap_id.c395
-rw-r--r--server/providers/ldap/ldap_id_cleanup.c539
-rw-r--r--server/providers/ldap/ldap_id_enum.c89
-rw-r--r--server/providers/ldap/sdap.h1
9 files changed, 915 insertions, 156 deletions
diff --git a/server/Makefile.am b/server/Makefile.am
index bdc2f9861..08c0295e4 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -531,6 +531,7 @@ stress_tests_LDADD = \
libsss_ldap_la_SOURCES = \
providers/ldap/ldap_id.c \
providers/ldap/ldap_id_enum.c \
+ providers/ldap/ldap_id_cleanup.c \
providers/ldap/ldap_auth.c \
providers/ldap/ldap_init.c \
providers/ldap/ldap_common.c \
@@ -580,6 +581,7 @@ libsss_ipa_la_SOURCES = \
providers/ipa/ipa_timerules.c \
providers/ldap/ldap_id.c \
providers/ldap/ldap_id_enum.c \
+ providers/ldap/ldap_id_cleanup.c \
providers/ldap/ldap_auth.c \
providers/ldap/ldap_common.c \
providers/ldap/sdap_async.c \
diff --git a/server/config/etc/sssd.api.d/sssd-ldap.conf b/server/config/etc/sssd.api.d/sssd-ldap.conf
index af1e66cfd..34aaa65b9 100644
--- a/server/config/etc/sssd.api.d/sssd-ldap.conf
+++ b/server/config/etc/sssd.api.d/sssd-ldap.conf
@@ -22,6 +22,7 @@ ldap_rootdse_last_usn = str, None
[provider/ldap/id]
ldap_search_timeout = int, None
ldap_enumeration_refresh_timeout = int, None
+ldap_purge_cache_timeout = int, None
ldap_id_use_start_tls = bool, None, false
ldap_user_search_base = str, None
ldap_user_search_scope = str, None
diff --git a/server/providers/ipa/ipa_common.c b/server/providers/ipa/ipa_common.c
index a571aead6..4d7dc952e 100644
--- a/server/providers/ipa/ipa_common.c
+++ b/server/providers/ipa/ipa_common.c
@@ -51,6 +51,7 @@ struct dp_option ipa_def_ldap_opts[] = {
{ "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },
{ "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },
{ "ldap_enumeration_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER },
+ { "ldap_purge_cache_timeout", DP_OPT_NUMBER, { .number = 3600 }, NULL_NUMBER },
{ "entry_cache_timeout", DP_OPT_NUMBER, { .number = 1800 }, NULL_NUMBER },
{ "ldap_tls_cacert", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_tls_cacertdir", DP_OPT_STRING, NULL_STRING, NULL_STRING },
@@ -211,7 +212,7 @@ done:
/* the following preprocessor code is used to keep track of
* the options in the ldap module, so that if they change and ipa
* is not updated correspondingly this will trigger a build error */
-#if SDAP_OPTS_BASIC > 28
+#if SDAP_OPTS_BASIC > 29
#error There are ldap options not accounted for
#endif
diff --git a/server/providers/ldap/ldap_common.c b/server/providers/ldap/ldap_common.c
index d8e73f71f..deffb4aa4 100644
--- a/server/providers/ldap/ldap_common.c
+++ b/server/providers/ldap/ldap_common.c
@@ -44,6 +44,7 @@ struct dp_option default_basic_opts[] = {
{ "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },
{ "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },
{ "ldap_enumeration_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER },
+ { "ldap_purge_cache_timeout", DP_OPT_NUMBER, { .number = 3600 }, NULL_NUMBER },
{ "entry_cache_timoeut", DP_OPT_NUMBER, { .number = 1800 }, NULL_NUMBER },
{ "ldap_tls_cacert", DP_OPT_STRING, NULL_STRING, NULL_STRING },
{ "ldap_tls_cacertdir", DP_OPT_STRING, NULL_STRING, NULL_STRING },
@@ -287,20 +288,23 @@ void sdap_mark_offline(struct sdap_id_ctx *ctx)
int sdap_id_setup_tasks(struct sdap_id_ctx *ctx)
{
- struct tevent_timer *enum_task;
+ struct timeval tv;
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;
- }
+ tv = tevent_timeval_current_ofs(2, 0);
+ ret = ldap_id_enumerate_set_timer(ctx, tv);
+ } else {
+ /* the enumeration task, runs the cleanup process by itself,
+ * but if enumeration is not runnig we need to schedule it */
+
+ /* run the first one in a couple of seconds so that we have time to
+ * finish initializations first*/
+ tv = tevent_timeval_current_ofs(2, 0);
+ ret = ldap_id_cleanup_set_timer(ctx, tv);
}
return ret;
diff --git a/server/providers/ldap/ldap_common.h b/server/providers/ldap/ldap_common.h
index 0c51428dc..9cc30f847 100644
--- a/server/providers/ldap/ldap_common.h
+++ b/server/providers/ldap/ldap_common.h
@@ -69,11 +69,26 @@ 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);
+int ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
+int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv);
bool sdap_connected(struct sdap_id_ctx *ctx);
void sdap_mark_offline(struct sdap_id_ctx *ctx);
+struct tevent_req *users_get_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx,
+ const char *name,
+ int filter_type,
+ int attrs_type);
+int users_get_recv(struct tevent_req *req);
+
+struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx,
+ const char *name,
+ int filter_type,
+ int attrs_type);
+int groups_get_recv(struct tevent_req *req);
+
#endif /* _LDAP_COMMON_H_ */
diff --git a/server/providers/ldap/ldap_id.c b/server/providers/ldap/ldap_id.c
index 3268d7344..124ee7d83 100644
--- a/server/providers/ldap/ldap_id.c
+++ b/server/providers/ldap/ldap_id.c
@@ -36,20 +36,26 @@
struct users_get_state {
struct tevent_context *ev;
struct sdap_id_ctx *ctx;
+ struct sysdb_ctx *sysdb;
+ struct sss_domain_info *domain;
+
+ const char *name;
+ int filter_type;
char *filter;
const char **attrs;
};
static void users_get_connect_done(struct tevent_req *subreq);
-static void users_get_op_done(struct tevent_req *subreq);
-
-static struct tevent_req *users_get_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sdap_id_ctx *ctx,
- const char *name,
- int filter_type,
- int attrs_type)
+static void users_get_done(struct tevent_req *subreq);
+static void users_get_delete(struct tevent_req *subreq);
+
+struct tevent_req *users_get_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx,
+ const char *name,
+ int filter_type,
+ int attrs_type)
{
struct tevent_req *req, *subreq;
struct users_get_state *state;
@@ -61,8 +67,12 @@ static struct tevent_req *users_get_send(TALLOC_CTX *memctx,
state->ev = ev;
state->ctx = ctx;
+ state->sysdb = ctx->be->sysdb;
+ state->domain = state->ctx->be->domain;
+ state->name = name;
+ state->filter_type = filter_type;
- switch(filter_type) {
+ switch (filter_type) {
case BE_FILTER_NAME:
attr_name = ctx->opts->user_map[SDAP_AT_USER_NAME].name;
break;
@@ -106,15 +116,14 @@ static struct tevent_req *users_get_send(TALLOC_CTX *memctx,
}
subreq = sdap_get_users_send(state, state->ev,
- state->ctx->be->domain,
- state->ctx->be->sysdb,
+ state->domain, state->sysdb,
state->ctx->opts, state->ctx->gsh,
state->attrs, state->filter);
if (!subreq) {
ret = ENOMEM;
goto fail;
}
- tevent_req_set_callback(subreq, users_get_op_done, req);
+ tevent_req_set_callback(subreq, users_get_done, req);
return req;
@@ -144,83 +153,130 @@ static void users_get_connect_done(struct tevent_req *subreq)
}
subreq = sdap_get_users_send(state, state->ev,
- state->ctx->be->domain,
- state->ctx->be->sysdb,
+ state->domain, state->sysdb,
state->ctx->opts, state->ctx->gsh,
state->attrs, state->filter);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
}
- tevent_req_set_callback(subreq, users_get_op_done, req);
+ tevent_req_set_callback(subreq, users_get_done, req);
}
-static void users_get_op_done(struct tevent_req *subreq)
+static void users_get_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
+ struct users_get_state *state = tevent_req_data(req,
+ struct users_get_state);
+ char *endptr;
+ uid_t uid;
int ret;
ret = sdap_get_users_recv(subreq, NULL, NULL);
talloc_zfree(subreq);
- if (ret) {
+ if (ret && ret != ENOENT) {
tevent_req_error(req, ret);
return;
}
+ if (ret == ENOENT) {
+ if (strchr(state->name, '*')) {
+ /* it was an enumeration */
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ switch (state->filter_type) {
+ case BE_FILTER_NAME:
+ subreq = sysdb_delete_user_send(state, state->ev,
+ state->sysdb, NULL,
+ state->domain, state->name, 0);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, users_get_delete, req);
+ return;
+
+ case BE_FILTER_IDNUM:
+ errno = 0;
+ uid = (uid_t)strtol(state->name, &endptr, 0);
+ if (errno || *endptr || (state->name == endptr)) {
+ tevent_req_error(req, errno);
+ return;
+ }
+
+ subreq = sysdb_delete_user_send(state, state->ev,
+ state->sysdb, NULL,
+ state->domain, NULL, uid);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, users_get_delete, req);
+ return;
+
+ default:
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+ }
+
tevent_req_done(req);
}
-static void users_get_done(struct tevent_req *req)
+static void users_get_delete(struct tevent_req *subreq)
{
- struct be_req *breq = tevent_req_callback_data(req, struct be_req);
- struct sdap_id_ctx *ctx;
- enum tevent_req_state tstate;
- uint64_t err = EIO;
- int dp_err = DP_ERR_OK;
- const char *error = NULL;
- int ret = EOK;
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct users_get_state *state = tevent_req_data(req,
+ struct users_get_state);
+ int ret;
- if (tevent_req_is_error(req, &tstate, &err)) {
- ret = err;
+ ret = sysdb_delete_user_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret) {
+ DEBUG(2, ("User (%s) delete returned %d (%s)\n",
+ state->name, ret, strerror(ret)));
}
- if (ret) {
- dp_err = DP_ERR_FATAL;
- error = "Enum Users Failed";
+ tevent_req_done(req);
+}
- if (ret == ETIMEDOUT) {
- dp_err = DP_ERR_TIMEOUT;
- }
- if (ret == ETIMEDOUT || ret == EFAULT) {
- ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
- struct sdap_id_ctx);
- sdap_mark_offline(ctx);
- }
- }
+int users_get_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
- sdap_handler_done(breq, dp_err, ret, error);
+ return EOK;
}
+
/* =Groups-Related-Functions-(by-name,by-uid)============================= */
struct groups_get_state {
struct tevent_context *ev;
struct sdap_id_ctx *ctx;
+ struct sysdb_ctx *sysdb;
+ struct sss_domain_info *domain;
+
+ const char *name;
+ int filter_type;
char *filter;
const char **attrs;
};
static void groups_get_connect_done(struct tevent_req *subreq);
-static void groups_get_op_done(struct tevent_req *subreq);
-
-static struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sdap_id_ctx *ctx,
- const char *name,
- int filter_type,
- int attrs_type)
+static void groups_get_done(struct tevent_req *subreq);
+static void groups_get_delete(struct tevent_req *subreq);
+
+struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx,
+ const char *name,
+ int filter_type,
+ int attrs_type)
{
struct tevent_req *req, *subreq;
struct groups_get_state *state;
@@ -232,6 +288,10 @@ static struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
state->ev = ev;
state->ctx = ctx;
+ state->sysdb = ctx->be->sysdb;
+ state->domain = state->ctx->be->domain;
+ state->name = name;
+ state->filter_type = filter_type;
switch(filter_type) {
case BE_FILTER_NAME:
@@ -277,15 +337,14 @@ static struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
}
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);
+ state->domain, state->sysdb,
+ state->ctx->opts, state->ctx->gsh,
+ state->attrs, state->filter);
if (!subreq) {
ret = ENOMEM;
goto fail;
}
- tevent_req_set_callback(subreq, groups_get_op_done, req);
+ tevent_req_set_callback(subreq, groups_get_done, req);
return req;
@@ -315,64 +374,105 @@ static void groups_get_connect_done(struct tevent_req *subreq)
}
subreq = sdap_get_groups_send(state, state->ev,
- state->ctx->be->domain,
- state->ctx->be->sysdb,
+ state->domain, state->sysdb,
state->ctx->opts, state->ctx->gsh,
state->attrs, state->filter);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
}
- tevent_req_set_callback(subreq, groups_get_op_done, req);
+ tevent_req_set_callback(subreq, groups_get_done, req);
}
-static void groups_get_op_done(struct tevent_req *subreq)
+static void groups_get_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
+ struct groups_get_state *state = tevent_req_data(req,
+ struct groups_get_state);
+ char *endptr;
+ gid_t gid;
int ret;
ret = sdap_get_groups_recv(subreq, NULL, NULL);
talloc_zfree(subreq);
- if (ret) {
+ if (ret && ret != ENOENT) {
tevent_req_error(req, ret);
return;
}
+ if (ret == ENOENT) {
+ if (strchr(state->name, '*')) {
+ /* it was an enumeration */
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ switch (state->filter_type) {
+ case BE_FILTER_NAME:
+ subreq = sysdb_delete_group_send(state, state->ev,
+ state->sysdb, NULL,
+ state->domain, state->name, 0);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, groups_get_delete, req);
+ return;
+
+ case BE_FILTER_IDNUM:
+ errno = 0;
+ gid = (gid_t)strtol(state->name, &endptr, 0);
+ if (errno || *endptr || (state->name == endptr)) {
+ tevent_req_error(req, errno);
+ return;
+ }
+
+ subreq = sysdb_delete_group_send(state, state->ev,
+ state->sysdb, NULL,
+ state->domain, NULL, gid);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, groups_get_delete, req);
+ return;
+
+ default:
+ tevent_req_error(req, EINVAL);
+ return;
+ }
+ }
+
tevent_req_done(req);
}
-static void groups_get_done(struct tevent_req *req)
+static void groups_get_delete(struct tevent_req *subreq)
{
- struct be_req *breq = tevent_req_callback_data(req, struct be_req);
- struct sdap_id_ctx *ctx;
- enum tevent_req_state tstate;
- uint64_t err = EIO;
- int dp_err = DP_ERR_OK;
- const char *error = NULL;
- int ret = EOK;
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct groups_get_state *state = tevent_req_data(req,
+ struct groups_get_state);
+ int ret;
- if (tevent_req_is_error(req, &tstate, &err)) {
- ret = err;
+ ret = sysdb_delete_group_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret) {
+ DEBUG(2, ("Group (%s) delete returned %d (%s)\n",
+ state->name, ret, strerror(ret)));
}
- if (ret) {
- dp_err = DP_ERR_FATAL;
- error = "Enum Groups Failed";
+ tevent_req_done(req);
+}
- if (ret == ETIMEDOUT) {
- dp_err = DP_ERR_TIMEOUT;
- }
- if (ret == ETIMEDOUT || ret == EFAULT) {
- ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
- struct sdap_id_ctx);
- sdap_mark_offline(ctx);
- }
- }
+int groups_get_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
- return sdap_handler_done(breq, dp_err, ret, error);
+ return EOK;
}
+
/* =Get-Groups-for-User================================================== */
struct groups_by_user_state {
@@ -383,7 +483,7 @@ struct groups_by_user_state {
};
static void groups_by_user_connect_done(struct tevent_req *subreq);
-static void groups_by_user_op_done(struct tevent_req *subreq);
+static void groups_by_user_done(struct tevent_req *subreq);
static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
@@ -431,7 +531,7 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
ret = ENOMEM;
goto fail;
}
- tevent_req_set_callback(subreq, groups_by_user_op_done, req);
+ tevent_req_set_callback(subreq, groups_by_user_done, req);
return req;
@@ -469,10 +569,10 @@ static void groups_by_user_connect_done(struct tevent_req *subreq)
tevent_req_error(req, ENOMEM);
return;
}
- tevent_req_set_callback(subreq, groups_by_user_op_done, req);
+ tevent_req_set_callback(subreq, groups_by_user_done, req);
}
-static void groups_by_user_op_done(struct tevent_req *subreq)
+static void groups_by_user_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
@@ -488,35 +588,11 @@ static void groups_by_user_op_done(struct tevent_req *subreq)
tevent_req_done(req);
}
-static void groups_by_user_done(struct tevent_req *req)
+int groups_by_user_recv(struct tevent_req *req)
{
- struct be_req *breq = tevent_req_callback_data(req, struct be_req);
- struct sdap_id_ctx *ctx;
- enum tevent_req_state tstate;
- uint64_t err = EIO;
- int dp_err = DP_ERR_OK;
- const char *error = NULL;
- int ret = EOK;
-
- if (tevent_req_is_error(req, &tstate, &err)) {
- ret = err;
- }
-
- if (ret) {
- dp_err = DP_ERR_FATAL;
- error = "Init Groups Failed";
-
- if (ret == ETIMEDOUT) {
- dp_err = DP_ERR_TIMEOUT;
- }
- if (ret == ETIMEDOUT || ret == EFAULT) {
- ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
- struct sdap_id_ctx);
- sdap_mark_offline(ctx);
- }
- }
+ TEVENT_REQ_RETURN_ON_ERROR(req);
- return sdap_handler_done(breq, dp_err, ret, error);
+ return EOK;
}
@@ -525,6 +601,11 @@ static void groups_by_user_done(struct tevent_req *req)
/* FIXME: embed this function in sssd_be and only call out
* specific functions from modules ? */
+
+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);
+
void sdap_account_info_handler(struct be_req *breq)
{
struct sdap_id_ctx *ctx;
@@ -557,7 +638,7 @@ void sdap_account_info_handler(struct be_req *breq)
return sdap_handler_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory");
}
- tevent_req_set_callback(req, users_get_done, breq);
+ tevent_req_set_callback(req, sdap_account_info_users_done, breq);
break;
@@ -576,7 +657,7 @@ void sdap_account_info_handler(struct be_req *breq)
return sdap_handler_done(breq, DP_ERR_FATAL, ENOMEM, "Out of memory");
}
- tevent_req_set_callback(req, groups_get_done, breq);
+ tevent_req_set_callback(req, sdap_account_info_groups_done, breq);
break;
@@ -601,7 +682,7 @@ void sdap_account_info_handler(struct be_req *breq)
if (!req) ret = ENOMEM;
/* tevent_req_set_callback(req, groups_by_user_done, breq); */
- tevent_req_set_callback(req, groups_by_user_done, breq);
+ tevent_req_set_callback(req, sdap_account_info_initgr_done, breq);
break;
@@ -613,3 +694,87 @@ void sdap_account_info_handler(struct be_req *breq)
if (ret != EOK) return sdap_handler_done(breq, DP_ERR_FATAL, ret, err);
}
+static void sdap_account_info_users_done(struct tevent_req *req)
+{
+ struct be_req *breq = tevent_req_callback_data(req, struct be_req);
+ struct sdap_id_ctx *ctx;
+ int dp_err = DP_ERR_OK;
+ const char *error = NULL;
+ int ret;
+
+ ret = users_get_recv(req);
+ talloc_zfree(req);
+
+ if (ret) {
+ dp_err = DP_ERR_FATAL;
+ error = "Enum Users Failed";
+
+ if (ret == ETIMEDOUT) {
+ dp_err = DP_ERR_TIMEOUT;
+ }
+ if (ret == ETIMEDOUT || ret == EFAULT) {
+ ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
+ struct sdap_id_ctx);
+ sdap_mark_offline(ctx);
+ }
+ }
+
+ sdap_handler_done(breq, dp_err, ret, error);
+}
+
+static void sdap_account_info_groups_done(struct tevent_req *req)
+{
+ struct be_req *breq = tevent_req_callback_data(req, struct be_req);
+ struct sdap_id_ctx *ctx;
+ int dp_err = DP_ERR_OK;
+ const char *error = NULL;
+ int ret;
+
+ ret = groups_get_recv(req);
+ talloc_zfree(req);
+
+ if (ret) {
+ dp_err = DP_ERR_FATAL;
+ error = "Enum Groups Failed";
+
+ if (ret == ETIMEDOUT) {
+ dp_err = DP_ERR_TIMEOUT;
+ }
+ if (ret == ETIMEDOUT || ret == EFAULT) {
+ ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
+ struct sdap_id_ctx);
+ sdap_mark_offline(ctx);
+ }
+ }
+
+ return sdap_handler_done(breq, dp_err, ret, error);
+}
+
+static void sdap_account_info_initgr_done(struct tevent_req *req)
+{
+ struct be_req *breq = tevent_req_callback_data(req, struct be_req);
+ struct sdap_id_ctx *ctx;
+ int dp_err = DP_ERR_OK;
+ const char *error = NULL;
+ int ret;
+
+ ret = groups_by_user_recv(req);
+ talloc_zfree(req);
+
+ if (ret) {
+ dp_err = DP_ERR_FATAL;
+ error = "Init Groups Failed";
+
+ if (ret == ETIMEDOUT) {
+ dp_err = DP_ERR_TIMEOUT;
+ }
+ if (ret == ETIMEDOUT || ret == EFAULT) {
+ ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,
+ struct sdap_id_ctx);
+ sdap_mark_offline(ctx);
+ }
+ }
+
+ return sdap_handler_done(breq, dp_err, ret, error);
+}
+
diff --git a/server/providers/ldap/ldap_id_cleanup.c b/server/providers/ldap/ldap_id_cleanup.c
new file mode 100644
index 000000000..7267b3540
--- /dev/null
+++ b/server/providers/ldap/ldap_id_cleanup.c
@@ -0,0 +1,539 @@
+/*
+ SSSD
+
+ LDAP Identity Cleanup Functions
+
+ 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"
+
+/* ==Cleanup-Task========================================================= */
+
+struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx);
+static void ldap_id_cleanup_reschedule(struct tevent_req *req);
+
+static void ldap_id_cleanup_timeout(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv, void *pvt);
+
+static void ldap_id_cleanup_timer(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 delay;
+
+ if (be_is_offline(ctx->be)) {
+ DEBUG(4, ("Backend is marked offline, retry later!\n"));
+ /* schedule starting from now, not the last run */
+ delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
+ tv = tevent_timeval_current_ofs(delay, 0);
+ ldap_id_cleanup_set_timer(ctx, tv);
+ return;
+ }
+
+ ctx->last_run = tv;
+
+ req = ldap_id_cleanup_send(ctx, ev, ctx);
+ if (!req) {
+ DEBUG(1, ("Failed to schedule cleanup, retrying later!\n"));
+ /* schedule starting from now, not the last run */
+ delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
+ tv = tevent_timeval_current_ofs(delay, 0);
+ ldap_id_cleanup_set_timer(ctx, tv);
+ return;
+ }
+ tevent_req_set_callback(req, ldap_id_cleanup_reschedule, ctx);
+
+ /* if cleanup takes so long, either we try to cleanup too
+ * frequently, or something went seriously wrong */
+ delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
+ tv = tevent_timeval_current_ofs(delay, 0);
+ timeout = tevent_add_timer(ctx->be->ev, req, tv,
+ ldap_id_cleanup_timeout, req);
+ return;
+}
+
+static void ldap_id_cleanup_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 delay;
+
+ delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
+ DEBUG(1, ("Cleanup timed out! Timeout too small? (%ds)!\n", delay));
+
+ tv = tevent_timeval_current_ofs(delay, 0);
+ ldap_id_enumerate_set_timer(ctx, tv);
+
+ talloc_zfree(req);
+}
+
+static void ldap_id_cleanup_reschedule(struct tevent_req *req)
+{
+ struct sdap_id_ctx *ctx = tevent_req_callback_data(req,
+ struct sdap_id_ctx);
+ enum tevent_req_state tstate;
+ uint64_t err;
+ struct timeval tv;
+ int delay;
+
+ 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);
+
+ delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);
+ tv = tevent_timeval_add(&tv, delay, 0);
+ ldap_id_enumerate_set_timer(ctx, tv);
+}
+
+
+
+int ldap_id_cleanup_set_timer(struct sdap_id_ctx *ctx, struct timeval tv)
+{
+ struct tevent_timer *cleanup_task;
+
+ DEBUG(6, ("Scheduling next cleanup at %ld.%ld\n",
+ (long)tv.tv_sec, (long)tv.tv_usec));
+
+ cleanup_task = tevent_add_timer(ctx->be->ev, ctx,
+ tv, ldap_id_cleanup_timer, ctx);
+ if (!cleanup_task) {
+ DEBUG(0, ("FATAL: failed to setup cleanup task!\n"));
+ return EFAULT;
+ }
+
+ return EOK;
+}
+
+
+
+struct global_cleanup_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *ctx;
+};
+
+static struct tevent_req *cleanup_users_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx);
+static void ldap_id_cleanup_users_done(struct tevent_req *subreq);
+static struct tevent_req *cleanup_groups_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx);
+static void ldap_id_cleanup_groups_done(struct tevent_req *subreq);
+
+struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx)
+{
+ struct global_cleanup_state *state;
+ struct tevent_req *req, *subreq;
+
+ req = tevent_req_create(memctx, &state, struct global_cleanup_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->ctx = ctx;
+
+ subreq = cleanup_users_send(state, ev, ctx);
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, ldap_id_cleanup_users_done, req);
+
+ return req;
+}
+
+static void ldap_id_cleanup_users_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct global_cleanup_state *state = tevent_req_data(req,
+ struct global_cleanup_state);
+ enum tevent_req_state tstate;
+ uint64_t err = 0;
+
+ if (tevent_req_is_error(subreq, &tstate, &err)) {
+ if (tstate != TEVENT_REQ_USER_ERROR) {
+ err = EIO;
+ }
+ if (err != ENOENT) {
+ goto fail;
+ }
+ }
+ talloc_zfree(subreq);
+
+ subreq = cleanup_groups_send(state, state->ev, state->ctx);
+ if (!subreq) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, ldap_id_cleanup_groups_done, req);
+
+ return;
+
+fail:
+ if (err) {
+ DEBUG(9, ("User cleanup failed with: (%d)[%s]\n",
+ (int)err, strerror(err)));
+
+ sdap_mark_offline(state->ctx);
+ }
+
+ DEBUG(1, ("Failed to cleanup users, retrying later!\n"));
+ tevent_req_done(req);
+}
+
+static void ldap_id_cleanup_groups_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct global_cleanup_state *state = tevent_req_data(req,
+ struct global_cleanup_state);
+ enum tevent_req_state tstate;
+ uint64_t err;
+
+ if (tevent_req_is_error(subreq, &tstate, &err)) {
+ if (tstate != TEVENT_REQ_USER_ERROR) {
+ err = EIO;
+ }
+ if (err != ENOENT) {
+ 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 cleanup groups (%d [%s]), retrying later!\n",
+ (int)err, strerror(err)));
+ tevent_req_done(req);
+}
+
+
+/* ==User-Cleanup-Process================================================= */
+
+struct cleanup_users_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *ctx;
+ struct sysdb_ctx *sysdb;
+ struct sss_domain_info *domain;
+
+ struct sysdb_handle *handle;
+
+ struct ldb_message **msgs;
+ size_t count;
+ int cur;
+};
+
+static void cleanup_users_process(struct tevent_req *subreq);
+static void cleanup_users_update(struct tevent_req *req);
+static void cleanup_users_up_done(struct tevent_req *subreq);
+
+static struct tevent_req *cleanup_users_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx)
+{
+ struct tevent_req *req, *subreq;
+ struct cleanup_users_state *state;
+ static const char *attrs[] = { SYSDB_NAME, NULL };
+ time_t now = time(NULL);
+ char *subfilter;
+
+ req = tevent_req_create(memctx, &state, struct cleanup_users_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->ctx = ctx;
+ state->sysdb = ctx->be->sysdb;
+ state->domain = ctx->be->domain;
+ state->msgs = NULL;
+ state->count = 0;
+ state->cur = 0;
+
+ subfilter = talloc_asprintf(state, "(&(!(%s=0))(%s<=%ld))",
+ SYSDB_CACHE_EXPIRE,
+ SYSDB_CACHE_EXPIRE, (long)now);
+ if (!subfilter) {
+ DEBUG(2, ("Failed to build filter\n"));
+ talloc_zfree(req);
+ return NULL;
+ }
+
+ subreq = sysdb_search_users_send(state, state->ev,
+ state->sysdb, NULL,
+ state->domain, subfilter, attrs);
+ if (!subreq) {
+ DEBUG(2, ("Failed to send entry search\n"));
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, cleanup_users_process, req);
+
+ return req;
+}
+
+static void cleanup_users_process(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cleanup_users_state *state = tevent_req_data(req,
+ struct cleanup_users_state);
+ int ret;
+
+ ret = sysdb_search_users_recv(subreq, state, &state->count, &state->msgs);
+ talloc_zfree(subreq);
+ if (ret) {
+ if (ret == ENOENT) {
+ tevent_req_done(req);
+ return;
+ }
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(4, ("Found %d expired user entries!\n", state->count));
+
+ if (state->count == 0) {
+ tevent_req_done(req);
+ }
+
+ cleanup_users_update(req);
+}
+
+static void cleanup_users_update(struct tevent_req *req)
+{
+ struct tevent_req *subreq;
+ struct cleanup_users_state *state = tevent_req_data(req,
+ struct cleanup_users_state);
+ const char *str;
+
+ str = ldb_msg_find_attr_as_string(state->msgs[state->cur],
+ SYSDB_NAME, NULL);
+ if (!str) {
+ DEBUG(2, ("Entry %s has no Name Attribute ?!?\n",
+ ldb_dn_get_linearized(state->msgs[state->cur]->dn)));
+ tevent_req_error(req, EFAULT);
+ return;
+ }
+
+ subreq = users_get_send(state, state->ev, state->ctx,
+ str, BE_FILTER_NAME, BE_ATTR_CORE);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, cleanup_users_up_done, req);
+}
+
+static void cleanup_users_up_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cleanup_users_state *state = tevent_req_data(req,
+ struct cleanup_users_state);
+ int ret;
+
+ ret = users_get_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret) {
+ DEBUG(2, ("User check returned: %d(%s)\n",
+ ret, strerror(ret)));
+ }
+
+ /* if the entry doesn't need to be purged, remove it from the list */
+ if (ret != ENOENT) {
+ talloc_zfree(state->msgs[state->cur]);
+ }
+
+ state->cur++;
+ if (state->cur < state->count) {
+ cleanup_users_update(req);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+/* ==Group-Cleanup-Process================================================ */
+
+struct cleanup_groups_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *ctx;
+ struct sysdb_ctx *sysdb;
+ struct sss_domain_info *domain;
+
+ struct sysdb_handle *handle;
+
+ struct ldb_message **msgs;
+ size_t count;
+ int cur;
+};
+
+static void cleanup_groups_process(struct tevent_req *subreq);
+static void cleanup_groups_update(struct tevent_req *req);
+static void cleanup_groups_up_done(struct tevent_req *subreq);
+
+static struct tevent_req *cleanup_groups_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx)
+{
+ struct tevent_req *req, *subreq;
+ struct cleanup_groups_state *state;
+ static const char *attrs[] = { SYSDB_NAME, NULL };
+ time_t now = time(NULL);
+ char *subfilter;
+
+ req = tevent_req_create(memctx, &state, struct cleanup_groups_state);
+ if (!req) {
+ return NULL;
+ }
+
+ state->ev = ev;
+ state->ctx = ctx;
+ state->sysdb = ctx->be->sysdb;
+ state->domain = ctx->be->domain;
+ state->msgs = NULL;
+ state->count = 0;
+ state->cur = 0;
+
+ subfilter = talloc_asprintf(state, "(&(!(%s=0))(%s<=%ld))",
+ SYSDB_CACHE_EXPIRE,
+ SYSDB_CACHE_EXPIRE, (long)now);
+ if (!subfilter) {
+ DEBUG(2, ("Failed to build filter\n"));
+ talloc_zfree(req);
+ return NULL;
+ }
+
+ subreq = sysdb_search_groups_send(state, state->ev,
+ state->sysdb, NULL,
+ state->domain, subfilter, attrs);
+ if (!subreq) {
+ DEBUG(2, ("Failed to send entry search\n"));
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, cleanup_groups_process, req);
+
+ return req;
+}
+
+static void cleanup_groups_process(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cleanup_groups_state *state = tevent_req_data(req,
+ struct cleanup_groups_state);
+ int ret;
+
+ ret = sysdb_search_groups_recv(subreq, state, &state->count, &state->msgs);
+ talloc_zfree(subreq);
+ if (ret) {
+ if (ret == ENOENT) {
+ tevent_req_done(req);
+ return;
+ }
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ DEBUG(4, ("Found %d expired group entries!\n", state->count));
+
+ if (state->count == 0) {
+ tevent_req_done(req);
+ }
+
+ cleanup_groups_update(req);
+}
+
+static void cleanup_groups_update(struct tevent_req *req)
+{
+ struct tevent_req *subreq;
+ struct cleanup_groups_state *state = tevent_req_data(req,
+ struct cleanup_groups_state);
+ const char *str;
+
+ str = ldb_msg_find_attr_as_string(state->msgs[state->cur],
+ SYSDB_NAME, NULL);
+ if (!str) {
+ DEBUG(2, ("Entry %s has no Name Attribute ?!?\n",
+ ldb_dn_get_linearized(state->msgs[state->cur]->dn)));
+ tevent_req_error(req, EFAULT);
+ return;
+ }
+
+ subreq = groups_get_send(state, state->ev, state->ctx,
+ str, BE_FILTER_NAME, BE_ATTR_CORE);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, cleanup_groups_up_done, req);
+}
+
+static void cleanup_groups_up_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct cleanup_groups_state *state = tevent_req_data(req,
+ struct cleanup_groups_state);
+ int ret;
+
+ ret = groups_get_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret) {
+ DEBUG(2, ("User check returned: %d(%s)\n",
+ ret, strerror(ret)));
+ }
+
+ state->cur++;
+ if (state->cur < state->count) {
+ cleanup_groups_update(req);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
diff --git a/server/providers/ldap/ldap_id_enum.c b/server/providers/ldap/ldap_id_enum.c
index b7035efe5..10b8d96c4 100644
--- a/server/providers/ldap/ldap_id_enum.c
+++ b/server/providers/ldap/ldap_id_enum.c
@@ -31,31 +31,36 @@
#include "providers/ldap/ldap_common.h"
#include "providers/ldap/sdap_async.h"
+extern struct tevent_req *ldap_id_cleanup_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *ctx);
+
/* ==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)
+static void ldap_id_enumerate_timer(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;
+ int delay;
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());
+ delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+ tv = tevent_timeval_current_ofs(delay, 0);
+ ldap_id_enumerate_set_timer(ctx, tv);
return;
}
@@ -65,16 +70,17 @@ void ldap_id_enumerate(struct tevent_context *ev,
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());
+ delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+ tv = tevent_timeval_current_ofs(delay, 0);
+ ldap_id_enumerate_set_timer(ctx, tv);
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);
+ delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+ tv = tevent_timeval_current_ofs(delay, 0);
timeout = tevent_add_timer(ctx->be->ev, req, tv,
ldap_id_enumerate_timeout, req);
return;
@@ -87,11 +93,13 @@ static void ldap_id_enumerate_timeout(struct tevent_context *ev,
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;
+ int delay;
- 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());
+ delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+ DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n", delay));
+
+ tv = tevent_timeval_current_ofs(delay, 0);
+ ldap_id_enumerate_set_timer(ctx, tv);
talloc_zfree(req);
}
@@ -100,9 +108,10 @@ 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;
+ struct timeval tv;
+ int delay;
if (tevent_req_is_error(req, &tstate, &err)) {
/* On error schedule starting from now, not the last run */
@@ -112,25 +121,29 @@ static void ldap_id_enumerate_reschedule(struct tevent_req *req)
}
talloc_zfree(req);
- ldap_id_enumerate_set_timer(ctx, ctx->last_run);
+ delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);
+ tv = tevent_timeval_add(&tv, delay, 0);
+ ldap_id_enumerate_set_timer(ctx, tv);
}
-static void ldap_id_enumerate_set_timer(struct sdap_id_ctx *ctx,
- struct timeval tv)
+
+
+int 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);
+ DEBUG(6, ("Scheduling next enumeration at %ld.%ld\n",
+ (long)tv.tv_sec, (long)tv.tv_usec));
+
+ enum_task = tevent_add_timer(ctx->be->ev, ctx,
+ tv, ldap_id_enumerate_timer, ctx);
if (!enum_task) {
DEBUG(0, ("FATAL: failed to setup enumeration task!\n"));
- /* shutdown! */
- exit(1);
+ return EFAULT;
}
-}
+ return EOK;
+}
struct global_enum_state {
@@ -146,6 +159,7 @@ 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 void ldap_id_enum_cleanup_done(struct tevent_req *subreq);
static struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev,
struct sdap_id_ctx *ctx)
@@ -182,7 +196,9 @@ static void ldap_id_enum_users_done(struct tevent_req *subreq)
if (tstate != TEVENT_REQ_USER_ERROR) {
err = EIO;
}
- goto fail;
+ if (err != ENOENT) {
+ goto fail;
+ }
}
talloc_zfree(subreq);
@@ -219,11 +235,18 @@ static void ldap_id_enum_groups_done(struct tevent_req *subreq)
if (tstate != TEVENT_REQ_USER_ERROR) {
err = EIO;
}
- goto fail;
+ if (err != ENOENT) {
+ goto fail;
+ }
}
talloc_zfree(subreq);
- tevent_req_done(req);
+ subreq = ldap_id_cleanup_send(state, state->ev, state->ctx);
+ if (!subreq) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, ldap_id_enum_cleanup_done, req);
+
return;
fail:
@@ -234,6 +257,14 @@ fail:
tevent_req_done(req);
}
+static void ldap_id_enum_cleanup_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ talloc_zfree(subreq);
+ tevent_req_done(req);
+}
+
/* ==User-Enumeration===================================================== */
diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h
index fec9eefaa..8330bd6fc 100644
--- a/server/providers/ldap/sdap.h
+++ b/server/providers/ldap/sdap.h
@@ -107,6 +107,7 @@ enum sdap_basic_opt {
SDAP_OFFLINE_TIMEOUT,
SDAP_FORCE_UPPER_CASE_REALM,
SDAP_ENUM_REFRESH_TIMEOUT,
+ SDAP_CACHE_PURGE_TIMEOUT,
SDAP_ENTRY_CACHE_TIMEOUT,
SDAP_TLS_CACERT,
SDAP_TLS_CACERTDIR,