r7626: a new ldap client library. Main features are:
authorAndrew Tridgell <tridge@samba.org>
Thu, 16 Jun 2005 05:39:40 +0000 (05:39 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:18:14 +0000 (13:18 -0500)
 - hooked into events system, so requests can be truly async and won't
   interfere with other processing happening at the same time

 - uses NTSTATUS codes for errors (previously errors were mostly
   ignored). In a similar fashion to the DOS error handling, I have
   reserved a range of the NTSTATUS code 32 bit space for LDAP error
   codes, so a function can return a LDAP error code in a NTSTATUS

 - much cleaner packet handling

16 files changed:
source/include/nt_status.h
source/include/structs.h
source/lib/socket/config.mk
source/lib/socket/connect.c [new file with mode: 0644]
source/lib/socket/socket.c
source/lib/socket/socket.h
source/libcli/ldap/config.mk
source/libcli/ldap/ldap.c
source/libcli/ldap/ldap.h
source/libcli/ldap/ldap_bind.c [new file with mode: 0644]
source/libcli/ldap/ldap_client.c
source/libcli/ldap/ldap_client.h [new file with mode: 0644]
source/libcli/ldap/ldap_msg.c [moved from source/libcli/ldap/ldap_ldif.c with 91% similarity]
source/libcli/util/nterr.c
source/torture/ldap/basic.c
source/torture/ldap/common.c

index 0ef443d35563b069d40a86e4e326cd929c0d204b..e427257aa92db672541b4129457d3680f596ed55 100644 (file)
@@ -117,4 +117,9 @@ typedef uint32_t WERROR;
 #define NT_STATUS_DOS_CLASS(status) ((NT_STATUS_V(status) >> 16) & 0xFF)
 #define NT_STATUS_DOS_CODE(status) (NT_STATUS_V(status) & 0xFFFF)
 
+/* define ldap error codes as NTSTATUS codes */
+#define NT_STATUS_LDAP(code) NT_STATUS(0xF2000000 | code)
+#define NT_STATUS_IS_LDAP(status) ((NT_STATUS_V(status) & 0xFF000000) == 0xF2000000)
+#define NT_STATUS_LDAP_CODE(status) (NT_STATUS_V(status) & ~0xFF000000)
+
 #endif
index 04fdaaba15740f03e584d88829d15f0668d5eef6..944f79225bbfc54216cbe085a2e4989916ffc96c 100644 (file)
@@ -92,6 +92,7 @@ struct ldapsrv_call;
 struct ldapsrv_connection;
 struct ldap_connection;
 struct ldap_message;
+struct ldap_Result;
 struct rw_buffer;
 struct registry_context;
 struct registry_key;
@@ -158,6 +159,8 @@ struct ldb_val;
 struct ldb_message;
 struct ldb_context;
 struct ldb_parse_tree;
+struct ldb_message_element;
+struct ldap_mod;
 
 struct dom_sid;
 struct security_token;
index e4719c3f67e4bbac88517bb945d45ad513aba322..13fe5843736a80f5c37618b2309cbc07367e314b 100644 (file)
@@ -35,7 +35,8 @@ NOPROTO=YES
 INIT_OBJ_FILES = \
                lib/socket/socket.o
 ADD_OBJ_FILES = \
-               lib/socket/access.o
+               lib/socket/access.o \
+               lib/socket/connect.o
 NOPROTO=YES
 # End SUBSYSTEM SOCKET
 ################################################
diff --git a/source/lib/socket/connect.c b/source/lib/socket/connect.c
new file mode 100644 (file)
index 0000000..f3f9134
--- /dev/null
@@ -0,0 +1,74 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   implements a non-blocking connect operation that is aware of the samba4 events
+   system
+
+   Copyright (C) Andrew Tridgell 2005
+   
+   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 2 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, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "lib/socket/socket.h"
+#include "lib/events/events.h"
+
+
+/*
+  handle write events on connect completion
+*/
+static void socket_connect_handler(struct event_context *ev, struct fd_event *fde, 
+                                  uint16_t flags, void *private)
+{
+       NTSTATUS *status = (NTSTATUS *)private;
+       *status = NT_STATUS_OK;
+}
+
+
+/*
+  just like socket_connect() but other events can happen while the
+  connect is ongoing. This isn't as good as making the calling code
+  fully async during its connect phase, but at least it means that any
+  calling code that uses this won't interfere with code that is
+  properly async
+ */
+NTSTATUS socket_connect_ev(struct socket_context *sock,
+                          const char *my_address, int my_port,
+                          const char *server_address, int server_port,
+                          uint32_t flags, struct event_context *ev)
+{
+       TALLOC_CTX *tmp_ctx = talloc_new(sock);
+       NTSTATUS status;
+       
+       set_blocking(socket_get_fd(sock), False);
+
+       status = socket_connect(sock, my_address, my_port, 
+                               server_address, server_port, flags);
+
+       event_add_fd(ev, tmp_ctx, socket_get_fd(sock), EVENT_FD_WRITE, 
+                    socket_connect_handler, &status);
+
+       while (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+               if (event_loop_once(ev) != 0) {
+                       talloc_free(tmp_ctx);
+                       return NT_STATUS_INTERNAL_ERROR;
+               }
+       }
+
+       status = socket_connect_complete(sock, flags);
+
+       talloc_free(tmp_ctx);
+       return status;
+}
index 39379be67872ea44202eb533635f1d08de237f73..9d5b67a96632808f9a52fec41ead2c2837740a40 100644 (file)
@@ -243,13 +243,10 @@ NTSTATUS socket_sendto(struct socket_context *sock,
 
 
 /*
-  ask for the number of bytes in a pending incoming datagram
+  ask for the number of bytes in a pending incoming packet
 */
 NTSTATUS socket_pending(struct socket_context *sock, size_t *npending)
 {
-       if (sock->type != SOCKET_TYPE_DGRAM) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
        if (!sock->ops->fn_pending) {
                return NT_STATUS_NOT_IMPLEMENTED;
        }
index e2879e52478dd2809f5e04121a95d0ad27b82d31..8645ba28bc0825209291aa5e17ccedf0e2a452e0 100644 (file)
@@ -139,4 +139,9 @@ BOOL socket_check_access(struct socket_context *sock,
                         const char *service_name,
                         const char **allow_list, const char **deny_list);
 
+NTSTATUS socket_connect_ev(struct socket_context *sock,
+                          const char *my_address, int my_port,
+                          const char *server_address, int server_port,
+                          uint32_t flags, struct event_context *ev);
+
 #endif /* _SAMBA_SOCKET_H */
index 888590ec5ef306479f553bbff142aa348f87f2b8..ca33581043032bb8c8dfc39331bd7e5ce4b58d15 100644 (file)
@@ -3,8 +3,8 @@
 [SUBSYSTEM::LIBCLI_LDAP]
 ADD_OBJ_FILES = libcli/ldap/ldap.o \
                libcli/ldap/ldap_client.o \
-               libcli/ldap/ldap_ldif.o \
+               libcli/ldap/ldap_bind.o \
+               libcli/ldap/ldap_msg.o \
                libcli/ldap/ldap_ndr.o
-NOPROTO=YES
 # End SUBSYSTEM LIBCLI_LDAP
 #################################
index bce3da94aeb4707cce25e28f562373e943aa0bf5..c642fc3e4b3de9eb5710950c50fbedec0ca80bf1 100644 (file)
@@ -1013,44 +1013,4 @@ BOOL ldap_decode(struct asn1_data *data, struct ldap_message *msg)
        return ((!data->has_error) && (data->nesting == NULL));
 }
 
-BOOL ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
-                         char **host, uint16_t *port, BOOL *ldaps)
-{
-       int tmp_port = 0;
-       char protocol[11];
-       char tmp_host[255];
-       const char *p = url;
-       int ret;
-
-       /* skip leading "URL:" (if any) */
-       if (strncasecmp( p, "URL:", 4) == 0) {
-               p += 4;
-       }
-
-       /* Paranoia check */
-       SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
-               
-       ret = sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
-       if (ret < 2) {
-               return False;
-       }
-
-       if (strequal(protocol, "ldap")) {
-               *port = 389;
-               *ldaps = False;
-       } else if (strequal(protocol, "ldaps")) {
-               *port = 636;
-               *ldaps = True;
-       } else {
-               DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
-               return False;
-       }
-
-       if (tmp_port != 0)
-               *port = tmp_port;
-
-       *host = talloc_strdup(mem_ctx, tmp_host);
-
-       return (*host != NULL);
-}
 
index 577df1fc3d8d362f86cfeca78c97b3b5215171e8..072070f723bd5e32d81ae1de9ced01a9346ce27f 100644 (file)
@@ -253,101 +253,4 @@ struct ldap_message {
        struct ldap_Control    *controls;
 };
 
-struct ldap_queue_entry {
-       struct ldap_queue_entry *next, *prev;
-       int msgid;
-       struct ldap_message *msg;
-};
-
-struct ldap_connection {
-       int sock;
-       int next_msgid;
-       char *host;
-       uint16_t port;
-       BOOL ldaps;
-
-       const char *auth_dn;
-       const char *simple_pw;
-
-       /* Current outstanding search entry */
-       int searchid;
-
-       /* List for incoming search entries */
-       struct ldap_queue_entry *search_entries;
-
-       /* Outstanding LDAP requests that have not yet been replied to */
-       struct ldap_queue_entry *outstanding;
-
-       /* Let's support SASL */
-       struct gensec_security *gensec;
-};
-
-#define LDAP_CONNECTION_TIMEOUT 10000
-
-/* The following definitions come from libcli/ldap/ldap.c  */
-
-BOOL ldap_encode(struct ldap_message *msg, DATA_BLOB *result);
-BOOL ldap_decode(struct asn1_data *data, struct ldap_message *msg);
-BOOL ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
-                         char **host, uint16_t *port, BOOL *ldaps);
-
-/* The following definitions come from libcli/ldap/ldap_client.c  */
-
-struct ldap_connection *ldap_connect(TALLOC_CTX *mem_ctx, const char *url);
-struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx);
-BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
-                  const struct timeval *endtime);
-BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
-                     const struct timeval *endtime);
-struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
-                                 const struct timeval *endtime);
-struct ldap_message *ldap_transaction(struct ldap_connection *conn,
-                                     struct ldap_message *request);
-int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password);
-int ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *creds);
-struct ldap_connection *ldap_setup_connection(TALLOC_CTX *mem_ctx, const char *url, 
-                                               const char *userdn, const char *password);
-struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx, const char *url,
-                                                       struct cli_credentials *creds);
-BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
-                                const struct timeval *endtime);
-BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
-                      const struct timeval *endtime);
-struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
-                                      const struct timeval *endtime);
-void ldap_endsearchent(struct ldap_connection *conn,
-                      const struct timeval *endtime);
-struct ldap_message *ldap_searchone(struct ldap_connection *conn,
-                                   struct ldap_message *msg,
-                                   const struct timeval *endtime);
-BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
-                           DATA_BLOB *value);
-BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
-                            TALLOC_CTX *mem_ctx, char **value);
-BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
-                         int *value);
-int ldap_error(struct ldap_connection *conn);
-NTSTATUS ldap2nterror(int ldaperror);
-
-/* The following definitions come from libcli/ldap/ldap_ldif.c  */
-
-BOOL add_value_to_attrib(TALLOC_CTX *mem_ctx, struct ldb_val *value,
-                        struct ldb_message_element *attrib);
-BOOL add_attrib_to_array_talloc(TALLOC_CTX *mem_ctx,
-                                      const struct ldb_message_element *attrib,
-                                      struct ldb_message_element **attribs,
-                                      int *num_attribs);
-BOOL add_mod_to_array_talloc(TALLOC_CTX *mem_ctx,
-                                   struct ldap_mod *mod,
-                                   struct ldap_mod **mods,
-                                   int *num_mods);
-struct ldap_message *ldap_ldif2msg(TALLOC_CTX *mem_ctx, const char *s);
-
-/* The following definitions come from libcli/ldap/ldap_ndr.c  */
-
-const char *ldap_encode_ndr_uint32(TALLOC_CTX *mem_ctx, uint32_t value);
-const char *ldap_encode_ndr_dom_sid(TALLOC_CTX *mem_ctx, struct dom_sid *sid);
-const char *ldap_encode_ndr_GUID(TALLOC_CTX *mem_ctx, struct GUID *guid);
-NTSTATUS ldap_decode_ndr_GUID(TALLOC_CTX *mem_ctx, struct ldb_val val, struct GUID *guid);
-
 #endif
