]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
winbindd: introduce update_trusted_domains_dc()
authorStefan Metzmacher <metze@samba.org>
Tue, 4 Feb 2025 17:32:59 +0000 (18:32 +0100)
committerRalph Boehme <slow@samba.org>
Sat, 8 Feb 2025 15:26:38 +0000 (15:26 +0000)
Reloading trusts should reload every aspect of
the trust and also remove deleted trusts from
the winbindd _domain_list.

But pending requests still continue.

With this commit it is required that
async state structures use struct winbindd_domain_ref
instead of raw struct winbindd_domain pointers,
in order to usage of stale pointers.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source3/winbindd/winbindd_dual.c
source3/winbindd/winbindd_proto.h
source3/winbindd/winbindd_util.c

index 65794552d9dbc438f10955366b44b8c9064348a3..956f47c02d96c855989db4b607d749f93a92aa94 100644 (file)
@@ -991,9 +991,9 @@ void winbindd_msg_reload_services_parent(struct messaging_context *msg,
                tevent_thread_call_depth_set_callback(NULL, NULL);
        }
 
-       ok = add_trusted_domains_dc();
+       ok = update_trusted_domains_dc();
        if (!ok) {
-               DBG_ERR("add_trusted_domains_dc() failed\n");
+               DBG_ERR("update_trusted_domains_dc() failed\n");
        }
 
        forall_children(winbind_msg_relay_fn, &state);
