From e2adbd456864e23724e83cd83f60269bcbb2fdaf Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 27 Nov 2001 20:57:14 +0000 Subject: Added negative caching to the user pw lookup by name and by uid. Jeremy. (This used to be commit 4013ae87a1c73ceba346de2a0b905e7c8df355c4) --- source3/nsswitch/winbindd_user.c | 133 ++++++++++++++++++-------------- source3/nsswitch/winbindd_util.c | 162 ++++++++++++++++++++------------------- 2 files changed, 159 insertions(+), 136 deletions(-) (limited to 'source3') diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index 5d317bdf94..61057cb1b3 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -27,7 +27,7 @@ static BOOL winbindd_fill_pwent(char *domain_name, char *name, uint32 user_rid, uint32 group_rid, - char *full_name, struct winbindd_pw *pw) + char *full_name, struct winbindd_pw *pw) { extern userdom_struct current_user_info; fstring name_domain, name_user; @@ -87,6 +87,12 @@ static BOOL winbindd_fill_pwent(char *domain_name, char *name, return True; } +/************************************************************************ + Empty static struct for negative caching. +*************************************************************************/ + +static struct winbindd_pw negative_pw_cache_entry; + /* Return a password structure from a username. Specify whether cached data can be returned. */ @@ -122,22 +128,28 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state /* Check for cached user entry */ - if (winbindd_fetch_user_cache_entry(domain, name_user, - &state->response.data.pw)) + if (winbindd_fetch_user_cache_entry(domain, name_user, &state->response.data.pw)) { + /* Check if this is a negative cache entry. */ + if (memcmp(&negative_pw_cache_entry, &state->response.data.pw, + sizeof(state->response.data.pw)) == 0) + return WINBINDD_ERROR; return WINBINDD_OK; - + } + slprintf(name, sizeof(name) - 1, "%s\\%s", name_domain, name_user); /* Get rid and name type from name */ if (!winbindd_lookup_sid_by_name(name, &user_sid, &name_type)) { DEBUG(1, ("user '%s' does not exist\n", name_user)); + winbindd_store_user_cache_entry(domain, name_user, &negative_pw_cache_entry); return WINBINDD_ERROR; } if (name_type != SID_NAME_USER) { DEBUG(1, ("name '%s' is not a user name: %d\n", name_user, name_type)); + winbindd_store_user_cache_entry(domain, name_user, &negative_pw_cache_entry); return WINBINDD_ERROR; } @@ -155,6 +167,7 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state if (!winbindd_lookup_userinfo(domain, mem_ctx, user_rid, &user_info)) { DEBUG(1, ("pwnam_from_user(): error getting user info for " "user '%s'\n", name_user)); + winbindd_store_user_cache_entry(domain, name_user, &negative_pw_cache_entry); return WINBINDD_ERROR; } @@ -171,19 +184,18 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state if (!winbindd_fill_pwent(name_domain, state->request.data.username, user_rid, group_rid, gecos_name, &state->response.data.pw)) { + winbindd_store_user_cache_entry(domain, name_user, &negative_pw_cache_entry); return WINBINDD_ERROR; } - winbindd_store_user_cache_entry(domain, name_user, - &state->response.data.pw); + winbindd_store_user_cache_entry(domain, name_user, &state->response.data.pw); return WINBINDD_OK; } /* Return a password structure given a uid number */ -enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state - *state) +enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state *state) { DOM_SID user_sid; struct winbindd_domain *domain; @@ -192,7 +204,7 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state enum SID_NAME_USE name_type; SAM_USERINFO_CTR *user_info; gid_t gid; - TALLOC_CTX *mem_ctx; + TALLOC_CTX *mem_ctx; /* Bug out if the uid isn't in the winbind range */ @@ -216,9 +228,14 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state if (winbindd_fetch_uid_cache_entry(domain, state->request.data.uid, - &state->response.data.pw)) + &state->response.data.pw)) { + /* Check if this is a negative cache entry. */ + if (memcmp(&negative_pw_cache_entry, &state->response.data.pw, + sizeof(state->response.data.pw)) == 0) + return WINBINDD_ERROR; return WINBINDD_OK; - + } + /* Get name and name type from rid */ sid_copy(&user_sid, &domain->sid); @@ -230,6 +247,7 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state sid_to_string(temp, &user_sid); DEBUG(1, ("Could not lookup sid %s\n", temp)); + winbindd_store_uid_cache_entry(domain, state->request.data.uid, &negative_pw_cache_entry); return WINBINDD_ERROR; } @@ -247,6 +265,7 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state if (!winbindd_lookup_userinfo(domain, mem_ctx, user_rid, &user_info)) { DEBUG(1, ("pwnam_from_uid(): error getting user info for " "user '%s'\n", user_name)); + winbindd_store_uid_cache_entry(domain, state->request.data.uid, &negative_pw_cache_entry); return WINBINDD_ERROR; } @@ -267,11 +286,12 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state /* Fill in password structure */ if (!winbindd_fill_pwent(domain->name, user_name, user_rid, group_rid, - gecos_name, &state->response.data.pw)) + gecos_name, &state->response.data.pw)) { + winbindd_store_uid_cache_entry(domain, state->request.data.uid, &negative_pw_cache_entry); return WINBINDD_ERROR; + } - winbindd_store_uid_cache_entry(domain, state->request.data.uid, - &state->response.data.pw); + winbindd_store_uid_cache_entry(domain, state->request.data.uid, &state->response.data.pw); return WINBINDD_OK; } @@ -284,65 +304,66 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state enum winbindd_result winbindd_setpwent(struct winbindd_cli_state *state) { - struct winbindd_domain *tmp; + struct winbindd_domain *tmp; - DEBUG(3, ("[%5d]: setpwent\n", state->pid)); + DEBUG(3, ("[%5d]: setpwent\n", state->pid)); - /* Check user has enabled this */ + /* Check user has enabled this */ - if (!lp_winbind_enum_users()) - return WINBINDD_ERROR; + if (!lp_winbind_enum_users()) + return WINBINDD_ERROR; - /* Free old static data if it exists */ + /* Free old static data if it exists */ - if (state->getpwent_state != NULL) { - free_getent_state(state->getpwent_state); - state->getpwent_state = NULL; - } + if (state->getpwent_state != NULL) { + free_getent_state(state->getpwent_state); + state->getpwent_state = NULL; + } - /* Create sam pipes for each domain we know about */ + /* Create sam pipes for each domain we know about */ - if (domain_list == NULL) - get_domain_info(); + if (domain_list == NULL) + get_domain_info(); - for(tmp = domain_list; tmp != NULL; tmp = tmp->next) { - struct getent_state *domain_state; + for(tmp = domain_list; tmp != NULL; tmp = tmp->next) { + struct getent_state *domain_state; - /* Skip domains other than WINBINDD_DOMAIN environment - variable */ + /* + * Skip domains other than WINBINDD_DOMAIN environment + * variable. + */ - if ((strcmp(state->request.domain, "") != 0) && - !check_domain_env(state->request.domain, tmp->name)) - continue; + if ((strcmp(state->request.domain, "") != 0) && + !check_domain_env(state->request.domain, tmp->name)) + continue; - /* Create a state record for this domain */ + /* Create a state record for this domain */ - if ((domain_state = (struct getent_state *) - malloc(sizeof(struct getent_state))) == NULL) - return WINBINDD_ERROR; + if ((domain_state = (struct getent_state *)malloc(sizeof(struct getent_state))) == NULL) + return WINBINDD_ERROR; - ZERO_STRUCTP(domain_state); + ZERO_STRUCTP(domain_state); - domain_state->domain = tmp; + domain_state->domain = tmp; - /* Add to list of open domains */ + /* Add to list of open domains */ - DLIST_ADD(state->getpwent_state, domain_state); - } + DLIST_ADD(state->getpwent_state, domain_state); + } - return WINBINDD_OK; + return WINBINDD_OK; } /* Close file pointer to ntdom passwd database */ enum winbindd_result winbindd_endpwent(struct winbindd_cli_state *state) { - DEBUG(3, ("[%5d]: endpwent\n", state->pid)); + DEBUG(3, ("[%5d]: endpwent\n", state->pid)); - free_getent_state(state->getpwent_state); - state->getpwent_state = NULL; + free_getent_state(state->getpwent_state); + state->getpwent_state = NULL; - return WINBINDD_OK; + return WINBINDD_OK; } /* Get partial list of domain users for a domain. We fill in the sam_entries, @@ -360,14 +381,14 @@ static BOOL get_sam_user_entries(struct getent_state *ent) SAM_DISPINFO_CTR ctr; struct getpwent_user *name_list = NULL; uint32 group_rid; - BOOL result = False; - TALLOC_CTX *mem_ctx; + BOOL result = False; + TALLOC_CTX *mem_ctx; if (ent->got_all_sam_entries) return False; - if (!(mem_ctx = talloc_init())) - return False; + if (!(mem_ctx = talloc_init())) + return False; ZERO_STRUCT(info1); ZERO_STRUCT(ctr); @@ -466,15 +487,15 @@ static BOOL get_sam_user_entries(struct getent_state *ent) ent->sam_entries = name_list; ent->sam_entry_index = 0; - ent->got_all_sam_entries = (NT_STATUS_V(status) != - NT_STATUS_V(STATUS_MORE_ENTRIES)); + ent->got_all_sam_entries = (NT_STATUS_V(status) != NT_STATUS_V(STATUS_MORE_ENTRIES)); result = ent->num_sam_entries > 0; done: - talloc_destroy(mem_ctx); - return result; + talloc_destroy(mem_ctx); + + return result; } /* Fetch next passwd entry from ntdom database */ diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index 033e5c38aa..777b3cdac2 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/nsswitch/winbindd_util.c @@ -534,53 +534,53 @@ BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32 user_rid, SAM_USERINFO_CTR **user_info) { - CLI_POLICY_HND *hnd; - uint16 info_level = 0x15; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; - POLICY_HND dom_pol, user_pol; - BOOL got_dom_pol = False, got_user_pol = False; + CLI_POLICY_HND *hnd; + uint16 info_level = 0x15; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; + POLICY_HND dom_pol, user_pol; + BOOL got_dom_pol = False, got_user_pol = False; - /* Get sam handle */ + /* Get sam handle */ - if (!(hnd = cm_get_sam_handle(domain->name))) - goto done; + if (!(hnd = cm_get_sam_handle(domain->name))) + goto done; - /* Get domain handle */ + /* Get domain handle */ - result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, - des_access, &domain->sid, &dom_pol); + result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, + des_access, &domain->sid, &dom_pol); - if (!NT_STATUS_IS_OK(result)) - goto done; + if (!NT_STATUS_IS_OK(result)) + goto done; - got_dom_pol = True; + got_dom_pol = True; - /* Get user handle */ + /* Get user handle */ - result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol, - des_access, user_rid, &user_pol); + result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol, + des_access, user_rid, &user_pol); - if (!NT_STATUS_IS_OK(result)) - goto done; + if (!NT_STATUS_IS_OK(result)) + goto done; - /* Get user info */ + /* Get user info */ - result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol, - info_level, user_info); + result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol, + info_level, user_info); - cli_samr_close(hnd->cli, mem_ctx, &user_pol); + cli_samr_close(hnd->cli, mem_ctx, &user_pol); done: - /* Clean up policy handles */ + /* Clean up policy handles */ - if (got_user_pol) - cli_samr_close(hnd->cli, mem_ctx, &user_pol); + if (got_user_pol) + cli_samr_close(hnd->cli, mem_ctx, &user_pol); - if (got_dom_pol) - cli_samr_close(hnd->cli, mem_ctx, &dom_pol); + if (got_dom_pol) + cli_samr_close(hnd->cli, mem_ctx, &dom_pol); - return NT_STATUS_IS_OK(result); + return NT_STATUS_IS_OK(result); } /* Lookup groups a user is a member of. I wish Unix had a call like this! */ @@ -592,50 +592,51 @@ BOOL winbindd_lookup_usergroups(struct winbindd_domain *domain, { CLI_POLICY_HND *hnd; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - POLICY_HND dom_pol, user_pol; - uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; - BOOL got_dom_pol = False, got_user_pol = False; + POLICY_HND dom_pol, user_pol; + uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; + BOOL got_dom_pol = False, got_user_pol = False; - /* Get sam handle */ + /* Get sam handle */ - if (!(hnd = cm_get_sam_handle(domain->name))) - goto done; + if (!(hnd = cm_get_sam_handle(domain->name))) + goto done; - /* Get domain handle */ + /* Get domain handle */ - result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, - des_access, &domain->sid, &dom_pol); + result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, + des_access, &domain->sid, &dom_pol); - if (!NT_STATUS_IS_OK(result)) - goto done; + if (!NT_STATUS_IS_OK(result)) + goto done; - got_dom_pol = True; + got_dom_pol = True; - /* Get user handle */ + /* Get user handle */ - result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol, - des_access, user_rid, &user_pol); + result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol, + des_access, user_rid, &user_pol); - if (!NT_STATUS_IS_OK(result)) - goto done; + if (!NT_STATUS_IS_OK(result)) + goto done; - got_user_pol = True; + got_user_pol = True; - /* Query user rids */ + /* Query user rids */ - result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol, - num_groups, user_groups); + result = cli_samr_query_usergroups(hnd->cli, mem_ctx, &user_pol, + num_groups, user_groups); done: - /* Clean up policy handles */ - if (got_user_pol) - cli_samr_close(hnd->cli, mem_ctx, &user_pol); + /* Clean up policy handles */ - if (got_dom_pol) - cli_samr_close(hnd->cli, mem_ctx, &dom_pol); + if (got_user_pol) + cli_samr_close(hnd->cli, mem_ctx, &user_pol); - return NT_STATUS_IS_OK(result); + if (got_dom_pol) + cli_samr_close(hnd->cli, mem_ctx, &dom_pol); + + return NT_STATUS_IS_OK(result); } /* Lookup group membership given a rid. */ @@ -792,38 +793,39 @@ NTSTATUS winbindd_query_dispinfo(struct winbindd_domain *domain, uint32 *start_ndx, uint16 info_level, uint32 *num_entries, SAM_DISPINFO_CTR *ctr) { - CLI_POLICY_HND *hnd; - NTSTATUS result = NT_STATUS_UNSUCCESSFUL; - POLICY_HND dom_pol; - BOOL got_dom_pol = False; - uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; + CLI_POLICY_HND *hnd; + NTSTATUS result = NT_STATUS_UNSUCCESSFUL; + POLICY_HND dom_pol; + BOOL got_dom_pol = False; + uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED; - /* Get sam handle */ + /* Get sam handle */ - if (!(hnd = cm_get_sam_handle(domain->name))) - goto done; + if (!(hnd = cm_get_sam_handle(domain->name))) + goto done; - /* Get domain handle */ + /* Get domain handle */ - result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, - des_access, &domain->sid, &dom_pol); + result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, + des_access, &domain->sid, &dom_pol); - if (!NT_STATUS_IS_OK(result)) - goto done; + if (!NT_STATUS_IS_OK(result)) + goto done; - got_dom_pol = True; + got_dom_pol = True; - /* Query display info */ + /* Query display info */ - result = cli_samr_query_dispinfo(hnd->cli, mem_ctx, - &dom_pol, start_ndx, info_level, - num_entries, 0xffff, ctr); + result = cli_samr_query_dispinfo(hnd->cli, mem_ctx, + &dom_pol, start_ndx, info_level, + num_entries, 0xffff, ctr); done: - if (got_dom_pol) - cli_samr_close(hnd->cli, mem_ctx, &dom_pol); - return result; + if (got_dom_pol) + cli_samr_close(hnd->cli, mem_ctx, &dom_pol); + + return result; } /* Check if a domain is present in a comma-separated list of domains */ @@ -849,12 +851,12 @@ void parse_domain_user(char *domuser, fstring domain, fstring user) char *sep = lp_winbind_separator(); if (!sep) - sep = "\\"; + sep = "\\"; p = strchr(domuser,*sep); if (!p) - p = strchr(domuser,'\\'); + p = strchr(domuser,'\\'); if (!p) { fstrcpy(domain,""); -- cgit