diff options
Diffstat (limited to 'source4/lib')
-rw-r--r-- | source4/lib/socket/socket.c | 25 | ||||
-rw-r--r-- | source4/lib/socket/socket.h | 8 | ||||
-rw-r--r-- | source4/lib/stream/packet.c | 33 | ||||
-rw-r--r-- | source4/lib/stream/packet.h | 6 | ||||
-rw-r--r-- | source4/lib/tls/tls.c | 4 |
5 files changed, 56 insertions, 20 deletions
diff --git a/source4/lib/socket/socket.c b/source4/lib/socket/socket.c index ac64bc4ddc..eca668885c 100644 --- a/source4/lib/socket/socket.c +++ b/source4/lib/socket/socket.c @@ -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); } diff --git a/source4/lib/socket/socket.h b/source4/lib/socket/socket.h index c0cf429887..025fc7e13d 100644 --- a/source4/lib/socket/socket.h +++ b/source4/lib/socket/socket.h @@ -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; diff --git a/source4/lib/stream/packet.c b/source4/lib/stream/packet.c index e06f4985ef..2759c75214 100644 --- a/source4/lib/stream/packet.c +++ b/source4/lib/stream/packet.c @@ -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) diff --git a/source4/lib/stream/packet.h b/source4/lib/stream/packet.h index b7ee428186..0d875d777c 100644 --- a/source4/lib/stream/packet.h +++ b/source4/lib/stream/packet.h @@ -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); /* diff --git a/source4/lib/tls/tls.c b/source4/lib/tls/tls.c index 1ba8ae9779..f9213af2a7 100644 --- a/source4/lib/tls/tls.c +++ b/source4/lib/tls/tls.c @@ -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; } |