tevent_abort_nesting crash in idmap_ad

Volker Lendecke vl at samba.org
Fri Jun 24 15:15:45 UTC 2016


On Fri, Jun 24, 2016 at 04:33:12PM +0200, Ralph Boehme wrote:
> Just came across the following while running selftests that involve
> idmap_ad on a member server testenv:
> 
> idmap_ad calls into tldap which calls into gensec where it runs a
> nested tevent loop, SBT attached.
> 
> For now I added a hack to allow nested tevent loops to
> tldap_gensec_bind(), this fixes the issue.

Please find a better patch attached. It's a pity, but it's inevitable.

Review&Push appreciated!

Volker
-------------- next part --------------
>From d7703befc8271092a3ca4e5b2a8029699c5c0b70 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 24 Jun 2016 17:07:33 +0200
Subject: [PATCH 1/2] Revert "winbind: Base idmap_ad on tldap"

This reverts commit a9b6276fbf51aba7478319f785ff3e0c9d60b6fe.

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/winbindd/idmap_ad.c    | 1059 +++++++++++++++-------------------------
 source3/winbindd/wscript_build |    2 +-
 2 files changed, 406 insertions(+), 655 deletions(-)

diff --git a/source3/winbindd/idmap_ad.c b/source3/winbindd/idmap_ad.c
index 242b788..8f15ecb 100644
--- a/source3/winbindd/idmap_ad.c
+++ b/source3/winbindd/idmap_ad.c
@@ -1,7 +1,15 @@
 /*
- * idmap_ad: map between Active Directory and RFC 2307 accounts
+ *  idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts
  *
- * Copyright (C) Volker Lendecke 2015
+ * Unix SMB/CIFS implementation.
+ *
+ * Winbind ADS backend functions
+ *
+ * Copyright (C) Andrew Tridgell 2001
+ * Copyright (C) Andrew Bartlett <abartlet at samba.org> 2003
+ * Copyright (C) Gerald (Jerry) Carter 2004-2007
+ * Copyright (C) Luke Howard 2001-2004
+ * Copyright (C) Michael Adam 2008,2010
  *
  * 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
@@ -19,739 +27,480 @@
 
 #include "includes.h"
 #include "winbindd.h"
-#include "idmap.h"
-#include "tldap_gensec_bind.h"
-#include "tldap_util.h"
-#include "lib/param/param.h"
-#include "utils/net.h"
-#include "auth/gensec/gensec.h"
-#include "librpc/gen_ndr/ndr_netlogon.h"
-#include "libads/ldap_schema_oids.h"
 #include "../libds/common/flags.h"
-#include "libcli/ldap/ldap_ndr.h"
-#include "libcli/security/dom_sid.h"
-
-struct idmap_ad_schema_names;
-
-struct idmap_ad_context {
-	struct idmap_domain *dom;
-	struct tldap_context *ld;
-	struct idmap_ad_schema_names *schema;
-	const char *default_nc;
-};
-
-static char *get_schema_path(TALLOC_CTX *mem_ctx, struct tldap_context *ld)
-{
-	struct tldap_message *rootdse;
-
-	rootdse = tldap_rootdse(ld);
-	if (rootdse == NULL) {
-		return NULL;
-	}
-
-	return tldap_talloc_single_attribute(rootdse, "schemaNamingContext",
-					     mem_ctx);
-}
+#include "ads.h"
+#include "libads/ldap_schema.h"
+#include "nss_info.h"
+#include "idmap.h"
+#include "../libcli/ldap/ldap_ndr.h"
+#include "../libcli/security/security.h"
 
-static char *get_default_nc(TALLOC_CTX *mem_ctx, struct tldap_context *ld)
-{
-	struct tldap_message *rootdse;
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_IDMAP
 
-	rootdse = tldap_rootdse(ld);
-	if (rootdse == NULL) {
-		return NULL;
-	}
+#define CHECK_ALLOC_DONE(mem) do { \
+     if (!mem) { \
+           DEBUG(0, ("Out of memory!\n")); \
+           ret = NT_STATUS_NO_MEMORY; \
+           goto done; \
+      } \
+} while (0)
 
-	return tldap_talloc_single_attribute(rootdse, "defaultNamingContext",
-					     mem_ctx);
-}
-
-struct idmap_ad_schema_names {
-	char *name;
-	char *uid;
-	char *gid;
-	char *gecos;
-	char *dir;
-	char *shell;
+struct idmap_ad_context {
+	ADS_STRUCT *ads;
+	struct posix_schema *ad_schema;
+	enum wb_posix_mapping ad_map_type; /* WB_POSIX_MAP_UNKNOWN */
 };
 
-static TLDAPRC get_attrnames_by_oids(struct tldap_context *ld,
-				     TALLOC_CTX *mem_ctx,
-				     const char *schema_path,
-				     size_t num_oids,
-				     const char **oids,
-				     char **names)
-{
-	char *filter;
-	const char *attrs[] = { "lDAPDisplayName", "attributeId" };
-	size_t i;
-	TLDAPRC rc;
-	struct tldap_message **msgs;
-	size_t num_msgs;
-
-	filter = talloc_strdup(mem_ctx, "(|");
-	if (filter == NULL) {
-		return TLDAP_NO_MEMORY;
-	}
-
-	for (i=0; i<num_oids; i++) {
-		filter = talloc_asprintf_append_buffer(
-			filter, "(attributeId=%s)", oids[i]);
-		if (filter == NULL) {
-			return TLDAP_NO_MEMORY;
-		}
-	}
-
-	filter = talloc_asprintf_append_buffer(filter, ")");
-	if (filter == NULL) {
-		return TLDAP_NO_MEMORY;
-	}
-
-	rc = tldap_search(ld, schema_path, TLDAP_SCOPE_SUB, filter,
-			  attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
-			  0, 0, 0, mem_ctx, &msgs);;
-	TALLOC_FREE(filter);
-	if (!TLDAP_RC_IS_SUCCESS(rc)) {
-		return rc;
-	}
-
-	for (i=0; i<num_oids; i++) {
-		names[i] = NULL;
-	}
-
-	num_msgs = talloc_array_length(msgs);
-
-	for (i=0; i<num_msgs; i++) {
-		struct tldap_message *msg = msgs[i];
-		char *oid;
-		size_t j;
-
-		if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
-			/* Could be a TLDAP_RES_SEARCH_REFERENCE */
-			continue;
-		}
-
-		oid = tldap_talloc_single_attribute(
-			msg, "attributeId", msg);
-		if (oid == NULL) {
-			continue;
-		}
-
-		for (j=0; j<num_oids; j++) {
-			if (strequal(oid, oids[j])) {
-				break;
-			}
-		}
-		TALLOC_FREE(oid);
-
-		if (j == num_oids) {
-			/* not found */
-			continue;
-		}
-
-		names[j] = tldap_talloc_single_attribute(
-			msg, "lDAPDisplayName", mem_ctx);
-	}
-
-	TALLOC_FREE(msgs);
-
-	return TLDAP_SUCCESS;
-}
-
-static TLDAPRC get_posix_schema_names(struct tldap_context *ld,
-				      const char *schema_mode,
-				      TALLOC_CTX *mem_ctx,
-				      struct idmap_ad_schema_names **pschema)
-{
-	char *schema_path;
-	struct idmap_ad_schema_names *schema;
-	char *names[6];
-	const char *oids_sfu[] = {
-		ADS_ATTR_SFU_UIDNUMBER_OID,
-		ADS_ATTR_SFU_GIDNUMBER_OID,
-		ADS_ATTR_SFU_HOMEDIR_OID,
-		ADS_ATTR_SFU_SHELL_OID,
-		ADS_ATTR_SFU_GECOS_OID,
-		ADS_ATTR_SFU_UID_OID
-	};
-	const char *oids_sfu20[] = {
-		ADS_ATTR_SFU20_UIDNUMBER_OID,
-		ADS_ATTR_SFU20_GIDNUMBER_OID,
-		ADS_ATTR_SFU20_HOMEDIR_OID,
-		ADS_ATTR_SFU20_SHELL_OID,
-		ADS_ATTR_SFU20_GECOS_OID,
-		ADS_ATTR_SFU20_UID_OID
-	};
-	const char *oids_rfc2307[] = {
-		ADS_ATTR_RFC2307_UIDNUMBER_OID,
-		ADS_ATTR_RFC2307_GIDNUMBER_OID,
-		ADS_ATTR_RFC2307_HOMEDIR_OID,
-		ADS_ATTR_RFC2307_SHELL_OID,
-		ADS_ATTR_RFC2307_GECOS_OID,
-		ADS_ATTR_RFC2307_UID_OID
-	};
-	const char **oids;
-
-	TLDAPRC rc;
-
-	schema = talloc(mem_ctx, struct idmap_ad_schema_names);
-	if (schema == NULL) {
-		return TLDAP_NO_MEMORY;
-	}
-
-	schema_path = get_schema_path(schema, ld);
-	if (schema_path == NULL) {
-		TALLOC_FREE(schema);
-		return TLDAP_NO_MEMORY;
-	}
-
-	oids = oids_rfc2307;
-
-	if ((schema_mode != NULL) && (schema_mode[0] != '\0')) {
-		if (strequal(schema_mode, "sfu")) {
-			oids = oids_sfu;
-		} else if (strequal(schema_mode, "sfu20")) {
-			oids = oids_sfu20;
-		} else if (strequal(schema_mode, "rfc2307" )) {
-			oids = oids_rfc2307;
-		} else {
-			DBG_WARNING("Unknown schema mode %s\n", schema_mode);
-		}
-	}
-
-	rc = get_attrnames_by_oids(ld, schema, schema_path, 6, oids, names);
-	TALLOC_FREE(schema_path);
-	if (!TLDAP_RC_IS_SUCCESS(rc)) {
-		TALLOC_FREE(schema);
-		return rc;
-	}
-
-	schema->uid = names[0];
-	schema->gid = names[1];
-	schema->dir = names[2];
-	schema->shell = names[3];
-	schema->gecos = names[4];
-	schema->name = names[5];
-
-	*pschema = schema;
-
-	return TLDAP_SUCCESS;
-}
+/************************************************************************
+ ***********************************************************************/
 
-static NTSTATUS idmap_ad_get_tldap_ctx(TALLOC_CTX *mem_ctx,
-				       const char *domname,
-				       struct tldap_context **pld)
+static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom)
 {
-	struct netr_DsRGetDCNameInfo *dcinfo;
-	struct sockaddr_storage dcaddr;
-	struct cli_credentials *creds;
-	struct loadparm_context *lp_ctx;
-	struct tldap_context *ld;
-	int fd;
-	NTSTATUS status;
-	bool ok;
-	TLDAPRC rc;
-
-	status = wb_dsgetdcname_gencache_get(mem_ctx, domname, &dcinfo);
-	if (!NT_STATUS_IS_OK(status)) {
-		DBG_DEBUG("Could not get dcinfo for %s: %s\n", domname,
-			  nt_errstr(status));
-		return status;
-	}
+	ADS_STATUS status;
+	struct idmap_ad_context * ctx;
 
-	if (dcinfo->dc_unc == NULL) {
-		TALLOC_FREE(dcinfo);
-		return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
-	}
-	if (dcinfo->dc_unc[0] == '\\') {
-		dcinfo->dc_unc += 1;
-	}
-	if (dcinfo->dc_unc[0] == '\\') {
-		dcinfo->dc_unc += 1;
-	}
+	DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
+		   dom->name));
 
-	ok = resolve_name(dcinfo->dc_unc, &dcaddr, 0x20, true);
-	if (!ok) {
-		DBG_DEBUG("Could not resolve name %s\n", dcinfo->dc_unc);
-		TALLOC_FREE(dcinfo);
-		return NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
-	}
+	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
 