diff --git a/source/libcli/ldap/ldap_bind.c b/source/libcli/ldap/ldap_bind.c
new file mode 100644 (file)
index 0000000..11a6997
--- /dev/null
@@ -0,0 +1,250 @@
+/* 
+   Unix SMB/CIFS mplementation.
+
+   LDAP bind calls
+   
+   Copyright (C) Andrew Tridgell  2005
+   Copyright (C) Volker Lendecke  2004
+    
+   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 2 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, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   
+*/
+
+#include "includes.h"
+#include "libcli/ldap/ldap.h"
+#include "libcli/ldap/ldap_client.h"
+#include "auth/auth.h"
+
+static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *conn, 
+                                                    const char *dn, const char *pw)
+{
+       struct ldap_message *res;
+
+       res = new_ldap_message(conn);
+       if (!res) {
+               return NULL;
+       }
+
+       res->type = LDAP_TAG_BindRequest;
+       res->r.BindRequest.version = 3;
+       res->r.BindRequest.dn = talloc_strdup(res, dn);
+       res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
+       res->r.BindRequest.creds.password = talloc_strdup(res, pw);
+
+       return res;
+}
+
+
+/*
+  perform a simple username/password bind
+*/
+NTSTATUS ldap_bind_simple(struct ldap_connection *conn, 
+                         const char *userdn, const char *password)
+{
+       struct ldap_request *req;
+       struct ldap_message *msg;
+       const char *dn, *pw;
+       NTSTATUS status;
+
+       if (conn == NULL) {
+               return NT_STATUS_INVALID_CONNECTION;
+       }
+
+       if (userdn) {
+               dn = userdn;
+       } else {
+               if (conn->auth_dn) {
+                       dn = conn->auth_dn;
+               } else {
+                       dn = "";
+               }
+       }
+
+       if (password) {
+               pw = password;
+       } else {
+               if (conn->simple_pw) {
+                       pw = conn->simple_pw;
+               } else {
+                       pw = "";
+               }
+       }
+
+       msg = new_ldap_simple_bind_msg(conn, dn, pw);
+       NT_STATUS_HAVE_NO_MEMORY(msg);
+
+       /* send the request */
+       req = ldap_request_send(conn, msg);
+       talloc_free(msg);
+       NT_STATUS_HAVE_NO_MEMORY(req);
+
+       /* wait for replies */
+       status = ldap_request_wait(req);
+       if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(req);
+               return status;
+       }
+
+       /* check its a valid reply */
+       msg = req->replies[0];
+       if (msg->type != LDAP_TAG_BindResponse) {
+               talloc_free(req);
+               return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+       }
+
+       status = ldap_check_response(conn, &msg->r.BindResponse.response);
+
+       talloc_free(req);
+
+       return status;
+}
+
+
+static struct ldap_message *new_ldap_sasl_bind_msg(struct ldap_connection *conn, 
+                                                  const char *sasl_mechanism, 
+                                                  DATA_BLOB *secblob)
+{
+       struct ldap_message *res;
+
+       res = new_ldap_message(conn);
+       if (!res) {
+               return NULL;
+       }
+
+       res->type = LDAP_TAG_BindRequest;
+       res->r.BindRequest.version = 3;
+       res->r.BindRequest.dn = "";
+       res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
+       res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res, sasl_mechanism);
+       res->r.BindRequest.creds.SASL.secblob = *secblob;
+
+       return res;
+}
+
+
+/*
+  perform a sasl bind using the given credentials
+*/
+NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *creds)
+{
+       NTSTATUS status;
+       TALLOC_CTX *tmp_ctx = NULL;
+       DATA_BLOB input = data_blob(NULL, 0);
+       DATA_BLOB output = data_blob(NULL, 0);
+
+       status = gensec_client_start(conn, &conn->gensec);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
+               goto failed;
+       }
+
+       gensec_want_feature(conn->gensec, 0 | GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
+
+       status = gensec_set_credentials(conn->gensec, creds);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to start set GENSEC creds: %s\n", 
+                         nt_errstr(status)));
+               goto failed;
+       }
+
+       status = gensec_set_target_hostname(conn->gensec, conn->host);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
+                         nt_errstr(status)));
+               goto failed;
+       }
+
+       status = gensec_set_target_service(conn->gensec, "ldap");
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to start set GENSEC target service: %s\n", 
+                         nt_errstr(status)));
+               goto failed;
+       }
+
+       status = gensec_start_mech_by_sasl_name(conn->gensec, "NTLM");
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
+                         nt_errstr(status)));
+               goto failed;
+       }
+
+       tmp_ctx = talloc_new(conn);
+       if (tmp_ctx == NULL) goto failed;
+
+       status = gensec_update(conn->gensec, tmp_ctx, input, &output);
+
+       while (1) {
+               struct ldap_message *response;
+               struct ldap_message *msg;
+               struct ldap_request *req;
+               int result = LDAP_OTHER;
+       
+               if (NT_STATUS_IS_OK(status) && output.length == 0) {
+                       break;
+               }
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && 
+                   !NT_STATUS_IS_OK(status)) {
+                       break;
+               }
+
+               msg = new_ldap_sasl_bind_msg(tmp_ctx, "GSS-SPNEGO", &output);
+               if (msg == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto failed;
+               }
+
+               req = ldap_request_send(conn, msg);
+               if (req == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto failed;
+               }
+               talloc_steal(tmp_ctx, req);
+
+               status = ldap_result_n(req, 0, &response);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto failed;
+               }
+               
+               if (response->type != LDAP_TAG_BindResponse) {
+                       status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+                       goto failed;
+               }
+
+               result = response->r.BindResponse.response.resultcode;
+
+               if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
+                       break;
+               }
+
+               status = gensec_update(conn->gensec, tmp_ctx,
+                                      response->r.BindResponse.SASL.secblob,
+                                      &output);
+       }
+
+       if (NT_STATUS_IS_OK(status) &&
+           (gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN) ||
+            gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN))) {
+               conn->enable_wrap = True;
+       }
+
+       talloc_free(tmp_ctx);
+       return status;
+
+failed:
+       talloc_free(tmp_ctx);
+       talloc_free(conn->gensec);
+       conn->gensec = NULL;
+       return status;
+}
index 6ff8db85a5130b7f3686a9e387dd5a9177276d98..f3a7f104d45814b610a225cfcd086b4744d49c48 100644 (file)
 */
 
 #include "includes.h"
