summaryrefslogtreecommitdiffstats
path: root/src/providers/ldap
diff options
context:
space:
mode:
Diffstat (limited to 'src/providers/ldap')
-rw-r--r--src/providers/ldap/ldap_id.c158
-rw-r--r--src/providers/ldap/sdap.h1
-rw-r--r--src/providers/ldap/sdap_async.c200
-rw-r--r--src/providers/ldap/sdap_async.h9
-rw-r--r--src/providers/ldap/sdap_async_enum.c96
5 files changed, 454 insertions, 10 deletions
diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c
index e36c1f697..b948ba9f3 100644
--- a/src/providers/ldap/ldap_id.c
+++ b/src/providers/ldap/ldap_id.c
@@ -50,6 +50,7 @@ struct users_get_state {
char *filter;
const char **attrs;
+ bool use_id_mapping;
int dp_error;
int sdap_ret;
@@ -58,6 +59,8 @@ struct users_get_state {
static int users_get_retry(struct tevent_req *req);
static void users_get_connect_done(struct tevent_req *subreq);
+static void users_get_posix_check_done(struct tevent_req *subreq);
+static void users_get_search(struct tevent_req *req);
static void users_get_done(struct tevent_req *subreq);
struct tevent_req *users_get_send(TALLOC_CTX *memctx,
@@ -79,7 +82,6 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
uid_t uid;
enum idmap_error_code err;
char *sid;
- bool use_id_mapping;
req = tevent_req_create(memctx, &state, struct users_get_state);
if (!req) return NULL;
@@ -103,7 +105,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
state->name = name;
state->filter_type = filter_type;
- use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
+ state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
ctx->opts->idmap_ctx,
sdom->dom->name,
sdom->dom->domain_id);
@@ -116,7 +118,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
}
break;
case BE_FILTER_IDNUM:
- if (use_id_mapping) {
+ if (state->use_id_mapping) {
/* If we're ID-mapping, we need to use the objectSID
* in the search filter.
*/
@@ -184,7 +186,7 @@ struct tevent_req *users_get_send(TALLOC_CTX *memctx,
goto fail;
}
- if (use_id_mapping || filter_type == BE_FILTER_SECID) {
+ if (state->use_id_mapping || filter_type == BE_FILTER_SECID) {
/* When mapping IDs or looking for SIDs, we don't want to limit
* ourselves to users with a UID value. But there must be a SID to map
* from.
@@ -269,6 +271,75 @@ static void users_get_connect_done(struct tevent_req *subreq)
return;
}
+ /* If POSIX attributes have been requested with an AD server and we
+ * have no idea about POSIX attributes support, run a one-time check
+ */
+ if (state->use_id_mapping == false &&
+ state->ctx->opts->schema_type == SDAP_SCHEMA_AD &&
+ state->ctx->srv_opts &&
+ state->ctx->srv_opts->posix_checked == false) {
+ subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
+ sdap_id_op_handle(state->op),
+ state->sdom->user_search_bases,
+ dp_opt_get_int(state->ctx->opts->basic,
+ SDAP_SEARCH_TIMEOUT));
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, users_get_posix_check_done, req);
+ return;
+ }
+
+ users_get_search(req);
+}
+
+static void users_get_posix_check_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ bool has_posix;
+ int dp_error;
+ 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);
+
+ ret = sdap_posix_check_recv(subreq, &has_posix);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ /* We can only finish the id_op on error as the connection
+ * is re-used by the user search
+ */
+ ret = sdap_id_op_done(state->op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = users_get_retry(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ }
+ return;
+ }
+ }
+
+ state->ctx->srv_opts->posix_checked = true;
+
+ /* If the check ran to completion, we know for certain about the attributes
+ */
+ if (has_posix == false) {
+ state->sdap_ret = ERR_NO_POSIX;
+ tevent_req_done(req);
+ return;
+ }
+
+ users_get_search(req);
+}
+
+static void users_get_search(struct tevent_req *req)
+{
+ struct users_get_state *state = tevent_req_data(req,
+ struct users_get_state);
+ struct tevent_req *subreq;
+
subreq = sdap_get_users_send(state, state->ev,
state->domain, state->sysdb,
state->ctx->opts,
@@ -434,6 +505,7 @@ struct groups_get_state {
char *filter;
const char **attrs;
+ bool use_id_mapping;
int dp_error;
int sdap_ret;
@@ -442,6 +514,8 @@ struct groups_get_state {
static int groups_get_retry(struct tevent_req *req);
static void groups_get_connect_done(struct tevent_req *subreq);
+static void groups_get_posix_check_done(struct tevent_req *subreq);
+static void groups_get_search(struct tevent_req *req);
static void groups_get_done(struct tevent_req *subreq);
struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
@@ -463,7 +537,6 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
gid_t gid;
enum idmap_error_code err;
char *sid;
- bool use_id_mapping;
const char *member_filter[2];
req = tevent_req_create(memctx, &state, struct groups_get_state);
@@ -488,7 +561,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
state->name = name;
state->filter_type = filter_type;
- use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
+ state->use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
ctx->opts->idmap_ctx,
sdom->dom->name,
sdom->dom->domain_id);
@@ -503,7 +576,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
}
break;
case BE_FILTER_IDNUM:
- if (use_id_mapping) {
+ if (state->use_id_mapping) {
/* If we're ID-mapping, we need to use the objectSID
* in the search filter.
*/
@@ -571,7 +644,7 @@ struct tevent_req *groups_get_send(TALLOC_CTX *memctx,
goto fail;
}
- if (use_id_mapping || filter_type == BE_FILTER_SECID) {
+ if (state->use_id_mapping || filter_type == BE_FILTER_SECID) {
/* When mapping IDs or looking for SIDs, we don't want to limit
* ourselves to groups with a GID value
*/
@@ -660,6 +733,75 @@ static void groups_get_connect_done(struct tevent_req *subreq)
return;
}
+ /* If POSIX attributes have been requested with an AD server and we
+ * have no idea about POSIX attributes support, run a one-time check
+ */
+ if (state->use_id_mapping == false &&
+ state->ctx->opts->schema_type == SDAP_SCHEMA_AD &&
+ state->ctx->srv_opts &&
+ state->ctx->srv_opts->posix_checked == false) {
+ subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
+ sdap_id_op_handle(state->op),
+ state->sdom->user_search_bases,
+ dp_opt_get_int(state->ctx->opts->basic,
+ SDAP_SEARCH_TIMEOUT));
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, groups_get_posix_check_done, req);
+ return;
+ }
+
+ groups_get_search(req);
+}
+
+static void groups_get_posix_check_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ bool has_posix;
+ int dp_error;
+ 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);
+
+ ret = sdap_posix_check_recv(subreq, &has_posix);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ /* We can only finish the id_op on error as the connection
+ * is re-used by the group search
+ */
+ ret = sdap_id_op_done(state->op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = groups_get_retry(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ }
+ return;
+ }
+ }
+
+ state->ctx->srv_opts->posix_checked = true;
+
+ /* If the check ran to completion, we know for certain about the attributes
+ */
+ if (has_posix == false) {
+ state->sdap_ret = ERR_NO_POSIX;
+ tevent_req_done(req);
+ return;
+ }
+
+ groups_get_search(req);
+}
+
+static void groups_get_search(struct tevent_req *req)
+{
+ struct groups_get_state *state = tevent_req_data(req,
+ struct groups_get_state);
+ struct tevent_req *subreq;
+
subreq = sdap_get_groups_send(state, state->ev,
state->sdom,
state->ctx->opts,
diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h
index d408be0a6..f3f13e9c7 100644
--- a/src/providers/ldap/sdap.h
+++ b/src/providers/ldap/sdap.h
@@ -446,6 +446,7 @@ struct sdap_server_opts {
char *max_group_value;
char *max_service_value;
char *max_sudo_value;
+ bool posix_checked;
};
struct sdap_id_ctx;
diff --git a/src/providers/ldap/sdap_async.c b/src/providers/ldap/sdap_async.c
index 367007bde..1022a093f 100644
--- a/src/providers/ldap/sdap_async.c
+++ b/src/providers/ldap/sdap_async.c
@@ -21,6 +21,7 @@
#include <ctype.h>
#include "util/util.h"
+#include "util/strtonum.h"
#include "providers/ldap/sdap_async_private.h"
#define REALM_SEPARATOR '@'
@@ -2083,6 +2084,205 @@ int sdap_asq_search_recv(struct tevent_req *req,
return EOK;
}
+/* ==Posix attribute presence test================================= */
+static errno_t sdap_posix_check_next(struct tevent_req *req);
+static void sdap_posix_check_done(struct tevent_req *subreq);
+static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
+ struct sdap_msg *msg,
+ void *pvt);
+
+struct sdap_posix_check_state {
+ struct tevent_context *ev;
+ struct sdap_options *opts;
+ struct sdap_handle *sh;
+ struct sdap_search_base **search_bases;
+ int timeout;
+
+ const char **attrs;
+ const char *filter;
+ size_t base_iter;
+
+ bool has_posix;
+};
+
+struct tevent_req *
+sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+ struct sdap_options *opts, struct sdap_handle *sh,
+ struct sdap_search_base **search_bases,
+ int timeout)
+{
+ struct tevent_req *req = NULL;
+ struct sdap_posix_check_state *state;
+ errno_t ret;
+
+ req = tevent_req_create(memctx, &state, struct sdap_posix_check_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->sh = sh;
+ state->opts = opts;
+ state->search_bases = search_bases;
+ state->timeout = timeout;
+
+ state->attrs = talloc_array(state, const char *, 4);
+ if (state->attrs == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ state->attrs[0] = "objectclass";
+ state->attrs[1] = opts->user_map[SDAP_AT_USER_UID].name;
+ state->attrs[2] = opts->group_map[SDAP_AT_GROUP_GID].name;
+ state->attrs[3] = NULL;
+
+ state->filter = talloc_asprintf(state, "(|(%s=*)(%s=*))",
+ opts->user_map[SDAP_AT_USER_UID].name,
+ opts->group_map[SDAP_AT_GROUP_GID].name);
+ if (state->filter == NULL) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = sdap_posix_check_next(req);
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ return req;
+
+fail:
+ tevent_req_error(req, ret);
+ tevent_req_post(req, ev);
+ return req;
+}
+
+static errno_t sdap_posix_check_next(struct tevent_req *req)
+{
+ struct tevent_req *subreq = NULL;
+ struct sdap_posix_check_state *state =
+ tevent_req_data(req, struct sdap_posix_check_state);
+
+ DEBUG(SSSDBG_TRACE_FUNC,
+ ("Searching for POSIX attributes with base [%s]\n",
+ state->search_bases[state->base_iter]->basedn));
+
+ subreq = sdap_get_generic_ext_send(state, state->ev, state->opts,
+ state->sh,
+ state->search_bases[state->base_iter]->basedn,
+ LDAP_SCOPE_SUBTREE, state->filter,
+ state->attrs, false,
+ NULL, NULL, 1, state->timeout,
+ false, sdap_posix_check_parse,
+ state);
+ if (subreq == NULL) {
+ return ENOMEM;
+ }
+ tevent_req_set_callback(subreq, sdap_posix_check_done, req);
+
+ return EOK;
+}
+
+static errno_t sdap_posix_check_parse(struct sdap_handle *sh,
+ struct sdap_msg *msg,
+ void *pvt)
+{
+ struct berval **vals = NULL;
+ struct sdap_posix_check_state *state =
+ talloc_get_type(pvt, struct sdap_posix_check_state);
+ char *dn;
+ char *endptr;
+
+ dn = ldap_get_dn(sh->ldap, msg->msg);
+ if (dn == NULL) {
+ DEBUG(SSSDBG_TRACE_LIBS,
+ ("Search did not find any entry with POSIX attributes\n"));
+ goto done;
+ }
+ DEBUG(SSSDBG_TRACE_LIBS, ("Found [%s] with POSIX attributes\n", dn));
+ ldap_memfree(dn);
+
+ vals = ldap_get_values_len(sh->ldap, msg->msg,
+ state->opts->user_map[SDAP_AT_USER_UID].name);
+ if (vals == NULL) {
+ vals = ldap_get_values_len(sh->ldap, msg->msg,
+ state->opts->group_map[SDAP_AT_GROUP_GID].name);
+ if (vals == NULL) {
+ DEBUG(SSSDBG_TRACE_LIBS, ("Entry does not have POSIX attrs?\n"));
+ goto done;
+ }
+ }
+
+ if (vals[0] == NULL) {
+ DEBUG(SSSDBG_TRACE_LIBS, ("No value for POSIX attr\n"));
+ goto done;
+ }
+
+ errno = 0;
+ strtouint32(vals[0]->bv_val, &endptr, 10);
+ if (errno || *endptr || (vals[0]->bv_val == endptr)) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("POSIX attribute is not a number: %s\n", vals[0]->bv_val));
+ goto done;
+ }
+
+ state->has_posix = true;
+done:
+ ldap_value_free_len(vals);
+ return EOK;
+}
+
+static void sdap_posix_check_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_posix_check_state *state =
+ tevent_req_data(req, struct sdap_posix_check_state);
+ errno_t ret;
+
+ ret = sdap_get_generic_ext_recv(subreq);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ DEBUG(SSSDBG_OP_FAILURE,
+ ("sdap_get_generic_ext_recv failed [%d]: %s\n",
+ ret, strerror(ret)));
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ /* Positive hit is definitve, no need to search other bases */
+ if (state->has_posix == true) {
+ DEBUG(SSSDBG_FUNC_DATA, ("Server has POSIX attributes\n"));
+ tevent_req_done(req);
+ return;
+ }
+
+ state->base_iter++;
+ if (state->search_bases[state->base_iter]) {
+ /* There are more search bases to try */
+ ret = sdap_posix_check_next(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ }
+ return;
+ }
+
+ /* All bases done! */
+ DEBUG(SSSDBG_TRACE_LIBS, ("Cycled through all bases\n"));
+ tevent_req_done(req);
+}
+
+int sdap_posix_check_recv(struct tevent_req *req,
+ bool *_has_posix)
+{
+ struct sdap_posix_check_state *state = tevent_req_data(req,
+ struct sdap_posix_check_state);
+
+ TEVENT_REQ_RETURN_ON_ERROR(req);
+
+ *_has_posix = state->has_posix;
+ return EOK;
+}
+
/* ==Generic Deref Search============================================ */
enum sdap_deref_type {
SDAP_DEREF_OPENLDAP,
diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 33e8708ab..593404af3 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -210,6 +210,15 @@ int sdap_deref_search_recv(struct tevent_req *req,
size_t *reply_count,
struct sdap_deref_attrs ***reply);
+struct tevent_req *
+sdap_posix_check_send(TALLOC_CTX *memctx, struct tevent_context *ev,
+ struct sdap_options *opts, struct sdap_handle *sh,
+ struct sdap_search_base **search_bases,
+ int timeout);
+
+int sdap_posix_check_recv(struct tevent_req *req,
+ bool *_has_posix);
+
errno_t
sdap_attrs_add_ldap_attr(struct sysdb_attrs *ldap_attrs,
const char *attr_name,
diff --git a/src/providers/ldap/sdap_async_enum.c b/src/providers/ldap/sdap_async_enum.c
index cbc56be20..0c20afa9d 100644
--- a/src/providers/ldap/sdap_async_enum.c
+++ b/src/providers/ldap/sdap_async_enum.c
@@ -68,6 +68,8 @@ static errno_t sdap_dom_enum_ex_retry(struct tevent_req *req,
tevent_req_fn tcb);
static bool sdap_dom_enum_ex_connected(struct tevent_req *subreq);
static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq);
+static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq);
+static errno_t sdap_dom_enum_search_users(struct tevent_req *req);
static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq);
static void sdap_dom_enum_ex_get_groups(struct tevent_req *subreq);
static void sdap_dom_enum_ex_groups_done(struct tevent_req *subreq);
@@ -178,19 +180,109 @@ static void sdap_dom_enum_ex_get_users(struct tevent_req *subreq)
struct tevent_req);
struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
struct sdap_dom_enum_ex_state);
+ bool use_id_mapping;
+ errno_t ret;
if (sdap_dom_enum_ex_connected(subreq) == false) {
return;
}
+ use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
+ state->ctx->opts->idmap_ctx,
+ state->sdom->dom->name,
+ state->sdom->dom->domain_id);
+
+ /* If POSIX attributes have been requested with an AD server and we
+ * have no idea about POSIX attributes support, run a one-time check
+ */
+ if (use_id_mapping == false &&
+ state->ctx->opts->schema_type == SDAP_SCHEMA_AD &&
+ state->ctx->srv_opts &&
+ state->ctx->srv_opts->posix_checked == false) {
+ subreq = sdap_posix_check_send(state, state->ev, state->ctx->opts,
+ sdap_id_op_handle(state->user_op),
+ state->sdom->user_search_bases,
+ dp_opt_get_int(state->ctx->opts->basic,
+ SDAP_SEARCH_TIMEOUT));
+ if (subreq == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq,
+ sdap_dom_enum_ex_posix_check_done, req);
+ return;
+ }
+
+
+ ret = sdap_dom_enum_search_users(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+ /* Execution resumes in sdap_dom_enum_ex_users_done */
+}
+
+static void sdap_dom_enum_ex_posix_check_done(struct tevent_req *subreq)
+{
+ errno_t ret;
+ bool has_posix;
+ int dp_error;
+
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+ struct sdap_dom_enum_ex_state);
+
+ ret = sdap_posix_check_recv(subreq, &has_posix);
+ talloc_zfree(subreq);
+ if (ret != EOK) {
+ /* We can only finish the id_op on error as the connection
+ * is re-used by the user search
+ */
+ ret = sdap_id_op_done(state->user_op, ret, &dp_error);
+ if (dp_error == DP_ERR_OK && ret != EOK) {
+ /* retry */
+ ret = sdap_dom_enum_ex_retry(req, state->user_op,
+ sdap_dom_enum_ex_get_users);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ }
+ return;
+ }
+ }
+
+ state->ctx->srv_opts->posix_checked = true;
+
+ /* If the check ran to completion, we know for certain about the attributes
+ */
+ if (has_posix == false) {
+ tevent_req_error(req, ERR_NO_POSIX);
+ return;
+ }
+
+
+ ret = sdap_dom_enum_search_users(req);
+ if (ret != EOK) {
+ tevent_req_error(req, ret);
+ return;
+ }
+ /* Execution resumes in sdap_dom_enum_ex_users_done */
+}
+
+static errno_t sdap_dom_enum_search_users(struct tevent_req *req)
+{
+ struct sdap_dom_enum_ex_state *state = tevent_req_data(req,
+ struct sdap_dom_enum_ex_state);
+ struct tevent_req *subreq;
+
subreq = enum_users_send(state, state->ev,
state->ctx, state->sdom,
state->user_op, state->purge);
if (subreq == NULL) {
- tevent_req_error(req, ENOMEM);
- return;
+ return ENOMEM;
}
tevent_req_set_callback(subreq, sdap_dom_enum_ex_users_done, req);
+ return EOK;
}
static void sdap_dom_enum_ex_users_done(struct tevent_req *subreq)