r17644: change the ldap server to always use the single process model. We are
[ira/wip.git] / source / ldap_server / ldap_server.c
index b1ef4ff006357a979fc9a57eda5c103b88d1f386..d48c0664d7ce15c84880af59be546393ed92a651 100644 (file)
 #include "ldap_server/ldap_server.h"
 #include "smbd/service_task.h"
 #include "smbd/service_stream.h"
-#include "lib/socket/socket.h"
+#include "smbd/service.h"
+#include "smbd/process_model.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"
-#include "netif/netif.h"
+#include "lib/socket/netif.h"
 
 /*
   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)
 {
-       if (conn->tls) {
-               talloc_free(conn->tls);
-               conn->tls = NULL;
-       }
        stream_terminate_connection(conn->connection, reason);
 }
 
@@ -71,7 +67,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) {
@@ -82,11 +77,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);
@@ -103,49 +101,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);
-       }
-
-       /* possibly encrypt/sign the reply */
-       if (enable_wrap) {
-               DATA_BLOB wrapped;
+               talloc_set_name_const(blob.data, "Outgoing, encoded LDAP packet");
 
-               status = gensec_wrap(conn->gensec, call, &blob, &wrapped);
                if (!NT_STATUS_IS_OK(status)) {
-                       goto failed;
+                       talloc_free(call);
+                       return;
                }
-               data_blob_free(&blob);
-               blob = data_blob_talloc(call, NULL, wrapped.length + 4);
-               if (blob.data == NULL) {
-                       goto failed;
-               }
-               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);
 
@@ -168,63 +153,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
 */
@@ -241,7 +169,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);
@@ -264,20 +192,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
 */
@@ -335,7 +249,7 @@ static int ldapsrv_load_limits(struct ldapsrv_connection *conn)
                goto failed;
        }
 
-       conf_dn_s = ldb_msg_find_string(res->msgs[0], "configurationNamingContext", NULL);
+       conf_dn_s = ldb_msg_find_attr_as_string(res->msgs[0], "configurationNamingContext", NULL);
        if (conf_dn_s == NULL) {
                goto failed;
        }
@@ -414,27 +328,10 @@ static void ldapsrv_accept(struct stream_connection *c)
                return;
        }
 
-       conn->enable_wrap = False;
        conn->packet      = NULL;
        conn->connection  = c;
        conn->service     = ldapsrv_service;
-
-       server_credentials 
-               = cli_credentials_init(conn);
-       if (!server_credentials) {
-               stream_terminate_connection(c, "Failed to init server credentials\n");
-               talloc_free(conn);
-               return;
-       }
-       
-       cli_credentials_set_conf(server_credentials);
-       status = cli_credentials_set_machine_account(server_credentials);
-       if (!NT_STATUS_IS_OK(status)) {
-               stream_terminate_connection(c, talloc_asprintf(conn, "Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status)));
-               talloc_free(conn);
-               return;
-       }
-       conn->server_credentials = server_credentials;
+       conn->sockets.raw = c->socket;
 
        c->private        = conn;
 
@@ -446,26 +343,53 @@ static void ldapsrv_accept(struct stream_connection *c)
        port = socket_address->port;
        talloc_free(socket_address);
 
-       conn->tls = tls_init_server(ldapsrv_service->tls_params, c->socket, 
-                                   c->event.fde, NULL, port != 389);
-       if (!conn->tls) {
-               ldapsrv_terminate_connection(conn, "ldapsrv_accept: tls_init_server() failed");
-               return;
-       }
+       if (port == 636) {
+               struct socket_context *tls_socket = tls_init_server(ldapsrv_service->tls_params, c->socket, 
+                                                                   c->event.fde, NULL);
+               if (!tls_socket) {
+                       ldapsrv_terminate_connection(conn, "ldapsrv_accept: tls_init_server() failed");
+                       return;
+               }
+               talloc_unlink(c, c->socket);
+               talloc_steal(c, tls_socket);
+               c->socket = tls_socket;
+               conn->sockets.tls = tls_socket;
 
+       } else if (port == 3268) /* Global catalog */ {
+               conn->global_catalog = True;
+       }
        conn->packet = packet_init(conn);
        if (conn->packet == NULL) {
                ldapsrv_terminate_connection(conn, "out of memory");
                return;
        }
+
        packet_set_private(conn->packet, conn);
-       packet_set_tls(conn->packet, conn->tls);
+       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);
        packet_set_serialise(conn->packet);
+       
+       /* Ensure we don't get packets until the database is ready below */
+       packet_recv_disable(conn->packet);
+
+       server_credentials 
+               = cli_credentials_init(conn);
+       if (!server_credentials) {
+               stream_terminate_connection(c, "Failed to init server credentials\n");
+               return;
+       }
+       
+       cli_credentials_set_conf(server_credentials);
+       status = cli_credentials_set_machine_account(server_credentials);
+       if (!NT_STATUS_IS_OK(status)) {
+               stream_terminate_connection(c, talloc_asprintf(conn, "Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status)));
+               return;
+       }
+       conn->server_credentials = server_credentials;
 
        /* Connections start out anonymous */
        if (!NT_STATUS_IS_OK(auth_anonymous_session_info(conn, &conn->session_info))) {
@@ -488,6 +412,9 @@ static void ldapsrv_accept(struct stream_connection *c)
        conn->limits.ite = event_add_timed(c->event.ctx, conn, 
                                           timeval_current_ofs(conn->limits.initial_timeout, 0),
                                           ldapsrv_conn_init_timeout, conn);
+
+       packet_recv_enable(conn->packet);
+
 }
 
 static const struct stream_server_ops ldap_stream_ops = {
@@ -546,8 +473,13 @@ static void ldapsrv_task_init(struct task_server *task)
 {      
        struct ldapsrv_service *ldap_service;
        NTSTATUS status;
+       const struct model_ops *model_ops;
+
+       task_server_set_title(task, "task[ldapsrv]");
 
-       ldb_global_init();
+       /* run the ldap server as a single process */
+       model_ops = process_model_byname("single");
+       if (!model_ops) goto failed;
 
        ldap_service = talloc_zero(task, struct ldapsrv_service);
        if (ldap_service == NULL) goto failed;
@@ -565,11 +497,11 @@ static void ldapsrv_task_init(struct task_server *task)
                */
                for(i = 0; i < num_interfaces; i++) {
                        const char *address = iface_n_ip(i);
-                       status = add_socket(task->event_ctx, task->model_ops, address, ldap_service);
+                       status = add_socket(task->event_ctx, model_ops, address, ldap_service);
                        if (!NT_STATUS_IS_OK(status)) goto failed;
                }
        } else {
-               status = add_socket(task->event_ctx, task->model_ops, lp_socket_address(), ldap_service);
+               status = add_socket(task->event_ctx, model_ops, lp_socket_address(), ldap_service);
                if (!NT_STATUS_IS_OK(status)) goto failed;
        }