*/
#include "includes.h"
-#include "asn_1.h"
-#include "dlinklist.h"
+#include "libcli/util/asn_1.h"
+#include "lib/util/dlinklist.h"
#include "lib/events/events.h"
#include "lib/socket/socket.h"
-#include "lib/tls/tls.h"
#include "libcli/ldap/ldap.h"
#include "libcli/ldap/ldap_client.h"
+#include "libcli/composite/composite.h"
+#include "lib/stream/packet.h"
+#include "lib/tls/tls.h"
+#include "auth/gensec/gensec.h"
+#include "system/time.h"
/*
/* set a reasonable request timeout */
conn->timeout = 60;
+ /* explicitly avoid reconnections by default */
+ conn->reconnect.max_retries = 0;
+
return conn;
}
-
/*
the connection is dead
*/
{
struct ldap_request *req;
+ /* return an error for any pending request ... */
while (conn->pending) {
req = conn->pending;
DLIST_REMOVE(req->conn->pending, req);
if (req->async.fn) {
req->async.fn(req);
}
- }
-
- while (conn->send_queue) {
- req = conn->send_queue;
- DLIST_REMOVE(req->conn->send_queue, req);
- req->state = LDAP_REQUEST_DONE;
- req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
- if (req->async.fn) {
- req->async.fn(req);
- }
}
- talloc_free(conn->tls);
- conn->tls = NULL;
+ talloc_free(conn->sock); /* this will also free event.fde */
+ talloc_free(conn->packet);
+ conn->sock = NULL;
+ conn->event.fde = NULL;
+ conn->packet = NULL;
+}
+
+static void ldap_reconnect(struct ldap_connection *conn);
+
+/*
+ handle packet errors
+*/
+static void ldap_error_handler(void *private_data, NTSTATUS status)
+{
+ struct ldap_connection *conn = talloc_get_type(private_data,
+ struct ldap_connection);
+ ldap_connection_dead(conn);
+
+ /* but try to reconnect so that the ldb client can go on */
+ ldap_reconnect(conn);
}
for (req=conn->pending; req; req=req->next) {
if (req->messageid == msg->messageid) break;
}
+ /* match a zero message id to the last request sent.
+ It seems that servers send 0 if unable to parse */
+ if (req == NULL && msg->messageid == 0) {
+ req = conn->pending;
+ }
if (req == NULL) {
DEBUG(0,("ldap: no matching message id for %u\n",
msg->messageid));
}
}
-/*
- try and decode/process plain data
-*/
-static void ldap_try_decode_plain(struct ldap_connection *conn)
-{
- struct asn1_data asn1;
-
- if (!asn1_load(&asn1, conn->partial)) {
- ldap_connection_dead(conn);
- return;
- }
-
- /* try and decode - this will fail if we don't have a full packet yet */
- while (asn1.ofs < asn1.length) {
- struct ldap_message *msg = talloc(conn, struct ldap_message);
- off_t saved_ofs = asn1.ofs;
-
- if (msg == NULL) {
- ldap_connection_dead(conn);
- return;
- }
-
- if (ldap_decode(&asn1, msg)) {
- ldap_match_message(conn, msg);
- } else {
- asn1.ofs = saved_ofs;
- talloc_free(msg);
- break;
- }
- }
-
- /* keep any remaining data in conn->partial */
- data_blob_free(&conn->partial);
- if (asn1.ofs != asn1.length) {
- conn->partial = data_blob_talloc(conn,
- asn1.data + asn1.ofs,
- asn1.length - asn1.ofs);
- }
- asn1_free(&asn1);
-}
/*
- try and decode/process wrapped data
+ decode/process LDAP data
*/
-static void ldap_try_decode_wrapped(struct ldap_connection *conn)
+static NTSTATUS ldap_recv_handler(void *private_data, DATA_BLOB blob)
{
- uint32_t len;
-
- /* keep decoding while we have a full wrapped packet */
- while (conn->partial.length >= 4 &&
- (len=RIVAL(conn->partial.data, 0)) <= conn->partial.length-4) {
- DATA_BLOB wrapped, unwrapped;
- struct asn1_data asn1;
- struct ldap_message *msg = talloc(conn, struct ldap_message);
- NTSTATUS status;
-
- if (msg == NULL) {
- ldap_connection_dead(conn);
- return;
- }
-
- wrapped.data = conn->partial.data+4;
- wrapped.length = len;
-
- status = gensec_unwrap(conn->gensec, msg, &wrapped, &unwrapped);
- if (!NT_STATUS_IS_OK(status)) {
- ldap_connection_dead(conn);
- return;
- }
-
- if (!asn1_load(&asn1, unwrapped)) {
- ldap_connection_dead(conn);
- return;
- }
+ struct asn1_data asn1;
+ struct ldap_connection *conn = talloc_get_type(private_data,
+ struct ldap_connection);
+ struct ldap_message *msg = talloc(conn, struct ldap_message);
- while (ldap_decode(&asn1, msg)) {
- ldap_match_message(conn, msg);
- msg = talloc(conn, struct ldap_message);
- }
-
- talloc_free(msg);
- asn1_free(&asn1);
-
- if (conn->partial.length == len + 4) {
- data_blob_free(&conn->partial);
- } else {
- memmove(conn->partial.data, conn->partial.data+len+4,
- conn->partial.length - (len+4));
- conn->partial.length -= len + 4;
- }
+ if (msg == NULL) {
+ return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
}
-}
-
-/*
- handle ldap recv events
-*/
-static void ldap_recv_handler(struct ldap_connection *conn)
-{
- NTSTATUS status;
- size_t npending=0, nread;
-
- /* work out how much data is pending */
- status = tls_socket_pending(conn->tls, &npending);
- if (!NT_STATUS_IS_OK(status) || npending == 0) {
- ldap_connection_dead(conn);
- return;
+ if (!asn1_load(&asn1, blob)) {
+ return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
}
-
- conn->partial.data = talloc_realloc_size(conn, conn->partial.data,
- conn->partial.length + npending);
- if (conn->partial.data == NULL) {
- ldap_connection_dead(conn);
- return;
+
+ if (!ldap_decode(&asn1, msg)) {
+ return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
}
- /* receive the pending data */
- status = tls_socket_recv(conn->tls, conn->partial.data + conn->partial.length,
- npending, &nread);
- if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
- return;
- }
- if (!NT_STATUS_IS_OK(status)) {
- ldap_connection_dead(conn);
- return;
- }
- conn->partial.length += nread;
+ ldap_match_message(conn, msg);
- /* see if we can decode what we have */
- if (conn->enable_wrap) {
- ldap_try_decode_wrapped(conn);
- } else {
- ldap_try_decode_plain(conn);
- }
+ data_blob_free(&blob);
+ asn1_free(&asn1);
+ return NT_STATUS_OK;
}
-
-/*
- handle ldap send events
-*/
-static void ldap_send_handler(struct ldap_connection *conn)
+/* Handle read events, from the GENSEC socket callback, or real events */
+void ldap_read_io_handler(void *private_data, uint16_t flags)
{
- while (conn->send_queue) {
- struct ldap_request *req = conn->send_queue;
- size_t nsent;
- NTSTATUS status;
-
- status = tls_socket_send(conn->tls, &req->data, &nsent);
- if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
- break;
- }
- if (!NT_STATUS_IS_OK(status)) {
- ldap_connection_dead(conn);
- return;
- }
-
- req->data.data += nsent;
- req->data.length -= nsent;
- if (req->data.length == 0) {
- req->state = LDAP_REQUEST_PENDING;
- DLIST_REMOVE(conn->send_queue, req);
-
- /* some types of requests don't expect a reply */
- if (req->type == LDAP_TAG_AbandonRequest ||
- req->type == LDAP_TAG_UnbindRequest) {
- req->status = NT_STATUS_OK;
- req->state = LDAP_REQUEST_DONE;
- if (req->async.fn) {
- req->async.fn(req);
- }
- } else {
- DLIST_ADD(conn->pending, req);
- }
- }
- }
- if (conn->send_queue == NULL) {
- EVENT_FD_NOT_WRITEABLE(conn->event.fde);
- }
+ struct ldap_connection *conn = talloc_get_type(private_data,
+ struct ldap_connection);
+ packet_recv(conn->packet);
}
-
/*
handle ldap socket events
*/
static void ldap_io_handler(struct event_context *ev, struct fd_event *fde,
- uint16_t flags, void *private)
+ uint16_t flags, void *private_data)
{
- struct ldap_connection *conn = talloc_get_type(private, struct ldap_connection);
+ struct ldap_connection *conn = talloc_get_type(private_data,
+ struct ldap_connection);
if (flags & EVENT_FD_WRITE) {
- ldap_send_handler(conn);
- if (conn->tls == NULL) return;
+ packet_queue_run(conn->packet);
+ if (!tls_enabled(conn->sock)) return;
}
if (flags & EVENT_FD_READ) {
- ldap_recv_handler(conn);
+ ldap_read_io_handler(private_data, flags);
}
}
{
int tmp_port = 0;
char protocol[11];
- char tmp_host[255];
- const char *p = url;
+ char tmp_host[1025];
int ret;
- /* skip leading "URL:" (if any) */
- if (strncasecmp(p, "URL:", 4) == 0) {
- p += 4;
- }
-
/* Paranoia check */
SMB_ASSERT(sizeof(protocol)>10 && sizeof(tmp_host)>254);
- ret = sscanf(p, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
+ ret = sscanf(url, "%10[^:]://%254[^:/]:%d", protocol, tmp_host, &tmp_port);
if (ret < 2) {
return NT_STATUS_INVALID_PARAMETER;
}
/*
connect to a ldap server
*/
-NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
+
+struct ldap_connect_state {
+ struct composite_context *ctx;
+ struct ldap_connection *conn;
+};
+
+static void ldap_connect_recv_unix_conn(struct composite_context *ctx);
+static void ldap_connect_recv_tcp_conn(struct composite_context *ctx);
+
+struct composite_context *ldap_connect_send(struct ldap_connection *conn,
+ const char *url)
{
- NTSTATUS status;
+ struct composite_context *result, *ctx;
+ struct ldap_connect_state *state;
+ char protocol[11];
+ int ret;
- status = ldap_parse_basic_url(conn, url, &conn->host,
- &conn->port, &conn->ldaps);
- NT_STATUS_NOT_OK_RETURN(status);
+ result = talloc_zero(NULL, struct composite_context);
+ if (result == NULL) goto failed;
+ result->state = COMPOSITE_STATE_IN_PROGRESS;
+ result->async.fn = NULL;
+ result->event_ctx = conn->event.event_ctx;
- status = socket_create("ipv4", SOCKET_TYPE_STREAM, &conn->sock, 0);
- NT_STATUS_NOT_OK_RETURN(status);
+ state = talloc(result, struct ldap_connect_state);
+ if (state == NULL) goto failed;
+ state->ctx = result;
+ result->private_data = state;
- talloc_steal(conn, conn->sock);
+ state->conn = conn;
- /* connect in a event friendly way */
- status = socket_connect_ev(conn->sock, NULL, 0, conn->host, conn->port, 0,
- conn->event.event_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(conn->sock);
- return status;
+ if (conn->reconnect.url == NULL) {
+ conn->reconnect.url = talloc_strdup(conn, url);
+ if (conn->reconnect.url == NULL) goto failed;
+ }
+
+ /* Paranoia check */
+ SMB_ASSERT(sizeof(protocol)>10);
+
+ ret = sscanf(url, "%10[^:]://", protocol);
+ if (ret < 1) {
+ return NULL;
}
+ if (strequal(protocol, "ldapi")) {
+ struct socket_address *unix_addr;
+ char path[1025];
+
+ NTSTATUS status = socket_create("unix", SOCKET_TYPE_STREAM, &conn->sock, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ return NULL;
+ }
+ SMB_ASSERT(sizeof(protocol)>10);
+ SMB_ASSERT(sizeof(path)>1024);
+
+ ret = sscanf(url, "%10[^:]://%1025c", protocol, path);
+ if (ret < 2) {
+ composite_error(state->ctx, NT_STATUS_INVALID_PARAMETER);
+ return result;
+ }
+
+ rfc1738_unescape(path);
+
+ unix_addr = socket_address_from_strings(conn, conn->sock->backend_name,
+ path, 0);
+ if (!unix_addr) {
+ return NULL;
+ }
+
+ ctx = socket_connect_send(conn->sock, NULL, unix_addr,
+ 0, conn->event.event_ctx);
+ ctx->async.fn = ldap_connect_recv_unix_conn;
+ ctx->async.private_data = state;
+ return result;
+ } else {
+ NTSTATUS status = ldap_parse_basic_url(conn, url, &conn->host,
+ &conn->port, &conn->ldaps);
+ if (!NT_STATUS_IS_OK(state->ctx->status)) {
+ composite_error(state->ctx, status);
+ return result;
+ }
+
+ ctx = socket_connect_multi_send(state, conn->host, 1, &conn->port,
+ conn->event.event_ctx);
+ if (ctx == NULL) goto failed;
+
+ ctx->async.fn = ldap_connect_recv_tcp_conn;
+ ctx->async.private_data = state;
+ return result;
+ }
+ failed:
+ talloc_free(result);
+ return NULL;
+}
+
+static void ldap_connect_got_sock(struct composite_context *ctx, struct ldap_connection *conn)
+{
/* setup a handler for events on this socket */
conn->event.fde = event_add_fd(conn->event.event_ctx, conn->sock,
socket_get_fd(conn->sock),
EVENT_FD_READ, ldap_io_handler, conn);
if (conn->event.fde == NULL) {
- talloc_free(conn->sock);
- return NT_STATUS_INTERNAL_ERROR;
+ composite_error(ctx, NT_STATUS_INTERNAL_ERROR);
+ return;
}
- conn->tls = tls_init_client(conn->sock, conn->event.fde, conn->ldaps);
- if (conn->tls == NULL) {
+ talloc_steal(conn, conn->sock);
+ if (conn->ldaps) {
+ struct socket_context *tls_socket = tls_init_client(conn->sock, conn->event.fde);
+ if (tls_socket == NULL) {
+ talloc_free(conn->sock);
+ return;
+ }
+ talloc_unlink(conn, conn->sock);
+ conn->sock = tls_socket;
+ talloc_steal(conn, conn->sock);
+ }
+
+ conn->packet = packet_init(conn);
+ if (conn->packet == NULL) {
talloc_free(conn->sock);
- return NT_STATUS_INTERNAL_ERROR;
+ return;
}
- talloc_steal(conn, conn->tls);
- talloc_steal(conn->tls, conn->sock);
- return NT_STATUS_OK;
+ packet_set_private(conn->packet, conn);
+ packet_set_socket(conn->packet, conn->sock);
+ packet_set_callback(conn->packet, ldap_recv_handler);
+ packet_set_full_request(conn->packet, ldap_full_packet);
+ packet_set_error_handler(conn->packet, ldap_error_handler);
+ packet_set_event_context(conn->packet, conn->event.event_ctx);
+ packet_set_fde(conn->packet, conn->event.fde);
+ packet_set_serialise(conn->packet);
+
+ composite_done(ctx);
}
-/* destroy an open ldap request */
-static int ldap_request_destructor(void *ptr)
+static void ldap_connect_recv_tcp_conn(struct composite_context *ctx)
+{
+ struct ldap_connect_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct ldap_connect_state);
+ struct ldap_connection *conn = state->conn;
+ uint16_t port;
+
+ NTSTATUS status = socket_connect_multi_recv(ctx, state, &conn->sock,
+ &port);
+ if (!NT_STATUS_IS_OK(state->ctx->status)) {
+ composite_error(state->ctx, status);
+ return;
+ }
+
+ ldap_connect_got_sock(state->ctx, conn);
+}
+
+static void ldap_connect_recv_unix_conn(struct composite_context *ctx)
+{
+ struct ldap_connect_state *state =
+ talloc_get_type(ctx->async.private_data,
+ struct ldap_connect_state);
+ struct ldap_connection *conn = state->conn;
+
+ NTSTATUS status = socket_connect_recv(ctx);
+
+ if (!NT_STATUS_IS_OK(state->ctx->status)) {
+ composite_error(state->ctx, status);
+ return;
+ }
+
+ ldap_connect_got_sock(state->ctx, conn);
+}
+
+NTSTATUS ldap_connect_recv(struct composite_context *ctx)
+{
+ NTSTATUS status = composite_wait(ctx);
+ talloc_free(ctx);
+ return status;
+}
+
+NTSTATUS ldap_connect(struct ldap_connection *conn, const char *url)
+{
+ struct composite_context *ctx = ldap_connect_send(conn, url);
+ return ldap_connect_recv(ctx);
+}
+
+/* set reconnect parameters */
+
+void ldap_set_reconn_params(struct ldap_connection *conn, int max_retries)
+{
+ if (conn) {
+ conn->reconnect.max_retries = max_retries;
+ conn->reconnect.retries = 0;
+ conn->reconnect.previous = time(NULL);
+ }
+}
+
+/* Actually this function is NOT ASYNC safe, FIXME? */
+static void ldap_reconnect(struct ldap_connection *conn)
{
- struct ldap_request *req = talloc_get_type(ptr, struct ldap_request);
- if (req->state == LDAP_REQUEST_SEND) {
- DLIST_REMOVE(req->conn->send_queue, req);
+ NTSTATUS status;
+ time_t now = time(NULL);
+
+ /* do we have set up reconnect ? */
+ if (conn->reconnect.max_retries == 0) return;
+
+ /* is the retry time expired ? */
+ if (now > conn->reconnect.previous + 30) {
+ conn->reconnect.retries = 0;
+ conn->reconnect.previous = now;
+ }
+
+ /* are we reconnectind too often and too fast? */
+ if (conn->reconnect.retries > conn->reconnect.max_retries) return;
+
+ /* keep track of the number of reconnections */
+ conn->reconnect.retries++;
+
+ /* reconnect */
+ status = ldap_connect(conn, conn->reconnect.url);
+ if ( ! NT_STATUS_IS_OK(status)) {
+ return;
}
+
+ /* rebind */
+ status = ldap_rebind(conn);
+ if ( ! NT_STATUS_IS_OK(status)) {
+ ldap_connection_dead(conn);
+ }
+}
+
+/* destroy an open ldap request */
+static int ldap_request_destructor(struct ldap_request *req)
+{
if (req->state == LDAP_REQUEST_PENDING) {
DLIST_REMOVE(req->conn->pending, req);
}
called on timeout of a ldap request
*/
static void ldap_request_timeout(struct event_context *ev, struct timed_event *te,
- struct timeval t, void *private)
+ struct timeval t, void *private_data)
{
- struct ldap_request *req = talloc_get_type(private, struct ldap_request);
+ struct ldap_request *req = talloc_get_type(private_data, struct ldap_request);
req->status = NT_STATUS_IO_TIMEOUT;
- if (req->state == LDAP_REQUEST_SEND) {
- DLIST_REMOVE(req->conn->send_queue, req);
- }
if (req->state == LDAP_REQUEST_PENDING) {
DLIST_REMOVE(req->conn->pending, req);
}
}
}
+
+/*
+ called on completion of a one-way ldap request
+*/
+static void ldap_request_complete(struct event_context *ev, struct timed_event *te,
+ struct timeval t, void *private_data)
+{
+ struct ldap_request *req = talloc_get_type(private_data, struct ldap_request);
+ if (req->async.fn) {
+ req->async.fn(req);
+ }
+}
+
/*
send a ldap message - async interface
*/
struct ldap_message *msg)
{
struct ldap_request *req;
-
- if (conn->tls == NULL) {
- return NULL;
- }
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
req = talloc_zero(conn, struct ldap_request);
- if (req == NULL) goto failed;
+ if (req == NULL) return NULL;
+
+ if (conn->sock == NULL) {
+ status = NT_STATUS_INVALID_CONNECTION;
+ goto failed;
+ }
req->state = LDAP_REQUEST_SEND;
req->conn = conn;
req->messageid = conn->next_messageid++;
+ if (conn->next_messageid == 0) {
+ conn->next_messageid = 1;
+ }
req->type = msg->type;
if (req->messageid == -1) {
goto failed;
msg->messageid = req->messageid;
- if (!ldap_encode(msg, &req->data)) {
+ if (!ldap_encode(msg, &req->data, req)) {
goto failed;
}
- /* possibly encrypt/sign the request */
- if (conn->enable_wrap) {
- DATA_BLOB wrapped;
- NTSTATUS status;
-
- status = gensec_wrap(conn->gensec, req, &req->data, &wrapped);
- if (!NT_STATUS_IS_OK(status)) {
- goto failed;
- }
- data_blob_free(&req->data);
- req->data = data_blob_talloc(req, NULL, wrapped.length + 4);
- if (req->data.data == NULL) {
- goto failed;
- }
- RSIVAL(req->data.data, 0, wrapped.length);
- memcpy(req->data.data+4, wrapped.data, wrapped.length);
- data_blob_free(&wrapped);
+ status = packet_send(conn->packet, req->data);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto failed;
}
-
- if (conn->send_queue == NULL) {
- EVENT_FD_WRITEABLE(conn->event.fde);
+ /* some requests don't expect a reply, so don't add those to the
+ pending queue */
+ if (req->type == LDAP_TAG_AbandonRequest ||
+ req->type == LDAP_TAG_UnbindRequest) {
+ req->status = NT_STATUS_OK;
+ req->state = LDAP_REQUEST_DONE;
+ /* we can't call the async callback now, as it isn't setup, so
+ call it as next event */
+ event_add_timed(conn->event.event_ctx, req, timeval_zero(),
+ ldap_request_complete, req);
+ return req;
}
- DLIST_ADD_END(conn->send_queue, req, struct ldap_request *);
+
+ req->state = LDAP_REQUEST_PENDING;
+ DLIST_ADD(conn->pending, req);
/* put a timeout on the request */
- event_add_timed(conn->event.event_ctx, req,
- timeval_current_ofs(conn->timeout, 0),
- ldap_request_timeout, req);
+ req->time_event = event_add_timed(conn->event.event_ctx, req,
+ timeval_current_ofs(conn->timeout, 0),
+ ldap_request_timeout, req);
return req;
failed:
- talloc_free(req);
- return NULL;
+ req->status = status;
+ req->state = LDAP_REQUEST_ERROR;
+ event_add_timed(conn->event.event_ctx, req, timeval_zero(),
+ ldap_request_complete, req);
+
+ return req;
}
*/
NTSTATUS ldap_request_wait(struct ldap_request *req)
{
- while (req->state != LDAP_REQUEST_DONE) {
+ while (req->state < LDAP_REQUEST_DONE) {
if (event_loop_once(req->conn->event.event_ctx) != 0) {
req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
break;
}
+/*
+ a mapping of ldap response code to strings
+*/
+static const struct {
+ enum ldap_result_code code;
+ const char *str;
+} ldap_code_map[] = {
+#define _LDAP_MAP_CODE(c) { c, #c }
+ _LDAP_MAP_CODE(LDAP_SUCCESS),
+ _LDAP_MAP_CODE(LDAP_OPERATIONS_ERROR),
+ _LDAP_MAP_CODE(LDAP_PROTOCOL_ERROR),
+ _LDAP_MAP_CODE(LDAP_TIME_LIMIT_EXCEEDED),
+ _LDAP_MAP_CODE(LDAP_SIZE_LIMIT_EXCEEDED),
+ _LDAP_MAP_CODE(LDAP_COMPARE_FALSE),
+ _LDAP_MAP_CODE(LDAP_COMPARE_TRUE),
+ _LDAP_MAP_CODE(LDAP_AUTH_METHOD_NOT_SUPPORTED),
+ _LDAP_MAP_CODE(LDAP_STRONG_AUTH_REQUIRED),
+ _LDAP_MAP_CODE(LDAP_REFERRAL),
+ _LDAP_MAP_CODE(LDAP_ADMIN_LIMIT_EXCEEDED),
+ _LDAP_MAP_CODE(LDAP_UNAVAILABLE_CRITICAL_EXTENSION),
+ _LDAP_MAP_CODE(LDAP_CONFIDENTIALITY_REQUIRED),
+ _LDAP_MAP_CODE(LDAP_SASL_BIND_IN_PROGRESS),
+ _LDAP_MAP_CODE(LDAP_NO_SUCH_ATTRIBUTE),
+ _LDAP_MAP_CODE(LDAP_UNDEFINED_ATTRIBUTE_TYPE),
+ _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_MATCHING),
+ _LDAP_MAP_CODE(LDAP_CONSTRAINT_VIOLATION),
+ _LDAP_MAP_CODE(LDAP_ATTRIBUTE_OR_VALUE_EXISTS),
+ _LDAP_MAP_CODE(LDAP_INVALID_ATTRIBUTE_SYNTAX),
+ _LDAP_MAP_CODE(LDAP_NO_SUCH_OBJECT),
+ _LDAP_MAP_CODE(LDAP_ALIAS_PROBLEM),
+ _LDAP_MAP_CODE(LDAP_INVALID_DN_SYNTAX),
+ _LDAP_MAP_CODE(LDAP_ALIAS_DEREFERENCING_PROBLEM),
+ _LDAP_MAP_CODE(LDAP_INAPPROPRIATE_AUTHENTICATION),
+ _LDAP_MAP_CODE(LDAP_INVALID_CREDENTIALS),
+ _LDAP_MAP_CODE(LDAP_INSUFFICIENT_ACCESS_RIGHTs),
+ _LDAP_MAP_CODE(LDAP_BUSY),
+ _LDAP_MAP_CODE(LDAP_UNAVAILABLE),
+ _LDAP_MAP_CODE(LDAP_UNWILLING_TO_PERFORM),
+ _LDAP_MAP_CODE(LDAP_LOOP_DETECT),
+ _LDAP_MAP_CODE(LDAP_NAMING_VIOLATION),
+ _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_VIOLATION),
+ _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_NON_LEAF),
+ _LDAP_MAP_CODE(LDAP_NOT_ALLOWED_ON_RDN),
+ _LDAP_MAP_CODE(LDAP_ENTRY_ALREADY_EXISTS),
+ _LDAP_MAP_CODE(LDAP_OBJECT_CLASS_MODS_PROHIBITED),
+ _LDAP_MAP_CODE(LDAP_AFFECTS_MULTIPLE_DSAS),
+ _LDAP_MAP_CODE(LDAP_OTHER)
+};
+
/*
used to setup the status code from a ldap response
*/
NTSTATUS ldap_check_response(struct ldap_connection *conn, struct ldap_Result *r)
{
+ int i;
+ const char *codename = "unknown";
+
if (r->resultcode == LDAP_SUCCESS) {
return NT_STATUS_OK;
}
if (conn->last_error) {
talloc_free(conn->last_error);
}
- conn->last_error = talloc_asprintf(conn, "LDAP error %u - %s <%s> <%s>",
+
+ for (i=0;i<ARRAY_SIZE(ldap_code_map);i++) {
+ if (r->resultcode == ldap_code_map[i].code) {
+ codename = ldap_code_map[i].str;
+ break;
+ }
+ }
+
+ conn->last_error = talloc_asprintf(conn, "LDAP error %u %s - %s <%s> <%s>",
r->resultcode,
+ codename,
r->dn?r->dn:"(NULL)",
r->errormessage?r->errormessage:"",
r->referral?r->referral:"");
NT_STATUS_HAVE_NO_MEMORY(req);
- while (req->state != LDAP_REQUEST_DONE && n >= req->num_replies) {
+ while (req->state < LDAP_REQUEST_DONE && n >= req->num_replies) {
if (event_loop_once(req->conn->event.event_ctx) != 0) {
return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
}