From 8408b3428d8c263f8453a0da8ef71e7fc1e4ec81 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sat, 6 Nov 2004 20:15:39 +0000 Subject: 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) --- source4/libcli/ldap/config.mk | 1 + source4/libcli/ldap/ldap.c | 655 +----------------------------------- source4/libcli/ldap/ldap_client.c | 690 ++++++++++++++++++++++++++++++++++++++ source4/libcli/ldap/ldap_ldif.c | 10 +- source4/torture/ldap/basic.c | 6 +- source4/torture/ldap/common.c | 10 +- 6 files changed, 707 insertions(+), 665 deletions(-) create mode 100644 source4/libcli/ldap/ldap_client.c 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; inum_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; inum_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 */ -- cgit