-#include "system/network.h"
-#include "system/filesys.h"
-#include "auth/auth.h"
 #include "asn_1.h"
 #include "dlinklist.h"
+#include "lib/events/events.h"
+#include "lib/socket/socket.h"
 #include "libcli/ldap/ldap.h"
+#include "libcli/ldap/ldap_client.h"
 
 
-
-/****************************************************************************
- Check the timeout. 
-****************************************************************************/
-static BOOL timeout_until(struct timeval *timeout,
-                         const struct timeval *endtime)
-{
-       struct timeval now;
-
-       GetTimeOfDay(&now);
-
-       if ((now.tv_sec > endtime->tv_sec) ||
-           ((now.tv_sec == endtime->tv_sec) &&
-            (now.tv_usec > endtime->tv_usec)))
-               return False;
-
-       timeout->tv_sec = endtime->tv_sec - now.tv_sec;
-       timeout->tv_usec = endtime->tv_usec - now.tv_usec;
-       return True;
-}
-
-
-/****************************************************************************
- Read data from the client, reading exactly N bytes, with timeout. 
-****************************************************************************/
-static ssize_t read_data_until(int fd,char *buffer,size_t N,
-                              const struct timeval *endtime)
+/*
+  create a new ldap_connection stucture. The event context is optional
+*/
+struct ldap_connection *ldap_new_connection(TALLOC_CTX *mem_ctx, 
+                                           struct event_context *ev)
 {
-       ssize_t ret;
-       size_t total=0;  
-       while (total < N) {
-
-               if (endtime != NULL) {
-                       fd_set r_fds;
-                       struct timeval timeout;
-                       int res;
-
-                       FD_ZERO(&r_fds);
-                       FD_SET(fd, &r_fds);
-
-                       if (!timeout_until(&timeout, endtime))
-                               return -1;
-
-                       res = sys_select(fd+1, &r_fds, NULL, NULL, &timeout);
-                       if (res <= 0)
-                               return -1;
-               }
-
-               ret = sys_read(fd,buffer + total,N - total);
-
-               if (ret == 0) {
-                       DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", (int)(N - total), strerror(errno) ));
-                       return 0;
-               }
+       struct ldap_connection *conn;
 
-               if (ret == -1) {
-                       DEBUG(0,("read_data: read failure for %d. Error = %s\n", (int)(N - total), strerror(errno) ));
-                       return -1;
-               }
-               total += ret;
+       conn = talloc_zero(mem_ctx, struct ldap_connection);
+       if (conn == NULL) {
+               return NULL;
        }
-       return (ssize_t)total;
-}
-
 
-/****************************************************************************
- Write data to a fd with timeout.
-****************************************************************************/
-static ssize_t write_data_until(int fd,char *buffer,size_t N,
-                               const struct timeval *endtime)
-{
-       size_t total=0;
-       ssize_t ret;
-
-       while (total < N) {
-
-               if (endtime != NULL) {
-                       fd_set w_fds;
-                       struct timeval timeout;
-                       int res;
-
-                       FD_ZERO(&w_fds);
-                       FD_SET(fd, &w_fds);
-
-                       if (!timeout_until(&timeout, endtime))
-                               return -1;
-
-                       res = sys_select(fd+1, NULL, &w_fds, NULL, &timeout);
-                       if (res <= 0)
-                               return -1;
-               }
-
-               ret = sys_write(fd,buffer + total,N - total);
-
-               if (ret == -1) {
-                       DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) ));
-                       return -1;
+       if (ev == NULL) {
+               ev = event_context_init(conn);
+               if (ev == NULL) {
+                       talloc_free(conn);
+                       return NULL;
                }
-               if (ret == 0)
-                       return total;
-
-               total += ret;
        }
-       return (ssize_t)total;
-}
 
+       conn->next_messageid  = 1;
+       conn->event.event_ctx = ev;
 
+       /* set a reasonable request timeout */
+       conn->timeout = 60;
 
-static BOOL read_one_uint8(int sock, uint8_t *result, struct asn1_data *data,
-                          const struct timeval *endtime)
-{
-       if (read_data_until(sock, result, 1, endtime) != 1)
-               return False;
-
-       return asn1_write(data, result, 1);
+       return conn;
 }
 
