s4-ldapserver: serialise ldap server operations
authorAndrew Tridgell <tridge@samba.org>
Tue, 7 Sep 2010 01:57:44 +0000 (11:57 +1000)
committerAndrew Tridgell <tridge@samba.org>
Tue, 7 Sep 2010 02:55:27 +0000 (12:55 +1000)
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
source4/ldap_server/ldap_server.h

index 946e1bf3b7dca0eee0d7865dd94a9c7489b223dc..e975590d43b822d7765c596c56a65e30ebcc06c4 100644 (file)
@@ -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");
index 8b45285463d11a62e075c012d256b1962aedf275..0fb8d2f4aca7f426902381f446da4e89ffbd1bae 100644 (file)
@@ -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"