1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-10 01:18:15 +03:00

s4:libcli/ldap: conversion to tstream

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
This commit is contained in:
Stefan Metzmacher 2015-06-19 12:26:06 +02:00 committed by Jeremy Allison
parent 6f2c29a13c
commit 67c5d5849e
4 changed files with 364 additions and 179 deletions

View File

@ -28,7 +28,7 @@
#include "lib/tls/tls.h"
#include "auth/gensec/gensec.h"
#include "auth/gensec/gensec_internal.h" /* TODO: remove this */
#include "auth/gensec/gensec_socket.h"
#include "source4/auth/gensec/gensec_tstream.h"
#include "auth/credentials/credentials.h"
#include "lib/stream/packet.h"
#include "param/param.h"
@ -224,6 +224,27 @@ _PUBLIC_ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn,
NULL
};
unsigned int logon_retries = 0;
size_t queue_length;
if (conn->sockets.active == NULL) {
status = NT_STATUS_CONNECTION_DISCONNECTED;
goto failed;
}
queue_length = tevent_queue_length(conn->sockets.send_queue);
if (queue_length != 0) {
status = NT_STATUS_INVALID_PARAMETER_MIX;
DEBUG(1, ("SASL bind triggered with non empty send_queue[%ju]: %s\n",
queue_length, nt_errstr(status)));
goto failed;
}
if (conn->pending != NULL) {
status = NT_STATUS_INVALID_PARAMETER_MIX;
DEBUG(1, ("SASL bind triggered with pending requests: %s\n",
nt_errstr(status)));
goto failed;
}
status = ildap_search(conn, "", LDAP_SEARCH_SCOPE_BASE, "", supported_sasl_mech_attrs,
false, NULL, NULL, &sasl_mechs_msgs);
@ -281,7 +302,7 @@ try_logon_again:
/* require Kerberos SIGN/SEAL only if we don't use SSL
* Windows seem not to like double encryption */
old_gensec_features = cli_credentials_get_gensec_features(creds);
if (tls_enabled(conn->sock)) {
if (conn->sockets.active == conn->sockets.tls) {
cli_credentials_set_gensec_features(creds, old_gensec_features & ~(GENSEC_FEATURE_SIGN|GENSEC_FEATURE_SEAL));
}
@ -436,27 +457,31 @@ try_logon_again:
}
}
talloc_free(tmp_ctx);
TALLOC_FREE(tmp_ctx);
if (NT_STATUS_IS_OK(status)) {
struct socket_context *sasl_socket;
status = gensec_socket_init(conn->gensec,
conn,
conn->sock,
conn->event.event_ctx,
ldap_read_io_handler,
conn,
&sasl_socket);
if (!NT_STATUS_IS_OK(status)) goto failed;
conn->sock = sasl_socket;
packet_set_socket(conn->packet, conn->sock);
conn->bind.type = LDAP_BIND_SASL;
conn->bind.creds = creds;
if (!NT_STATUS_IS_OK(status)) {
goto failed;
}
return status;
conn->bind.type = LDAP_BIND_SASL;
conn->bind.creds = creds;
if (!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN) &&
!gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL)) {
return NT_STATUS_OK;
}
status = gensec_create_tstream(conn->sockets.raw,
conn->gensec,
conn->sockets.raw,
&conn->sockets.sasl);
if (!NT_STATUS_IS_OK(status)) {
goto failed;
}
conn->sockets.active = conn->sockets.sasl;
return NT_STATUS_OK;
failed:
talloc_free(tmp_ctx);

View File