index 5d428ef2845c42fa865f72ab4849e9d2c649298b..7874e9b98bde8f030f9f5a1c887c96d90b1b5d78 100644 (file)
@@ -372,7 +372,7 @@ void winbindd_msg_reload_services_parent(struct messaging_context *msg,
 NTSTATUS winbindd_reinit_after_fork(const struct winbindd_child *myself,
                                    const char *logfilename);
 struct winbindd_domain *wb_child_domain(void);
-bool add_trusted_domains_dc(void);
+bool update_trusted_domains_dc(void);
 
 /* The following definitions come from winbindd/winbindd_group.c  */
 bool fill_grent(TALLOC_CTX *mem_ctx, struct winbindd_gr *gr,
index 192a2103b5a1fde90afd3cfb723f037dfc3b43fe..28448cf6961a73ba860139d83e6cc8f5fda2bce7 100644 (file)
@@ -888,7 +888,7 @@ static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
 
        DBG_NOTICE("Rescanning trusted domains\n");
 
-       ok = add_trusted_domains_dc();
+       ok = update_trusted_domains_dc();
        if (!ok) {
                DBG_ERR("Failed to reload trusted domains\n");
        }
@@ -937,7 +937,221 @@ static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
        return true;
 }
 
-bool add_trusted_domains_dc(void)
+static void free_domain(struct winbindd_domain *d)
+{
+       struct winbindd_domain *nd = NULL;
+       struct dom_sid_buf sbuf = {};
+
+       nd = find_domain_from_sid_noinit(&d->sid);
+       if (nd != NULL) {
+               DBG_WARNING("Free updated domain[%p] name[%s] %s "
+                           "replaced by domain[%p] name[%s]\n",
+                           d, d->name, dom_sid_str_buf(&d->sid, &sbuf),
+                           nd, nd->name);
+       } else {
+               DBG_WARNING("Free removed domain[%p] name[%s] %s\n",
+                           d, d->name, dom_sid_str_buf(&d->sid, &sbuf));
+       }
+       talloc_free(d);
+}
+
+static void terminate_child(struct tevent_req *subreq)
+{
+       struct winbindd_child *c =
+               (struct winbindd_child *)
+               tevent_req_callback_data_void(subreq);
+       struct winbindd_domain *d = c->domain;
+       size_t ci;
+       bool ok;
+
+       ok = tevent_queue_wait_recv(subreq);
+       SMB_ASSERT(ok);
+       TALLOC_FREE(subreq);
+
+       if (c->pid != 0) {
+               kill(c->pid, SIGTERM);
+               c->pid = 0;
+               if (c->sock != -1) {
+                       close(c->sock);
+               }
+               c->sock = -1;
+               TALLOC_FREE(c->monitor_fde);
+       }
+
+       c = NULL;
+       if (d == NULL) {
+               return;
+       }
+       if (d->internal) {
+               return;
+       }
+
+       for (ci = 0; ci < talloc_array_length(d->children); ci++) {
+               c = &d->children[ci];
+
+               if (c->pid != 0) {
+                       /*
+                        * still waiting
+                        */
+                       return;
+               }
+       }
+
+       free_domain(d);
+}
+
+static void terminate_domain(struct tevent_req *subreq)
+{
+       struct winbindd_domain *d =
+               tevent_req_callback_data(subreq,
+               struct winbindd_domain);
+       size_t ci;
+       bool ok;
+
+       ok = tevent_queue_wait_recv(subreq);
+       SMB_ASSERT(ok);
+
+       /* NO TALLOC_FREE(subreq); */
+       subreq = NULL;
+
+       for (ci = 0; ci < talloc_array_length(d->children); ci++) {
+               struct winbindd_child *c = &d->children[ci];
+
+               if (c->pid == 0) {
+                       continue;
+               }
+
+               subreq = tevent_queue_wait_send(d->children,
+                                               global_event_context(),
+                                               c->queue);
+               if (subreq == NULL) {
+                       return;
+               }
+               tevent_req_set_callback(subreq,
+                                       terminate_child,
+                                       c);
+       }
+
+       if (subreq != NULL) {
+               /*
+                * still waiting
+                */
+               return;
+       }
+
+       free_domain(d);
+}
+
+static bool remove_trusted_domains_dc(void)
+{
+       struct winbindd_domain *d = NULL;
+       struct winbindd_domain *n = NULL;
+       struct winbindd_child *c = NULL;
+       struct tevent_req *subreq = NULL;
+
+       SMB_ASSERT(IS_DC);
+
+       /*
+        * We need to terminate all
+        * child processes, but we need
+        * to go through the child and domain
+        * queues * in order to keep existing
+        * requests to finish.
+        *
+        * First start with the idmap and locator
+        * children
+        */
+
+       c = idmap_child();
+       if (c->pid != 0) {
+               subreq = tevent_queue_wait_send(c,
+                                               global_event_context(),
+                                               c->queue);
+               if (subreq == NULL) {
+                       return false;
+               }
+               tevent_req_set_callback(subreq,
+                                       terminate_child,
+                                       c);
+       }
+
+       c = locator_child();
+       if (c->pid != 0) {
+               subreq = tevent_queue_wait_send(c,
+                                               global_event_context(),
+                                               c->queue);
+               if (subreq == NULL) {
+                       return false;
+               }
+               tevent_req_set_callback(subreq,
+                                       terminate_child,
+                                       c);
+       }
+
+       /*
+        * For internal domains BUILTIN and local SAM
+        * we just terminate the children, forcing
+        * a re-fork
+        */
+       for (d = _domain_list; d != NULL; d = d->next) {
+               size_t ci;
+
+               if (!d->internal) {
+                       continue;
+               }
+
+               for (ci = 0; ci < talloc_array_length(d->children); ci++) {
+                       c = &d->children[ci];
+
+                       if (c->pid == 0) {
+                               continue;
+                       }
+
+                       subreq = tevent_queue_wait_send(d->children,
+                                                       global_event_context(),
+                                                       c->queue);
+                       if (subreq == NULL) {
+                               return false;
+                       }
+                       tevent_req_set_callback(subreq,
+                                               terminate_child,
+                                               c);
+               }
+       }
+
+       /*
+        * For trusted domain
+        * we need to wait in
+        * the domain queue in order
+        * to let pending requests
+        * use the existing domain
+        * children.
+        */
+       for (d = _domain_list; d != NULL; d = n) {
+               n = d->next;
+
+               if (d->internal) {
+                       continue;
+               }
+
+               subreq = tevent_queue_wait_send(d,
+                                               global_event_context(),
+                                               d->queue);
+               if (subreq == NULL) {
+                       return false;
+               }
+               tevent_req_set_callback(subreq,
+                                       terminate_domain,
+                                       d);
+
+               DLIST_REMOVE(_domain_list, d);
+               domain_list_generation += 1;
+       }
+
+       return true;
+}
+
+static bool add_trusted_domains_dc(void)
 {
        struct winbindd_domain *domain =  NULL;
        struct pdb_trusted_domain **domains = NULL;
@@ -945,6 +1159,8 @@ bool add_trusted_domains_dc(void)
        uint32_t i;
        NTSTATUS status;
 
+       SMB_ASSERT(IS_DC);
+
        if (!(pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
                struct trustdom_info **ti = NULL;
 
@@ -1120,6 +1336,26 @@ bool add_trusted_domains_dc(void)
        return true;
 }
 
+bool update_trusted_domains_dc(void)
+{
+       bool ok;
+
+       if (!IS_DC) {
+               return true;
+       }
+
+       ok = remove_trusted_domains_dc();
+       if (!ok) {
+               return false;
+       }
+
+       ok = add_trusted_domains_dc();
+       if (!ok) {
+               return false;
+       }
+
+       return true;
+}
 
 /* Look up global info for the winbind daemon */
 bool init_domain_list(void)