summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/providers/ldap/ldap_id.c2
-rw-r--r--src/providers/ldap/ldap_id_enum.c60
-rw-r--r--src/providers/ldap/sdap.c5
-rw-r--r--src/providers/ldap/sdap.h1
-rw-r--r--src/providers/ldap/sdap_async.h11
-rw-r--r--src/providers/ldap/sdap_async_services.c138
-rw-r--r--src/providers/ldap/sdap_id_op.c1
7 files changed, 215 insertions, 3 deletions
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index db49e77d9..a433a8d53 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -731,11 +731,13 @@ static void sdap_check_online_done(struct tevent_req *req)
if (!check_ctx->id_ctx->srv_opts) {
srv_opts->max_user_value = 0;
srv_opts->max_group_value = 0;
+ srv_opts->max_service_value = 0;
} else if (strcmp(srv_opts->server_id, check_ctx->id_ctx->srv_opts->server_id) == 0
&& srv_opts->supports_usn
&& check_ctx->id_ctx->srv_opts->last_usn > srv_opts->last_usn) {
check_ctx->id_ctx->srv_opts->max_user_value = 0;
check_ctx->id_ctx->srv_opts->max_group_value = 0;
+ check_ctx->id_ctx->srv_opts->max_service_value = 0;
check_ctx->id_ctx->srv_opts->last_usn = srv_opts->last_usn;
}
diff --git a/src/providers/ldap/ldap_id_enum.c b/src/providers/ldap/ldap_id_enum.c
index 7a8d0712e..3679a7d7f 100644
--- a/src/providers/ldap/ldap_id_enum.c
+++ b/src/providers/ldap/ldap_id_enum.c
@@ -199,6 +199,7 @@ static struct tevent_req *enum_groups_send(TALLOC_CTX *memctx,
struct sdap_id_op *op,
bool purge);
static void ldap_id_enum_groups_done(struct tevent_req *subreq);
+static void ldap_id_enum_services_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,
@@ -362,7 +363,59 @@ static void ldap_id_enum_groups_done(struct tevent_req *subreq)
}
talloc_zfree(subreq);
- ret = sdap_id_op_done(state->op, (int)err, &dp_error);
+ if (err != EOK) {
+ /* We call sdap_id_op_done only on error
+ * as the connection is reused by services enumeration */
+ ret = sdap_id_op_done(state->op, (int)err, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = ldap_id_enumerate_retry(req);
+ if (ret == EOK) {
+ return;
+ }
+
+ dp_error = DP_ERR_FATAL;
+ }
+
+ if (ret != EOK) {
+ if (dp_error == DP_ERR_OFFLINE) {
+ tevent_req_done(req);
+ } else {
+ DEBUG(9, ("Group enumeration failed with: (%d)[%s]\n",
+ ret, strerror(ret)));
+ tevent_req_error(req, ret);
+ }
+
+ return;
+ }
+ }
+
+ subreq = enum_services_send(state, state->ev, state->ctx,
+ state->op, state->purge);
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, ldap_id_enum_services_done, req);
+}
+
+static void ldap_id_enum_services_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ int dp_error = DP_ERR_FATAL;
+ 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);
+
+ ret = enum_services_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret == ENOENT) ret = EOK;
+
+ /* All enumerations are complete, so conclude the
+ * id_op
+ */
+ ret = sdap_id_op_done(state->op, ret, &dp_error);
if (dp_error == DP_ERR_OK && ret != EOK) {
/* retry */
ret = ldap_id_enumerate_retry(req);
@@ -377,8 +430,9 @@ static void ldap_id_enum_groups_done(struct tevent_req *subreq)
if (dp_error == DP_ERR_OFFLINE) {
tevent_req_done(req);
} else {
- DEBUG(9, ("Group enumeration failed with: (%d)[%s]\n",
- ret, strerror(ret)));
+ DEBUG(SSSDBG_MINOR_FAILURE,
+ ("Service enumeration failed with: (%d)[%s]\n",
+ ret, strerror(ret)));
tevent_req_error(req, ret);
}
diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c
index ba1c7911e..8a118150b 100644
--- a/src/providers/ldap/sdap.c
+++ b/src/providers/ldap/sdap.c
@@ -925,6 +925,11 @@ int sdap_get_server_opts_from_rootdse(TALLOC_CTX *memctx,
talloc_strdup(opts->group_map,
opts->gen_map[SDAP_AT_ENTRY_USN].name);
}
+ if (!opts->service_map[SDAP_AT_SERVICE_USN].name) {
+ opts->service_map[SDAP_AT_SERVICE_USN].name =
+ talloc_strdup(opts->service_map,
+ opts->gen_map[SDAP_AT_ENTRY_USN].name);
+ }
*srv_opts = so;
return EOK;
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index bbc59414a..7bf1805c1 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -359,6 +359,7 @@ struct sdap_server_opts {
unsigned long last_usn;
char *max_user_value;
char *max_group_value;
+ char *max_service_value;
};
struct sdap_id_ctx;
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index abf16b0c6..8f8af47d5 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -28,6 +28,7 @@
#include <tevent.h>
#include "providers/dp_backend.h"
#include "providers/ldap/sdap.h"
+#include "providers/ldap/sdap_id_op.h"
#include "providers/fail_over.h"
struct tevent_req *sdap_connect_send(TALLOC_CTX *memctx,
@@ -228,4 +229,14 @@ sdap_get_services_recv(TALLOC_CTX *mem_ctx,
struct tevent_req *req,
char **usn_value);
+struct tevent_req *
+enum_services_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *id_ctx,
+ struct sdap_id_op *op,
+ bool purge);
+
+errno_t
+enum_services_recv(struct tevent_req *req);
+
#endif /* _SDAP_ASYNC_H_ */
diff --git a/src/providers/ldap/sdap_async_services.c b/src/providers/ldap/sdap_async_services.c
index 6fab4ace1..e4371f58e 100644
--- a/src/providers/ldap/sdap_async_services.c
+++ b/src/providers/ldap/sdap_async_services.c
@@ -483,3 +483,141 @@ sdap_get_services_recv(TALLOC_CTX *mem_ctx,
return EOK;
}
+
+
+/* Enumeration routines */
+
+struct enum_services_state {
+ struct tevent_context *ev;
+ struct sdap_id_ctx *id_ctx;
+ struct sdap_id_op *op;
+ struct sss_domain_info *domain;
+ struct sysdb_ctx *sysdb;
+
+ char *filter;
+ const char **attrs;
+};
+
+static void
+enum_services_op_done(struct tevent_req *subreq);
+
+struct tevent_req *
+enum_services_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_id_ctx *id_ctx,
+ struct sdap_id_op *op,
+ bool purge)
+{
+ errno_t ret;
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct enum_services_state *state;
+
+ req = tevent_req_create(memctx, &state, struct enum_services_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->id_ctx = id_ctx;
+ state->domain = id_ctx->be->domain;
+ state->sysdb = id_ctx->be->sysdb;
+ state->op = op;
+
+ if (id_ctx->srv_opts && id_ctx->srv_opts->max_service_value && !purge) {
+ state->filter = talloc_asprintf(
+ state,
+ "(&(objectclass=%s)(%s=*)(%s=*)(%s=*)(%s>=%s)(!(%s=%s)))",
+ id_ctx->opts->service_map[SDAP_OC_SERVICE].name,
+ id_ctx->opts->service_map[SDAP_AT_SERVICE_NAME].name,
+ id_ctx->opts->service_map[SDAP_AT_SERVICE_PORT].name,
+ id_ctx->opts->service_map[SDAP_AT_SERVICE_PROTOCOL].name,
+ id_ctx->opts->service_map[SDAP_AT_SERVICE_USN].name,
+ id_ctx->srv_opts->max_service_value,
+ id_ctx->opts->service_map[SDAP_AT_SERVICE_USN].name,
+ id_ctx->srv_opts->max_service_value);
+ } else {
+ state->filter = talloc_asprintf(
+ state,
+ "(&(objectclass=%s)(%s=*)(%s=*)(%s=*))",
+ id_ctx->opts->service_map[SDAP_OC_SERVICE].name,
+ id_ctx->opts->service_map[SDAP_AT_SERVICE_NAME].name,
+ id_ctx->opts->service_map[SDAP_AT_SERVICE_PORT].name,
+ id_ctx->opts->service_map[SDAP_AT_SERVICE_PROTOCOL].name);
+ }
+ if (!state->filter) {
+ DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to build base filter\n"));
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ /* TODO: handle attrs_type */
+ ret = build_attrs_from_map(state, id_ctx->opts->service_map,
+ SDAP_OPTS_SERVICES, &state->attrs);
+ if (ret != EOK) goto fail;
+
+ subreq = sdap_get_services_send(state, state->ev,
+ state->domain, state->sysdb,
+ state->id_ctx->opts,
+ state->id_ctx->opts->service_search_bases,
+ sdap_id_op_handle(state->op),
+ state->attrs, state->filter,
+ dp_opt_get_int(state->id_ctx->opts->basic,
+ SDAP_SEARCH_TIMEOUT),
+ true);
+ if (!subreq) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, enum_services_op_done, req);
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static void
+enum_services_op_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct enum_services_state *state =
+ tevent_req_data(req, struct enum_services_state);
+ char *usn_value;
+ char *endptr = NULL;
+ unsigned usn_number;
+ int ret;
+
+ ret = sdap_get_services_recv(state, subreq, &usn_value);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (usn_value) {
+ talloc_zfree(state->id_ctx->srv_opts->max_service_value);
+ state->id_ctx->srv_opts->max_service_value =
+ talloc_steal(state->id_ctx, usn_value);
+
+ usn_number = strtoul(usn_value, &endptr, 10);
+ if ((endptr == NULL || (*endptr == '\0' && endptr != usn_value))
+ && (usn_number > state->id_ctx->srv_opts->last_usn)) {
+ state->id_ctx->srv_opts->last_usn = usn_number;
+ }
+ }
+
+ DEBUG(SSSDBG_FUNC_DATA, ("Services higher USN value: [%s]\n",
+ state->id_ctx->srv_opts->max_service_value));
+
+ tevent_req_done(req);
+}
+
+errno_t
+enum_services_recv(struct tevent_req *req)
+{
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ return EOK;
+}
diff --git a/src/providers/ldap/sdap_id_op.c b/src/providers/ldap/sdap_id_op.c
index 5087cddc6..539f26f0c 100644
--- a/src/providers/ldap/sdap_id_op.c
+++ b/src/providers/ldap/sdap_id_op.c
@@ -541,6 +541,7 @@ static void sdap_id_op_connect_done(struct tevent_req *subreq)
current_srv_opts->max_user_value = 0;
current_srv_opts->max_group_value = 0;
+ current_srv_opts->max_service_value = 0;
current_srv_opts->last_usn = srv_opts->last_usn;
}
}