From bb378225078409e7f4e1b70925550003ca0aaca5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Tue, 16 Apr 2013 15:09:34 +0200
Subject: [PATCH 4/6] sdap: add sdap_connect_host request

Create connection to specified LDAP server without using any
failover stuff.
---
 src/providers/ldap/sdap_async.h            |  15 +++
 src/providers/ldap/sdap_async_connection.c | 186 +++++++++++++++++++++++++++++
 2 files changed, 201 insertions(+)

diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h
index 59269110126c7015d6ae18f2ae1ddc6b2871d360..eedf8a706edadac437fadc80df7af4c4066bab2a 100644
--- a/src/providers/ldap/sdap_async.h
+++ b/src/providers/ldap/sdap_async.h
@@ -43,6 +43,21 @@ int sdap_connect_recv(struct tevent_req *req,
                       TALLOC_CTX *memctx,
                       struct sdap_handle **sh);
 
+struct tevent_req *sdap_connect_host_send(TALLOC_CTX *mem_ctx,
+                                          struct tevent_context *ev,
+                                          struct sdap_options *opts,
+                                          struct resolv_ctx *resolv_ctx,
+                                          enum restrict_family family_order,
+                                          enum host_database *host_db,
+                                          const char *protocol,
+                                          const char *host,
+                                          int port,
+                                          bool use_start_tls);
+
+errno_t sdap_connect_host_recv(TALLOC_CTX *mem_ctx,
+                               struct tevent_req *req,
+                               struct sdap_handle **_sh);
+
 struct tevent_req *sdap_get_users_send(TALLOC_CTX *memctx,
                                        struct tevent_context *ev,
                                        struct sss_domain_info *dom,
diff --git a/src/providers/ldap/sdap_async_connection.c b/src/providers/ldap/sdap_async_connection.c
index f77d0380582a0a12950606b5991b8d4f48bd2dd6..173d72ae96f86dcced412aa0028294e2f6c29872 100644
--- a/src/providers/ldap/sdap_async_connection.c
+++ b/src/providers/ldap/sdap_async_connection.c
@@ -434,6 +434,192 @@ int sdap_connect_recv(struct tevent_req *req,
     return EOK;
 }
 
+struct sdap_connect_host_state {
+    struct tevent_context *ev;
+    struct sdap_options *opts;
+    char *uri;
+    char *protocol;
+    char *host;
+    int port;
+    bool use_start_tls;
+
+    struct sdap_handle *sh;
+};
+
+static void sdap_connect_host_resolv_done(struct tevent_req *subreq);
+static void sdap_connect_host_done(struct tevent_req *subreq);
+
+struct tevent_req *sdap_connect_host_send(TALLOC_CTX *mem_ctx,
+                                          struct tevent_context *ev,
+                                          struct sdap_options *opts,
+                                          struct resolv_ctx *resolv_ctx,
+                                          enum restrict_family family_order,
+                                          enum host_database *host_db,
+                                          const char *protocol,
+                                          const char *host,
+                                          int port,
+                                          bool use_start_tls)
+{
+    struct sdap_connect_host_state *state = NULL;
+    struct tevent_req *req = NULL;
+    struct tevent_req *subreq = NULL;
+    errno_t ret;
+
+    req = tevent_req_create(mem_ctx, &state,
+                            struct sdap_connect_host_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, ("tevent_req_create() failed\n"));
+        return NULL;
+    }
+
+    state->ev = ev;
+    state->opts = opts;
+    state->port = port;
+    state->use_start_tls = use_start_tls;
+
+    state->protocol = talloc_strdup(state, protocol);
+    if (state->protocol == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    state->host = talloc_strdup(state, host);
+    if (state->host == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    state->uri = talloc_asprintf(state, "%s://%s:%d", protocol, host, port);
+    if (state->uri == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, ("Resolving host %s\n", host));
+
+    subreq = resolv_gethostbyname_send(state, state->ev, resolv_ctx,
+                                       host, family_order, host_db);
+    if (subreq == NULL) {
+        ret = ENOMEM;
+        goto immediately;
+    }
+
+    tevent_req_set_callback(subreq, sdap_connect_host_resolv_done, req);
+
+    return req;
+
+immediately:
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+    tevent_req_post(req, ev);
+
+    return req;
+}
+
+static void sdap_connect_host_resolv_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req = NULL;
+    struct sdap_connect_host_state *state = NULL;
+    struct resolv_hostent *hostent = NULL;
+    struct sockaddr_storage *sockaddr = NULL;
+    int status;
+    errno_t ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_connect_host_state);
+
+    ret = resolv_gethostbyname_recv(subreq, state, &status, NULL, &hostent);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_OP_FAILURE, ("Failed to resolve host %s: %s\n",
+                                  state->host, resolv_strerror(status)));
+        goto done;
+    }
+
+    sockaddr = resolv_get_sockaddr_address(state, hostent, state->port);
+    if (sockaddr == NULL) {
+        DEBUG(SSSDBG_OP_FAILURE, ("resolv_get_sockaddr_address() failed\n"));
+        ret = EIO;
+        goto done;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, ("Connecting to %s\n", state->uri));
+
+    subreq = sdap_connect_send(state, state->ev, state->opts,
+                               state->uri, sockaddr, state->use_start_tls);
+    if (subreq == NULL) {
+        ret = ENOMEM;
+        goto done;
+    }
+
+    tevent_req_set_callback(subreq, sdap_connect_host_done, req);
+
+    ret = EAGAIN;
+
+done:
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else if (ret != EAGAIN) {
+        tevent_req_error(req, ret);
+    }
+
+    return;
+}
+
+static void sdap_connect_host_done(struct tevent_req *subreq)
+{
+    struct sdap_connect_host_state *state = NULL;
+    struct tevent_req *req = NULL;
+    errno_t ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sdap_connect_host_state);
+
+    ret = sdap_connect_recv(subreq, state, &state->sh);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        goto done;
+    }
+
+    /* if TLS was used, the sdap handle is already marked as connected */
+    if (!state->use_start_tls) {
+        /* we need to mark handle as connected to allow anonymous bind */
+        ret = sdap_set_connected(state->sh, state->ev);
+        if (ret != EOK) {
+            DEBUG(SSSDBG_CRIT_FAILURE, ("sdap_set_connected() failed\n"));
+            goto done;
+        }
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, ("Successful connection to %s\n", state->uri));
+
+done:
+    if (ret != EOK) {
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+errno_t sdap_connect_host_recv(TALLOC_CTX *mem_ctx,
+                               struct tevent_req *req,
+                               struct sdap_handle **_sh)
+{
+    struct sdap_connect_host_state *state = NULL;
+    state = tevent_req_data(req, struct sdap_connect_host_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *_sh = talloc_steal(mem_ctx, state->sh);
+
+    return EOK;
+}
+
+
 /* ==Simple-Bind========================================================== */
 
 struct simple_bind_state {
-- 
1.7.11.7