-	status = open_socket_out(&dcaddr, 389, 10000, &fd);
-	if (!NT_STATUS_IS_OK(status)) {
-		DBG_DEBUG("open_socket_out failed: %s\n", nt_errstr(status));
-		TALLOC_FREE(dcinfo);
+	status = ads_idmap_cached_connection(&ctx->ads, dom->name);
+	if (!ADS_ERR_OK(status)) {
 		return status;
 	}
 
-	ld = tldap_context_create(dcinfo, fd);
-	if (ld == NULL) {
-		DBG_DEBUG("tldap_context_create failed\n");
-		close(fd);
-		TALLOC_FREE(dcinfo);
-		return NT_STATUS_NO_MEMORY;
-	}
+	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
 
-	creds = cli_credentials_init(dcinfo);
-	if (creds == NULL) {
-		DBG_DEBUG("cli_credentials_init failed\n");
-		TALLOC_FREE(dcinfo);
-		return NT_STATUS_NO_MEMORY;
-	}
+	/* if we have a valid ADS_STRUCT and the schema model is
+	   defined, then we can return here. */
 
-	lp_ctx = loadparm_init_s3(dcinfo, loadparm_s3_helpers());
-	if (lp_ctx == NULL) {
-		DBG_DEBUG("loadparm_init_s3 failed\n");
-		TALLOC_FREE(dcinfo);
-		return NT_STATUS_NO_MEMORY;
+	if ( ctx->ad_schema ) {
+		return ADS_SUCCESS;
 	}
 
-	cli_credentials_set_conf(creds, lp_ctx);
+	/* Otherwise, set the schema model */
 
-	status = cli_credentials_set_machine_account(creds, lp_ctx);
-	if (!NT_STATUS_IS_OK(status)) {
-		DBG_DEBUG("cli_credentials_set_machine_account "
-			  "failed: %s\n", nt_errstr(status));
-		TALLOC_FREE(dcinfo);
-		return status;
-	}
-
-	rc = tldap_gensec_bind(ld, creds, "ldap", dcinfo->dc_unc, NULL, lp_ctx,
-			       GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
-	if (!TLDAP_RC_IS_SUCCESS(rc)) {
-		DBG_DEBUG("tldap_gensec_bind failed: %s\n",
-			  tldap_errstr(dcinfo, ld, rc));
-		TALLOC_FREE(dcinfo);
-		return NT_STATUS_LDAP(TLDAP_RC_V(rc));
-	}
-
-	rc = tldap_fetch_rootdse(ld);
-	if (!TLDAP_RC_IS_SUCCESS(rc)) {
-		DBG_DEBUG("tldap_fetch_rootdse failed: %s\n",
-			  tldap_errstr(dcinfo, ld, rc));
-		TALLOC_FREE(dcinfo);
-		return NT_STATUS_LDAP(TLDAP_RC_V(rc));
+	if ( (ctx->ad_map_type ==  WB_POSIX_MAP_SFU) ||
+	     (ctx->ad_map_type ==  WB_POSIX_MAP_SFU20) ||
+	     (ctx->ad_map_type ==  WB_POSIX_MAP_RFC2307) )
+	{
+		status = ads_check_posix_schema_mapping(
+			ctx, ctx->ads, ctx->ad_map_type, &ctx->ad_schema);
+		if ( !ADS_ERR_OK(status) ) {
+			DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
+		}
 	}
 
-	*pld = talloc_move(mem_ctx, &ld);
-	TALLOC_FREE(dcinfo);
-	return NT_STATUS_OK;
+	return status;
 }
 
 static int idmap_ad_context_destructor(struct idmap_ad_context *ctx)
 {
-	if ((ctx->dom != NULL) && (ctx->dom->private_data == ctx)) {
-		ctx->dom->private_data = NULL;
+	if (ctx->ads != NULL) {
+		/* we own this ADS_STRUCT so make sure it goes away */
+		ctx->ads->is_mine = True;
+		ads_destroy( &ctx->ads );
+		ctx->ads = NULL;
 	}
 	return 0;
 }
 
-static NTSTATUS idmap_ad_context_create(TALLOC_CTX *mem_ctx,
-					struct idmap_domain *dom,
-					const char *domname,
-					struct idmap_ad_context **pctx)
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom)
 {
 	struct idmap_ad_context *ctx;
-	char *schema_config_option;
-	const char *schema_mode;
-	NTSTATUS status;
-	TLDAPRC rc;
+	char *config_option;
+	const char *schema_mode = NULL;	
 
-	ctx = talloc(mem_ctx, struct idmap_ad_context);
+	ctx = talloc_zero(dom, struct idmap_ad_context);
 	if (ctx == NULL) {
+		DEBUG(0, ("Out of memory!\n"));
 		return NT_STATUS_NO_MEMORY;
 	}
-	ctx->dom = dom;
-
 	talloc_set_destructor(ctx, idmap_ad_context_destructor);
 
-	status = idmap_ad_get_tldap_ctx(ctx, domname, &ctx->ld);
-	if (!NT_STATUS_IS_OK(status)) {
-		DBG_DEBUG("idmap_ad_get_tldap_ctx failed: %s\n",
-			  nt_errstr(status));
-		TALLOC_FREE(ctx);
-		return status;
-	}
-
-	ctx->default_nc = get_default_nc(ctx, ctx->ld);
-	if (ctx->default_nc == NULL) {
-		DBG_DEBUG("No default nc\n");
-		TALLOC_FREE(ctx);
-		return status;
-	}
-
-	schema_config_option = talloc_asprintf(
-		ctx, "idmap config %s", domname);
-	if (schema_config_option == NULL) {
-		TALLOC_FREE(ctx);
+	config_option = talloc_asprintf(ctx, "idmap config %s", dom->name);
+	if (config_option == NULL) {
+		DEBUG(0, ("Out of memory!\n"));
+		talloc_free(ctx);
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	schema_mode = lp_parm_const_string(
-		-1, schema_config_option, "schema_mode", "rfc2307");
-	TALLOC_FREE(schema_config_option);
+	/* default map type */
+	ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
 
-	rc = get_posix_schema_names(ctx->ld, schema_mode, ctx, &ctx->schema);
-	if (!TLDAP_RC_IS_SUCCESS(rc)) {
-		DBG_DEBUG("get_posix_schema_names failed: %s\n",
-			  tldap_errstr(ctx, ctx->ld, rc));
-		TALLOC_FREE(ctx);
-		return NT_STATUS_LDAP(TLDAP_RC_V(rc));
+	/* schema mode */
+	schema_mode = lp_parm_const_string(-1, config_option, "schema_mode", NULL);
+	if ( schema_mode && schema_mode[0] ) {
+		if ( strequal(schema_mode, "sfu") )
+			ctx->ad_map_type = WB_POSIX_MAP_SFU;
+		else if ( strequal(schema_mode, "sfu20" ) )
+			ctx->ad_map_type = WB_POSIX_MAP_SFU20;
+		else if ( strequal(schema_mode, "rfc2307" ) )
+			ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
+		else
+			DEBUG(0,("idmap_ad_initialize: Unknown schema_mode (%s)\n",
+				 schema_mode));
 	}
 
-	*pctx = ctx;
-	return NT_STATUS_OK;
-}
-
-static NTSTATUS idmap_ad_initialize(struct idmap_domain *dom)
-{
-	dom->private_data = NULL;
-	return NT_STATUS_OK;
-}
-
-static NTSTATUS idmap_ad_get_context(struct idmap_domain *dom,
-				     struct idmap_ad_context **pctx)
-{
-	struct idmap_ad_context *ctx = NULL;
-	NTSTATUS status;
-
-	if (dom->private_data != NULL) {
-		*pctx = talloc_get_type_abort(dom->private_data,
-					      struct idmap_ad_context);
-		return NT_STATUS_OK;
-	}
+	dom->private_data = ctx;
 
-	status = idmap_ad_context_create(dom, dom, dom->name, &ctx);
-	if (!NT_STATUS_IS_OK(status)) {
-		DBG_DEBUG("idmap_ad_context_create failed: %s\n",
-			  nt_errstr(status));
-		return status;
-	}
+	talloc_free(config_option);
 
-	dom->private_data = ctx;
-	*pctx = ctx;
 	return NT_STATUS_OK;
 }
 
-static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom,
-					 struct id_map **ids)
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS idmap_ad_unixids_to_sids(struct idmap_domain *dom, struct id_map **ids)
 {
+	NTSTATUS ret;
+	TALLOC_CTX *memctx;
 	struct idmap_ad_context *ctx;
-	TLDAPRC rc;
-	NTSTATUS status;
-	struct tldap_message **msgs;
-
-	size_t i, num_msgs;
-	char *u_filter, *g_filter, *filter;
-
-	const char *attrs[] = {
-		"sAMAccountType",
-		"objectSid",
-		NULL, /* attr_uidnumber */
-		NULL, /* attr_gidnumber */
-	};
-
-	status = idmap_ad_get_context(dom, &ctx);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	ADS_STATUS rc;
+	const char *attrs[] = { "sAMAccountType", 
+				"objectSid",
+				NULL, /* uidnumber */
+				NULL, /* gidnumber */
+				NULL };
+	LDAPMessage *res = NULL;
+	LDAPMessage *entry = NULL;
+	char *filter = NULL;
+	int idx = 0;
+	int bidx = 0;
+	int count;
+	int i;
+	char *u_filter = NULL;
+	char *g_filter = NULL;
+
+	/* initialize the status to avoid suprise */
+	for (i = 0; ids[i]; i++) {
+		ids[i]->status = ID_UNKNOWN;
 	}
 
-	attrs[2] = ctx->schema->uid;
-	attrs[3] = ctx->schema->gid;
-
-	u_filter = talloc_strdup(talloc_tos(), "");
-	if (u_filter == NULL) {
-		return NT_STATUS_NO_MEMORY;
+	/* Only do query if we are online */
+	if (idmap_is_offline())	{
+		return NT_STATUS_FILE_IS_OFFLINE;
 	}
 
-	g_filter = talloc_strdup(talloc_tos(), "");
-	if (g_filter == NULL) {
+	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
+
+	if ( (memctx = talloc_new(ctx)) == NULL ) {
+		DEBUG(0, ("Out of memory!\n"));
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	for (i=0; ids[i] != NULL; i++) {
-		struct id_map *id = ids[i];
-
-		id->status = ID_UNKNOWN;
-
-		switch (id->xid.type) {
-		    case ID_TYPE_UID: {
-			    u_filter = talloc_asprintf_append_buffer(
-				    u_filter, "(%s=%ju)", ctx->schema->uid,
-				    (uintmax_t)id->xid.id);
-			    if (u_filter == NULL) {
-				    return NT_STATUS_NO_MEMORY;
-			    }
-			    break;
-		    }
-
-		    case ID_TYPE_GID: {
-			    g_filter = talloc_asprintf_append_buffer(
-				    g_filter, "(%s=%ju)", ctx->schema->gid,
-				    (uintmax_t)id->xid.id);
-			    if (g_filter == NULL) {
-				    return NT_STATUS_NO_MEMORY;
-			    }
-			    break;
-		    }
-
-		    default:
-			    DBG_WARNING("Unknown id type: %u\n",
-					(unsigned)id->xid.type);
-			    break;
-		}
-	}
+	rc = ad_idmap_cached_connection(dom);
+	if (!ADS_ERR_OK(rc)) {
+		DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
+		ret = NT_STATUS_UNSUCCESSFUL;
+		/* ret = ads_ntstatus(rc); */
+		goto done;
+	}
+
+	attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
+	attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
+
+again:
+	bidx = idx;
+	for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
+		switch (ids[idx]->xid.type) {
+		case ID_TYPE_UID:     
+			if ( ! u_filter) {
+				u_filter = talloc_asprintf(memctx, "(&(|"
+							   "(sAMAccountType=%d)"
+							   "(sAMAccountType=%d)"
+							   "(sAMAccountType=%d))(|",
+							   ATYPE_NORMAL_ACCOUNT,
+							   ATYPE_WORKSTATION_TRUST,
+							   ATYPE_INTERDOMAIN_TRUST);
+			}
+			u_filter = talloc_asprintf_append_buffer(u_filter, "(%s=%lu)",
+							  ctx->ad_schema->posix_uidnumber_attr,
+							  (unsigned long)ids[idx]->xid.id);
+			CHECK_ALLOC_DONE(u_filter);
+			break;
 
-	filter = talloc_strdup(talloc_tos(), "(|");
-	if (filter == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
+		case ID_TYPE_GID:
+			if ( ! g_filter) {
+				g_filter = talloc_asprintf(memctx, "(&(|"
+							   "(sAMAccountType=%d)"
+							   "(sAMAccountType=%d))(|",
+							   ATYPE_SECURITY_GLOBAL_GROUP,
+							   ATYPE_SECURITY_LOCAL_GROUP);
+			}
+			g_filter = talloc_asprintf_append_buffer(g_filter, "(%s=%lu)",
+							  ctx->ad_schema->posix_gidnumber_attr,
+							  (unsigned long)ids[idx]->xid.id);
+			CHECK_ALLOC_DONE(g_filter);
+			break;
 
-	if (*u_filter != '\0') {
-		filter = talloc_asprintf_append_buffer(
-			filter,
-			"(&(|(sAMAccountType=%d)(sAMAccountType=%d)"
-			"(sAMAccountType=%d))(|%s))",
-			ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST,
-			ATYPE_INTERDOMAIN_TRUST, u_filter);
-		if (filter == NULL) {
-			return NT_STATUS_NO_MEMORY;
+		default:
+			DEBUG(3, ("Error: mapping requested but Unknown ID type\n"));
+			ids[idx]->status = ID_UNKNOWN;
+			continue;
 		}
 	}
-	TALLOC_FREE(u_filter);
-
-	if (*g_filter != '\0') {
-		filter = talloc_asprintf_append_buffer(
-			filter,
-			"(&(|(sAMAccountType=%d)(sAMAccountType=%d))(|%s))",
-			ATYPE_SECURITY_GLOBAL_GROUP,
-			ATYPE_SECURITY_LOCAL_GROUP,
-			g_filter);
-		if (filter == NULL) {
-			return NT_STATUS_NO_MEMORY;
-		}
+	filter = talloc_asprintf(memctx, "(|");
+	CHECK_ALLOC_DONE(filter);
+	if ( u_filter) {
+		filter = talloc_asprintf_append_buffer(filter, "%s))", u_filter);
+		CHECK_ALLOC_DONE(filter);
+			TALLOC_FREE(u_filter);
 	}
-	TALLOC_FREE(g_filter);
-
-	filter = talloc_asprintf_append_buffer(filter, ")");
-	if (filter == NULL) {
-		return NT_STATUS_NO_MEMORY;
+	if ( g_filter) {
+		filter = talloc_asprintf_append_buffer(filter, "%s))", g_filter);
+		CHECK_ALLOC_DONE(filter);
+		TALLOC_FREE(g_filter);
 	}
+	filter = talloc_asprintf_append_buffer(filter, ")");
+	CHECK_ALLOC_DONE(filter);
 
-	DBG_DEBUG("Filter: [%s]\n", filter);
-
-	rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter,
-			  attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
-			  0, 0, 0, talloc_tos(), &msgs);
-	if (!TLDAP_RC_IS_SUCCESS(rc)) {
-		return NT_STATUS_LDAP(TLDAP_RC_V(rc));
+	rc = ads_search_retry(ctx->ads, &res, filter, attrs);
+	if (!ADS_ERR_OK(rc)) {
+		DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
+		ret = NT_STATUS_UNSUCCESSFUL;
+		goto done;
 	}
 
-	TALLOC_FREE(filter);
-
-	num_msgs = talloc_array_length(msgs);
+	if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
+		DEBUG(10, ("No IDs found\n"));
+	}
 
-	for (i=0; i<num_msgs; i++) {
-		struct tldap_message *msg = msgs[i];
-		char *dn;
-		struct id_map *map;
+	entry = res;
+	for (i = 0; (i < count) && entry; i++) {
 		struct dom_sid sid;
-		size_t j;
-		bool ok;
-		uint32_t atype, xid;
 		enum id_type type;
+		struct id_map *map;
+		uint32_t id;
+		uint32_t atype;
 
-		if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
-			continue;
+		if (i == 0) { /* first entry */
+			entry = ads_first_entry(ctx->ads, entry);
+		} else { /* following ones */
+			entry = ads_next_entry(ctx->ads, entry);
 		}
 
-		ok = tldap_entry_dn(msg, &dn);
-		if (!ok) {
-			DBG_DEBUG("No dn found in msg %zu\n", i);
+		if ( !entry ) {
+			DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
+			break;
+		}
+
+		/* first check if the SID is present */
+		if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
+			DEBUG(2, ("Could not retrieve SID from entry\n"));
 			continue;
 		}
 
-		ok = tldap_pull_uint32(msg, "sAMAccountType", &atype);
-		if (!ok) {
-			DBG_DEBUG("No atype in object %s\n", dn);
+		/* get type */
+		if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
+			DEBUG(1, ("could not get SAM account type\n"));
 			continue;
 		}
 
 		switch (atype & 0xF0000000) {
-		    case ATYPE_SECURITY_GLOBAL_GROUP:
-		    case ATYPE_SECURITY_LOCAL_GROUP:
-			    type = ID_TYPE_GID;
-			    break;
-		    case ATYPE_NORMAL_ACCOUNT:
-		    case ATYPE_WORKSTATION_TRUST:
-		    case ATYPE_INTERDOMAIN_TRUST:
-			    type = ID_TYPE_UID;
-			    break;
-		    default:
-			    DBG_WARNING("unrecognized SAM account type %08x\n",
-					atype);
+		case ATYPE_SECURITY_GLOBAL_GROUP:
+		case ATYPE_SECURITY_LOCAL_GROUP:
+			type = ID_TYPE_GID;
+			break;
+		case ATYPE_NORMAL_ACCOUNT:
+		case ATYPE_WORKSTATION_TRUST:
+		case ATYPE_INTERDOMAIN_TRUST:
+			type = ID_TYPE_UID;
+			break;
+		default:
+			DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
 			continue;
 		}
 
-		ok = tldap_pull_uint32(msg, (type == ID_TYPE_UID) ?
-				       ctx->schema->uid : ctx->schema->gid,
-				       &xid);
-		if (!ok) {
-			DBG_WARNING("No unix id in object %s\n", dn);
+		if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
+				                 ctx->ad_schema->posix_uidnumber_attr :
+				                 ctx->ad_schema->posix_gidnumber_attr,
+				     &id)) 
+		{
+			DEBUG(1, ("Could not get unix ID for SID %s\n",
+				  dom_sid_string(talloc_tos(), &sid)));
 			continue;
 		}
 
-		ok = tldap_pull_binsid(msg, "objectSid", &sid);
-		if (!ok) {
-			DBG_DEBUG("No objectSid in object %s\n", dn);
+		if (!idmap_unix_id_is_in_range(id, dom)) {
+			DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
+				id, dom->low_id, dom->high_id));
 			continue;
 		}
 
-		map = NULL;
-		for (j=0; ids[j]; j++) {
-			if ((type == ids[j]->xid.type) &&
-			    (xid == ids[j]->xid.id)) {
-				map = ids[j];
-				break;
-			}
-		}
-		if (map == NULL) {
-			DBG_DEBUG("Got unexpected sid %s from object %s\n",
-				  sid_string_tos(&sid), dn);
+		map = idmap_find_map_by_id(&ids[bidx], type, id);
+		if (!map) {
+			DEBUG(2, ("WARNING: couldn't match result with requested ID\n"));
 			continue;
 		}
 
 		sid_copy(map->sid, &sid);
+
+		/* mapped */
 		map->status = ID_MAPPED;
 
-		DBG_DEBUG("Mapped %s -> %ju (%d)\n", sid_string_dbg(map->sid),
-			  (uintmax_t)map->xid.id, map->xid.type);
+		DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
+			   (unsigned long)map->xid.id,
+			   map->xid.type));
+	}
+
+	if (res) {
+		ads_msgfree(ctx->ads, res);
 	}
 
-	TALLOC_FREE(msgs);
+	if (ids[idx]) { /* still some values to map */
+		goto again;
+	}
 
-	return NT_STATUS_OK;
+	ret = NT_STATUS_OK;
+
+	/* mark all unknown/expired ones as unmapped */
+	for (i = 0; ids[i]; i++) {
+		if (ids[i]->status != ID_MAPPED) 
+			ids[i]->status = ID_UNMAPPED;
+	}
+
+done:
+	talloc_free(memctx);
+	return ret;
 }
 
-static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom,
-					 struct id_map **ids)
+/************************************************************************
+ ***********************************************************************/
+
+static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom, struct id_map **ids)
 {
+	NTSTATUS ret;
+	TALLOC_CTX *memctx;
 	struct idmap_ad_context *ctx;
-	TLDAPRC rc;
-	NTSTATUS status;
-	struct tldap_message **msgs;
-
-	char *filter;
-	size_t i, num_msgs;
-
-	const char *attrs[] = {
-		"sAMAccountType",
-		"objectSid",
-		NULL, /* attr_uidnumber */
-		NULL, /* attr_gidnumber */
-	};
-
-	status = idmap_ad_get_context(dom, &ctx);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	ADS_STATUS rc;
+	const char *attrs[] = { "sAMAccountType", 
+				"objectSid",
+				NULL, /* attr_uidnumber */
+				NULL, /* attr_gidnumber */
+				NULL };
+	LDAPMessage *res = NULL;
+	LDAPMessage *entry = NULL;
+	char *filter = NULL;
+	int idx = 0;
+	int bidx = 0;
+	int count;
+	int i;
+	char *sidstr;
+
+	/* initialize the status to avoid suprise */
+	for (i = 0; ids[i]; i++) {
+		ids[i]->status = ID_UNKNOWN;
 	}
 
-	attrs[2] = ctx->schema->uid;
-	attrs[3] = ctx->schema->gid;
+	/* Only do query if we are online */
+	if (idmap_is_offline())	{
+		return NT_STATUS_FILE_IS_OFFLINE;
+	}
 
-	filter = talloc_asprintf(
-		talloc_tos(),
-		"(&(|(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)"
-		"(sAMAccountType=%d)(sAMAccountType=%d))(|",
-		ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST,
-		ATYPE_INTERDOMAIN_TRUST, ATYPE_SECURITY_GLOBAL_GROUP,
-		ATYPE_SECURITY_LOCAL_GROUP);
-	if (filter == NULL) {
+	ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);	
+
+	if ( (memctx = talloc_new(ctx)) == NULL ) {		
+		DEBUG(0, ("Out of memory!\n"));
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	for (i=0; ids[i]; i++) {
-		char *sidstr;
+	rc = ad_idmap_cached_connection(dom);
+	if (!ADS_ERR_OK(rc)) {
+		DEBUG(1, ("ADS uninitialized: %s\n", ads_errstr(rc)));
+		ret = NT_STATUS_UNSUCCESSFUL;
+		/* ret = ads_ntstatus(rc); */
+		goto done;
+	}
 
-		ids[i]->status = ID_UNKNOWN;
+	if (ctx->ad_schema == NULL) {
+		DEBUG(0, ("haven't got ctx->ad_schema ! \n"));
+		ret = NT_STATUS_UNSUCCESSFUL;
+		goto done;
+	}
 
-		sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), ids[i]->sid);
-		if (sidstr == NULL) {
-			return NT_STATUS_NO_MEMORY;
-		}
+	attrs[2] = ctx->ad_schema->posix_uidnumber_attr;
+	attrs[3] = ctx->ad_schema->posix_gidnumber_attr;
 
-		filter = talloc_asprintf_append_buffer(
-			filter, "(objectSid=%s)", sidstr);
-		TALLOC_FREE(sidstr);
-		if (filter == NULL) {
-			return NT_STATUS_NO_MEMORY;
-		}
-	}
+again:
+	filter = talloc_asprintf(memctx, "(&(|"
+				 "(sAMAccountType=%d)(sAMAccountType=%d)(sAMAccountType=%d)" /* user account types */
+				 "(sAMAccountType=%d)(sAMAccountType=%d)" /* group account types */
+				 ")(|",
+				 ATYPE_NORMAL_ACCOUNT, ATYPE_WORKSTATION_TRUST, ATYPE_INTERDOMAIN_TRUST,
+				 ATYPE_SECURITY_GLOBAL_GROUP, ATYPE_SECURITY_LOCAL_GROUP);
 
-	filter = talloc_asprintf_append_buffer(filter, "))");
-	if (filter == NULL) {
-		return NT_STATUS_NO_MEMORY;
-	}
+	CHECK_ALLOC_DONE(filter);
+
+	bidx = idx;
+	for (i = 0; (i < IDMAP_LDAP_MAX_IDS) && ids[idx]; i++, idx++) {
 
-	DBG_DEBUG("Filter: [%s]\n", filter);
+		ids[idx]->status = ID_UNKNOWN;
 
-	rc = tldap_search(ctx->ld, ctx->default_nc, TLDAP_SCOPE_SUB, filter,
-			  attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0,
-			  0, 0, 0, talloc_tos(), &msgs);
-	if (!TLDAP_RC_IS_SUCCESS(rc)) {
-		return NT_STATUS_LDAP(TLDAP_RC_V(rc));
+		sidstr = ldap_encode_ndr_dom_sid(talloc_tos(), ids[idx]->sid);
+		filter = talloc_asprintf_append_buffer(filter, "(objectSid=%s)", sidstr);
+
+		TALLOC_FREE(sidstr);
+		CHECK_ALLOC_DONE(filter);
 	}
+	filter = talloc_asprintf_append_buffer(filter, "))");
+	CHECK_ALLOC_DONE(filter);
+	DEBUG(10, ("Filter: [%s]\n", filter));
 
-	TALLOC_FREE(filter);
+	rc = ads_search_retry(ctx->ads, &res, filter, attrs);
+	if (!ADS_ERR_OK(rc)) {
+		DEBUG(1, ("ERROR: ads search returned: %s\n", ads_errstr(rc)));
+		ret = NT_STATUS_UNSUCCESSFUL;
+		goto done;
+	}
 
-	num_msgs = talloc_array_length(msgs);
+	if ( (count = ads_count_replies(ctx->ads, res)) == 0 ) {
+		DEBUG(10, ("No IDs found\n"));
+	}
 
-	for (i=0; i<num_msgs; i++) {
-		struct tldap_message *msg = msgs[i];
-		char *dn;
-		struct id_map *map;
+	entry = res;	
+	for (i = 0; (i < count) && entry; i++) {
 		struct dom_sid sid;
-		size_t j;
-		bool ok;
-		uint64_t account_type, xid;
 		enum id_type type;
+		struct id_map *map;
+		uint32_t id;
+		uint32_t atype;
 
-		if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
-			continue;
+		if (i == 0) { /* first entry */
+			entry = ads_first_entry(ctx->ads, entry);
+		} else { /* following ones */
+			entry = ads_next_entry(ctx->ads, entry);
 		}
 
-		ok = tldap_entry_dn(msg, &dn);
-		if (!ok) {
-			DBG_DEBUG("No dn found in msg %zu\n", i);
-			continue;
+		if ( !entry ) {
+			DEBUG(2, ("ERROR: Unable to fetch ldap entries from results\n"));
+			break;
 		}
 
-		ok = tldap_pull_binsid(msg, "objectSid", &sid);
-		if (!ok) {
-			DBG_DEBUG("No objectSid in object %s\n", dn);
+		/* first check if the SID is present */
+		if (!ads_pull_sid(ctx->ads, entry, "objectSid", &sid)) {
+			DEBUG(2, ("Could not retrieve SID from entry\n"));
 			continue;
 		}
 
-		map = NULL;
-		for (j=0; ids[j]; j++) {
-			if (dom_sid_equal(&sid, ids[j]->sid)) {
-				map = ids[j];
-				break;
-			}
-		}
-		if (map == NULL) {
-			DBG_DEBUG("Got unexpected sid %s from object %s\n",
-				  sid_string_tos(&sid), dn);
+		map = idmap_find_map_by_sid(&ids[bidx], &sid);
+		if (!map) {
+			DEBUG(2, ("WARNING: couldn't match result with requested SID\n"));
 			continue;
 		}
 
-		ok = tldap_pull_uint64(msg, "sAMAccountType", &account_type);
-		if (!ok) {
-			DBG_DEBUG("No sAMAccountType in %s\n", dn);
+		/* get type */
+		if (!ads_pull_uint32(ctx->ads, entry, "sAMAccountType", &atype)) {
+			DEBUG(1, ("could not get SAM account type\n"));
 			continue;
 		}
 
-		switch (account_type & 0xF0000000) {
+		switch (atype & 0xF0000000) {
 		case ATYPE_SECURITY_GLOBAL_GROUP:
 		case ATYPE_SECURITY_LOCAL_GROUP:
 			type = ID_TYPE_GID;
@@ -762,89 +511,91 @@ static NTSTATUS idmap_ad_sids_to_unixids(struct idmap_domain *dom,
 			type = ID_TYPE_UID;
 			break;
 		default:
-			DBG_WARNING("unrecognized SAM account type %"PRIu64"\n",
-				    account_type);
+			DEBUG(1, ("unrecognized SAM account type %08x\n", atype));
 			continue;
 		}
 
-		ok = tldap_pull_uint64(msg,
-				       type == ID_TYPE_UID ?
-				       ctx->schema->uid : ctx->schema->gid,
-				       &xid);
-		if (!ok) {
-			DBG_DEBUG("No xid in %s\n", dn);
+		if (!ads_pull_uint32(ctx->ads, entry, (type==ID_TYPE_UID) ?
+				                 ctx->ad_schema->posix_uidnumber_attr :
+				                 ctx->ad_schema->posix_gidnumber_attr,
+				     &id)) 
+		{
+			DEBUG(1, ("Could not get unix ID for SID %s\n",
+				sid_string_dbg(map->sid)));
+			continue;
+		}
+		if (!idmap_unix_id_is_in_range(id, dom)) {
+			DEBUG(5, ("Requested id (%u) out of range (%u - %u). Filtered!\n",
+				id, dom->low_id, dom->high_id));
 			continue;
 		}
 
 		/* mapped */
 		map->xid.type = type;
-		map->xid.id = xid;
+		map->xid.id = id;
 		map->status = ID_MAPPED;
 
 		DEBUG(10, ("Mapped %s -> %lu (%d)\n", sid_string_dbg(map->sid),
-			   (unsigned long)map->xid.id, map->xid.type));
+			   (unsigned long)map->xid.id,
+			   map->xid.type));
 	}
 
-	TALLOC_FREE(msgs);
-
-	return NT_STATUS_OK;
-}
-
-static NTSTATUS idmap_ad_unixids_to_sids_retry(struct idmap_domain *dom,
-					       struct id_map **ids)
-{
-	const NTSTATUS status_server_down =
-		NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN));
-	NTSTATUS status;
-
-	status = idmap_ad_unixids_to_sids(dom, ids);
-
-	if (NT_STATUS_EQUAL(status, status_server_down)) {
-		TALLOC_FREE(dom->private_data);
-		status = idmap_ad_unixids_to_sids(dom, ids);
+	if (res) {
+		ads_msgfree(ctx->ads, res);
 	}
 
-	return status;
-}
-
-static NTSTATUS idmap_ad_sids_to_unixids_retry(struct idmap_domain *dom,
-					       struct id_map **ids)
-{
-	const NTSTATUS status_server_down =
-		NT_STATUS_LDAP(TLDAP_RC_V(TLDAP_SERVER_DOWN));
-	NTSTATUS status;
+	if (ids[idx]) { /* still some values to map */
+		goto again;
+	}
 
-	status = idmap_ad_sids_to_unixids(dom, ids);
+	ret = NT_STATUS_OK;
 
-	if (NT_STATUS_EQUAL(status, status_server_down)) {
-		TALLOC_FREE(dom->private_data);
-		status = idmap_ad_sids_to_unixids(dom, ids);
+	/* mark all unknown/expired ones as unmapped */
+	for (i = 0; ids[i]; i++) {
+		if (ids[i]->status != ID_MAPPED) 
+			ids[i]->status = ID_UNMAPPED;
 	}
 
-	return status;
+done:
+	talloc_free(memctx);
+	return ret;
 }
 
+/************************************************************************
+ Function dispatch tables for the idmap and nss plugins
+ ***********************************************************************/
+
 static struct idmap_methods ad_methods = {
 	.init            = idmap_ad_initialize,
-	.unixids_to_sids = idmap_ad_unixids_to_sids_retry,
-	.sids_to_unixids = idmap_ad_sids_to_unixids_retry,
+	.unixids_to_sids = idmap_ad_unixids_to_sids,
+	.sids_to_unixids = idmap_ad_sids_to_unixids,
 };
 
+/************************************************************************
+ Initialize the plugins
+ ***********************************************************************/
+
 static_decl_idmap;
 NTSTATUS idmap_ad_init(void)
 {
-	NTSTATUS status;
+	static NTSTATUS status_idmap_ad = NT_STATUS_UNSUCCESSFUL;
+	static NTSTATUS status_ad_nss = NT_STATUS_UNSUCCESSFUL;
 
-	status = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION,
-				    "ad", &ad_methods);
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	/* Always register the AD method first in order to get the
+	   idmap_domain interface called */
+
+	if ( !NT_STATUS_IS_OK(status_idmap_ad) ) {
+		status_idmap_ad = smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, 
+						     "ad", &ad_methods);
+		if ( !NT_STATUS_IS_OK(status_idmap_ad) )
+			return status_idmap_ad;		
 	}
 
-	status = idmap_ad_nss_init();
-	if (!NT_STATUS_IS_OK(status)) {
-		return status;
+	if ( !NT_STATUS_IS_OK( status_ad_nss ) ) {
+		status_ad_nss = idmap_ad_nss_init();
+		if ( !NT_STATUS_IS_OK(status_ad_nss) )
+			return status_ad_nss;
 	}
 
-	return NT_STATUS_OK;
+	return NT_STATUS_OK;	
 }
diff --git a/source3/winbindd/wscript_build b/source3/winbindd/wscript_build
index 1a2c497..eab788f 100644
--- a/source3/winbindd/wscript_build
+++ b/source3/winbindd/wscript_build
@@ -28,7 +28,7 @@ bld.SAMBA3_MODULE('idmap_ad',
                  subsystem='idmap',
                  allow_undefined_symbols=True,
                  source='',
-                 deps='IDMAP_AD TLDAP LIBNMB',
+                 deps='IDMAP_AD',
                  init_function='',
                  internal_module=bld.SAMBA3_IS_STATIC_MODULE('idmap_ad'),
                  enabled=bld.SAMBA3_IS_ENABLED_MODULE('idmap_ad'))
-- 
1.9.1


>From 8881d4ec291e6fee126884cb87c17f8620e64bd7 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl at samba.org>
Date: Fri, 24 Jun 2016 17:12:24 +0200
Subject: [PATCH 2/2] lib: Remove tldap

Signed-off-by: Volker Lendecke <vl at samba.org>
---
 source3/include/tldap.h      |  309 -----
 source3/include/tldap_util.h |  104 --
 source3/lib/tldap.c          | 2668 ------------------------------------------
 source3/lib/tldap_util.c     |  832 -------------
 source3/torture/torture.c    |  108 --
 source3/wscript_build        |    8 -
 6 files changed, 4029 deletions(-)
 delete mode 100644 source3/include/tldap.h
 delete mode 100644 source3/include/tldap_util.h
 delete mode 100644 source3/lib/tldap.c
 delete mode 100644 source3/lib/tldap_util.c

diff --git a/source3/include/tldap.h b/source3/include/tldap.h
deleted file mode 100644
index 74279a4..0000000
--- a/source3/include/tldap.h
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
-   Unix SMB/CIFS implementation.
-   Infrastructure for async ldap client requests
-   Copyright (C) Volker Lendecke 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/>.
-*/
-
-#ifndef __TLDAP_H__
-#define __TLDAP_H__
-
-#include "replace.h"
-#include <talloc.h>
-#include <tevent.h>
-#include "lib/util/data_blob.h"
-
-struct tldap_context;
-struct tldap_message;
-
-struct tldap_control {
-	const char *oid;
-	DATA_BLOB value;
-	bool critical;
-};
-
-struct tldap_attribute {
-	char *name;
-	int num_values;
-	DATA_BLOB *values;
-};
-
-struct tldap_mod {
-	int mod_op;
-	char *attribute;
-	int num_values;
-	DATA_BLOB *values;
-};
-
-typedef struct { uint8_t rc; } TLDAPRC;
-#define TLDAP_RC(x) ((TLDAPRC){.rc = x})
-#define TLDAP_RC_V(x) ((x).rc)
-
-#define TLDAP_RC_EQUAL(x,y) (TLDAP_RC_V(x)==TLDAP_RC_V(y))
-#define TLDAP_RC_IS_SUCCESS(x) TLDAP_RC_EQUAL(x,TLDAP_SUCCESS)
-
-#define TLDAP_SUCCESS TLDAP_RC(0x00)
-#define TLDAP_OPERATIONS_ERROR TLDAP_RC(0x01)
-#define TLDAP_PROTOCOL_ERROR TLDAP_RC(0x02)
-#define TLDAP_TIMELIMIT_EXCEEDED TLDAP_RC(0x03)
-#define TLDAP_SIZELIMIT_EXCEEDED TLDAP_RC(0x04)
-#define TLDAP_COMPARE_FALSE TLDAP_RC(0x05)
-#define TLDAP_COMPARE_TRUE TLDAP_RC(0x06)
-#define TLDAP_STRONG_AUTH_NOT_SUPPORTED TLDAP_RC(0x07)
-#define TLDAP_STRONG_AUTH_REQUIRED TLDAP_RC(0x08)
-#define TLDAP_REFERRAL TLDAP_RC(0x0a)
-#define TLDAP_ADMINLIMIT_EXCEEDED TLDAP_RC(0x0b)
-#define TLDAP_UNAVAILABLE_CRITICAL_EXTENSION TLDAP_RC(0x0c)
-#define TLDAP_CONFIDENTIALITY_REQUIRED TLDAP_RC(0x0d)
-#define TLDAP_SASL_BIND_IN_PROGRESS TLDAP_RC(0x0e)
-#define TLDAP_NO_SUCH_ATTRIBUTE TLDAP_RC(0x10)
-#define TLDAP_UNDEFINED_TYPE TLDAP_RC(0x11)
-#define TLDAP_INAPPROPRIATE_MATCHING TLDAP_RC(0x12)
-#define TLDAP_CONSTRAINT_VIOLATION TLDAP_RC(0x13)
-#define TLDAP_TYPE_OR_VALUE_EXISTS TLDAP_RC(0x14)
-#define TLDAP_INVALID_SYNTAX TLDAP_RC(0x15)
-#define TLDAP_NO_SUCH_OBJECT TLDAP_RC(0x20)
-#define TLDAP_ALIAS_PROBLEM TLDAP_RC(0x21)
-#define TLDAP_INVALID_DN_SYNTAX TLDAP_RC(0x22)
-#define TLDAP_IS_LEAF TLDAP_RC(0x23)
-#define TLDAP_ALIAS_DEREF_PROBLEM TLDAP_RC(0x24)
-#define TLDAP_INAPPROPRIATE_AUTH TLDAP_RC(0x30)
-#define TLDAP_INVALID_CREDENTIALS TLDAP_RC(0x31)
-#define TLDAP_INSUFFICIENT_ACCESS TLDAP_RC(0x32)
-#define TLDAP_BUSY TLDAP_RC(0x33)
-#define TLDAP_UNAVAILABLE TLDAP_RC(0x34)
-#define TLDAP_UNWILLING_TO_PERFORM TLDAP_RC(0x35)
-#define TLDAP_LOOP_DETECT TLDAP_RC(0x36)
-#define TLDAP_NAMING_VIOLATION TLDAP_RC(0x40)
-#define TLDAP_OBJECT_CLASS_VIOLATION TLDAP_RC(0x41)
-#define TLDAP_NOT_ALLOWED_ON_NONLEAF TLDAP_RC(0x42)
-#define TLDAP_NOT_ALLOWED_ON_RDN TLDAP_RC(0x43)
-#define TLDAP_ALREADY_EXISTS TLDAP_RC(0x44)
-#define TLDAP_NO_OBJECT_CLASS_MODS TLDAP_RC(0x45)
-#define TLDAP_RESULTS_TOO_LARGE TLDAP_RC(0x46)
-#define TLDAP_AFFECTS_MULTIPLE_DSAS TLDAP_RC(0x47)
-#define TLDAP_OTHER TLDAP_RC(0x50)
-#define TLDAP_SERVER_DOWN TLDAP_RC(0x51)
-#define TLDAP_LOCAL_ERROR TLDAP_RC(0x52)
-#define TLDAP_ENCODING_ERROR TLDAP_RC(0x53)
-#define TLDAP_DECODING_ERROR TLDAP_RC(0x54)
-#define TLDAP_TIMEOUT TLDAP_RC(0x55)
-#define TLDAP_AUTH_UNKNOWN TLDAP_RC(0x56)
-#define TLDAP_FILTER_ERROR TLDAP_RC(0x57)
-#define TLDAP_USER_CANCELLED TLDAP_RC(0x58)
-#define TLDAP_PARAM_ERROR TLDAP_RC(0x59)
-#define TLDAP_NO_MEMORY TLDAP_RC(0x5a)
-#define TLDAP_CONNECT_ERROR TLDAP_RC(0x5b)
-#define TLDAP_NOT_SUPPORTED TLDAP_RC(0x5c)
-#define TLDAP_CONTROL_NOT_FOUND TLDAP_RC(0x5d)
-#define TLDAP_NO_RESULTS_RETURNED TLDAP_RC(0x5e)
-#define TLDAP_MORE_RESULTS_TO_RETURN TLDAP_RC(0x5f)
-#define TLDAP_CLIENT_LOOP TLDAP_RC(0x60)
-#define TLDAP_REFERRAL_LIMIT_EXCEEDED TLDAP_RC(0x61)
-
-bool tevent_req_ldap_error(struct tevent_req *req, TLDAPRC rc);
-bool tevent_req_is_ldap_error(struct tevent_req *req, TLDAPRC *perr);
-
-struct tldap_context *tldap_context_create(TALLOC_CTX *mem_ctx, int fd);
-struct tstream_context *tldap_get_tstream(struct tldap_context *ld);
-void tldap_set_tstream(struct tldap_context *ld,
-		       struct tstream_context *stream);
-
-bool tldap_connection_ok(struct tldap_context *ld);
-bool tldap_context_setattr(struct tldap_context *ld,
-			   const char *name, const void *pptr);
-void *tldap_context_getattr(struct tldap_context *ld, const char *name);
-
-struct tevent_req *tldap_sasl_bind_send(TALLOC_CTX *mem_ctx,
-					struct tevent_context *ev,
-					struct tldap_context *ld,
-					const char *dn,
-					const char *mechanism,
-					DATA_BLOB *creds,
-					struct tldap_control *sctrls,
-					int num_sctrls,
-					struct tldap_control *cctrls,
-					int num_cctrls);
-TLDAPRC tldap_sasl_bind_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-			     DATA_BLOB *serverSaslCreds);
-TLDAPRC tldap_sasl_bind(struct tldap_context *ldap,
-			const char *dn,
-			const char *mechanism,
-			DATA_BLOB *creds,
-			struct tldap_control *sctrls,
-			int num_sctrls,
-			struct tldap_control *cctrls,
-			int num_cctrls,
-			TALLOC_CTX *mem_ctx,
-			DATA_BLOB *serverSaslCreds);
-
-struct tevent_req *tldap_simple_bind_send(TALLOC_CTX *mem_ctx,
-					  struct tevent_context *ev,
-					  struct tldap_context *ldap,
-					  const char *dn,
-					  const char *passwd);
-TLDAPRC tldap_simple_bind_recv(struct tevent_req *req);
-TLDAPRC tldap_simple_bind(struct tldap_context *ldap, const char *dn,
-			  const char *passwd);
-
-struct tevent_req *tldap_search_send(TALLOC_CTX *mem_ctx,
-				     struct tevent_context *ev,
-				     struct tldap_context *ld,
-				     const char *base, int scope,
-				     const char *filter,
-				     const char **attrs,
-				     int num_attrs,
-				     int attrsonly,
-				     struct tldap_control *sctrls,
-				     int num_sctrls,
-				     struct tldap_control *cctrls,
-				     int num_cctrls,
-				     int timelimit,
-				     int sizelimit,
-				     int deref);
-TLDAPRC tldap_search_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-			  struct tldap_message **pmsg);
-
-struct tevent_req *tldap_search_all_send(
-	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-	struct tldap_context *ld, const char *base, int scope,
-	const char *filter, const char **attrs, int num_attrs, int attrsonly,
-	struct tldap_control *sctrls, int num_sctrls,
-	struct tldap_control *cctrls, int num_cctrls,
-	int timelimit, int sizelimit, int deref);
-TLDAPRC tldap_search_all_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-			      struct tldap_message ***msgs,
-			      struct tldap_message **result);
-
-TLDAPRC tldap_search(struct tldap_context *ld,
-		     const char *base, int scope, const char *filter,
-		     const char **attrs, int num_attrs, int attrsonly,
-		     struct tldap_control *sctrls, int num_sctrls,
-		     struct tldap_control *cctrls, int num_cctrls,
-		     int timelimit, int sizelimit, int deref,
-		     TALLOC_CTX *mem_ctx, struct tldap_message ***pmsgs);
-
-bool tldap_entry_dn(struct tldap_message *msg, char **dn);
-bool tldap_entry_attributes(struct tldap_message *msg,
-			    struct tldap_attribute **attributes,
-			    int *num_attributes);
-
-struct tevent_req *tldap_add_send(TALLOC_CTX *mem_ctx,
-				  struct tevent_context *ev,
-				  struct tldap_context *ld,
-				  const char *dn,
-				  struct tldap_mod *attributes,
-				  int num_attributes,
-				  struct tldap_control *sctrls,
-				  int num_sctrls,
-				  struct tldap_control *cctrls,
-				  int num_cctrls);
-TLDAPRC tldap_add_recv(struct tevent_req *req);
-TLDAPRC tldap_add(struct tldap_context *ld, const char *dn,
-		  struct tldap_mod *attributes, int num_attributes,
-		  struct tldap_control *sctrls, int num_sctrls,
-		  struct tldap_control *cctrls, int num_cctrls);
-
-struct tevent_req *tldap_modify_send(TALLOC_CTX *mem_ctx,
-				     struct tevent_context *ev,
-				     struct tldap_context *ld,
-				     const char *dn,
-				     struct tldap_mod *mods, int num_mods,
-				     struct tldap_control *sctrls,
-				     int num_sctrls,
-				     struct tldap_control *cctrls,
-				     int num_cctrls);
-TLDAPRC tldap_modify_recv(struct tevent_req *req);
-TLDAPRC tldap_modify(struct tldap_context *ld, const char *dn,
-		     struct tldap_mod *mods, int num_mods,
-		     struct tldap_control *sctrls, int num_sctrls,
-		     struct tldap_control *cctrls, int num_cctrls);
-
-struct tevent_req *tldap_delete_send(TALLOC_CTX *mem_ctx,
-				     struct tevent_context *ev,
-				     struct tldap_context *ld,
-				     const char *dn,
-				     struct tldap_control *sctrls,
-				     int num_sctrls,
-				     struct tldap_control *cctrls,
-				     int num_cctrls);
-TLDAPRC tldap_delete_recv(struct tevent_req *req);
-TLDAPRC tldap_delete(struct tldap_context *ld, const char *dn,
-		     struct tldap_control *sctrls, int num_sctrls,
-		     struct tldap_control *cctrls, int num_cctrls);
-
-int tldap_msg_id(const struct tldap_message *msg);
-int tldap_msg_type(const struct tldap_message *msg);
-const char *tldap_msg_matcheddn(struct tldap_message *msg);
-const char *tldap_msg_diagnosticmessage(struct tldap_message *msg);
-const char *tldap_msg_referral(struct tldap_message *msg);
-void tldap_msg_sctrls(struct tldap_message *msg, int *num_sctrls,
-		      struct tldap_control **sctrls);
-struct tldap_message *tldap_ctx_lastmsg(struct tldap_context *ld);
-const char *tldap_rc2string(TLDAPRC rc);
-
-/* DEBUG */
-enum tldap_debug_level {
-	TLDAP_DEBUG_FATAL,
-	TLDAP_DEBUG_ERROR,
-	TLDAP_DEBUG_WARNING,
-	TLDAP_DEBUG_TRACE
-};
-
-void tldap_set_debug(struct tldap_context *ld,
-		     void (*log_fn)(void *log_private,
-				    enum tldap_debug_level level,
-				    const char *fmt,
-				    va_list ap) PRINTF_ATTRIBUTE(3,0),
-		     void *log_private);
-
-/*
- * "+ 0x60" is from ASN1_APPLICATION
- */
-#define TLDAP_REQ_BIND (0 + 0x60)
-#define TLDAP_RES_BIND (1 + 0x60)
-#define TLDAP_REQ_UNBIND (2 + 0x60)
-#define TLDAP_REQ_SEARCH (3 + 0x60)
-#define TLDAP_RES_SEARCH_ENTRY (4 + 0x60)
-#define TLDAP_RES_SEARCH_RESULT (5 + 0x60)
-#define TLDAP_REQ_MODIFY (6 + 0x60)
-#define TLDAP_RES_MODIFY (7 + 0x60)
-#define TLDAP_REQ_ADD (8 + 0x60)
-#define TLDAP_RES_ADD (9 + 0x60)
-/* ASN1_APPLICATION_SIMPLE instead of ASN1_APPLICATION */
-#define TLDAP_REQ_DELETE (10 + 0x40)
-#define TLDAP_RES_DELETE (11 + 0x60)
-#define TLDAP_REQ_MODDN (12 + 0x60)
-#define TLDAP_RES_MODDN (13 + 0x60)
-#define TLDAP_REQ_COMPARE (14 + 0x60)
-#define TLDAP_RES_COMPARE (15 + 0x60)
-/* ASN1_APPLICATION_SIMPLE instead of ASN1_APPLICATION */
-#define TLDAP_REQ_ABANDON (16 + 0x40)
-#define TLDAP_RES_SEARCH_REFERENCE (19 + 0x60)
-#define TLDAP_REQ_EXTENDED (23 + 0x60)
-#define TLDAP_RES_EXTENDED (24 + 0x60)
-#define TLDAP_RES_INTERMEDIATE (25 + 0x60)
-
-#define TLDAP_MOD_ADD (0)
-#define TLDAP_MOD_DELETE (1)
-#define TLDAP_MOD_REPLACE (2)
-
-#define TLDAP_SCOPE_BASE (0)
-#define TLDAP_SCOPE_ONE (1)
-#define TLDAP_SCOPE_SUB (2)
-
-#define TLDAP_CONTROL_PAGEDRESULTS "1.2.840.113556.1.4.319"
-
-#endif
diff --git a/source3/include/tldap_util.h b/source3/include/tldap_util.h
deleted file mode 100644
index f9d088c..0000000
--- a/source3/include/tldap_util.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
-   Unix SMB/CIFS implementation.
-   Infrastructure for async ldap client requests
-   Copyright (C) Volker Lendecke 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/>.
-*/
-
-#ifndef __TLDAP_UTIL_H__
-#define __TLDAP_UTIL_H__
-
-#include "includes.h"
-
-bool tldap_entry_values(struct tldap_message *msg, const char *attribute,
-			DATA_BLOB **values, int *num_values);
-bool tldap_get_single_valueblob(struct tldap_message *msg,
-				const char *attribute, DATA_BLOB *blob);
-char *tldap_talloc_single_attribute(struct tldap_message *msg,
-				    const char *attribute,
-				    TALLOC_CTX *mem_ctx);
-bool tldap_pull_binsid(struct tldap_message *msg, const char *attribute,
-		       struct dom_sid *sid);
-bool tldap_pull_guid(struct tldap_message *msg, const char *attribute,
-		     struct GUID *guid);
-bool tldap_add_mod_blobs(TALLOC_CTX *mem_ctx,
-			 struct tldap_mod **pmods, int *pnum_mods,
-			 int mod_op, const char *attrib,
-			 DATA_BLOB *newvals, int num_newvals);
-bool tldap_add_mod_str(TALLOC_CTX *mem_ctx,
-		       struct tldap_mod **pmods, int *pnum_mods,
-		       int mod_op, const char *attrib, const char *str);
-bool tldap_make_mod_blob(struct tldap_message *existing, TALLOC_CTX *mem_ctx,
-			 struct tldap_mod **pmods, int *pnum_mods,
-			 const char *attrib, DATA_BLOB newval);
-bool tldap_make_mod_fmt(struct tldap_message *existing, TALLOC_CTX *mem_ctx,
-			struct tldap_mod **pmods, int *pnum_mods,
-			const char *attrib, const char *fmt, ...);
-
-const char *tldap_errstr(TALLOC_CTX *mem_ctx, struct tldap_context *ld,
-			 TLDAPRC rc);
-TLDAPRC tldap_search_va(struct tldap_context *ld, const char *base, int scope,
-			const char *attrs[], int num_attrs, int attrsonly,
-			TALLOC_CTX *mem_ctx, struct tldap_message ***res,
-		    const char *fmt, va_list ap);
-TLDAPRC tldap_search_fmt(struct tldap_context *ld, const char *base, int scope,
-			 const char *attrs[], int num_attrs, int attrsonly,
-			 TALLOC_CTX *mem_ctx, struct tldap_message ***res,
-			 const char *fmt, ...);
-bool tldap_pull_uint64(struct tldap_message *msg, const char *attr,
-		       uint64_t *presult);
-bool tldap_pull_uint32(struct tldap_message *msg, const char *attr,
-		       uint32_t *presult);
-
-struct tevent_req *tldap_fetch_rootdse_send(TALLOC_CTX *mem_ctx,
-					    struct tevent_context *ev,
-					    struct tldap_context *ld);
-TLDAPRC tldap_fetch_rootdse_recv(struct tevent_req *req);
-TLDAPRC tldap_fetch_rootdse(struct tldap_context *ld);
-struct tldap_message *tldap_rootdse(struct tldap_context *ld);
-
-bool tldap_entry_has_attrvalue(struct tldap_message *msg,
-			       const char *attribute,
-			       const DATA_BLOB blob);
-bool tldap_supports_control(struct tldap_context *ld, const char *oid);
-
-struct tldap_control *tldap_add_control(TALLOC_CTX *mem_ctx,
-					struct tldap_control *ctrls,
-					int num_ctrls,
-					struct tldap_control *ctrl);
-struct tldap_control *tldap_msg_findcontrol(struct tldap_message *msg,
-					    const char *oid);
-
-struct tevent_req *tldap_search_paged_send(TALLOC_CTX *mem_ctx,
-					   struct tevent_context *ev,
-					   struct tldap_context *ld,
-					   const char *base, int scope,
-					   const char *filter,
-					   const char **attrs,
-					   int num_attrs,
-					   int attrsonly,
-					   struct tldap_control *sctrls,
-					   int num_sctrls,
-					   struct tldap_control *cctrls,
-					   int num_cctrls,
-					   int timelimit,
-					   int sizelimit,
-					   int deref,
-					   int page_size);
-TLDAPRC tldap_search_paged_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-				struct tldap_message **pmsg);
-
-
-#endif
diff --git a/source3/lib/tldap.c b/source3/lib/tldap.c
deleted file mode 100644
index 5fcb43c..0000000
--- a/source3/lib/tldap.c
+++ /dev/null
@@ -1,2668 +0,0 @@
-/*
-   Unix SMB/CIFS implementation.
-   Infrastructure for async ldap client requests
-   Copyright (C) Volker Lendecke 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 "replace.h"
-#include "tldap.h"
-#include "system/network.h"
-#include "system/locale.h"
-#include "lib/util/talloc_stack.h"
-#include "lib/util/samba_util.h"
-#include "lib/util_tsock.h"
-#include "../lib/util/asn1.h"
-#include "../lib/tsocket/tsocket.h"
-#include "../lib/util/tevent_unix.h"
-
-static TLDAPRC tldap_simple_recv(struct tevent_req *req);
-
-#define TEVENT_TLDAP_RC_MAGIC (0x87bcd26e)
-
-bool tevent_req_ldap_error(struct tevent_req *req, TLDAPRC rc)
-{
-	uint64_t err;
-
-	if (TLDAP_RC_IS_SUCCESS(rc)) {
-		return false;
-	}
-
-	err = TEVENT_TLDAP_RC_MAGIC;
-	err <<= 32;
-	err |= TLDAP_RC_V(rc);
-
-	return tevent_req_error(req, err);
-}
-
-bool tevent_req_is_ldap_error(struct tevent_req *req, TLDAPRC *perr)
-{
-	enum tevent_req_state state;
-	uint64_t err;
-
-	if (!tevent_req_is_error(req, &state, &err)) {
-		return false;
-	}
-	switch (state) {
-	case TEVENT_REQ_TIMED_OUT:
-		*perr = TLDAP_TIMEOUT;
-		break;
-	case TEVENT_REQ_NO_MEMORY:
-		*perr = TLDAP_NO_MEMORY;
-		break;
-	case TEVENT_REQ_USER_ERROR:
-		if ((err >> 32) != TEVENT_TLDAP_RC_MAGIC) {
-			abort();
-		}
-		*perr = TLDAP_RC(err & 0xffffffff);
-		break;
-	default:
-		*perr = TLDAP_OPERATIONS_ERROR;
-		break;
-	}
-	return true;
-}
-
-struct tldap_ctx_attribute {
-	char *name;
-	void *ptr;
-};
-
-struct tldap_context {
-	int ld_version;
-	struct tstream_context *conn;
-	bool server_down;
-	int msgid;
-	struct tevent_queue *outgoing;
-	struct tevent_req **pending;
-
-	/* For the sync wrappers we need something like get_last_error... */
-	struct tldap_message *last_msg;
-
-	/* debug */
-	void (*log_fn)(void *context, enum tldap_debug_level level,
-		       const char *fmt, va_list ap);
-	void *log_private;
-
-	struct tldap_ctx_attribute *ctx_attrs;
-};
-
-struct tldap_message {
-	struct asn1_data *data;
-	uint8_t *inbuf;
-	int type;
-	int id;
-
-	/* RESULT_ENTRY */
-	char *dn;
-	struct tldap_attribute *attribs;
-
-	/* Error data sent by the server */
-	TLDAPRC lderr;
-	char *res_matcheddn;
-	char *res_diagnosticmessage;
-	char *res_referral;
-	DATA_BLOB res_serverSaslCreds;
-	struct tldap_control *res_sctrls;
-
-	/* Controls sent by the server */
-	struct tldap_control *ctrls;
-};
-
-void tldap_set_debug(struct tldap_context *ld,
-		     void (*log_fn)(void *log_private,
-				    enum tldap_debug_level level,
-				    const char *fmt,
-				    va_list ap) PRINTF_ATTRIBUTE(3,0),
-		     void *log_private)
-{
-	ld->log_fn = log_fn;
-	ld->log_private = log_private;
-}
-
-static void tldap_debug(struct tldap_context *ld,
-			 enum tldap_debug_level level,
-			 const char *fmt, ...)
-{
-	va_list ap;
-	if (!ld) {
-		return;
-	}
-	if (ld->log_fn == NULL) {
-		return;
-	}
-	va_start(ap, fmt);
-	ld->log_fn(ld->log_private, level, fmt, ap);
-	va_end(ap);
-}
-
-static int tldap_next_msgid(struct tldap_context *ld)
-{
-	int result;
-
-	result = ld->msgid++;
-	if (ld->msgid == 2147483647) {
-		ld->msgid = 1;
-	}
-	return result;
-}
-
-struct tldap_context *tldap_context_create(TALLOC_CTX *mem_ctx, int fd)
-{
-	struct tldap_context *ctx;
-	int ret;
-
-	ctx = talloc_zero(mem_ctx, struct tldap_context);
-	if (ctx == NULL) {
-		return NULL;
-	}
-	ret = tstream_bsd_existing_socket(ctx, fd, &ctx->conn);
-	if (ret == -1) {
-		TALLOC_FREE(ctx);
-		return NULL;
-	}
-	ctx->msgid = 1;
-	ctx->ld_version = 3;
-	ctx->outgoing = tevent_queue_create(ctx, "tldap_outgoing");
-	if (ctx->outgoing == NULL) {
-		TALLOC_FREE(ctx);
-		return NULL;
-	}
-	return ctx;
-}
-
-bool tldap_connection_ok(struct tldap_context *ld)
-{
-	if (ld == NULL) {
-		return false;
-	}
-	return !ld->server_down;
-}
-
-static size_t tldap_pending_reqs(struct tldap_context *ld)
-{
-	return talloc_array_length(ld->pending);
-}
-
-struct tstream_context *tldap_get_tstream(struct tldap_context *ld)
-{
-	return ld->conn;
-}
-
-void tldap_set_tstream(struct tldap_context *ld,
-		       struct tstream_context *stream)
-{
-	ld->conn = stream;
-}
-
-static struct tldap_ctx_attribute *tldap_context_findattr(
-	struct tldap_context *ld, const char *name)
-{
-	size_t i, num_attrs;
-
-	num_attrs = talloc_array_length(ld->ctx_attrs);
-
-	for (i=0; i<num_attrs; i++) {
-		if (strcmp(ld->ctx_attrs[i].name, name) == 0) {
-			return &ld->ctx_attrs[i];
-		}
-	}
-	return NULL;
-}
-
-bool tldap_context_setattr(struct tldap_context *ld,
-			   const char *name, const void *_pptr)
-{
-	struct tldap_ctx_attribute *tmp, *attr;
-	char *tmpname;
-	int num_attrs;
-	void **pptr = (void **)discard_const_p(void,_pptr);
-
-	attr = tldap_context_findattr(ld, name);
-	if (attr != NULL) {
-		/*
-		 * We don't actually delete attrs, we don't expect tons of
-		 * attributes being shuffled around.
-		 */
-		TALLOC_FREE(attr->ptr);
-		if (*pptr != NULL) {
-			attr->ptr = talloc_move(ld->ctx_attrs, pptr);
-			*pptr = NULL;
-		}
-		return true;
-	}
-
-	tmpname = talloc_strdup(ld, name);
-	if (tmpname == NULL) {
-		return false;
-	}
-
-	num_attrs = talloc_array_length(ld->ctx_attrs);
-
-	tmp = talloc_realloc(ld, ld->ctx_attrs, struct tldap_ctx_attribute,
-			     num_attrs+1);
-	if (tmp == NULL) {
-		TALLOC_FREE(tmpname);
-		return false;
-	}
-	tmp[num_attrs].name = talloc_move(tmp, &tmpname);
-	if (*pptr != NULL) {
-		tmp[num_attrs].ptr = talloc_move(tmp, pptr);
-	} else {
-		tmp[num_attrs].ptr = NULL;
-	}
-	*pptr = NULL;
-	ld->ctx_attrs = tmp;
-	return true;
-}
-
-void *tldap_context_getattr(struct tldap_context *ld, const char *name)
-{
-	struct tldap_ctx_attribute *attr = tldap_context_findattr(ld, name);
-
-	if (attr == NULL) {
-		return NULL;
-	}
-	return attr->ptr;
-}
-
-struct read_ldap_state {
-	uint8_t *buf;
-	bool done;
-};
-
-static ssize_t read_ldap_more(uint8_t *buf, size_t buflen, void *private_data);
-static void read_ldap_done(struct tevent_req *subreq);
-
-static struct tevent_req *read_ldap_send(TALLOC_CTX *mem_ctx,
-					 struct tevent_context *ev,
-					 struct tstream_context *conn)
-{
-	struct tevent_req *req, *subreq;
-	struct read_ldap_state *state;
-
-	req = tevent_req_create(mem_ctx, &state, struct read_ldap_state);
-	if (req == NULL) {
-		return NULL;
-	}
-	state->done = false;
-
-	subreq = tstream_read_packet_send(state, ev, conn, 2, read_ldap_more,
-					  state);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(subreq, read_ldap_done, req);
-	return req;
-}
-
-static ssize_t read_ldap_more(uint8_t *buf, size_t buflen, void *private_data)
-{
-	struct read_ldap_state *state = talloc_get_type_abort(
-		private_data, struct read_ldap_state);
-	size_t len;
-	int i, lensize;
-
-	if (state->done) {
-		/* We've been here, we're done */
-		return 0;
-	}
-
-	/*
-	 * From ldap.h: LDAP_TAG_MESSAGE is 0x30
-	 */
-	if (buf[0] != 0x30) {
-		return -1;
-	}
-
-	len = buf[1];
-	if ((len & 0x80) == 0) {
-		state->done = true;
-		return len;
-	}
-
-	lensize = (len & 0x7f);
-	len = 0;
-
-	if (buflen == 2) {
-		/* Please get us the full length */
-		return lensize;
-	}
-	if (buflen > 2 + lensize) {
-		state->done = true;
-		return 0;
-	}
-	if (buflen != 2 + lensize) {
-		return -1;
-	}
-
-	for (i=0; i<lensize; i++) {
-		len = (len << 8) | buf[2+i];
-	}
-	return len;
-}
-
-static void read_ldap_done(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct read_ldap_state *state = tevent_req_data(
-		req, struct read_ldap_state);
-	ssize_t nread;
-	int err;
-
-	nread = tstream_read_packet_recv(subreq, state, &state->buf, &err);
-	TALLOC_FREE(subreq);
-	if (nread == -1) {
-		tevent_req_error(req, err);
-		return;
-	}
-	tevent_req_done(req);
-}
-
-static ssize_t read_ldap_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-			      uint8_t **pbuf, int *perrno)
-{
-	struct read_ldap_state *state = tevent_req_data(
-		req, struct read_ldap_state);
-
-	if (tevent_req_is_unix_error(req, perrno)) {
-		return -1;
-	}
-	*pbuf = talloc_move(mem_ctx, &state->buf);
-	return talloc_get_size(*pbuf);
-}
-
-struct tldap_msg_state {
-	struct tldap_context *ld;
-	struct tevent_context *ev;
-	int id;
-	struct iovec iov;
-
-	struct asn1_data *data;
-	uint8_t *inbuf;
-};
-
-static bool tldap_push_controls(struct asn1_data *data,
-				struct tldap_control *sctrls,
-				int num_sctrls)
-{
-	int i;
-
-	if ((sctrls == NULL) || (num_sctrls == 0)) {
-		return true;
-	}
-
-	if (!asn1_push_tag(data, ASN1_CONTEXT(0))) return false;
-
-	for (i=0; i<num_sctrls; i++) {
-		struct tldap_control *c = &sctrls[i];
-		if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
-		if (!asn1_write_OctetString(data, c->oid, strlen(c->oid))) return false;
-		if (c->critical) {
-			if (!asn1_write_BOOLEAN(data, true)) return false;
-		}
-		if (c->value.data != NULL) {
-			if (!asn1_write_OctetString(data, c->value.data,
-					       c->value.length)) return false;
-		}
-		if (!asn1_pop_tag(data)) return false; /* ASN1_SEQUENCE(0) */
-	}
-
-	return asn1_pop_tag(data); /* ASN1_CONTEXT(0) */
-}
-
-static void tldap_msg_sent(struct tevent_req *subreq);
-static void tldap_msg_received(struct tevent_req *subreq);
-
-static struct tevent_req *tldap_msg_send(TALLOC_CTX *mem_ctx,
-					 struct tevent_context *ev,
-					 struct tldap_context *ld,
-					 int id, struct asn1_data *data,
-					 struct tldap_control *sctrls,
-					 int num_sctrls)
-{
-	struct tevent_req *req, *subreq;
-	struct tldap_msg_state *state;
-	DATA_BLOB blob;
-
-	tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_send: sending msg %d\n",
-		    id);
-
-	req = tevent_req_create(mem_ctx, &state, struct tldap_msg_state);
-	if (req == NULL) {
-		return NULL;
-	}
-	state->ld = ld;
-	state->ev = ev;
-	state->id = id;
-
-	if (state->ld->server_down) {
-		tevent_req_ldap_error(req, TLDAP_SERVER_DOWN);
-		return tevent_req_post(req, ev);
-	}
-
-	if (!tldap_push_controls(data, sctrls, num_sctrls)) {
-		tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
-		return tevent_req_post(req, ev);
-	}
-
-
-	if (!asn1_pop_tag(data)) {
-		tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
-		return tevent_req_post(req, ev);
-	}
-
-	if (!asn1_blob(data, &blob)) {
-		tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
-		return tevent_req_post(req, ev);
-	}
-
-	state->iov.iov_base = (void *)blob.data;
-	state->iov.iov_len = blob.length;
-
-	subreq = tstream_writev_queue_send(state, ev, ld->conn, ld->outgoing,
-					   &state->iov, 1);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(subreq, tldap_msg_sent, req);
-	return req;
-}
-
-static void tldap_msg_unset_pending(struct tevent_req *req)
-{
-	struct tldap_msg_state *state = tevent_req_data(
-		req, struct tldap_msg_state);
-	struct tldap_context *ld = state->ld;
-	int num_pending = tldap_pending_reqs(ld);
-	int i;
-
-	tevent_req_set_cleanup_fn(req, NULL);
-
-	if (num_pending == 1) {
-		TALLOC_FREE(ld->pending);
-		return;
-	}
-
-	for (i=0; i<num_pending; i++) {
-		if (req == ld->pending[i]) {
-			break;
-		}
-	}
-	if (i == num_pending) {
-		/*
-		 * Something's seriously broken. Just returning here is the
-		 * right thing nevertheless, the point of this routine is to
-		 * remove ourselves from cli->pending.
-		 */
-		return;
-	}
-
-	/*
-	 * Remove ourselves from the cli->pending array
-	 */
-	if (num_pending > 1) {
-		ld->pending[i] = ld->pending[num_pending-1];
-	}
-
-	/*
-	 * No NULL check here, we're shrinking by sizeof(void *), and
-	 * talloc_realloc just adjusts the size for this.
-	 */
-	ld->pending = talloc_realloc(NULL, ld->pending, struct tevent_req *,
-				     num_pending - 1);
-}
-
-static void tldap_msg_cleanup(struct tevent_req *req,
-			      enum tevent_req_state req_state)
-{
-	switch (req_state) {
-	case TEVENT_REQ_USER_ERROR:
-	case TEVENT_REQ_RECEIVED:
-		tldap_msg_unset_pending(req);
-		return;
-	default:
-		return;
-	}
-}
-
-static bool tldap_msg_set_pending(struct tevent_req *req)
-{
-	struct tldap_msg_state *state = tevent_req_data(
-		req, struct tldap_msg_state);
-	struct tldap_context *ld;
-	struct tevent_req **pending;
-	int num_pending;
-	struct tevent_req *subreq;
-
-	ld = state->ld;
-	num_pending = tldap_pending_reqs(ld);
-
-	pending = talloc_realloc(ld, ld->pending, struct tevent_req *,
-				 num_pending+1);
-	if (pending == NULL) {
-		return false;
-	}
-	pending[num_pending] = req;
-	ld->pending = pending;
-	tevent_req_set_cleanup_fn(req, tldap_msg_cleanup);
-
-	if (num_pending > 0) {
-		return true;
-	}
-
-	/*
-	 * We're the first one, add the read_ldap request that waits for the
-	 * answer from the server
-	 */
-	subreq = read_ldap_send(ld->pending, state->ev, ld->conn);
-	if (subreq == NULL) {
-		tldap_msg_unset_pending(req);
-		return false;
-	}
-	tevent_req_set_callback(subreq, tldap_msg_received, ld);
-	return true;
-}
-
-static void tldap_msg_sent(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct tldap_msg_state *state = tevent_req_data(
-		req, struct tldap_msg_state);
-	ssize_t nwritten;
-	int err;
-
-	nwritten = tstream_writev_queue_recv(subreq, &err);
-	TALLOC_FREE(subreq);
-	if (nwritten == -1) {
-		state->ld->server_down = true;
-		tevent_req_ldap_error(req, TLDAP_SERVER_DOWN);
-		return;
-	}
-
-	if (!tldap_msg_set_pending(req)) {
-		tevent_req_oom(req);
-		return;
-	}
-}
-
-static int tldap_msg_msgid(struct tevent_req *req)
-{
-	struct tldap_msg_state *state = tevent_req_data(
-		req, struct tldap_msg_state);
-
-	return state->id;
-}
-
-static void tldap_msg_received(struct tevent_req *subreq)
-{
-	struct tldap_context *ld = tevent_req_callback_data(
-		subreq, struct tldap_context);
-	struct tevent_req *req;
-	struct tldap_msg_state *state;
-	struct asn1_data *data;
-	uint8_t *inbuf;
-	ssize_t received;
-	size_t num_pending;
-	int i, err;
-	TLDAPRC status;
-	int id;
-	uint8_t type;
-	bool ok;
-
-	received = read_ldap_recv(subreq, talloc_tos(), &inbuf, &err);
-	TALLOC_FREE(subreq);
-	if (received == -1) {
-		ld->server_down = true;
-		status = TLDAP_SERVER_DOWN;
-		goto fail;
-	}
-
-	data = asn1_init(talloc_tos());
-	if (data == NULL) {
-		status = TLDAP_NO_MEMORY;
-		goto fail;
-	}
-	asn1_load_nocopy(data, inbuf, received);
-
-	ok = true;
-	ok &= asn1_start_tag(data, ASN1_SEQUENCE(0));
-	ok &= asn1_read_Integer(data, &id);
-	ok &= asn1_peek_uint8(data, &type);
-
-	if (!ok) {
-		status = TLDAP_PROTOCOL_ERROR;
-		goto fail;
-	}
-
-	tldap_debug(ld, TLDAP_DEBUG_TRACE, "tldap_msg_received: got msg %d "
-		    "type %d\n", id, (int)type);
-
-	num_pending = talloc_array_length(ld->pending);
-
-	for (i=0; i<num_pending; i++) {
-		if (id == tldap_msg_msgid(ld->pending[i])) {
-			break;
-		}
-	}
-	if (i == num_pending) {
-		/* Dump unexpected reply */
-		tldap_debug(ld, TLDAP_DEBUG_WARNING, "tldap_msg_received: "
-			    "No request pending for msg %d\n", id);
-		TALLOC_FREE(data);
-		TALLOC_FREE(inbuf);
-		goto done;
-	}
-
-	req = ld->pending[i];
-	state = tevent_req_data(req, struct tldap_msg_state);
-
-	state->inbuf = talloc_move(state, &inbuf);
-	state->data = talloc_move(state, &data);
-
-	tldap_msg_unset_pending(req);
-	num_pending = talloc_array_length(ld->pending);
-
-	tevent_req_done(req);
-
- done:
-	if (num_pending == 0) {
-		return;
-	}
-	if (talloc_array_length(ld->pending) > num_pending) {
-		/*
-		 * The callback functions called from tevent_req_done() above
-		 * have put something on the pending queue. We don't have to
-		 * trigger the read_ldap_send(), tldap_msg_set_pending() has
-		 * done it for us already.
-		 */
-		return;
-	}
-
-	state = tevent_req_data(ld->pending[0],	struct tldap_msg_state);
-	subreq = read_ldap_send(ld->pending, state->ev, ld->conn);
-	if (subreq == NULL) {
-		status = TLDAP_NO_MEMORY;
-		goto fail;
-	}
-	tevent_req_set_callback(subreq, tldap_msg_received, ld);
-	return;
-
- fail:
-	while (talloc_array_length(ld->pending) > 0) {
-		req = ld->pending[0];
-		state = tevent_req_data(req, struct tldap_msg_state);
-		tevent_req_defer_callback(req, state->ev);
-		tevent_req_ldap_error(req, status);
-	}
-}
-
-static TLDAPRC tldap_msg_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-			      struct tldap_message **pmsg)
-{
-	struct tldap_msg_state *state = tevent_req_data(
-		req, struct tldap_msg_state);
-	struct tldap_message *msg;
-	TLDAPRC err;
-	uint8_t msgtype;
-
-	if (tevent_req_is_ldap_error(req, &err)) {
-		return err;
-	}
-
-	if (!asn1_peek_uint8(state->data, &msgtype)) {
-		return TLDAP_PROTOCOL_ERROR;
-	}
-
-	if (pmsg == NULL) {
-		return TLDAP_SUCCESS;
-	}
-
-	msg = talloc_zero(mem_ctx, struct tldap_message);
-	if (msg == NULL) {
-		return TLDAP_NO_MEMORY;
-	}
-	msg->id = state->id;
-
-	msg->inbuf = talloc_move(msg, &state->inbuf);
-	msg->data = talloc_move(msg, &state->data);
-	msg->type = msgtype;
-
-	*pmsg = msg;
-	return TLDAP_SUCCESS;
-}
-
-struct tldap_req_state {
-	int id;
-	struct asn1_data *out;
-	struct tldap_message *result;
-};
-
-static struct tevent_req *tldap_req_create(TALLOC_CTX *mem_ctx,
-					   struct tldap_context *ld,
-					   struct tldap_req_state **pstate)
-{
-	struct tevent_req *req;
-	struct tldap_req_state *state;
-
-	req = tevent_req_create(mem_ctx, &state, struct tldap_req_state);
-	if (req == NULL) {
-		return NULL;
-	}
-	state->out = asn1_init(state);
-	if (state->out == NULL) {
-		goto err;
-	}
-	state->id = tldap_next_msgid(ld);
-
-	if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
-	if (!asn1_write_Integer(state->out, state->id)) goto err;
-
-	*pstate = state;
-	return req;
-
-  err:
-
-	TALLOC_FREE(req);
-	return NULL;
-}
-
-static void tldap_save_msg(struct tldap_context *ld, struct tevent_req *req)
-{
-	struct tldap_req_state *state = tevent_req_data(
-		req, struct tldap_req_state);
-
-	TALLOC_FREE(ld->last_msg);
-	ld->last_msg = talloc_move(ld, &state->result);
-}
-
-static char *blob2string_talloc(TALLOC_CTX *mem_ctx, DATA_BLOB blob)
-{
-	char *result = talloc_array(mem_ctx, char, blob.length+1);
-
-	if (result == NULL) {
-		return NULL;
-	}
-
-	memcpy(result, blob.data, blob.length);
-	result[blob.length] = '\0';
-	return result;
-}
-
-static bool asn1_read_OctetString_talloc(TALLOC_CTX *mem_ctx,
-					 struct asn1_data *data,
-					 char **presult)
-{
-	DATA_BLOB string;
-	char *result;
-	if (!asn1_read_OctetString(data, mem_ctx, &string))
-		return false;
-
-	result = blob2string_talloc(mem_ctx, string);
-
-	data_blob_free(&string);
-
-	if (result == NULL) {
-		return false;
-	}
-	*presult = result;
-	return true;
-}
-
-static bool tldap_decode_controls(struct tldap_req_state *state);
-
-static bool tldap_decode_response(struct tldap_req_state *state)
-{
-	struct asn1_data *data = state->result->data;
-	struct tldap_message *msg = state->result;
-	int rc;
-	bool ok = true;
-
-	ok &= asn1_read_enumerated(data, &rc);
-	if (ok) {
-		msg->lderr = TLDAP_RC(rc);
-	}
-
-	ok &= asn1_read_OctetString_talloc(msg, data, &msg->res_matcheddn);
-	ok &= asn1_read_OctetString_talloc(msg, data,
-					   &msg->res_diagnosticmessage);
-	if (!ok) return ok;
-	if (asn1_peek_tag(data, ASN1_CONTEXT(3))) {
-		ok &= asn1_start_tag(data, ASN1_CONTEXT(3));
-		ok &= asn1_read_OctetString_talloc(msg, data,
-						   &msg->res_referral);
-		ok &= asn1_end_tag(data);
-	} else {
-		msg->res_referral = NULL;
-	}
-
-	return ok;
-}
-
-static void tldap_sasl_bind_done(struct tevent_req *subreq);
-
-struct tevent_req *tldap_sasl_bind_send(TALLOC_CTX *mem_ctx,
-					struct tevent_context *ev,
-					struct tldap_context *ld,
-					const char *dn,
-					const char *mechanism,
-					DATA_BLOB *creds,
-					struct tldap_control *sctrls,
-					int num_sctrls,
-					struct tldap_control *cctrls,
-					int num_cctrls)
-{
-	struct tevent_req *req, *subreq;
-	struct tldap_req_state *state;
-
-	req = tldap_req_create(mem_ctx, ld, &state);
-	if (req == NULL) {
-		return NULL;
-	}
-
-	if (dn == NULL) {
-		dn = "";
-	}
-
-	if (!asn1_push_tag(state->out, TLDAP_REQ_BIND)) goto err;
-	if (!asn1_write_Integer(state->out, ld->ld_version)) goto err;
-	if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
-
-	if (mechanism == NULL) {
-		if (!asn1_push_tag(state->out, ASN1_CONTEXT_SIMPLE(0))) goto err;
-		if (!asn1_write(state->out, creds->data, creds->length)) goto err;
-		if (!asn1_pop_tag(state->out)) goto err;
-	} else {
-		if (!asn1_push_tag(state->out, ASN1_CONTEXT(3))) goto err;
-		if (!asn1_write_OctetString(state->out, mechanism,
-				       strlen(mechanism))) goto err;
-		if ((creds != NULL) && (creds->data != NULL)) {
-			if (!asn1_write_OctetString(state->out, creds->data,
-					       creds->length)) goto err;
-		}
-		if (!asn1_pop_tag(state->out)) goto err;
-	}
-
-	if (!asn1_pop_tag(state->out)) goto err;
-
-	subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
-				sctrls, num_sctrls);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(subreq, tldap_sasl_bind_done, req);
-	return req;
-
-  err:
-
-	tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
-	return tevent_req_post(req, ev);
-}
-
-static void tldap_sasl_bind_done(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct tldap_req_state *state = tevent_req_data(
-		req, struct tldap_req_state);
-	TLDAPRC rc;
-	bool ok;
-
-	rc = tldap_msg_recv(subreq, state, &state->result);
-	TALLOC_FREE(subreq);
-	if (tevent_req_ldap_error(req, rc)) {
-		return;
-	}
-	if (state->result->type != TLDAP_RES_BIND) {
-		tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
-		return;
-	}
-
-	ok = asn1_start_tag(state->result->data, TLDAP_RES_BIND);
-	ok &= tldap_decode_response(state);
-
-	if (asn1_peek_tag(state->result->data, ASN1_CONTEXT_SIMPLE(7))) {
-		int len;
-
-		ok &= asn1_start_tag(state->result->data,
-				     ASN1_CONTEXT_SIMPLE(7));
-		if (!ok) {
-			goto decode_error;
-		}
-
-		len = asn1_tag_remaining(state->result->data);
-		if (len == -1) {
-			goto decode_error;
-		}
-
-		state->result->res_serverSaslCreds =
-			data_blob_talloc(state->result, NULL, len);
-		if (state->result->res_serverSaslCreds.data == NULL) {
-			goto decode_error;
-		}
-
-		ok = asn1_read(state->result->data,
-			       state->result->res_serverSaslCreds.data,
-			       state->result->res_serverSaslCreds.length);
-
-		ok &= asn1_end_tag(state->result->data);
-	}
-
-	ok &= asn1_end_tag(state->result->data);
-
-	if (!ok) {
-		goto decode_error;
-	}
-
-	if (!TLDAP_RC_IS_SUCCESS(state->result->lderr) &&
-	    !TLDAP_RC_EQUAL(state->result->lderr,
-			    TLDAP_SASL_BIND_IN_PROGRESS)) {
-		tevent_req_ldap_error(req, state->result->lderr);
-		return;
-	}
-	tevent_req_done(req);
-	return;
-
-decode_error:
-	tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
-	return;
-}
-
-TLDAPRC tldap_sasl_bind_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-			     DATA_BLOB *serverSaslCreds)
-{
-	struct tldap_req_state *state = tevent_req_data(
-		req, struct tldap_req_state);
-	TLDAPRC rc;
-
-	if (tevent_req_is_ldap_error(req, &rc)) {
-		return rc;
-	}
-
-	if (serverSaslCreds != NULL) {
-		serverSaslCreds->data = talloc_move(
-			mem_ctx, &state->result->res_serverSaslCreds.data);
-		serverSaslCreds->length =
-			state->result->res_serverSaslCreds.length;
-	}
-
-	return state->result->lderr;
-}
-
-TLDAPRC tldap_sasl_bind(struct tldap_context *ld,
-			const char *dn,
-			const char *mechanism,
-			DATA_BLOB *creds,
-			struct tldap_control *sctrls,
-			int num_sctrls,
-			struct tldap_control *cctrls,
-			int num_cctrls,
-			TALLOC_CTX *mem_ctx,
-			DATA_BLOB *serverSaslCreds)
-{
-	TALLOC_CTX *frame = talloc_stackframe();
-	struct tevent_context *ev;
-	struct tevent_req *req;
-	TLDAPRC rc = TLDAP_NO_MEMORY;
-
-	ev = samba_tevent_context_init(frame);
-	if (ev == NULL) {
-		goto fail;
-	}
-	req = tldap_sasl_bind_send(frame, ev, ld, dn, mechanism, creds,
-				   sctrls, num_sctrls, cctrls, num_cctrls);
-	if (req == NULL) {
-		goto fail;
-	}
-	if (!tevent_req_poll(req, ev)) {
-		rc = TLDAP_OPERATIONS_ERROR;
-		goto fail;
-	}
-	rc = tldap_sasl_bind_recv(req, mem_ctx, serverSaslCreds);
-	tldap_save_msg(ld, req);
- fail:
-	TALLOC_FREE(frame);
-	return rc;
-}
-
-struct tevent_req *tldap_simple_bind_send(TALLOC_CTX *mem_ctx,
-					  struct tevent_context *ev,
-					  struct tldap_context *ld,
-					  const char *dn,
-					  const char *passwd)
-{
-	DATA_BLOB cred;
-
-	if (passwd != NULL) {
-		cred.data = discard_const_p(uint8_t, passwd);
-		cred.length = strlen(passwd);
-	} else {
-		cred.data = discard_const_p(uint8_t, "");
-		cred.length = 0;
-	}
-	return tldap_sasl_bind_send(mem_ctx, ev, ld, dn, NULL, &cred, NULL, 0,
-				    NULL, 0);
-}
-
-TLDAPRC tldap_simple_bind_recv(struct tevent_req *req)
-{
-	return tldap_sasl_bind_recv(req, NULL, NULL);
-}
-
-TLDAPRC tldap_simple_bind(struct tldap_context *ld, const char *dn,
-			  const char *passwd)
-{
-	DATA_BLOB cred;
-
-	if (passwd != NULL) {
-		cred.data = discard_const_p(uint8_t, passwd);
-		cred.length = strlen(passwd);
-	} else {
-		cred.data = discard_const_p(uint8_t, "");
-		cred.length = 0;
-	}
-	return tldap_sasl_bind(ld, dn, NULL, &cred, NULL, 0, NULL, 0,
-			       NULL, NULL);
-}
-
-/*****************************************************************************/
-
-/* can't use isalpha() as only a strict set is valid for LDAP */
-
-static bool tldap_is_alpha(char c)
-{
-	return (((c >= 'a') && (c <= 'z')) || \
-		((c >= 'A') && (c <= 'Z')));
-}
-
-static bool tldap_is_adh(char c)
-{
-	return tldap_is_alpha(c) || isdigit(c) || (c == '-');
-}
-
-#define TLDAP_FILTER_AND  ASN1_CONTEXT(0)
-#define TLDAP_FILTER_OR   ASN1_CONTEXT(1)
-#define TLDAP_FILTER_NOT  ASN1_CONTEXT(2)
-#define TLDAP_FILTER_EQ   ASN1_CONTEXT(3)
-#define TLDAP_FILTER_SUB  ASN1_CONTEXT(4)
-#define TLDAP_FILTER_LE   ASN1_CONTEXT(5)
-#define TLDAP_FILTER_GE   ASN1_CONTEXT(6)
-#define TLDAP_FILTER_PRES ASN1_CONTEXT_SIMPLE(7)
-#define TLDAP_FILTER_APX  ASN1_CONTEXT(8)
-#define TLDAP_FILTER_EXT  ASN1_CONTEXT(9)
-
-#define TLDAP_SUB_INI ASN1_CONTEXT_SIMPLE(0)
-#define TLDAP_SUB_ANY ASN1_CONTEXT_SIMPLE(1)
-#define TLDAP_SUB_FIN ASN1_CONTEXT_SIMPLE(2)
-
-
-/* oid's should be numerical only in theory,
- * but apparently some broken servers may have alphanum aliases instead.
- * Do like openldap libraries and allow alphanum aliases for oids, but
- * do not allow Tagging options in that case.
- */
-static bool tldap_is_attrdesc(const char *s, int len, bool no_tagopts)
-{
-	bool is_oid = false;
-	bool dot = false;
-	int i;
-
-	/* first char has stricter rules */
-	if (isdigit(*s)) {
-		is_oid = true;
-	} else if (!tldap_is_alpha(*s)) {
-		/* bad first char */
-		return false;
-	}
-
-	for (i = 1; i < len; i++) {
-
-		if (is_oid) {
-			if (isdigit(s[i])) {
-				dot = false;
-				continue;
-			}
-			if (s[i] == '.') {
-				if (dot) {
-					/* malformed */
-					return false;
-				}
-				dot = true;
-				continue;
-			}
-		} else {
-			if (tldap_is_adh(s[i])) {
-				continue;
-			}
-		}
-
-		if (s[i] == ';') {
-			if (no_tagopts) {
-				/* no tagging options */
-				return false;
-			}
-			if (dot) {
-				/* malformed */
-				return false;
-			}
-			if ((i + 1) == len) {
-				/* malformed */
-				return false;
-			}
-
-			is_oid = false;
-			continue;
-		}
-	}
-
-	if (dot) {
-		/* malformed */
-		return false;
-	}
-
-	return true;
-}
-
-/* this function copies the value until the closing parenthesis is found. */
-static char *tldap_get_val(TALLOC_CTX *memctx,
-			   const char *value, const char **_s)
-{
-	const char *s = value;
-
-	/* find terminator */
-	while (*s) {
-		s = strchr(s, ')');
-		if (s && (*(s - 1) == '\\')) {
-			continue;
-		}
-		break;
-	}
-	if (!s || !(*s == ')')) {
-		/* malformed filter */
-		return NULL;
-	}
-
-	*_s = s;
-
-	return talloc_strndup(memctx, value, s - value);
-}
-
-static int tldap_hex2char(const char *x)
-{
-	if (isxdigit(x[0]) && isxdigit(x[1])) {
-		const char h1 = x[0], h2 = x[1];
-		int c = 0;
-
-		if (h1 >= 'a') c = h1 - (int)'a' + 10;
-		else if (h1 >= 'A') c = h1 - (int)'A' + 10;
-		else if (h1 >= '0') c = h1 - (int)'0';
-		c = c << 4;
-		if (h2 >= 'a') c += h2 - (int)'a' + 10;
-		else if (h2 >= 'A') c += h2 - (int)'A' + 10;
-		else if (h2 >= '0') c += h2 - (int)'0';
-
-		return c;
-	}
-
-	return -1;
-}
-
-static bool tldap_find_first_star(const char *val, const char **star)
-{
-	const char *s;
-
-	for (s = val; *s; s++) {
-		switch (*s) {
-		case '\\':
-			if (isxdigit(s[1]) && isxdigit(s[2])) {
-				s += 2;
-				break;
-			}
-			/* not hex based escape, check older syntax */
-			switch (s[1]) {
-			case '(':
-			case ')':
-			case '*':
-			case '\\':
-				s++;
-				break;
-			default:
-				/* invalid escape sequence */
-				return false;
-			}
-			break;
-		case ')':
-			/* end of val, nothing found */
-			*star = s;
-			return true;
-
-		case '*':
-			*star = s;
-			return true;
-		}
-	}
-
-	/* string ended without closing parenthesis, filter is malformed */
-	return false;
-}
-
-static bool tldap_unescape_inplace(char *value, size_t *val_len)
-{
-	int c, i, p;
-
-	for (i = 0,p = 0; i < *val_len; i++) {
-
-		switch (value[i]) {
-		case '(':
-		case ')':
-		case '*':
-			/* these must be escaped */
-			return false;
-
-		case '\\':
-			if (!value[i + 1]) {
-				/* invalid EOL */
-				return false;
-			}
-			i++;
-
-			c = tldap_hex2char(&value[i]);
-			if (c >= 0 && c < 256) {
-				value[p] = c;
-				i++;
-				p++;
-				break;
-			}
-
-			switch (value[i]) {
-			case '(':
-			case ')':
-			case '*':
-			case '\\':
-				value[p] = value[i];
-				p++;
-			default:
-				/* invalid */
-				return false;
-			}
-			break;
-
-		default:
-			value[p] = value[i];
-			p++;
-		}
-	}
-	value[p] = '\0';
-	*val_len = p;
-	return true;
-}
-
-static bool tldap_push_filter_basic(struct tldap_context *ld,
-				    struct asn1_data *data,
-				    const char **_s);
-static bool tldap_push_filter_substring(struct tldap_context *ld,
-					struct asn1_data *data,
-					const char *val,
-					const char **_s);
-static bool tldap_push_filter_int(struct tldap_context *ld,
-				  struct asn1_data *data,
-				  const char **_s)
-{
-	const char *s = *_s;
-	bool ret;
-
-	if (*s != '(') {
-		tldap_debug(ld, TLDAP_DEBUG_ERROR,
-			    "Incomplete or malformed filter\n");
-		return false;
-	}
-	s++;
-
-	/* we are right after a parenthesis,
-	 * find out what op we have at hand */
-	switch (*s) {
-	case '&':
-		tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: AND\n");
-		if (!asn1_push_tag(data, TLDAP_FILTER_AND)) return false;
-		s++;
-		break;
-
-	case '|':
-		tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: OR\n");
-		if (!asn1_push_tag(data, TLDAP_FILTER_OR)) return false;
-		s++;
-		break;
-
-	case '!':
-		tldap_debug(ld, TLDAP_DEBUG_TRACE, "Filter op: NOT\n");
-		if (!asn1_push_tag(data, TLDAP_FILTER_NOT)) return false;
-		s++;
-		ret = tldap_push_filter_int(ld, data, &s);
-		if (!ret) {
-			return false;
-		}
-		if (!asn1_pop_tag(data)) return false;
-		goto done;
-
-	case '(':
-	case ')':
-		tldap_debug(ld, TLDAP_DEBUG_ERROR,
-			    "Invalid parenthesis '%c'\n", *s);
-		return false;
-
-	case '\0':
-		tldap_debug(ld, TLDAP_DEBUG_ERROR,
-			    "Invalid filter termination\n");
-		return false;
-
-	default:
-		ret = tldap_push_filter_basic(ld, data, &s);
-		if (!ret) {
-			return false;
-		}
-		goto done;
-	}
-
-	/* only and/or filters get here.
-	 * go through the list of filters */
-
-	if (*s == ')') {
-		/* RFC 4526: empty and/or */
-		if (!asn1_pop_tag(data)) return false;
-		goto done;
-	}
-
-	while (*s) {
-		ret = tldap_push_filter_int(ld, data, &s);
-		if (!ret) {
-			return false;
-		}
-
-		if (*s == ')') {
-			/* end of list, return */
-			if (!asn1_pop_tag(data)) return false;
-			break;
-		}
-	}
-
-done:
-	if (*s != ')') {
-		tldap_debug(ld, TLDAP_DEBUG_ERROR,
-			    "Incomplete or malformed filter\n");
-		return false;
-	}
-	s++;
-
-	if (asn1_has_error(data)) {
-		return false;
-	}
-
-	*_s = s;
-	return true;
-}
-
-
-static bool tldap_push_filter_basic(struct tldap_context *ld,
-				    struct asn1_data *data,
-				    const char **_s)
-{
-	TALLOC_CTX *tmpctx = talloc_tos();
-	const char *s = *_s;
-	const char *e;
-	const char *eq;
-	const char *val;
-	const char *type;
-	const char *dn;
-	const char *rule;
-	const char *star;
-	size_t type_len = 0;
-	char *uval;
-	size_t uval_len;
-	bool write_octect = true;
-	bool ret;
-
-	eq = strchr(s, '=');
-	if (!eq) {
-		tldap_debug(ld, TLDAP_DEBUG_ERROR,
-			    "Invalid filter, missing equal sign\n");
-		return false;
-	}
-
-	val = eq + 1;
-	e = eq - 1;
-
-	switch (*e) {
-	case '<':
-		if (!asn1_push_tag(data, TLDAP_FILTER_LE)) return false;
-		break;
-
-	case '>':
-		if (!asn1_push_tag(data, TLDAP_FILTER_GE)) return false;
-		break;
-
-	case '~':
-		if (!asn1_push_tag(data, TLDAP_FILTER_APX)) return false;
-		break;
-
-	case ':':
-		if (!asn1_push_tag(data, TLDAP_FILTER_EXT)) return false;
-		write_octect = false;
-
-		type = NULL;
-		dn = NULL;
-		rule = NULL;
-
-		if (*s == ':') { /* [:dn]:rule:= value */
-			if (s == e) {
-				/* malformed filter */
-				return false;
-			}
-			dn = s;
-		} else { /* type[:dn][:rule]:= value */
-			type = s;
-			dn = strchr(s, ':');
-			type_len = dn - type;
-			if (dn == e) { /* type:= value */
-				dn = NULL;
-			}
-		}
-		if (dn) {
-			dn++;
-
-			rule = strchr(dn, ':');
-			if (rule == NULL) {
-				return false;
-			}
-			if ((rule == dn + 1) || rule + 1 == e) {
-				/* malformed filter, contains "::" */
-				return false;
-			}
-
-			if (strncasecmp_m(dn, "dn:", 3) != 0) {
-				if (rule == e) {
-					rule = dn;
-					dn = NULL;
-				} else {
-					/* malformed filter. With two
-					 * optionals, the first must be "dn"
-					 */
-					return false;
-				}
-			} else {
-				if (rule == e) {
-					rule = NULL;
-				} else {
-					rule++;
-				}
-			}
-		}
-
-		if (!type && !dn && !rule) {
-			/* malformed filter, there must be at least one */
-			return false;
-		}
-
-		/*
-		  MatchingRuleAssertion ::= SEQUENCE {
-		  matchingRule    [1] MatchingRuleID OPTIONAL,
-		  type	    [2] AttributeDescription OPTIONAL,
-		  matchValue      [3] AssertionValue,
-		  dnAttributes    [4] BOOLEAN DEFAULT FALSE
-		  }
-		*/
-
-		/* check and add rule */
-		if (rule) {
-			ret = tldap_is_attrdesc(rule, e - rule, true);
-			if (!ret) {
-				return false;
-			}
-			if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(1))) return false;
-			if (!asn1_write(data, rule, e - rule)) return false;
-			if (!asn1_pop_tag(data)) return false;
-		}
-
-		/* check and add type */
-		if (type) {
-			ret = tldap_is_attrdesc(type, type_len, false);
-			if (!ret) {
-				return false;
-			}
-			if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(2))) return false;
-			if (!asn1_write(data, type, type_len)) return false;
-			if (!asn1_pop_tag(data)) return false;
-		}
-
-		uval = tldap_get_val(tmpctx, val, _s);
-		if (!uval) {
-			return false;
-		}
-		uval_len = *_s - val;
-		ret = tldap_unescape_inplace(uval, &uval_len);
-		if (!ret) {
-			return false;
-		}
-
-		if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(3))) return false;
-		if (!asn1_write(data, uval, uval_len)) return false;
-		if (!asn1_pop_tag(data)) return false;
-
-		if (!asn1_push_tag(data, ASN1_CONTEXT_SIMPLE(4))) return false;
-		if (!asn1_write_uint8(data, dn?1:0)) return false;
-		if (!asn1_pop_tag(data)) return false;
-		break;
-
-	default:
-		e = eq;
-
-		ret = tldap_is_attrdesc(s, e - s, false);
-		if (!ret) {
-			return false;
-		}
-
-		if (strncmp(val, "*)", 2) == 0) {
-			/* presence */
-			if (!asn1_push_tag(data, TLDAP_FILTER_PRES)) return false;
-			if (!asn1_write(data, s, e - s)) return false;
-			*_s = val + 1;
-			write_octect = false;
-			break;
-		}
-
-		ret = tldap_find_first_star(val, &star);
-		if (!ret) {
-			return false;
-		}
-		if (*star == '*') {
-			/* substring */
-			if (!asn1_push_tag(data, TLDAP_FILTER_SUB)) return false;
-			if (!asn1_write_OctetString(data, s, e - s)) return false;
-			ret = tldap_push_filter_substring(ld, data, val, &s);
-			if (!ret) {
-				return false;
-			}
-			*_s = s;
-			write_octect = false;
-			break;
-		}
-
-		/* if nothing else, then it is just equality */
-		if (!asn1_push_tag(data, TLDAP_FILTER_EQ)) return false;
-		write_octect = true;
-		break;
-	}
-
-	if (write_octect) {
-		uval = tldap_get_val(tmpctx, val, _s);
-		if (!uval) {
-			return false;
-		}
-		uval_len = *_s - val;
-		ret = tldap_unescape_inplace(uval, &uval_len);
-		if (!ret) {
-			return false;
-		}
-
-		if (!asn1_write_OctetString(data, s, e - s)) return false;
-		if (!asn1_write_OctetString(data, uval, uval_len)) return false;
-	}
-
-	if (asn1_has_error(data)) {
-		return false;
-	}
-	return asn1_pop_tag(data);
-}
-
-static bool tldap_push_filter_substring(struct tldap_context *ld,
-					struct asn1_data *data,
-					const char *val,
-					const char **_s)
-{
-	TALLOC_CTX *tmpctx = talloc_tos();
-	bool initial = true;
-	const char *star;
-	char *chunk;
-	size_t chunk_len;
-	bool ret;
-
-	/*
-	  SubstringFilter ::= SEQUENCE {
-		  type	    AttributeDescription,
-		  -- at least one must be present
-		  substrings      SEQUENCE OF CHOICE {
-			  initial [0] LDAPString,
-			  any     [1] LDAPString,
-			  final   [2] LDAPString } }
-	*/
-	if (!asn1_push_tag(data, ASN1_SEQUENCE(0))) return false;
-
-	do {
-		ret = tldap_find_first_star(val, &star);
-		if (!ret) {
-			return false;
-		}
-		chunk_len = star - val;
-
-		switch (*star) {
-		case '*':
-			if (!initial && chunk_len == 0) {
-				/* found '**', which is illegal */
-				return false;
-			}
-			break;
-		case ')':
-			if (initial) {
-				/* no stars ?? */
-				return false;
-			}
-			/* we are done */
-			break;
-		default:
-			/* ?? */
-			return false;
-		}
-
-		if (initial && chunk_len == 0) {
-			val = star + 1;
-			initial = false;
-			continue;
-		}
-
-		chunk = talloc_strndup(tmpctx, val, chunk_len);
-		if (!chunk) {
-			return false;
-		}
-		ret = tldap_unescape_inplace(chunk, &chunk_len);
-		if (!ret) {
-			return false;
-		}
-		switch (*star) {
-		case '*':
-			if (initial) {
-				if (!asn1_push_tag(data, TLDAP_SUB_INI)) return false;
-				initial = false;
-			} else {
-				if (!asn1_push_tag(data, TLDAP_SUB_ANY)) return false;
-			}
-			break;
-		case ')':
-			if (!asn1_push_tag(data, TLDAP_SUB_FIN)) return false;
-			break;
-		default:
-			/* ?? */
-			return false;
-		}
-		if (!asn1_write(data, chunk, chunk_len)) return false;
-		if (!asn1_pop_tag(data)) return false;
-
-		val = star + 1;
-
-	} while (*star == '*');
-
-	*_s = star;
-
-	/* end of sequence */
-	return asn1_pop_tag(data);
-}
-
-/* NOTE: although openldap libraries allow for spaces in some places, mosly
- * around parenthesis, we do not allow any spaces (except in values of
- * course) as I couldn't fine any place in RFC 4512 or RFC 4515 where
- * leading or trailing spaces where allowed.
- */
-static bool tldap_push_filter(struct tldap_context *ld,
-			      struct asn1_data *data,
-			      const char *filter)
-{
-	const char *s = filter;
-	bool ret;
-
-	ret = tldap_push_filter_int(ld, data, &s);
-	if (ret && *s) {
-		tldap_debug(ld, TLDAP_DEBUG_ERROR,
-			    "Incomplete or malformed filter\n");
-		return false;
-	}
-	return ret;
-}
-
-/*****************************************************************************/
-
-static void tldap_search_done(struct tevent_req *subreq);
-
-struct tevent_req *tldap_search_send(TALLOC_CTX *mem_ctx,
-				     struct tevent_context *ev,
-				     struct tldap_context *ld,
-				     const char *base, int scope,
-				     const char *filter,
-				     const char **attrs,
-				     int num_attrs,
-				     int attrsonly,
-				     struct tldap_control *sctrls,
-				     int num_sctrls,
-				     struct tldap_control *cctrls,
-				     int num_cctrls,
-				     int timelimit,
-				     int sizelimit,
-				     int deref)
-{
-	struct tevent_req *req, *subreq;
-	struct tldap_req_state *state;
-	int i;
-
-	req = tldap_req_create(mem_ctx, ld, &state);
-	if (req == NULL) {
-		return NULL;
-	}
-
-	if (!asn1_push_tag(state->out, TLDAP_REQ_SEARCH)) goto encoding_error;
-	if (!asn1_write_OctetString(state->out, base, strlen(base))) goto encoding_error;
-	if (!asn1_write_enumerated(state->out, scope)) goto encoding_error;
-	if (!asn1_write_enumerated(state->out, deref)) goto encoding_error;
-	if (!asn1_write_Integer(state->out, sizelimit)) goto encoding_error;
-	if (!asn1_write_Integer(state->out, timelimit)) goto encoding_error;
-	if (!asn1_write_BOOLEAN(state->out, attrsonly)) goto encoding_error;
-
-	if (!tldap_push_filter(ld, state->out, filter)) {
-		goto encoding_error;
-	}
-
-	if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto encoding_error;
-	for (i=0; i<num_attrs; i++) {
-		if (!asn1_write_OctetString(state->out, attrs[i], strlen(attrs[i]))) goto encoding_error;
-	}
-	if (!asn1_pop_tag(state->out)) goto encoding_error;
-	if (!asn1_pop_tag(state->out)) goto encoding_error;
-
-	subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
-				sctrls, num_sctrls);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(subreq, tldap_search_done, req);
-	return req;
-
- encoding_error:
-	tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
-	return tevent_req_post(req, ev);
-}
-
-static void tldap_search_done(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct tldap_req_state *state = tevent_req_data(
-		req, struct tldap_req_state);
-	TLDAPRC rc;
-
-	rc = tldap_msg_recv(subreq, state, &state->result);
-	if (tevent_req_ldap_error(req, rc)) {
-		return;
-	}
-	switch (state->result->type) {
-	case TLDAP_RES_SEARCH_ENTRY:
-	case TLDAP_RES_SEARCH_REFERENCE:
-		if (!tldap_msg_set_pending(subreq)) {
-			tevent_req_oom(req);
-			return;
-		}
-		tevent_req_notify_callback(req);
-		break;
-	case TLDAP_RES_SEARCH_RESULT:
-		TALLOC_FREE(subreq);
-		if (!asn1_start_tag(state->result->data,
-				    state->result->type) ||
-		    !tldap_decode_response(state) ||
-		    !asn1_end_tag(state->result->data) ||
-		    !tldap_decode_controls(state)) {
-			tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
-			return;
-		}
-		tevent_req_done(req);
-		break;
-	default:
-		tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
-		return;
-	}
-}
-
-TLDAPRC tldap_search_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-			  struct tldap_message **pmsg)
-{
-	struct tldap_req_state *state = tevent_req_data(
-		req, struct tldap_req_state);
-	TLDAPRC rc;
-
-	if (!tevent_req_is_in_progress(req)
-	    && tevent_req_is_ldap_error(req, &rc)) {
-		return rc;
-	}
-
-	if (tevent_req_is_in_progress(req)) {
-		switch (state->result->type) {
-		case TLDAP_RES_SEARCH_ENTRY:
-		case TLDAP_RES_SEARCH_REFERENCE:
-			break;
-		default:
-			return TLDAP_OPERATIONS_ERROR;
-		}
-	}
-
-	*pmsg = talloc_move(mem_ctx, &state->result);
-	return TLDAP_SUCCESS;
-}
-
-struct tldap_search_all_state {
-	struct tldap_message **msgs;
-	struct tldap_message *result;
-};
-
-static void tldap_search_all_done(struct tevent_req *subreq);
-
-struct tevent_req *tldap_search_all_send(
-	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-	struct tldap_context *ld, const char *base, int scope,
-	const char *filter, const char **attrs, int num_attrs, int attrsonly,
-	struct tldap_control *sctrls, int num_sctrls,
-	struct tldap_control *cctrls, int num_cctrls,
-	int timelimit, int sizelimit, int deref)
-{
-	struct tevent_req *req, *subreq;
-	struct tldap_search_all_state *state;
-
-	req = tevent_req_create(mem_ctx, &state,
-				struct tldap_search_all_state);
-	if (req == NULL) {
-		return NULL;
-	}
-
-	subreq = tldap_search_send(state, ev, ld, base, scope, filter,
-				   attrs, num_attrs, attrsonly,
-				   sctrls, num_sctrls, cctrls, num_cctrls,
-				   timelimit, sizelimit, deref);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(subreq, tldap_search_all_done, req);
-	return req;
-}
-
-static void tldap_search_all_done(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct tldap_search_all_state *state = tevent_req_data(
-		req, struct tldap_search_all_state);
-	struct tldap_message *msg, **tmp;
-	size_t num_msgs;
-	TLDAPRC rc;
-	int msgtype;
-
-	rc = tldap_search_recv(subreq, state, &msg);
-	/* No TALLOC_FREE(subreq), this is multi-step */
-	if (tevent_req_ldap_error(req, rc)) {
-		TALLOC_FREE(subreq);
-		return;
-	}
-
-	msgtype = tldap_msg_type(msg);
-	if (msgtype == TLDAP_RES_SEARCH_RESULT) {
-		state->result = msg;
-		tevent_req_done(req);
-		return;
-	}
-
-	num_msgs = talloc_array_length(state->msgs);
-
-	tmp = talloc_realloc(state, state->msgs, struct tldap_message *,
-			     num_msgs + 1);
-	if (tevent_req_nomem(tmp, req)) {
-		return;
-	}
-	state->msgs = tmp;
-	state->msgs[num_msgs] = talloc_move(state->msgs, &msg);
-}
-
-TLDAPRC tldap_search_all_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-			      struct tldap_message ***msgs,
-			      struct tldap_message **result)
-{
-	struct tldap_search_all_state *state = tevent_req_data(
-		req, struct tldap_search_all_state);
-	TLDAPRC rc;
-
-	if (tevent_req_is_ldap_error(req, &rc)) {
-		return rc;
-	}
-
-	if (msgs != NULL) {
-		*msgs = talloc_move(mem_ctx, &state->msgs);
-	}
-	if (result != NULL) {
-		*result = talloc_move(mem_ctx, &state->result);
-	}
-
-	return TLDAP_SUCCESS;
-}
-
-TLDAPRC tldap_search(struct tldap_context *ld,
-		     const char *base, int scope, const char *filter,
-		     const char **attrs, int num_attrs, int attrsonly,
-		     struct tldap_control *sctrls, int num_sctrls,
-		     struct tldap_control *cctrls, int num_cctrls,
-		     int timelimit, int sizelimit, int deref,
-		     TALLOC_CTX *mem_ctx, struct tldap_message ***pmsgs)
-{
-	TALLOC_CTX *frame;
-	struct tevent_context *ev;
-	struct tevent_req *req;
-	TLDAPRC rc = TLDAP_NO_MEMORY;
-	struct tldap_message **msgs;
-	struct tldap_message *result;
-
-	if (tldap_pending_reqs(ld)) {
-		return TLDAP_BUSY;
-	}
-
-	frame = talloc_stackframe();
-
-	ev = samba_tevent_context_init(frame);
-	if (ev == NULL) {
-		goto fail;
-	}
-	req = tldap_search_all_send(frame, ev, ld, base, scope, filter,
-				    attrs, num_attrs, attrsonly,
-				    sctrls, num_sctrls, cctrls, num_cctrls,
-				    timelimit, sizelimit, deref);
-	if (req == NULL) {
-		goto fail;
-	}
-	if (!tevent_req_poll(req, ev)) {
-		rc = TLDAP_OPERATIONS_ERROR;
-		goto fail;
-	}
-	rc = tldap_search_all_recv(req, mem_ctx, &msgs, &result);
-	TALLOC_FREE(req);
-	if (!TLDAP_RC_IS_SUCCESS(rc)) {
-		goto fail;
-	}
-
-	TALLOC_FREE(ld->last_msg);
-	ld->last_msg = talloc_move(ld, &result);
-
-	*pmsgs = msgs;
-fail:
-	TALLOC_FREE(frame);
-	return rc;
-}
-
-static bool tldap_parse_search_entry(struct tldap_message *msg)
-{
-	int num_attribs = 0;
-
-	if (msg->type != TLDAP_RES_SEARCH_ENTRY) {
-		return false;
-	}
-	if (!asn1_start_tag(msg->data, TLDAP_RES_SEARCH_ENTRY)) {
-		return false;
-	}
-
-	/* dn */
-
-	if (!asn1_read_OctetString_talloc(msg, msg->data, &msg->dn)) return false;
-
-	if (msg->dn == NULL) {
-		return false;
-	}
-
-	/*
-	 * Attributes: We overallocate msg->attribs by one, so that while
-	 * looping over the attributes we can directly parse into the last
-	 * array element. Same for the values in the inner loop.
-	 */
-
-	msg->attribs = talloc_array(msg, struct tldap_attribute, 1);
-	if (msg->attribs == NULL) {
-		return false;
-	}
-
-	if (!asn1_start_tag(msg->data, ASN1_SEQUENCE(0))) return false;
-	while (asn1_peek_tag(msg->data, ASN1_SEQUENCE(0))) {
-		struct tldap_attribute *attrib;
-		int num_values = 0;
-
-		attrib = &msg->attribs[num_attribs];
-		attrib->values = talloc_array(msg->attribs, DATA_BLOB, 1);
-		if (attrib->values == NULL) {
-			return false;
-		}
-		if (!asn1_start_tag(msg->data, ASN1_SEQUENCE(0))) return false;
-		if (!asn1_read_OctetString_talloc(msg->attribs, msg->data,
-					     &attrib->name)) return false;
-		if (!asn1_start_tag(msg->data, ASN1_SET)) return false;
-
-		while (asn1_peek_tag(msg->data, ASN1_OCTET_STRING)) {
-			if (!asn1_read_OctetString(msg->data, msg,
-					      &attrib->values[num_values])) return false;
-
-			attrib->values = talloc_realloc(
-				msg->attribs, attrib->values, DATA_BLOB,
-				num_values + 2);
-			if (attrib->values == NULL) {
-				return false;
-			}
-			num_values += 1;
-		}
-		attrib->values = talloc_realloc(msg->attribs, attrib->values,
-						DATA_BLOB, num_values);
-		attrib->num_values = num_values;
-
-		if (!asn1_end_tag(msg->data)) return false; /* ASN1_SET */
-		if (!asn1_end_tag(msg->data)) return false; /* ASN1_SEQUENCE(0) */
-		msg->attribs = talloc_realloc(
-			msg, msg->attribs, struct tldap_attribute,
-			num_attribs + 2);
-		if (msg->attribs == NULL) {
-			return false;
-		}
-		num_attribs += 1;
-	}
-	msg->attribs = talloc_realloc(
-		msg, msg->attribs, struct tldap_attribute, num_attribs);
-	return asn1_end_tag(msg->data);
-}
-
-bool tldap_entry_dn(struct tldap_message *msg, char **dn)
-{
-	if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
-		return false;
-	}
-	*dn = msg->dn;
-	return true;
-}
-
-bool tldap_entry_attributes(struct tldap_message *msg,
-			    struct tldap_attribute **attributes,
-			    int *num_attributes)
-{
-	if ((msg->dn == NULL) && (!tldap_parse_search_entry(msg))) {
-		return false;
-	}
-	*attributes = msg->attribs;
-	*num_attributes = talloc_array_length(msg->attribs);
-	return true;
-}
-
-static bool tldap_decode_controls(struct tldap_req_state *state)
-{
-	struct tldap_message *msg = state->result;
-	struct asn1_data *data = msg->data;
-	struct tldap_control *sctrls = NULL;
-	int num_controls = 0;
-	bool ret = false;
-
-	msg->res_sctrls = NULL;
-
-	if (!asn1_peek_tag(data, ASN1_CONTEXT(0))) {
-		return true;
-	}
-
-	if (!asn1_start_tag(data, ASN1_CONTEXT(0))) goto out;
-
-	while (asn1_peek_tag(data, ASN1_SEQUENCE(0))) {
-		struct tldap_control *c;
-		char *oid = NULL;
-
-		sctrls = talloc_realloc(msg, sctrls, struct tldap_control,
-					num_controls + 1);
-		if (sctrls == NULL) {
-			goto out;
-		}
-		c = &sctrls[num_controls];
-
-		if (!asn1_start_tag(data, ASN1_SEQUENCE(0))) goto out;
-		if (!asn1_read_OctetString_talloc(msg, data, &oid)) goto out;
-		if (asn1_has_error(data) || (oid == NULL)) {
-			goto out;
-		}
-		c->oid = oid;
-		if (asn1_peek_tag(data, ASN1_BOOLEAN)) {
-			if (!asn1_read_BOOLEAN(data, &c->critical)) goto out;
-		} else {
-			c->critical = false;
-		}
-		c->value = data_blob_null;
-		if (asn1_peek_tag(data, ASN1_OCTET_STRING) &&
-		    !asn1_read_OctetString(data, msg, &c->value)) {
-			goto out;
-		}
-		if (!asn1_end_tag(data)) goto out; /* ASN1_SEQUENCE(0) */
-
-		num_controls += 1;
-	}
-
-	if (!asn1_end_tag(data)) goto out; 	/* ASN1_CONTEXT(0) */
-
-	ret = true;
-
- out:
-
-	if (ret) {
-		msg->res_sctrls = sctrls;
-	} else {
-		TALLOC_FREE(sctrls);
-	}
-	return ret;
-}
-
-static void tldap_simple_done(struct tevent_req *subreq, int type)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct tldap_req_state *state = tevent_req_data(
-		req, struct tldap_req_state);
-	TLDAPRC rc;
-
-	rc = tldap_msg_recv(subreq, state, &state->result);
-	TALLOC_FREE(subreq);
-	if (tevent_req_ldap_error(req, rc)) {
-		return;
-	}
-	if (state->result->type != type) {
-		tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
-		return;
-	}
-	if (!asn1_start_tag(state->result->data, state->result->type) ||
-	    !tldap_decode_response(state) ||
-	    !asn1_end_tag(state->result->data) ||
-	    !tldap_decode_controls(state)) {
-		tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
-		return;
-	}
-	if (!TLDAP_RC_IS_SUCCESS(state->result->lderr)) {
-		tevent_req_ldap_error(req, state->result->lderr);
-		return;
-	}
-	tevent_req_done(req);
-}
-
-static TLDAPRC tldap_simple_recv(struct tevent_req *req)
-{
-	TLDAPRC rc;
-	if (tevent_req_is_ldap_error(req, &rc)) {
-		return rc;
-	}
-	return TLDAP_SUCCESS;
-}
-
-static void tldap_add_done(struct tevent_req *subreq);
-
-struct tevent_req *tldap_add_send(TALLOC_CTX *mem_ctx,
-				  struct tevent_context *ev,
-				  struct tldap_context *ld,
-				  const char *dn,
-				  struct tldap_mod *attributes,
-				  int num_attributes,
-				  struct tldap_control *sctrls,
-				  int num_sctrls,
-				  struct tldap_control *cctrls,
-				  int num_cctrls)
-{
-	struct tevent_req *req, *subreq;
-	struct tldap_req_state *state;
-	int i, j;
-
-	req = tldap_req_create(mem_ctx, ld, &state);
-	if (req == NULL) {
-		return NULL;
-	}
-
-	if (!asn1_push_tag(state->out, TLDAP_REQ_ADD)) goto err;
-	if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
-	if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
-
-	for (i=0; i<num_attributes; i++) {
-		struct tldap_mod *attrib = &attributes[i];
-		if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
-		if (!asn1_write_OctetString(state->out, attrib->attribute,
-				       strlen(attrib->attribute))) goto err;
-		if (!asn1_push_tag(state->out, ASN1_SET)) goto err;
-		for (j=0; j<attrib->num_values; j++) {
-			if (!asn1_write_OctetString(state->out,
-					       attrib->values[j].data,
-					       attrib->values[j].length)) goto err;
-		}
-		if (!asn1_pop_tag(state->out)) goto err;
-		if (!asn1_pop_tag(state->out)) goto err;
-	}
-
-	if (!asn1_pop_tag(state->out)) goto err;
-	if (!asn1_pop_tag(state->out)) goto err;
-
-	subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
-				sctrls, num_sctrls);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(subreq, tldap_add_done, req);
-	return req;
-
-  err:
-
-	tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
-	return tevent_req_post(req, ev);
-}
-
-static void tldap_add_done(struct tevent_req *subreq)
-{
-	tldap_simple_done(subreq, TLDAP_RES_ADD);
-}
-
-TLDAPRC tldap_add_recv(struct tevent_req *req)
-{
-	return tldap_simple_recv(req);
-}
-
-TLDAPRC tldap_add(struct tldap_context *ld, const char *dn,
-		  struct tldap_mod *attributes, int num_attributes,
-		  struct tldap_control *sctrls, int num_sctrls,
-		  struct tldap_control *cctrls, int num_cctrls)
-{
-	TALLOC_CTX *frame = talloc_stackframe();
-	struct tevent_context *ev;
-	struct tevent_req *req;
-	TLDAPRC rc = TLDAP_NO_MEMORY;
-
-	ev = samba_tevent_context_init(frame);
-	if (ev == NULL) {
-		goto fail;
-	}
-	req = tldap_add_send(frame, ev, ld, dn, attributes, num_attributes,
-			     sctrls, num_sctrls, cctrls, num_cctrls);
-	if (req == NULL) {
-		goto fail;
-	}
-	if (!tevent_req_poll(req, ev)) {
-		rc = TLDAP_OPERATIONS_ERROR;
-		goto fail;
-	}
-	rc = tldap_add_recv(req);
-	tldap_save_msg(ld, req);
- fail:
-	TALLOC_FREE(frame);
-	return rc;
-}
-
-static void tldap_modify_done(struct tevent_req *subreq);
-
-struct tevent_req *tldap_modify_send(TALLOC_CTX *mem_ctx,
-				     struct tevent_context *ev,
-				     struct tldap_context *ld,
-				     const char *dn,
-				     struct tldap_mod *mods, int num_mods,
-				     struct tldap_control *sctrls,
-				     int num_sctrls,
-				     struct tldap_control *cctrls,
-				     int num_cctrls)
-{
-	struct tevent_req *req, *subreq;
-	struct tldap_req_state *state;
-	int i, j;
-
-	req = tldap_req_create(mem_ctx, ld, &state);
-	if (req == NULL) {
-		return NULL;
-	}
-
-	if (!asn1_push_tag(state->out, TLDAP_REQ_MODIFY)) goto err;
-	if (!asn1_write_OctetString(state->out, dn, strlen(dn))) goto err;
-	if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
-
-	for (i=0; i<num_mods; i++) {
-		struct tldap_mod *mod = &mods[i];
-		if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
-		if (!asn1_write_enumerated(state->out, mod->mod_op)) goto err;
-		if (!asn1_push_tag(state->out, ASN1_SEQUENCE(0))) goto err;
-		if (!asn1_write_OctetString(state->out, mod->attribute,
-				       strlen(mod->attribute))) goto err;
-		if (!asn1_push_tag(state->out, ASN1_SET)) goto err;
-		for (j=0; j<mod->num_values; j++) {
-			if (!asn1_write_OctetString(state->out,
-					       mod->values[j].data,
-					       mod->values[j].length)) goto err;
-		}
-		if (!asn1_pop_tag(state->out)) goto err;
-		if (!asn1_pop_tag(state->out)) goto err;
-		if (!asn1_pop_tag(state->out)) goto err;
-	}
-
-	if (!asn1_pop_tag(state->out)) goto err;
-	if (!asn1_pop_tag(state->out)) goto err;
-
-	subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
-				sctrls, num_sctrls);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(subreq, tldap_modify_done, req);
-	return req;
-
-  err:
-
-	tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
-	return tevent_req_post(req, ev);
-}
-
-static void tldap_modify_done(struct tevent_req *subreq)
-{
-	tldap_simple_done(subreq, TLDAP_RES_MODIFY);
-}
-
-TLDAPRC tldap_modify_recv(struct tevent_req *req)
-{
-	return tldap_simple_recv(req);
-}
-
-TLDAPRC tldap_modify(struct tldap_context *ld, const char *dn,
-		     struct tldap_mod *mods, int num_mods,
-		     struct tldap_control *sctrls, int num_sctrls,
-		     struct tldap_control *cctrls, int num_cctrls)
- {
-	TALLOC_CTX *frame = talloc_stackframe();
-	struct tevent_context *ev;
-	struct tevent_req *req;
-	TLDAPRC rc = TLDAP_NO_MEMORY;
-
-	ev = samba_tevent_context_init(frame);
-	if (ev == NULL) {
-		goto fail;
-	}
-	req = tldap_modify_send(frame, ev, ld, dn, mods, num_mods,
-				sctrls, num_sctrls, cctrls, num_cctrls);
-	if (req == NULL) {
-		goto fail;
-	}
-	if (!tevent_req_poll(req, ev)) {
-		rc = TLDAP_OPERATIONS_ERROR;
-		goto fail;
-	}
-	rc = tldap_modify_recv(req);
-	tldap_save_msg(ld, req);
- fail:
-	TALLOC_FREE(frame);
-	return rc;
-}
-
-static void tldap_delete_done(struct tevent_req *subreq);
-
-struct tevent_req *tldap_delete_send(TALLOC_CTX *mem_ctx,
-				     struct tevent_context *ev,
-				     struct tldap_context *ld,
-				     const char *dn,
-				     struct tldap_control *sctrls,
-				     int num_sctrls,
-				     struct tldap_control *cctrls,
-				     int num_cctrls)
-{
-	struct tevent_req *req, *subreq;
-	struct tldap_req_state *state;
-
-	req = tldap_req_create(mem_ctx, ld, &state);
-	if (req == NULL) {
-		return NULL;
-	}
-
-	if (!asn1_push_tag(state->out, TLDAP_REQ_DELETE)) goto err;
-	if (!asn1_write(state->out, dn, strlen(dn))) goto err;
-	if (!asn1_pop_tag(state->out)) goto err;
-
-	subreq = tldap_msg_send(state, ev, ld, state->id, state->out,
-				sctrls, num_sctrls);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(subreq, tldap_delete_done, req);
-	return req;
-
-  err:
-
-	tevent_req_ldap_error(req, TLDAP_ENCODING_ERROR);
-	return tevent_req_post(req, ev);
-}
-
-static void tldap_delete_done(struct tevent_req *subreq)
-{
-	tldap_simple_done(subreq, TLDAP_RES_DELETE);
-}
-
-TLDAPRC tldap_delete_recv(struct tevent_req *req)
-{
-	return tldap_simple_recv(req);
-}
-
-TLDAPRC tldap_delete(struct tldap_context *ld, const char *dn,
-		     struct tldap_control *sctrls, int num_sctrls,
-		     struct tldap_control *cctrls, int num_cctrls)
-{
-	TALLOC_CTX *frame = talloc_stackframe();
-	struct tevent_context *ev;
-	struct tevent_req *req;
-	TLDAPRC rc = TLDAP_NO_MEMORY;
-
-	ev = samba_tevent_context_init(frame);
-	if (ev == NULL) {
-		goto fail;
-	}
-	req = tldap_delete_send(frame, ev, ld, dn, sctrls, num_sctrls,
-				cctrls, num_cctrls);
-	if (req == NULL) {
-		goto fail;
-	}
-	if (!tevent_req_poll(req, ev)) {
-		rc = TLDAP_OPERATIONS_ERROR;
-		goto fail;
-	}
-	rc = tldap_delete_recv(req);
-	tldap_save_msg(ld, req);
- fail:
-	TALLOC_FREE(frame);
-	return rc;
-}
-
-int tldap_msg_id(const struct tldap_message *msg)
-{
-	return msg->id;
-}
-
-int tldap_msg_type(const struct tldap_message *msg)
-{
-	return msg->type;
-}
-
-const char *tldap_msg_matcheddn(struct tldap_message *msg)
-{
-	if (msg == NULL) {
-		return NULL;
-	}
-	return msg->res_matcheddn;
-}
-
-const char *tldap_msg_diagnosticmessage(struct tldap_message *msg)
-{
-	if (msg == NULL) {
-		return NULL;
-	}
-	return msg->res_diagnosticmessage;
-}
-
-const char *tldap_msg_referral(struct tldap_message *msg)
-{
-	if (msg == NULL) {
-		return NULL;
-	}
-	return msg->res_referral;
-}
-
-void tldap_msg_sctrls(struct tldap_message *msg, int *num_sctrls,
-		      struct tldap_control **sctrls)
-{
-	if (msg == NULL) {
-		*sctrls = NULL;
-		*num_sctrls = 0;
-		return;
-	}
-	*sctrls = msg->res_sctrls;
-	*num_sctrls = talloc_array_length(msg->res_sctrls);
-}
-
-struct tldap_message *tldap_ctx_lastmsg(struct tldap_context *ld)
-{
-	return ld->last_msg;
-}
-
-static const struct { TLDAPRC rc; const char *string; } tldaprc_errmap[] =
-{
-	{ TLDAP_SUCCESS,
-	  "TLDAP_SUCCESS" },
-	{ TLDAP_OPERATIONS_ERROR,
-	  "TLDAP_OPERATIONS_ERROR" },
-	{ TLDAP_PROTOCOL_ERROR,
-	  "TLDAP_PROTOCOL_ERROR" },
-	{ TLDAP_TIMELIMIT_EXCEEDED,
-	  "TLDAP_TIMELIMIT_EXCEEDED" },
-	{ TLDAP_SIZELIMIT_EXCEEDED,
-	  "TLDAP_SIZELIMIT_EXCEEDED" },
-	{ TLDAP_COMPARE_FALSE,
-	  "TLDAP_COMPARE_FALSE" },
-	{ TLDAP_COMPARE_TRUE,
-	  "TLDAP_COMPARE_TRUE" },
-	{ TLDAP_STRONG_AUTH_NOT_SUPPORTED,
-	  "TLDAP_STRONG_AUTH_NOT_SUPPORTED" },
-	{ TLDAP_STRONG_AUTH_REQUIRED,
-	  "TLDAP_STRONG_AUTH_REQUIRED" },
-	{ TLDAP_REFERRAL,
-	  "TLDAP_REFERRAL" },
-	{ TLDAP_ADMINLIMIT_EXCEEDED,
-	  "TLDAP_ADMINLIMIT_EXCEEDED" },
-	{ TLDAP_UNAVAILABLE_CRITICAL_EXTENSION,
-	  "TLDAP_UNAVAILABLE_CRITICAL_EXTENSION" },
-	{ TLDAP_CONFIDENTIALITY_REQUIRED,
-	  "TLDAP_CONFIDENTIALITY_REQUIRED" },
-	{ TLDAP_SASL_BIND_IN_PROGRESS,
-	  "TLDAP_SASL_BIND_IN_PROGRESS" },
-	{ TLDAP_NO_SUCH_ATTRIBUTE,
-	  "TLDAP_NO_SUCH_ATTRIBUTE" },
-	{ TLDAP_UNDEFINED_TYPE,
-	  "TLDAP_UNDEFINED_TYPE" },
-	{ TLDAP_INAPPROPRIATE_MATCHING,
-	  "TLDAP_INAPPROPRIATE_MATCHING" },
-	{ TLDAP_CONSTRAINT_VIOLATION,
-	  "TLDAP_CONSTRAINT_VIOLATION" },
-	{ TLDAP_TYPE_OR_VALUE_EXISTS,
-	  "TLDAP_TYPE_OR_VALUE_EXISTS" },
-	{ TLDAP_INVALID_SYNTAX,
-	  "TLDAP_INVALID_SYNTAX" },
-	{ TLDAP_NO_SUCH_OBJECT,
-	  "TLDAP_NO_SUCH_OBJECT" },
-	{ TLDAP_ALIAS_PROBLEM,
-	  "TLDAP_ALIAS_PROBLEM" },
-	{ TLDAP_INVALID_DN_SYNTAX,
-	  "TLDAP_INVALID_DN_SYNTAX" },
-	{ TLDAP_IS_LEAF,
-	  "TLDAP_IS_LEAF" },
-	{ TLDAP_ALIAS_DEREF_PROBLEM,
-	  "TLDAP_ALIAS_DEREF_PROBLEM" },
-	{ TLDAP_INAPPROPRIATE_AUTH,
-	  "TLDAP_INAPPROPRIATE_AUTH" },
-	{ TLDAP_INVALID_CREDENTIALS,
-	  "TLDAP_INVALID_CREDENTIALS" },
-	{ TLDAP_INSUFFICIENT_ACCESS,
-	  "TLDAP_INSUFFICIENT_ACCESS" },
-	{ TLDAP_BUSY,
-	  "TLDAP_BUSY" },
-	{ TLDAP_UNAVAILABLE,
-	  "TLDAP_UNAVAILABLE" },
-	{ TLDAP_UNWILLING_TO_PERFORM,
-	  "TLDAP_UNWILLING_TO_PERFORM" },
-	{ TLDAP_LOOP_DETECT,
-	  "TLDAP_LOOP_DETECT" },
-	{ TLDAP_NAMING_VIOLATION,
-	  "TLDAP_NAMING_VIOLATION" },
-	{ TLDAP_OBJECT_CLASS_VIOLATION,
-	  "TLDAP_OBJECT_CLASS_VIOLATION" },
-	{ TLDAP_NOT_ALLOWED_ON_NONLEAF,
-	  "TLDAP_NOT_ALLOWED_ON_NONLEAF" },
-	{ TLDAP_NOT_ALLOWED_ON_RDN,
-	  "TLDAP_NOT_ALLOWED_ON_RDN" },
-	{ TLDAP_ALREADY_EXISTS,
-	  "TLDAP_ALREADY_EXISTS" },
-	{ TLDAP_NO_OBJECT_CLASS_MODS,
-	  "TLDAP_NO_OBJECT_CLASS_MODS" },
-	{ TLDAP_RESULTS_TOO_LARGE,
-	  "TLDAP_RESULTS_TOO_LARGE" },
-	{ TLDAP_AFFECTS_MULTIPLE_DSAS,
-	  "TLDAP_AFFECTS_MULTIPLE_DSAS" },
-	{ TLDAP_OTHER,
-	  "TLDAP_OTHER" },
-	{ TLDAP_SERVER_DOWN,
-	  "TLDAP_SERVER_DOWN" },
-	{ TLDAP_LOCAL_ERROR,
-	  "TLDAP_LOCAL_ERROR" },
-	{ TLDAP_ENCODING_ERROR,
-	  "TLDAP_ENCODING_ERROR" },
-	{ TLDAP_DECODING_ERROR,
-	  "TLDAP_DECODING_ERROR" },
-	{ TLDAP_TIMEOUT,
-	  "TLDAP_TIMEOUT" },
-	{ TLDAP_AUTH_UNKNOWN,
-	  "TLDAP_AUTH_UNKNOWN" },
-	{ TLDAP_FILTER_ERROR,
-	  "TLDAP_FILTER_ERROR" },
-	{ TLDAP_USER_CANCELLED,
-	  "TLDAP_USER_CANCELLED" },
-	{ TLDAP_PARAM_ERROR,
-	  "TLDAP_PARAM_ERROR" },
-	{ TLDAP_NO_MEMORY,
-	  "TLDAP_NO_MEMORY" },
-	{ TLDAP_CONNECT_ERROR,
-	  "TLDAP_CONNECT_ERROR" },
-	{ TLDAP_NOT_SUPPORTED,
-	  "TLDAP_NOT_SUPPORTED" },
-	{ TLDAP_CONTROL_NOT_FOUND,
-	  "TLDAP_CONTROL_NOT_FOUND" },
-	{ TLDAP_NO_RESULTS_RETURNED,
-	  "TLDAP_NO_RESULTS_RETURNED" },
-	{ TLDAP_MORE_RESULTS_TO_RETURN,
-	  "TLDAP_MORE_RESULTS_TO_RETURN" },
-	{ TLDAP_CLIENT_LOOP,
-	  "TLDAP_CLIENT_LOOP" },
-	{ TLDAP_REFERRAL_LIMIT_EXCEEDED,
-	  "TLDAP_REFERRAL_LIMIT_EXCEEDED" },
-};
-
-const char *tldap_rc2string(TLDAPRC rc)
-{
-	size_t i;
-
-	for (i=0; i<ARRAY_SIZE(tldaprc_errmap); i++) {
-		if (TLDAP_RC_EQUAL(rc, tldaprc_errmap[i].rc)) {
-			return tldaprc_errmap[i].string;
-		}
-	}
-
-	return "Unknown LDAP Error";
-}
diff --git a/source3/lib/tldap_util.c b/source3/lib/tldap_util.c
deleted file mode 100644
index 89f812b..0000000
--- a/source3/lib/tldap_util.c
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
-   Unix SMB/CIFS implementation.
-   Infrastructure for async ldap client requests
-   Copyright (C) Volker Lendecke 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 "includes.h"
-#include "tldap.h"
-#include "tldap_util.h"
-#include "../libcli/security/security.h"
-#include "../lib/util/asn1.h"
-#include "../librpc/ndr/libndr.h"
-#include "lib/util/base64.h"
-
-bool tldap_entry_values(struct tldap_message *msg, const char *attribute,
-			DATA_BLOB **values, int *num_values)
-{
-	struct tldap_attribute *attributes;
-	int i, num_attributes;
-
-	if (!tldap_entry_attributes(msg, &attributes, &num_attributes)) {
-		return false;
-	}
-
-	for (i=0; i<num_attributes; i++) {
-		if (strequal(attribute, attributes[i].name)) {
-			break;
-		}
-	}
-	if (i == num_attributes) {
-		return false;
-	}
-	*num_values = attributes[i].num_values;
-	*values = attributes[i].values;
-	return true;
-}
-
-bool tldap_get_single_valueblob(struct tldap_message *msg,
-				const char *attribute, DATA_BLOB *blob)
-{
-	int num_values;
-	DATA_BLOB *values;
-
-	if (attribute == NULL) {
-		return NULL;
-	}
-	if (!tldap_entry_values(msg, attribute, &values, &num_values)) {
-		return NULL;
-	}
-	if (num_values != 1) {
-		return NULL;
-	}
-	*blob = values[0];
-	return true;
-}
-
-char *tldap_talloc_single_attribute(struct tldap_message *msg,
-				    const char *attribute,
-				    TALLOC_CTX *mem_ctx)
-{
-	DATA_BLOB val;
-	char *result;
-	size_t len;
-
-	if (!tldap_get_single_valueblob(msg, attribute, &val)) {
-		return NULL;
-	}
-	if (!convert_string_talloc(mem_ctx, CH_UTF8, CH_UNIX,
-				   val.data, val.length,
-				   &result, &len)) {
-		return NULL;
-	}
-	return result;
-}
-
-bool tldap_pull_binsid(struct tldap_message *msg, const char *attribute,
-		       struct dom_sid *sid)
-{
-	DATA_BLOB val;
-
-	if (!tldap_get_single_valueblob(msg, attribute, &val)) {
-		return false;
-	}
-	return sid_parse(val.data, val.length, sid);
-}
-
-bool tldap_pull_guid(struct tldap_message *msg, const char *attribute,
-		     struct GUID *guid)
-{
-	DATA_BLOB val;
-
-	if (!tldap_get_single_valueblob(msg, attribute, &val)) {
-		return false;
-	}
-	return NT_STATUS_IS_OK(GUID_from_data_blob(&val, guid));
-}
-
-static bool tldap_add_blob_vals(TALLOC_CTX *mem_ctx, struct tldap_mod *mod,
-				DATA_BLOB *newvals, int num_newvals)
-{
-	int num_values = talloc_array_length(mod->values);
-	int i;
-	DATA_BLOB *tmp;
-
-	tmp = talloc_realloc(mem_ctx, mod->values, DATA_BLOB,
-			     num_values + num_newvals);
-	if (tmp == NULL) {
-		return false;
-	}
-	mod->values = tmp;
-
-	for (i=0; i<num_newvals; i++) {
-		mod->values[i+num_values].data = (uint8_t *)talloc_memdup(
-			mod->values, newvals[i].data, newvals[i].length);
-		if (mod->values[i+num_values].data == NULL) {
-			return false;
-		}
-		mod->values[i+num_values].length = newvals[i].length;
-	}
-	mod->num_values = num_values + num_newvals;
-	return true;
-}
-
-bool tldap_add_mod_blobs(TALLOC_CTX *mem_ctx,
-			 struct tldap_mod **pmods, int *pnum_mods,
-			 int mod_op, const char *attrib,
-			 DATA_BLOB *newvals, int num_newvals)
-{
-	struct tldap_mod new_mod;
-	struct tldap_mod *mods = *pmods;
-	struct tldap_mod *mod = NULL;
-	int i, num_mods;
-
-	if (mods == NULL) {
-		mods = talloc_array(mem_ctx, struct tldap_mod, 0);
-	}
-	if (mods == NULL) {
-		return false;
-	}
-
-	num_mods = *pnum_mods;
-
-	for (i=0; i<num_mods; i++) {
-		if ((mods[i].mod_op == mod_op)
-		    && strequal(mods[i].attribute, attrib)) {
-			mod = &mods[i];
-			break;
-		}
-	}
-
-	if (mod == NULL) {
-		new_mod.mod_op = mod_op;
-		new_mod.attribute = talloc_strdup(mods, attrib);
-		if (new_mod.attribute == NULL) {
-			return false;
-		}
-		new_mod.num_values = 0;
-		new_mod.values = NULL;
-		mod = &new_mod;
-	}
-
-	if ((num_newvals != 0)
-	    && !tldap_add_blob_vals(mods, mod, newvals, num_newvals)) {
-		return false;
-	}
-
-	if ((i == num_mods) && (talloc_array_length(mods) < num_mods + 1)) {
-		mods = talloc_realloc(talloc_tos(), mods, struct tldap_mod,
-				      num_mods+1);
-		if (mods == NULL) {
-			return false;
-		}
-		mods[num_mods] = *mod;
-	}
-
-	*pmods = mods;
-	*pnum_mods += 1;
-	return true;
-}
-
-bool tldap_add_mod_str(TALLOC_CTX *mem_ctx,
-		       struct tldap_mod **pmods, int *pnum_mods,
-		       int mod_op, const char *attrib, const char *str)
-{
-	DATA_BLOB utf8;
-	bool ret;
-
-	if (!convert_string_talloc(talloc_tos(), CH_UNIX, CH_UTF8, str,
-				   strlen(str), &utf8.data, &utf8.length)) {
-		return false;
-	}
-
-	ret = tldap_add_mod_blobs(mem_ctx, pmods, pnum_mods, mod_op, attrib,
-				  &utf8, 1);
-	TALLOC_FREE(utf8.data);
-	return ret;
-}
-
-static bool tldap_make_mod_blob_int(struct tldap_message *existing,
-				    TALLOC_CTX *mem_ctx,
-				    struct tldap_mod **pmods, int *pnum_mods,
-				    const char *attrib, DATA_BLOB newval,
-				    int (*comparison)(const DATA_BLOB *d1,
-						      const DATA_BLOB *d2))
-{
-	int num_values = 0;
-	DATA_BLOB *values = NULL;
-	DATA_BLOB oldval = data_blob_null;
-
-	if ((existing != NULL)
-	    && tldap_entry_values(existing, attrib, &values, &num_values)) {
-
-		if (num_values > 1) {
-			/* can't change multivalue attributes atm */
-			return false;
-		}
-		if (num_values == 1) {
-			oldval = values[0];
-		}
-	}
-
-	if ((oldval.data != NULL) && (newval.data != NULL)
-	    && (comparison(&oldval, &newval) == 0)) {
-		/* Believe it or not, but LDAP will deny a delete and
-		   an add at the same time if the values are the
-		   same... */
-		DEBUG(10,("tldap_make_mod_blob_int: attribute |%s| not "
-			  "changed.\n", attrib));
-		return true;
-	}
-
-	if (oldval.data != NULL) {
-		/* By deleting exactly the value we found in the entry this
-		 * should be race-free in the sense that the LDAP-Server will
-		 * deny the complete operation if somebody changed the
-		 * attribute behind our back. */
-		/* This will also allow modifying single valued attributes in
-		 * Novell NDS. In NDS you have to first remove attribute and
-		 * then you could add new value */
-
-		DEBUG(10, ("tldap_make_mod_blob_int: deleting attribute |%s|\n",
-			   attrib));
-		if (!tldap_add_mod_blobs(mem_ctx, pmods, pnum_mods,
-					 TLDAP_MOD_DELETE,
-					 attrib, &oldval, 1)) {
-			return false;
-		}
-	}
-
-	/* Regardless of the real operation (add or modify)
-	   we add the new value here. We rely on deleting
-	   the old value, should it exist. */
-
-	if (newval.data != NULL) {
-		DEBUG(10, ("tldap_make_mod_blob_int: adding attribute |%s| value len "
-			   "%d\n", attrib, (int)newval.length));
-	        if (!tldap_add_mod_blobs(mem_ctx, pmods, pnum_mods,
-					 TLDAP_MOD_ADD,
-					 attrib, &newval, 1)) {
-			return false;
-		}
-	}
-	return true;
-}
-
-bool tldap_make_mod_blob(struct tldap_message *existing, TALLOC_CTX *mem_ctx,
-			 struct tldap_mod **pmods, int *pnum_mods,
-			 const char *attrib, DATA_BLOB newval)
-{
-	return tldap_make_mod_blob_int(existing, mem_ctx, pmods, pnum_mods,
-				       attrib, newval, data_blob_cmp);
-}
-
-static int compare_utf8_blobs(const DATA_BLOB *d1, const DATA_BLOB *d2)
-{
-	char *s1, *s2;
-	size_t s1len, s2len;
-	int ret;
-
-	if (!convert_string_talloc(talloc_tos(), CH_UTF8, CH_UNIX, d1->data,
-				   d1->length, &s1, &s1len)) {
-		/* can't do much here */
-		return 0;
-	}
-	if (!convert_string_talloc(talloc_tos(), CH_UTF8, CH_UNIX, d2->data,
-				   d2->length, &s2, &s2len)) {
-		/* can't do much here */
-		TALLOC_FREE(s1);
-		return 0;
-	}
-	ret = strcasecmp_m(s1, s2);
-	TALLOC_FREE(s2);
-	TALLOC_FREE(s1);
-	return ret;
-}
-
-bool tldap_make_mod_fmt(struct tldap_message *existing, TALLOC_CTX *mem_ctx,
-			struct tldap_mod **pmods, int *pnum_mods,
-			const char *attrib, const char *fmt, ...)
-{
-	va_list ap;
-	char *newval;
-	bool ret;
-	DATA_BLOB blob = data_blob_null;
-
-	va_start(ap, fmt);
-	newval = talloc_vasprintf(talloc_tos(), fmt, ap);
-	va_end(ap);
-
-	if (newval == NULL) {
-		return false;
-	}
-
-	blob.length = strlen(newval);
-	if (blob.length != 0) {
-		blob.data = discard_const_p(uint8_t, newval);
-	}
-	ret = tldap_make_mod_blob_int(existing, mem_ctx, pmods, pnum_mods,
-				      attrib, blob, compare_utf8_blobs);
-	TALLOC_FREE(newval);
-	return ret;
-}
-
-const char *tldap_errstr(TALLOC_CTX *mem_ctx, struct tldap_context *ld,
-			 TLDAPRC rc)
-{
-	const char *ld_error = NULL;
-	char *res;
-
-	if (ld != NULL) {
-		ld_error = tldap_msg_diagnosticmessage(tldap_ctx_lastmsg(ld));
-	}
-	res = talloc_asprintf(mem_ctx, "LDAP error %d (%s), %s",
-			      (int)TLDAP_RC_V(rc), tldap_rc2string(rc),
-			      ld_error ? ld_error : "unknown");
-	return res;
-}
-
-TLDAPRC tldap_search_va(struct tldap_context *ld, const char *base, int scope,
-			const char *attrs[], int num_attrs, int attrsonly,
-			TALLOC_CTX *mem_ctx, struct tldap_message ***res,
-			const char *fmt, va_list ap)
-{
-	char *filter;
-	TLDAPRC rc;
-
-	filter = talloc_vasprintf(talloc_tos(), fmt, ap);
-	if (filter == NULL) {
-		return TLDAP_NO_MEMORY;
-	}
-
-	rc = tldap_search(ld, base, scope, filter,
-			  attrs, num_attrs, attrsonly,
-			  NULL /*sctrls*/, 0, NULL /*cctrls*/, 0,
-			  0 /*timelimit*/, 0 /*sizelimit*/, 0 /*deref*/,
-			  mem_ctx, res);
-	TALLOC_FREE(filter);
-	return rc;
-}
-
-TLDAPRC tldap_search_fmt(struct tldap_context *ld, const char *base, int scope,
-			 const char *attrs[], int num_attrs, int attrsonly,
-			 TALLOC_CTX *mem_ctx, struct tldap_message ***res,
-			 const char *fmt, ...)
-{
-	va_list ap;
-	TLDAPRC rc;
-
-	va_start(ap, fmt);
-	rc = tldap_search_va(ld, base, scope, attrs, num_attrs, attrsonly,
-			     mem_ctx, res, fmt, ap);
-	va_end(ap);
-	return rc;
-}
-
-bool tldap_pull_uint64(struct tldap_message *msg, const char *attr,
-		       uint64_t *presult)
-{
-	char *str;
-	uint64_t result;
-
-	str = tldap_talloc_single_attribute(msg, attr, talloc_tos());
-	if (str == NULL) {
-		DEBUG(10, ("Could not find attribute %s\n", attr));
-		return false;
-	}
-	result = strtoull(str, NULL, 10);
-	TALLOC_FREE(str);
-	*presult = result;
-	return true;
-}
-
-bool tldap_pull_uint32(struct tldap_message *msg, const char *attr,
-		       uint32_t *presult)
-{
-	uint64_t result;
-
-	if (!tldap_pull_uint64(msg, attr, &result)) {
-		return false;
-	}
-	*presult = (uint32_t)result;
-	return true;
-}
-
-struct tldap_fetch_rootdse_state {
-	struct tldap_context *ld;
-	struct tldap_message *rootdse;
-};
-
-static void tldap_fetch_rootdse_done(struct tevent_req *subreq);
-
-struct tevent_req *tldap_fetch_rootdse_send(TALLOC_CTX *mem_ctx,
-					    struct tevent_context *ev,
-					    struct tldap_context *ld)
-{
-	struct tevent_req *req, *subreq;
-	struct tldap_fetch_rootdse_state *state;
-	static const char *attrs[2] = { "*", "+" };
-
-	req = tevent_req_create(mem_ctx, &state,
-				struct tldap_fetch_rootdse_state);
-	if (req == NULL) {
-		return NULL;
-	}
-	state->ld = ld;
-	state->rootdse = NULL;
-
-	subreq = tldap_search_send(
-		mem_ctx, ev, ld, "", TLDAP_SCOPE_BASE, "(objectclass=*)",
-		attrs, ARRAY_SIZE(attrs), 0, NULL, 0, NULL, 0, 0, 0, 0);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(subreq, tldap_fetch_rootdse_done, req);
-	return req;
-}
-
-static void tldap_fetch_rootdse_done(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct tldap_fetch_rootdse_state *state = tevent_req_data(
-		req, struct tldap_fetch_rootdse_state);
-	struct tldap_message *msg;
-	TLDAPRC rc;
-
-	rc = tldap_search_recv(subreq, state, &msg);
-	if (tevent_req_ldap_error(req, rc)) {
-		TALLOC_FREE(subreq);
-		return;
-	}
-
-	switch (tldap_msg_type(msg)) {
-	case TLDAP_RES_SEARCH_ENTRY:
-		if (state->rootdse != NULL) {
-			goto protocol_error;
-		}
-		state->rootdse = msg;
-		break;
-	case TLDAP_RES_SEARCH_RESULT:
-		TALLOC_FREE(subreq);
-		if (state->rootdse == NULL) {
-			goto protocol_error;
-		}
-		tevent_req_done(req);
-		break;
-	default:
-		goto protocol_error;
-	}
-	return;
-
-protocol_error:
-	tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
-	return;
-}
-
-TLDAPRC tldap_fetch_rootdse_recv(struct tevent_req *req)
-{
-	struct tldap_fetch_rootdse_state *state = tevent_req_data(
-		req, struct tldap_fetch_rootdse_state);
-	TLDAPRC rc;
-	char *dn;
-
-	if (tevent_req_is_ldap_error(req, &rc)) {
-		return rc;
-	}
-	/* Trigger parsing the dn, just to make sure it's ok */
-	if (!tldap_entry_dn(state->rootdse, &dn)) {
-		return TLDAP_DECODING_ERROR;
-	}
-	if (!tldap_context_setattr(state->ld, "tldap:rootdse",
-				   &state->rootdse)) {
-		return TLDAP_NO_MEMORY;
-	}
-	return TLDAP_SUCCESS;
-}
-
-TLDAPRC tldap_fetch_rootdse(struct tldap_context *ld)
-{
-	TALLOC_CTX *frame = talloc_stackframe();
-	struct tevent_context *ev;
-	struct tevent_req *req;
-	TLDAPRC rc = TLDAP_NO_MEMORY;
-
-	ev = samba_tevent_context_init(frame);
-	if (ev == NULL) {
-		goto fail;
-	}
-	req = tldap_fetch_rootdse_send(frame, ev, ld);
-	if (req == NULL) {
-		goto fail;
-	}
-	if (!tevent_req_poll(req, ev)) {
-		rc = TLDAP_OPERATIONS_ERROR;
-		goto fail;
-	}
-
-	rc = tldap_fetch_rootdse_recv(req);
- fail:
-	TALLOC_FREE(frame);
-	return rc;
-}
-
-struct tldap_message *tldap_rootdse(struct tldap_context *ld)
-{
-	return talloc_get_type(tldap_context_getattr(ld, "tldap:rootdse"),
-			       struct tldap_message);
-}
-
-bool tldap_entry_has_attrvalue(struct tldap_message *msg,
-			       const char *attribute,
-			       const DATA_BLOB blob)
-{
-	int i, num_values;
-	DATA_BLOB *values;
-
-	if (!tldap_entry_values(msg, attribute, &values, &num_values)) {
-		return false;
-	}
-	for (i=0; i<num_values; i++) {
-		if (data_blob_cmp(&values[i], &blob) == 0) {
-			return true;
-		}
-	}
-	return false;
-}
-
-bool tldap_supports_control(struct tldap_context *ld, const char *oid)
-{
-	struct tldap_message *rootdse = tldap_rootdse(ld);
-
-	if (rootdse == NULL) {
-		return false;
-	}
-	return tldap_entry_has_attrvalue(rootdse, "supportedControl",
-					 data_blob_const(oid, strlen(oid)));
-}
-
-struct tldap_control *tldap_add_control(TALLOC_CTX *mem_ctx,
-					struct tldap_control *ctrls,
-					int num_ctrls,
-					struct tldap_control *ctrl)
-{
-	struct tldap_control *result;
-
-	result = talloc_array(mem_ctx, struct tldap_control, num_ctrls+1);
-	if (result == NULL) {
-		return NULL;
-	}
-	memcpy(result, ctrls, sizeof(struct tldap_control) * num_ctrls);
-	result[num_ctrls] = *ctrl;
-	return result;
-}
-
-/*
- * Find a control returned by the server
- */
-struct tldap_control *tldap_msg_findcontrol(struct tldap_message *msg,
-					    const char *oid)
-{
-	struct tldap_control *controls;
-	int i, num_controls;
-
-	tldap_msg_sctrls(msg, &num_controls, &controls);
-
-	for (i=0; i<num_controls; i++) {
-		if (strcmp(controls[i].oid, oid) == 0) {
-			return &controls[i];
-		}
-	}
-	return NULL;
-}
-
-struct tldap_search_paged_state {
-	struct tevent_context *ev;
-	struct tldap_context *ld;
-	const char *base;
-	const char *filter;
-	int scope;
-	const char **attrs;
-	int num_attrs;
-	int attrsonly;
-	struct tldap_control *sctrls;
-	int num_sctrls;
-	struct tldap_control *cctrls;
-	int num_cctrls;
-	int timelimit;
-	int sizelimit;
-	int deref;
-
-	int page_size;
-	struct asn1_data *asn1;
-	DATA_BLOB cookie;
-	struct tldap_message *result;
-};
-
-static struct tevent_req *tldap_ship_paged_search(
-	TALLOC_CTX *mem_ctx,
-	struct tldap_search_paged_state *state)
-{
-	struct tldap_control *pgctrl;
-	struct asn1_data *asn1 = NULL;
-
-	asn1 = asn1_init(state);
-	if (asn1 == NULL) {
-		return NULL;
-	}
-	if (!asn1_push_tag(asn1, ASN1_SEQUENCE(0))) goto err;
-	if (!asn1_write_Integer(asn1, state->page_size)) goto err;
-	if (!asn1_write_OctetString(asn1, state->cookie.data, state->cookie.length)) goto err;
-	if (!asn1_pop_tag(asn1)) goto err;
-	state->asn1 = asn1;
-
-	pgctrl = &state->sctrls[state->num_sctrls-1];
-	pgctrl->oid = TLDAP_CONTROL_PAGEDRESULTS;
-	pgctrl->critical = true;
-	if (!asn1_blob(state->asn1, &pgctrl->value)) {
-		goto err;
-	}
-	return tldap_search_send(mem_ctx, state->ev, state->ld, state->base,
-				 state->scope, state->filter, state->attrs,
-				 state->num_attrs, state->attrsonly,
-				 state->sctrls, state->num_sctrls,
-				 state->cctrls, state->num_cctrls,
-				 state->timelimit, state->sizelimit,
-				 state->deref);
-
-  err:
-
-	TALLOC_FREE(asn1);
-	return NULL;
-}
-
-static void tldap_search_paged_done(struct tevent_req *subreq);
-
-struct tevent_req *tldap_search_paged_send(TALLOC_CTX *mem_ctx,
-					   struct tevent_context *ev,
-					   struct tldap_context *ld,
-					   const char *base, int scope,
-					   const char *filter,
-					   const char **attrs,
-					   int num_attrs,
-					   int attrsonly,
-					   struct tldap_control *sctrls,
-					   int num_sctrls,
-					   struct tldap_control *cctrls,
-					   int num_cctrls,
-					   int timelimit,
-					   int sizelimit,
-					   int deref,
-					   int page_size)
-{
-	struct tevent_req *req, *subreq;
-	struct tldap_search_paged_state *state;
-	struct tldap_control empty_control;
-
-	req = tevent_req_create(mem_ctx, &state,
-				struct tldap_search_paged_state);
-	if (req == NULL) {
-		return NULL;
-	}
-	state->ev = ev;
-	state->ld = ld;
-	state->base = base;
-	state->filter = filter;
-	state->scope = scope;
-	state->attrs = attrs;
-	state->num_attrs = num_attrs;
-	state->attrsonly = attrsonly;
-	state->cctrls = cctrls;
-	state->num_cctrls = num_cctrls;
-	state->timelimit = timelimit;
-	state->sizelimit = sizelimit;
-	state->deref = deref;
-
-	state->page_size = page_size;
-	state->asn1 = NULL;
-	state->cookie = data_blob_null;
-
-	ZERO_STRUCT(empty_control);
-
-	state->sctrls = tldap_add_control(state, sctrls, num_sctrls,
-					  &empty_control);
-	if (tevent_req_nomem(state->sctrls, req)) {
-		return tevent_req_post(req, ev);
-	}
-	state->num_sctrls = num_sctrls+1;
-
-	subreq = tldap_ship_paged_search(state, state);
-	if (tevent_req_nomem(subreq, req)) {
-		return tevent_req_post(req, ev);
-	}
-	tevent_req_set_callback(subreq, tldap_search_paged_done, req);
-
-	return req;
-}
-
-static void tldap_search_paged_done(struct tevent_req *subreq)
-{
-	struct tevent_req *req = tevent_req_callback_data(
-		subreq, struct tevent_req);
-	struct tldap_search_paged_state *state = tevent_req_data(
-		req, struct tldap_search_paged_state);
-	struct asn1_data *asn1 = NULL;
-	struct tldap_control *pgctrl;
-	TLDAPRC rc;
-	int size;
-
-	rc = tldap_search_recv(subreq, state, &state->result);
-	if (tevent_req_ldap_error(req, rc)) {
-		TALLOC_FREE(subreq);
-		return;
-	}
-
-	TALLOC_FREE(state->asn1);
-
-	switch (tldap_msg_type(state->result)) {
-	case TLDAP_RES_SEARCH_ENTRY:
-	case TLDAP_RES_SEARCH_REFERENCE:
-		tevent_req_notify_callback(req);
-		return;
-	case TLDAP_RES_SEARCH_RESULT:
-		break;
-	default:
-		TALLOC_FREE(subreq);
-		tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
-		return;
-	}
-
-	TALLOC_FREE(subreq);
-
-	/* We've finished one paged search, fire the next */
-
-	pgctrl = tldap_msg_findcontrol(state->result,
-				       TLDAP_CONTROL_PAGEDRESULTS);
-	if (pgctrl == NULL) {
-		/* RFC2696 requires the server to return the control */
-		tevent_req_ldap_error(req, TLDAP_PROTOCOL_ERROR);
-		return;
-	}
-
-	TALLOC_FREE(state->cookie.data);
-
-	asn1 = asn1_init(talloc_tos());
-	if (tevent_req_nomem(asn1, req)) {
-		return;
-	}
-
-	asn1_load_nocopy(asn1, pgctrl->value.data, pgctrl->value.length);
-	if (!asn1_start_tag(asn1, ASN1_SEQUENCE(0))) goto err;
-	if (!asn1_read_Integer(asn1, &size)) goto err;
-	if (!asn1_read_OctetString(asn1, state, &state->cookie)) goto err;
-	if (!asn1_end_tag(asn1)) goto err;
-
-	TALLOC_FREE(asn1);
-
-	if (state->cookie.length == 0) {
-		/* We're done, no cookie anymore */
-		tevent_req_done(req);
-		return;
-	}
-
-	TALLOC_FREE(state->result);
-
-	subreq = tldap_ship_paged_search(state, state);
-	if (tevent_req_nomem(subreq, req)) {
-		return;
-	}
-	tevent_req_set_callback(subreq, tldap_search_paged_done, req);
-
-  err:
-
-	TALLOC_FREE(asn1);
-	tevent_req_ldap_error(req, TLDAP_DECODING_ERROR);
-}
-
-TLDAPRC tldap_search_paged_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-				struct tldap_message **pmsg)
-{
-	struct tldap_search_paged_state *state = tevent_req_data(
-		req, struct tldap_search_paged_state);
-	TLDAPRC rc;
-
-	if (!tevent_req_is_in_progress(req)
-	    && tevent_req_is_ldap_error(req, &rc)) {
-		return rc;
-	}
-	if (tevent_req_is_in_progress(req)) {
-		switch (tldap_msg_type(state->result)) {
-		case TLDAP_RES_SEARCH_ENTRY:
-		case TLDAP_RES_SEARCH_REFERENCE:
-			break;
-		default:
-			return TLDAP_PROTOCOL_ERROR;
-		}
-	}
-	*pmsg = talloc_move(mem_ctx, &state->result);
-	return TLDAP_SUCCESS;
-}
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 0926690..9a79078 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -23,8 +23,6 @@
 #include "wbc_async.h"
 #include "torture/proto.h"
 #include "libcli/security/security.h"