@ -25,22 +25,36 @@
#include "includes.h"
#include <tevent.h>
#include "lib/socket/socket.h"
#include "lib/tsocket/tsocket.h"
#include "libcli/util/tstream.h"
#include "../lib/util/asn1.h"
#include "../lib/util/dlinklist.h"
#include "libcli/ldap/libcli_ldap.h"
#include "libcli/ldap/ldap_proto.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"
#include "param/param.h"
#include "libcli/resolve/resolve.h"
static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status);
static int ldap_connection_destructor(struct ldap_connection *conn)
{
/*
* NT_STATUS_OK means that callbacks of pending requests are not
* triggered
*/
ldap_connection_dead(conn, NT_STATUS_OK);
return 0;
}
/**
create a new ldap_connection stucture. The event context is optional
*/
_PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx,
struct loadparm_context *lp_ctx,
struct tevent_context *ev)
@ -59,6 +73,13 @@ _PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx,
conn->next_messageid = 1;
conn->event.event_ctx = ev;
conn->sockets.send_queue = tevent_queue_create(conn,
"ldap_connection send_queue");
if (conn->sockets.send_queue == NULL) {
TALLOC_FREE(conn);
return NULL;
}
conn->lp_ctx = lp_ctx;
/* set a reasonable request timeout */
@ -66,29 +87,35 @@ _PUBLIC_ struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx,
/* explicitly avoid reconnections by default */
conn->reconnect.max_retries = 0;
talloc_set_destructor(conn, ldap_connection_destructor);
return conn;
}
/*
the connection is dead
*/
static void ldap_connection_dead(struct ldap_connection *conn)
static void ldap_connection_dead(struct ldap_connection *conn, NTSTATUS status)
{
struct ldap_request *req;
talloc_free(conn->sock); /* this will also free event.fde */
talloc_free(conn->packet);
conn->sock = NULL;
conn->event.fde = NULL;
conn->packet = NULL;
tevent_queue_stop(conn->sockets.send_queue);
TALLOC_FREE(conn->sockets.recv_subreq);
conn->sockets.active = NULL;
TALLOC_FREE(conn->sockets.sasl);
TALLOC_FREE(conn->sockets.tls);
TALLOC_FREE(conn->sockets.raw);
/* return an error for any pending request ... */
while (conn->pending) {
req = conn->pending;
DLIST_REMOVE(req->conn->pending, req);
req->conn = NULL;
req->state = LDAP_REQUEST_DONE;
req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
if (NT_STATUS_IS_OK(status)) {
continue;
}
req->status = status;
if (req->async.fn) {
req->async.fn(req);
}
@ -100,11 +127,9 @@ static void ldap_reconnect(struct ldap_connection *conn);
/*
handle packet errors
*/
static void ldap_error_handler(void *private_data, NTSTATUS status)
static void ldap_error_handler(struct ldap_connection *conn, NTSTATUS status)
{
struct ldap_connection *conn = talloc_get_type(private_data,
struct ldap_connection);
ldap_connection_dead(conn);
ldap_connection_dead(conn, status);
/* but try to reconnect so that the ldb client can go on */
ldap_reconnect(conn);
@ -130,7 +155,7 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message
if (req == NULL) {
DEBUG(0,("ldap: no matching message id for %u\n",
msg->messageid));
talloc_free(msg);
TALLOC_FREE(msg);
return;
}
@ -138,6 +163,7 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message
for (i=0; msg->controls && msg->controls[i]; i++) {
if (!msg->controls_decoded[i] &&
msg->controls[i]->critical) {
TALLOC_FREE(msg);
req->status = NT_STATUS_LDAP(LDAP_UNAVAILABLE_CRITICAL_EXTENSION);
req->state = LDAP_REQUEST_DONE;
DLIST_REMOVE(conn->pending, req);
@ -149,10 +175,10 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message
}
/* add to the list of replies received */
talloc_steal(req, msg);
req->replies = talloc_realloc(req, req->replies,
struct ldap_message *, req->num_replies+1);
if (req->replies == NULL) {
TALLOC_FREE(msg);
req->status = NT_STATUS_NO_MEMORY;
req->state = LDAP_REQUEST_DONE;
DLIST_REMOVE(conn->pending, req);
@ -178,64 +204,120 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message
}
}
static void ldap_connection_recv_done(struct tevent_req *subreq);
static void ldap_connection_recv_next(struct ldap_connection *conn)
{
struct tevent_req *subreq = NULL;
if (conn->sockets.recv_subreq != NULL) {
return;
}
if (conn->sockets.active == NULL) {
return;
}
if (conn->pending == NULL) {
return;
}
/*
* The minimun size of a LDAP pdu is 7 bytes
*
* dumpasn1 -hh ldap-unbind-min.dat
*
* <30 05 02 01 09 42 00>
* 0 5: SEQUENCE {
* <02 01 09>
* 2 1: INTEGER 9
* <42 00>
* 5 0: [APPLICATION 2]
* : Error: Object has zero length.
* : }
*
* dumpasn1 -hh ldap-unbind-windows.dat
*
* <30 84 00 00 00 05 02 01 09 42 00>
* 0 5: SEQUENCE {
* <02 01 09>
* 6 1: INTEGER 9
* <42 00>
* 9 0: [APPLICATION 2]
* : Error: Object has zero length.
* : }
*
* This means using an initial read size
* of 7 is ok.
*/
subreq = tstream_read_pdu_blob_send(conn,
conn->event.event_ctx,
conn->sockets.active,
7, /* initial_read_size */
ldap_full_packet,
conn);
if (subreq == NULL) {
ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
return;
}
tevent_req_set_callback(subreq, ldap_connection_recv_done, conn);
conn->sockets.recv_subreq = subreq;
return;
}
/*
decode/process LDAP data
*/
static NTSTATUS ldap_recv_handler(void *private_data, DATA_BLOB blob)
static void ldap_connection_recv_done(struct tevent_req *subreq)
{
NTSTATUS status;
struct ldap_connection *conn = talloc_get_type(private_data,
struct ldap_connection);
struct ldap_message *msg = talloc(conn, struct ldap_message);
struct asn1_data *asn1 = asn1_init(conn);
struct ldap_connection *conn =
tevent_req_callback_data(subreq,
struct ldap_connection);
struct ldap_message *msg;
struct asn1_data *asn1;
DATA_BLOB blob;
if (asn1 == NULL || msg == NULL) {
return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
msg = talloc_zero(conn, struct ldap_message);
if (msg == NULL) {
ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
return;
}
if (!asn1_load(asn1, blob)) {
talloc_free(msg);
talloc_free(asn1);
return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
asn1 = asn1_init(conn);
if (asn1 == NULL) {
TALLOC_FREE(msg);
ldap_error_handler(conn, NT_STATUS_NO_MEMORY);
return;
}
status = ldap_decode(asn1, samba_ldap_control_handlers(), msg);
conn->sockets.recv_subreq = NULL;
status = tstream_read_pdu_blob_recv(subreq,
asn1,
&blob);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(msg);
asn1_free(asn1);
return status;
ldap_error_handler(conn, status);
return;
}
asn1_load_nocopy(asn1, blob.data, blob.length);
status = ldap_decode(asn1, samba_ldap_control_handlers(), msg);
asn1_free(asn1);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(msg);
ldap_error_handler(conn, status);
return;
}
ldap_match_message(conn, msg);
ldap_connection_recv_next(conn);
data_blob_free(&blob);
asn1_free(asn1);
return NT_STATUS_OK;
}
/* Handle read events, from the GENSEC socket callback, or real events */
void ldap_read_io_handler(void *private_data, uint16_t flags)
{
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 tevent_context *ev, struct tevent_fd *fde,
uint16_t flags, void *private_data)
{
struct ldap_connection *conn = talloc_get_type(private_data,
struct ldap_connection);
if (flags & TEVENT_FD_WRITE) {
packet_queue_run(conn->packet);
if (!tls_enabled(conn->sock)) return;
}
if (flags & TEVENT_FD_READ) {
ldap_read_io_handler(private_data, flags);
}
return;
}
/*
@ -284,6 +366,10 @@ static NTSTATUS ldap_parse_basic_url(TALLOC_CTX *mem_ctx, const char *url,
struct ldap_connect_state {
struct composite_context *ctx;
struct ldap_connection *conn;
struct socket_context *sock;
struct tstream_context *raw;
struct tstream_tls_params *tls_params;
struct tstream_context *tls;
};
static void ldap_connect_recv_unix_conn(struct composite_context *ctx);
@ -327,11 +413,11 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con
struct socket_address *unix_addr;
char path[1025];
NTSTATUS status = socket_create("unix", SOCKET_TYPE_STREAM, &conn->sock, 0);
NTSTATUS status = socket_create("unix", SOCKET_TYPE_STREAM, &state->sock, 0);
if (!NT_STATUS_IS_OK(status)) {
return NULL;
}
talloc_steal(conn, conn->sock);
talloc_steal(state, state->sock);
SMB_ASSERT(sizeof(protocol)>10);
SMB_ASSERT(sizeof(path)>1024);
@ -354,29 +440,53 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con
}
rfc1738_unescape(path);
unix_addr = socket_address_from_strings(conn, conn->sock->backend_name,
unix_addr = socket_address_from_strings(state, state->sock->backend_name,
path, 0);
if (!unix_addr) {
return NULL;
if (composite_nomem(unix_addr, result)) {
return result;
}
ctx = socket_connect_send(conn->sock, NULL, unix_addr,
0, conn->event.event_ctx);
ctx = socket_connect_send(state->sock, NULL, unix_addr,
0, result->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);
if (!NT_STATUS_IS_OK(status)) {
composite_error(result, status);
return result;
}
if (conn->ldaps) {
char *ca_file = lpcfg_tls_cafile(state, conn->lp_ctx);
char *crl_file = lpcfg_tls_crlfile(state, conn->lp_ctx);
if (!ca_file || !*ca_file) {
composite_error(result,
NT_STATUS_INVALID_PARAMETER_MIX);
return result;
}
status = tstream_tls_params_client(state,
ca_file,
crl_file,
&state->tls_params);
if (!NT_STATUS_IS_OK(status)) {
composite_error(result, status);
return result;
}
}
ctx = socket_connect_multi_send(state, conn->host, 1, &conn->port,
lpcfg_resolve_context(conn->lp_ctx), conn->event.event_ctx);
if (ctx == NULL) goto failed;
lpcfg_resolve_context(conn->lp_ctx),
result->event_ctx);
if (composite_nomem(ctx, result)) {
return result;
}
ctx->async.fn = ldap_connect_recv_tcp_conn;
ctx->async.private_data = state;
@ -387,72 +497,80 @@ _PUBLIC_ struct composite_context *ldap_connect_send(struct ldap_connection *con
return NULL;
}
static void ldap_connect_got_tls(struct tevent_req *subreq);
static void ldap_connect_got_sock(struct composite_context *ctx,
struct ldap_connection *conn)
struct ldap_connection *conn)
{
/* setup a handler for events on this socket */
conn->event.fde = tevent_add_fd(conn->event.event_ctx, conn->sock,
socket_get_fd(conn->sock),
TEVENT_FD_READ, ldap_io_handler, conn);
if (conn->event.fde == NULL) {
composite_error(ctx, NT_STATUS_INTERNAL_ERROR);
struct ldap_connect_state *state =
talloc_get_type_abort(ctx->private_data,
struct ldap_connect_state);
struct tevent_req *subreq = NULL;
int fd;
int ret;
socket_set_flags(state->sock, SOCKET_FLAG_NOCLOSE);
fd = socket_get_fd(state->sock);
TALLOC_FREE(state->sock);
smb_set_close_on_exec(fd);
set_blocking(fd, false);
ret = tstream_bsd_existing_socket(state, fd, &state->raw);
if (ret == -1) {
NTSTATUS status = map_nt_error_from_unix_common(errno);
composite_error(state->ctx, status);
return;
}
tevent_fd_set_close_fn(conn->event.fde, socket_tevent_fd_close_fn);
socket_set_flags(conn->sock, SOCKET_FLAG_NOCLOSE);
talloc_steal(conn, conn->sock);
if (conn->ldaps) {
struct socket_context *tls_socket;
char *cafile = lpcfg_tls_cafile(conn->sock, conn->lp_ctx);
if (!cafile || !*cafile) {
talloc_free(conn->sock);
return;
}
tls_socket = tls_init_client(conn->sock, conn->event.fde, cafile);
talloc_free(cafile);
if (tls_socket == NULL) {
talloc_free(conn->sock);
return;
}
conn->sock = talloc_steal(conn, tls_socket);
}
conn->packet = packet_init(conn);
if (conn->packet == NULL) {
talloc_free(conn->sock);
if (!conn->ldaps) {
conn->sockets.raw = talloc_move(conn, &state->raw);
conn->sockets.active = conn->sockets.raw;
composite_done(state->ctx);
return;
}
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); */
subreq = tstream_tls_connect_send(state, state->ctx->event_ctx,
state->raw, state->tls_params);
if (composite_nomem(subreq, state->ctx)) {
return;
}
tevent_req_set_callback(subreq, ldap_connect_got_tls, state);
}
if (conn->ldaps) {
packet_set_unreliable_select(conn->packet);
static void ldap_connect_got_tls(struct tevent_req *subreq)
{
struct ldap_connect_state *state =
tevent_req_callback_data(subreq,
struct ldap_connect_state);
int err;
int ret;
ret = tstream_tls_connect_recv(subreq, &err, state, &state->tls);
TALLOC_FREE(subreq);
if (ret == -1) {
NTSTATUS status = map_nt_error_from_unix_common(err);
composite_error(state->ctx, status);
return;
}
composite_done(ctx);
talloc_steal(state->tls, state->tls_params);
state->conn->sockets.raw = talloc_move(state->conn, &state->raw);
state->conn->sockets.tls = talloc_move(state->conn->sockets.raw,
&state->tls);
state->conn->sockets.active = state->conn->sockets.tls;
composite_done(state->ctx);
}
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);
talloc_get_type_abort(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,
NTSTATUS status = socket_connect_multi_recv(ctx, state, &state->sock,
&port);
if (!NT_STATUS_IS_OK(status)) {
composite_error(state->ctx, status);
@ -465,8 +583,8 @@ static void ldap_connect_recv_tcp_conn(struct composite_context *ctx)
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);
talloc_get_type_abort(ctx->async.private_data,
struct ldap_connect_state);
struct ldap_connection *conn = state->conn;
NTSTATUS status = socket_connect_recv(ctx);
@ -533,7 +651,7 @@ static void ldap_reconnect(struct ldap_connection *conn)
/* rebind */
status = ldap_rebind(conn);
if ( ! NT_STATUS_IS_OK(status)) {
ldap_connection_dead(conn);
ldap_connection_dead(conn, status);
}
}
@ -552,7 +670,10 @@ static int ldap_request_destructor(struct ldap_request *req)
static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer *te,
struct timeval t, void *private_data)
{
struct ldap_request *req = talloc_get_type(private_data, struct ldap_request);
struct ldap_request *req =
talloc_get_type_abort(private_data,
struct ldap_request);
req->status = NT_STATUS_IO_TIMEOUT;
if (req->state == LDAP_REQUEST_PENDING) {
DLIST_REMOVE(req->conn->pending, req);
@ -570,26 +691,17 @@ static void ldap_request_timeout(struct tevent_context *ev, struct tevent_timer
static void ldap_request_failed_complete(struct tevent_context *ev, struct tevent_timer *te,
struct timeval t, void *private_data)
{
struct ldap_request *req = talloc_get_type(private_data, struct ldap_request);
struct ldap_request *req =
talloc_get_type_abort(private_data,
struct ldap_request);
if (req->async.fn) {
req->async.fn(req);
}
}
/*
called on completion of a one-way ldap request
*/
static void ldap_request_oneway_complete(void *private_data)
{
struct ldap_request *req = talloc_get_type(private_data, struct ldap_request);
if (req->state == LDAP_REQUEST_PENDING) {
DLIST_REMOVE(req->conn->pending, req);
}
req->state = LDAP_REQUEST_DONE;
if (req->async.fn) {
req->async.fn(req);
}
}
static void ldap_request_written(struct tevent_req *subreq);
/*
send a ldap message - async interface
*/
@ -598,12 +710,12 @@ _PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
{
struct ldap_request *req;
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
packet_send_callback_fn_t send_callback = NULL;
struct tevent_req *subreq = NULL;
req = talloc_zero(conn, struct ldap_request);
if (req == NULL) return NULL;
if (conn->sock == NULL) {
if (conn->sockets.active == NULL) {
status = NT_STATUS_INVALID_CONNECTION;
goto failed;
}
@ -628,24 +740,30 @@ _PUBLIC_ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
goto failed;
}
if (req->type == LDAP_TAG_AbandonRequest ||
req->type == LDAP_TAG_UnbindRequest) {
send_callback = ldap_request_oneway_complete;
}
status = packet_send_callback(conn->packet, req->data,
send_callback, req);
if (!NT_STATUS_IS_OK(status)) {
goto failed;
}
req->state = LDAP_REQUEST_PENDING;
DLIST_ADD(conn->pending, req);
/* put a timeout on the request */
req->time_event = tevent_add_timer(conn->event.event_ctx, req,
timeval_current_ofs(conn->timeout, 0),
ldap_request_timeout, req);
if (req->time_event == NULL) {
status = NT_STATUS_NO_MEMORY;
goto failed;
}
req->write_iov.iov_base = req->data.data;
req->write_iov.iov_len = req->data.length;
subreq = tstream_writev_queue_send(req, conn->event.event_ctx,
conn->sockets.active,
conn->sockets.send_queue,
&req->write_iov, 1);
if (subreq == NULL) {
status = NT_STATUS_NO_MEMORY;
goto failed;
}
tevent_req_set_callback(subreq, ldap_request_written, req);
req->state = LDAP_REQUEST_PENDING;
DLIST_ADD(conn->pending, req);
return req;
@ -658,6 +776,38 @@ failed:
return req;
}
static void ldap_request_written(struct tevent_req *subreq)
{
struct ldap_request *req =
tevent_req_callback_data(subreq,
struct ldap_request);
int err;
ssize_t ret;
ret = tstream_writev_queue_recv(subreq, &err);
TALLOC_FREE(subreq);
if (ret == -1) {
NTSTATUS error = map_nt_error_from_unix_common(err);
ldap_error_handler(req->conn, error);
return;
}
if (req->type == LDAP_TAG_AbandonRequest ||
req->type == LDAP_TAG_UnbindRequest)
{
if (req->state == LDAP_REQUEST_PENDING) {
DLIST_REMOVE(req->conn->pending, req);
}
req->state = LDAP_REQUEST_DONE;
if (req->async.fn) {
req->async.fn(req);
}
return;
}
ldap_connection_recv_next(req->conn);
}
/*
wait for a request to complete
@ -667,6 +817,7 @@ _PUBLIC_ NTSTATUS ldap_request_wait(struct ldap_request *req)
{
while (req->state < LDAP_REQUEST_DONE) {
if (tevent_loop_once(req->conn->event.event_ctx) != 0) {
req->state = LDAP_REQUEST_ERROR;
req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
break;
}

View File

@ -20,6 +20,7 @@
*/
#include "system/network.h" /* for struct iovec */
#include "libcli/ldap/libcli_ldap.h"
enum ldap_request_state { LDAP_REQUEST_SEND=1, LDAP_REQUEST_PENDING=2, LDAP_REQUEST_DONE=3, LDAP_REQUEST_ERROR=4 };
@ -39,6 +40,8 @@ struct ldap_request {
NTSTATUS status;
DATA_BLOB data;
struct iovec write_iov;
struct {
void (*fn)(struct ldap_request *);
void *private_data;
@ -50,7 +53,16 @@ struct ldap_request {
/* main context for a ldap client connection */
struct ldap_connection {
struct socket_context *sock;
struct {
struct tstream_context *raw;
struct tstream_context *tls;
struct tstream_context *sasl;
struct tstream_context *active;
struct tevent_queue *send_queue;
struct tevent_req *recv_subreq;
} sockets;
struct loadparm_context *lp_ctx;
char *host;
@ -89,10 +101,7 @@ struct ldap_connection {
struct {
struct tevent_context *event_ctx;
struct tevent_fd *fde;
} event;
struct packet_context *packet;
};
struct ldap_connection *ldap4_new_connection(TALLOC_CTX *mem_ctx,

View File

@ -3,9 +3,9 @@
bld.SAMBA_LIBRARY('cli-ldap',
source='ldap_client.c ldap_bind.c ldap_ildap.c ldap_controls.c',
autoproto='ldap_proto.h',
public_deps='errors tevent LIBPACKET',
public_deps='errors tevent',
public_headers='libcli_ldap.h:ldap-util.h',
deps='cli_composite samba_socket NDR_SAMR LIBTLS ndr LP_RESOLVE gensec cli-ldap-common',
deps='cli_composite LIBSAMBA_TSOCKET samba_socket NDR_SAMR LIBTLS ndr LP_RESOLVE gensec cli-ldap-common',
private_library=True
)