summaryrefslogtreecommitdiffstats
path: root/src/providers/ldap/sdap_async.c
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2013-12-16 18:36:12 +0100
committerJakub Hrozek <jhrozek@redhat.com>2014-02-12 15:29:21 +0100
commit86c2e80de2243c3bd7691657086f1a182e7fc45c (patch)
tree32591bfcb63c492698d484d1ebe9102d5734a868 /src/providers/ldap/sdap_async.c
parentfba393bc85e28f517aefa9c0c18608a2bf58937b (diff)
downloadsssd-86c2e80de2243c3bd7691657086f1a182e7fc45c.tar.gz
sssd-86c2e80de2243c3bd7691657086f1a182e7fc45c.tar.xz
sssd-86c2e80de2243c3bd7691657086f1a182e7fc45c.zip
LDAP: Detect the presence of POSIX attributes
When the schema is set to AD and ID mapping is not used, there is a one-time check ran when searching for users to detect the presence of POSIX attributes in LDAP. If this check fails, the search fails as if no entry was found and returns a special error code. The sdap_server_opts structure is filled every time a client connects to a server so the posix check boolean is reset to false again on connecting to the server. It might be better to move the check to where the rootDSE is retrieved, but the check depends on several features that are not known to the code that retrieves the rootDSE (or the connection code for example) such as what the attribute mappings are or the authentication method that should be used. Reviewed-by: Sumit Bose <sbose@redhat.com> Reviewed-by: Pavel Březina <pbrezina@redhat.com> (cherry picked from commit e81deec535d11912b87954c81a1edd768c1386c9)
Diffstat (limited to 'src/providers/ldap/sdap_async.c')
-rw-r--r--src/providers/ldap/sdap_async.c200
1 files changed, 200 insertions, 0 deletions
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,