From 9b8fd65b6eb242936a5d0734eb05e3c09d3268a5 Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Wed, 2 Mar 2016 14:33:38 -0500
Subject: [PATCH 1/3] Util: Move socket setup in a common utility file

Other components may need to connect sockets, the code here is generic enough
that with minimal modifications can be used for non-ldap connections too.

So create a sss_sockets.c/h utility file with all the non-ldap specific socket
setup functions and make them available for other uses.

Resolves:
https://fedorahosted.org/sssd/ticket/2968
---
 Makefile.am            |   5 +
 src/util/sss_ldap.c    | 258 ++---------------------------------
 src/util/sss_sockets.c | 356 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/util/sss_sockets.h |  39 ++++++
 4 files changed, 413 insertions(+), 245 deletions(-)
 create mode 100644 src/util/sss_sockets.c
 create mode 100644 src/util/sss_sockets.h

diff --git a/Makefile.am b/Makefile.am
index 4e4f38a5eaf5bfa2cfafa88b9b32848e6c27131b..d6eb0fc732a3b566dba91952bd6598a31f8d8d3e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -541,6 +541,7 @@ dist_noinst_HEADERS = \
     src/util/sss_python.h \
     src/util/sss_krb5.h \
     src/util/sss_selinux.h \
+    src/util/sss_sockets.h \
     src/util/sss_utf8.h \
     src/util/sss_ssh.h \
     src/util/sss_ini.h \
@@ -1663,6 +1664,7 @@ ipa_ldap_opt_tests_SOURCES = \
     src/providers/ad/ad_opts.c \
     src/providers/ipa/ipa_opts.c \
     src/providers/krb5/krb5_opts.c \
+    src/util/sss_sockets.c \
     src/util/sss_ldap.c \
     src/tests/ipa_ldap_opt-tests.c
 ipa_ldap_opt_tests_CFLAGS = \
@@ -1877,6 +1879,7 @@ TEST_MOCK_RESP_OBJ = \
      src/responder/common/responder_cache_req.c
 
 TEST_MOCK_PROVIDER_OBJ = \
+     src/util/sss_sockets.c \
      src/util/sss_ldap.c \
      src/providers/data_provider_opts.c \
      src/providers/ldap/ldap_opts.c \
@@ -2264,6 +2267,7 @@ sdap_tests_SOURCES = \
     src/providers/ldap/sdap_range.c \
     src/providers/ldap/ldap_opts.c \
     src/providers/ipa/ipa_opts.c \
+    src/util/sss_sockets.c \
     src/util/sss_ldap.c \
     src/tests/cmocka/test_sdap.c \
     $(NULL)
@@ -2879,6 +2883,7 @@ libsss_ldap_common_la_SOURCES = \
     src/providers/ldap/sdap.c \
     src/providers/ipa/ipa_dn.c \
     src/util/user_info_msg.c \
+    src/util/sss_sockets.c \
     src/util/sss_ldap.c \
     $(NULL)
 libsss_ldap_common_la_CFLAGS = \
diff --git a/src/util/sss_ldap.c b/src/util/sss_ldap.c
index c440d5445133c8b31f662fc69b35e2296c3f1702..7fdaadb5cebf5d3e7fe7f8fb1780f0db3dbcae4a 100644
--- a/src/util/sss_ldap.c
+++ b/src/util/sss_ldap.c
@@ -17,18 +17,13 @@
     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
 
 #include "config.h"
-
-#include "providers/ldap/sdap.h"
-#include "util/sss_ldap.h"
 #include "util/util.h"
