From 8e8ce079b8c54b257111537d487a5419ce0d1479 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 4 Dec 2001 06:17:39 +0000 Subject: added a query_user backend fixed a winbindd crash when the group membership can't be looked up (This used to be commit 088f4cc5be4a1a38781e4d019146d53993ed8c6f) --- source3/nsswitch/winbindd.h | 7 ++++ source3/nsswitch/winbindd_ads.c | 75 +++++++++++++++++++++++++++++++++++++-- source3/nsswitch/winbindd_group.c | 9 +++-- source3/nsswitch/winbindd_proto.h | 3 -- source3/nsswitch/winbindd_rpc.c | 59 +++++++++++++++++++++++++++++- source3/nsswitch/winbindd_user.c | 58 ++++++++++++++---------------- source3/nsswitch/winbindd_util.c | 55 ---------------------------- 7 files changed, 169 insertions(+), 97 deletions(-) diff --git a/source3/nsswitch/winbindd.h b/source3/nsswitch/winbindd.h index a3c9d0afb7..01d334d4eb 100644 --- a/source3/nsswitch/winbindd.h +++ b/source3/nsswitch/winbindd.h @@ -109,6 +109,13 @@ struct winbindd_methods { DOM_SID *sid, char **name, enum SID_NAME_USE *type); + + /* query_user is a bit strange. The backend has a choice of + doing the lookup by user name or rid */ + NTSTATUS (*query_user)(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *user_name, uint32 user_rid, + WINBIND_USERINFO *user_info); }; /* Structures to hold per domain information */ diff --git a/source3/nsswitch/winbindd_ads.c b/source3/nsswitch/winbindd_ads.c index 287151abd7..d86c498cfe 100644 --- a/source3/nsswitch/winbindd_ads.c +++ b/source3/nsswitch/winbindd_ads.c @@ -271,6 +271,76 @@ static NTSTATUS name_to_sid(struct winbindd_domain *domain, return NT_STATUS_OK; } +/* Lookup user information from a rid or username. */ +static NTSTATUS query_user(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *user_name, uint32 user_rid, + WINBIND_USERINFO *info) +{ + ADS_STRUCT *ads; + const char *attrs[] = {"sAMAccountName", "name", "objectSid", "primaryGroupID", + "userAccountControl", NULL}; + int rc, count; + void *msg; + char *exp; + DOM_SID sid; + fstring dom2, name2; + + /* sigh. Need to fix interface to give us a raw name */ + parse_domain_user(user_name, dom2, name2); + + DEBUG(3,("ads: query_user\n")); + + ads = ads_init(NULL, NULL, NULL); + if (!ads) { + DEBUG(1,("ads_init failed\n")); + return NT_STATUS_UNSUCCESSFUL; + } + + rc = ads_connect(ads); + if (rc) { + DEBUG(1,("query_user ads_connect: %s\n", ads_errstr(rc))); + return NT_STATUS_UNSUCCESSFUL; + } + + asprintf(&exp, "(sAMAccountName=%s)", name2); + rc = ads_search(ads, &msg, exp, attrs); + free(exp); + if (rc) { + DEBUG(1,("query_user(%s) ads_search: %s\n", user_name, ads_errstr(rc))); + return NT_STATUS_UNSUCCESSFUL; + } + + count = ads_count_replies(ads, msg); + if (count != 1) { + DEBUG(1,("query_user(%s): Not found\n", user_name)); + return NT_STATUS_UNSUCCESSFUL; + } + + info->acct_name = ads_pull_string(ads, mem_ctx, msg, "sAMAccountName"); + info->full_name = ads_pull_string(ads, mem_ctx, msg, "name"); + if (!ads_pull_sid(ads, msg, "objectSid", &sid)) { + DEBUG(1,("No sid for %s !?\n", user_name)); + goto error; + } + if (!ads_pull_uint32(ads, msg, "primaryGroupID", &info->group_rid)) { + DEBUG(1,("No primary group for %s !?\n", user_name)); + goto error; + } + + if (!sid_peek_rid(&sid, &info->user_rid)) { + DEBUG(1,("No rid for %s !?\n", user_name)); + goto error; + } + + ads_destroy(&ads); + + return NT_STATUS_OK; +error: + ads_destroy(&ads); + return NT_STATUS_UNSUCCESSFUL; +} + /* the ADS backend methods are exposed via this structure */ struct winbindd_methods ads_methods = { query_user_list, @@ -278,8 +348,9 @@ struct winbindd_methods ads_methods = { name_to_sid, /* I can't see a good way to do a sid to name mapping with ldap, and MS servers always allow RPC for this (even in native mode) so - just use RPC. Maybe that's why they allow it? */ - winbindd_rpc_sid_to_name + just use RPC for sid_to_name. Maybe that's why they allow it? */ + winbindd_rpc_sid_to_name, + query_user }; #endif diff --git a/source3/nsswitch/winbindd_group.c b/source3/nsswitch/winbindd_group.c index f71cdb7ece..07f30f0acc 100644 --- a/source3/nsswitch/winbindd_group.c +++ b/source3/nsswitch/winbindd_group.c @@ -614,6 +614,8 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) fstring domain_group_name; uint32 result; gid_t group_gid; + int gr_mem_len; + char *gr_mem, *new_gr_mem_list; /* Do we need to fetch another chunk of groups? */ @@ -678,20 +680,17 @@ enum winbindd_result winbindd_getgrent(struct winbindd_cli_state *state) /* Fill in group membership entry */ if (result) { - int gr_mem_len; - char *gr_mem, *new_gr_mem_list; - /* Get group membership */ - result = fill_grent_mem( ent->domain, name_list[ent->sam_entry_index].rid, SID_NAME_DOM_GRP, &group_list[group_list_ndx].num_gr_mem, &gr_mem, &gr_mem_len); + } + if (result) { /* Append to group membership list */ - new_gr_mem_list = Realloc( gr_mem_list, gr_mem_list_len + gr_mem_len); diff --git a/source3/nsswitch/winbindd_proto.h b/source3/nsswitch/winbindd_proto.h index 260985ec58..1d553fdceb 100644 --- a/source3/nsswitch/winbindd_proto.h +++ b/source3/nsswitch/winbindd_proto.h @@ -145,9 +145,6 @@ BOOL winbindd_lookup_sid_by_name(struct winbindd_domain *domain, BOOL winbindd_lookup_name_by_sid(DOM_SID *sid, fstring name, enum SID_NAME_USE *type); -BOOL winbindd_lookup_userinfo(struct winbindd_domain *domain, - TALLOC_CTX *mem_ctx, uint32 user_rid, - SAM_USERINFO_CTR **user_info); BOOL winbindd_lookup_usergroups(struct winbindd_domain *domain, TALLOC_CTX *mem_ctx, uint32 user_rid, uint32 *num_groups, diff --git a/source3/nsswitch/winbindd_rpc.c b/source3/nsswitch/winbindd_rpc.c index e4654254cb..b92e456185 100644 --- a/source3/nsswitch/winbindd_rpc.c +++ b/source3/nsswitch/winbindd_rpc.c @@ -184,12 +184,69 @@ NTSTATUS winbindd_rpc_sid_to_name(struct winbindd_domain *domain, return status; } +/* Lookup user information from a rid or username. */ +static NTSTATUS query_user(struct winbindd_domain *domain, + TALLOC_CTX *mem_ctx, + const char *user_name, uint32 user_rid, + WINBIND_USERINFO *user_info) +{ + CLI_POLICY_HND *hnd; + NTSTATUS result; + POLICY_HND dom_pol, user_pol; + BOOL got_dom_pol = False, got_user_pol = False; + SAM_USERINFO_CTR *ctr; + + /* Get sam handle */ + if (!(hnd = cm_get_sam_handle(domain->name))) + goto done; + + /* Get domain handle */ + + result = cli_samr_open_domain(hnd->cli, mem_ctx, &hnd->pol, + SEC_RIGHTS_MAXIMUM_ALLOWED, + &domain->sid, &dom_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + got_dom_pol = True; + + /* Get user handle */ + result = cli_samr_open_user(hnd->cli, mem_ctx, &dom_pol, + SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol); + + if (!NT_STATUS_IS_OK(result)) + goto done; + + /* Get user info */ + result = cli_samr_query_userinfo(hnd->cli, mem_ctx, &user_pol, + 0x15, &ctr); + + cli_samr_close(hnd->cli, mem_ctx, &user_pol); + + user_info->acct_name = talloc_strdup(mem_ctx, user_name); + user_info->group_rid = ctr->info.id21->group_rid; + user_info->full_name = unistr2_tdup(mem_ctx, + &ctr->info.id21->uni_full_name); + + done: + /* Clean up policy handles */ + 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); + + return result; +} + /* the rpc backend methods are exposed via this structure */ struct winbindd_methods msrpc_methods = { query_user_list, enum_dom_groups, name_to_sid, - winbindd_rpc_sid_to_name + winbindd_rpc_sid_to_name, + query_user }; diff --git a/source3/nsswitch/winbindd_user.c b/source3/nsswitch/winbindd_user.c index ebd9503c7c..c8d9ce299f 100644 --- a/source3/nsswitch/winbindd_user.c +++ b/source3/nsswitch/winbindd_user.c @@ -99,10 +99,11 @@ static struct winbindd_pw negative_pw_cache_entry; enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *state) { - uint32 user_rid, group_rid; - SAM_USERINFO_CTR *user_info; + uint32 user_rid; + WINBIND_USERINFO user_info; DOM_SID user_sid; - fstring name_domain, name_user, name, gecos_name; + NTSTATUS status; + fstring name_domain, name_user, name; enum SID_NAME_USE name_type; struct winbindd_domain *domain; TALLOC_CTX *mem_ctx; @@ -163,30 +164,27 @@ enum winbindd_result winbindd_getpwnam_from_user(struct winbindd_cli_state *stat } sid_split_rid(&user_sid, &user_rid); - - if (!winbindd_lookup_userinfo(domain, mem_ctx, user_rid, &user_info)) { + + status = domain->methods->query_user(domain, mem_ctx, name_user, user_rid, + &user_info); + if (!NT_STATUS_IS_OK(status)) { 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); + talloc_destroy(mem_ctx); return WINBINDD_ERROR; } - group_rid = user_info->info.id21->group_rid; - - unistr2_to_ascii(gecos_name, &user_info->info.id21->uni_full_name, - sizeof(gecos_name) - 1); - - talloc_destroy(mem_ctx); - user_info = NULL; - - /* Now take all this information and fill in a passwd structure */ - + /* Now take all this information and fill in a passwd structure */ if (!winbindd_fill_pwent(name_domain, state->request.data.username, - user_rid, group_rid, gecos_name, + user_rid, user_info.group_rid, user_info.full_name, &state->response.data.pw)) { winbindd_store_user_cache_entry(domain, name_user, &negative_pw_cache_entry); + talloc_destroy(mem_ctx); return WINBINDD_ERROR; } + + talloc_destroy(mem_ctx); winbindd_store_user_cache_entry(domain, name_user, &state->response.data.pw); @@ -199,12 +197,13 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state *state { DOM_SID user_sid; struct winbindd_domain *domain; - uint32 user_rid, group_rid; - fstring user_name, gecos_name; + uint32 user_rid; + fstring user_name; enum SID_NAME_USE name_type; - SAM_USERINFO_CTR *user_info; + WINBIND_USERINFO user_info; gid_t gid; TALLOC_CTX *mem_ctx; + NTSTATUS status; /* Bug out if the uid isn't in the winbind range */ @@ -262,37 +261,34 @@ enum winbindd_result winbindd_getpwnam_from_uid(struct winbindd_cli_state *state return WINBINDD_ERROR; } - if (!winbindd_lookup_userinfo(domain, mem_ctx, user_rid, &user_info)) { + status = domain->methods->query_user(domain, mem_ctx, user_name, user_rid, + &user_info); + if (!NT_STATUS_IS_OK(status)) { 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; } - group_rid = user_info->info.id21->group_rid; - unistr2_to_ascii(gecos_name, &user_info->info.id21->uni_full_name, - sizeof(gecos_name) - 1); - - talloc_destroy(mem_ctx); - user_info = NULL; - /* Resolve gid number */ - if (!winbindd_idmap_get_gid_from_rid(domain->name, group_rid, &gid)) { + if (!winbindd_idmap_get_gid_from_rid(domain->name, user_info.group_rid, &gid)) { DEBUG(1, ("error getting group id for user %s\n", user_name)); return WINBINDD_ERROR; } /* Fill in password structure */ - if (!winbindd_fill_pwent(domain->name, user_name, user_rid, group_rid, - gecos_name, &state->response.data.pw)) { + if (!winbindd_fill_pwent(domain->name, user_name, user_rid, user_info.group_rid, + user_info.full_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); - + + talloc_destroy(mem_ctx); + return WINBINDD_OK; } diff --git a/source3/nsswitch/winbindd_util.c b/source3/nsswitch/winbindd_util.c index 900fc900bf..d6f4ca0bcf 100644 --- a/source3/nsswitch/winbindd_util.c +++ b/source3/nsswitch/winbindd_util.c @@ -478,61 +478,6 @@ BOOL winbindd_lookup_name_by_sid(DOM_SID *sid, return rv; } -/* Lookup user information from a rid */ - -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; - - /* Get sam handle */ - - if (!(hnd = cm_get_sam_handle(domain->name))) - goto done; - - /* Get domain handle */ - - 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; - - got_dom_pol = True; - - /* Get user handle */ - - 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; - - /* Get 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); - - done: - /* Clean up policy handles */ - - 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); - - return NT_STATUS_IS_OK(result); -} - /* Lookup groups a user is a member of. I wish Unix had a call like this! */ BOOL winbindd_lookup_usergroups(struct winbindd_domain *domain, -- cgit