-/* Read a complete ASN sequence (ie LDAP result) from a socket */
-static BOOL asn1_read_sequence_until(int sock, struct asn1_data *data,
-                                    const struct timeval *endtime)
-{
-       uint8_t b;
-       size_t len;
-       char *buf;
-
-       ZERO_STRUCTP(data);
-
-       if (!read_one_uint8(sock, &b, data, endtime))
-               return False;
 
-       if (b != 0x30) {
-               data->has_error = True;
-               return False;
-       }
+/*
+  the connection is dead
+*/
+static void ldap_connection_dead(struct ldap_connection *conn)
+{
+       struct ldap_request *req;
 
-       if (!read_one_uint8(sock, &b, data, endtime))
-               return False;
-
-       if (b & 0x80) {
-               int n = b & 0x7f;
-               if (!read_one_uint8(sock, &b, data, endtime))
-                       return False;
-               len = b;
-               while (n > 1) {
-                       if (!read_one_uint8(sock, &b, data, endtime))
-                               return False;
-                       len = (len<<8) | b;
-                       n--;
+       while (conn->pending) {
+               req = conn->pending;
+               DLIST_REMOVE(req->conn->pending, req);
+               req->state = LDAP_REQUEST_DONE;
+               req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+               if (req->async.fn) {
+                       req->async.fn(req);
+               }
+       }       
+
+       while (conn->send_queue) {
+               req = conn->send_queue;
+               DLIST_REMOVE(req->conn->send_queue, req);
+               req->state = LDAP_REQUEST_DONE;
+               req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+               if (req->async.fn) {
+                       req->async.fn(req);
                }
-       } else {
-               len = b;
        }
 
-       buf = talloc_size(NULL, len);
-       if (buf == NULL)
-               return False;
-
-       if (read_data_until(sock, buf, len, endtime) != len)
-               return False;
-
-       if (!asn1_write(data, buf, len))
-               return False;
-
-       talloc_free(buf);
-
-       data->ofs = 0;
-       
-       return True;
+       talloc_free(conn->sock);
+       conn->sock = NULL;
 }
 
 
-
-/****************************************************************************
-  create an outgoing socket. timeout is in milliseconds.
-  **************************************************************************/
-static int open_socket_out(int type, struct ipv4_addr *addr, int port, int timeout)
-{
-       struct sockaddr_in sock_out;
-       int res,ret;
-       int connect_loop = 250; /* 250 milliseconds */
-       int loops = (timeout) / connect_loop;
-
-       /* create a socket to write to */
-       res = socket(PF_INET, type, 0);
-       if (res == -1) 
-       { DEBUG(0,("socket error\n")); return -1; }
-       
-       if (type != SOCK_STREAM) return(res);
-       
-       memset((char *)&sock_out,'\0',sizeof(sock_out));
-       sock_out.sin_addr.s_addr = addr->addr;
-       
-       sock_out.sin_port = htons( port );
-       sock_out.sin_family = PF_INET;
-       
-       /* set it non-blocking */
-       set_blocking(res,False);
-       
-       DEBUG(3,("Connecting to %s at port %d\n", sys_inet_ntoa(*addr),port));
-       
-       /* and connect it to the destination */
-connect_again:
-       ret = connect(res,(struct sockaddr *)&sock_out,sizeof(sock_out));
-       
-       /* Some systems return EAGAIN when they mean EINPROGRESS */
-       if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
-                       errno == EAGAIN) && loops--) {
-               msleep(connect_loop);
-               goto connect_again;
-       }
-       
-       if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
-                       errno == EAGAIN)) {
-               DEBUG(1,("timeout connecting to %s:%d\n", sys_inet_ntoa(*addr),port));
-               close(res);
-               return -1;
-       }
-       
-#ifdef EISCONN
-       if (ret < 0 && errno == EISCONN) {
-               errno = 0;
-               ret = 0;
-       }
-#endif
-       
-       if (ret < 0) {
-               DEBUG(2,("error connecting to %s:%d (%s)\n",
-                        sys_inet_ntoa(*addr),port,strerror(errno)));
-               close(res);
-               return -1;
-       }
-       
-       /* set it blocking again */
-       set_blocking(res,True);
-       
-       return res;
-}
-
-#if 0
-static struct ldap_message *new_ldap_search_message(struct ldap_connection *conn,
-                                            const char *base,
-                                            enum ldap_scope scope,
-                                            char *filter,
-                                            int num_attributes,
-                                            const char **attributes)
+/*
+  match up with a pending message, adding to the replies list
+*/
+static void ldap_match_message(struct ldap_connection *conn, struct ldap_message *msg)
 {
-       struct ldap_message *res;
+       struct ldap_request *req;
 
-       res = new_ldap_message(conn);
-       if (!res) {
-               return NULL;
+       for (req=conn->pending; req; req=req->next) {
+               if (req->messageid == msg->messageid) break;
        }
-
-       res->type = LDAP_TAG_SearchRequest;
-       res->r.SearchRequest.basedn = base;
-       res->r.SearchRequest.scope = scope;
-       res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
-       res->r.SearchRequest.timelimit = 0;
-       res->r.SearchRequest.sizelimit = 0;
-       res->r.SearchRequest.attributesonly = False;
-       res->r.SearchRequest.filter = filter;
-       res->r.SearchRequest.num_attributes = num_attributes;
-       res->r.SearchRequest.attributes = attributes;
-
-       return res;
-}
-#endif
-
-static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *conn, const char *dn, const char *pw)
-{
-       struct ldap_message *res;
-
-       res = new_ldap_message(conn);
-       if (!res) {
-               return NULL;
+       if (req == NULL) {
+               DEBUG(0,("ldap: no matching message id for %u\n",
+                        msg->messageid));
+               talloc_free(msg);
+               return;
        }
 
-       res->type = LDAP_TAG_BindRequest;
-       res->r.BindRequest.version = 3;
-       res->r.BindRequest.dn = talloc_strdup(res, dn);
-       res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
-       res->r.BindRequest.creds.password = talloc_strdup(res, pw);
-
-       return res;
-}
-
-static struct ldap_message *new_ldap_sasl_bind_msg(struct ldap_connection *conn, const char *sasl_mechanism, DATA_BLOB *secblob)
-{
-       struct ldap_message *res;
-
-       res = new_ldap_message(conn);
-       if (!res) {
-               return NULL;
+       /* add to the list of replies received */
+       talloc_steal(req, msg);
+       req->replies = talloc_realloc(req, req->replies, 
+                                     struct ldap_message *, req->num_replies+1);
+       if (req->replies == NULL) {
+               req->status = NT_STATUS_NO_MEMORY;
+               req->state = LDAP_REQUEST_DONE;
+               DLIST_REMOVE(conn->pending, req);
+               if (req->async.fn) {
+                       req->async.fn(req);
+               }
+               return;
        }
 
-       res->type = LDAP_TAG_BindRequest;
-       res->r.BindRequest.version = 3;
-       res->r.BindRequest.dn = "";
-       res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
-       res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res, sasl_mechanism);
-       res->r.BindRequest.creds.SASL.secblob = *secblob;
-
-       return res;
-}
-
-static struct ldap_connection *new_ldap_connection(TALLOC_CTX *mem_ctx)
-{
-       struct ldap_connection *result;
+       req->replies[req->num_replies] = talloc_steal(req->replies, msg);
+       req->num_replies++;
 
-       result = talloc(mem_ctx, struct ldap_connection);
-
-       if (!result) {
-               return NULL;
+       if (msg->type != LDAP_TAG_SearchResultEntry) {
+               /* currently only search results expect multiple
+                  replies */
+               req->state = LDAP_REQUEST_DONE;
+               DLIST_REMOVE(conn->pending, req);
        }
 
-       result->next_msgid = 1;
-       result->outstanding = NULL;
-       result->searchid = 0;
-       result->search_entries = NULL;
-       result->auth_dn = NULL;
-       result->simple_pw = NULL;
-       result->gensec = NULL;
-
-       return result;
+       if (req->async.fn) {
+               req->async.fn(req);
+       }
 }
 
-struct ldap_connection *ldap_connect(TALLOC_CTX *mem_ctx, const char *url)
+/*
+  try and decode/process plain data
+*/
+static void ldap_try_decode_plain(struct ldap_connection *conn)
 {
-       struct hostent *hp;
-       struct ipv4_addr ip;
-       struct ldap_connection *conn;
-       BOOL ret;
+       struct asn1_data asn1;
 
-       conn = new_ldap_connection(mem_ctx);
-       if (!conn) {
-               return NULL;
+       if (!asn1_load(&asn1, conn->partial)) {
+               ldap_connection_dead(conn);
+               return;
        }
 
-       ret = ldap_parse_basic_url(conn, url, &conn->host,
-                                  &conn->port, &conn->ldaps);
-       if (!ret) {
-               talloc_free(conn);
-               return NULL;
-       }
+       /* try and decode - this will fail if we don't have a full packet yet */
+       while (asn1.ofs < asn1.length) {
+               struct ldap_message *msg = talloc(conn, struct ldap_message);
+               if (msg == NULL) {
+                       ldap_connection_dead(conn);
+                       return;
+               }
 
-       hp = sys_gethostbyname(conn->host);
-       if (!hp || !hp->h_addr) {
-               talloc_free(conn);
-               return NULL;
+               if (ldap_decode(&asn1, msg)) {
+                       ldap_match_message(conn, msg);
+               } else {
+                       talloc_free(msg);
+                       break;
+               }
        }
 
-       memcpy((char *)&ip, (char *)hp->h_addr, 4);
-
-       conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
-       if (conn->sock < 0) {
-               talloc_free(conn);
-               return NULL;
+       /* keep any remaining data in conn->partial */
+       data_blob_free(&conn->partial);
+       if (asn1.ofs != conn->partial.length) {
+               conn->partial = data_blob_talloc(conn, 
+                                                asn1.data + asn1.ofs, 
+                                                asn1.length - asn1.ofs);
        }
-
-       return conn;
-}
-
-struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
-{
-       return talloc(mem_ctx, struct ldap_message);
-}
-
-BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
-                  const struct timeval *endtime)
-{
-       DATA_BLOB request;
-       BOOL result;
-       struct ldap_queue_entry *entry;
-
-       msg->messageid = conn->next_msgid++;
-
-       if (!ldap_encode(msg, &request))
-               return False;
-
-       result = (write_data_until(conn->sock, request.data, request.length,
-                                  endtime) == request.length);
-
-       data_blob_free(&request);
-
-       if (!result)
-               return result;
-
-       /* abandon and unbind don't expect results */
-
-       if ((msg->type == LDAP_TAG_AbandonRequest) ||
-           (msg->type == LDAP_TAG_UnbindRequest))
-               return True;
-
-       entry = malloc_p(struct ldap_queue_entry);
-
-       if (entry == NULL)
-               return False;
-
-       entry->msgid = msg->messageid;
-       entry->msg = NULL;
-       DLIST_ADD(conn->outstanding, entry);
-
-       return True;
-}
-
-BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
-                     const struct timeval *endtime)
-{
-        struct asn1_data data;
-        BOOL result;
-
-        if (!asn1_read_sequence_until(conn->sock, &data, endtime))
-                return False;
-
-        result = ldap_decode(&data, msg);
-
-        asn1_free(&data);
-        return result;
+       asn1_free(&asn1);
 }
 
-static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
-                                           int msgid)
+/*
+  try and decode/process wrapped data
+*/
+static void ldap_try_decode_wrapped(struct ldap_connection *conn)
 {
-       struct ldap_queue_entry *e;
+       uint32_t len;
 
-       for (e = conn->outstanding; e != NULL; e = e->next) {
+       /* keep decoding while we have a full wrapped packet */
+       while (conn->partial.length >= 4 &&
+              (len=RIVAL(conn->partial.data, 0)) <= conn->partial.length-4) {
+               DATA_BLOB wrapped, unwrapped;
+               struct asn1_data asn1;
+               struct ldap_message *msg = talloc(conn, struct ldap_message);
+               NTSTATUS status;
 
-               if (e->msgid == msgid) {
-                       struct ldap_message *result = e->msg;
-                       DLIST_REMOVE(conn->outstanding, e);
-                       SAFE_FREE(e);
-                       return result;
+               if (msg == NULL) {
+                       ldap_connection_dead(conn);
+                       return;
                }
-       }
 
-       return NULL;
-}
-
-static void add_search_entry(struct ldap_connection *conn,
-                            struct ldap_message *msg)
-{
-       struct ldap_queue_entry *e = malloc_p(struct ldap_queue_entry);
-
-       if (e == NULL)
-               return;
+               wrapped.data   = conn->partial.data+4;
+               wrapped.length = len;
 
-       e->msg = msg;
-       DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
-       return;
-}
-
-static void fill_outstanding_request(struct ldap_connection *conn,
-                                    struct ldap_message *msg)
-{
-       struct ldap_queue_entry *e;
-
-       for (e = conn->outstanding; e != NULL; e = e->next) {
-               if (e->msgid == msg->messageid) {
-                       e->msg = msg;
+               status = gensec_unwrap(conn->gensec, msg, &wrapped, &unwrapped);
+               if (!NT_STATUS_IS_OK(status)) {
+                       ldap_connection_dead(conn);
                        return;
                }
-       }
-
-       /* This reply has not been expected, destroy the incoming msg */
-       talloc_free(msg);
-       return;
-}
-
-struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
-                                 const struct timeval *endtime)
-{
-       struct ldap_message *result = recv_from_queue(conn, msgid);
-
-       if (result != NULL)
-               return result;
 
-       while (True) {
-               struct asn1_data data;
-               BOOL res;
-
-               result = new_ldap_message(conn);
-
-               if (!asn1_read_sequence_until(conn->sock, &data, endtime))
-                       return NULL;
-
-               res = ldap_decode(&data, result);
-               asn1_free(&data);
-
-               if (!res)
-                       return NULL;
+               if (!asn1_load(&asn1, unwrapped)) {
+                       ldap_connection_dead(conn);
+                       return;
+               }
 
-               if (result->messageid == msgid)
-                       return result;
+               if (ldap_decode(&asn1, msg)) {
+                       ldap_match_message(conn, msg);
+               } else {
+                       talloc_free(msg);
+               }
+               
+               asn1_free(&asn1);
 
-               if (result->type == LDAP_TAG_SearchResultEntry) {
-                       add_search_entry(conn, result);
+               if (conn->partial.length == len + 4) {
+                       data_blob_free(&conn->partial);
                } else {
-                       fill_outstanding_request(conn, result);
+                       memmove(conn->partial.data, conn->partial.data+len+4,
+                               conn->partial.length - (len+4));
+                       conn->partial.length -= len + 4;
                }
        }
-
-       return NULL;
 }
 
+
 /*
- Write data to a fd
+  handle ldap recv events
 */
-static ssize_t write_data(int fd, char *buffer, size_t N)
+static void ldap_recv_handler(struct ldap_connection *conn)
 {
-       size_t total=0;
-       ssize_t ret;
+       NTSTATUS status;
+       size_t npending=0, nread;
 
-       while (total < N) {
-               ret = sys_write(fd,buffer + total,N - total);
+       /* work out how much data is pending */
+       status = socket_pending(conn->sock, &npending);
+       if (!NT_STATUS_IS_OK(status) || npending == 0) {
+               DEBUG(0,("ldap_recv_handler - pending=%d - %s\n", 
+                        (int)npending, nt_errstr(status)));
+               return;
+       }
 
-               if (ret == -1) {
-                       DEBUG(0,("write_data: write failure. Error = %s\n", strerror(errno) ));
-                       return -1;
-               }
-               if (ret == 0)
-                       return total;
+       conn->partial.data = talloc_realloc_size(conn, conn->partial.data, 
+                                                conn->partial.length + npending);
+       if (conn->partial.data == NULL) {
+               ldap_connection_dead(conn);
+               return;
+       }
 
-               total += ret;
+       /* receive the pending data */
+       status = socket_recv(conn->sock, conn->partial.data + conn->partial.length,
+                            npending, &nread, 0);
+       if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+               return;
        }
+       if (!NT_STATUS_IS_OK(status)) {
+               ldap_connection_dead(conn);
+               return;
+       }
+       conn->partial.length += nread;
 
-       return (ssize_t)total;
+       /* see if we can decode what we have */
+       if (conn->enable_wrap) {
+               ldap_try_decode_wrapped(conn);
+       } else {
+               ldap_try_decode_plain(conn);
+       }
 }
 
 
 /*
Read data from the client, reading exactly N bytes
 handle ldap send events
 */
-static ssize_t read_data(int fd, char *buffer, size_t N)
+static void ldap_send_handler(struct ldap_connection *conn)
 {
-       ssize_t ret;
-       size_t total=0;  
-       while (total < N) {
+       while (conn->send_queue) {
+               struct ldap_request *req = conn->send_queue;
+               size_t nsent;
+               NTSTATUS status;
 
-               ret = sys_read(fd,buffer + total,N - total);
-
-               if (ret == 0) {
-                       DEBUG(10,("read_data: read of %d returned 0. Error = %s\n", 
-                                 (int)(N - total), strerror(errno) ));
-                       return 0;
+               status = socket_send(conn->sock, &req->data, &nsent, 0);
+               if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+                       break;
                }
-
-               if (ret == -1) {
-                       DEBUG(0,("read_data: read failure for %d. Error = %s\n", 
-                                (int)(N - total), strerror(errno) ));
-                       return -1;
+               if (!NT_STATUS_IS_OK(status)) {
+                       ldap_connection_dead(conn);
+                       return;
                }
-               total += ret;
-       }
-
-       return (ssize_t)total;
-}
-
-static struct ldap_message *ldap_transaction_sasl(struct ldap_connection *conn, struct ldap_message *req)
-{
-       NTSTATUS status;
-       DATA_BLOB request;
-       BOOL result;
-       DATA_BLOB wrapped;
-       int len;
-       char length[4];
-       struct asn1_data asn1;
-       struct ldap_message *rep;
-
-       req->messageid = conn->next_msgid++;
-
-       if (!ldap_encode(req, &request))
-               return NULL;
-
-       status = gensec_wrap(conn->gensec, 
-                            req, 
-                            &request,
-                            &wrapped);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("gensec_wrap: %s\n",nt_errstr(status)));
-               return NULL;
-       }
-
-       RSIVAL(length, 0, wrapped.length);
 
-       result = (write_data(conn->sock, length, 4) == 4);
-       if (!result)
-               return NULL;
-
-       result = (write_data(conn->sock, wrapped.data, wrapped.length) == wrapped.length);
-       if (!result)
-               return NULL;
-
-       wrapped = data_blob(NULL, 0x4000);
-       data_blob_clear(&wrapped);
-
-       result = (read_data(conn->sock, length, 4) == 4);
-       if (!result)
-               return NULL;
-
-       len = RIVAL(length,0);
-
-       result = (read_data(conn->sock, wrapped.data, MIN(wrapped.length,len)) == len);
-       if (!result)
-               return NULL;
-
-       wrapped.length = len;
-
-       status = gensec_unwrap(conn->gensec,
-                              req,
-                              &wrapped,
-                              &request);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0,("gensec_unwrap: %s\n",nt_errstr(status)));
-               return NULL;
+               req->data.data += nsent;
+               req->data.length -= nsent;
+               if (req->data.length == 0) {
+                       req->state = LDAP_REQUEST_PENDING;
+                       DLIST_REMOVE(conn->send_queue, req);
+
+                       /* some types of requests don't expect a reply */
+                       if (req->type == LDAP_TAG_AbandonRequest ||
+                           req->type == LDAP_TAG_UnbindRequest) {
+                               req->status = NT_STATUS_OK;
+                               req->state = LDAP_REQUEST_DONE;
+                               if (req->async.fn) {
+                                       req->async.fn(req);
+                               }
+                       } else {
+                               DLIST_ADD(conn->pending, req);
+                       }
+               }
        }
-
-       rep = new_ldap_message(req);
-
-       asn1_load(&asn1, request);
-       if (!ldap_decode(&asn1, rep)) {
-               return NULL;
+       if (conn->send_queue == NULL) {
+               EVENT_FD_NOT_WRITEABLE(conn->event.fde);
        }
-
-       return rep;
 }
 
-struct ldap_message *ldap_transaction(struct ldap_connection *conn,
-                                     struct ldap_message *request)
+
+/*
+  handle ldap socket events
+*/
+static void ldap_io_handler(struct event_context *ev, struct fd_event *fde, 
+                           uint16_t flags, void *private)
 {
-       if ((request->type != LDAP_TAG_BindRequest) && conn->gensec &&
-           (gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN) ||
-            gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN))) {
-               return ldap_transaction_sasl(conn, request);
+       struct ldap_connection *conn = talloc_get_type(private, struct ldap_connection);
+       if (flags & EVENT_FD_WRITE) {
+               ldap_send_handler(conn);
+               if (conn->sock == NULL) return;
+       }
+       if (flags & EVENT_FD_READ) {
+               ldap_recv_handler(conn);
        }
-
-       if (!ldap_send_msg(conn, request, NULL))
-               return False;
-
-       return ldap_receive(conn, request->messageid, NULL);
 }
 
-int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
+/*
+  parse a ldap URL
+*/
+static NTSTATUS ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
+                                    char **host, uint16_t *port, BOOL *ldaps)
 {
-       struct ldap_message *response;
-       struct ldap_message *msg;
-       const char *dn, *pw;
-       int result = LDAP_OTHER;
+       int tmp_port = 0;
+       char protocol[11];
+       char tmp_host[255];
+       const char *p = url;
+       int ret;
 
-       if (conn == NULL)
-               return result;
+       /* skip leading "URL:" (if any) */
+       if (strncasecmp(p, "URL:", 4) == 0) {
+               p += 4;
+       }
 
-       if (userdn) {
-               dn = userdn;
-       } else {
-               if (conn->auth_dn) {
-                       dn = conn->auth_dn;
-               } else {
-                       dn = "";
-               }
+       /* Paranoia check */
+       SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
+               
+       ret = sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
+       if (ret < 2) {
+               return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if (password) {
-               pw = password;
+       if (strequal(protocol, "ldap")) {
+               *port = 389;
+               *ldaps = False;
+       } else if (strequal(protocol, "ldaps")) {
+               *port = 636;
+               *ldaps = True;
        } else {
-               if (conn->simple_pw) {
-                       pw = conn->simple_pw;
-               } else {
-                       pw = "";
-               }
+               DEBUG(0, ("unrecognised ldap protocol (%s)!\n", protocol));
+               return NT_STATUS_PROTOCOL_UNREACHABLE;
        }
 
-       msg =  new_ldap_simple_bind_msg(conn, dn, pw);
-       if (!msg)
-               return result;
+       if (tmp_port != 0)
+               *port = tmp_port;
 
-       response = ldap_transaction(conn, msg);
-       if (!response) {
-               talloc_free(msg);
-               return result;
-       }
-               
-       result = response->r.BindResponse.response.resultcode;
-
-       talloc_free(msg);
-       talloc_free(response);
+       *host = talloc_strdup(mem_ctx, tmp_host);
+       NT_STATUS_HAVE_NO_MEMORY(*host);
 
-       return result;
+       return NT_STATUS_OK;
 }
 
-int ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *creds)
+/*
+  connect to a ldap server
+*/
+NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
 {
        NTSTATUS status;
-       TALLOC_CTX *mem_ctx = NULL;
-       struct ldap_message *response;
-       struct ldap_message *msg;
-       DATA_BLOB input = data_blob(NULL, 0);
-       DATA_BLOB output = data_blob(NULL, 0);
-       int result = LDAP_OTHER;
 
-       if (conn == NULL)
-               return result;
+       status = ldap_parse_basic_url(conn, url, &conn->host,
+                                     &conn->port, &conn->ldaps);
+       NT_STATUS_NOT_OK_RETURN(status);
 
-       status = gensec_client_start(conn, &conn->gensec);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
-               return result;
-       }
-
-       gensec_want_feature(conn->gensec, 0 | GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
-
-       status = gensec_set_credentials(conn->gensec, creds);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC creds: %s\n", 
-                         nt_errstr(status)));
-               goto done;
-       }
+       status = socket_create("ipv4", SOCKET_TYPE_STREAM, &conn->sock, 0);
+       NT_STATUS_NOT_OK_RETURN(status);
 
-       status = gensec_set_target_hostname(conn->gensec, conn->host);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n", 
-                         nt_errstr(status)));
-               goto done;
-       }
+       talloc_steal(conn, conn->sock);
 
