summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/providers/ldap/ldap_id.c575
-rw-r--r--server/providers/ldap/sdap.c22
-rw-r--r--server/providers/ldap/sdap.h10
-rw-r--r--server/providers/ldap/sdap_async.c148
-rw-r--r--server/providers/ldap/sdap_async.h6
5 files changed, 693 insertions, 68 deletions
diff --git a/server/providers/ldap/ldap_id.c b/server/providers/ldap/ldap_id.c
index a8093308..b5fdc63b 100644
--- a/server/providers/ldap/ldap_id.c
+++ b/server/providers/ldap/ldap_id.c
@@ -32,6 +32,8 @@
#include "providers/ldap/sdap_async.h"
struct sdap_id_ctx {
+ struct be_ctx *be;
+
struct sdap_options *opts;
/* global sdap handler */
@@ -39,6 +41,12 @@ struct sdap_id_ctx {
time_t went_offline;
bool offline;
+
+ /* enumeration loop timer */
+ struct timeval last_run;
+
+ char *max_user_timestamp;
+ char *max_group_timestamp;
};
static void sdap_req_done(struct be_req *req, int ret, const char *err)
@@ -79,20 +87,23 @@ static int build_attrs_from_map(TALLOC_CTX *memctx,
const char ***_attrs)
{
char **attrs;
- int i;
+ int i, j;
attrs = talloc_array(memctx, char *, size + 1);
if (!attrs) return ENOMEM;
- /* first attribute is the objectclass value not the attribute name */
+ /* first attribute is "objectclass" not the specifc one */
attrs[0] = talloc_strdup(memctx, "objectClass");
if (!attrs[0]) return ENOMEM;
/* add the others */
- for (i = 1; i < size; i++) {
- attrs[i] = map[i].name;
+ for (i = j = 1; i < size; i++) {
+ if (map[i].name) {
+ attrs[j] = map[i].name;
+ j++;
+ }
}
- attrs[i] = NULL;
+ attrs[j] = NULL;
*_attrs = (const char **)attrs;
@@ -229,9 +240,6 @@ struct users_get_state {
struct tevent_context *ev;
struct sdap_id_ctx *ctx;
- struct sss_domain_info *dom;
- struct sysdb_ctx *sysdb;
-
char *filter;
const char **attrs;
};
@@ -242,8 +250,7 @@ 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,
- struct be_ctx *bectx,
- const char *wildcard,
+ const char *name,
int filter_type,
int attrs_type)
{
@@ -257,8 +264,6 @@ static struct tevent_req *users_get_send(TALLOC_CTX *memctx,
state->ev = ev;
state->ctx = ctx;
- state->dom = bectx->domain;
- state->sysdb = bectx->sysdb;
switch(filter_type) {
case BE_FILTER_NAME:
@@ -273,7 +278,7 @@ static struct tevent_req *users_get_send(TALLOC_CTX *memctx,
}
state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
- attr_name, wildcard,
+ attr_name, name,
ctx->opts->user_map[SDAP_OC_USER].name);
if (!state->filter) {
DEBUG(2, ("Failed to build filter\n"));
@@ -307,7 +312,8 @@ static struct tevent_req *users_get_send(TALLOC_CTX *memctx,
}
subreq = sdap_get_users_send(state, state->ev,
- state->dom, bectx->sysdb,
+ state->ctx->be->domain,
+ state->ctx->be->sysdb,
state->ctx->opts, state->ctx->gsh,
state->attrs, state->filter);
if (!subreq) {
@@ -340,7 +346,8 @@ static void users_get_connect_done(struct tevent_req *subreq)
}
subreq = sdap_get_users_send(state, state->ev,
- state->dom, state->sysdb,
+ state->ctx->be->domain,
+ state->ctx->be->sysdb,
state->ctx->opts, state->ctx->gsh,
state->attrs, state->filter);
if (!subreq) {
@@ -356,7 +363,7 @@ static void users_get_op_done(struct tevent_req *subreq)
struct tevent_req);
int ret;
- ret = sdap_get_users_recv(subreq);
+ ret = sdap_get_users_recv(subreq, NULL, NULL);
talloc_zfree(subreq);
if (ret) {
tevent_req_error(req, ret);
@@ -389,9 +396,6 @@ struct groups_get_state {
struct tevent_context *ev;
struct sdap_id_ctx *ctx;
- struct sss_domain_info *dom;
- struct sysdb_ctx *sysdb;
-
char *filter;
const char **attrs;
};
@@ -402,8 +406,7 @@ 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,
- struct be_ctx *bectx,
- const char *wildcard,
+ const char *name,
int filter_type,
int attrs_type)
{
@@ -417,8 +420,6 @@ static struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
state->ev = ev;
state->ctx = ctx;
- state->dom = bectx->domain;
- state->sysdb = bectx->sysdb;
switch(filter_type) {
case BE_FILTER_NAME:
@@ -433,7 +434,7 @@ static struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
}
state->filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",
- attr_name, wildcard,
+ attr_name, name,
ctx->opts->group_map[SDAP_OC_GROUP].name);
if (!state->filter) {
DEBUG(2, ("Failed to build filter\n"));
@@ -467,7 +468,8 @@ static struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
}
subreq = sdap_get_groups_send(state, state->ev,
- state->dom, bectx->sysdb,
+ state->ctx->be->domain,
+ state->ctx->be->sysdb,
state->ctx->opts, state->ctx->gsh,
state->attrs, state->filter);
if (!subreq) {
@@ -500,9 +502,10 @@ static void groups_get_connect_done(struct tevent_req *subreq)
}
subreq = sdap_get_groups_send(state, state->ev,
- state->dom, state->sysdb,
- state->ctx->opts, state->ctx->gsh,
- state->attrs, state->filter);
+ 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;
@@ -516,7 +519,7 @@ static void groups_get_op_done(struct tevent_req *subreq)
struct tevent_req);
int ret;
- ret = sdap_get_groups_recv(subreq);
+ ret = sdap_get_groups_recv(subreq, NULL, NULL);
talloc_zfree(subreq);
if (ret) {
tevent_req_error(req, ret);
@@ -548,8 +551,6 @@ static void groups_get_done(struct tevent_req *req)
struct groups_by_user_state {
struct tevent_context *ev;
struct sdap_id_ctx *ctx;
- struct sss_domain_info *dom;
- struct sysdb_ctx *sysdb;
const char *name;
const char **attrs;
};
@@ -560,8 +561,6 @@ static void groups_by_user_op_done(struct tevent_req *subreq);
static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
struct sdap_id_ctx *ctx,
- struct sss_domain_info *dom,
- struct sysdb_ctx *sysdb,
const char *name)
{
struct tevent_req *req, *subreq;
@@ -573,8 +572,6 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
state->ev = ev;
state->ctx = ctx;
- state->dom = dom;
- state->sysdb = sysdb;
state->name = name;
ret = build_attrs_from_map(state, ctx->opts->group_map,
@@ -602,7 +599,8 @@ static struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx,
}
subreq = sdap_get_initgr_send(state, state->ev,
- state->dom, state->sysdb,
+ state->ctx->be->domain,
+ state->ctx->be->sysdb,
state->ctx->opts, state->ctx->gsh,
state->name, state->attrs);
if (!subreq) {
@@ -635,7 +633,8 @@ static void groups_by_user_connect_done(struct tevent_req *subreq)
}
subreq = sdap_get_initgr_send(state, state->ev,
- state->dom, state->sysdb,
+ state->ctx->be->domain,
+ state->ctx->be->sysdb,
state->ctx->opts, state->ctx->gsh,
state->name, state->attrs);
if (!subreq) {
@@ -703,8 +702,12 @@ static void sdap_get_account_info(struct be_req *breq)
switch (ar->entry_type) {
case BE_REQ_USER: /* user */
- req = users_get_send(breq, breq->be_ctx->ev,
- ctx, breq->be_ctx,
+ /* skip enumerations on demand */
+ if (strcmp(ar->filter_value, "*") == 0) {
+ return sdap_req_done(breq, EOK, "Success");
+ }
+
+ req = users_get_send(breq, breq->be_ctx->ev, ctx,
ar->filter_value,
ar->filter_type,
ar->attr_type);
@@ -718,8 +721,12 @@ static void sdap_get_account_info(struct be_req *breq)
case BE_REQ_GROUP: /* group */
- req = groups_get_send(breq, breq->be_ctx->ev,
- ctx, breq->be_ctx,
+ if (strcmp(ar->filter_value, "*") == 0) {
+ return sdap_req_done(breq, EOK, "Success");
+ }
+
+ /* skip enumerations on demand */
+ req = groups_get_send(breq, breq->be_ctx->ev, ctx,
ar->filter_value,
ar->filter_type,
ar->attr_type);
@@ -748,7 +755,6 @@ static void sdap_get_account_info(struct be_req *breq)
break;
}
req = groups_by_user_send(breq, breq->be_ctx->ev, ctx,
- breq->be_ctx->domain, breq->be_ctx->sysdb,
ar->filter_value);
if (!req) ret = ENOMEM;
/* tevent_req_set_callback(req, groups_by_user_done, breq); */
@@ -765,6 +771,478 @@ static void sdap_get_account_info(struct be_req *breq)
if (ret != EOK) return sdap_req_done(breq, 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;
+
+ 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();
+ tv = tevent_timeval_add(&tv, ctx->opts->enum_refresh_timeout, 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);
+
+ DEBUG(1, ("Enumeration timed out! Timeout too small? (%ds)!\n",
+ ctx->opts->enum_refresh_timeout));
+ 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);
+ 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;
+
+ tv = tevent_timeval_add(&tv, ctx->opts->enum_refresh_timeout, 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;
+
+ 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:
+ DEBUG(1, ("Failed to enumerate users, retrying later!\n"));
+ /* schedule starting from now, not the last run */
+ ldap_id_enumerate_set_timer(state->ctx, tevent_timeval_current());
+
+ talloc_zfree(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(req);
+
+ ldap_id_enumerate_set_timer(state->ctx, state->ctx->last_run);
+
+ return;
+
+fail:
+ DEBUG(1, ("Failed to enumerate groups, retrying later!\n"));
+ /* schedule starting from now, not the last run */
+ ldap_id_enumerate_set_timer(state->ctx, tevent_timeval_current());
+
+ talloc_zfree(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 users_get_state *state;
+ int ret;
+
+ req = tevent_req_create(memctx, &state, struct users_get_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_id_connect_send(state, ev, ctx, false,
+ ctx->opts->basic[SDAP_DEFAULT_BIND_DN].value,
+ ctx->opts->basic[SDAP_DEFAULT_AUTHTOK_TYPE].value,
+ ctx->opts->basic[SDAP_DEFAULT_AUTHTOK].value);
+ 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_id_connect_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret) {
+ 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_id_connect_send(state, ev, ctx, false,
+ ctx->opts->basic[SDAP_DEFAULT_BIND_DN].value,
+ ctx->opts->basic[SDAP_DEFAULT_AUTHTOK_TYPE].value,
+ ctx->opts->basic[SDAP_DEFAULT_AUTHTOK].value);
+ 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_id_connect_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret) {
+ 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);
+}
+
+
+
+/* ==Initialization-Functions============================================= */
+
static void sdap_shutdown(struct be_req *req)
{
/* TODO: Clean up any internal data */
@@ -782,6 +1260,7 @@ int sssm_ldap_init(struct be_ctx *bectx,
void **pvt_data)
{
int ldap_opt_x_tls_require_cert;
+ struct tevent_timer *enum_task;
struct sdap_id_ctx *ctx;
char *tls_reqcert;
int ret;
@@ -789,6 +1268,8 @@ int sssm_ldap_init(struct be_ctx *bectx,
ctx = talloc_zero(bectx, struct sdap_id_ctx);
if (!ctx) return ENOMEM;
+ ctx->be = bectx;
+
ret = sdap_get_options(ctx, bectx->cdb, bectx->conf_path,
&ctx->opts);
@@ -825,6 +1306,16 @@ int sssm_ldap_init(struct be_ctx *bectx,
}
}
+ /* set up enumeration task */
+ ctx->last_run = tevent_timeval_current(); /* run the first immediately */
+ 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;
+ goto done;
+ }
+
*ops = &sdap_id_ops;
*pvt_data = ctx;
ret = EOK;
diff --git a/server/providers/ldap/sdap.c b/server/providers/ldap/sdap.c
index 3260043b..dacce9c2 100644
--- a/server/providers/ldap/sdap.c
+++ b/server/providers/ldap/sdap.c
@@ -40,8 +40,9 @@ struct sdap_gen_opts default_basic_opts[] = {
{ "groupSearchScope", "sub", NULL },
{ "groupSearchFilter", NULL, NULL },
{ "ldapSchema", "rfc2307", NULL },
- { "offline_timeout", "5", NULL },
- { "force_upper_case_realm", "0", NULL }
+ { "offline_timeout", "60", NULL },
+ { "force_upper_case_realm", "0", NULL },
+ { "enumeration_refresh_timeout", "300", NULL }
};
struct sdap_id_map rfc2307_user_map[] = {
@@ -56,7 +57,8 @@ struct sdap_id_map rfc2307_user_map[] = {
{ "userPrincipal", "krbPrincipalName", SYSDB_UPN, NULL },
{ "userFullname", "cn", SYSDB_FULLNAME, NULL },
{ "userMemberOf", NULL, SYSDB_MEMBEROF, NULL },
- { "userUUID", NULL, SYSDB_UUID, NULL }
+ { "userUUID", NULL, SYSDB_UUID, NULL },
+ { "userModifyTimestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }
};
struct sdap_id_map rfc2307_group_map[] = {
@@ -65,7 +67,8 @@ struct sdap_id_map rfc2307_group_map[] = {
{ "groupPwd", "userPassword", SYSDB_PWD, NULL },
{ "groupGidNumber", "gidNumber", SYSDB_GIDNUM, NULL },
{ "groupMember", "memberuid", SYSDB_MEMBER, NULL },
- { "groupUUID", NULL, SYSDB_UUID, NULL }
+ { "groupUUID", NULL, SYSDB_UUID, NULL },
+ { "groupModifyTimestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }
};
struct sdap_id_map rfc2307bis_user_map[] = {
@@ -81,7 +84,8 @@ struct sdap_id_map rfc2307bis_user_map[] = {
{ "userFullname", "cn", SYSDB_FULLNAME, NULL },
{ "userMemberOf", "memberOf", SYSDB_MEMBEROF, NULL },
/* FIXME: this is 389ds specific */
- { "userUUID", "nsUniqueId", SYSDB_UUID, NULL }
+ { "userUUID", "nsUniqueId", SYSDB_UUID, NULL },
+ { "userModifyTimestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }
};
struct sdap_id_map rfc2307bis_group_map[] = {
@@ -91,7 +95,8 @@ struct sdap_id_map rfc2307bis_group_map[] = {
{ "groupGidNumber", "gidNumber", SYSDB_GIDNUM, NULL },
{ "groupMember", "member", SYSDB_MEMBER, NULL },
/* FIXME: this is 389ds specific */
- { "groupUUID", "nsUniqueId", SYSDB_UUID, NULL }
+ { "groupUUID", "nsUniqueId", SYSDB_UUID, NULL },
+ { "groupModifyTimestamp", "modifyTimestamp", SYSDB_ORIG_MODSTAMP, NULL }
};
/* =Retrieve-Options====================================================== */
@@ -171,6 +176,11 @@ int sdap_get_options(TALLOC_CTX *memctx,
&opts->force_upper_case_realm);
if (ret != EOK) goto done;
+ ret = confdb_get_int(cdb, opts, conf_path,
+ "enumeration_refresh_timeout", 300,
+ &opts->enum_refresh_timeout);
+ if (ret != EOK) goto done;
+
/* schema type */
if (strcasecmp(opts->basic[SDAP_SCHEMA].value, "rfc2307") == 0) {
opts->schema_type = SDAP_SCHEMA_RFC2307;
diff --git a/server/providers/ldap/sdap.h b/server/providers/ldap/sdap.h
index 50fc3d10..42af68f5 100644
--- a/server/providers/ldap/sdap.h
+++ b/server/providers/ldap/sdap.h
@@ -85,8 +85,9 @@ enum sdap_result {
#define SDAP_SCHEMA 13
#define SDAP_OFFLINE_TIMEOUT 14
#define SDAP_FORCE_UPPER_CASE_REALM 15
+#define SDAP_ENUM_REFRESH_TIMEOUT 16
-#define SDAP_OPTS_BASIC 16 /* opts counter */
+#define SDAP_OPTS_BASIC 17 /* opts counter */
/* the objectclass must be the first attribute.
* Functions depend on this */
@@ -102,8 +103,9 @@ enum sdap_result {
#define SDAP_AT_USER_PRINC 9
#define SDAP_AT_USER_FULLNAME 10
#define SDAP_AT_USER_MEMBEROF 11
+#define SDAP_AT_USER_MODSTAMP 12
-#define SDAP_OPTS_USER 12 /* attrs counter */
+#define SDAP_OPTS_USER 13 /* attrs counter */
/* the objectclass must be the first attribute.
* Functions depend on this */
@@ -113,8 +115,9 @@ enum sdap_result {
#define SDAP_AT_GROUP_GID 3
#define SDAP_AT_GROUP_MEMBER 4
#define SDAP_AT_GROUP_UUID 5
+#define SDAP_AT_GROUP_MODSTAMP 6
-#define SDAP_OPTS_GROUP 6 /* attrs counter */
+#define SDAP_OPTS_GROUP 7 /* attrs counter */
struct sdap_gen_opts {
const char *opt_name;
@@ -140,6 +143,7 @@ struct sdap_options {
int network_timeout;
int opt_timeout;
int offline_timeout;
+ int enum_refresh_timeout;
bool force_upper_case_realm;
/* supported schema types */
diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c
index 57ccd865..4d74061f 100644
--- a/server/providers/ldap/sdap_async.c
+++ b/server/providers/ldap/sdap_async.c
@@ -834,6 +834,7 @@ struct sdap_save_user_state {
const char *name;
struct sysdb_attrs *attrs;
+ char *timestamp;
};
static void sdap_save_user_done(struct tevent_req *subreq);
@@ -871,6 +872,7 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
state->sh = sh;
state->dom = dom;
state->opts = opts;
+ state->timestamp = NULL;
ret = sdap_parse_user(state, state->opts, state->sh,
entry, &state->attrs, NULL);
@@ -966,6 +968,29 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
}
ret = sysdb_attrs_get_el(state->attrs,
+ opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name, &el);
+ if (ret) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
+ state->name));
+ } else {
+ ret = sysdb_attrs_add_string(user_attrs,
+ opts->user_map[SDAP_AT_USER_MODSTAMP].sys_name,
+ (const char*)el->values[0].data);
+ if (ret) {
+ goto fail;
+ }
+ state->timestamp = talloc_strdup(state,
+ (const char*)el->values[0].data);
+ if (!state->timestamp) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ }
+
+ ret = sysdb_attrs_get_el(state->attrs,
opts->user_map[SDAP_AT_USER_PRINC].sys_name, &el);
if (ret) {
goto fail;
@@ -991,10 +1016,10 @@ static struct tevent_req *sdap_save_user_send(TALLOC_CTX *memctx,
DEBUG(6, ("Storing info for user %s\n", state->name));
- subreq = sysdb_store_user_with_attrs_send(state, state->ev, state->handle,
- state->dom, state->name, pwd,
- uid, gid, gecos, homedir, shell,
- user_attrs);
+ subreq = sysdb_store_user_send(state, state->ev, state->handle,
+ state->dom, state->name, pwd,
+ uid, gid, gecos, homedir, shell,
+ user_attrs);
if (!subreq) {
ret = ENOMEM;
goto fail;
@@ -1017,7 +1042,7 @@ static void sdap_save_user_done(struct tevent_req *subreq)
struct sdap_save_user_state);
int ret;
- ret = sysdb_store_user_with_attrs_recv(subreq);
+ ret = sysdb_store_user_recv(subreq);
talloc_zfree(subreq);
if (ret) {
DEBUG(2, ("Failed to save user %s\n", state->name));
@@ -1028,8 +1053,11 @@ static void sdap_save_user_done(struct tevent_req *subreq)
tevent_req_done(req);
}
-int sdap_save_user_recv(struct tevent_req *req)
+static int sdap_save_user_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx, char **timestamp)
{
+ struct sdap_save_user_state *state = tevent_req_data(req,
+ struct sdap_save_user_state);
enum tevent_req_state tstate;
uint64_t err;
@@ -1038,6 +1066,8 @@ int sdap_save_user_recv(struct tevent_req *req)
return err;
}
+ *timestamp = talloc_steal(mem_ctx, state->timestamp);
+
return EOK;
}
@@ -1054,6 +1084,7 @@ struct sdap_save_group_state {
const char *name;
struct sysdb_attrs *attrs;
+ char *timestamp;
};
static void sdap_save_group_done(struct tevent_req *subreq);
@@ -1076,6 +1107,7 @@ static struct tevent_req *sdap_save_group_send(TALLOC_CTX *memctx,
const char **members;
long int l;
gid_t gid;
+ struct sysdb_attrs *group_attrs;
req = tevent_req_create(memctx, &state, struct sdap_save_group_state);
if (!req) return NULL;
@@ -1085,6 +1117,7 @@ static struct tevent_req *sdap_save_group_send(TALLOC_CTX *memctx,
state->sh = sh;
state->dom = dom;
state->opts = opts;
+ state->timestamp = NULL;
ret = sdap_parse_group(state, state->opts, state->sh,
entry, &state->attrs, NULL);
@@ -1126,10 +1159,41 @@ static struct tevent_req *sdap_save_group_send(TALLOC_CTX *memctx,
}
gid = l;
+ group_attrs = sysdb_new_attrs(state);
+ if (!group_attrs) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = sysdb_attrs_get_el(state->attrs,
+ opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name, &el);
+ if (ret) {
+ goto fail;
+ }
+ if (el->num_values == 0) {
+ DEBUG(7, ("Original mod-Timestamp is not available for [%s].\n",
+ state->name));
+ } else {
+ ret = sysdb_attrs_add_string(group_attrs,
+ opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name,
+ (const char*)el->values[0].data);
+ if (ret) {
+ goto fail;
+ }
+ state->timestamp = talloc_strdup(state,
+ (const char*)el->values[0].data);
+ if (!state->timestamp) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ }
+
DEBUG(6, ("Storing info for group %s\n", state->name));
- subreq = sysdb_store_group_send(state, state->ev, state->handle,
- state->dom, state->name, gid, members);
+ subreq = sysdb_store_group_send(state, state->ev,
+ state->handle, state->dom,
+ state->name, gid, members,
+ group_attrs);
if (!subreq) {
ret = ENOMEM;
goto fail;
@@ -1155,7 +1219,7 @@ static void sdap_save_group_done(struct tevent_req *subreq)
ret = sysdb_store_group_recv(subreq);
talloc_zfree(subreq);
if (ret) {
- DEBUG(2, ("Failed to save group %s\n", state->name));
+ DEBUG(2, ("Failed to save group %s [%d]\n", state->name, ret));
tevent_req_error(req, ret);
return;
}
@@ -1163,8 +1227,11 @@ static void sdap_save_group_done(struct tevent_req *subreq)
tevent_req_done(req);
}
-int sdap_save_group_recv(struct tevent_req *req)
+static int sdap_save_group_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx, char **timestamp)
{
+ struct sdap_save_group_state *state = tevent_req_data(req,
+ struct sdap_save_group_state);
enum tevent_req_state tstate;
uint64_t err;
@@ -1173,6 +1240,8 @@ int sdap_save_group_recv(struct tevent_req *req)
return err;
}
+ *timestamp = talloc_steal(mem_ctx, state->timestamp);
+
return EOK;
}
@@ -1189,6 +1258,8 @@ struct sdap_get_users_state {
struct sysdb_handle *handle;
struct sdap_op *op;
+
+ char *higher_timestamp;
};
static void sdap_get_users_transaction(struct tevent_req *subreq);
@@ -1218,6 +1289,7 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
state->sh = sh;
state->filter = filter;
state->attrs = attrs;
+ state->higher_timestamp = NULL;
subreq = sysdb_transaction_send(state, state->ev, sysdb);
if (!subreq) return NULL;
@@ -1344,23 +1416,41 @@ static void sdap_get_users_save_done(struct tevent_req *subreq)
struct tevent_req);
struct sdap_get_users_state *state = tevent_req_data(req,
struct sdap_get_users_state);
+ char *timestamp;
int ret;
- ret = sdap_save_user_recv(subreq);
+ ret = sdap_save_user_recv(subreq, state, &timestamp);
talloc_zfree(subreq);
/* Do not fail completely on errors.
* Just report the failure to save and go on */
if (ret) {
DEBUG(2, ("Failed to store user. Ignoring.\n"));
+ timestamp = NULL;
+ }
+
+ if (timestamp) {
+ if (state->higher_timestamp) {
+ if (strcmp(timestamp, state->higher_timestamp) > 0) {
+ talloc_zfree(state->higher_timestamp);
+ state->higher_timestamp = timestamp;
+ } else {
+ talloc_zfree(timestamp);
+ }
+ } else {
+ state->higher_timestamp = timestamp;
+ }
}
/* unlock the operation so that we can proceed with the next result */
sdap_unlock_next_reply(state->op);
}
-int sdap_get_users_recv(struct tevent_req *req)
+int sdap_get_users_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx, char **timestamp)
{
+ struct sdap_get_users_state *state = tevent_req_data(req,
+ struct sdap_get_users_state);
enum tevent_req_state tstate;
uint64_t err;
@@ -1369,6 +1459,10 @@ int sdap_get_users_recv(struct tevent_req *req)
return EIO;
}
+ if (timestamp) {
+ *timestamp = talloc_steal(mem_ctx, state->higher_timestamp);
+ }
+
return EOK;
}
@@ -1384,6 +1478,7 @@ struct sdap_get_groups_state {
struct sysdb_handle *handle;
struct sdap_op *op;
+ char *higher_timestamp;
};
static void sdap_get_groups_transaction(struct tevent_req *subreq);
@@ -1413,6 +1508,7 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
state->sh = sh;
state->filter = filter;
state->attrs = attrs;
+ state->higher_timestamp = NULL;
subreq = sysdb_transaction_send(state, state->ev, sysdb);
if (!subreq) return NULL;
@@ -1544,9 +1640,10 @@ static void sdap_get_groups_save_done(struct tevent_req *subreq)
struct tevent_req);
struct sdap_get_groups_state *state = tevent_req_data(req,
struct sdap_get_groups_state);
+ char *timestamp;
int ret;
- ret = sdap_save_group_recv(subreq);
+ ret = sdap_save_group_recv(subreq, state, &timestamp);
talloc_zfree(subreq);
/* Do not fail completely on errors.
@@ -1554,14 +1651,31 @@ static void sdap_get_groups_save_done(struct tevent_req *subreq)
if (ret) {
DEBUG(2, ("Failed to store group. Ignoring.\n"));
+ timestamp = NULL;
+ }
+
+ if (timestamp) {
+ if (state->higher_timestamp) {
+ if (strcmp(timestamp, state->higher_timestamp) > 0) {
+ talloc_zfree(state->higher_timestamp);
+ state->higher_timestamp = timestamp;
+ } else {
+ talloc_zfree(timestamp);
+ }
+ } else {
+ state->higher_timestamp = timestamp;
+ }
}
/* unlock the operation so that we can proceed with the next result */
sdap_unlock_next_reply(state->op);
}
-int sdap_get_groups_recv(struct tevent_req *req)
+int sdap_get_groups_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx, char **timestamp)
{
+ struct sdap_get_groups_state *state = tevent_req_data(req,
+ struct sdap_get_groups_state);
enum tevent_req_state tstate;
uint64_t err;
@@ -1570,6 +1684,10 @@ int sdap_get_groups_recv(struct tevent_req *req)
return EIO;
}
+ if (timestamp) {
+ *timestamp = talloc_steal(mem_ctx, state->higher_timestamp);
+ }
+
return EOK;
}
@@ -1853,7 +1971,7 @@ static void sdap_get_initgr_save_done(struct tevent_req *subreq)
struct sdap_get_initgr_state);
int ret;
- ret = sdap_save_group_recv(subreq);
+ ret = sdap_save_group_recv(subreq, NULL, NULL);
talloc_zfree(subreq);
/* Do not fail completely on errors.
diff --git a/server/providers/ldap/sdap_async.h b/server/providers/ldap/sdap_async.h
index 0cb0b907..c9af750b 100644
--- a/server/providers/ldap/sdap_async.h
+++ b/server/providers/ldap/sdap_async.h
@@ -40,7 +40,8 @@ struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
struct sdap_handle *sh,
const char **attrs,
const char *wildcard);
-int sdap_get_users_recv(struct tevent_req *req);
+int sdap_get_users_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx, char **timestamp);
struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
@@ -50,7 +51,8 @@ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
struct sdap_handle *sh,
const char **attrs,
const char *wildcard);
-int sdap_get_groups_recv(struct tevent_req *req);
+int sdap_get_groups_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx, char **timestamp);
struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx,
struct tevent_context *ev,