-#include "tldap.h"
-#include "tldap_util.h"
 #include "../librpc/gen_ndr/svcctl.h"
 #include "../lib/util/memcache.h"
 #include "nsswitch/winbind_client.h"
@@ -8393,111 +8391,6 @@ static bool run_shortname_test(int dummy)
 	return correct;
 }
 
-static void pagedsearch_cb(struct tevent_req *req)
-{
-	TLDAPRC rc;
-	struct tldap_message *msg;
-	char *dn;
-
-	rc = tldap_search_paged_recv(req, talloc_tos(), &msg);
-	if (!TLDAP_RC_IS_SUCCESS(rc)) {
-		d_printf("tldap_search_paged_recv failed: %s\n",
-			 tldap_rc2string(rc));
-		return;
-	}
-	if (tldap_msg_type(msg) != TLDAP_RES_SEARCH_ENTRY) {
-		TALLOC_FREE(msg);
-		return;
-	}
-	if (!tldap_entry_dn(msg, &dn)) {
-		d_printf("tldap_entry_dn failed\n");
-		return;
-	}
-	d_printf("%s\n", dn);
-	TALLOC_FREE(msg);
-}
-
-static bool run_tldap(int dummy)
-{
-	struct tldap_context *ld;
-	int fd;
-	TLDAPRC rc;
-	NTSTATUS status;
-	struct sockaddr_storage addr;
-	struct tevent_context *ev;
-	struct tevent_req *req;
-	char *basedn;
-	const char *filter;
-
-	if (!resolve_name(host, &addr, 0, false)) {
-		d_printf("could not find host %s\n", host);
-		return false;
-	}
-	status = open_socket_out(&addr, 389, 9999, &fd);
-	if (!NT_STATUS_IS_OK(status)) {
-		d_printf("open_socket_out failed: %s\n", nt_errstr(status));
-		return false;
-	}
-
-	ld = tldap_context_create(talloc_tos(), fd);
-	if (ld == NULL) {
-		close(fd);
-		d_printf("tldap_context_create failed\n");
-		return false;
-	}
-
-	rc = tldap_fetch_rootdse(ld);
-	if (!TLDAP_RC_IS_SUCCESS(rc)) {
-		d_printf("tldap_fetch_rootdse failed: %s\n",
-			 tldap_errstr(talloc_tos(), ld, rc));
-		return false;
-	}
-
-	basedn = tldap_talloc_single_attribute(
-		tldap_rootdse(ld), "defaultNamingContext", talloc_tos());
-	if (basedn == NULL) {
-		d_printf("no defaultNamingContext\n");
-		return false;
-	}
-	d_printf("defaultNamingContext: %s\n", basedn);
-
-	ev = samba_tevent_context_init(talloc_tos());
-	if (ev == NULL) {
-		d_printf("tevent_context_init failed\n");
-		return false;
-	}
-
-	req = tldap_search_paged_send(talloc_tos(), ev, ld, basedn,
-				      TLDAP_SCOPE_SUB, "(objectclass=*)",
-				      NULL, 0, 0,
-				      NULL, 0, NULL, 0, 0, 0, 0, 5);
-	if (req == NULL) {
-		d_printf("tldap_search_paged_send failed\n");
-		return false;
-	}
-	tevent_req_set_callback(req, pagedsearch_cb, NULL);
-
-	tevent_req_poll(req, ev);
-
-	TALLOC_FREE(req);
-
-	/* test search filters against rootDSE */
-	filter = "(&(|(name=samba)(nextRid<=10000000)(usnChanged>=10)(samba~=ambas)(!(name=s*m*a)))"
-		   "(|(name:=samba)(name:dn:2.5.13.5:=samba)(:dn:2.5.13.5:=samba)(!(name=*samba))))";
-
-	rc = tldap_search(ld, "", TLDAP_SCOPE_BASE, filter,
-			  NULL, 0, 0, NULL, 0, NULL, 0, 0, 0, 0,
-			  talloc_tos(), NULL);
-	if (!TLDAP_RC_IS_SUCCESS(rc)) {
-		d_printf("tldap_search with complex filter failed: %s\n",
-			 tldap_errstr(talloc_tos(), ld, rc));
-		return false;
-	}
-
-	TALLOC_FREE(ld);
-	return true;
-}
-
 /* Torture test to ensure no regression of :
 https://bugzilla.samba.org/show_bug.cgi?id=7084
 */
