ctdb-failover: Split statd_callout add-client/del-client
[samba.git] / source4 / ldap_server / ldap_server.c
index e3d6a22e56831950de8368da9abcbfb2407f5bac..90316fd6b68cd2578cd57e07235775fda0484497 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    Unix SMB/CIFS implementation.
 
    LDAP server
@@ -48,6 +48,9 @@
 #include "../libcli/util/tstream.h"
 #include "libds/common/roles.h"
 #include "lib/util/time.h"
+#include "lib/util/server_id.h"
+#include "lib/util/server_id_db.h"
+#include "lib/messaging/messaging_internal.h"
 
 #undef strcasecmp
 
@@ -297,9 +300,10 @@ static void ldapsrv_accept_tls_done(struct tevent_req *subreq);
 */
 static void ldapsrv_accept(struct stream_connection *c,
                           struct auth_session_info *session_info,
-                          bool is_privileged)
+                          bool is_privileged,
+                          bool is_ldapi)
 {
-       struct ldapsrv_service *ldapsrv_service = 
+       struct ldapsrv_service *ldapsrv_service =
                talloc_get_type(c->private_data, struct ldapsrv_service);
        struct ldapsrv_connection *conn;
        struct cli_credentials *server_credentials;
@@ -316,8 +320,9 @@ static void ldapsrv_accept(struct stream_connection *c,
                return;
        }
        conn->is_privileged = is_privileged;
+       conn->is_ldapi = is_ldapi;
 
-       conn->sockets.send_queue = tevent_queue_create(conn, "ldapsev send queue");
+       conn->sockets.send_queue = tevent_queue_create(conn, "ldapsrv send queue");
        if (conn->sockets.send_queue == NULL) {
                stream_terminate_connection(c,
                                            "ldapsrv_accept: tevent_queue_create failed");
@@ -335,6 +340,8 @@ static void ldapsrv_accept(struct stream_connection *c,
                return;
        }
        socket_set_flags(c->socket, SOCKET_FLAG_NOCLOSE);
+       /* as server we want to fail early */
+       tstream_bsd_fail_readv_first_error(conn->sockets.raw, true);
 
        conn->connection  = c;
        conn->service     = ldapsrv_service;
@@ -371,6 +378,17 @@ static void ldapsrv_accept(struct stream_connection *c,
                conn->require_strong_auth = lpcfg_ldap_server_require_strong_auth(conn->lp_ctx);
        }
 
+       if (conn->require_strong_auth ==
+           LDAP_SERVER_REQUIRE_STRONG_AUTH_ALLOW_SASL_OVER_TLS)
+       {
+               D_ERR("WARNING: You have not configured "
+                     "'ldap server require strong auth = "
+                     "allow_sasl_over_tls'.\n"
+                     "Please change to 'yes' (preferred and default) or "
+                     "'allow_sasl_without_tls_channel_bindings' "
+                     "(if really needed)\n\n");
+       }
+
        ret = ldapsrv_backend_Init(conn, &errstring);
        if (ret != LDB_SUCCESS) {
                char *reason = talloc_asprintf(conn,
@@ -384,7 +402,7 @@ static void ldapsrv_accept(struct stream_connection *c,
        /* load limits from the conf partition */
        ldapsrv_load_limits(conn); /* should we fail on error ? */
 
-       /* register the server */       
+       /* register the server */
        irpc_add_name(c->msg_ctx, "ldap_server");
 
        DLIST_ADD_END(ldapsrv_service->connections, conn);
@@ -444,6 +462,7 @@ static void ldapsrv_accept_tls_done(struct tevent_req *subreq)
 
 static void ldapsrv_call_read_done(struct tevent_req *subreq);
 static NTSTATUS ldapsrv_packet_check(
+       struct tstream_context *stream,
        void *private_data,
        DATA_BLOB blob,
        size_t *packet_size);
@@ -1123,7 +1142,7 @@ static void ldapsrv_accept_nonpriv(struct stream_connection *c)
                                            "session info");
                return;
        }
-       ldapsrv_accept(c, session_info, false);
+       ldapsrv_accept(c, session_info, false, false);
 }
 
 static const struct stream_server_ops ldap_stream_nonpriv_ops = {
@@ -1133,13 +1152,37 @@ static const struct stream_server_ops ldap_stream_nonpriv_ops = {
        .send_handler           = ldapsrv_send,
 };
 
+static void ldapsrv_accept_nonpriv_ldapi(struct stream_connection *c)
+{
+       struct ldapsrv_service *ldapsrv_service = talloc_get_type_abort(
+               c->private_data, struct ldapsrv_service);
+       struct auth_session_info *session_info;
+       NTSTATUS status;
+
+       status = auth_anonymous_session_info(
+               c, ldapsrv_service->lp_ctx, &session_info);
+       if (!NT_STATUS_IS_OK(status)) {
+               stream_terminate_connection(c, "failed to setup anonymous "
+                                           "session info");
+               return;
+       }
+       ldapsrv_accept(c, session_info, false, true);
+}
+
+static const struct stream_server_ops ldapi_stream_nonpriv_ops = {
+       .name                   = "ldap",
+       .accept_connection      = ldapsrv_accept_nonpriv_ldapi,
+       .recv_handler           = ldapsrv_recv,
+       .send_handler           = ldapsrv_send,
+};
+
 /* The feature removed behind an #ifdef until we can do it properly
  * with an EXTERNAL bind. */
 
 #define WITH_LDAPI_PRIV_SOCKET
 
 #ifdef WITH_LDAPI_PRIV_SOCKET
-static void ldapsrv_accept_priv(struct stream_connection *c)
+static void ldapsrv_accept_priv_ldapi(struct stream_connection *c)
 {
        struct ldapsrv_service *ldapsrv_service = talloc_get_type_abort(
                c->private_data, struct ldapsrv_service);
@@ -1151,12 +1194,12 @@ static void ldapsrv_accept_priv(struct stream_connection *c)
                                            "session info");
                return;
        }
-       ldapsrv_accept(c, session_info, true);
+       ldapsrv_accept(c, session_info, true, true);
 }
 
-static const struct stream_server_ops ldap_stream_priv_ops = {
+static const struct stream_server_ops ldapi_stream_priv_ops = {
        .name                   = "ldap",
-       .accept_connection      = ldapsrv_accept_priv,
+       .accept_connection      = ldapsrv_accept_priv_ldapi,
        .recv_handler           = ldapsrv_recv,
        .send_handler           = ldapsrv_send,
 };
@@ -1254,11 +1297,111 @@ static NTSTATUS add_socket(struct task_server *task,
        return NT_STATUS_OK;
 }
 
+static void ldap_reload_certs(struct imessaging_context *msg_ctx,
+                             void *private_data,
+                             uint32_t msg_type,
+                             struct server_id server_id,
+                             size_t num_fds,
+                             int *fds,
+                             DATA_BLOB *data)
+{
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct ldapsrv_service *ldap_service =
+               talloc_get_type_abort(private_data,
+               struct ldapsrv_service);
+       int default_children;
+       int num_children;
+       int i;
+       bool ok;
+       struct server_id ldap_master_id;
+       NTSTATUS status;
+       struct tstream_tls_params *new_tls_params = NULL;
+
+       SMB_ASSERT(msg_ctx == ldap_service->current_msg);
+
+       /* reload certificates */
+       status = tstream_tls_params_server(ldap_service,
+                                          ldap_service->dns_host_name,
+                                          lpcfg_tls_enabled(ldap_service->lp_ctx),
+                                          lpcfg_tls_keyfile(frame, ldap_service->lp_ctx),
+                                          lpcfg_tls_certfile(frame, ldap_service->lp_ctx),
+                                          lpcfg_tls_cafile(frame, ldap_service->lp_ctx),
+                                          lpcfg_tls_crlfile(frame, ldap_service->lp_ctx),
+                                          lpcfg_tls_dhpfile(frame, ldap_service->lp_ctx),
+                                          lpcfg_tls_priority(ldap_service->lp_ctx),
+                                          &new_tls_params);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_ERR("ldapsrv failed tstream_tls_params_server - %s\n",
+                       nt_errstr(status));
+               TALLOC_FREE(frame);
+               return;
+       }
+
+       TALLOC_FREE(ldap_service->tls_params);
+       ldap_service->tls_params = new_tls_params;
+
+       if (getpid() != ldap_service->parent_pid) {
+               /*
+                * If we are not the master process we are done
+                */
+               TALLOC_FREE(frame);
+               return;
+       }
+
+       /*
+        * Check we're running under the prefork model,
+        * by checking if the prefork-master-ldap name
+        * was registered
+        */
+       ok = server_id_db_lookup_one(msg_ctx->names, "prefork-master-ldap", &ldap_master_id);
+       if (!ok) {
+               /*
+                * We are done if another process model is in use.
+                */
+               TALLOC_FREE(frame);
+               return;
+       }
+
+       /*
+        * Now we loop over all possible prefork workers
+        * in order to notify them about the reload
+        */
+       default_children = lpcfg_prefork_children(ldap_service->lp_ctx);
+       num_children = lpcfg_parm_int(ldap_service->lp_ctx,
+                                     NULL, "prefork children", "ldap",
+                                     default_children);
+       for (i = 0; i < num_children; i++) {
+               char child_name[64] = { 0, };
+               struct server_id ldap_worker_id;
+
+               snprintf(child_name, sizeof(child_name), "prefork-worker-ldap-%d", i);
+               ok = server_id_db_lookup_one(msg_ctx->names, child_name, &ldap_worker_id);
+               if (!ok) {
+                       DBG_ERR("server_id_db_lookup_one(%s) - failed\n",
+                               child_name);
+                       continue;
+               }
+
+               status = imessaging_send(msg_ctx, ldap_worker_id,
+                                        MSG_RELOAD_TLS_CERTIFICATES, NULL);
+               if (!NT_STATUS_IS_OK(status)) {
+                       struct server_id_buf id_buf;
+                       DBG_ERR("ldapsrv failed imessaging_send(%s, %s) - %s\n",
+                               child_name,
+                               server_id_str_buf(ldap_worker_id, &id_buf),
+                               nt_errstr(status));
+                       continue;
+               }
+       }
+
+       TALLOC_FREE(frame);
+}
+
 /*
   open the ldap server sockets
 */
 static NTSTATUS ldapsrv_task_init(struct task_server *task)
-{      
+{
        char *ldapi_path;
 #ifdef WITH_LDAPI_PRIV_SOCKET
        char *priv_dir;
@@ -1268,11 +1411,11 @@ static NTSTATUS ldapsrv_task_init(struct task_server *task)
 
        switch (lpcfg_server_role(task->lp_ctx)) {
        case ROLE_STANDALONE:
-               task_server_terminate(task, "ldap_server: no LDAP server required in standalone configuration", 
+               task_server_terminate(task, "ldap_server: no LDAP server required in standalone configuration",
                                      false);
                return NT_STATUS_INVALID_DOMAIN_ROLE;
        case ROLE_DOMAIN_MEMBER:
-               task_server_terminate(task, "ldap_server: no LDAP server required in member server configuration", 
+               task_server_terminate(task, "ldap_server: no LDAP server required in member server configuration",
                                      false);
                return NT_STATUS_INVALID_DOMAIN_ROLE;
        case ROLE_ACTIVE_DIRECTORY_DC:
@@ -1300,6 +1443,8 @@ static NTSTATUS ldapsrv_task_init(struct task_server *task)
                goto failed;
        }
 
+       ldap_service->parent_pid = getpid();
+
        status = tstream_tls_params_server(ldap_service,
                                           ldap_service->dns_host_name,
                                           lpcfg_tls_enabled(task->lp_ctx),
@@ -1330,7 +1475,7 @@ static NTSTATUS ldapsrv_task_init(struct task_server *task)
                load_interface_list(task, task->lp_ctx, &ifaces);
                num_interfaces = iface_list_count(ifaces);
 
-               /* We have been given an interfaces line, and been 
+               /* We have been given an interfaces line, and been
                   told to only bind to those interfaces. Create a
                   socket per interface and bind to only these.
                */
@@ -1371,8 +1516,8 @@ static NTSTATUS ldapsrv_task_init(struct task_server *task)
        }
 
        status = stream_setup_socket(task, task->event_ctx, task->lp_ctx,
-                                    task->model_ops, &ldap_stream_nonpriv_ops,
-                                    "unix", ldapi_path, NULL, 
+                                    task->model_ops, &ldapi_stream_nonpriv_ops,
+                                    "unix", ldapi_path, NULL,
                                     lpcfg_socket_options(task->lp_ctx),
                                     ldap_service, task->process_context);
        talloc_free(ldapi_path);
@@ -1404,7 +1549,7 @@ static NTSTATUS ldapsrv_task_init(struct task_server *task)
        }
 
        status = stream_setup_socket(task, task->event_ctx, task->lp_ctx,
-                                    task->model_ops, &ldap_stream_priv_ops,
+                                    task->model_ops, &ldapi_stream_priv_ops,
                                     "unix", ldapi_path, NULL,
                                     lpcfg_socket_options(task->lp_ctx),
                                     ldap_service,
@@ -1463,6 +1608,7 @@ static void ldapsrv_before_loop(struct task_server *task)
 {
        struct ldapsrv_service *ldap_service =
                talloc_get_type_abort(task->private_data, struct ldapsrv_service);
+       NTSTATUS status;
 
        if (ldap_service->sam_ctx != NULL) {
                /*
@@ -1481,6 +1627,16 @@ static void ldapsrv_before_loop(struct task_server *task)
                ldap_service->current_ev = task->event_ctx;
                ldap_service->current_msg = task->msg_ctx;
        }
+
+       status = imessaging_register(ldap_service->current_msg,
+                                    ldap_service,
+                                    MSG_RELOAD_TLS_CERTIFICATES,
+                                    ldap_reload_certs);
+       if (!NT_STATUS_IS_OK(status)) {
+               task_server_terminate(task, "Cannot register ldap_reload_certs",
+                                     true);
+               return;
+       }
 }
 
 /*
@@ -1542,6 +1698,7 @@ static int ldapsrv_check_packet_size(
  *
  */
 static NTSTATUS ldapsrv_packet_check(
+       struct tstream_context *stream,
        void *private_data,
        DATA_BLOB blob,
        size_t *packet_size)
@@ -1550,7 +1707,7 @@ static NTSTATUS ldapsrv_packet_check(
        struct ldapsrv_connection *conn = private_data;
        int result = LDB_SUCCESS;
 
-       ret = ldap_full_packet(private_data, blob, packet_size);
+       ret = ldap_full_packet(stream, private_data, blob, packet_size);
        if (!NT_STATUS_IS_OK(ret)) {
                return ret;
        }