Always query the PDC for the list of trusted domains rather than interating
authorTim Potter <tpot@samba.org>
Fri, 11 Jan 2002 05:33:45 +0000 (05:33 +0000)
committerTim Potter <tpot@samba.org>
Fri, 11 Jan 2002 05:33:45 +0000 (05:33 +0000)
the list received at startup or we get an out of date list.  I thought
there might be some sequence number that is incremented when a trusted
domain is added or removed - perhaps there is but I just haven't found it
yet.

 - Renamed get_domain_info() to init_domain_list()

 - Made an accessor function to return the list of trusted domains rather
   than using a global so we don't have to remember to put a magic init
   function

 - The getent state can not keep a pointer to a winbind_domain structure as
   it may be freed if init_domain_list() is called again so we keep the
   domain name instead
(This used to be commit 37216c649a394b449eaaaa6644709eafb3bf37ff)

source3/nsswitch/winbindd.c
source3/nsswitch/winbindd.h
source3/nsswitch/winbindd_group.c
source3/nsswitch/winbindd_misc.c
source3/nsswitch/winbindd_proto.h
source3/nsswitch/winbindd_user.c
source3/nsswitch/winbindd_util.c

index 01cd0eb55df57b163feb9c042e2a9d533509db19..bd995611cd6c0abed12279a1fe9758c6e9eeffa3 100644 (file)
@@ -834,10 +834,10 @@ int main(int argc, char **argv)
        secrets_init();
 
        /* Get list of domains we look up requests for.  This includes the
-               domain which we are a member of as well as any trusted
-               domains. */ 
+          domain which we are a member of as well as any trusted
+          domains. */ 
 
-       get_domain_info();
+       init_domain_list();
 
        ZERO_STRUCT(server_state);
 
index 74206da9ef07543887ef5ebbb31225575bd8ca51..a8b9980be3600f661a6939080488ca99a43e6248 100644 (file)
@@ -52,7 +52,7 @@ struct getent_state {
        void *sam_entries;
        uint32 sam_entry_index, num_sam_entries;
        BOOL got_sam_entries;
-       struct winbindd_domain *domain;
+       fstring domain_name;
 };
 
 /* Storage for cached getpwent() user entries */
@@ -82,6 +82,31 @@ typedef struct {
        uint32 group_rid; /* primary group */
 } WINBIND_USERINFO;
 
+/* Structures to hold per domain information */
+
+struct winbindd_domain {
+       fstring name;                          /* Domain name */        
+       fstring full_name;                     /* full Domain name (realm) */   
+       DOM_SID sid;                           /* SID for this domain */
+
+       /* Lookup methods for this domain (LDAP or RPC) */
+
+       struct winbindd_methods *methods;
+
+        /* Private data for the backends (used for connection cache) */
+
+       void *private; 
+
+       /* Sequence number stuff */
+
+       time_t last_seq_check;
+       uint32 sequence_number;
+
+       /* Linked list info */
+
+       struct winbindd_domain *prev, *next;
+};
+
 /* per-domain methods. This is how LDAP vs RPC is selected
  */
 struct winbindd_methods {
@@ -150,22 +175,6 @@ struct winbindd_methods {
                               DOM_SID *sid);
 };
 
-/* Structures to hold per domain information */
-struct winbindd_domain {
-       fstring name;                          /* Domain name */        
-       fstring full_name;                     /* full Domain name (realm) */   
-       DOM_SID sid;                           /* SID for this domain */
-       struct winbindd_methods *methods;      /* lookup methods for
-                                                  this domain (LDAP or
-                                                  RPC) */
-       void *private; /* private data for the backends (used for connection cache) */
-       time_t last_seq_check;
-       uint32 sequence_number;
-       struct winbindd_domain *prev, *next;   /* Linked list info */
-};
-
-extern struct winbindd_domain *domain_list;  /* List of domains we know */
-
 /* Used to glue a policy handle and cli_state together */
 
 typedef struct {
index ff15611fba3c8399cf9d7731063200593da7b3f9..cd4254acfccdf40c8ddbe8ec9fe9bfd11002abf7 100644 (file)
@@ -352,10 +352,7 @@ enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state)
        
        /* Create sam pipes for each domain we know about */
        