+#include "util/sss_sockets.h"
+#include "util/sss_ldap.h"
+
+#include "providers/ldap/sdap.h"
 
 const char* sss_ldap_err2string(int err)
 {
@@ -103,183 +98,6 @@ int sss_ldap_control_create(const char *oid, int iscritical,
 }
 
 #ifdef HAVE_LDAP_INIT_FD
-struct sdap_async_sys_connect_state {
-    long old_flags;
-    struct tevent_fd *fde;
-    int fd;
-    socklen_t addr_len;
-    struct sockaddr_storage addr;
-};
-
-static void sdap_async_sys_connect_done(struct tevent_context *ev,
-                                        struct tevent_fd *fde, uint16_t flags,
-                                        void *priv);
-
-static struct tevent_req *sdap_async_sys_connect_send(TALLOC_CTX *mem_ctx,
-                                                    struct tevent_context *ev,
-                                                    int fd,
-                                                    const struct sockaddr *addr,
-                                                    socklen_t addr_len)
-{
-    struct tevent_req *req;
-    struct sdap_async_sys_connect_state *state;
-    long flags;
-    int ret;
-    int fret;
-
-    flags = fcntl(fd, F_GETFL, 0);
-    if (flags == -1) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_GETFL failed.\n");
-        return NULL;
-    }
-
-    req = tevent_req_create(mem_ctx, &state,
-                            struct sdap_async_sys_connect_state);
-    if (req == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
-        return NULL;
-    }
-
-    state->old_flags = flags;
-    state->fd = fd;
-    state->addr_len = addr_len;
-    memcpy(&state->addr, addr, addr_len);
-
-    ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
-        goto done;
-    }
-
-    ret = connect(fd, addr, addr_len);
-    if (ret == EOK) {
-        goto done;
-    }
-
-    ret = errno;
-    switch(ret) {
-        case EINPROGRESS:
-        case EINTR:
-            state->fde = tevent_add_fd(ev, state, fd,
-                                       TEVENT_FD_READ | TEVENT_FD_WRITE,
-                                       sdap_async_sys_connect_done, req);
-            if (state->fde == NULL) {
-                DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_fd failed.\n");
-                ret = ENOMEM;
-                goto done;
-            }
-
-            return req;
-
-            break;
-        default:
-            DEBUG(SSSDBG_CRIT_FAILURE,
-                  "connect failed [%d][%s].\n", ret, strerror(ret));
-    }
-
-done:
-    fret = fcntl(fd, F_SETFL, flags);
-    if (fret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
-    }
-
-    if (ret == EOK) {
-        tevent_req_done(req);
-    } else {
-        tevent_req_error(req, ret);
-    }
-
-    tevent_req_post(req, ev);
-    return req;
-}
-
-static void sdap_async_sys_connect_done(struct tevent_context *ev,
-                                        struct tevent_fd *fde, uint16_t flags,
-                                        void *priv)
-{
-    struct tevent_req *req = talloc_get_type(priv, struct tevent_req);
-    struct sdap_async_sys_connect_state *state = tevent_req_data(req,
-                                          struct sdap_async_sys_connect_state);
-    int ret;
-    int fret;
-
-    errno = 0;
-    ret = connect(state->fd, (struct sockaddr *) &state->addr,
-                  state->addr_len);
-    if (ret != EOK) {
-        ret = errno;
-        if (ret == EINPROGRESS || ret == EINTR) {
-            return; /* Try again later */
-        }
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "connect failed [%d][%s].\n", ret, strerror(ret));
-    }
-
-    talloc_zfree(fde);
-
-    fret = fcntl(state->fd, F_SETFL, state->old_flags);
-    if (fret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
-    }
-
-    if (ret == EOK) {
-        tevent_req_done(req);
-    } else {
-        tevent_req_error(req, ret);
-    }
-
-    return;
-}
-
-static int sdap_async_sys_connect_recv(struct tevent_req *req)
-{
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    return EOK;
-}
-
-static errno_t set_fd_flags_and_opts(int fd)
-{
-    int ret;
-    long flags;
-    int dummy = 1;
-
-    flags = fcntl(fd, F_GETFD, 0);
-    if (flags == -1) {
-        ret = errno;
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "fcntl F_GETFD failed [%d][%s].\n", ret, strerror(ret));
-        return ret;
-    }
-
-    flags = fcntl(fd, F_SETFD, flags| FD_CLOEXEC);
-    if (flags == -1) {
-        ret = errno;
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "fcntl F_SETFD failed [%d][%s].\n", ret, strerror(ret));
-        return ret;
-    }
-
-    /* SO_KEEPALIVE and TCP_NODELAY are set by OpenLDAP client libraries but
-     * failures are ignored.*/
-    ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &dummy, sizeof(dummy));
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(SSSDBG_FUNC_DATA,
-              "setsockopt SO_KEEPALIVE failed.[%d][%s].\n", ret,
-                  strerror(ret));
-    }
-
-    ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &dummy, sizeof(dummy));
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(SSSDBG_FUNC_DATA,
-              "setsockopt TCP_NODELAY failed.[%d][%s].\n", ret,
-                  strerror(ret));
-    }
-
-    return EOK;
-}
 
 #define LDAP_PROTO_TCP 1 /* ldap://  */
 #define LDAP_PROTO_UDP 2 /* reserved */
