From fed660877c16562265327c6093ea645cf4176b5c Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Wed, 8 Jun 2005 22:10:34 +0000 Subject: r7415: * big change -- volker's new async winbindd from trunk (This used to be commit a0ac9a8ffd4af31a0ebc423b4acbb2f043d865b8) --- source3/nsswitch/winbindd_group.c | 591 ++++++++++++++------------------------ 1 file changed, 219 insertions(+), 372 deletions(-) (limited to 'source3/nsswitch/winbindd_group.c') diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index c431e32cc1..1138762cc4 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -61,7 +61,7 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, enum SID_NAME_USE group_name_type, int *num_gr_mem, char **gr_mem, int *gr_mem_len) { - DOM_SID **sid_mem = NULL; + DOM_SID *sid_mem = NULL; uint32 num_names = 0; uint32 *name_types = NULL; unsigned int buf_len, buf_ndx, i; @@ -112,7 +112,8 @@ static BOOL fill_grent_mem(struct winbindd_domain *domain, if (DEBUGLEVEL >= 10) { for (i = 0; i < num_names; i++) - DEBUG(10, ("\t%20s %s %d\n", names[i], sid_to_string(sid_string, sid_mem[i]), + DEBUG(10, ("\t%20s %s %d\n", names[i], + sid_string_static(&sid_mem[i]), name_types[i])); } @@ -222,7 +223,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) parse_domain_user(tmp, name_domain, name_group); - /* if no domain or our local domain, default to our local domain for aliases */ + /* if no domain or our local domain and no local tdb group, default to + * our local domain for aliases */ if ( !*name_domain || strequal(name_domain, get_global_sam_name()) ) { fstrcpy(name_domain, get_global_sam_name()); @@ -245,8 +247,8 @@ enum winbindd_result winbindd_getgrnam(struct winbindd_cli_state *state) /* Get rid and name type from name */ - if (!winbindd_lookup_sid_by_name(domain, domain->name, name_group, &group_sid, - &name_type)) { + if (!winbindd_lookup_sid_by_name(state->mem_ctx, domain, domain->name, + name_group, &group_sid, &name_type)) { DEBUG(1, ("group %s in domain %s does not exist\n", name_group, name_domain)); return WINBINDD_ERROR; @@ -306,7 +308,7 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state) return WINBINDD_ERROR; /* Get rid from gid */ - if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid))) { + if (!NT_STATUS_IS_OK(idmap_gid_to_sid(&group_sid, state->request.data.gid, 0))) { DEBUG(1, ("could not convert gid %lu to rid\n", (unsigned long)state->request.data.gid)); return WINBINDD_ERROR; @@ -314,14 +316,15 @@ enum winbindd_result winbindd_getgrgid(struct winbindd_cli_state *state) /* Get name from sid */ - if (!winbindd_lookup_name_by_sid(&group_sid, dom_name, group_name, &name_type)) { + if (!winbindd_lookup_name_by_sid(state->mem_ctx, &group_sid, dom_name, + group_name, &name_type)) { DEBUG(1, ("could not lookup sid\n")); return WINBINDD_ERROR; } /* Fill in group structure */ - domain = find_domain_from_sid(&group_sid); + domain = find_domain_from_sid_noinit(&group_sid); if (!domain) { DEBUG(1,("Can't find domain from sid\n")); @@ -793,10 +796,6 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) if ( *which_domain && !strequal(which_domain, domain->name) ) continue; - - if ( !domain->initialized ) - set_dc_type_and_flags( domain ); - ZERO_STRUCT(groups); @@ -856,323 +855,155 @@ enum winbindd_result winbindd_list_groups(struct winbindd_cli_state *state) return WINBINDD_OK; } -static BOOL enum_alias_memberships(const DOM_SID *member_sid, - DOM_SID **aliases, int *num_aliases) -{ - TALLOC_CTX *mem_ctx = talloc_init("enum_alias_memberships"); - - uint32 *rids = NULL; - int i, num_rids = 0; - - BOOL result = False; - - if (mem_ctx == NULL) - return False; - - *aliases = NULL; - *num_aliases = 0; - - if (!pdb_enum_alias_memberships(mem_ctx, get_global_sam_sid(), - member_sid, 1, &rids, &num_rids)) - goto done; - - for (i=0; irequest.data.username[sizeof(state->request.data.username)-1]='\0'; + state->request.data.username + [sizeof(state->request.data.username)-1]='\0'; DEBUG(3, ("[%5lu]: getgroups %s\n", (unsigned long)state->pid, state->request.data.username)); - if (!(mem_ctx = talloc_init("winbindd_getgroups(%s)", - state->request.data.username))) - return WINBINDD_ERROR; - /* Parse domain and username */ - parse_domain_user(state->request.data.username, - name_domain, name_user); - - /* Get info for the domain */ - - if ((domain = find_domain_from_name(name_domain)) == NULL) { - DEBUG(7, ("could not find domain entry for domain %s\n", - name_domain)); - goto done; + s = TALLOC_P(state->mem_ctx, struct getgroups_state); + if (s == NULL) { + DEBUG(0, ("talloc failed\n")); + return WINBINDD_ERROR; } - if ( domain->primary && lp_winbind_trusted_domains_only()) { - DEBUG(7,("winbindd_getgroups: My domain -- rejecting " - "getgroups() for %s\\%s.\n", name_domain, name_user)); + s->state = state; + + if (!parse_domain_user_talloc(state->mem_ctx, + state->request.data.username, + &s->domname, &s->username)) { + DEBUG(0, ("Could not parse domain user: %s\n", + state->request.data.username)); return WINBINDD_ERROR; - } + } - /* Get rid and name type from name. The following costs 1 packet */ + /* Get info for the domain */ - if (!winbindd_lookup_sid_by_name(domain, domain->name, name_user, &user_sid, - &name_type)) { - DEBUG(4, ("user '%s' does not exist\n", name_user)); - goto done; - } + s->domain = find_domain_from_name_noinit(s->domname); - if (name_type != SID_NAME_USER && name_type != SID_NAME_COMPUTER) { - DEBUG(1, ("name '%s' is not a user name: %d\n", - name_user, name_type)); - goto done; + if (s->domain == NULL) { + DEBUG(7, ("could not find domain entry for domain %s\n", + s->domname)); + return WINBINDD_ERROR; } - add_gids_from_user_sid(&user_sid, &gid_list, &num_gids); - - /* Treat the info3 cache as authoritative as the - lookup_usergroups() function may return cached data. */ - - if ( !opt_nocache && (info3 = netsamlogon_cache_get(mem_ctx, &user_sid))) { - - struct winbindd_domain *our_domain = find_our_domain(); - - if (our_domain == NULL) { - DEBUG(0, ("Could not find our domain\n")); - goto done; - } - - DEBUG(10, ("winbindd_getgroups: info3 has %d groups, %d other sids\n", - info3->num_groups2, info3->num_other_sids)); - - num_groups = info3->num_other_sids + info3->num_groups2; - - /* Go through each other sid and convert it to a gid */ - - for (i = 0; i < info3->num_other_sids; i++) { - DOM_SID *sid = &info3->other_sids[i].sid; - fstring name; - fstring dom_name; - enum SID_NAME_USE sid_type; - - /* Is this sid known to us? It can either be - a trusted domain sid or a foreign sid. */ - - if (!winbindd_lookup_name_by_sid( sid, dom_name, - name, &sid_type)) { - DEBUG(10, ("winbindd_getgroups: could not " - "lookup name for %s\n", - sid_string_static(sid))); - continue; - } - - /* Check it is a domain group or an alias (domain - local group) in a win2k native mode domain. */ - - if (!((sid_type==SID_NAME_DOM_GRP) || - ((sid_type==SID_NAME_ALIAS) && - (our_domain->active_directory) && - (our_domain->native_mode) && - (sid_compare_domain(sid, &our_domain->sid) - == 0)))) { - DEBUG(10, ("winbindd_getgroups: sid type %d " - "for %s is not a domain group\n", - sid_type, sid_string_static(sid))); - continue; - } - - add_gids_from_group_sid(sid, &gid_list, &num_gids); - } - - for (i = 0; i < info3->num_groups2; i++) { - - /* create the group SID */ - - sid_copy( &group_sid, &domain->sid ); - sid_append_rid( &group_sid, info3->gids[i].g_rid ); - - add_gids_from_group_sid(&group_sid, &gid_list, - &num_gids); - } + if ( s->domain->primary && lp_winbind_trusted_domains_only()) { + DEBUG(7,("winbindd_getpwnam: My domain -- rejecting " + "getgroups() for %s\\%s.\n", s->domname, + s->username)); + return WINBINDD_ERROR; + } - SAFE_FREE(info3); + /* Get rid and name type from name. The following costs 1 packet */ - } else { - status = domain->methods->lookup_usergroups(domain, mem_ctx, - &user_sid, &num_groups, - &user_grpsids); - if (!NT_STATUS_IS_OK(status)) - goto done; + winbindd_lookupname_async(state->mem_ctx, s->domname, s->username, + getgroups_usersid_recv, s); + return WINBINDD_PENDING; +} - if (state->response.extra_data) - goto done; +static void getgroups_usersid_recv(void *private, BOOL success, + const DOM_SID *sid, enum SID_NAME_USE type) +{ + struct getgroups_state *s = private; - for (i = 0; i < num_groups; i++) { - add_gids_from_group_sid(user_grpsids[i], - &gid_list, &num_gids); - } + if ((!success) || + ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER))) { + s->state->response.result = WINBINDD_ERROR; + request_finished(s->state); + return; } - /* We want at least one group... */ - if (gid_list == NULL) - goto done; - - remove_duplicate_gids( &num_gids, gid_list ); - - /* Send data back to client */ + sid_copy(&s->user_sid, sid); - state->response.data.num_entries = num_gids; - state->response.extra_data = gid_list; - state->response.length += num_gids * sizeof(gid_t); - - result = WINBINDD_OK; - - done: - - talloc_destroy(mem_ctx); - - return result; + winbindd_gettoken_async(s->state->mem_ctx, &s->user_sid, + getgroups_tokensids_recv, s); } -static void add_sid_to_parray_unique(TALLOC_CTX *mem_ctx, const DOM_SID *sid, - DOM_SID ***sids, int *num_sids) +static void getgroups_tokensids_recv(void *private, BOOL success, + DOM_SID *token_sids, int num_token_sids) { - int i; + struct getgroups_state *s = private; - for (i=0; i<(*num_sids); i++) { - if (sid_compare(sid, (*sids)[i]) == 0) - return; + /* We need at least the user sid and the primary group in the token, + * otherwise it's an error */ + + if ((!success) || (num_token_sids < 2)) { + s->state->response.result = WINBINDD_ERROR; + request_finished(s->state); + return; } - *sids = TALLOC_REALLOC_ARRAY(mem_ctx, *sids, DOM_SID *, *num_sids+1); + s->token_sids = token_sids; + s->num_token_sids = num_token_sids; + s->i = 0; - if (*sids == NULL) - return; + s->token_gids = NULL; + s->num_token_gids = 0; - (*sids)[*num_sids] = TALLOC_P(mem_ctx, DOM_SID); - sid_copy((*sids)[*num_sids], sid); - *num_sids += 1; - return; + getgroups_sid2gid_recv(s, False, 0); } -static void add_local_sids_from_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, - DOM_SID ***user_grpsids, - int *num_groups) +static void getgroups_sid2gid_recv(void *private, BOOL success, gid_t gid) { - DOM_SID *aliases = NULL; - int i, num_aliases = 0; + struct getgroups_state *s = private; - if (!enum_alias_memberships(sid, &aliases, &num_aliases)) - return; + if (success) + add_gid_to_array_unique(NULL, gid, + &s->token_gids, + &s->num_token_gids); - if (num_aliases == 0) - return; + if (s->i < s->num_token_sids) { + const DOM_SID *sid = &s->token_sids[s->i]; + s->i += 1; - for (i=0; iuser_sid)) { + getgroups_sid2gid_recv(s, False, 0); + return; + } - SAFE_FREE(aliases); + winbindd_sid2gid_async(s->state->mem_ctx, sid, + getgroups_sid2gid_recv, s); + return; + } - return; + s->state->response.data.num_entries = s->num_token_gids; + s->state->response.extra_data = s->token_gids; + s->state->response.length += s->num_token_gids * sizeof(gid_t); + s->state->response.result = WINBINDD_OK; + request_finished(s->state); } /* Get user supplementary sids. This is equivalent to the @@ -1186,106 +1017,50 @@ static void add_local_sids_from_sid(TALLOC_CTX *mem_ctx, const DOM_SID *sid, you pass in another type of SID then you may get unpredictable results. */ + +static void getusersids_recv(void *private, BOOL success, DOM_SID *sids, + int num_sids); + enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state) { - DOM_SID user_sid; - NTSTATUS status; - DOM_SID **user_grpsids; - struct winbindd_domain *domain; - enum winbindd_result result = WINBINDD_ERROR; - unsigned int i; - TALLOC_CTX *mem_ctx; - char *ret = NULL; - uint32 num_groups; - unsigned ofs, ret_size = 0; + DOM_SID *user_sid; /* Ensure null termination */ state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; - if (!string_to_sid(&user_sid, state->request.data.sid)) { - DEBUG(1, ("Could not get convert sid %s from string\n", state->request.data.sid)); + user_sid = TALLOC_P(state->mem_ctx, DOM_SID); + if (user_sid == NULL) { + DEBUG(1, ("talloc failed\n")); return WINBINDD_ERROR; } - if (!(mem_ctx = talloc_init("winbindd_getusersids(%s)", - state->request.data.username))) { + if (!string_to_sid(user_sid, state->request.data.sid)) { + DEBUG(1, ("Could not get convert sid %s from string\n", + state->request.data.sid)); return WINBINDD_ERROR; } - /* Get info for the domain */ - if ((domain = find_domain_from_sid(&user_sid)) == NULL) { - DEBUG(0,("could not find domain entry for sid %s\n", - sid_string_static(&user_sid))); - goto done; - } - - status = domain->methods->lookup_usergroups(domain, mem_ctx, - &user_sid, &num_groups, - &user_grpsids); - if (!NT_STATUS_IS_OK(status)) - goto done; + winbindd_gettoken_async(state->mem_ctx, user_sid, getusersids_recv, + state); + return WINBINDD_PENDING; +} - if (num_groups == 0) { - goto no_groups; - } +static void getusersids_recv(void *private, BOOL success, DOM_SID *sids, + int num_sids) +{ + struct winbindd_cli_state *state = private; + char *ret = NULL; + unsigned ofs, ret_size = 0; + int i; - domain = find_our_domain(); + state->response.result = WINBINDD_ERROR; - if (domain == NULL) { - DEBUG(0, ("Could not find our domain\n")); + if (!success) goto done; - } - - /* Note that I do not check for AD or its mode. XP in a real NT4 - * domain also asks for this info. -- vl */ - - if (!IS_DC) { - uint32 *alias_rids = NULL; - int num_aliases; - - /* We need to include the user SID to expand */ - user_grpsids = TALLOC_REALLOC_ARRAY(mem_ctx, user_grpsids, - DOM_SID *, num_groups+1); - user_grpsids[num_groups] = &user_sid; - - status = domain->methods->lookup_useraliases(domain, mem_ctx, - num_groups+1, - user_grpsids, - &num_aliases, - &alias_rids); - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("Could not expand alias sids: %s\n", - nt_errstr(status))); - goto done; - } - - for (i=0; isid); - sid_append_rid(&sid, alias_rids[i]); - add_sid_to_parray_unique(mem_ctx, &sid, &user_grpsids, - &num_groups); - } - } - - if (lp_winbind_nested_groups()) { - int k; - /* num_groups is changed during the loop, that's why we have - to count down here.*/ - - for (k=num_groups-1; k>=0; k--) { - add_local_sids_from_sid(mem_ctx, user_grpsids[k], - &user_grpsids, &num_groups); - } - - add_local_sids_from_sid(mem_ctx, &user_sid, &user_grpsids, - &num_groups); - } /* work out the response size */ - for (i = 0; i < num_groups; i++) { - const char *s = sid_string_static(user_grpsids[i]); + for (i = 0; i < num_sids; i++) { + const char *s = sid_string_static(&sids[i]); ret_size += strlen(s) + 1; } @@ -1293,22 +1068,94 @@ enum winbindd_result winbindd_getusersids(struct winbindd_cli_state *state) ret = SMB_MALLOC(ret_size); if (!ret) goto done; ofs = 0; - for (i = 0; i < num_groups; i++) { - const char *s = sid_string_static(user_grpsids[i]); + for (i = 0; i < num_sids; i++) { + const char *s = sid_string_static(&sids[i]); safe_strcpy(ret + ofs, s, ret_size - ofs - 1); ofs += strlen(ret+ofs) + 1; } -no_groups: /* Send data back to client */ - state->response.data.num_entries = num_groups; + state->response.data.num_entries = num_sids; state->response.extra_data = ret; state->response.length += ret_size; - result = WINBINDD_OK; + state->response.result = WINBINDD_OK; done: - talloc_destroy(mem_ctx); + request_finished(state); +} - return result; +enum winbindd_result winbindd_getuserdomgroups(struct winbindd_cli_state *state) +{ + DOM_SID user_sid; + struct winbindd_domain *domain; + + /* Ensure null termination */ + state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; + + if (!string_to_sid(&user_sid, state->request.data.sid)) { + DEBUG(1, ("Could not get convert sid %s from string\n", + state->request.data.sid)); + return WINBINDD_ERROR; + } + + /* Get info for the domain */ + if ((domain = find_domain_from_sid_noinit(&user_sid)) == NULL) { + DEBUG(0,("could not find domain entry for sid %s\n", + sid_string_static(&user_sid))); + return WINBINDD_ERROR; + } + + async_domain_request(state->mem_ctx, domain, &state->request, + &state->response, request_finished_cont, state); + return WINBINDD_PENDING; } +enum winbindd_result winbindd_dual_getuserdomgroups(struct winbindd_domain *domain, + struct winbindd_cli_state *state) +{ + DOM_SID user_sid; + NTSTATUS status; + + int i, num_groups, len, bufsize; + DOM_SID *groups; + + /* Ensure null termination */ + state->request.data.sid[sizeof(state->request.data.sid)-1]='\0'; + + if (!string_to_sid(&user_sid, state->request.data.sid)) { + DEBUG(1, ("Could not get convert sid %s from string\n", + state->request.data.sid)); + return WINBINDD_ERROR; + } + + status = domain->methods->lookup_usergroups(domain, state->mem_ctx, + &user_sid, &num_groups, + &groups); + if (!NT_STATUS_IS_OK(status)) + return WINBINDD_ERROR; + + if (num_groups == 0) { + state->response.data.num_entries = 0; + state->response.extra_data = NULL; + return WINBINDD_OK; + } + + len=bufsize=0; + state->response.extra_data = NULL; + + for (i=0; iresponse.extra_data, + &len, &bufsize, + "%s\n", sid_string_static(&groups[i])); + } + + if (state->response.extra_data == NULL) { + /* Hmmm. Allocation failed somewhere */ + return WINBINDD_ERROR; + } + + state->response.data.num_entries = num_groups; + state->response.length += len+1; + + return WINBINDD_OK; +} -- cgit