]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
s4:dsdb/ldb_modules: add trust_notify module
authorStefan Metzmacher <metze@samba.org>
Thu, 6 Feb 2025 19:11:20 +0000 (20:11 +0100)
committerRalph Boehme <slow@samba.org>
Sat, 8 Feb 2025 15:26:38 +0000 (15:26 +0000)
This will notify winbindd if critical aspects
of the trusted domain topology are changed.

It means it will also happen when the changes are
replicated from other DCs.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
source4/dsdb/samdb/ldb_modules/samba_dsdb.c
source4/dsdb/samdb/ldb_modules/trust_notify.c [new file with mode: 0644]
source4/dsdb/samdb/ldb_modules/wscript_build_server

index e494ca85f97659feacf5b9147229a07c26fb48b5..2f14b80f3ef5c4f2f3b53d17734f20404a3ccfb2 100644 (file)
@@ -231,11 +231,14 @@ static int samba_dsdb_init(struct ldb_module *module)
        const char *extended_dn_module_ldb = "extended_dn_out_ldb";
        const char *extended_dn_in_module = "extended_dn_in";
 
-       static const char *modules_list2[] = {"dns_notify",
-                                             "show_deleted",
-                                             "new_partition",
-                                             "partition",
-                                             NULL };
+       static const char *modules_list2[] = {
+               "trust_notify",
+               "dns_notify",
+               "show_deleted",
+               "new_partition",
+               "partition",
+               NULL
+       };
 
        const char **backend_modules;
        static const char *samba_dsdb_attrs[] = { SAMBA_COMPATIBLE_FEATURES_ATTR,
diff --git a/source4/dsdb/samdb/ldb_modules/trust_notify.c b/source4/dsdb/samdb/ldb_modules/trust_notify.c
new file mode 100644 (file)
index 0000000..d8ed80e
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+   ldb database library
+
+   Copyright (C) Stefan Metzmacher 2025
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "param/param.h"
+#include "ldb_module.h"
+#include "dsdb/samdb/ldb_modules/util.h"
+#include "lib/messaging/irpc.h"
+
+struct trust_notify_private {
+       bool notify_winbind;
+};
+
+static void trust_notify_winbind_server(struct ldb_module *module)
+{
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct imessaging_context *imsg_ctx = NULL;
+       struct loadparm_context *lp_ctx= NULL;
+       struct server_id *server_ids = NULL;
+       uint32_t num_server_ids = 0;
+       NTSTATUS status;
+
+       lp_ctx = ldb_get_opaque(ldb, "loadparm");
+       if (lp_ctx == NULL) {
+               TALLOC_FREE(frame);
+               return;
+       }
+
+       imsg_ctx = imessaging_client_init(frame, lp_ctx,
+                                         ldb_get_event_context(ldb));
+       if (imsg_ctx == NULL) {
+               ldb_asprintf_errstring(ldb,
+                                      "imessaging_client_init failed in %s",
+                                      lpcfg_imessaging_path(frame, lp_ctx));
+               TALLOC_FREE(frame);
+               return;
+       }
+
+       status = irpc_servers_byname(imsg_ctx,
+                                    frame,
+                                    "winbind_server",
+                                    &num_server_ids,
+                                    &server_ids);
+       if (NT_STATUS_IS_OK(status) && num_server_ids >= 1) {
+               imessaging_send(imsg_ctx,
+                               server_ids[0],
+                               MSG_WINBIND_RELOAD_TRUSTED_DOMAINS,
+                               NULL);
+       }
+       TALLOC_FREE(frame);
+}
+
+static bool trust_notify_has_watched_attrs(const struct ldb_message *msg)
+{
+       static const char * const trust_attrs[] = {
+               /*
+                * We only use attributes used
+                * and cached by winbindd.
+                */
+
+               /*
+                * These are from the trustedDomain objects
+                */
+               "securityIdentifier",
+               "flatName",
+               "trustPartner",
+               "trustAttributes",
+               "trustDirection",
+               "trustType",
+               "msDS-TrustForestTrustInfo",
+               "trustAuthIncoming",
+               "trustAuthOutgoing",
+               "msDS-SupportedEncryptionTypes",
+               "msDS-IngressClaimsTransformationPolicy",
+               "msDS-EgressClaimsTransformationPolicy",
+
+               /*
+                * These are from the crossRefContainer object
+                */
+               "uPNSuffixes",
+               "msDS-SPNSuffixes",
+
+               /*
+                * These are from the crossRef objects
+                *
+                * Very unlikely to ever change
+                */
+               "dnsRoot",
+               "nETBIOSName",
+
+               NULL
+       };
+       size_t ti;
+
+       for (ti = 0; trust_attrs[ti] != NULL; ti++) {
+               const struct ldb_message_element *el = NULL;
+
+               el = ldb_msg_find_element(msg, trust_attrs[ti]);
+               if (el != NULL) {
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static int trust_notify_add(struct ldb_module *module, struct ldb_request *req)
+{
+       struct trust_notify_private *data = NULL;
+       bool found = false;
+
+       if (ldb_dn_is_special(req->op.add.message->dn)) {
+               return ldb_next_request(module, req);
+       }
+
+       data = talloc_get_type_abort(ldb_module_get_private(module),
+                                    struct trust_notify_private);
+
+       found = trust_notify_has_watched_attrs(req->op.add.message);
+       if (found) {
+               data->notify_winbind = true;
+       }
+
+       return ldb_next_request(module, req);
+}
+
+static int trust_notify_modify(struct ldb_module *module, struct ldb_request *req)
+{
+       struct trust_notify_private *data = NULL;
+       bool found = false;
+
+       if (ldb_dn_is_special(req->op.mod.message->dn)) {
+               return ldb_next_request(module, req);
+       }
+
+       data = talloc_get_type_abort(ldb_module_get_private(module),
+                                    struct trust_notify_private);
+
+       found = trust_notify_has_watched_attrs(req->op.add.message);
+       if (found) {
+               data->notify_winbind = true;
+       }
+
+       return ldb_next_request(module, req);
+}
+
+static int trust_notify_delete(struct ldb_module *module, struct ldb_request *req)
+{
+       TALLOC_CTX *frame = NULL;
+       struct trust_notify_private *data = NULL;
+       struct ldb_result *res = NULL;
+       const char * const attrs[] = { "objectClass", NULL };
+       const char * const classes[] = {
+               /*
+                * these must be in the correct spelling
+                * as in the schema!
+                */
+               "trustedDomain",
+               "crossRef",
+               NULL
+       };
+       size_t ci;
+       int ret;
+
+       if (ldb_dn_is_special(req->op.del.dn)) {
+               return ldb_next_request(module, req);
+       }
+
+       data = talloc_get_type_abort(ldb_module_get_private(module),
+                                    struct trust_notify_private);
+
+       frame = talloc_stackframe();
+
+       ret = dsdb_module_search_dn(module, frame, &res, req->op.del.dn,
+                                   attrs,
+                                   DSDB_FLAG_NEXT_MODULE |
+                                   DSDB_SEARCH_SHOW_RECYCLED |
+                                   DSDB_SEARCH_REVEAL_INTERNALS |
+                                   DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
+                                   req);
+       if (ret != LDB_SUCCESS) {
+               TALLOC_FREE(frame);
+               return ret;
+       }
+
+       for (ci = 0; classes[ci] != NULL; ci++) {
+               ret = ldb_msg_check_string_attribute(res->msgs[0],
+                                                    "objectClass",
+                                                    classes[ci]);
+               if (ret == 0) {
+                       continue;
+               }
+               data->notify_winbind = true;
+               break;
+       }
+
+       TALLOC_FREE(frame);
+       return ldb_next_request(module, req);
+}
+
+static int trust_notify_start_trans(struct ldb_module *module)
+{
+       struct trust_notify_private *data =
+               talloc_get_type_abort(ldb_module_get_private(module),
+               struct trust_notify_private);
+
+       data->notify_winbind = false;
+
+       return ldb_next_start_trans(module);
+}
+
+static int trust_notify_end_trans(struct ldb_module *module)
+{
+       struct trust_notify_private *data =
+               talloc_get_type_abort(ldb_module_get_private(module),
+               struct trust_notify_private);
+       int ret;
+
+       ret = ldb_next_end_trans(module);
+       if (ret == LDB_SUCCESS) {
+               if (data->notify_winbind) {
+                       trust_notify_winbind_server(module);
+               }
+       }
+
+       return ret;
+}
+
+static int trust_notify_del_trans(struct ldb_module *module)
+{
+       struct trust_notify_private *data =
+               talloc_get_type_abort(ldb_module_get_private(module),
+               struct trust_notify_private);
+
+       data->notify_winbind = false;
+
+       return ldb_next_del_trans(module);
+}
+
+static int trust_notify_init(struct ldb_module *module)
+{
+       struct ldb_context *ldb = ldb_module_get_ctx(module);
+       struct trust_notify_private *data = NULL;
+
+       data = talloc_zero(module, struct trust_notify_private);
+       if (data == NULL) {
+               return ldb_oom(ldb);
+       }
+
+       ldb_module_set_private(module, data);
+
+       return ldb_next_init(module);
+}
+
+static const struct ldb_module_ops ldb_trust_notify_module_ops = {
+       .name              = "trust_notify",
+       .init_context      = trust_notify_init,
+       .add               = trust_notify_add,
+       .modify            = trust_notify_modify,
+       .del               = trust_notify_delete,
+       .start_transaction = trust_notify_start_trans,
+       .end_transaction   = trust_notify_end_trans,
+       .del_transaction   = trust_notify_del_trans,
+};
+
+int ldb_trust_notify_module_init(const char *version)
+{
+       LDB_MODULE_CHECK_VERSION(version);
+       return ldb_register_module(&ldb_trust_notify_module_ops);
+}
index 800ed2954c418de9312247d401e983ce2c9433f2..06a6c350b3dd3e4a55d3ff5e418d503a0a9d4640 100644 (file)
@@ -435,6 +435,15 @@ bld.SAMBA_MODULE('ldb_dsdb_notification',
        deps='talloc samba-security samdb DSDB_MODULE_HELPERS'
        )
 
+bld.SAMBA_MODULE('ldb_trust_notify',
+       source='trust_notify.c',
+       subsystem='ldb',
+       init_function='ldb_trust_notify_module_init',
+       module_init_name='ldb_init_module',
+       internal_module=False,
+       deps='talloc samdb DSDB_MODULE_HELPERS MESSAGING RPC_NDR_IRPC'
+       )
+
 bld.SAMBA_MODULE('ldb_dns_notify',
        source='dns_notify.c',
        subsystem='ldb',