From 73c3932b2d0dac784a0605abf6e532dba5514a01 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 7 Sep 2010 11:57:44 +1000 Subject: [PATCH] s4-ldapserver: serialise ldap server operations This ensures that two ldap server operations cannot happen in parallel by using packet_recv_disable() and packet_recv_enable() to disable other interfaces during ldap calls. This prevents problems caused by parallel ldap operations where transactions could overlap. --- source4/ldap_server/ldap_server.c | 53 +++++++++++++++++++++++++++++++ source4/ldap_server/ldap_server.h | 7 ++++ 2 files changed, 60 insertions(+) diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c index 946e1bf3b7d..e975590d43b 100644 --- a/source4/ldap_server/ldap_server.c +++ b/source4/ldap_server/ldap_server.c @@ -131,6 +131,32 @@ static void ldapsrv_process_message(struct ldapsrv_connection *conn, return; } +/* + disable packets on other sockets while processing this one + */ +static void ldapsrv_disable_recv(struct ldapsrv_connection *conn) +{ + struct ldapsrv_packet_interfaces *p; + for (p=conn->service->packet_interfaces; p; p=p->next) { + if (p->packet != conn->packet) { + packet_recv_disable(p->packet); + } + } +} + +/* + disable packets on other sockets while processing this one + */ +static void ldapsrv_enable_recv(struct ldapsrv_connection *conn) +{ + struct ldapsrv_packet_interfaces *p; + for (p=conn->service->packet_interfaces; p; p=p->next) { + if (p->packet != conn->packet) { + packet_recv_enable(p->packet); + } + } +} + /* decode/process data */ @@ -162,7 +188,13 @@ static NTSTATUS ldapsrv_decode(void *private_data, DATA_BLOB blob) talloc_steal(conn, msg); asn1_free(asn1); + /* disable messages on other sockets while processing this one */ + ldapsrv_disable_recv(conn); + ldapsrv_process_message(conn, msg); + + ldapsrv_enable_recv(conn); + return NT_STATUS_OK; } @@ -324,6 +356,15 @@ failed: return -1; } +/* + remove a packet interface from the service level list + */ +static int packet_interface_destructor(struct ldapsrv_packet_interfaces *packet_interface) +{ + DLIST_REMOVE(packet_interface->service->packet_interfaces, packet_interface); + return 0; +} + /* initialise a server_context from a open socket and register a event handler for reading from that socket @@ -397,6 +438,18 @@ static void ldapsrv_accept(struct stream_connection *c, /* Ensure we don't get packets until the database is ready below */ packet_recv_disable(conn->packet); + /* add to the service level list of packet interfaces, to + * allow us to serialise between connections + */ + conn->packet_interface = talloc(conn, struct ldapsrv_packet_interfaces); + if (conn->packet_interface == NULL) { + ldapsrv_terminate_connection(conn, "out of memory"); + } + conn->packet_interface->service = ldapsrv_service; + conn->packet_interface->packet = conn->packet; + DLIST_ADD(conn->service->packet_interfaces, conn->packet_interface); + talloc_set_destructor(conn->packet_interface, packet_interface_destructor); + server_credentials = cli_credentials_init(conn); if (!server_credentials) { stream_terminate_connection(c, "Failed to init server credentials\n"); diff --git a/source4/ldap_server/ldap_server.h b/source4/ldap_server/ldap_server.h index 8b45285463d..0fb8d2f4aca 100644 --- a/source4/ldap_server/ldap_server.h +++ b/source4/ldap_server/ldap_server.h @@ -50,6 +50,8 @@ struct ldapsrv_connection { struct tevent_timer *ite; struct tevent_timer *te; } limits; + + struct ldapsrv_packet_interfaces *packet_interface; }; struct ldapsrv_call { @@ -66,6 +68,11 @@ struct ldapsrv_call { struct ldapsrv_service { struct tls_params *tls_params; struct task_server *task; + struct ldapsrv_packet_interfaces { + struct ldapsrv_packet_interfaces *next, *prev; + struct packet_context *packet; + struct ldapsrv_service *service; + } *packet_interfaces; }; #include "ldap_server/proto.h"