@@ -10336,7 +10229,6 @@ static struct {
 	{ "NTTRANS-FSCTL", run_nttrans_fsctl, 0},
 	{ "CLI_ECHO", run_cli_echo, 0},
 	{ "GETADDRINFO", run_getaddrinfo_send, 0},
-	{ "TLDAP", run_tldap },
 	{ "STREAMERROR", run_streamerror },
 	{ "NOTIFY-BENCH", run_notify_bench },
 	{ "NOTIFY-BENCH2", run_notify_bench2 },
diff --git a/source3/wscript_build b/source3/wscript_build
index 365b250..66ddfba 100755
--- a/source3/wscript_build
+++ b/source3/wscript_build
@@ -93,13 +93,6 @@ bld.SAMBA3_SUBSYSTEM('GROUPDB',
                     source='groupdb/mapping.c groupdb/mapping_tdb.c',
                     deps='tdb')
 
-bld.SAMBA3_SUBSYSTEM('TLDAP',
-                    source='''lib/tldap.c
-                    lib/tldap_util.c
-                    lib/tldap_gensec_bind.c
-                    ''',
-                    deps='asn1util LIBTSOCKET samba3util')
-
 # libpdb.so should not expose internal symbols that are only usable
 # to the statically linked modules that are merged into libpdb.
 # Note that we always filter these symbols out in libpdb, even
@@ -1294,7 +1287,6 @@ bld.SAMBA3_BINARY('smbtorture' + bld.env.suffix3,
                  param
                  libsmb
                  msrpc3
-                 TLDAP
                  RPC_NDR_ECHO
                  WB_REQTRANS
                  LOCKING
-- 
1.9.1



More information about the samba-technical mailing list