-       if (domain_list == NULL)
-               get_domain_info();
-
-       for (domain = domain_list; domain != NULL; domain = domain->next) {
+       for (domain = domain_list(); domain != NULL; domain = domain->next) {
                struct getent_state *domain_state;
                
                /* Skip domains other than WINBINDD_DOMAIN environment 
@@ -373,7 +370,7 @@ enum winbindd_result winbindd_setgrent(struct winbindd_cli_state *state)
                
                ZERO_STRUCTP(domain_state);
                
-               domain_state->domain = domain;
+               fstrcpy(domain_state->domain_name, domain->name);
 
                /* Add to list of open domains */
                
@@ -410,12 +407,13 @@ static BOOL get_sam_group_entries(struct getent_state *ent)
        TALLOC_CTX *mem_ctx;
        BOOL result = False;
        struct acct_info *sam_grp_entries = NULL;
+       struct winbindd_domain *domain;
         
        if (ent->got_sam_entries)
                return False;
 
        if (!(mem_ctx = talloc_init_named("get_sam_group_entries(%s)",
-                                         ent->domain->name)))
+                                         ent->domain_name)))
                return False;
                
        /* Free any existing group info */
@@ -425,12 +423,18 @@ static BOOL get_sam_group_entries(struct getent_state *ent)
        ent->got_sam_entries = True;
 
        /* Enumerate domain groups */
+
        num_entries = 0;
 
-       status = ent->domain->methods->enum_dom_groups(ent->domain,
-                                                      mem_ctx, 
-                                                      &num_entries,
-                                                      &sam_grp_entries);
+       if (!(domain = find_domain_from_name(ent->domain_name))) {
+               DEBUG(3, ("no such domain %s in get_sam_group_entries\n", ent->domain_name));
+               goto done;
+       }
+
+       status = domain->methods->enum_dom_groups(domain,
+                                                 mem_ctx, 
+                                                 &num_entries,
+                                                 &sam_grp_entries);
        
        if (!NT_STATUS_IS_OK(status)) {
                result = False;
@@ -438,6 +442,7 @@ static BOOL get_sam_group_entries(struct getent_state *ent)
        }
 
        /* Copy entries into return buffer */
