mirror of
https://github.com/samba-team/samba.git
synced 2025-01-29 21:47:30 +03:00
added a query_user backend
fixed a winbindd crash when the group membership can't be looked up
This commit is contained in:
parent
660238adca
commit
088f4cc5be
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user