1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-26 10:04:02 +03:00

Added negative caching to group lookups.

Jeremy.
This commit is contained in:
Jeremy Allison -
parent 17e2f38973
commit fceba7dea5
2 changed files with 87 additions and 48 deletions

View File

@ -1,10 +1,11 @@
/*
Unix SMB/Netbios implementation.
Version 2.0
Version 2.2.
Winbind daemon for ntdom nss module
Copyright (C) Tim Potter 2000
Copyright (C) Jeremy Allison 2001.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -23,6 +24,12 @@
#include "winbindd.h"
/***************************************************************
Empty static struct for negative caching.
****************************************************************/
static struct winbindd_gr negative_gr_cache_entry;
/* Fill a grent structure from various other information */
static BOOL fill_grent(struct winbindd_gr *gr, char *gr_name,
@ -52,10 +59,10 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
int buf_len, buf_ndx, i;
char **names = NULL, *buf;
BOOL result = False;
TALLOC_CTX *mem_ctx;
TALLOC_CTX *mem_ctx;
if (!(mem_ctx = talloc_init()))
return False;
if (!(mem_ctx = talloc_init()))
return False;
/* Initialise group membership information */
@ -174,6 +181,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain,
result = True;
done:
talloc_destroy(mem_ctx);
DEBUG(10, ("fill_grent_mem(): returning %d\n", result));
@ -183,8 +191,7 @@ done:
/* Return a group structure from a group name */
enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state
*state)
enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state *state)
{
DOM_SID group_sid;
struct winbindd_domain *domain;
@ -225,6 +232,13 @@ enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state
&state->response.data.gr,
&state->response.extra_data,
&extra_data_len)) {
/* Check if this is a negative cache entry. */
if (memcmp(&negative_gr_cache_entry, &state->response.data.gr,
sizeof(state->response.data.gr)) == 0)
return WINBINDD_ERROR;
state->response.length += extra_data_len;
return WINBINDD_OK;
}
@ -236,12 +250,20 @@ enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state
if (!winbindd_lookup_sid_by_name(name, &group_sid, &name_type)) {
DEBUG(1, ("group %s in domain %s does not exist\n",
name_group, name_domain));
winbindd_store_group_cache_entry(domain, name_group,
&negative_gr_cache_entry, NULL, 0);
return WINBINDD_ERROR;
}
if ((name_type != SID_NAME_ALIAS) && (name_type != SID_NAME_DOM_GRP)) {
DEBUG(1, ("from_group: name '%s' is not a local or domain "
"group: %d\n", name_group, name_type));
winbindd_store_group_cache_entry(domain, name_group,
&negative_gr_cache_entry, NULL, 0);
return WINBINDD_ERROR;
}
@ -251,6 +273,10 @@ enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state
if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) {
DEBUG(1, ("error sursing unix gid for sid\n"));
winbindd_store_group_cache_entry(domain, name_group,
&negative_gr_cache_entry, NULL, 0);
return WINBINDD_ERROR;
}
@ -258,8 +284,13 @@ enum winbindd_result winbindd_getgrnam_from_group(struct winbindd_cli_state
state->request.data.groupname, gid) ||
!fill_grent_mem(domain, group_rid, name_type,
&state->response.data.gr.num_gr_mem,
&gr_mem, &gr_mem_len))
&gr_mem, &gr_mem_len)) {
winbindd_store_group_cache_entry(domain, name_group,
&negative_gr_cache_entry, NULL, 0);
return WINBINDD_ERROR;
}
/* Group membership lives at start of extra data */
@ -316,6 +347,13 @@ enum winbindd_result winbindd_getgrnam_from_gid(struct winbindd_cli_state
&state->response.data.gr,
&state->response.extra_data,
&extra_data_len)) {
/* Check if this is a negative cache entry. */
if (memcmp(&negative_gr_cache_entry, &state->response.data.gr,
sizeof(state->response.data.gr)) == 0)
return WINBINDD_ERROR;
state->response.length += extra_data_len;
return WINBINDD_OK;
}
@ -448,8 +486,8 @@ static BOOL get_sam_group_entries(struct getent_state *ent)
NTSTATUS status;
uint32 num_entries;
struct acct_info *name_list = NULL, *tnl;
TALLOC_CTX *mem_ctx;
BOOL result = False;
TALLOC_CTX *mem_ctx;
BOOL result = False;
if (ent->got_all_sam_entries)
return False;
@ -461,8 +499,8 @@ static BOOL get_sam_group_entries(struct getent_state *ent)
return True;
#endif
if (!(mem_ctx = talloc_init()))
return False;
if (!(mem_ctx = talloc_init()))
return False;
/* Free any existing group info */
@ -473,29 +511,28 @@ static BOOL get_sam_group_entries(struct getent_state *ent)
do {
struct acct_info *sam_grp_entries = NULL;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
CLI_POLICY_HND *hnd;
POLICY_HND dom_pol;
uint32 des_access = SEC_RIGHTS_MAXIMUM_ALLOWED;
CLI_POLICY_HND *hnd;
POLICY_HND dom_pol;
num_entries = 0;
if (!(hnd = cm_get_sam_handle(ent->domain->name)))
break;
if (!(hnd = cm_get_sam_handle(ent->domain->name)))
break;
status = cli_samr_open_domain(hnd->cli, mem_ctx,
&hnd->pol, des_access,
&ent->domain->sid, &dom_pol);
status = cli_samr_open_domain(hnd->cli, mem_ctx,
&hnd->pol, des_access, &ent->domain->sid, &dom_pol);
if (!NT_STATUS_IS_OK(status))
break;
if (!NT_STATUS_IS_OK(status))
break;
status = cli_samr_enum_dom_groups(
hnd->cli, mem_ctx, &dom_pol,
&ent->grp_query_start_ndx,
0x8000, /* buffer size? */
(struct acct_info **) &sam_grp_entries, &num_entries);
status = cli_samr_enum_dom_groups(
hnd->cli, mem_ctx, &dom_pol,
&ent->grp_query_start_ndx,
0x8000, /* buffer size? */
(struct acct_info **) &sam_grp_entries, &num_entries);
cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
cli_samr_close(hnd->cli, mem_ctx, &dom_pol);
/* Copy entries into return buffer */
@ -544,9 +581,10 @@ static BOOL get_sam_group_entries(struct getent_state *ent)
result = (ent->num_sam_entries > 0);
done:
talloc_destroy(mem_ctx);
return result;
talloc_destroy(mem_ctx);
return result;
}
/* Fetch next group entry from ntdom database */
@ -748,6 +786,7 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
/* Out of domains */
done:
return (group_list_ndx > 0) ? WINBINDD_OK : WINBINDD_ERROR;
}
@ -755,9 +794,9 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state)
enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
{
uint32 total_entries = 0;
uint32 total_entries = 0;
uint32 num_domain_entries;
struct winbindd_domain *domain;
struct winbindd_domain *domain;
struct getent_state groups;
char *extra_data = NULL;
char *ted = NULL;
@ -766,14 +805,14 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
DEBUG(3, ("[%5d]: list groups\n", state->pid));
/* Enumerate over trusted domains */
/* Enumerate over trusted domains */
ZERO_STRUCT(groups);
if (domain_list == NULL)
get_domain_info();
if (domain_list == NULL)
get_domain_info();
for (domain = domain_list; domain; domain = domain->next) {
for (domain = domain_list; domain; domain = domain->next) {
/* Skip domains other than WINBINDD_DOMAIN environment
variable */
@ -880,7 +919,7 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state)
/* No domains may have responded but that's still OK so don't
return an error. */
return WINBINDD_OK;
return WINBINDD_OK;
}
/* Get user supplementary groups. This is much quicker than trying to
@ -897,13 +936,13 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
enum winbindd_result result = WINBINDD_ERROR;
gid_t *gid_list;
int i;
TALLOC_CTX *mem_ctx;
TALLOC_CTX *mem_ctx;
DEBUG(3, ("[%5d]: getgroups %s\n", state->pid,
state->request.data.username));
if (!(mem_ctx = talloc_init()))
return WINBINDD_ERROR;
if (!(mem_ctx = talloc_init()))
return WINBINDD_ERROR;
/* Parse domain and username */
@ -930,29 +969,28 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
if (!winbindd_lookup_sid_by_name(name, &user_sid, &name_type)) {
DEBUG(1, ("user '%s' does not exist\n", name_user));
goto done;
goto done;
}
if (name_type != SID_NAME_USER) {
DEBUG(1, ("name '%s' is not a user name: %d\n", name_user,
name_type));
goto done;
goto done;
}
sid_split_rid(&user_sid, &user_rid);
if (!winbindd_lookup_usergroups(domain, mem_ctx, user_rid,
&num_groups, &user_groups))
goto done;
goto done;
/* Copy data back to client */
num_gids = 0;
gid_list = malloc(sizeof(gid_t) * num_groups);
if (state->response.extra_data) {
if (state->response.extra_data)
goto done;
}
for (i = 0; i < num_groups; i++) {
if (!winbindd_idmap_get_gid_from_rid(
@ -974,7 +1012,8 @@ enum winbindd_result winbindd_getgroups(struct winbindd_cli_state *state)
result = WINBINDD_OK;
done:
talloc_destroy(mem_ctx);
talloc_destroy(mem_ctx);
return result;
}

View File

@ -1,10 +1,11 @@
/*
Unix SMB/Netbios implementation.
Version 2.0
Version 2.2
Winbind daemon - user related functions
Copyright (C) Tim Potter 2000
Copyright (C) Jeremy Allison 2001.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -96,8 +97,7 @@ static struct winbindd_pw negative_pw_cache_entry;
/* Return a password structure from a username. Specify whether cached data
can be returned. */
enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state
*state)
enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *state)
{
uint32 user_rid, group_rid;
SAM_USERINFO_CTR *user_info;