s4:ldap_server: reload tls certificates on smbcontrol reload-certs
authorJule Anger <janger@samba.org>
Wed, 1 Mar 2023 09:53:53 +0000 (09:53 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 25 Jul 2023 20:04:29 +0000 (20:04 +0000)
Reload certificates with the command 'smbcontrol ldap_server reload-certs'.
The message is send to the master process, who forwards it to the workers
processes.
The master process reload and, if necessary, create the certificates first,
then the workers processes reload them.

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Jule Anger <janger@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
librpc/idl/messaging.idl
source3/utils/smbcontrol.c
source4/ldap_server/ldap_server.c
source4/ldap_server/ldap_server.h

index 398deed8e4c27e3361cb381b49a0a3a1fb5e3d61..2bcf10214533b3e482f1c9fad009bcf53aee51c0 100644 (file)
@@ -41,6 +41,7 @@ interface messaging
 
                /* Changes to smb.conf are really of general interest */
                MSG_SMB_CONF_UPDATED            = 0x0021,
+               MSG_RELOAD_TLS_CERTIFICATES     = 0x0022,
 
                MSG_PREFORK_CHILD_EVENT         = 0x0031,
                MSG_PREFORK_PARENT_EVENT        = 0x0032,
index b85dceca60565e61981871065f0664e7dcad6d7f..863f8c93dd102331c49804f3c2de9c5084b31e20 100644 (file)
@@ -1342,6 +1342,18 @@ static bool do_winbind_validate_cache(struct tevent_context *ev_ctx,
        return num_replies;
 }
 
+static bool do_reload_certs(struct tevent_context *ev_ctx,
+                                       struct messaging_context *msg_ctx,
+                                       const struct server_id pid,
+                                       const int argc, const char **argv)
+{
+       if (argc != 1) {
+               fprintf(stderr, "Usage: smbcontrol ldap_server reload-certs \n");
+               return false;
+       }
+
+       return send_message(msg_ctx, pid, MSG_RELOAD_TLS_CERTIFICATES, NULL, 0);
+}
 static bool do_reload_config(struct tevent_context *ev_ctx,
                             struct messaging_context *msg_ctx,
                             const struct server_id pid,
@@ -1543,6 +1555,11 @@ static const struct {
                .fn   = do_drvupgrade,
                .help = "Notify a printer driver has changed",
        },
+       {
+               .name = "reload-certs",
+               .fn   = do_reload_certs,
+               .help = "Reload TLS certificates"
+       },
        {
                .name = "reload-config",
                .fn   = do_reload_config,
@@ -1615,8 +1632,8 @@ static void usage(poptContext pc)
        poptPrintHelp(pc, stderr, 0);
 
        fprintf(stderr, "\n");
-       fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\" or a "
-               "process ID\n");
+       fprintf(stderr, "<destination> is one of \"nmbd\", \"smbd\", \"winbindd\", "
+               "\"ldap_server\" or a process ID\n");
 
        fprintf(stderr, "\n");
        fprintf(stderr, "<message-type> is one of:\n");
index e3d6a22e56831950de8368da9abcbfb2407f5bac..38c29be3ecbbd37ff40baf38968eb22df5f10dbe 100644 (file)
@@ -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
 
@@ -1254,6 +1257,106 @@ 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
 */
@@ -1300,6 +1403,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),
@@ -1463,6 +1568,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 +1587,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;
+       }
 }
 
 /*
index 44a80556445f0668e9f5aec254dee0d47f146e4b..a56aa8f8c4a15821413db4dacf9d65a4f46caff6 100644 (file)
@@ -115,6 +115,7 @@ struct ldapsrv_call {
 
 struct ldapsrv_service {
        const char *dns_host_name;
+       pid_t parent_pid;
        struct tstream_tls_params *tls_params;
        struct tevent_queue *call_queue;
        struct ldapsrv_connection *connections;