-       status = gensec_set_target_service(conn->gensec, "ldap");
+       /* connect in a event friendly way */
+       status = socket_connect_ev(conn->sock, NULL, 0, conn->host, conn->port, 0, 
+                                  conn->event.event_ctx);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC target service: %s\n", 
-                         nt_errstr(status)));
-               goto done;
+               talloc_free(conn->sock);
+               return status;
        }
 
-       status = gensec_start_mech_by_sasl_name(conn->gensec, "NTLM");
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
-                         nt_errstr(status)));
-               goto done;
+       /* setup a handler for events on this socket */
+       conn->event.fde = event_add_fd(conn->event.event_ctx, conn->sock, 
+                                      socket_get_fd(conn->sock), 
+                                      EVENT_FD_READ, ldap_io_handler, conn);
+       if (conn->event.fde == NULL) {
+               talloc_free(conn->sock);
+               return NT_STATUS_INTERNAL_ERROR;
        }
 
-       mem_ctx = talloc_init("ldap_bind_sasl");
-       if (!mem_ctx)
-               goto done;
-
-       status = gensec_update(conn->gensec, mem_ctx,
-                              input,
-                              &output);
-
-       while(1) {
-               if (NT_STATUS_IS_OK(status) && output.length == 0) {
-                       break;
-               }
-               if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
-                       break;
-               }
-
-               msg =  new_ldap_sasl_bind_msg(conn, "GSS-SPNEGO", &output);
-               if (!msg)
-                       goto done;
-
-               response = ldap_transaction(conn, msg);
-               talloc_free(msg);
-
-               if (!response) {
-                       goto done;
-               }
-
-               result = response->r.BindResponse.response.resultcode;
-
-               if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
-                       break;
-               }
-
-               if (!NT_STATUS_IS_OK(status)) {
-                       status = gensec_update(conn->gensec, mem_ctx,
-                                              response->r.BindResponse.SASL.secblob,
-                                              &output);
-               } else {
-                       output.length = 0;
-               }
-
-               talloc_free(response);
-       }
-
-done:
-       talloc_free(mem_ctx);
-
-       return result;
+       return NT_STATUS_OK;
 }
 
