summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2004-11-06 20:15:39 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:05:35 -0500
commit8408b3428d8c263f8453a0da8ef71e7fc1e4ec81 (patch)
tree4c8b4a7686f730333fdf137c28166c7c561414b0
parenteee5cc3b9a6fe7cdc1fa81fac8ce524391bee519 (diff)
downloadsamba-8408b3428d8c263f8453a0da8ef71e7fc1e4ec81.tar.gz
samba-8408b3428d8c263f8453a0da8ef71e7fc1e4ec81.tar.bz2
samba-8408b3428d8c263f8453a0da8ef71e7fc1e4ec81.zip
r3583: - seperate the ldap client code and the ldap parsing code
(vl: we should only sync the parsing code with trunk) - use hierachical talloc in the ldap client code metze (This used to be commit 1e9c0b68ca9ddb28877d45fc1b47653b13a7446d)
-rw-r--r--source4/libcli/ldap/config.mk1
-rw-r--r--source4/libcli/ldap/ldap.c655
-rw-r--r--source4/libcli/ldap/ldap_client.c690
-rw-r--r--source4/libcli/ldap/ldap_ldif.c10
-rw-r--r--source4/torture/ldap/basic.c6
-rw-r--r--source4/torture/ldap/common.c10
6 files changed, 707 insertions, 665 deletions
diff --git a/source4/libcli/ldap/config.mk b/source4/libcli/ldap/config.mk
index ac047214ca..284edfd95e 100644
--- a/source4/libcli/ldap/config.mk
+++ b/source4/libcli/ldap/config.mk
@@ -2,6 +2,7 @@
# Start SUBSYSTEM LIBCLI_LDAP
[SUBSYSTEM::LIBCLI_LDAP]
ADD_OBJ_FILES = libcli/ldap/ldap.o \
+ libcli/ldap/ldap_client.o \
libcli/ldap/ldap_ldif.o
# End SUBSYSTEM LIBCLI_LDAP
#################################
diff --git a/source4/libcli/ldap/ldap.c b/source4/libcli/ldap/ldap.c
index 6d2cef8bdb..315241e5b1 100644
--- a/source4/libcli/ldap/ldap.c
+++ b/source4/libcli/ldap/ldap.c
@@ -24,11 +24,8 @@
*/
#include "includes.h"
-#include "system/network.h"
#include "system/iconv.h"
-#include "auth/auth.h"
#include "asn_1.h"
-#include "dlinklist.h"
/****************************************************************************
*
@@ -1218,8 +1215,8 @@ BOOL ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
char **host, uint16 *port, BOOL *ldaps)
{
int tmp_port = 0;
- fstring protocol;
- fstring tmp_host;
+ char protocol[11];
+ char tmp_host[255];
const char *p = url;
/* skip leading "URL:" (if any) */
@@ -1245,654 +1242,8 @@ BOOL ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
if (tmp_port != 0)
*port = tmp_port;
-
+
*host = talloc_strdup(mem_ctx, tmp_host);
return (*host != NULL);
}
-
-struct ldap_connection *new_ldap_connection(void)
-{
- TALLOC_CTX *mem_ctx = talloc_init("ldap_connection");
- struct ldap_connection *result;
-
- if (mem_ctx == NULL)
- return NULL;
-
- result = talloc(mem_ctx, sizeof(*result));
-
- if (result == NULL)
- return NULL;
-
- result->mem_ctx = mem_ctx;
- result->next_msgid = 1;
- result->outstanding = NULL;
- result->searchid = 0;
- result->search_entries = NULL;
- result->auth_dn = NULL;
- result->simple_pw = NULL;
- result->gensec = NULL;
-
- return result;
-}
-
-BOOL ldap_connect(struct ldap_connection *conn, const char *url)
-{
- struct hostent *hp;
- struct ipv4_addr ip;
-
- if (!ldap_parse_basic_url(conn->mem_ctx, url, &conn->host,
- &conn->port, &conn->ldaps))
- return False;
-
- hp = sys_gethostbyname(conn->host);
-
- if ((hp == NULL) || (hp->h_addr == NULL))
- return False;
-
- putip((char *)&ip, (char *)hp->h_addr);
-
- conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
-
- return (conn->sock >= 0);
-}
-
-BOOL ldap_set_simple_creds(struct ldap_connection *conn,
- const char *dn, const char *password)
-{
- conn->auth_dn = talloc_strdup(conn->mem_ctx, dn);
- conn->simple_pw = talloc_strdup(conn->mem_ctx, password);
-
- return ((conn->auth_dn != NULL) && (conn->simple_pw != NULL));
-}
-
-struct ldap_message *new_ldap_message(void)
-{
- TALLOC_CTX *mem_ctx = talloc_init("ldap_message");
- struct ldap_message *result;
-
- if (mem_ctx == NULL)
- return NULL;
-
- result = talloc(mem_ctx, sizeof(*result));
-
- if (result == NULL)
- return NULL;
-
- result->mem_ctx = mem_ctx;
- return result;
-}
-
-void destroy_ldap_message(struct ldap_message *msg)
-{
- if (msg != NULL)
- talloc_destroy(msg->mem_ctx);
-}
-
-BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
- const struct timeval *endtime)
-{
- DATA_BLOB request;
- BOOL result;
- struct ldap_queue_entry *entry;
-
- msg->messageid = conn->next_msgid++;
-
- if (!ldap_encode(msg, &request))
- return False;
-
- result = (write_data_until(conn->sock, request.data, request.length,
- endtime) == request.length);
-
- data_blob_free(&request);
-
- if (!result)
- return result;
-
- /* abandon and unbind don't expect results */
-
- if ((msg->type == LDAP_TAG_AbandonRequest) ||
- (msg->type == LDAP_TAG_UnbindRequest))
- return True;
-
- entry = malloc(sizeof(*entry));
-
- if (entry == NULL)
- return False;
-
- entry->msgid = msg->messageid;
- entry->msg = NULL;
- DLIST_ADD(conn->outstanding, entry);
-
- return True;
-}
-
-BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
- const struct timeval *endtime)
-{
- struct asn1_data data;
- BOOL result;
-
- if (!asn1_read_sequence_until(conn->sock, &data, endtime))
- return False;
-
- result = ldap_decode(&data, msg);
-
- asn1_free(&data);
- return result;
-}
-
-static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
- int msgid)
-{
- struct ldap_queue_entry *e;
-
- for (e = conn->outstanding; e != NULL; e = e->next) {
-
- if (e->msgid == msgid) {
- struct ldap_message *result = e->msg;
- DLIST_REMOVE(conn->outstanding, e);
- SAFE_FREE(e);
- return result;
- }
- }
-
- return NULL;
-}
-
-static void add_search_entry(struct ldap_connection *conn,
- struct ldap_message *msg)
-{
- struct ldap_queue_entry *e = malloc(sizeof *e);
-
- if (e == NULL)
- return;
-
- e->msg = msg;
- DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
- return;
-}
-
-static void fill_outstanding_request(struct ldap_connection *conn,
- struct ldap_message *msg)
-{
- struct ldap_queue_entry *e;
-
- for (e = conn->outstanding; e != NULL; e = e->next) {
- if (e->msgid == msg->messageid) {
- e->msg = msg;
- return;
- }
- }
-
- /* This reply has not been expected, destroy the incoming msg */
- destroy_ldap_message(msg);
- return;
-}
-
-struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
- const struct timeval *endtime)
-{
- struct ldap_message *result = recv_from_queue(conn, msgid);
-
- if (result != NULL)
- return result;
-
- while (True) {
- struct asn1_data data;
- BOOL res;
-
- result = new_ldap_message();
-
- if (!asn1_read_sequence_until(conn->sock, &data, endtime))
- return NULL;
-
- res = ldap_decode(&data, result);
- asn1_free(&data);
-
- if (!res)
- return NULL;
-
- if (result->messageid == msgid)
- return result;
-
- if (result->type == LDAP_TAG_SearchResultEntry) {
- add_search_entry(conn, result);
- } else {
- fill_outstanding_request(conn, result);
- }
- }
-
- return NULL;
-}
-
-struct ldap_message *ldap_transaction(struct ldap_connection *conn,
- struct ldap_message *request)
-{
- if (!ldap_send_msg(conn, request, NULL))
- return False;
-
- return ldap_receive(conn, request->messageid, NULL);
-}
-
-int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
-{
- struct ldap_message *response;
- struct ldap_message *msg;
- const char *dn, *pw;
- int result = LDAP_OTHER;
-
- if (conn == NULL)
- return result;
-
- if (userdn) {
- dn = userdn;
- } else {
- if (conn->auth_dn) {
- dn = conn->auth_dn;
- } else {
- dn = "";
- }
- }
-
- if (password) {
- pw = password;
- } else {
- if (conn->simple_pw) {
- pw = conn->simple_pw;
- } else {
- pw = "";
- }
- }
-
- msg = new_ldap_simple_bind_msg(dn, pw);
- if (!msg)
- return result;
-
- response = ldap_transaction(conn, msg);
- if (!response) {
- destroy_ldap_message(msg);
- return result;
- }
-
- result = response->r.BindResponse.response.resultcode;
-
- destroy_ldap_message(msg);
- destroy_ldap_message(response);
-
- return result;
-}
-
-int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
-{
- NTSTATUS status;
- TALLOC_CTX *mem_ctx = NULL;
- struct ldap_message *response;
- struct ldap_message *msg;
- DATA_BLOB input = data_blob(NULL, 0);
- DATA_BLOB output = data_blob(NULL, 0);
- int result = LDAP_OTHER;
-
- if (conn == NULL)
- return result;
-
- status = gensec_client_start(conn, &conn->gensec);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
- return result;
- }
-
- gensec_want_feature(conn->gensec, GENSEC_WANT_SIGN | GENSEC_WANT_SEAL);
-
- status = gensec_set_domain(conn->gensec, domain);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n",
- domain, nt_errstr(status)));
- goto done;
- }
-
- status = gensec_set_username(conn->gensec, username);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n",
- username, nt_errstr(status)));
- goto done;
- }
-
- status = gensec_set_password(conn->gensec, password);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Failed to start set GENSEC client password: %s\n",
- nt_errstr(status)));
- goto done;
- }
-
- status = gensec_set_target_hostname(conn->gensec, conn->host);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n",
- nt_errstr(status)));
- goto done;
- }
-
- status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
- nt_errstr(status)));
- goto done;
- }
-
- mem_ctx = talloc_init("ldap_bind_sasl");
- if (!mem_ctx)
- goto done;
-
- status = gensec_update(conn->gensec, mem_ctx,
- input,
- &output);
-
- while(1) {
- if (NT_STATUS_IS_OK(status) && output.length == 0) {
- break;
- }
- if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
- break;
- }
-
- msg = new_ldap_sasl_bind_msg("GSS-SPNEGO", &output);
- if (!msg)
- goto done;
-
- response = ldap_transaction(conn, msg);
- destroy_ldap_message(msg);
-
- if (!response) {
- goto done;
- }
-
- result = response->r.BindResponse.response.resultcode;
-
- if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
- break;
- }
-
- status = gensec_update(conn->gensec, mem_ctx,
- response->r.BindResponse.SASL.secblob,
- &output);
-
- destroy_ldap_message(response);
- }
-
-done:
- if (mem_ctx)
- talloc_destroy(mem_ctx);
-
- return result;
-}
-
-BOOL ldap_setup_connection(struct ldap_connection *conn,
- const char *url, const char *userdn, const char *password)
-{
- int result;
-
- if (!ldap_connect(conn, url)) {
- return False;
- }
-
- result = ldap_bind_simple(conn, userdn, password);
- if (result == LDAP_SUCCESS) {
- return True;
- }
-
- return False;
-}
-
-BOOL ldap_setup_connection_with_sasl(struct ldap_connection *conn, const char *url, const char *username, const char *domain, const char *password)
-{
- int result;
-
- if (!ldap_connect(conn, url)) {
- return False;
- }
-
- result = ldap_bind_sasl(conn, username, domain, password);
- if (result == LDAP_SUCCESS) {
- return True;
- }
-
- return False;
-}
-
-static BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
- const struct timeval *endtime)
-{
- struct ldap_message *msg = new_ldap_message();
- BOOL result;
-
- if (msg == NULL)
- return False;
-
- msg->type = LDAP_TAG_AbandonRequest;
- msg->r.AbandonRequest.messageid = msgid;
-
- result = ldap_send_msg(conn, msg, endtime);
- destroy_ldap_message(msg);
- return result;
-}
-
-struct ldap_message *new_ldap_search_message(const char *base,
- enum ldap_scope scope,
- char *filter,
- int num_attributes,
- const char **attributes)
-{
- struct ldap_message *res = new_ldap_message();
-
- if (res == NULL)
- return NULL;
-
- res->type = LDAP_TAG_SearchRequest;
- res->r.SearchRequest.basedn = base;
- res->r.SearchRequest.scope = scope;
- res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
- res->r.SearchRequest.timelimit = 0;
- res->r.SearchRequest.sizelimit = 0;
- res->r.SearchRequest.attributesonly = False;
- res->r.SearchRequest.filter = filter;
- res->r.SearchRequest.num_attributes = num_attributes;
- res->r.SearchRequest.attributes = attributes;
- return res;
-}
-
-struct ldap_message *new_ldap_simple_bind_msg(const char *dn, const char *pw)
-{
- struct ldap_message *res = new_ldap_message();
-
- if (res == NULL)
- return NULL;
-
- res->type = LDAP_TAG_BindRequest;
- res->r.BindRequest.version = 3;
- res->r.BindRequest.dn = talloc_strdup(res->mem_ctx, dn);
- res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
- res->r.BindRequest.creds.password = talloc_strdup(res->mem_ctx, pw);
- return res;
-}
-
-struct ldap_message *new_ldap_sasl_bind_msg(const char *sasl_mechanism, DATA_BLOB *secblob)
-{
- struct ldap_message *res = new_ldap_message();
-
- if (res == NULL)
- return NULL;
-
- res->type = LDAP_TAG_BindRequest;
- res->r.BindRequest.version = 3;
- res->r.BindRequest.dn = "";
- res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
- res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res->mem_ctx, sasl_mechanism);
- res->r.BindRequest.creds.SASL.secblob = *secblob;
- return res;
-}
-
-BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
- const struct timeval *endtime)
-{
- if ((conn->searchid != 0) &&
- (!ldap_abandon_message(conn, conn->searchid, endtime)))
- return False;
-
- conn->searchid = conn->next_msgid;
- return ldap_send_msg(conn, msg, endtime);
-}
-
-struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
- const struct timeval *endtime)
-{
- struct ldap_message *result;
-
- if (conn->search_entries != NULL) {
- struct ldap_queue_entry *e = conn->search_entries;
-
- result = e->msg;
- DLIST_REMOVE(conn->search_entries, e);
- SAFE_FREE(e);
- return result;
- }
-
- result = ldap_receive(conn, conn->searchid, endtime);
- if (!result) {
- return NULL;
- }
-
- if (result->type == LDAP_TAG_SearchResultEntry)
- return result;
-
- if (result->type == LDAP_TAG_SearchResultDone) {
- /* TODO: Handle Paged Results */
- destroy_ldap_message(result);
- return NULL;
- }
-
- /* TODO: Handle Search References here */
- return NULL;
-}
-
-void ldap_endsearchent(struct ldap_connection *conn,
- const struct timeval *endtime)
-{
- struct ldap_queue_entry *e;
-
- e = conn->search_entries;
-
- while (e != NULL) {
- struct ldap_queue_entry *next = e->next;
- DLIST_REMOVE(conn->search_entries, e);
- SAFE_FREE(e);
- e = next;
- }
-}
-
-struct ldap_message *ldap_searchone(struct ldap_connection *conn,
- struct ldap_message *msg,
- const struct timeval *endtime)
-{
- struct ldap_message *res1, *res2 = NULL;
- if (!ldap_setsearchent(conn, msg, endtime))
- return NULL;
-
- res1 = ldap_getsearchent(conn, endtime);
-
- if (res1 != NULL)
- res2 = ldap_getsearchent(conn, endtime);
-
- ldap_endsearchent(conn, endtime);
-
- if (res1 == NULL)
- return NULL;
-
- if (res2 != NULL) {
- /* More than one entry */
- destroy_ldap_message(res1);
- destroy_ldap_message(res2);
- return NULL;
- }
-
- return res1;
-}
-
-BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
- DATA_BLOB *value)
-{
- int i;
- struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
-
- if (msg->type != LDAP_TAG_SearchResultEntry)
- return False;
-
- for (i=0; i<r->num_attributes; i++) {
- if (strequal(attr, r->attributes[i].name)) {
- if (r->attributes[i].num_values != 1)
- return False;
-
- *value = r->attributes[i].values[0];
- return True;
- }
- }
- return False;
-}
-
-BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
- TALLOC_CTX *mem_ctx, char **value)
-{
- DATA_BLOB blob;
-
- if (!ldap_find_single_value(msg, attr, &blob))
- return False;
-
- *value = talloc(mem_ctx, blob.length+1);
-
- if (*value == NULL)
- return False;
-
- memcpy(*value, blob.data, blob.length);
- (*value)[blob.length] = '\0';
- return True;
-}
-
-BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
- int *value)
-{
- DATA_BLOB blob;
- char *val;
- int errno_save;
- BOOL res;
-
- if (!ldap_find_single_value(msg, attr, &blob))
- return False;
-
- val = malloc(blob.length+1);
- if (val == NULL)
- return False;
-
- memcpy(val, blob.data, blob.length);
- val[blob.length] = '\0';
-
- errno_save = errno;
- errno = 0;
-
- *value = strtol(val, NULL, 10);
-
- res = (errno == 0);
-
- free(val);
- errno = errno_save;
-
- return res;
-}
-
-int ldap_error(struct ldap_connection *conn)
-{
- return 0;
-}
-
-NTSTATUS ldap2nterror(int ldaperror)
-{
- return NT_STATUS_OK;
-}
diff --git a/source4/libcli/ldap/ldap_client.c b/source4/libcli/ldap/ldap_client.c
new file mode 100644
index 0000000000..7a72734c57
--- /dev/null
+++ b/source4/libcli/ldap/ldap_client.c
@@ -0,0 +1,690 @@
+/*
+ Unix SMB/CIFS mplementation.
+ LDAP protocol helper functions for SAMBA
+
+ Copyright (C) Andrew Tridgell 2004
+ Copyright (C) Volker Lendecke 2004
+ Copyright (C) Stefan Metzmacher 2004
+ Copyright (C) Simo Sorce 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "includes.h"
+#include "system/network.h"
+#include "auth/auth.h"
+#include "asn_1.h"
+#include "dlinklist.h"
+
+#if 0
+static struct ldap_message *new_ldap_search_message(struct ldap_connection *conn,
+ const char *base,
+ enum ldap_scope scope,
+ char *filter,
+ int num_attributes,
+ const char **attributes)
+{
+ struct ldap_message *res;
+
+ res = new_ldap_message(conn);
+ if (!res) {
+ return NULL;
+ }
+
+ res->type = LDAP_TAG_SearchRequest;
+ res->r.SearchRequest.basedn = base;
+ res->r.SearchRequest.scope = scope;
+ res->r.SearchRequest.deref = LDAP_DEREFERENCE_NEVER;
+ res->r.SearchRequest.timelimit = 0;
+ res->r.SearchRequest.sizelimit = 0;
+ res->r.SearchRequest.attributesonly = False;
+ res->r.SearchRequest.filter = filter;
+ res->r.SearchRequest.num_attributes = num_attributes;
+ res->r.SearchRequest.attributes = attributes;
+
+ return res;
+}
+#endif
+
+static struct ldap_message *new_ldap_simple_bind_msg(struct ldap_connection *conn, const char *dn, const char *pw)
+{
+ struct ldap_message *res;
+
+ res = new_ldap_message(conn);
+ if (!res) {
+ return NULL;
+ }
+
+ res->type = LDAP_TAG_BindRequest;
+ res->r.BindRequest.version = 3;
+ res->r.BindRequest.dn = talloc_strdup(res->mem_ctx, dn);
+ res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SIMPLE;
+ res->r.BindRequest.creds.password = talloc_strdup(res->mem_ctx, pw);
+
+ return res;
+}
+
+static struct ldap_message *new_ldap_sasl_bind_msg(struct ldap_connection *conn, const char *sasl_mechanism, DATA_BLOB *secblob)
+{
+ struct ldap_message *res;
+
+ res = new_ldap_message(conn);
+ if (!res) {
+ return NULL;
+ }
+
+ res->type = LDAP_TAG_BindRequest;
+ res->r.BindRequest.version = 3;
+ res->r.BindRequest.dn = "";
+ res->r.BindRequest.mechanism = LDAP_AUTH_MECH_SASL;
+ res->r.BindRequest.creds.SASL.mechanism = talloc_strdup(res->mem_ctx, sasl_mechanism);
+ res->r.BindRequest.creds.SASL.secblob = *secblob;
+
+ return res;
+}
+
+static struct ldap_connection *new_ldap_connection(TALLOC_CTX *mem_ctx)
+{
+ struct ldap_connection *result;
+
+ result = talloc_p(mem_ctx, struct ldap_connection);
+
+ if (!result) {
+ return NULL;
+ }
+
+ result->mem_ctx = result;
+ result->next_msgid = 1;
+ result->outstanding = NULL;
+ result->searchid = 0;
+ result->search_entries = NULL;
+ result->auth_dn = NULL;
+ result->simple_pw = NULL;
+ result->gensec = NULL;
+
+ return result;
+}
+
+struct ldap_connection *ldap_connect(TALLOC_CTX *mem_ctx, const char *url)
+{
+ struct hostent *hp;
+ struct ipv4_addr ip;
+ struct ldap_connection *conn;
+ BOOL ret;
+
+ conn = new_ldap_connection(mem_ctx);
+ if (!conn) {
+ return NULL;
+ }
+
+ ret = ldap_parse_basic_url(conn->mem_ctx, url, &conn->host,
+ &conn->port, &conn->ldaps);
+ if (!ret) {
+ talloc_free(conn);
+ return NULL;
+ }
+
+ hp = sys_gethostbyname(conn->host);
+ if (!hp || !hp->h_addr) {
+ talloc_free(conn);
+ return NULL;
+ }
+
+ putip((char *)&ip, (char *)hp->h_addr);
+
+ conn->sock = open_socket_out(SOCK_STREAM, &ip, conn->port, LDAP_CONNECTION_TIMEOUT);
+ if (conn->sock < 0) {
+ talloc_free(conn);
+ return NULL;
+ }
+
+ return conn;
+}
+
+struct ldap_message *new_ldap_message(TALLOC_CTX *mem_ctx)
+{
+ struct ldap_message *result;
+
+ result = talloc_p(mem_ctx, struct ldap_message);
+
+ if (!result) {
+ return NULL;
+ }
+
+ result->mem_ctx = result;
+
+ return result;
+}
+
+BOOL ldap_send_msg(struct ldap_connection *conn, struct ldap_message *msg,
+ const struct timeval *endtime)
+{
+ DATA_BLOB request;
+ BOOL result;
+ struct ldap_queue_entry *entry;
+
+ msg->messageid = conn->next_msgid++;
+
+ if (!ldap_encode(msg, &request))
+ return False;
+
+ result = (write_data_until(conn->sock, request.data, request.length,
+ endtime) == request.length);
+
+ data_blob_free(&request);
+
+ if (!result)
+ return result;
+
+ /* abandon and unbind don't expect results */
+
+ if ((msg->type == LDAP_TAG_AbandonRequest) ||
+ (msg->type == LDAP_TAG_UnbindRequest))
+ return True;
+
+ entry = malloc(sizeof(*entry));
+
+ if (entry == NULL)
+ return False;
+
+ entry->msgid = msg->messageid;
+ entry->msg = NULL;
+ DLIST_ADD(conn->outstanding, entry);
+
+ return True;
+}
+
+BOOL ldap_receive_msg(struct ldap_connection *conn, struct ldap_message *msg,
+ const struct timeval *endtime)
+{
+ struct asn1_data data;
+ BOOL result;
+
+ if (!asn1_read_sequence_until(conn->sock, &data, endtime))
+ return False;
+
+ result = ldap_decode(&data, msg);
+
+ asn1_free(&data);
+ return result;
+}
+
+static struct ldap_message *recv_from_queue(struct ldap_connection *conn,
+ int msgid)
+{
+ struct ldap_queue_entry *e;
+
+ for (e = conn->outstanding; e != NULL; e = e->next) {
+
+ if (e->msgid == msgid) {
+ struct ldap_message *result = e->msg;
+ DLIST_REMOVE(conn->outstanding, e);
+ SAFE_FREE(e);
+ return result;
+ }
+ }
+
+ return NULL;
+}
+
+static void add_search_entry(struct ldap_connection *conn,
+ struct ldap_message *msg)
+{
+ struct ldap_queue_entry *e = malloc(sizeof *e);
+
+ if (e == NULL)
+ return;
+
+ e->msg = msg;
+ DLIST_ADD_END(conn->search_entries, e, struct ldap_queue_entry *);
+ return;
+}
+
+static void fill_outstanding_request(struct ldap_connection *conn,
+ struct ldap_message *msg)
+{
+ struct ldap_queue_entry *e;
+
+ for (e = conn->outstanding; e != NULL; e = e->next) {
+ if (e->msgid == msg->messageid) {
+ e->msg = msg;
+ return;
+ }
+ }
+
+ /* This reply has not been expected, destroy the incoming msg */
+ talloc_free(msg);
+ return;
+}
+
+struct ldap_message *ldap_receive(struct ldap_connection *conn, int msgid,
+ const struct timeval *endtime)
+{
+ struct ldap_message *result = recv_from_queue(conn, msgid);
+
+ if (result != NULL)
+ return result;
+
+ while (True) {
+ struct asn1_data data;
+ BOOL res;
+
+ result = new_ldap_message(conn);
+
+ if (!asn1_read_sequence_until(conn->sock, &data, endtime))
+ return NULL;
+
+ res = ldap_decode(&data, result);
+ asn1_free(&data);
+
+ if (!res)
+ return NULL;
+
+ if (result->messageid == msgid)
+ return result;
+
+ if (result->type == LDAP_TAG_SearchResultEntry) {
+ add_search_entry(conn, result);
+ } else {
+ fill_outstanding_request(conn, result);
+ }
+ }
+
+ return NULL;
+}
+
+struct ldap_message *ldap_transaction(struct ldap_connection *conn,
+ struct ldap_message *request)
+{
+ if (!ldap_send_msg(conn, request, NULL))
+ return False;
+
+ return ldap_receive(conn, request->messageid, NULL);
+}
+
+int ldap_bind_simple(struct ldap_connection *conn, const char *userdn, const char *password)
+{
+ struct ldap_message *response;
+ struct ldap_message *msg;
+ const char *dn, *pw;
+ int result = LDAP_OTHER;
+
+ if (conn == NULL)
+ return result;
+
+ if (userdn) {
+ dn = userdn;
+ } else {
+ if (conn->auth_dn) {
+ dn = conn->auth_dn;
+ } else {
+ dn = "";
+ }
+ }
+
+ if (password) {
+ pw = password;
+ } else {
+ if (conn->simple_pw) {
+ pw = conn->simple_pw;
+ } else {
+ pw = "";
+ }
+ }
+
+ msg = new_ldap_simple_bind_msg(conn, dn, pw);
+ if (!msg)
+ return result;
+
+ response = ldap_transaction(conn, msg);
+ if (!response) {
+ talloc_free(msg);
+ return result;
+ }
+
+ result = response->r.BindResponse.response.resultcode;
+
+ talloc_free(msg);
+ talloc_free(response);
+
+ return result;
+}
+
+int ldap_bind_sasl(struct ldap_connection *conn, const char *username, const char *domain, const char *password)
+{
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx = NULL;
+ struct ldap_message *response;
+ struct ldap_message *msg;
+ DATA_BLOB input = data_blob(NULL, 0);
+ DATA_BLOB output = data_blob(NULL, 0);
+ int result = LDAP_OTHER;
+
+ if (conn == NULL)
+ return result;
+
+ status = gensec_client_start(conn, &conn->gensec);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("Failed to start GENSEC engine (%s)\n", nt_errstr(status)));
+ return result;
+ }
+
+ gensec_want_feature(conn->gensec, GENSEC_WANT_SIGN | GENSEC_WANT_SEAL);
+
+ status = gensec_set_domain(conn->gensec, domain);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client domain to %s: %s\n",
+ domain, nt_errstr(status)));
+ goto done;
+ }
+
+ status = gensec_set_username(conn->gensec, username);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client username to %s: %s\n",
+ username, nt_errstr(status)));
+ goto done;
+ }
+
+ status = gensec_set_password(conn->gensec, password);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client password: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ status = gensec_set_target_hostname(conn->gensec, conn->host);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC target hostname: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ status = gensec_start_mech_by_sasl_name(conn->gensec, "GSS-SPNEGO");
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(1, ("Failed to start set GENSEC client SPNEGO mechanism: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+
+ mem_ctx = talloc_init("ldap_bind_sasl");
+ if (!mem_ctx)
+ goto done;
+
+ status = gensec_update(conn->gensec, mem_ctx,
+ input,
+ &output);
+
+ while(1) {
+ if (NT_STATUS_IS_OK(status) && output.length == 0) {
+ break;
+ }
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
+ break;
+ }
+
+ msg = new_ldap_sasl_bind_msg(conn, "GSS-SPNEGO", &output);
+ if (!msg)
+ goto done;
+
+ response = ldap_transaction(conn, msg);
+ talloc_free(msg);
+
+ if (!response) {
+ goto done;
+ }
+
+ result = response->r.BindResponse.response.resultcode;
+
+ if (result != LDAP_SUCCESS && result != LDAP_SASL_BIND_IN_PROGRESS) {
+ break;
+ }
+
+ status = gensec_update(conn->gensec, mem_ctx,
+ response->r.BindResponse.SASL.secblob,
+ &output);
+
+ talloc_free(response);
+ }
+
+done:
+ if (mem_ctx)
+ talloc_destroy(mem_ctx);
+
+ return result;
+}
+
+struct ldap_connection *ldap_setup_connection(TALLOC_CTX *mem_ctx, const char *url,
+ const char *userdn, const char *password)
+{
+ struct ldap_connection *conn;
+ int result;
+
+ conn =ldap_connect(mem_ctx, url);
+ if (!conn) {
+ return NULL;
+ }
+
+ result = ldap_bind_simple(conn, userdn, password);
+ if (result != LDAP_SUCCESS) {
+ talloc_free(conn);
+ return NULL;
+ }
+
+ return conn;
+}
+
+struct ldap_connection *ldap_setup_connection_with_sasl(TALLOC_CTX *mem_ctx, const char *url,
+ const char *username, const char *domain, const char *password)
+{
+ struct ldap_connection *conn;
+ int result;
+
+ conn =ldap_connect(mem_ctx, url);
+ if (!conn) {
+ return NULL;
+ }
+
+ result = ldap_bind_sasl(conn, username, domain, password);
+ if (result != LDAP_SUCCESS) {
+ talloc_free(conn);
+ return NULL;
+ }
+
+ return conn;
+}
+
+BOOL ldap_abandon_message(struct ldap_connection *conn, int msgid,
+ const struct timeval *endtime)
+{
+ struct ldap_message *msg = new_ldap_message(conn);
+ BOOL result;
+
+ if (msg == NULL)
+ return False;
+
+ msg->type = LDAP_TAG_AbandonRequest;
+ msg->r.AbandonRequest.messageid = msgid;
+
+ result = ldap_send_msg(conn, msg, endtime);
+ talloc_free(msg);
+ return result;
+}
+
+BOOL ldap_setsearchent(struct ldap_connection *conn, struct ldap_message *msg,
+ const struct timeval *endtime)
+{
+ if ((conn->searchid != 0) &&
+ (!ldap_abandon_message(conn, conn->searchid, endtime)))
+ return False;
+
+ conn->searchid = conn->next_msgid;
+ return ldap_send_msg(conn, msg, endtime);
+}
+
+struct ldap_message *ldap_getsearchent(struct ldap_connection *conn,
+ const struct timeval *endtime)
+{
+ struct ldap_message *result;
+
+ if (conn->search_entries != NULL) {
+ struct ldap_queue_entry *e = conn->search_entries;
+
+ result = e->msg;
+ DLIST_REMOVE(conn->search_entries, e);
+ SAFE_FREE(e);
+ return result;
+ }
+
+ result = ldap_receive(conn, conn->searchid, endtime);
+ if (!result) {
+ return NULL;
+ }
+
+ if (result->type == LDAP_TAG_SearchResultEntry)
+ return result;
+
+ if (result->type == LDAP_TAG_SearchResultDone) {
+ /* TODO: Handle Paged Results */
+ talloc_free(result);
+ return NULL;
+ }
+
+ /* TODO: Handle Search References here */
+ return NULL;
+}
+
+void ldap_endsearchent(struct ldap_connection *conn,
+ const struct timeval *endtime)
+{
+ struct ldap_queue_entry *e;
+
+ e = conn->search_entries;
+
+ while (e != NULL) {
+ struct ldap_queue_entry *next = e->next;
+ DLIST_REMOVE(conn->search_entries, e);
+ SAFE_FREE(e);
+ e = next;
+ }
+}
+
+struct ldap_message *ldap_searchone(struct ldap_connection *conn,
+ struct ldap_message *msg,
+ const struct timeval *endtime)
+{
+ struct ldap_message *res1, *res2 = NULL;
+ if (!ldap_setsearchent(conn, msg, endtime))
+ return NULL;
+
+ res1 = ldap_getsearchent(conn, endtime);
+
+ if (res1 != NULL)
+ res2 = ldap_getsearchent(conn, endtime);
+
+ ldap_endsearchent(conn, endtime);
+
+ if (res1 == NULL)
+ return NULL;
+
+ if (res2 != NULL) {
+ /* More than one entry */
+ talloc_free(res1);
+ talloc_free(res2);
+ return NULL;
+ }
+
+ return res1;
+}
+
+BOOL ldap_find_single_value(struct ldap_message *msg, const char *attr,
+ DATA_BLOB *value)
+{
+ int i;
+ struct ldap_SearchResEntry *r = &msg->r.SearchResultEntry;
+
+ if (msg->type != LDAP_TAG_SearchResultEntry)
+ return False;
+
+ for (i=0; i<r->num_attributes; i++) {
+ if (strequal(attr, r->attributes[i].name)) {
+ if (r->attributes[i].num_values != 1)
+ return False;
+
+ *value = r->attributes[i].values[0];
+ return True;
+ }
+ }
+ return False;
+}
+
+BOOL ldap_find_single_string(struct ldap_message *msg, const char *attr,
+ TALLOC_CTX *mem_ctx, char **value)
+{
+ DATA_BLOB blob;
+
+ if (!ldap_find_single_value(msg, attr, &blob))
+ return False;
+
+ *value = talloc(mem_ctx, blob.length+1);
+
+ if (*value == NULL)
+ return False;
+
+ memcpy(*value, blob.data, blob.length);
+ (*value)[blob.length] = '\0';
+ return True;
+}
+
+BOOL ldap_find_single_int(struct ldap_message *msg, const char *attr,
+ int *value)
+{
+ DATA_BLOB blob;
+ char *val;
+ int errno_save;
+ BOOL res;
+
+ if (!ldap_find_single_value(msg, attr, &blob))
+ return False;
+
+ val = malloc(blob.length+1);
+ if (val == NULL)
+ return False;
+
+ memcpy(val, blob.data, blob.length);
+ val[blob.length] = '\0';
+
+ errno_save = errno;
+ errno = 0;
+
+ *value = strtol(val, NULL, 10);
+
+ res = (errno == 0);
+
+ free(val);
+ errno = errno_save;
+
+ return res;
+}
+
+int ldap_error(struct ldap_connection *conn)
+{
+ return 0;
+}
+
+NTSTATUS ldap2nterror(int ldaperror)
+{
+ return NT_STATUS_OK;
+}
diff --git a/source4/libcli/ldap/ldap_ldif.c b/source4/libcli/ldap/ldap_ldif.c
index 19f4e56e73..c276b7e917 100644
--- a/source4/libcli/ldap/ldap_ldif.c
+++ b/source4/libcli/ldap/ldap_ldif.c
@@ -307,7 +307,7 @@ static BOOL fill_mods(struct ldap_message *msg, char **chunk)
/*
read from a LDIF source, creating a ldap_message
*/
-static struct ldap_message *ldif_read(int (*fgetc_fn)(void *),
+static struct ldap_message *ldif_read(TALLOC_CTX *mem_ctx, int (*fgetc_fn)(void *),
void *private_data)
{
struct ldap_message *msg;
@@ -318,7 +318,7 @@ static struct ldap_message *ldif_read(int (*fgetc_fn)(void *),
value.data = NULL;
- msg = new_ldap_message();
+ msg = new_ldap_message(mem_ctx);
if (msg == NULL)
return NULL;
@@ -383,7 +383,7 @@ static struct ldap_message *ldif_read(int (*fgetc_fn)(void *),
DEBUG(3, ("changetype %s not supported\n", (char *)value.data));
failed:
- destroy_ldap_message(msg);
+ talloc_free(msg);
return NULL;
}
@@ -403,10 +403,10 @@ static int fgetc_string(void *private_data)
return EOF;
}
-struct ldap_message *ldap_ldif2msg(const char *s)
+struct ldap_message *ldap_ldif2msg(TALLOC_CTX *mem_ctx, const char *s)
{
struct ldif_read_string_state state;
state.s = s;
- return ldif_read(fgetc_string, &state);
+ return ldif_read(mem_ctx, fgetc_string, &state);
}
diff --git a/source4/torture/ldap/basic.c b/source4/torture/ldap/basic.c
index 4a0ae772d2..8b1aca05f4 100644
--- a/source4/torture/ldap/basic.c
+++ b/source4/torture/ldap/basic.c
@@ -82,7 +82,7 @@ static BOOL test_search_rootDSE(struct ldap_connection *conn, char **basedn)
conn->searchid = 0;
conn->next_msgid = 30;
- msg = new_ldap_message();
+ msg = new_ldap_message(conn);
if (!msg) {
return False;
}
@@ -147,7 +147,7 @@ static BOOL test_compare_sasl(struct ldap_connection *conn, const char *basedn)
conn->next_msgid = 55;
- msg = new_ldap_message();
+ msg = new_ldap_message(conn);
if (!msg) {
return False;
}
@@ -200,7 +200,7 @@ BOOL torture_ldap_basic(void)
url = talloc_asprintf(mem_ctx, "ldap://%s/", host);
- status = torture_ldap_connection(&conn, url, userdn, secret);
+ status = torture_ldap_connection(mem_ctx, &conn, url, userdn, secret);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
diff --git a/source4/torture/ldap/common.c b/source4/torture/ldap/common.c
index a0fe31d0e9..eea3b12073 100644
--- a/source4/torture/ldap/common.c
+++ b/source4/torture/ldap/common.c
@@ -67,25 +67,25 @@ NTSTATUS torture_ldap_bind_sasl(struct ldap_connection *conn, const char *userna
}
/* open a ldap connection to a server */
-NTSTATUS torture_ldap_connection(struct ldap_connection **conn,
+NTSTATUS torture_ldap_connection(TALLOC_CTX *mem_ctx, struct ldap_connection **conn,
const char *url, const char *userdn, const char *password)
{
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- BOOL ret;
+ int ret;
if (!url) {
printf("You must specify a url string\n");
return NT_STATUS_INVALID_PARAMETER;
}
- *conn = new_ldap_connection();
+ *conn = ldap_connect(mem_ctx, url);
if (!*conn) {
printf("Failed to initialize ldap_connection structure\n");
return status;
}
- ret = ldap_setup_connection(*conn, url, userdn, password);
- if (!ret) {
+ ret = ldap_bind_simple(*conn, userdn, password);
+ if (ret != LDAP_SUCCESS) {
printf("Failed to connect with url [%s]\n", url);
/* FIXME: what abut actually implementing an ldap_connection_free() function ?
:-) sss */