]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
winbindd: add struct winbindd_domain_ref infrastructure
authorStefan Metzmacher <metze@samba.org>
Fri, 7 Feb 2025 12:43:10 +0000 (13:43 +0100)
committerRalph Boehme <slow@samba.org>
Sat, 8 Feb 2025 15:26:38 +0000 (15:26 +0000)
In the next commits it will be possible that
struct winbindd_domain instances become stale
because trusted domains were reloaded.

That means aync state structure should not use
pointers to 'struct winbindd_domain' as they
can become stale!

Instead they should use 'struct winbindd_domain_ref domain'
in the async state and use winbindd_domain_ref_set/get()
to manage the 'struct winbindd_domain' pointer.

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

index dd1163663b07738c0d9d4a83a87e532068a0de3e..144fd466e6ef542dc691f87898426436afcc1f80 100644 (file)
@@ -67,6 +67,35 @@ struct winbindd_cli_state {
        struct getgrent_state *grent_state; /* State for getgrent() */
 };
 
+struct winbindd_domain;
+
+struct winbindd_domain_ref_internals {
+       const char *location;
+       const char *func;
+       bool stale;
+       struct dom_sid sid;
+       uint64_t generation;
+       struct winbindd_domain *domain; /* might be stale */
+};
+
+struct winbindd_domain_ref {
+       struct winbindd_domain_ref_internals internals;
+};
+
+void _winbindd_domain_ref_set(struct winbindd_domain_ref *ref,
+                             struct winbindd_domain *domain,
+                             const char *location,
+                             const char *func);
+#define winbindd_domain_ref_set(__ref, __domain) \
+       _winbindd_domain_ref_set(__ref, __domain, __location__, __func__)
+
+bool _winbindd_domain_ref_get(struct winbindd_domain_ref *ref,
+                             struct winbindd_domain **_domain,
+                             const char *location,
+                             const char *func);
+#define winbindd_domain_ref_get(__ref, __domain) \
+       _winbindd_domain_ref_get(__ref, __domain, __location__, __func__)
+
 struct getpwent_state {
        struct winbindd_domain *domain;
        uint32_t next_user;
@@ -101,8 +130,6 @@ struct winbindd_cm_conn {
 
 /* Async child */
 
-struct winbindd_domain;
-
 struct winbindd_child {
        pid_t pid;
        struct winbindd_domain *domain; /* if valid also talloc (grant) parent */
index 23b34b01641be256ad6dd598adbff49bda59afb5..e66e07546046495a3d94a55ca55bb9b5f4502bc2 100644 (file)
@@ -53,6 +53,7 @@
    the domain name instead. */
 
 static struct winbindd_domain *_domain_list = NULL;
+static uint64_t domain_list_generation;
 
 struct winbindd_domain *domain_list(void)
 {
@@ -87,6 +88,79 @@ struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
        return domain;
 }
 
+void _winbindd_domain_ref_set(struct winbindd_domain_ref *ref,
+                             struct winbindd_domain *domain,
+                             const char *location,
+                             const char *func)
+{
+       if (domain == NULL) {
+               ref->internals = (struct winbindd_domain_ref_internals) {
+                       .location = location,
+                       .func = func,
+               };
+               return;
+       }
+
+       ref->internals = (struct winbindd_domain_ref_internals) {
+               .location = location,
+               .func = func,
+               .sid = domain->sid,
+               .generation = domain_list_generation,
+               .domain = domain,
+       };
+}
+
+bool _winbindd_domain_ref_get(struct winbindd_domain_ref *ref,
+                             struct winbindd_domain **_domain,
+                             const char *location,
+                             const char *func)
+{
+       struct winbindd_domain *domain = NULL;
+
+       if (ref->internals.stale) {
+               goto stale;
+       }
+
+       if (ref->internals.domain == NULL) {
+               *_domain = NULL;
+               return true;
+       }
+
+       if (ref->internals.generation == domain_list_generation) {
+               *_domain = ref->internals.domain;
+               return true;
+       }
+
+       domain = find_domain_from_sid_noinit(&ref->internals.sid);
+stale:
+       if (domain == NULL) {
+               struct dom_sid_buf sbuf = {};
+
+               D_ERR("%s:%s: stale domain %s, set in %s\n",
+                     func,
+                     location,
+                     dom_sid_str_buf(&ref->internals.sid, &sbuf),
+                     ref->internals.location);
+
+               ref->internals.stale = true;
+               ref->internals.domain = NULL;
+
+               *_domain = NULL;
+               return false;
+       }
+
+       ref->internals = (struct winbindd_domain_ref_internals) {
+               .location = location,
+               .func = func,
+               .sid = domain->sid,
+               .generation = domain_list_generation,
+               .domain = domain,
+       };
+
+       *_domain = domain;
+       return true;
+}
+
 static bool is_internal_domain(const struct dom_sid *sid)
 {
        if (sid == NULL)
@@ -292,6 +366,7 @@ static NTSTATUS add_trusted_domain(const char *domain_name,
 
        /* Link to domain list */
        DLIST_ADD_END(_domain_list, domain);
+       domain_list_generation += 1;
 
        wcache_tdc_add_domain( domain );