-struct ldap_connection *ldap_setup_connection(TALLOC_CTX *mem_ctx, const char *url, 
-                                               const char *userdn, const char *password)
+/* destroy an open ldap request */
+static int ldap_request_destructor(void *ptr)
 {
-       struct ldap_connection *conn;
-       int result;
-
-       conn =ldap_connect(mem_ctx, url);
-       if (!conn) {
-               return NULL;
+       struct ldap_request *req = talloc_get_type(ptr, struct ldap_request);
+       if (req->state == LDAP_REQUEST_SEND) {
+               DLIST_REMOVE(req->conn->send_queue, req);
        }
-
-       result = ldap_bind_simple(conn, userdn, password);
-       if (result != LDAP_SUCCESS) {
-               talloc_free(conn);
-               return NULL;
+       if (req->state == LDAP_REQUEST_PENDING) {
+               DLIST_REMOVE(req->conn->pending, req);
        }
-
-       return conn;
+       return 0;
 }
 
-struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx, 
-                                                       const char *url,
-                                                       struct cli_credentials *creds)
+/*
+  called on timeout of a ldap request
+*/
+static void ldap_request_timeout(struct event_context *ev, struct timed_event *te, 
+                                     struct timeval t, void *private)
 {
-       struct ldap_connection *conn;
-       int result;
-
-       conn =ldap_connect(mem_ctx, url);
-       if (!conn) {
-               return NULL;
+       struct ldap_request *req = talloc_get_type(private, struct ldap_request);
+       req->status = NT_STATUS_IO_TIMEOUT;
+       if (req->state == LDAP_REQUEST_SEND) {
+               DLIST_REMOVE(req->conn->send_queue, req);
        }
-
-       result = ldap_bind_sasl(conn, creds);
-       if (result != LDAP_SUCCESS) {
-               talloc_free(conn);
-               return NULL;
+       if (req->state == LDAP_REQUEST_PENDING) {
+               DLIST_REMOVE(req->conn->pending, req);
+       }
+       req->state = LDAP_REQUEST_DONE;
+       if (req->async.fn) {
+               req->async.fn(req);
        }
-
-       return conn;
 }
 
-BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
-                                const struct timeval *endtime)
+/*
+  send a ldap message - async interface
+*/
+struct ldap_request *ldap_request_send(struct ldap_connection *conn,
+                                      struct ldap_message *msg)
 {
-       struct ldap_message *msg = new_ldap_message(conn);
-       BOOL result;
+       struct ldap_request *req;
 
-       if (msg == NULL)
-               return False;
+       if (conn->sock == NULL) {
+               return NULL;
+       }
 
-       msg->type = LDAP_TAG_AbandonRequest;
-       msg->r.AbandonRequest.messageid = msgid;
+       req = talloc_zero(conn, struct ldap_request);
+       if (req == NULL) goto failed;
 
-       result = ldap_send_msg(conn, msg, endtime);
-       talloc_free(msg);
-       return result;
-}
+       req->state       = LDAP_REQUEST_SEND;
+       req->conn        = conn;
+       req->messageid   = conn->next_messageid++;
+       req->type        = msg->type;
+       if (req->messageid == -1) {
+               goto failed;
+       }
 
-BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
-                      const struct timeval *endtime)
-{
-       if ((conn->searchid != 0) &&
-           (!ldap_abandon_message(conn, conn->searchid, endtime)))
-               return False;
+       talloc_set_destructor(req, ldap_request_destructor);
 
-       conn->searchid = conn->next_msgid;
-       return ldap_send_msg(conn, msg, endtime);
-}
+       msg->messageid = req->messageid;
 
-struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
-                                      const struct timeval *endtime)
-{
-       struct ldap_message *result;
+       if (!ldap_encode(msg, &req->data)) {
+               goto failed;            
+       }
 
-       if (conn->search_entries != NULL) {
-               struct ldap_queue_entry *e = conn->search_entries;
+       /* possibly encrypt/sign the request */
+       if (conn->enable_wrap) {
+               DATA_BLOB wrapped;
+               NTSTATUS status;
 
-               result = e->msg;
-               DLIST_REMOVE(conn->search_entries, e);
-               SAFE_FREE(e);
-               return result;
+               status = gensec_wrap(conn->gensec, req, &req->data, &wrapped);
+               if (!NT_STATUS_IS_OK(status)) {
+                       goto failed;
+               }
+               data_blob_free(&req->data);
+               req->data = data_blob_talloc(req, NULL, wrapped.length + 4);
+               if (req->data.data == NULL) {
+                       goto failed;
+               }
+               RSIVAL(req->data.data, 0, wrapped.length);
+               memcpy(req->data.data+4, wrapped.data, wrapped.length);
+               data_blob_free(&wrapped);
        }
 
-       result = ldap_receive(conn, conn->searchid, endtime);
-       if (!result) {
-               return NULL;
+
+       if (conn->send_queue == NULL) {
+               EVENT_FD_WRITEABLE(conn->event.fde);
        }
+       DLIST_ADD_END(conn->send_queue, req, struct ldap_request *);
 
-       if (result->type == LDAP_TAG_SearchResultEntry)
-               return result;
+       /* put a timeout on the request */
+       event_add_timed(conn->event.event_ctx, req, 
+                       timeval_current_ofs(conn->timeout, 0),
+                       ldap_request_timeout, req);
 
-       if (result->type == LDAP_TAG_SearchResultDone) {
-               /* TODO: Handle Paged Results */
-               talloc_free(result);
-               return NULL;
-       }
+       return req;
 
-       /* TODO: Handle Search References here */
+failed:
+       talloc_free(req);
        return NULL;
 }
 
-void ldap_endsearchent(struct ldap_connection *conn,
-                      const struct timeval *endtime)
-{
-       struct ldap_queue_entry *e;
-
-       e = conn->search_entries;
 
-       while (e != NULL) {
-               struct ldap_queue_entry *next = e->next;
-               DLIST_REMOVE(conn->search_entries, e);
-               SAFE_FREE(e);
-               e = next;
+/*
+  wait for a request to complete
+  note that this does not destroy the request
+*/
+NTSTATUS ldap_request_wait(struct ldap_request *req)
+{
+       while (req->state != LDAP_REQUEST_DONE) {
+               if (event_loop_once(req->conn->event.event_ctx) != 0) {
+                       req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+                       break;
+               }
        }
+       return req->status;
 }
 
-struct ldap_message *ldap_searchone(struct ldap_connection *conn,
-                                   struct ldap_message *msg,
-                                   const struct timeval *endtime)
-{
-       struct ldap_message *res1, *res2 = NULL;
-       if (!ldap_setsearchent(conn, msg, endtime))
-               return NULL;
-
-       res1 = ldap_getsearchent(conn, endtime);
-
-       if (res1 != NULL)
-               res2 = ldap_getsearchent(conn, endtime);
-
-       ldap_endsearchent(conn, endtime);
-
-       if (res1 == NULL)
-               return NULL;
 
-       if (res2 != NULL) {
-               /* More than one entry */
-               talloc_free(res1);
-               talloc_free(res2);
-               return NULL;
+/*
+  used to setup the status code from a ldap response
+*/
+NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r)
+{
+       if (r->resultcode == LDAP_SUCCESS) {
+               return NT_STATUS_OK;
        }
 
-       return res1;
+       if (conn->last_error) {
+               talloc_free(conn->last_error);
+       }
+       conn->last_error = talloc_asprintf(conn, "LDAP error %u - %s <%s> <%s>", 
+                                          r->resultcode,
+                                          r->dn, r->errormessage, r->referral);
+       
+       return NT_STATUS_LDAP(r->resultcode);
 }
 
-BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
-                           DATA_BLOB *value)
+/*
+  return error string representing the last error
+*/
+const char *ldap_errstr(struct ldap_connection *conn, NTSTATUS status)
 {
-       int i;
-       struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
-
-       if (msg->type != LDAP_TAG_SearchResultEntry)
-               return False;
-
-       for (i=0; i<r->num_attributes; i++) {
-               if (strequal(attr, r->attributes[i].name)) {
-                       if (r->attributes[i].num_values != 1)
-                               return False;
-
-                       *value = r->attributes[i].values[0];
-                       return True;
-               }
+       if (NT_STATUS_IS_LDAP(status) && conn->last_error != NULL) {
+               return conn->last_error;
        }
-       return False;
+       return nt_errstr(status);
 }
 
-BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
-                            TALLOC_CTX *mem_ctx, char **value)
-{
-       DATA_BLOB blob;
-
-       if (!ldap_find_single_value(msg, attr, &blob))
-               return False;
-
-       *value = talloc_size(mem_ctx, blob.length+1);
-
-       if (*value == NULL)
-               return False;
 
-       memcpy(*value, blob.data, blob.length);
-       (*value)[blob.length] = '\0';
-       return True;
-}
-
-BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
-                         int *value)
+/*
+  return the Nth result message, waiting if necessary
+*/
+NTSTATUS ldap_result_n(struct ldap_request *req, int n, struct ldap_message **msg)
 {
-       DATA_BLOB blob;
-       char *val;
-       int errno_save;
-       BOOL res;
-
-       if (!ldap_find_single_value(msg, attr, &blob))
-               return False;
-
-       val = malloc(blob.length+1);
-       if (val == NULL)
-               return False;
+       *msg = NULL;
 
-       memcpy(val, blob.data, blob.length);
-       val[blob.length] = '\0';
-
-       errno_save = errno;
-       errno = 0;
-
-       *value = strtol(val, NULL, 10);
+       while (req->state != LDAP_REQUEST_DONE && n >= req->num_replies) {
+               if (event_loop_once(req->conn->event.event_ctx) != 0) {
+                       return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+               }
+       }
 
-       res = (errno == 0);
+       if (n < req->num_replies) {
+               *msg = req->replies[n];
+               return NT_STATUS_OK;
+       }
 
-       free(val);
-       errno = errno_save;
+       if (!NT_STATUS_IS_OK(req->status)) {
+               return req->status;
+       }
 
-       return res;
+       return NT_STATUS_NO_MORE_ENTRIES;
 }
 
-int ldap_error(struct ldap_connection *conn)
-{
-       return 0;
-}
 
-NTSTATUS ldap2nterror(int ldaperror)
+/*
+  return a single result message, checking if it is of the expected LDAP type
+*/
+NTSTATUS ldap_result_one(struct ldap_request *req, struct ldap_message **msg, int type)
 {
-       return NT_STATUS_OK;
+       NTSTATUS status;
+       status = ldap_result_n(req, 0, msg);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+       if ((*msg)->type != type) {
+               *msg = NULL;
+               return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
+       }
+       return status;
 }
diff --git a/source/libcli/ldap/ldap_client.h b/source/libcli/ldap/ldap_client.h
new file mode 100644 (file)
index 0000000..719c363
--- /dev/null
@@ -0,0 +1,86 @@
+/* 
+   Unix SMB/CIFS Implementation.
+
+   ldap client side header
+
+   Copyright (C) Andrew Tridgell 2005
+    
+   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 2 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, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+enum ldap_request_state {LDAP_REQUEST_SEND, LDAP_REQUEST_PENDING, LDAP_REQUEST_DONE};
+
+/* this is the handle that the caller gets when an async ldap message
+   is sent */
+struct ldap_request {
+       struct ldap_request *next, *prev;
+       struct ldap_connection *conn;
+
+       enum ldap_request_tag type;
+       int messageid;
+       enum ldap_request_state state;
+
+       int num_replies;
+       struct ldap_message **replies;
+
+       NTSTATUS status;
+       DATA_BLOB data;
+       struct {
+               void (*fn)(struct ldap_request *);
+               void *private;
+       } async;
+};
+
+
+/* main context for a ldap client connection */
+struct ldap_connection {
+       struct socket_context *sock;
+       char *host;
+       uint16_t port;
+       BOOL ldaps;
+
+       const char *auth_dn;
+       const char *simple_pw;
+
+       /* next message id to assign */
+       unsigned next_messageid;
+
+       /* outgoing send queue */
+       struct ldap_request *send_queue;
+
+       /* Outstanding LDAP requests that have not yet been replied to */
+       struct ldap_request *pending;
+
+       /* Let's support SASL */
+       struct gensec_security *gensec;
+
+       /* set if we are wrapping requests */
+       BOOL enable_wrap;
+
+       /* partially received packet */
+       DATA_BLOB partial;
+
+       /* the default timeout for messages */
+       int timeout;
+
+       /* last error message */
+       char *last_error;
+
+       struct {
+               struct event_context *event_ctx;
+               struct fd_event *fde;
+       } event;
+};
similarity index 91%
rename from source/libcli/ldap/ldap_ldif.c
rename to source/libcli/ldap/ldap_msg.c
index 55e902ecadea013ece3464d43eb14e19c77b8dae..5ac44a5226526cc6b5983c5cb838ee2ac0760bf4 100644 (file)
@@ -1,11 +1,10 @@
 /* 
    Unix SMB/CIFS mplementation.
+
    LDAP protocol helper functions for SAMBA
    
-   Copyright (C) Andrew Tridgell  2004
+   Copyright (C) Andrew Tridgell  2005
    Copyright (C) Volker Lendecke 2004
-   Copyright (C) Stefan Metzmacher 2004
-   Copyright (C) Simo Sorce 2004
     
    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
 */
 
 #include "includes.h"
-#include "system/iconv.h"
 #include "libcli/ldap/ldap.h"
+#include "libcli/ldap/ldap_client.h"
+
+
+struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
+{
+       return talloc(mem_ctx, struct ldap_message);
+}
+
 
 BOOL add_value_to_attrib(TALLOC_CTX *mem_ctx, struct ldb_val *value,
                         struct ldb_message_element *attrib)
index d727cfe2a9e8f8bdf8ffbd73b6b20427f06da56d..eca47572e36cce85a6a9b93086600de0d4b78bb0 100644 (file)
@@ -648,7 +648,7 @@ static const nt_err_code_struct nt_err_desc[] =
  *****************************************************************************/
 const char *nt_errstr(NTSTATUS nt_code)
 {
-        static pstring msg;
+        static fstring msg;
         int idx = 0;
 
        while (nt_errs[idx].nt_errstr != NULL) {
@@ -659,7 +659,14 @@ const char *nt_errstr(NTSTATUS nt_code)
                idx++;
        }
 
-       slprintf(msg, sizeof(msg), "NT code 0x%08x", NT_STATUS_V(nt_code));
+       if (NT_STATUS_IS_DOS(nt_code)) {
+               slprintf(msg, sizeof(msg), "DOS code %u:%u", 
+                        NT_STATUS_DOS_CLASS(nt_code), NT_STATUS_DOS_CODE(nt_code));
+       } else if (NT_STATUS_IS_LDAP(nt_code)) {
+               slprintf(msg, sizeof(msg), "LDAP code %u", NT_STATUS_LDAP_CODE(nt_code));
+       } else {
+               slprintf(msg, sizeof(msg), "NT code 0x%08x", NT_STATUS_V(nt_code));
+       }
 
         return msg;
 }
index 97837d9ba8decf1f0d7492a304cbdb1e67e6ea18..69b9017d8a586b29e390c57d748c574a41fc5b34 100644 (file)
@@ -24,6 +24,7 @@
 #include "includes.h"
 #include "lib/ldb/include/ldb.h"
 #include "libcli/ldap/ldap.h"
+#include "libcli/ldap/ldap_client.h"
 #include "lib/cmdline/popt_common.h"
 
 static BOOL test_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
@@ -78,12 +79,14 @@ static BOOL test_search_rootDSE(struct ldap_connection *conn, char **basedn)
 {
        BOOL ret = True;
        struct ldap_message *msg, *result;
+       struct ldap_request *req;
+       int i;
+       struct ldap_SearchResEntry *r;
+       NTSTATUS status;
 
        printf("Testing RootDSE Search\n");
 
        *basedn = NULL;
-       conn->searchid = 0;
-       conn->next_msgid = 30;
 
        msg = new_ldap_message(conn);
        if (!msg) {
@@ -101,45 +104,50 @@ static BOOL test_search_rootDSE(struct ldap_connection *conn, char **basedn)
        msg->r.SearchRequest.num_attributes = 0;
        msg->r.SearchRequest.attributes = NULL;
 
-       if (!ldap_setsearchent(conn, msg, NULL)) {
-               printf("Could not setsearchent\n");
+       req = ldap_request_send(conn, msg);
+       if (req == NULL) {
+               printf("Could not setup ldap search\n");
+               return False;
+       }
+
+       status = ldap_result_one(req, &result, LDAP_TAG_SearchResultEntry);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("search failed - %s\n", nt_errstr(status));
                return False;
        }
 
-       result = ldap_getsearchent(conn, NULL);
-       if (result) {
-               int i;
-               struct ldap_SearchResEntry *r = &result->r.SearchResultEntry;
+       printf("received %d replies\n", req->num_replies);
+
+       r = &result->r.SearchResultEntry;
                
-               DEBUG(1,("\tdn: %s\n", r->dn));
-               for (i=0; i<r->num_attributes; i++) {
-                       int j;
-                       for (j=0; j<r->attributes[i].num_values; j++) {
-                               DEBUG(1,("\t%s: %d %.*s\n", r->attributes[i].name,
-                                        r->attributes[i].values[j].length,
-                                        r->attributes[i].values[j].length,
-                                        (char *)r->attributes[i].values[j].data));
-                               if (!(*basedn) && 
-                                   strcasecmp("defaultNamingContext",r->attributes[i].name)==0) {
-                                        *basedn = talloc_asprintf(conn, "%.*s",
-                                        r->attributes[i].values[j].length,
-                                        (char *)r->attributes[i].values[j].data);
-                               }
+       DEBUG(1,("\tdn: %s\n", r->dn));
+       for (i=0; i<r->num_attributes; i++) {
+               int j;
+               for (j=0; j<r->attributes[i].num_values; j++) {
+                       DEBUG(1,("\t%s: %d %.*s\n", r->attributes[i].name,
+                                r->attributes[i].values[j].length,
+                                r->attributes[i].values[j].length,
+                                (char *)r->attributes[i].values[j].data));
+                       if (!(*basedn) && 
+                           strcasecmp("defaultNamingContext",r->attributes[i].name)==0) {
+                               *basedn = talloc_asprintf(conn, "%.*s",
+                                                         r->attributes[i].values[j].length,
+                                                         (char *)r->attributes[i].values[j].data);
                        }
                }
-       } else {
-               ret = False;
        }
 
-       ldap_endsearchent(conn, NULL);
+       talloc_free(req);
 
        return ret;
 }
 
 static BOOL test_compare_sasl(struct ldap_connection *conn, const char *basedn)
 {
-       struct ldap_message *req, *rep;
+       struct ldap_message *msg, *rep;
+       struct ldap_request *req;
        const char *val;
+       NTSTATUS status;
 
        printf("Testing SASL Compare: %s\n", basedn);
 
@@ -147,21 +155,25 @@ static BOOL test_compare_sasl(struct ldap_connection *conn, const char *basedn)
                return False;
        }
 
-       conn->next_msgid = 55;
-
-       req = new_ldap_message(conn);
-       if (!req) {
+       msg = new_ldap_message(conn);
+       if (!msg) {
                return False;
        }
 
-       req->type = LDAP_TAG_CompareRequest;
-       req->r.CompareRequest.dn = basedn;
-       req->r.CompareRequest.attribute = talloc_strdup(req, "objectClass");
+       msg->type = LDAP_TAG_CompareRequest;
+       msg->r.CompareRequest.dn = basedn;
+       msg->r.CompareRequest.attribute = talloc_strdup(msg, "objectClass");
        val = "domain";
-       req->r.CompareRequest.value = data_blob_talloc(req, val, strlen(val));
+       msg->r.CompareRequest.value = data_blob_talloc(msg, val, strlen(val));
+
+       req = ldap_request_send(conn, msg);
+       if (!req) {
+               return False;
+       }
 
-       rep = ldap_transaction(conn, req);
-       if (!rep) {
+       status = ldap_result_one(req, &rep, LDAP_TAG_CompareResponse);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("error in ldap compare request - %s\n", nt_errstr(status));
                return False;
        }
 
@@ -171,13 +183,10 @@ static BOOL test_compare_sasl(struct ldap_connection *conn, const char *basedn)
                rep->r.CompareResponse.errormessage,
                rep->r.CompareResponse.referral));
 
-       if (rep->type != LDAP_TAG_CompareResponse) {
-               return False;
-       }
-
        return True;
 }
 
+
 BOOL torture_ldap_basic(void)
 {
         NTSTATUS status;
@@ -186,7 +195,6 @@ BOOL torture_ldap_basic(void)
        BOOL ret = True;
        const char *host = lp_parm_string(-1, "torture", "host");
        const char *userdn = lp_parm_string(-1, "torture", "ldap_userdn");
-       /*const char *basedn = lp_parm_string(-1, "torture", "ldap_basedn");*/
        const char *secret = lp_parm_string(-1, "torture", "ldap_secret");
        char *url;
        char *basedn;
@@ -195,18 +203,18 @@ BOOL torture_ldap_basic(void)
 
        url = talloc_asprintf(mem_ctx, "ldap://%s/", host);
 
-       status = torture_ldap_connection2(mem_ctx, &conn, url, userdn, secret);
+       status = torture_ldap_connection(mem_ctx, &conn, url);
        if (!NT_STATUS_IS_OK(status)) {
                return False;
        }
 
-       /* other basic tests here */
-
-       if (!test_multibind(conn, userdn, secret)) {
+       if (!test_search_rootDSE(conn, &basedn)) {
                ret = False;
        }
 
-       if (!test_search_rootDSE(conn, &basedn)) {
+       /* other basic tests here */
+
+       if (!test_multibind(conn, userdn, secret)) {
                ret = False;
        }
 
@@ -219,10 +227,9 @@ BOOL torture_ldap_basic(void)
        }
 
        /* no more test we are closing */
-
+        torture_ldap_close(conn);
        talloc_free(mem_ctx);
 
-        torture_ldap_close(conn);
 
        return ret;
 }
index a65d24804c43c909a38054feb7524cc2eaa8740a..f5b2a1254d7e4cc9a68a6cc3b43710e3e0fbe84b 100644 (file)
 
 NTSTATUS torture_ldap_bind(struct ldap_connection *conn, const char *userdn, const char *password)
 {
-        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-       int result;
+       NTSTATUS status;
 
-       if (!conn) {
-               printf("We need a valid ldap_connection structure and be connected\n");
-               return status;
+       status = ldap_bind_simple(conn, userdn, password);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("Failed to bind with provided credentials - %s\n", 
+                      nt_errstr(status));
        }
 
-       result = ldap_bind_simple(conn, userdn, password);
-       if (result != LDAP_SUCCESS) {
-               printf("Failed to bind with provided credentials\n");
-               /* FIXME: what abut actually implementing an ldap_connection_free() function ?
-                         :-) sss */
-               return status;
-       }
-       return NT_STATUS_OK;
+       return status;
 }
 
 NTSTATUS torture_ldap_bind_sasl(struct ldap_connection *conn, 
                                struct cli_credentials *creds)
 {
-        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-       int result;
-
-       if (!conn) {
-               printf("We need a valid ldap_connection structure and be connected\n");
-               return status;
-       }
+        NTSTATUS status;
 
-       result = ldap_bind_sasl(conn, creds);
-       if (result != LDAP_SUCCESS) {
-               printf("Failed to bind with provided credentials and SASL mechanism\n");
-               /* FIXME: what abut actually implementing an ldap_connection_free() function ?
-                         :-) sss */
-               return status;
+       status = ldap_bind_sasl(conn, creds);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("Failed sasl bind with provided credentials - %s\n", 
+                      nt_errstr(status));
        }
  
-       return NT_STATUS_OK;
+       return status;
 }
 
 /* open a ldap connection to a server */
 NTSTATUS torture_ldap_connection(TALLOC_CTX *mem_ctx, struct ldap_connection **conn, 
                                const char *url)
 {
-        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+       NTSTATUS status;
 
        if (!url) {
                printf("You must specify a url string\n");
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       *conn = ldap_connect(mem_ctx, url);
-       if (!*conn) {
-               printf("Failed to initialize ldap_connection structure\n");
-               return status;
+       *conn = ldap_new_connection(mem_ctx, NULL);
+
+       status = ldap_connect(*conn, url);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("Failed to connect to ldap server '%s' - %s\n",
+                      url, nt_errstr(status));
        }
 
-       return NT_STATUS_OK;
+       return status;
 }
 
 /* open a ldap connection to a server */
 NTSTATUS torture_ldap_connection2(TALLOC_CTX *mem_ctx, struct ldap_connection **conn, 
                                const char *url, const char *userdn, const char *password)
 {
-        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
-       int ret;
+        NTSTATUS status;
 
        status = torture_ldap_connection(mem_ctx, conn, url);
        NT_STATUS_NOT_OK_RETURN(status);
 
-       ret = ldap_bind_simple(*conn, userdn, password);
-       if (ret != LDAP_SUCCESS) {
-               printf("Failed to connect with url [%s]\n", url);
-               /* FIXME: what abut actually implementing an ldap_connection_free() function ?
-                         :-) sss */
-               return status;
+       status = ldap_bind_simple(*conn, userdn, password);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("Failed a simple ldap bind - %s\n", ldap_errstr(*conn, status));
        }
  
-       return NT_STATUS_OK;
+       return status;
 }
 
 /* close an ldap connection to a server */
 NTSTATUS torture_ldap_close(struct ldap_connection *conn)
 {
-       /* FIXME: what about actually implementing ldap_close() ?
-                 :-) sss */
+       talloc_free(conn);
        return NT_STATUS_OK;
 }