@@ -289,19 +107,12 @@ static errno_t set_fd_flags_and_opts(int fd)
 extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, LDAP **ld);
 
 static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq);
-static void sdap_async_sys_connect_timeout(struct tevent_context *ev,
-                                           struct tevent_timer *te,
-                                           struct timeval tv, void *pvt);
 #endif
 
 struct sss_ldap_init_state {
     LDAP *ldap;
     int sd;
     const char *uri;
-
-#ifdef HAVE_LDAP_INIT_FD
-    struct tevent_timer *connect_timeout;
-#endif
 };
 
 static int sss_ldap_init_state_destructor(void *data)
@@ -313,14 +124,17 @@ static int sss_ldap_init_state_destructor(void *data)
               "calling ldap_unbind_ext for ldap:[%p] sd:[%d]\n",
               state->ldap, state->sd);
         ldap_unbind_ext(state->ldap, NULL, NULL);
-    } else if (state->sd != -1) {
+    }
+    if (state->sd != -1) {
         DEBUG(SSSDBG_TRACE_FUNC, "closing socket [%d]\n", state->sd);
         close(state->sd);
+        state->sd = -1;
     }
 
     return 0;
 }
 
+
 struct tevent_req *sss_ldap_init_send(TALLOC_CTX *mem_ctx,
                                       struct tevent_context *ev,
                                       const char *uri,
@@ -340,47 +154,16 @@ struct tevent_req *sss_ldap_init_send(TALLOC_CTX *mem_ctx,
     talloc_set_destructor((TALLOC_CTX *)state, sss_ldap_init_state_destructor);
 
     state->ldap = NULL;
+    state->sd = -1;
     state->uri = uri;
 
 #ifdef HAVE_LDAP_INIT_FD
     struct tevent_req *subreq;
-    struct timeval tv;
 
-    state->sd = socket(addr->ss_family, SOCK_STREAM, 0);
-    if (state->sd == -1) {
-        ret = errno;
-        DEBUG(SSSDBG_CRIT_FAILURE,
-              "socket failed [%d][%s].\n", ret, strerror(ret));
-        goto fail;
-    }
-
-    ret = set_fd_flags_and_opts(state->sd);
-    if (ret != EOK) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "set_fd_flags_and_opts failed.\n");
-        goto fail;
-    }
-
-    DEBUG(SSSDBG_TRACE_ALL,
-          "Using file descriptor [%d] for LDAP connection.\n", state->sd);
-
-    subreq = sdap_async_sys_connect_send(state, ev, state->sd,
-                                         (struct sockaddr *) addr, addr_len);
+    subreq = sssd_async_socket_init_send(state, ev, addr, addr_len, timeout);
     if (subreq == NULL) {
         ret = ENOMEM;
-        DEBUG(SSSDBG_CRIT_FAILURE, "sdap_async_sys_connect_send failed.\n");
-        goto fail;
-    }
-
-    DEBUG(SSSDBG_TRACE_FUNC,
-          "Setting %d seconds timeout for connecting\n", timeout);
-    tv = tevent_timeval_current_ofs(timeout, 0);
-
-    state->connect_timeout = tevent_add_timer(ev, subreq, tv,
-                                              sdap_async_sys_connect_timeout,
-                                              subreq);
-    if (state->connect_timeout == NULL) {
-        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
-        ret = ENOMEM;
+        DEBUG(SSSDBG_CRIT_FAILURE, "sssd_async_socket_init_send failed.\n");
         goto fail;
     }
 
