r17197: This patch moves the encryption of bulk data on SASL negotiated security
authorAndrew Bartlett <abartlet@samba.org>
Sun, 23 Jul 2006 02:50:08 +0000 (02:50 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:10:18 +0000 (14:10 -0500)
contexts from the application layer into the socket layer.

This improves a number of correctness aspects, as we now allow LDAP
packets to cross multiple SASL packets.  It should also make it much
easier to write async LDAP tests from windows clients, as they use SASL
by default.  It is also vital to allowing OpenLDAP clients to use GSSAPI
against Samba4, as it negotiates a rather small SASL buffer size.

This patch mirrors the earlier work done to move TLS into the socket
layer.

Unusual in this pstch is the extra read callback argument I take.  As
SASL is a layer on top of a socket, it is entirely possible for the
SASL layer to drain a socket dry, but for the caller not to have read
all the decrypted data.  This would leave the system without an event
to restart the read (as the socket is dry).

As such, I re-invoke the read handler from a timed callback, which
should trigger on the next running of the event loop.  I believe that
the TLS code does require a similar callback.

In trying to understand why this is required, imagine a SASL-encrypted
LDAP packet in the following formation:

+-----------------+---------------------+
| SASL  Packet #1 | SASL Packet #2      |
----------------------------------------+
| LDAP Packet #1       | LDAP Packet #2 |
----------------------------------------+

In the old code, this was illegal, but it is perfectly standard
SASL-encrypted LDAP.  Without the callback, we would read and process
the first LDAP packet, and the SASL code would have read the second SASL
packet (to decrypt enough data for the LDAP packet), and no data would
remain on the socket.

Without data on the socket, read events stop.  That is why I add timed
events, until the SASL buffer is drained.

Another approach would be to add a hack to the event system, to have it
pretend there remained data to read off the network (but that is ugly).

In improving the code, to handle more real-world cases, I've been able
to remove almost all the special-cases in the testnonblock code.  The
only special case is that we must use a deterministic partial packet
when calling send, rather than a random length.  (1 + n/2).  This is
needed because of the way the SASL and TLS code works, and the 'resend
on failure' requirements.

Andrew Bartlett
(This used to be commit 5d7c9c12cb2b39673172a357092b80cd814850b0)

18 files changed:
source4/auth/gensec/config.mk
source4/auth/gensec/socket.c [new file with mode: 0644]
source4/auth/gensec/socket.h [new file with mode: 0644]
source4/auth/gensec/spnego.c
source4/ldap_server/config.mk
source4/ldap_server/ldap_bind.c
source4/ldap_server/ldap_server.c
source4/ldap_server/ldap_server.h
source4/lib/socket/socket.c
source4/lib/socket/socket.h
source4/lib/stream/packet.c
source4/lib/stream/packet.h
source4/lib/tls/tls.c
source4/libcli/ldap/config.mk
source4/libcli/ldap/ldap_bind.c
source4/libcli/ldap/ldap_client.c
source4/libcli/ldap/ldap_client.h
source4/smbd/service_stream.c

index 5aeca28689b12c7ba3561d227dfcc3b4fb37762a..0aaf82949e875d25a27fbc8e059a8ff6ed821752 100644 (file)
@@ -67,3 +67,14 @@ OBJ_FILES = \
 # End SUBSYSTEM SCHANNELDB
 ################################################
 
+################################################
+# Start SUBSYSTEM GENSEC_SOCKET
+[SUBSYSTEM::GENSEC_SOCKET]
+OBJ_FILES = \
+               socket.o
+PUBLIC_DEPENDENCIES = samba-socket
+#PUBLIC_DEPENDENCIES =  gensec
+#
+# End SUBSYSTEM GENSEC_SOCKET
+################################################
+
diff --git a/source4/auth/gensec/socket.c b/source4/auth/gensec/socket.c
new file mode 100644 (file)
index 0000000..f308f72
--- /dev/null
@@ -0,0 +1,421 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   GENSEC socket interface
+
+   Copyright (C) Andrew Bartlett 2006
+   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 "lib/events/events.h"
+#include "lib/socket/socket.h"
+#include "lib/stream/packet.h"
+#include "auth/gensec/gensec.h"
+
+static const struct socket_ops gensec_socket_ops;
+
+struct gensec_socket {
+       struct gensec_security *gensec_security;
+       struct socket_context *socket;
+       struct event_context *ev;
+       struct packet_context *packet;
+       DATA_BLOB read_buffer;  /* SASL packets are turned into liniarlised data here, for reading */
+       size_t orig_send_len;
+       BOOL eof;
+       NTSTATUS error;
+       BOOL interrupted;
+       void (*recv_handler)(void *, uint16_t);
+       void *recv_private;
+       int in_extra_read;
+};
+
+static NTSTATUS gensec_socket_init_fn(struct socket_context *sock)
+{
+       switch (sock->type) {
+       case SOCKET_TYPE_STREAM:
+               break;
+       default:
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       sock->backend_name = "gensec";
+
+       return NT_STATUS_OK;
+}
+
+/* Try to figure out how much data is waiting to be read */
+static NTSTATUS gensec_socket_pending(struct socket_context *sock, size_t *npending) 
+{
+       struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
+       if (gensec_socket->read_buffer.length > 0) {
+               *npending = gensec_socket->read_buffer.length;
+               return NT_STATUS_OK;
+       }
+
+       /* This is a lie.  We hope the decrypted data will always be
+        * less than this value, so the application just gets a short
+        * read.  Without reading and decrypting it, we can't tell.
+        * If the SASL mech does compression, then we just need to
+        * manually trigger read events */
+       return socket_pending(gensec_socket->socket, npending);
+}      
+
+/* Note if an error occours, so we can return it up the stack */
+static void gensec_socket_error_handler(void *private, NTSTATUS status)
+{
+       struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
+               gensec_socket->eof = True;
+       } else {
+               gensec_socket->error = status;
+       }
+}
+
+static void gensec_socket_trigger_read(struct event_context *ev, 
+                                      struct timed_event *te, 
+                                      struct timeval t, void *private)
+{
+       struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
+
+       gensec_socket->in_extra_read++;
+       gensec_socket->recv_handler(gensec_socket->recv_private, EVENT_FD_READ);
+       gensec_socket->in_extra_read--;
+
+       /* It may well be that, having run the recv handler, we still
+        * have even more data waiting for us! 
+        */
+       if (gensec_socket->read_buffer.length && gensec_socket->recv_handler) {
+               /* Schedule this funcion to run again */
+               event_add_timed(gensec_socket->ev, gensec_socket, timeval_zero(), 
+                               gensec_socket_trigger_read, gensec_socket);
+       }
+}
+
+/* These two routines could be changed to use a circular buffer of
+ * some kind, or linked lists, or ... */
+static NTSTATUS gensec_socket_recv(struct socket_context *sock, void *buf,
+                                  size_t wantlen, size_t *nread) 
+{
+       struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
+
+       gensec_socket->error = NT_STATUS_OK;
+
+       if (gensec_socket->read_buffer.length == 0) {
+               /* Process any data on the socket, into the read buffer. At
+                * this point, the socket is not available for read any
+                * longer */
+               packet_recv(gensec_socket->packet);
+
+               if (gensec_socket->eof) {
+                       *nread = 0;
+                       return NT_STATUS_OK;
+               }
+               
+               if (!NT_STATUS_IS_OK(gensec_socket->error)) {
+                       return gensec_socket->error;
+               }
+
+               if (gensec_socket->read_buffer.length == 0) {
+                       /* Clearly we don't have the entire SASL packet yet,
+                        * so it has not been written into the buffer */
+                       *nread = 0;
+                       return STATUS_MORE_ENTRIES;
+               }
+       }
+
+
+       *nread = MIN(wantlen, gensec_socket->read_buffer.length);
+       memcpy(buf, gensec_socket->read_buffer.data, *nread);
+
+       if (gensec_socket->read_buffer.length > *nread) {
+               memmove(gensec_socket->read_buffer.data, 
+                       gensec_socket->read_buffer.data + *nread, 
+                       gensec_socket->read_buffer.length - *nread);
+       }
+
+       gensec_socket->read_buffer.length -= *nread;
+       gensec_socket->read_buffer.data = talloc_realloc(gensec_socket, 
+                                                        gensec_socket->read_buffer.data, 
+                                                        uint8_t, 
+                                                        gensec_socket->read_buffer.length);
+
+       if (gensec_socket->read_buffer.length && 
+           gensec_socket->in_extra_read == 0 && 
+           gensec_socket->recv_handler) {
+               /* Manually call a read event, to get this moving
+                * again (as the socket should be dry, so the normal
+                * event handler won't trigger) */
+               event_add_timed(gensec_socket->ev, gensec_socket, timeval_zero(), 
+                               gensec_socket_trigger_read, gensec_socket);
+       }
+
+       return NT_STATUS_OK;
+}
+
+/* Completed SASL packet callback.  When we have a 'whole' SASL
+ * packet, decrypt it, and add it to the read buffer
+ *
+ * This function (and anything under it) MUST NOT call the event system
+ */
+static NTSTATUS gensec_socket_unwrap(void *private, DATA_BLOB blob)
+{
+       struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
+       DATA_BLOB wrapped;
+       DATA_BLOB unwrapped;
+       NTSTATUS nt_status;
+       TALLOC_CTX *mem_ctx;
+       uint32_t packet_size;
+
+       if (blob.length < 4) {
+               /* Missing the header we already had! */
+               DEBUG(0, ("Asked to unwrap packed of bogus length!  How did we get the short packet?!\n"));
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       wrapped = data_blob_const(blob.data + 4, blob.length - 4);
+
+       packet_size = RIVAL(blob.data, 0);
+       if (packet_size != wrapped.length) {
+               DEBUG(0, ("Asked to unwrap packed of bogus length!  How did we get this?!\n"));
+               return NT_STATUS_INTERNAL_ERROR;
+       }
+
+       mem_ctx = talloc_new(gensec_socket);
+       if (!mem_ctx) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       nt_status = gensec_unwrap(gensec_socket->gensec_security, 
+                                 mem_ctx,
+                                 &wrapped, &unwrapped);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               talloc_free(mem_ctx);
+               return nt_status;
+       }
+       /* We could change this into a linked list, and have
+        * gensec_socket_recv() and gensec_socket_pending() walk the
+        * linked list */
+
+       nt_status = data_blob_append(gensec_socket, &gensec_socket->read_buffer, 
+                                    unwrapped.data, unwrapped.length); 
+       talloc_free(mem_ctx);
+       return nt_status;
+}
+
+/* when the data is sent, we know we have not been interrupted */
+static void send_callback(void *private) 
+{
+       struct gensec_socket *gensec_socket = talloc_get_type(private, struct gensec_socket);
+       gensec_socket->interrupted = False;
+}
+
+/*
+  send data, but only as much as we allow in one packet.  
+
+  If this returns STATUS_MORE_ENTRIES, the caller must retry with
+  exactly the same data, or a NULL blob.
+*/
+static NTSTATUS gensec_socket_send(struct socket_context *sock, 
+                                  const DATA_BLOB *blob, size_t *sendlen)
+{
+       NTSTATUS nt_status;
+       struct gensec_socket *gensec_socket = talloc_get_type(sock->private_data, struct gensec_socket);
+       DATA_BLOB unwrapped, wrapped, out;
+       TALLOC_CTX *mem_ctx;
+       size_t max_input_size;
+
+       *sendlen = 0;
+
+       /* We have have been interupted, so the caller should be
+        * giving us the same data again.  */
+       if (gensec_socket->interrupted) {
+               packet_queue_run(gensec_socket->packet);
+
+               if (!NT_STATUS_IS_OK(gensec_socket->error)) {
+                       return gensec_socket->error;
+               } else if (gensec_socket->interrupted) {
+                       return STATUS_MORE_ENTRIES;
+               } else {
+                       *sendlen = gensec_socket->orig_send_len;
+                       gensec_socket->orig_send_len = 0;
+                       return NT_STATUS_OK;
+               }
+       }
+
+       mem_ctx = talloc_new(gensec_socket);
+       if (!mem_ctx) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       max_input_size = gensec_max_input_size(gensec_socket->gensec_security);
+       unwrapped = data_blob_const(blob->data, MIN(max_input_size, (size_t)blob->length));
+       
+       nt_status = gensec_wrap(gensec_socket->gensec_security, 
+                               mem_ctx,
+                               &unwrapped, &wrapped);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               talloc_free(mem_ctx);
+               return nt_status;
+       }
+       
+       out = data_blob_talloc(mem_ctx, NULL, 4);
+       if (!out.data) {
+               talloc_free(mem_ctx);
+               return NT_STATUS_NO_MEMORY;
+       }
+       RSIVAL(out.data, 0, wrapped.length);
+
+       nt_status = data_blob_append(gensec_socket, &out, wrapped.data, wrapped.length);
+
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               talloc_free(mem_ctx);
+               return nt_status;
+       }
+       
+       gensec_socket->interrupted = True;
+       gensec_socket->error = NT_STATUS_OK;
+       gensec_socket->orig_send_len
+               = unwrapped.length;
+
+       nt_status = packet_send_callback(gensec_socket->packet, 
+                                        out,
+                                        send_callback, gensec_socket);
+
+       talloc_free(mem_ctx);
+
+       packet_queue_run(gensec_socket->packet);
+
+       if (!NT_STATUS_IS_OK(gensec_socket->error)) {
+               return gensec_socket->error;
+       } else if (gensec_socket->interrupted) {
+               return STATUS_MORE_ENTRIES;
+       } else {
+               *sendlen = gensec_socket->orig_send_len;
+               gensec_socket->orig_send_len = 0;
+               return NT_STATUS_OK;
+       }
+}
+
+struct socket_context *gensec_socket_init(struct gensec_security *gensec_security,
+                                         struct socket_context *socket,
+                                         struct event_context *ev,
+                                         void (*recv_handler)(void *, uint16_t),
+                                         void *recv_private)
+{
+       struct gensec_socket *gensec_socket;
+       struct socket_context *new_sock;
+       NTSTATUS nt_status;
+
+       /* Nothing to do here, if we are not actually wrapping on this socket */
+       if (!gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL) &&
+           !gensec_have_feature(gensec_security, GENSEC_FEATURE_SIGN)) {
+               return socket;
+       }
+
+       nt_status = socket_create_with_ops(socket, &gensec_socket_ops, &new_sock, 
+                                          SOCKET_TYPE_STREAM, socket->flags | SOCKET_FLAG_ENCRYPT);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return NULL;
+       }
+
+       gensec_socket = talloc(new_sock, struct gensec_socket);
+       if (gensec_socket == NULL) {
+               return NULL;
+       }
+
+       gensec_socket->eof = False;
+       gensec_socket->error = NT_STATUS_OK;
+       gensec_socket->interrupted = False;
+       gensec_socket->in_extra_read = 0;
+
+       gensec_socket->read_buffer = data_blob(NULL, 0);
+
+       gensec_socket->gensec_security = gensec_security;
+       gensec_socket->socket          = socket;
+       if (talloc_reference(gensec_socket, socket) == NULL) {
+               return NULL;
+       }
+       gensec_socket->recv_handler    = recv_handler;
+       gensec_socket->recv_private    = recv_private;
+       gensec_socket->ev              = ev;
+
+       new_sock->private_data    = gensec_socket;
+
+       gensec_socket->packet = packet_init(gensec_socket);
+       if (gensec_socket->packet == NULL) {
+               return NULL;
+       }
+
+       packet_set_private(gensec_socket->packet, gensec_socket);
+       packet_set_socket(gensec_socket->packet, socket);
+       packet_set_callback(gensec_socket->packet, gensec_socket_unwrap);
+       packet_set_full_request(gensec_socket->packet, packet_full_request_u32);
+       packet_set_error_handler(gensec_socket->packet, gensec_socket_error_handler);
+       packet_set_serialise(gensec_socket->packet);
+
+       /* TODO: full-request that knows about maximum packet size */
+
+       new_sock->state = socket->state;
+
+       return new_sock;
+}
+
+
+static NTSTATUS gensec_socket_set_option(struct socket_context *sock, const char *option, const char *val)
+{
+       set_socket_options(socket_get_fd(sock), option);
+       return NT_STATUS_OK;
+}
+
+static char *gensec_socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+       struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
+       return socket_get_peer_name(gensec->socket, mem_ctx);
+}
+
+static struct socket_address *gensec_socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+       struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
+       return socket_get_peer_addr(gensec->socket, mem_ctx);
+}
+
+static struct socket_address *gensec_socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+       struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
+       return socket_get_my_addr(gensec->socket, mem_ctx);
+}
+
+static int gensec_socket_get_fd(struct socket_context *sock)
+{
+       struct gensec_socket *gensec = talloc_get_type(sock->private_data, struct gensec_socket);
+       return socket_get_fd(gensec->socket);
+}
+
+static const struct socket_ops gensec_socket_ops = {
+       .name                   = "gensec",
+       .fn_init                = gensec_socket_init_fn,
+       .fn_recv                = gensec_socket_recv,
+       .fn_send                = gensec_socket_send,
+       .fn_pending             = gensec_socket_pending,
+
+       .fn_set_option          = gensec_socket_set_option,
+
+       .fn_get_peer_name       = gensec_socket_get_peer_name,
+       .fn_get_peer_addr       = gensec_socket_get_peer_addr,
+       .fn_get_my_addr         = gensec_socket_get_my_addr,
+       .fn_get_fd              = gensec_socket_get_fd
+};
+
diff --git a/source4/auth/gensec/socket.h b/source4/auth/gensec/socket.h
new file mode 100644 (file)
index 0000000..1641e50
--- /dev/null
@@ -0,0 +1,27 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Generic Authentication Interface (socket wrapper)
+
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
+   
+   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.
+*/
+
+struct socket_context *gensec_socket_init(struct gensec_security *gensec_security,
+                                         struct socket_context *socket,
+                                         struct event_context *ev,
+                                         void (*recv_handler)(void *, uint16_t),
+                                         void *recv_private);
index 6ede774cc83abaa46cdeb654481fabea6e0c711a..a57e8cc8469b7fe35923b0f14dba9ed7257bef82 100644 (file)
@@ -211,6 +211,30 @@ static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security, si
        return gensec_sig_size(spnego_state->sub_sec_security, data_size);
 }
 
