From 120c09b125f656d6d03b979560f3ef6652217691 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 26 Jun 2008 14:02:39 -0700 Subject: From Steve Danneman @ Isilon. Attached is the companion patch to (037b9689d9042a398cb91e4628a82fcdfa913c21), which made handling of WINBINDD_LIST_GROUPS asynchronous. Because most all of the list_groups code was reusable, I abstracted it, and implemented both list_groups and list_users on top of it. On my large test domain a "wbinfo -u" call went from 70 seconds to 30 seconds with this patch. Plus, the parent process is no longer blocked from receiving new requests during that time. Steven Danneman | Software Development Engineer Isilon Systems P +1-206-315-7500 F +1-206-315-7501 www.isilon.com (This used to be commit 5188f2861137ff06d5399561d55d7d00c3a08644) --- source3/winbindd/winbindd_misc.c | 123 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) (limited to 'source3/winbindd/winbindd_misc.c') diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c index 8933cf2794..01a4054d44 100644 --- a/source3/winbindd/winbindd_misc.c +++ b/source3/winbindd/winbindd_misc.c @@ -97,6 +97,129 @@ enum winbindd_result winbindd_dual_check_machine_acct(struct winbindd_domain *do return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; } +/* Helpers for listing user and group names */ + +const char *ent_type_strings[] = {"users", + "groups"}; + +static const char *get_ent_type_string(enum ent_type type) +{ + return ent_type_strings[type]; +} + +struct listent_state { + TALLOC_CTX *mem_ctx; + struct winbindd_cli_state *cli_state; + enum ent_type type; + int domain_count; + char *extra_data; + uint32_t extra_data_len; +}; + +static void listent_recv(void *private_data, bool success, fstring dom_name, + char *extra_data); + +/* List domain users/groups without mapping to unix ids */ +void winbindd_list_ent(struct winbindd_cli_state *state, enum ent_type type) +{ + struct winbindd_domain *domain; + const char *which_domain; + struct listent_state *ent_state; + + DEBUG(3, ("[%5lu]: list %s\n", (unsigned long)state->pid, + get_ent_type_string(type))); + + /* Ensure null termination */ + state->request.domain_name[sizeof(state->request.domain_name)-1]='\0'; + which_domain = state->request.domain_name; + + /* Initialize listent_state */ + ent_state = TALLOC_P(state->mem_ctx, struct listent_state); + if (ent_state == NULL) { + DEBUG(0, ("talloc failed\n")); + request_error(state); + return; + } + + ent_state->mem_ctx = state->mem_ctx; + ent_state->cli_state = state; + ent_state->type = type; + ent_state->domain_count = 0; + ent_state->extra_data = NULL; + ent_state->extra_data_len = 0; + + /* Must count the full list of expected domains before we request data + * from any of them. Otherwise it's possible for a connection to the + * first domain to fail, call listent_recv(), and return to the + * client without checking any other domains. */ + for (domain = domain_list(); domain; domain = domain->next) { + /* if we have a domain name restricting the request and this + one in the list doesn't match, then just bypass the remainder + of the loop */ + if ( *which_domain && !strequal(which_domain, domain->name) ) + continue; + + ent_state->domain_count++; + } + + /* Make sure we're enumerating at least one domain */ + if (!ent_state->domain_count) { + request_ok(state); + return; + } + + /* Enumerate list of trusted domains and request user/group list from + * each */ + for (domain = domain_list(); domain; domain = domain->next) { + if ( *which_domain && !strequal(which_domain, domain->name) ) + continue; + + winbindd_listent_async(state->mem_ctx, domain, + listent_recv, ent_state, type); + } +} + +static void listent_recv(void *private_data, bool success, fstring dom_name, + char *extra_data) +{ + /* extra_data comes to us as a '\0' terminated string of comma + separated users or groups */ + struct listent_state *state = talloc_get_type_abort( + private_data, struct listent_state); + + /* Append users/groups from one domain onto the whole list */ + if (extra_data) { + DEBUG(5, ("listent_recv: %s returned %s.\n", + dom_name, get_ent_type_string(state->type))); + if (!state->extra_data) + state->extra_data = talloc_asprintf(state->mem_ctx, + "%s", extra_data); + else + state->extra_data = talloc_asprintf_append( + state->extra_data, + ",%s", extra_data); + /* Add one for the '\0' and each additional ',' */ + state->extra_data_len += strlen(extra_data) + 1; + } + else { + DEBUG(5, ("listent_recv: %s returned no %s.\n", + dom_name, get_ent_type_string(state->type))); + } + + if (--state->domain_count) + /* Still waiting for some child domains to return */ + return; + + /* Return list of all users/groups to the client */ + if (state->extra_data) { + state->cli_state->response.extra_data.data = + SMB_STRDUP(state->extra_data); + state->cli_state->response.length += state->extra_data_len; + } + + request_ok(state->cli_state); +} + /* Constants and helper functions for determining domain trust types */ enum trust_type { -- cgit