@@ -392,7 +175,6 @@ fail:
 #else
     DEBUG(SSSDBG_MINOR_FAILURE, "ldap_init_fd not available, "
               "will use ldap_initialize with uri [%s].\n", uri);
-    state->sd = -1;
     ret = ldap_initialize(&state->ldap, uri);
     if (ret == LDAP_SUCCESS) {
         tevent_req_done(req);
@@ -412,18 +194,6 @@ fail:
 }
 
 #ifdef HAVE_LDAP_INIT_FD
-static void sdap_async_sys_connect_timeout(struct tevent_context *ev,
-                                           struct tevent_timer *te,
-                                           struct timeval tv, void *pvt)
-{
-    struct tevent_req *connection_request;
-
-    DEBUG(SSSDBG_CONF_SETTINGS, "The LDAP connection timed out\n");
-
-    connection_request = talloc_get_type(pvt, struct tevent_req);
-    tevent_req_error(connection_request, ETIMEDOUT);
-}
-
 static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq)
 {
     struct tevent_req *req = tevent_req_callback_data(subreq,
@@ -433,13 +203,11 @@ static void sss_ldap_init_sys_connect_done(struct tevent_req *subreq)
     int ret;
     int lret;
 
-    talloc_zfree(state->connect_timeout);
-
-    ret = sdap_async_sys_connect_recv(subreq);
+    ret = sssd_async_socket_init_recv(subreq, &state->sd);
     talloc_zfree(subreq);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE,
-              "sdap_async_sys_connect request failed: [%d]: %s.\n",
+              "sssd_async_socket_init request failed: [%d]: %s.\n",
               ret, sss_strerror(ret));
         goto fail;
     }