+
        if (num_entries) {
                name_list = malloc(sizeof(struct acct_info) * num_entries);
                memcpy(name_list, sam_grp_entries, 
@@ -447,6 +452,7 @@ static BOOL get_sam_group_entries(struct getent_state *ent)
        ent->num_sam_entries = num_entries;
                
        /* Fill in remaining fields */
+
        ent->sam_entries = name_list;
        ent->sam_entry_index = 0;
 
@@ -512,7 +518,7 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
                        while(ent && !get_sam_group_entries(ent)) {
                                struct getent_state *next_ent;
 
-                               DEBUG(10, ("freeing state info for domain %s\n", ent->domain->name)); 
+                               DEBUG(10, ("freeing state info for domain %s\n", ent->domain_name)); 
 
                                /* Free state information for this domain */
 
@@ -536,7 +542,7 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
                /* Lookup group info */
                
                if (!winbindd_idmap_get_gid_from_rid(
-                       ent->domain->name,
+                       ent->domain_name,
                        name_list[ent->sam_entry_index].rid,
                        &group_gid)) {
                        
@@ -553,7 +559,7 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
                /* Fill in group entry */
 
                slprintf(domain_group_name, sizeof(domain_group_name) - 1,
-                        "%s%s%s", ent->domain->name, lp_winbind_separator(), 
+                        "%s%s%s", ent->domain_name, lp_winbind_separator(), 
                         name_list[ent->sam_entry_index].acct_name);
    
                result = fill_grent(&group_list[group_list_ndx], 
@@ -562,9 +568,19 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
                /* Fill in group membership entry */
 
                if (result) {
+                       struct winbindd_domain *domain;
+
+                       if (!(domain = 
+                             find_domain_from_name(ent->domain_name))) {
+                               DEBUG(3, ("No such domain %s in winbindd_getgrent\n", ent->domain_name));
+                               result = False;
+                               goto done;
+                       }
+
                        /* Get group membership */
+                       
                        result = fill_grent_mem(
-                               ent->domain,
+                               domain,
                                name_list[ent->sam_entry_index].rid,
                                SID_NAME_DOM_GRP,
                                &group_list[group_list_ndx].num_gr_mem, 
@@ -673,10 +689,7 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
 
        /* Enumerate over trusted domains */
 
-       if (domain_list == NULL)
-               get_domain_info();
-
-       for (domain = domain_list; domain; domain = domain->next) {
+       for (domain = domain_list(); domain; domain = domain->next) {
                struct getent_state groups;
 
                ZERO_STRUCT(groups);
@@ -689,7 +702,7 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
 
                /* Get list of sam groups */
                ZERO_STRUCT(groups);
-               groups.domain = domain;
+               fstrcpy(groups.domain_name, domain->name);
 
                get_sam_group_entries(&groups);
                        
index d820bb35dce466c45b878c8ed5a18d04337d815e..883f9a4e22fc32cde9a24dec8b32d9090cc7d478 100644 (file)
@@ -104,10 +104,13 @@ enum winbindd_result winbindd_list_trusted_domains(struct winbindd_cli_state
 
        DEBUG(3, ("[%5d]: list trusted domains\n", state->pid));
 
-        if (domain_list == NULL)
-                get_domain_info();
+       /* We need to refresh the trusted domain list as the domains may
+          have changed since we last looked.  There may be a sequence
+          number or something we should use but I haven't found it yet. */
 
-       for(domain = domain_list; domain; domain = domain->next) {
+       init_domain_list();
+
+       for(domain = domain_list(); domain; domain = domain->next) {
 
                /* Skip own domain */
 
index fa5fec1b48fec2f5a87accb8c19e2035e7ba1496..bfadcc9a6c0d95a76a44c9b1f730f48ae478b4a1 100644 (file)
@@ -102,11 +102,14 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state);
 
 /* The following definitions come from nsswitch/winbindd_util.c  */
 
+struct winbindd_domain *domain_list(void);
+void free_domain_list(void);
+BOOL init_domain_list(void);
 struct winbindd_domain *find_domain_from_name(char *domain_name);
 struct winbindd_domain *find_domain_from_sid(DOM_SID *sid);
-BOOL get_domain_info(void);
 BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, 
-                                const char *name, DOM_SID *sid, enum SID_NAME_USE *type);
+                                const char *name, DOM_SID *sid, 
+                                enum SID_NAME_USE *type);
 BOOL winbindd_lookup_name_by_sid(DOM_SID *sid,
                                 fstring name,
                                 enum SID_NAME_USE *type);
index b5f9436de5517e5b98595646ba18106ca9aa0eea..e5cacbb9897e7270d30d15d730dc04db437f134e 100644 (file)
@@ -281,10 +281,7 @@ enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state)
         
        /* Create sam pipes for each domain we know about */
         
-       if (domain_list == NULL)
-               get_domain_info();
-
-       for(domain = domain_list; domain != NULL; domain = domain->next) {
+       for(domain = domain_list(); domain != NULL; domain = domain->next) {
                struct getent_state *domain_state;
                 
                /*
@@ -305,7 +302,7 @@ enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state)
                 
                ZERO_STRUCTP(domain_state);
 
-               domain_state->domain = domain;
+               fstrcpy(domain_state->domain_name, domain->name);
 
                /* Add to list of open domains */
                 
@@ -342,6 +339,7 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
        struct getpwent_user *name_list = NULL;
        BOOL result = False;
        TALLOC_CTX *mem_ctx;
+       struct winbindd_domain *domain;
        struct winbindd_methods *methods;
        int i;
 
@@ -349,10 +347,16 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
                return False;
 
        if (!(mem_ctx = talloc_init_named("get_sam_user_entries(%s)",
-                                         ent->domain->name)))
+                                         ent->domain_name)))
                return False;
 
-       methods = ent->domain->methods;
+       if (!(domain = find_domain_from_name(ent->domain_name))) {
+               DEBUG(3, ("no such domain %s in get_sam_user_entries\n",
+                         ent->domain_name));
+               return False;
+       }
+
+       methods = domain->methods;
 
        /* Free any existing user info */
 
@@ -360,10 +364,11 @@ static BOOL get_sam_user_entries(struct getent_state *ent)
        ent->num_sam_entries = 0;
        
        /* Call query_user_list to get a list of usernames and user rids */
+
        num_entries = 0;
 
-       status = methods->query_user_list(ent->domain, mem_ctx,
-                                         &num_entries, &info);
+       status = methods->query_user_list(domain, mem_ctx, &num_entries, 
+                                         &info);
                
        if (num_entries) {
                struct getpwent_user *tnl;
@@ -496,11 +501,11 @@ enum winbindd_result winbindd_getpwent(struct winbindd_cli_state *state)
                /* Lookup user info */
                
                slprintf(domain_user_name, sizeof(domain_user_name) - 1,
-                        "%s%s%s", ent->domain->name, sep,
+                        "%s%s%s", ent->domain_name, sep,
                         name_list[ent->sam_entry_index].name);
                
                result = winbindd_fill_pwent(
-                       ent->domain->name, 
+                       ent->domain_name, 
                        domain_user_name,
                        name_list[ent->sam_entry_index].user_rid,
                        name_list[ent->sam_entry_index].group_rid,
@@ -547,10 +552,7 @@ enum winbindd_result winbindd_list_users(struct winbindd_cli_state *state)
 
        /* Enumerate over trusted domains */
 
-       if (domain_list == NULL)
-               get_domain_info();
-
-       for (domain = domain_list; domain; domain = domain->next) {
+       for (domain = domain_list(); domain; domain = domain->next) {
                NTSTATUS status;
                struct winbindd_methods *methods;
                int i;
index 3086795a494b51fb5005d29e56f52f7d8bb8437d..f90e89c23f4b44733dcd16fa39ca55d4bb4e5171 100644 (file)
  *
  * Correct code should never look at a field that has this value.
  **/
+
 static const fstring name_deadbeef = "<deadbeef>";
 
+/* The list of trusted domains.  Note that the list can be deleted and
+   recreated using the init_domain_list() function so pointers to
+   individual winbindd_domain structures cannot be made.  Keep a copy of
+   the domain name instead. */
 
-/* Globals for domain list stuff */
-struct winbindd_domain *domain_list = NULL;
+static struct winbindd_domain *_domain_list;
 
-/* Given a domain name, return the struct winbindd domain info for it 
-   if it is actually working. */
-
-struct winbindd_domain *find_domain_from_name(char *domain_name)
+struct winbindd_domain *domain_list(void)
 {
-       struct winbindd_domain *domain;
-
-       if (domain_list == NULL)
-               get_domain_info();
+       /* Initialise list */
 
-       /* Search through list */
+       if (!_domain_list)
+               init_domain_list();
 
-       for (domain = domain_list; domain != NULL; domain = domain->next) {
-               if (strcasecmp(domain_name, domain->name) == 0 ||
-                   strcasecmp(domain_name, domain->full_name) == 0)
-                       return domain;
-       }
-
-       /* Not found */
-
-       return NULL;
+       return _domain_list;
 }
 
-/* Given a domain sid, return the struct winbindd domain info for it */
+/* Free all entries in the trusted domain list */
 
-struct winbindd_domain *find_domain_from_sid(DOM_SID *sid)
+void free_domain_list(void)
 {
-       struct winbindd_domain *domain;
-
-       if (domain_list == NULL)
-               get_domain_info();
-
-       /* Search through list */
-       for (domain = domain_list; domain != NULL; domain = domain->next) {
-               if (sid_compare_domain(sid, &domain->sid) == 0)
-                       return domain;
+       struct winbindd_domain *domain = _domain_list;
+
+       while(domain) {
+               struct winbindd_domain *next = domain->next;
+               
+               DLIST_REMOVE(_domain_list, domain);
+               SAFE_FREE(domain);
+               domain = next;
        }
-
-       /* Not found */
-
-       return NULL;
 }
 
 /* Add a trusted domain to our list of domains */
@@ -92,7 +78,10 @@ static struct winbindd_domain *add_trusted_domain(char *domain_name,
 {
        struct winbindd_domain *domain;
         
-       for (domain = domain_list; domain; domain = domain->next) {
+       /* We can't call domain_list() as this function is called from
+          init_domain_list() and we'll get stuck in a loop. */
+
+       for (domain = _domain_list; domain; domain = domain->next) {
                if (strcmp(domain_name, domain->name) == 0) {
                        DEBUG(3, ("domain %s already in domain list\n", 
                                  domain_name));
@@ -117,14 +106,14 @@ static struct winbindd_domain *add_trusted_domain(char *domain_name,
 
        /* Link to domain list */
         
-       DLIST_ADD(domain_list, domain);
+       DLIST_ADD(_domain_list, domain);
         
        return domain;
 }
 
 /* Look up global info for the winbind daemon */
 
-BOOL get_domain_info(void)
+BOOL init_domain_list(void)
 {
        NTSTATUS result;
        TALLOC_CTX *mem_ctx;
@@ -134,13 +123,20 @@ BOOL get_domain_info(void)
        char **names;
        int num_domains = 0;
 
-       if (!(mem_ctx = talloc_init_named("get_domain_info")))
+       if (!(mem_ctx = talloc_init_named("init_domain_list")))
                return False;
 
+       /* Free existing list */
+
+       free_domain_list();
+
+       /* Add ourselves as the first entry */
+
        domain = add_trusted_domain(lp_workgroup(), &cache_methods);
 
-       /* now we *must* get the domain sid for our primary domain. Go into a holding
-          pattern until that is available */
+       /* Now we *must* get the domain sid for our primary domain. Go into
+          a holding pattern until that is available */
+
        result = cache_methods.domain_sid(domain, &domain->sid);
        while (!NT_STATUS_IS_OK(result)) {
                sleep(10);
@@ -179,10 +175,49 @@ BOOL get_domain_info(void)
        return True;
 }
 
+/* Given a domain name, return the struct winbindd domain info for it 
+   if it is actually working. */
+
+struct winbindd_domain *find_domain_from_name(char *domain_name)
+{
+       struct winbindd_domain *domain;
+
+       /* Search through list */
+
+       for (domain = domain_list(); domain != NULL; domain = domain->next) {
+               if (strequal(domain_name, domain->name) ||
+                   strequal(domain_name, domain->full_name))
+                       return domain;
+       }
+
+       /* Not found */
+
+       return NULL;
+}
+
+/* Given a domain sid, return the struct winbindd domain info for it */
+
+struct winbindd_domain *find_domain_from_sid(DOM_SID *sid)
+{
+       struct winbindd_domain *domain;
+
+       /* Search through list */
+
+       for (domain = domain_list(); domain != NULL; domain = domain->next) {
+               if (sid_compare_domain(sid, &domain->sid) == 0)
+                       return domain;
+       }
+
+       /* Not found */
+
+       return NULL;
+}
 
 /* Lookup a sid in a domain from a name */
+
 BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, 
-                                const char *name, DOM_SID *sid, enum SID_NAME_USE *type)
+                                const char *name, DOM_SID *sid, 
+                                enum SID_NAME_USE *type)
 {
        NTSTATUS result;
         
@@ -282,19 +317,19 @@ void free_getent_state(struct getent_state *state)
 
 BOOL winbindd_param_init(void)
 {
-    /* Parse winbind uid and winbind_gid parameters */
-
-    if (!lp_winbind_uid(&server_state.uid_low, &server_state.uid_high)) {
-            DEBUG(0, ("winbind uid range missing or invalid\n"));
-            return False;
-    }
-
-    if (!lp_winbind_gid(&server_state.gid_low, &server_state.gid_high)) {
-            DEBUG(0, ("winbind gid range missing or invalid\n"));
-            return False;
-    }
-    
-    return True;
+       /* Parse winbind uid and winbind_gid parameters */
+
+       if (!lp_winbind_uid(&server_state.uid_low, &server_state.uid_high)) {
+               DEBUG(0, ("winbind uid range missing or invalid\n"));
+               return False;
+       }
+       
+       if (!lp_winbind_gid(&server_state.gid_low, &server_state.gid_high)) {
+               DEBUG(0, ("winbind gid range missing or invalid\n"));
+               return False;
+       }
+       
+       return True;
 }
 
 /* Check if a domain is present in a comma-separated list of domains */