+static size_t gensec_spnego_max_input_size(struct gensec_security *gensec_security) 
+{
+       struct spnego_state *spnego_state = gensec_security->private_data;
+
+       if (spnego_state->state_position != SPNEGO_DONE 
+           && spnego_state->state_position != SPNEGO_FALLBACK) {
+               return 0;
+       }
+       
+       return gensec_max_input_size(spnego_state->sub_sec_security);
+}
+
+static size_t gensec_spnego_max_wrapped_size(struct gensec_security *gensec_security) 
+{
+       struct spnego_state *spnego_state = gensec_security->private_data;
+
+       if (spnego_state->state_position != SPNEGO_DONE 
+           && spnego_state->state_position != SPNEGO_FALLBACK) {
+               return 0;
+       }
+       
+       return gensec_max_wrapped_size(spnego_state->sub_sec_security);
+}
+
 static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security, 
                                          DATA_BLOB *session_key)
 {
@@ -938,24 +962,26 @@ static const char *gensec_spnego_oids[] = {
 };
 
 static const struct gensec_security_ops gensec_spnego_security_ops = {
-       .name           = "spnego",
-       .sasl_name      = "GSS-SPNEGO",
-       .auth_type      = DCERPC_AUTH_TYPE_SPNEGO,
-       .oid            = gensec_spnego_oids,
-       .client_start   = gensec_spnego_client_start,
-       .server_start   = gensec_spnego_server_start,
-       .update         = gensec_spnego_update,
-       .seal_packet    = gensec_spnego_seal_packet,
-       .sign_packet    = gensec_spnego_sign_packet,
-       .sig_size       = gensec_spnego_sig_size,
-       .check_packet   = gensec_spnego_check_packet,
-       .unseal_packet  = gensec_spnego_unseal_packet,
-       .wrap           = gensec_spnego_wrap,
-       .unwrap         = gensec_spnego_unwrap,
-       .session_key    = gensec_spnego_session_key,
-       .session_info   = gensec_spnego_session_info,
-       .have_feature   = gensec_spnego_have_feature,
-       .enabled        = True,
+       .name             = "spnego",
+       .sasl_name        = "GSS-SPNEGO",
+       .auth_type        = DCERPC_AUTH_TYPE_SPNEGO,
+       .oid              = gensec_spnego_oids,
+       .client_start     = gensec_spnego_client_start,
+       .server_start     = gensec_spnego_server_start,
+       .update           = gensec_spnego_update,
+       .seal_packet      = gensec_spnego_seal_packet,
+       .sign_packet      = gensec_spnego_sign_packet,
+       .sig_size         = gensec_spnego_sig_size,
+       .max_wrapped_size = gensec_spnego_max_wrapped_size,
+       .max_input_size   = gensec_spnego_max_input_size,
+       .check_packet     = gensec_spnego_check_packet,
+       .unseal_packet    = gensec_spnego_unseal_packet,
+       .wrap             = gensec_spnego_wrap,
+       .unwrap           = gensec_spnego_unwrap,
+       .session_key      = gensec_spnego_session_key,
+       .session_info     = gensec_spnego_session_info,
+       .have_feature     = gensec_spnego_have_feature,
+       .enabled          = True,
 };
 
 NTSTATUS gensec_spnego_init(void)
index 0ef8ced92856f30a128ed6a848bd91234163125e..fc9d04c46a6964c9ddab9e594e34546830a8aa84 100644 (file)
@@ -11,6 +11,6 @@ OBJ_FILES = \
                ldap_backend.o \
                ldap_bind.o
 PUBLIC_DEPENDENCIES = \
-               LIBCLI_LDAP SAMDB process_model auth
+               LIBCLI_LDAP SAMDB process_model auth GENSEC_SOCKET
 # End SUBSYSTEM SMB
 #######################
index 35b6ad5fbf474e33c10a402d48d10074e0f35016..7fce3904505fcf01ed68d3e6a22ecd96039596bb 100644 (file)
 #include "ldap_server/ldap_server.h"
 #include "auth/auth.h"
 #include "libcli/ldap/ldap.h"
-#include "smbd/service_stream.h"
+#include "smbd/service.h"
 #include "lib/ldb/include/ldb.h"
 #include "lib/ldb/include/ldb_errors.h"
 #include "dsdb/samdb/samdb.h"
+#include "auth/gensec/socket.h"
 
 static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
 {
@@ -89,6 +90,23 @@ static NTSTATUS ldapsrv_BindSimple(struct ldapsrv_call *call)
        return NT_STATUS_OK;
 }
 
+static void ldapsrv_set_sasl(void *private) 
+{
+       struct ldapsrv_connection *conn = talloc_get_type(private, struct ldapsrv_connection);
+       struct socket_context *socket = gensec_socket_init(conn->gensec, 
+                                                          conn->connection->socket,
+                                                          conn->connection->event.ctx, 
+                                                          stream_io_handler_callback,
+                                                          conn->connection);
+       if (socket) {
+               conn->connection->socket = socket;
+               talloc_steal(conn->connection->socket, socket);
+               packet_set_socket(conn->packet, socket);
+       } else {
+               ldapsrv_terminate_connection(conn, "Failed to setup SASL wrapping on socket");
+       }
+}
+
 static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
 {
        struct ldap_BindRequest *req = &call->request->r.BindRequest;
@@ -175,10 +193,10 @@ static NTSTATUS ldapsrv_BindSASL(struct ldapsrv_call *call)
 
                result = LDAP_SUCCESS;
                errstr = NULL;
-               if (gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL) ||
-                   gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN)) {
-                       conn->enable_wrap = True;
-               }
+
+               call->send_callback = ldapsrv_set_sasl;
+               call->send_private = conn;
+               
                old_session_info = conn->session_info;
                conn->session_info = NULL;
                status = gensec_session_info(conn->gensec, &conn->session_info);