diff --git a/src/util/sss_sockets.c b/src/util/sss_sockets.c
new file mode 100644
index 0000000000000000000000000000000000000000..d0283af2d18ad42a13ec00faf7d6c4934eb696d0
--- /dev/null
+++ b/src/util/sss_sockets.c
@@ -0,0 +1,356 @@
+/*
+   SSSD
+
+   Socket utils
+
+   Copyright (C) Simo Sorce <ssorce@redhat.com>	2016
+   Copyright (C) Sumit Bose <sbose@redhat.com> 2009
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include "util/util.h"
+
+
+static errno_t set_fd_flags_and_opts(int fd)
+{
+    int ret;
+    long flags;
+    int dummy = 1;
+
+    flags = fcntl(fd, F_GETFD, 0);
+    if (flags == -1) {
+        ret = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "fcntl F_GETFD failed [%d][%s].\n", ret, strerror(ret));
+        return ret;
+    }
+
+    flags = fcntl(fd, F_SETFD, flags| FD_CLOEXEC);
+    if (flags == -1) {
+        ret = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "fcntl F_SETFD failed [%d][%s].\n", ret, strerror(ret));
+        return ret;
+    }
+
+    /* SO_KEEPALIVE and TCP_NODELAY are set by OpenLDAP client libraries but
+     * failures are ignored.*/
+    ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &dummy, sizeof(dummy));
+    if (ret != 0) {
+        ret = errno;
+        DEBUG(SSSDBG_FUNC_DATA,
+              "setsockopt SO_KEEPALIVE failed.[%d][%s].\n", ret,
+                  strerror(ret));
+    }
+
+    ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &dummy, sizeof(dummy));
+    if (ret != 0) {
+        ret = errno;
+        DEBUG(SSSDBG_FUNC_DATA,
+              "setsockopt TCP_NODELAY failed.[%d][%s].\n", ret,
+                  strerror(ret));
+    }
+
+    return EOK;
+}
+
+
+struct sssd_async_connect_state {
+    long old_flags;
+    struct tevent_fd *fde;
+    int fd;
+    socklen_t addr_len;
+    struct sockaddr_storage addr;
+};
+
+static void sssd_async_connect_done(struct tevent_context *ev,
+                                    struct tevent_fd *fde, uint16_t flags,
+                                    void *priv);
+
+struct tevent_req *sssd_async_connect_send(TALLOC_CTX *mem_ctx,
+                                           struct tevent_context *ev,
+                                           int fd,
+                                           const struct sockaddr *addr,
+                                           socklen_t addr_len)
+{
+    struct tevent_req *req;
+    struct sssd_async_connect_state *state;
+    long flags;
+    int ret;
+    int fret;
+
+    flags = fcntl(fd, F_GETFL, 0);
+    if (flags == -1) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_GETFL failed.\n");
+        return NULL;
+    }
+
+    req = tevent_req_create(mem_ctx, &state,
+                            struct sssd_async_connect_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
+        return NULL;
+    }
+
+    state->old_flags = flags;
+    state->fd = fd;
+    state->addr_len = addr_len;
+    memcpy(&state->addr, addr, addr_len);
+
+    ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
+        goto done;
+    }
+
+    ret = connect(fd, addr, addr_len);
+    if (ret == EOK) {
+        goto done;
+    }
+
+    ret = errno;
+    switch (ret) {
+    case EINPROGRESS:
+    case EINTR:
+        state->fde = tevent_add_fd(ev, state, fd,
+                                   TEVENT_FD_READ | TEVENT_FD_WRITE,
+                                   sssd_async_connect_done, req);
+        if (state->fde == NULL) {
+            DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_fd failed.\n");
+            ret = ENOMEM;
+            goto done;
+        }
+
+        return req;
+
+        break;
+    default:
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "connect failed [%d][%s].\n", ret, strerror(ret));
+    }
+
+done:
+    fret = fcntl(fd, F_SETFL, flags);
+    if (fret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
+    }
+
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static void sssd_async_connect_done(struct tevent_context *ev,
+                                    struct tevent_fd *fde, uint16_t flags,
+                                    void *priv)
+{
+    struct tevent_req *req = talloc_get_type(priv, struct tevent_req);
+    struct sssd_async_connect_state *state =
+                tevent_req_data(req, struct sssd_async_connect_state);
+    int ret;
+    int fret;
+
+    errno = 0;
+    ret = connect(state->fd, (struct sockaddr *) &state->addr,
+                  state->addr_len);
+    if (ret != EOK) {
+        ret = errno;
+        if (ret == EINPROGRESS || ret == EINTR) {
+            return; /* Try again later */
+        }
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "connect failed [%d][%s].\n", ret, strerror(ret));
+    }
+
+    talloc_zfree(fde);
+
+    fret = fcntl(state->fd, F_SETFL, state->old_flags);
+    if (fret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "fcntl F_SETFL failed.\n");
+    }
+
+    if (ret == EOK) {
+        tevent_req_done(req);
+    } else {
+        tevent_req_error(req, ret);
+    }
+
+    return;
+}
+
+int sssd_async_connect_recv(struct tevent_req *req)
+{
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    return EOK;
+}
+
+
+static void sssd_async_connect_timeout(struct tevent_context *ev,
+                                       struct tevent_timer *te,
+                                       struct timeval tv, void *pvt)
+{
+    struct tevent_req *connection_request;
+
+    DEBUG(SSSDBG_CONF_SETTINGS, "The connection timed out\n");
+
+    connection_request = talloc_get_type(pvt, struct tevent_req);
+    tevent_req_error(connection_request, ETIMEDOUT);
+}
+
+
+struct sssd_async_socket_state {
+    struct tevent_timer *connect_timeout;
+    int sd;
+};
+
+static int sssd_async_socket_state_destructor(void *data);
+static void sssd_async_socket_init_done(struct tevent_req *subreq);
+
+struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               struct sockaddr_storage *addr,
+                                               socklen_t addr_len, int timeout)
+{
+    struct sssd_async_socket_state *state;
+    struct tevent_req *req, *subreq;
+    struct timeval tv;
+    int ret;
+
+    req = tevent_req_create(mem_ctx, &state, struct sssd_async_socket_state);
+    if (req == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
+        return NULL;
+    }
+    state->sd = -1;
+
+    talloc_set_destructor((TALLOC_CTX *)state,
+                          sssd_async_socket_state_destructor);
+
+    state->sd = socket(addr->ss_family, SOCK_STREAM, 0);
+    if (state->sd == -1) {
+        ret = errno;
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "socket failed [%d][%s].\n", ret, strerror(ret));
+        goto fail;
+    }
+
+    ret = set_fd_flags_and_opts(state->sd);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "set_fd_flags_and_opts failed.\n");
+        goto fail;
+    }
+
+    DEBUG(SSSDBG_TRACE_ALL,
+          "Using file descriptor [%d] for LDAP connection.\n", state->sd);
+
+    subreq = sssd_async_connect_send(state, ev, state->sd,
+                                     (struct sockaddr *) addr, addr_len);
+    if (subreq == NULL) {
+        ret = ENOMEM;
+        DEBUG(SSSDBG_CRIT_FAILURE, "sssd_async_connect_send failed.\n");
+        goto fail;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC,
+          "Setting %d seconds timeout for connecting\n", timeout);
+    tv = tevent_timeval_current_ofs(timeout, 0);
+
+    state->connect_timeout = tevent_add_timer(ev, subreq, tv,
+                                              sssd_async_connect_timeout,
+                                              subreq);
+    if (state->connect_timeout == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
+        ret = ENOMEM;
+        goto fail;
+    }
+
+    tevent_req_set_callback(subreq, sssd_async_socket_init_done, req);
+    return req;
+
+fail:
+    tevent_req_error(req, ret);
+    tevent_req_post(req, ev);
+    return req;
+}
+
+static void sssd_async_socket_init_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req =
+                tevent_req_callback_data(subreq, struct tevent_req);
+    struct sssd_async_socket_state *state =
+                tevent_req_data(req, struct sssd_async_socket_state);
+    int ret;
+
+    /* kill the timeout handler now that we got a reply */
+    talloc_zfree(state->connect_timeout);
+
+    ret = sssd_async_connect_recv(subreq);
+    talloc_zfree(subreq);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "sdap_async_sys_connect request failed: [%d]: %s.\n",
+              ret, sss_strerror(ret));
+        goto fail;
+    }
+
+    tevent_req_done(req);
+    return;
+
+fail:
+    tevent_req_error(req, ret);
+}
+
+int sssd_async_socket_init_recv(struct tevent_req *req, int *sd)
+{
+    struct sssd_async_socket_state *state =
+                tevent_req_data(req, struct sssd_async_socket_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    /* steal the sd and neutralize destructor actions */
+    *sd = state->sd;
+    state->sd = -1;
+
+    return EOK;
+}
+
+static int sssd_async_socket_state_destructor(void *data)
+{
+    struct sssd_async_socket_state *state =
+        talloc_get_type(data, struct sssd_async_socket_state);
+
+    if (state->sd != -1) {
+        DEBUG(SSSDBG_TRACE_FUNC, "closing socket [%d]\n", state->sd);
+        close(state->sd);
+        state->sd = -1;
+    }
+
+    return 0;
+}
diff --git a/src/util/sss_sockets.h b/src/util/sss_sockets.h
new file mode 100644
index 0000000000000000000000000000000000000000..ccb05cb846a7cf520f150a7ba0a5cbd3cf7e3fb5
--- /dev/null
+++ b/src/util/sss_sockets.h
@@ -0,0 +1,39 @@
+/*
+   SSSD
+
+   Socket utils
+
+   Copyright (C) Simo Sorce <ssorce@redhat.com>	2016
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef __SSS_SOCKETS_H__
+#define __SSS_SOCKETS_H__
+
+struct tevent_req *sssd_async_connect_send(TALLOC_CTX *mem_ctx,
+                                           struct tevent_context *ev,
+                                           int fd,
+                                           const struct sockaddr *addr,
+                                           socklen_t addr_len);
+int sssd_async_connect_recv(struct tevent_req *req);
+
+
+struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx,
+                                               struct tevent_context *ev,
+                                               struct sockaddr_storage *addr,
+                                               socklen_t addr_len, int timeout);
+int sssd_async_socket_init_recv(struct tevent_req *req, int *sd);
+
+#endif /* __SSS_SOCKETS_H__ */
-- 
2.5.0

