From 16ceec46d6e6d908314e12ac0586c49b37a95256 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 21 Nov 2001 09:59:15 +0000 Subject: Added transparent +ve caching for lookupname/lookupsid. -ve caching can be easily added (a one liner) once we know the correct error codes returned by a W2K DC. All other winbindd calls should go through a similar transparent caching layer (and will soon). Jeremy. (This used to be commit b16bb21d371772816a4331f5011c151be0e083d5) --- source3/nsswitch/winbindd.h | 2 +- source3/nsswitch/winbindd_user.c | 12 +- source3/nsswitch/winbindd_util.c | 336 +++++++++++++++++++++++++++------------ 3 files changed, 238 insertions(+), 112 deletions(-) diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index a9035ca200..1380d5cc88 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -82,7 +82,7 @@ extern struct winbindd_state server_state; /* Server information */ struct winbindd_domain { fstring name; /* Domain name */ DOM_SID sid; /* SID for this domain */ - struct winbindd_domain *prev, *next; /* Linked list info */ + struct winbindd_domain *prev, *next; /* Linked list info */ }; extern struct winbindd_domain *domain_list; /* List of domains we know */ diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index 8dc3e82f42..85abe9b587 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -98,8 +98,8 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state DOM_SID user_sid; fstring name_domain, name_user, name, gecos_name; enum SID_NAME_USE name_type; - struct winbindd_domain *domain; - TALLOC_CTX *mem_ctx; + struct winbindd_domain *domain; + TALLOC_CTX *mem_ctx; DEBUG(3, ("[%5d]: getpwnam %s\n", state->pid, state->request.data.username)); @@ -115,10 +115,10 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state if (strequal(name_domain, "")) return WINBINDD_ERROR; - if ((domain = find_domain_from_name(name_domain)) == NULL) { - DEBUG(5, ("No such domain: %s\n", name_domain)); - return WINBINDD_ERROR; - } + if ((domain = find_domain_from_name(name_domain)) == NULL) { + DEBUG(5, ("No such domain: %s\n", name_domain)); + return WINBINDD_ERROR; + } /* Check for cached user entry */ diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index 65012e0f1c..90292ec2d2 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/nsswitch/winbindd_util.c @@ -24,6 +24,53 @@ #include "winbindd.h" #include "sids.h" +/* Globals for domain list stuff */ + +struct winbindd_domain *domain_list = NULL; + +/* 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 *tmp; + + if (domain_list == NULL) + get_domain_info(); + + /* Search through list */ + + for (tmp = domain_list; tmp != NULL; tmp = tmp->next) { + if (strcmp(domain_name, tmp->name) == 0) + return tmp; + } + + /* Not found */ + + return NULL; +} + +/* Given a domain name, return the struct winbindd domain info for it */ + +struct winbindd_domain *find_domain_from_sid(DOM_SID *sid) +{ + struct winbindd_domain *tmp; + + if (domain_list == NULL) + get_domain_info(); + + /* Search through list */ + + for (tmp = domain_list; tmp != NULL; tmp = tmp->next) { + if (sid_equal(sid, &tmp->sid)) + return tmp; + } + + /* Not found */ + + return NULL; +} + /* Add a trusted domain to our list of domains */ static struct winbindd_domain *add_trusted_domain(char *domain_name, @@ -205,57 +252,171 @@ BOOL lookup_domain_sid(char *domain_name, struct winbindd_domain *domain) return rv; } +/* Store a SID in a domain indexed by name in the cache. */ + +static void store_sid_by_name_in_cache(fstring name, DOM_SID *sid, enum SID_NAME_USE type) +{ + fstring domain_str; + char *p; + struct winbindd_sid sid_val; + struct winbindd_domain *domain; + + /* Get name from domain. */ + fstrcpy( domain_str, name); + p = strchr(domain_str, '\\'); + if (p) + *p = '\0'; + + if ((domain = find_domain_from_name(domain_str)) == NULL) + return; + + sid_to_string(sid_val.sid, sid); + sid_val.type = (int)type; + + winbindd_store_sid_cache_entry(domain, name, &sid_val); +} + +/* Lookup a SID in a domain indexed by name in the cache. */ + +static BOOL winbindd_lookup_sid_by_name_in_cache(fstring name, DOM_SID *sid, enum SID_NAME_USE *type) +{ + fstring domain_str; + char *p; + struct winbindd_sid sid_ret; + struct winbindd_domain *domain; + + /* Get name from domain. */ + fstrcpy( domain_str, name); + p = strchr(domain_str, '\\'); + if (p) + *p = '\0'; + + if ((domain = find_domain_from_name(domain_str)) == NULL) + return False; + + if (winbindd_fetch_sid_cache_entry(domain, name, &sid_ret)) + return False; + + string_to_sid( sid, sid_ret.sid); + *type = (enum SID_NAME_USE)sid_ret.type; + + return True; +} + /* Lookup a sid in a domain from a name */ BOOL winbindd_lookup_sid_by_name(char *name, DOM_SID *sid, enum SID_NAME_USE *type) { - int num_sids = 0, num_names = 1; - DOM_SID *sids = NULL; - uint32 *types = NULL; - CLI_POLICY_HND *hnd; - NTSTATUS result; - TALLOC_CTX *mem_ctx; - BOOL rv = False; + int num_sids = 0, num_names = 1; + DOM_SID *sids = NULL; + uint32 *types = NULL; + CLI_POLICY_HND *hnd; + NTSTATUS result; + TALLOC_CTX *mem_ctx; + BOOL rv = False; - /* Don't bother with machine accounts */ + /* Don't bother with machine accounts */ - if (name[strlen(name) - 1] == '$') - return False; + if (name[strlen(name) - 1] == '$') + return False; + + /* First check cache. */ + if (winbindd_lookup_sid_by_name_in_cache(name, sid, type)) { + if (*type == SID_NAME_USE_NONE) + return False; /* Negative cache hit. */ + return True; + } - /* Lookup name */ + /* Lookup name */ - if (!(mem_ctx = talloc_init())) - return False; + if (!(mem_ctx = talloc_init())) + return False; - if (!(hnd = cm_get_lsa_handle(lp_workgroup()))) - goto done; + if (!(hnd = cm_get_lsa_handle(lp_workgroup()))) + goto done; - result = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, - num_names, (char **)&name, &sids, - &types, &num_sids); + result = cli_lsa_lookup_names(hnd->cli, mem_ctx, &hnd->pol, + num_names, (char **)&name, &sids, + &types, &num_sids); - /* Return rid and type if lookup successful */ + /* Return rid and type if lookup successful */ - if (NT_STATUS_IS_OK(result)) { + if (NT_STATUS_IS_OK(result)) { - /* Return sid */ + /* Return sid */ - if ((sid != NULL) && (sids != NULL)) - sid_copy(sid, &sids[0]); + if ((sid != NULL) && (sids != NULL)) + sid_copy(sid, &sids[0]); - /* Return name type */ + /* Return name type */ - if ((type != NULL) && (types != NULL)) - *type = types[0]; - } + if ((type != NULL) && (types != NULL)) + *type = types[0]; - rv = NT_STATUS_IS_OK(result); + store_sid_by_name_in_cache(name, &sids[0], types[0]); + } + /* JRA. Here's where we add the -ve cache store with a name type of SID_NAME_USE_NONE. */ + /* We need to know the error returns that W2K gives on "no such user". */ + + rv = NT_STATUS_IS_OK(result); done: - talloc_destroy(mem_ctx); + talloc_destroy(mem_ctx); - return rv; + return rv; +} + +/* Store a name in a domain indexed by SID in the cache. */ + +static void store_name_by_sid_in_cache(DOM_SID *sid, fstring name, enum SID_NAME_USE type) +{ + fstring sid_str; + uint32 rid; + DOM_SID domain_sid; + struct winbindd_name name_val; + struct winbindd_domain *domain; + + /* Split sid into domain sid and user rid */ + sid_copy(&domain_sid, sid); + sid_split_rid(&domain_sid, &rid); + + if ((domain = find_domain_from_sid(&domain_sid)) == NULL) + return; + + sid_to_string(sid_str, sid); + fstrcpy( name_val.name, name ); + name_val.type = (int)type; + + winbindd_store_name_cache_entry(domain, sid_str, &name_val); +} + +/* Lookup a name in a domain indexed by SID in the cache. */ + +static BOOL winbindd_lookup_name_by_sid_in_cache(DOM_SID *sid, fstring name, enum SID_NAME_USE *type) +{ + fstring sid_str; + uint32 rid; + DOM_SID domain_sid; + struct winbindd_name name_ret; + struct winbindd_domain *domain; + + /* Split sid into domain sid and user rid */ + sid_copy(&domain_sid, sid); + sid_split_rid(&domain_sid, &rid); + + if ((domain = find_domain_from_sid(&domain_sid)) == NULL) + return False; + + sid_to_string(sid_str, sid); + + if (winbindd_fetch_name_cache_entry(domain, sid_str, &name_ret)) + return False; + + fstrcpy( name, name_ret.name ); + *type = (enum SID_NAME_USE)name_ret.type; + + return True; } /* Lookup a name in a domain from a sid */ @@ -263,47 +424,59 @@ BOOL winbindd_lookup_sid_by_name(char *name, DOM_SID *sid, BOOL winbindd_lookup_name_by_sid(DOM_SID *sid, fstring name, enum SID_NAME_USE *type) { - int num_sids = 1, num_names = 0; - uint32 *types = NULL; - char **names; - CLI_POLICY_HND *hnd; - NTSTATUS result; - TALLOC_CTX *mem_ctx; - BOOL rv = False; - - /* Lookup name */ + int num_sids = 1, num_names = 0; + uint32 *types = NULL; + char **names; + CLI_POLICY_HND *hnd; + NTSTATUS result; + TALLOC_CTX *mem_ctx; + BOOL rv = False; + + /* First check cache. */ + if (winbindd_lookup_name_by_sid_in_cache(sid, name, type)) { + if (*type == SID_NAME_USE_NONE) + return False; /* Negative cache hit. */ + return True; + } - if (!(mem_ctx = talloc_init())) - return False; + /* Lookup name */ + + if (!(mem_ctx = talloc_init())) + return False; - if (!(hnd = cm_get_lsa_handle(lp_workgroup()))) - goto done; + if (!(hnd = cm_get_lsa_handle(lp_workgroup()))) + goto done; - result = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol, - num_sids, sid, &names, &types, - &num_names); + result = cli_lsa_lookup_sids(hnd->cli, mem_ctx, &hnd->pol, + num_sids, sid, &names, &types, + &num_names); - /* Return name and type if successful */ + /* Return name and type if successful */ - if (NT_STATUS_IS_OK(result)) { + if (NT_STATUS_IS_OK(result)) { - /* Return name */ + /* Return name */ - if ((names != NULL) && (name != NULL)) - fstrcpy(name, names[0]); + if ((names != NULL) && (name != NULL)) + fstrcpy(name, names[0]); - /* Return name type */ + /* Return name type */ - if ((type != NULL) && (types != NULL)) - *type = types[0]; - } + if ((type != NULL) && (types != NULL)) + *type = types[0]; + + store_name_by_sid_in_cache(sid, names[0], types[0]); + } + /* JRA. Here's where we add the -ve cache store with a name type of SID_NAME_USE_NONE. */ + /* We need to know the error returns that W2K gives on "no such user". */ - rv = NT_STATUS_IS_OK(result); + rv = NT_STATUS_IS_OK(result); done: - talloc_destroy(mem_ctx); - return rv; + talloc_destroy(mem_ctx); + + return rv; } /* Lookup user information from a rid */ @@ -523,53 +696,6 @@ BOOL winbindd_lookup_groupmem(struct winbindd_domain *domain, return NT_STATUS_IS_OK(result); } -/* Globals for domain list stuff */ - -struct winbindd_domain *domain_list = NULL; - -/* 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 *tmp; - - if (domain_list == NULL) - get_domain_info(); - - /* Search through list */ - - for (tmp = domain_list; tmp != NULL; tmp = tmp->next) { - if (strcmp(domain_name, tmp->name) == 0) - return tmp; - } - - /* Not found */ - - return NULL; -} - -/* Given a domain name, return the struct winbindd domain info for it */ - -struct winbindd_domain *find_domain_from_sid(DOM_SID *sid) -{ - struct winbindd_domain *tmp; - - if (domain_list == NULL) - get_domain_info(); - - /* Search through list */ - - for (tmp = domain_list; tmp != NULL; tmp = tmp->next) { - if (sid_equal(sid, &tmp->sid)) - return tmp; - } - - /* Not found */ - - return NULL; -} - /* Free state information held for {set,get,end}{pw,gr}ent() functions */ void free_getent_state(struct getent_state *state) -- cgit