From da84e2a7568eac084ad04793d60523c63ec664c3 Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Fri, 11 Jan 2002 05:33:45 +0000 Subject: Always query the PDC for the list of trusted domains rather than interating 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 | 6 +- source3/nsswitch/winbindd.h | 43 ++++++----- source3/nsswitch/winbindd_group.c | 51 +++++++++----- source3/nsswitch/winbindd_misc.c | 9 ++- source3/nsswitch/winbindd_proto.h | 7 +- source3/nsswitch/winbindd_user.c | 32 +++++---- source3/nsswitch/winbindd_util.c | 145 +++++++++++++++++++++++--------------- 7 files changed, 179 insertions(+), 114 deletions(-) (limited to 'source3') diff --git a/source3/nsswitch/winbindd.c b/source3/nsswitch/winbindd.c index 01cd0eb55d..bd995611cd 100644 --- a/source3/nsswitch/winbindd.c +++ b/source3/nsswitch/winbindd.c @@ -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); diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index 74206da9ef..a8b9980be3 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -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 { diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index ff15611fba..cd4254acfc 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -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); diff --git a/source3/nsswitch/winbindd_misc.c b/source3/nsswitch/winbindd_misc.c index d820bb35dc..883f9a4e22 100644 --- a/source3/nsswitch/winbindd_misc.c +++ b/source3/nsswitch/winbindd_misc.c @@ -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 */ diff --git a/source3/nsswitch/winbindd_proto.h b/source3/nsswitch/winbindd_proto.h index fa5fec1b48..bfadcc9a6c 100644 --- a/source3/nsswitch/winbindd_proto.h +++ b/source3/nsswitch/winbindd_proto.h @@ -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); diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index b5f9436de5..e5cacbb989 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -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; diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index 3086795a49..f90e89c23f 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/nsswitch/winbindd_util.c @@ -36,53 +36,39 @@ * * Correct code should never look at a field that has this value. **/ + static const fstring name_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 */ -- cgit