summaryrefslogtreecommitdiff
path: root/server/providers/ldap/sdap_async.c
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2009-10-29 15:02:41 -0400
committerStephen Gallagher <sgallagh@redhat.com>2009-10-29 16:05:13 -0400
commit44685ff64447b7ad87c75aec478e5f21bd50b4b7 (patch)
treeb0c8b4e0054de890c006b0ad2486c99adbcc7b1c /server/providers/ldap/sdap_async.c
parentb79b1228de615c860df841670c9a882ca748f63a (diff)
downloadsssd-44685ff64447b7ad87c75aec478e5f21bd50b4b7.tar.gz
sssd-44685ff64447b7ad87c75aec478e5f21bd50b4b7.tar.bz2
sssd-44685ff64447b7ad87c75aec478e5f21bd50b4b7.zip
Add support to get rootDSE from the LDAP server.
Also fic sdap_get_generic_send() to be a bit more "generic" :-) Also figs bugs within it. This patch allow us 2 good things. A) we check that the server effectively supports GSSAPI auth before we try to use it. B) against IPA it substantially cuts delays when the server is offline because it uses a 5 second async timeout on the connection and doesn't try to do a slow synchronous kinit+sasl_bind if the server is not even available.
Diffstat (limited to 'server/providers/ldap/sdap_async.c')
-rw-r--r--server/providers/ldap/sdap_async.c407
1 files changed, 311 insertions, 96 deletions
diff --git a/server/providers/ldap/sdap_async.c b/server/providers/ldap/sdap_async.c
index 28e4fa4f..ae6806f4 100644
--- a/server/providers/ldap/sdap_async.c
+++ b/server/providers/ldap/sdap_async.c
@@ -2276,7 +2276,6 @@ static void sdap_get_users_transaction(struct tevent_req *subreq)
}
DEBUG(8, ("ldap_search_ext called, msgid = %d\n", msgid));
- /* FIXME: get timeouts from configuration, for now 10 minutes */
ret = sdap_op_add(state, state->ev, state->sh, msgid,
sdap_get_users_done, req,
dp_opt_get_int(state->opts->basic,
@@ -3233,22 +3232,127 @@ int sdap_exop_modify_passwd_recv(struct tevent_req *req,
return EOK;
}
+/* ==Fetch-RootDSE============================================= */
+
+struct sdap_get_rootdse_state {
+ struct tevent_context *ev;
+ struct sdap_options *opts;
+ struct sdap_handle *sh;
+
+ struct sysdb_attrs *rootdse;
+};
+
+static void sdap_get_rootdse_done(struct tevent_req *subreq);
+
+struct tevent_req *sdap_get_rootdse_send(TALLOC_CTX *memctx,
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sdap_handle *sh)
+{
+ struct tevent_req *req, *subreq;
+ struct sdap_get_rootdse_state *state;
+
+ DEBUG(9, ("Getting rootdse\n"));
+
+ req = tevent_req_create(memctx, &state, struct sdap_get_rootdse_state);
+ if (!req) return NULL;
+
+ state->ev = ev;
+ state->opts = opts;
+ state->sh = sh;
+ state->rootdse = NULL;
+
+ subreq = sdap_get_generic_send(state, ev, opts, sh,
+ "", LDAP_SCOPE_BASE,
+ "(objectclass=*)", NULL);
+ if (!subreq) {
+ talloc_zfree(req);
+ return NULL;
+ }
+ tevent_req_set_callback(subreq, sdap_get_rootdse_done, req);
+
+ return req;
+}
+
+static void sdap_get_rootdse_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct sdap_get_rootdse_state *state = tevent_req_data(req,
+ struct sdap_get_rootdse_state);
+ struct sysdb_attrs **results;
+ size_t num_results;
+ int ret;
+
+ ret = sdap_get_generic_recv(subreq, state, &num_results, &results);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ if (num_results == 0 || !results) {
+ DEBUG(2, ("No RootDSE for server ?!\n"));
+ tevent_req_error(req, ENOENT);
+ return;
+ }
+
+ if (num_results > 1) {
+ DEBUG(2, ("Multiple replies when searching for RootDSE ??\n"));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ state->rootdse = talloc_steal(state, results[0]);
+ talloc_zfree(results);
+
+ DEBUG(9, ("Got rootdse\n"));
+
+ tevent_req_done(req);
+}
+
+static int sdap_get_rootdse_recv(struct tevent_req *req,
+ TALLOC_CTX *memctx,
+ struct sysdb_attrs **rootdse)
+{
+ struct sdap_get_rootdse_state *state = tevent_req_data(req,
+ struct sdap_get_rootdse_state);
+ enum tevent_req_state tstate;
+ uint64_t err;
+
+ if (tevent_req_is_error(req, &tstate, &err)) {
+ if (err) return err;
+ return EIO;
+ }
+
+ *rootdse = talloc_steal(memctx, state->rootdse);
+
+ return EOK;
+}
+
/* ==Client connect============================================ */
struct sdap_cli_connect_state {
struct tevent_context *ev;
struct sdap_options *opts;
+ struct sysdb_attrs *rootdse;
+ bool use_rootdse;
struct sdap_handle *sh;
};
static void sdap_cli_connect_done(struct tevent_req *subreq);
+static void sdap_cli_rootdse_step(struct tevent_req *req);
+static void sdap_cli_rootdse_done(struct tevent_req *subreq);
+static void sdap_cli_kinit_step(struct tevent_req *req);
static void sdap_cli_kinit_done(struct tevent_req *subreq);
-static void sdap_cli_bind_done(struct tevent_req *subreq);
+static void sdap_cli_auth_step(struct tevent_req *req);
+static void sdap_cli_auth_done(struct tevent_req *subreq);
struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
struct tevent_context *ev,
- struct sdap_options *opts)
+ struct sdap_options *opts,
+ struct sysdb_attrs **rootdse)
{
struct tevent_req *req, *subreq;
struct sdap_cli_connect_state *state;
@@ -3258,6 +3362,13 @@ struct tevent_req *sdap_cli_connect_send(TALLOC_CTX *memctx,
state->ev = ev;
state->opts = opts;
+ if (rootdse) {
+ state->use_rootdse = true;
+ state->rootdse = *rootdse;
+ } else {
+ state->use_rootdse = false;
+ state->rootdse = NULL;
+ }
subreq = sdap_connect_send(state, ev, opts,
dp_opt_get_bool(opts->basic, SDAP_ID_TLS));
@@ -3275,7 +3386,7 @@ static void sdap_cli_connect_done(struct tevent_req *subreq)
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct sdap_cli_connect_state *state = tevent_req_data(req,
- struct sdap_cli_connect_state);
+ struct sdap_cli_connect_state);
const char *sasl_mech;
int ret;
@@ -3286,50 +3397,120 @@ static void sdap_cli_connect_done(struct tevent_req *subreq)
return;
}
+ if (state->use_rootdse && !state->rootdse) {
+ /* fetch the rootDSE this time */
+ sdap_cli_rootdse_step(req);
+ return;
+ }
+
sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH);
+
+ if (state->use_rootdse) {
+ /* check if server claims to support GSSAPI */
+ if (!sdap_rootdse_sasl_mech_is_supported(state->rootdse,
+ sasl_mech)) {
+ tevent_req_error(req, ENOTSUP);
+ return;
+ }
+ }
+
if (sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) {
if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) {
- subreq = sdap_kinit_send(state, state->ev, state->sh,
- dp_opt_get_string(state->opts->basic,
- SDAP_KRB5_KEYTAB),
- dp_opt_get_string(state->opts->basic,
- SDAP_SASL_AUTHID),
- dp_opt_get_string(state->opts->basic,
- SDAP_KRB5_REALM));
- if (!subreq) {
- tevent_req_error(req, ENOMEM);
- return;
- }
- tevent_req_set_callback(subreq, sdap_cli_kinit_done, req);
+ sdap_cli_kinit_step(req);
return;
}
}
- subreq = sdap_auth_send(state,
- state->ev,
- state->sh,
- sasl_mech,
- dp_opt_get_string(state->opts->basic,
- SDAP_SASL_AUTHID),
- dp_opt_get_string(state->opts->basic,
- SDAP_DEFAULT_BIND_DN),
- dp_opt_get_string(state->opts->basic,
- SDAP_DEFAULT_AUTHTOK_TYPE),
- dp_opt_get_blob(state->opts->basic,
- SDAP_DEFAULT_AUTHTOK));
+ sdap_cli_auth_step(req);
+}
+
+static void sdap_cli_rootdse_step(struct tevent_req *req)
+{
+ struct sdap_cli_connect_state *state = tevent_req_data(req,
+ struct sdap_cli_connect_state);
+ struct tevent_req *subreq;
+ int ret;
+
+ subreq = sdap_get_rootdse_send(state, state->ev, state->opts, state->sh);
if (!subreq) {
tevent_req_error(req, ENOMEM);
return;
}
- tevent_req_set_callback(subreq, sdap_cli_bind_done, req);
+ tevent_req_set_callback(subreq, sdap_cli_rootdse_done, req);
+
+ if (!state->sh->connected) {
+ /* this rootdse search is performed before we actually do a bind,
+ * so we need to set up the callbacks or we will never get notified
+ * of a reply */
+ state->sh->connected = true;
+ ret = sdap_install_ldap_callbacks(state->sh, state->ev);
+ if (ret) {
+ tevent_req_error(req, ret);
+ }
+ }
}
-static void sdap_cli_kinit_done(struct tevent_req *subreq)
+static void sdap_cli_rootdse_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
struct sdap_cli_connect_state *state = tevent_req_data(req,
- struct sdap_cli_connect_state);
+ struct sdap_cli_connect_state);
+ const char *sasl_mech;
+ int ret;
+
+ ret = sdap_get_rootdse_recv(subreq, state, &state->rootdse);
+ talloc_zfree(subreq);
+ if (ret) {
+ tevent_req_error(req, ret);
+ return;
+ }
+
+ sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH);
+
+ if (state->use_rootdse) {
+ /* check if server claims to support GSSAPI */
+ if (!sdap_rootdse_sasl_mech_is_supported(state->rootdse,
+ sasl_mech)) {
+ tevent_req_error(req, ENOTSUP);
+ return;
+ }
+ }
+
+ if (sasl_mech && (strcasecmp(sasl_mech, "GSSAPI") == 0)) {
+ if (dp_opt_get_bool(state->opts->basic, SDAP_KRB5_KINIT)) {
+ sdap_cli_kinit_step(req);
+ return;
+ }
+ }
+
+ sdap_cli_auth_step(req);
+}
+
+static void sdap_cli_kinit_step(struct tevent_req *req)
+{
+ struct sdap_cli_connect_state *state = tevent_req_data(req,
+ struct sdap_cli_connect_state);
+ struct tevent_req *subreq;
+
+ subreq = sdap_kinit_send(state, state->ev, state->sh,
+ dp_opt_get_string(state->opts->basic,
+ SDAP_KRB5_KEYTAB),
+ dp_opt_get_string(state->opts->basic,
+ SDAP_SASL_AUTHID),
+ dp_opt_get_string(state->opts->basic,
+ SDAP_KRB5_REALM));
+ if (!subreq) {
+ tevent_req_error(req, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(subreq, sdap_cli_kinit_done, req);
+}
+
+static void sdap_cli_kinit_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(subreq,
+ struct tevent_req);
enum sdap_result result;
int ret;
@@ -3344,6 +3525,15 @@ static void sdap_cli_kinit_done(struct tevent_req *subreq)
return;
}
+ sdap_cli_auth_step(req);
+}
+
+static void sdap_cli_auth_step(struct tevent_req *req)
+{
+ struct sdap_cli_connect_state *state = tevent_req_data(req,
+ struct sdap_cli_connect_state);
+ struct tevent_req *subreq;
+
subreq = sdap_auth_send(state,
state->ev,
state->sh,
@@ -3361,10 +3551,10 @@ static void sdap_cli_kinit_done(struct tevent_req *subreq)
tevent_req_error(req, ENOMEM);
return;
}
- tevent_req_set_callback(subreq, sdap_cli_bind_done, req);
+ tevent_req_set_callback(subreq, sdap_cli_auth_done, req);
}
-static void sdap_cli_bind_done(struct tevent_req *subreq)
+static void sdap_cli_auth_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(subreq,
struct tevent_req);
@@ -3385,11 +3575,13 @@ static void sdap_cli_bind_done(struct tevent_req *subreq)
tevent_req_done(req);
}
-int sdap_cli_connect_recv(struct tevent_req *req, TALLOC_CTX *memctx,
- struct sdap_handle **gsh)
+int sdap_cli_connect_recv(struct tevent_req *req,
+ TALLOC_CTX *memctx,
+ struct sdap_handle **gsh,
+ struct sysdb_attrs **rootdse)
{
struct sdap_cli_connect_state *state = tevent_req_data(req,
- struct sdap_cli_connect_state);
+ struct sdap_cli_connect_state);
enum tevent_req_state tstate;
uint64_t err;
@@ -3398,10 +3590,28 @@ int sdap_cli_connect_recv(struct tevent_req *req, TALLOC_CTX *memctx,
return EIO;
}
- *gsh = talloc_steal(memctx, state->sh);
- if (!*gsh) {
- return ENOMEM;
+ if (gsh) {
+ *gsh = talloc_steal(memctx, state->sh);
+ if (!*gsh) {
+ return ENOMEM;
+ }
+ } else {
+ talloc_zfree(state->sh);
}
+
+ if (rootdse) {
+ if (state->use_rootdse) {
+ *rootdse = talloc_steal(memctx, state->rootdse);
+ if (!*rootdse) {
+ return ENOMEM;
+ }
+ } else {
+ *rootdse = NULL;
+ }
+ } else {
+ talloc_zfree(rootdse);
+ }
+
return EOK;
}
@@ -3411,35 +3621,33 @@ struct sdap_get_generic_state {
struct tevent_context *ev;
struct sdap_options *opts;
struct sdap_handle *sh;
- struct sss_domain_info *dom;
- const char **attrs;
- const char *filter;
const char *search_base;
- struct sysdb_attrs **reply;
- size_t reply_max;
- size_t reply_count;
+ int scope;
+ const char *filter;
+ const char **attrs;
- struct sysdb_handle *handle;
struct sdap_op *op;
+
+ size_t reply_max;
+ size_t reply_count;
+ struct sysdb_attrs **reply;
};
-static errno_t add_to_reply(TALLOC_CTX *memctx,
- struct sdap_get_generic_state *state,
+static errno_t add_to_reply(struct sdap_get_generic_state *state,
struct sysdb_attrs *msg);
static void sdap_get_generic_done(struct sdap_op *op,
- struct sdap_msg *reply,
- int error, void *pvt);
+ struct sdap_msg *reply,
+ int error, void *pvt);
struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
- struct tevent_context *ev,
- struct sss_domain_info *dom,
- struct sysdb_ctx *sysdb,
- struct sdap_options *opts,
- struct sdap_handle *sh,
- const char **attrs,
- const char *filter,
- const char *search_base)
+ struct tevent_context *ev,
+ struct sdap_options *opts,
+ struct sdap_handle *sh,
+ const char *search_base,
+ int scope,
+ const char *filter,
+ const char **attrs)
{
struct tevent_req *req = NULL;
struct sdap_get_generic_state *state = NULL;
@@ -3452,29 +3660,30 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
state->ev = ev;
state->opts = opts;
- state->dom = dom;
state->sh = sh;
+ state->search_base = search_base;
+ state->scope = scope;
state->filter = filter;
state->attrs = attrs;
- state->search_base = search_base;
- state->reply = NULL;
+ state->op = NULL;
state->reply_max = 0;
state->reply_count = 0;
- state->op = NULL;
- state->handle = NULL;
+ state->reply = NULL;
DEBUG(7, ("calling ldap_search_ext with [%s][%s].\n", state->filter,
state->search_base));
if (debug_level >= 7) {
int i;
- for (i = 0; state->attrs[i]; i++) {
- DEBUG(7, ("Requesting attrs: [%s]\n", state->attrs[i]));
+ if (state->attrs) {
+ for (i = 0; state->attrs[i]; i++) {
+ DEBUG(7, ("Requesting attrs: [%s]\n", state->attrs[i]));
+ }
}
}
lret = ldap_search_ext(state->sh->ldap, state->search_base,
- LDAP_SCOPE_SUBTREE, state->filter,
+ state->scope, state->filter,
discard_const(state->attrs),
false, NULL, NULL, NULL, 0, &msgid);
if (lret != LDAP_SUCCESS) {
@@ -3486,7 +3695,8 @@ struct tevent_req *sdap_get_generic_send(TALLOC_CTX *memctx,
ret = sdap_op_add(state, state->ev, state->sh, msgid,
sdap_get_generic_done, req,
- dp_opt_get_int(state->opts->basic,SDAP_SEARCH_TIMEOUT),
+ dp_opt_get_int(state->opts->basic,
+ SDAP_SEARCH_TIMEOUT),
&state->op);
if (ret != EOK) {
DEBUG(1, ("Failed to set up operation!\n"));
@@ -3509,8 +3719,10 @@ static void sdap_get_generic_done(struct sdap_op *op,
struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
struct sdap_get_generic_state *state = tevent_req_data(req,
struct sdap_get_generic_state);
- int ret;
struct sysdb_attrs *attrs;
+ char *errmsg;
+ int result;
+ int ret;
if (error) {
tevent_req_error(req, error);
@@ -3534,7 +3746,7 @@ static void sdap_get_generic_done(struct sdap_op *op,
return;
}
- ret = add_to_reply(state, state, attrs);
+ ret = add_to_reply(state, attrs);
if (ret != EOK) {
DEBUG(1, ("add_to_reply failed.\n"));
tevent_req_error(req, ret);
@@ -3543,18 +3755,46 @@ static void sdap_get_generic_done(struct sdap_op *op,
sdap_unlock_next_reply(state->op);
break;
+
case LDAP_RES_SEARCH_RESULT:
+ ret = ldap_parse_result(state->sh->ldap, reply->msg,
+ &result, NULL, &errmsg, NULL, NULL, 0);
+ if (ret != LDAP_SUCCESS) {
+ DEBUG(2, ("ldap_parse_result failed (%d)\n", state->op->msgid));
+ tevent_req_error(req, EIO);
+ return;
+ }
+
+ DEBUG(3, ("Search result: %s(%d), %s\n",
+ ldap_err2string(result), result, errmsg));
+
tevent_req_done(req);
return;
- break;
default:
/* what is going on here !? */
tevent_req_error(req, EIO);
return;
}
+}
- return;
+static errno_t add_to_reply(struct sdap_get_generic_state *state,
+ struct sysdb_attrs *msg)
+{
+ if (state->reply == NULL || state->reply_max == state->reply_count) {
+ state->reply_max += REPLY_REALLOC_INCREMENT;
+ state->reply = talloc_realloc(state, state->reply,
+ struct sysdb_attrs *,
+ state->reply_max);
+ if (state->reply == NULL) {
+ DEBUG(1, ("talloc_realloc failed.\n"));
+ return ENOMEM;
+ }
+ }
+
+ state->reply[state->reply_count++] = talloc_steal(state->reply, msg);
+
+ return EOK;
}
int sdap_get_generic_recv(struct tevent_req *req,
@@ -3566,7 +3806,6 @@ int sdap_get_generic_recv(struct tevent_req *req,
struct sdap_get_generic_state);
enum tevent_req_state tstate;
uint64_t err;
- int i;
if (tevent_req_is_error(req, &tstate, &err)) {
if (err) return err;
@@ -3575,31 +3814,7 @@ int sdap_get_generic_recv(struct tevent_req *req,
*reply_count = state->reply_count;
*reply = talloc_steal(mem_ctx, state->reply);
- for (i = 0; i < state->reply_count; i++) {
- talloc_steal(mem_ctx, state->reply[i]);
- }
return EOK;
}
-static errno_t add_to_reply(TALLOC_CTX *memctx,
- struct sdap_get_generic_state *state,
- struct sysdb_attrs *msg)
-{
- struct sysdb_attrs **dummy;
-
- if (state->reply == NULL || state->reply_max == state->reply_count) {
- state->reply_max += REPLY_REALLOC_INCREMENT;
- dummy = talloc_realloc(memctx, state->reply, struct sysdb_attrs *,
- state->reply_max);
- if (dummy == NULL) {
- DEBUG(1, ("talloc_realloc failed.\n"));
- return ENOMEM;
- }
- state->reply = dummy;
- }
-
- state->reply[state->reply_count++] = talloc_steal(state->reply, msg);
-
- return EOK;
-}