index 07b1bc6a27f04c03f18db351613661b8700d26a9..cfbe6eb5b25c010bbd078f44e4d84696cd032bed 100644 (file)
 #include "smbd/service_task.h"
 #include "smbd/service_stream.h"
 #include "smbd/service.h"
-#include "lib/socket/socket.h"
 #include "lib/tls/tls.h"
 #include "lib/messaging/irpc.h"
-#include "lib/stream/packet.h"
 #include "lib/ldb/include/ldb.h"
 #include "lib/ldb/include/ldb_errors.h"
 #include "system/network.h"
@@ -43,7 +41,7 @@
 /*
   close the socket and shutdown a server_context
 */
-static void ldapsrv_terminate_connection(struct ldapsrv_connection *conn, 
+void ldapsrv_terminate_connection(struct ldapsrv_connection *conn, 
                                         const char *reason)
 {
        stream_terminate_connection(conn->connection, reason);
@@ -68,7 +66,6 @@ static void ldapsrv_process_message(struct ldapsrv_connection *conn,
        struct ldapsrv_call *call;
        NTSTATUS status;
        DATA_BLOB blob;
-       BOOL enable_wrap = conn->enable_wrap;
 
        call = talloc(conn, struct ldapsrv_call);
        if (!call) {
@@ -79,11 +76,14 @@ static void ldapsrv_process_message(struct ldapsrv_connection *conn,
        call->request = talloc_steal(call, msg);
        call->conn = conn;
        call->replies = NULL;
-
+       call->send_callback = NULL;
+       call->send_private = NULL;
+       
        /* make the call */
        status = ldapsrv_do_call(call);
        if (!NT_STATUS_IS_OK(status)) {
-               goto failed;
+               talloc_free(call);
+               return;
        }
        
        blob = data_blob(NULL, 0);
@@ -100,49 +100,36 @@ static void ldapsrv_process_message(struct ldapsrv_connection *conn,
                msg = call->replies->msg;
                if (!ldap_encode(msg, &b, call)) {
                        DEBUG(0,("Failed to encode ldap reply of type %d\n", msg->type));
-                       goto failed;
+                       talloc_free(call);
+                       return;
                }
 
                status = data_blob_append(call, &blob, b.data, b.length);
                data_blob_free(&b);
 
-               if (!NT_STATUS_IS_OK(status)) goto failed;
-
-               DLIST_REMOVE(call->replies, call->replies);
-       }
+               talloc_set_name_const(blob.data, "Outgoing, encoded LDAP packet");
 
-       /* possibly encrypt/sign the reply */
-       if (enable_wrap) {
-               DATA_BLOB wrapped;
-
-               status = gensec_wrap(conn->gensec, call, &blob, &wrapped);
                if (!NT_STATUS_IS_OK(status)) {
-                       goto failed;
-               }
-               data_blob_free(&blob);
-               blob = data_blob_talloc(call, NULL, wrapped.length + 4);
-               if (blob.data == NULL) {
-                       goto failed;
+                       talloc_free(call);
+                       return;
                }
-               RSIVAL(blob.data, 0, wrapped.length);
-               memcpy(blob.data+4, wrapped.data, wrapped.length);
-               data_blob_free(&wrapped);
+
+               DLIST_REMOVE(call->replies, call->replies);
        }
 
-       packet_send(conn->packet, blob);
+       packet_send_callback(conn->packet, blob, 
+                            call->send_callback, call->send_private);
        talloc_free(call);
        return;
-
-failed:
-       talloc_free(call);
 }
 
-
 /*
-  decode the input buffer
+  decode/process data
 */
-static NTSTATUS ldapsrv_decode_plain(struct ldapsrv_connection *conn, DATA_BLOB blob)
+static NTSTATUS ldapsrv_decode(void *private, DATA_BLOB blob)
 {
+       struct ldapsrv_connection *conn = talloc_get_type(private, 
+                                                         struct ldapsrv_connection);
        struct asn1_data asn1;
        struct ldap_message *msg = talloc(conn, struct ldap_message);
 
@@ -165,63 +152,6 @@ static NTSTATUS ldapsrv_decode_plain(struct ldapsrv_connection *conn, DATA_BLOB
        return NT_STATUS_OK;
 }
 
-
-/*
-  decode/process wrapped data
-*/
-static NTSTATUS ldapsrv_decode_wrapped(struct ldapsrv_connection *conn, 
-                                      DATA_BLOB blob)
-{
-       DATA_BLOB wrapped, unwrapped;
-       struct asn1_data asn1;
-       struct ldap_message *msg = talloc(conn, struct ldap_message);
-       NTSTATUS status;
-
-       if (msg == NULL) {
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       wrapped = data_blob_const(blob.data+4, blob.length-4);
-
-       status = gensec_unwrap(conn->gensec, msg, &wrapped, &unwrapped);
-       if (!NT_STATUS_IS_OK(status)) {
-               return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
-       }
-
-       data_blob_free(&blob);
-
-       if (!asn1_load(&asn1, unwrapped)) {
-               return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
-       }
-
-       while (ldap_decode(&asn1, msg)) {
-               ldapsrv_process_message(conn, msg);
-               msg = talloc(conn, struct ldap_message);
-       }
-
-       if (asn1.ofs < asn1.length) {
-               return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
-       }
-               
-       talloc_free(msg);
-       asn1_free(&asn1);
-
-       return NT_STATUS_OK;
-}
-
-/*
-  decode/process data
-*/
-static NTSTATUS ldapsrv_decode(void *private, DATA_BLOB blob)
-{
-       struct ldapsrv_connection *conn = talloc_get_type(private, 
-                                                         struct ldapsrv_connection);
-       if (conn->enable_wrap) {
-               return ldapsrv_decode_wrapped(conn, blob);
-       }
-       return ldapsrv_decode_plain(conn, blob);
-}
-
 /*
  Idle timeout handler
 */
@@ -238,7 +168,7 @@ static void ldapsrv_conn_idle_timeout(struct event_context *ev,
 /*
   called when a LDAP socket becomes readable
 */
-static void ldapsrv_recv(struct stream_connection *c, uint16_t flags)
+void ldapsrv_recv(struct stream_connection *c, uint16_t flags)
 {
        struct ldapsrv_connection *conn = 
                talloc_get_type(c->private, struct ldapsrv_connection);
@@ -261,20 +191,6 @@ static void ldapsrv_recv(struct stream_connection *c, uint16_t flags)
                                           ldapsrv_conn_idle_timeout, conn);
 }
 
-/*
-  check if a blob is a complete ldap packet
-  handle wrapper or unwrapped connections
-*/
-NTSTATUS ldapsrv_complete_packet(void *private, DATA_BLOB blob, size_t *size)
-{
-       struct ldapsrv_connection *conn = talloc_get_type(private, 
-                                                         struct ldapsrv_connection);
-       if (conn->enable_wrap) {
-               return packet_full_request_u32(private, blob, size);
-       }
-       return ldap_full_packet(private, blob, size);
-}
-       
 /*
   called when a LDAP socket becomes writable
 */
@@ -411,7 +327,6 @@ static void ldapsrv_accept(struct stream_connection *c)
                return;
        }
 
-       conn->enable_wrap = False;
        conn->packet      = NULL;
        conn->connection  = c;
        conn->service     = ldapsrv_service;
@@ -445,7 +360,7 @@ static void ldapsrv_accept(struct stream_connection *c)
        packet_set_private(conn->packet, conn);
        packet_set_socket(conn->packet, c->socket);
        packet_set_callback(conn->packet, ldapsrv_decode);
-       packet_set_full_request(conn->packet, ldapsrv_complete_packet);
+       packet_set_full_request(conn->packet, ldap_full_packet);
        packet_set_error_handler(conn->packet, ldapsrv_error_handler);
        packet_set_event_context(conn->packet, c->event.ctx);
        packet_set_fde(conn->packet, c->event.fde);
index 0b0b78ea7f400b70d8c528d9b8e19aabf6b4b527..c35f62f134987ffb680928bfeb9545c0b1fa9679 100644 (file)
@@ -20,6 +20,8 @@
 */
 
 #include "libcli/ldap/ldap.h"
+#include "lib/socket/socket.h"
+#include "lib/stream/packet.h"
 
 struct ldapsrv_connection {
        struct stream_connection *connection;
@@ -29,9 +31,6 @@ struct ldapsrv_connection {
        struct cli_credentials *server_credentials;
        struct ldb_context *ldb;
 
-       /* are we using gensec wrapping? */
-       BOOL enable_wrap;
-
        BOOL global_catalog;
 
        struct packet_context *packet;
@@ -54,6 +53,8 @@ struct ldapsrv_call {
                struct ldapsrv_reply *prev, *next;
                struct ldap_message *msg;
        } *replies;
+       packet_send_callback_fn_t send_callback;
+       void *send_private;
 };
 
 struct ldapsrv_service;
index ac64bc4ddc272f0e69fe5fbd9b24d5fa0d910450..eca668885cfaa32784b06cd5bc1c000b12297c0f 100644 (file)
@@ -189,15 +189,9 @@ _PUBLIC_ NTSTATUS socket_recv(struct socket_context *sock, void *buf,
        if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK) 
            && wantlen > 1) {
 
-               /* The returning of 0 and MORE_ENTRIES is incompatible
-                  with TLS and SASL sockets, as there is not a
-                  constant event source to re-trigger the reads */
-
-               if (!(sock->flags & SOCKET_FLAG_FAKE)) {
-                       if (random() % 10 == 0) {
-                               *nread = 0;
-                               return STATUS_MORE_ENTRIES;
-                       }
+               if (random() % 10 == 0) {
+                       *nread = 0;
+                       return STATUS_MORE_ENTRIES;
                }
                return sock->ops->fn_recv(sock, buf, 1+(random() % wantlen), nread);
        }
@@ -240,17 +234,22 @@ _PUBLIC_ NTSTATUS socket_send(struct socket_context *sock,
        
        if ((sock->flags & SOCKET_FLAG_TESTNONBLOCK)
            && blob->length > 1) {
+               DATA_BLOB blob2 = *blob;
                if (random() % 10 == 0) {
                        *sendlen = 0;
                        return STATUS_MORE_ENTRIES;
                }
-               /* The variable size sends are incompatilbe with TLS and SASL
+               /* The random size sends are incompatible with TLS and SASL
                 * sockets, which require re-sends to be consistant */
-               if (!(sock->flags & SOCKET_FLAG_FAKE)) {
-                       DATA_BLOB blob2 = *blob;
+               if (!(sock->flags & SOCKET_FLAG_ENCRYPT)) {
                        blob2.length = 1+(random() % blob2.length);
-                       return sock->ops->fn_send(sock, &blob2, sendlen);
+               } else {
+                       /* This is particularly stressful on buggy
+                        * LDAP clients, that don't expect on LDAP
+                        * packet in many SASL packets */
+                       blob2.length = 1 + blob2.length/2;
                }
+               return sock->ops->fn_send(sock, &blob2, sendlen);
        }
        return sock->ops->fn_send(sock, blob, sendlen);
 }
index c0cf429887c3e0ecc57ee01c44b8927ef346d7e6..025fc7e13da7e990c02f421b145378f34112b0dd 100644 (file)
@@ -102,7 +102,13 @@ enum socket_state {
 #define SOCKET_FLAG_BLOCK        0x00000001
 #define SOCKET_FLAG_PEEK         0x00000002
 #define SOCKET_FLAG_TESTNONBLOCK 0x00000004
-#define SOCKET_FLAG_FAKE         0x00000008 /* This is an implementation not directly on top of a real socket */
+#define SOCKET_FLAG_ENCRYPT      0x00000008 /* This socket
+                                            * implementation requires
+                                            * that re-sends be
+                                            * consistant, because it
+                                            * is encrypting data.
+                                            * This modifies the
+                                            * TESTNONBLOCK case */
 
 struct socket_context {
        enum socket_type type;
index e06f4985eff5e398a6d9bacc0ef2cc81c47a8cb4..2759c752149c11a63d98488c37b8c4f47718a85f 100644 (file)
@@ -28,7 +28,6 @@
 #include "lib/socket/socket.h"
 #include "lib/stream/packet.h"
 
-
 struct packet_context {
        packet_callback_fn_t callback;
        packet_full_request_fn_t full_request;
@@ -53,6 +52,8 @@ struct packet_context {
                struct send_element *next, *prev;
                DATA_BLOB blob;
                size_t nsent;
+               packet_send_callback_fn_t send_callback;
+               void *send_callback_private;
        } *send_queue;
 };
 
@@ -374,6 +375,7 @@ next_partial:
                return;
        }
 
+       /* Have we consumed the whole buffer yet? */
        if (pc->partial.length == 0) {
                return;
        }
@@ -436,7 +438,7 @@ _PUBLIC_ void packet_queue_run(struct packet_context *pc)
                status = socket_send(pc->sock, &blob, &nwritten);
 
                if (NT_STATUS_IS_ERR(status)) {
-                       packet_error(pc, NT_STATUS_NET_WRITE_FAULT);
+                       packet_error(pc, status);
                        return;
                }
                if (!NT_STATUS_IS_OK(status)) {
@@ -445,6 +447,9 @@ _PUBLIC_ void packet_queue_run(struct packet_context *pc)
                el->nsent += nwritten;
                if (el->nsent == el->blob.length) {
                        DLIST_REMOVE(pc->send_queue, el);
+                       if (el->send_callback) {
+                               el->send_callback(el->send_callback_private);
+                       }
                        talloc_free(el);
                }
        }
@@ -455,9 +460,15 @@ _PUBLIC_ void packet_queue_run(struct packet_context *pc)
 }
 
 /*
-  put a packet in the send queue
+  put a packet in the send queue.  When the packet is actually sent,
+  call send_callback.  
+
+  Useful for operations that must occour after sending a message, such
+  as the switch to SASL encryption after as sucessful LDAP bind relpy.
 */
-_PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob)
+_PUBLIC_ NTSTATUS packet_send_callback(struct packet_context *pc, DATA_BLOB blob,
+                                      packet_send_callback_fn_t send_callback, 
+                                      void *private)
 {
        struct send_element *el;
        el = talloc(pc, struct send_element);
@@ -466,6 +477,8 @@ _PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob)
        DLIST_ADD_END(pc->send_queue, el, struct send_element *);
        el->blob = blob;
        el->nsent = 0;
+       el->send_callback = send_callback;
+       el->send_callback_private = private;
 
        /* if we aren't going to free the packet then we must reference it
           to ensure it doesn't disappear before going out */
@@ -477,11 +490,23 @@ _PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob)
                talloc_steal(el, blob.data);
        }
 
+       if (private && !talloc_reference(el, private)) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        EVENT_FD_WRITEABLE(pc->fde);
 
        return NT_STATUS_OK;
 }
 
+/*
+  put a packet in the send queue
+*/
+_PUBLIC_ NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob)
+{
+       return packet_send_callback(pc, blob, NULL, NULL);
+}
+
 
 /*
   a full request checker for NBT formatted packets (first 3 bytes are length)
index b7ee428186b8ef2e0ec9dcd6f35b0305fd498f94..0d875d777c881d3f66fd8f7e82f6bfe49fa100b9 100644 (file)
@@ -24,6 +24,9 @@
 typedef NTSTATUS (*packet_full_request_fn_t)(void *private, 
                                             DATA_BLOB blob, size_t *packet_size);
 typedef NTSTATUS (*packet_callback_fn_t)(void *private, DATA_BLOB blob);
+
+/* Used to notify that a packet has been sent, and is on the wire */
+typedef void (*packet_send_callback_fn_t)(void *private);
 typedef void (*packet_error_handler_fn_t)(void *private, NTSTATUS status);
 
 
@@ -43,6 +46,9 @@ void packet_recv(struct packet_context *pc);
 void packet_recv_disable(struct packet_context *pc);
 void packet_recv_enable(struct packet_context *pc);
 NTSTATUS packet_send(struct packet_context *pc, DATA_BLOB blob);
+NTSTATUS packet_send_callback(struct packet_context *pc, DATA_BLOB blob,
+                             packet_send_callback_fn_t send_callback, 
+                             void *private);
 void packet_queue_run(struct packet_context *pc);
 
 /*
index 1ba8ae977917592734cbc70a43958ce2b552d0a2..f9213af2a77b8416123ec0d7061816566c0a9f10 100644 (file)
@@ -444,7 +444,7 @@ struct socket_context *tls_init_server(struct tls_params *params,
        
        nt_status = socket_create_with_ops(socket, &tls_socket_ops, &new_sock, 
                                           SOCKET_TYPE_STREAM, 
-                                          socket->flags | SOCKET_FLAG_FAKE);
+                                          socket->flags | SOCKET_FLAG_ENCRYPT);
        if (!NT_STATUS_IS_OK(nt_status)) {
                return NULL;
        }
@@ -524,7 +524,7 @@ struct socket_context *tls_init_client(struct socket_context *socket,
        
        nt_status = socket_create_with_ops(socket, &tls_socket_ops, &new_sock, 
                                           SOCKET_TYPE_STREAM, 
-                                          socket->flags | SOCKET_FLAG_FAKE);
+                                          socket->flags | SOCKET_FLAG_ENCRYPT);
        if (!NT_STATUS_IS_OK(nt_status)) {
                return NULL;
        }
index 88ebc3256f422d75df1faa701f52165d4964d968..e5a7133cfa49213c2fe0209bad4af651ae39c2a8 100644 (file)
@@ -11,7 +11,7 @@ OBJ_FILES = ldap.o \
                ldap_ildap.o \
                ldap_controls.o
 PUBLIC_DEPENDENCIES = LIBSAMBA-ERRORS LIBEVENTS LIBPACKET
-PRIVATE_DEPENDENCIES = LIBCLI_COMPOSITE samba-socket LIBCLI_RESOLVE NDR_SAMR LIBTLS ASN1_UTIL
+PRIVATE_DEPENDENCIES = LIBCLI_COMPOSITE samba-socket LIBCLI_RESOLVE NDR_SAMR LIBTLS ASN1_UTIL GENSEC_SOCKET
 #PRIVATE_DEPENDENCIES = gensec
 # End SUBSYSTEM LIBCLI_LDAP
 #################################
index 6714d68b0ed2b3a20249231ab8c6f2c50742b3ea..2b209c38711f3fce8bb12dcd63dfc6e49ed1801d 100644 (file)
@@ -27,6 +27,8 @@
 #include "libcli/ldap/ldap_client.h"
 #include "lib/tls/tls.h"
 #include "auth/auth.h"
+#include "auth/gensec/socket.h"
+#include "lib/stream/packet.h"
 
 struct ldap_simple_creds {
        const char *dn;
@@ -365,15 +367,23 @@ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *cr
                }
        }
 
-       if (NT_STATUS_IS_OK(status) &&
-           (gensec_have_feature(conn->gensec, GENSEC_FEATURE_SEAL) ||
-            gensec_have_feature(conn->gensec, GENSEC_FEATURE_SIGN))) {
-               conn->enable_wrap = True;
-       }
-
        talloc_free(tmp_ctx);
 
        if (NT_STATUS_IS_OK(status)) {
+               struct socket_context *socket = gensec_socket_init(conn->gensec, 
+                                                                  conn->sock,
+                                                                  conn->event.event_ctx, 
+                                                                  ldap_read_io_handler,
+                                                                  conn);
+               if (socket) {
+                       conn->sock = socket;
+                       talloc_steal(conn->sock, socket);
+                       packet_set_socket(conn->packet, socket);
+               } else {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto failed;
+               }
+               
                conn->bind.type = LDAP_BIND_SASL;
                conn->bind.creds = creds;
        }
index 07b7f2b412d0e2c12ba6cac19355e8b51eb28cba..2e834b5244f8ea0406754f8eee99f3c80f092521 100644 (file)
@@ -165,25 +165,13 @@ static void ldap_match_message(struct ldap_connection *conn, struct ldap_message
 
 
 /*
-  check if a blob is a complete ldap packet
-  handle wrapper or unwrapped connections
+  decode/process LDAP data
 */
-NTSTATUS ldap_complete_packet(void *private_data, DATA_BLOB blob, size_t *size)
-{
-       struct ldap_connection *conn = talloc_get_type(private_data,
-                                                      struct ldap_connection);
-       if (conn->enable_wrap) {
-               return packet_full_request_u32(private_data, blob, size);
-       }
-       return ldap_full_packet(private_data, blob, size);
-}
-
-/*
-  decode/process plain data
-*/
-static NTSTATUS ldap_decode_plain(struct ldap_connection *conn, DATA_BLOB blob)
+static NTSTATUS ldap_recv_handler(void *private_data, DATA_BLOB blob)
 {
        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);
 
        if (msg == NULL) {
@@ -205,60 +193,14 @@ static NTSTATUS ldap_decode_plain(struct ldap_connection *conn, DATA_BLOB blob)
        return NT_STATUS_OK;
 }
 
-/*
-  decode/process wrapped data
-*/
-static NTSTATUS ldap_decode_wrapped(struct ldap_connection *conn, DATA_BLOB blob)
-{
-       DATA_BLOB wrapped, unwrapped;
-       struct asn1_data asn1;
-       struct ldap_message *msg = talloc(conn, struct ldap_message);
-       NTSTATUS status;
-
-       if (msg == NULL) {
-               return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
-       }
-
-       wrapped = data_blob_const(blob.data+4, blob.length-4);
-
-       status = gensec_unwrap(conn->gensec, msg, &wrapped, &unwrapped);
-       if (!NT_STATUS_IS_OK(status)) {
-               return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
-       }
-
-       data_blob_free(&blob);
-
-       if (!asn1_load(&asn1, unwrapped)) {
-               return NT_STATUS_LDAP(LDAP_PROTOCOL_ERROR);
-       }
-
-       while (ldap_decode(&asn1, msg)) {
-               ldap_match_message(conn, msg);
-               msg = talloc(conn, struct ldap_message);
-       }
-               
-       talloc_free(msg);
-       asn1_free(&asn1);
-
-       return NT_STATUS_OK;
-}
-
-
-/*
-  handle ldap recv events
-*/
-static NTSTATUS ldap_recv_handler(void *private_data, DATA_BLOB blob)
+/* 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);
-       if (conn->enable_wrap) {
-               return ldap_decode_wrapped(conn, blob);
-       }
-
-       return ldap_decode_plain(conn, blob);
+       packet_recv(conn->packet);
 }
 
-
 /*
   handle ldap socket events
 */
@@ -272,7 +214,7 @@ static void ldap_io_handler(struct event_context *ev, struct fd_event *fde,
                if (!tls_enabled(conn->sock)) return;
        }
        if (flags & EVENT_FD_READ) {
-               packet_recv(conn->packet);
+               ldap_read_io_handler(private_data, flags);
        }
 }
 
@@ -417,7 +359,7 @@ static void ldap_connect_recv_conn(struct composite_context *ctx)
        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_complete_packet);
+       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);
@@ -561,24 +503,6 @@ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
                goto failed;            
        }
 
-       /* possibly encrypt/sign the request */
-       if (conn->enable_wrap) {
-               DATA_BLOB wrapped;
-
-               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;
index 28b9f2763cf7ad78ffaf422a821a930afd8d6bc3..849737d8a9a8a20169549779ec9b21f044f67bb2 100644 (file)
@@ -80,9 +80,6 @@ struct ldap_connection {
        /* Let's support SASL */
        struct gensec_security *gensec;
 
-       /* set if we are wrapping requests */
-       BOOL enable_wrap;
-
        /* the default timeout for messages */
        int timeout;
 
index 59e87304d3ae433c53b5de1b53be5cee7689ba76..d238fc4128e03f1955317c008240b54addac22ac 100644 (file)
@@ -100,6 +100,11 @@ static void stream_io_handler(struct event_context *ev, struct fd_event *fde,
        }
 }
 
+void stream_io_handler_callback(void *conn, uint16_t flags) 
+{
+       stream_io_handler(NULL, NULL, flags, conn);
+}
+
 /*
   this creates a stream_connection from an already existing connection,
   used for protocols, where a client connection needs to switched into