1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-26 21:57:41 +03:00

winbind: Restructure wb_getpwsid

This patch moves the responsibility to create a winbind user from the
winbind backends into wb_queryuser.c. The name comes from lsa_lookupsids,
the uid from idmap. If we have a netsamlogon_cache, we get the primary
group sid from there. Without netsamlogon_cache, we default to -513, as
we do right now as default for non-reachable ADS domains anyway. Shell
and homedir default to template. This can all be done in the parent
without contacting any LDAP-related calls and is correct once we have
a netsamlogon_cache.

Once the parent has filled in the userinfo, the idmap child is queried
with the GetNssInfo call, taking the userinfo [in,out]. The child is
free to override the whole thing, something the AD backend will do in
the next patch.

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Uri Simchoni <uri@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
This commit is contained in:
Volker Lendecke 2016-12-29 10:05:28 +00:00
parent d0f1d761b5
commit bce19a6efe
2 changed files with 307 additions and 102 deletions

View File

@ -30,8 +30,6 @@ struct wb_getpwsid_state {
};
static void wb_getpwsid_queryuser_done(struct tevent_req *subreq);
static void wb_getpwsid_lookupsid_done(struct tevent_req *subreq);
static void wb_getpwsid_done(struct tevent_req *subreq);
struct tevent_req *wb_getpwsid_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
@ -63,108 +61,57 @@ static void wb_getpwsid_queryuser_done(struct tevent_req *subreq)
subreq, struct tevent_req);
struct wb_getpwsid_state *state = tevent_req_data(
req, struct wb_getpwsid_state);
struct winbindd_pw *pw = state->pw;
struct wbint_userinfo *info;
fstring acct_name, output_username;
char *tmp;
NTSTATUS status;
status = wb_queryuser_recv(subreq, state, &state->userinfo);
TALLOC_FREE(subreq);
if (NT_STATUS_IS_OK(status)
&& (state->userinfo->acct_name != NULL)
&& (state->userinfo->acct_name[0] != '\0'))
{
/*
* QueryUser got us a name, let's go directly to the
* fill_pwent step
*/
subreq = wb_fill_pwent_send(state, state->ev, state->userinfo,
state->pw);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, wb_getpwsid_done, req);
return;
}
/*
* Either query_user did not succeed, or it
* succeeded but did not return an acct_name.
* (TODO: Can this happen at all???)
* ==> Try lsa_lookupsids.
*/
if (state->userinfo == NULL) {
state->userinfo = talloc_zero(state, struct wbint_userinfo);
if (tevent_req_nomem(state->userinfo, req)) {
return;
}
/* a successful query_user call would have filled these */
sid_copy(&state->userinfo->user_sid, &state->sid);
state->userinfo->homedir = NULL;
state->userinfo->shell = NULL;
state->userinfo->primary_gid = (gid_t)-1;
}
subreq = wb_lookupsid_send(state, state->ev, &state->sid);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, wb_getpwsid_lookupsid_done, req);
}
static void wb_getpwsid_lookupsid_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct wb_getpwsid_state *state = tevent_req_data(
req, struct wb_getpwsid_state);
NTSTATUS status;
enum lsa_SidType type;
const char *domain;
status = wb_lookupsid_recv(subreq, state->userinfo, &type, &domain,
&state->userinfo->acct_name);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
info = state->userinfo;
switch (type) {
case SID_NAME_USER:
case SID_NAME_COMPUTER:
/*
* user case: we only need the account name from lookup_sids
*/
break;
case SID_NAME_DOM_GRP:
case SID_NAME_ALIAS:
case SID_NAME_WKN_GRP:
/*
* also treat group-type SIDs (they might map to ID_TYPE_BOTH)
*/
sid_copy(&state->userinfo->group_sid, &state->sid);
break;
default:
tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
pw->pw_uid = info->uid;
pw->pw_gid = info->primary_gid;
fstrcpy(acct_name, info->acct_name);
if (!strlower_m(acct_name)) {
tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
return;
}
subreq = wb_fill_pwent_send(state, state->ev, state->userinfo,
state->pw);
if (tevent_req_nomem(subreq, req)) {
fill_domain_username(output_username, info->domain_name,
acct_name, true);
strlcpy(pw->pw_name, output_username, sizeof(pw->pw_name));
strlcpy(pw->pw_gecos, info->full_name ? info->full_name : "",
sizeof(pw->pw_gecos));
tmp = talloc_sub_specified(
state, info->homedir, acct_name,
info->primary_group_name, info->domain_name,
pw->pw_uid, pw->pw_gid);
if (tevent_req_nomem(tmp, req)) {
return;
}
tevent_req_set_callback(subreq, wb_getpwsid_done, req);
}
strlcpy(pw->pw_dir, tmp, sizeof(pw->pw_dir));
TALLOC_FREE(tmp);
static void wb_getpwsid_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
NTSTATUS status;
status = wb_fill_pwent_recv(subreq);
if (tevent_req_nterror(req, status)) {
tmp = talloc_sub_specified(
state, info->shell, info->acct_name,
info->primary_group_name, info->domain_name,
pw->pw_uid, pw->pw_gid);
if (tevent_req_nomem(tmp, req)) {
return;
}
strlcpy(pw->pw_shell, tmp, sizeof(pw->pw_dir));
TALLOC_FREE(tmp);
strlcpy(pw->pw_passwd, "*", sizeof(pw->pw_passwd));
tevent_req_done(req);
}

View File

@ -21,12 +21,19 @@
#include "winbindd.h"
#include "librpc/gen_ndr/ndr_winbind_c.h"
#include "../libcli/security/security.h"
#include "libsmb/samlogon_cache.h"
struct wb_queryuser_state {
struct dom_sid sid;
struct tevent_context *ev;
struct wbint_userinfo *info;
bool tried_dclookup;
};
static void wb_queryuser_got_uid(struct tevent_req *subreq);
static void wb_queryuser_got_domain(struct tevent_req *subreq);
static void wb_queryuser_got_dc(struct tevent_req *subreq);
static void wb_queryuser_got_gid(struct tevent_req *subreq);
static void wb_queryuser_got_group_name(struct tevent_req *subreq);
static void wb_queryuser_done(struct tevent_req *subreq);
struct tevent_req *wb_queryuser_send(TALLOC_CTX *mem_ctx,
@ -35,46 +42,297 @@ struct tevent_req *wb_queryuser_send(TALLOC_CTX *mem_ctx,
{
struct tevent_req *req, *subreq;
struct wb_queryuser_state *state;
struct winbindd_domain *domain;
struct wbint_userinfo *info;
req = tevent_req_create(mem_ctx, &state, struct wb_queryuser_state);
if (req == NULL) {
return NULL;
}
sid_copy(&state->sid, user_sid);
state->ev = ev;
domain = find_domain_from_sid_noinit(user_sid);
if (domain == NULL) {
tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
return tevent_req_post(req, ev);
if (lp_winbind_trusted_domains_only()) {
struct winbindd_domain *our_domain = find_our_domain();
if (dom_sid_compare_domain(user_sid, &our_domain->sid) == 0) {
char buf[DOM_SID_STR_BUFLEN];
dom_sid_string_buf(user_sid, buf, sizeof(buf));
DBG_NOTICE("My domain -- rejecting %s\n", buf);
tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
return tevent_req_post(req, ev);
}
}
state->info = talloc(state, struct wbint_userinfo);
state->info = talloc_zero(state, struct wbint_userinfo);
if (tevent_req_nomem(state->info, req)) {
return tevent_req_post(req, ev);
}
info = state->info;
subreq = dcerpc_wbint_QueryUser_send(state, ev, dom_child_handle(domain),
&state->sid, state->info);
info->primary_gid = (gid_t)-1;
sid_copy(&info->user_sid, user_sid);
subreq = wb_sids2xids_send(
state, state->ev, &state->info->user_sid, 1);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
tevent_req_set_callback(subreq, wb_queryuser_done, req);
tevent_req_set_callback(subreq, wb_queryuser_got_uid, req);
return req;
}
static void wb_queryuser_got_uid(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct wb_queryuser_state *state = tevent_req_data(
req, struct wb_queryuser_state);
struct wbint_userinfo *info = state->info;
struct netr_SamInfo3 *info3;
struct winbindd_child *child;
struct unixid xid;
NTSTATUS status;
status = wb_sids2xids_recv(subreq, &xid, 1);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
if ((xid.type != ID_TYPE_UID) && (xid.type != ID_TYPE_BOTH)) {
tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
return;
}
info->uid = xid.id;
/*
* Default the group sid to "Domain Users" in the user's
* domain. The samlogon cache or the query_user call later on
* can override this.
*/
sid_copy(&info->group_sid, &info->user_sid);
sid_split_rid(&info->group_sid, NULL);
sid_append_rid(&info->group_sid, DOMAIN_RID_USERS);
info->homedir = talloc_strdup(info, lp_template_homedir());
if (tevent_req_nomem(info->homedir, req)) {
return;
}
info->shell = talloc_strdup(info, lp_template_shell());
if (tevent_req_nomem(info->shell, req)) {
return;
}
info3 = netsamlogon_cache_get(state, &info->user_sid);
if (info3 != NULL) {
sid_compose(&info->group_sid, info3->base.domain_sid,
info3->base.primary_gid);
info->acct_name = talloc_move(
info, &info3->base.account_name.string);
info->full_name = talloc_move(
info, &info3->base.full_name.string);
info->domain_name = talloc_move(
state, &info3->base.logon_domain.string);
TALLOC_FREE(info3);
}
if (info->domain_name == NULL) {
subreq = wb_lookupsid_send(state, state->ev, &info->user_sid);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, wb_queryuser_got_domain, req);
return;
}
child = idmap_child();
subreq = dcerpc_wbint_GetNssInfo_send(
state, state->ev, child->binding_handle, info);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, wb_queryuser_done, req);
}
static void wb_queryuser_got_domain(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct wb_queryuser_state *state = tevent_req_data(
req, struct wb_queryuser_state);
struct wbint_userinfo *info = state->info;
enum lsa_SidType type;
struct winbindd_child *child;
NTSTATUS status;
status = wb_lookupsid_recv(subreq, state, &type,
&info->domain_name, &info->acct_name);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
if (type != SID_NAME_USER) {
/* allow SID_NAME_COMPUTER? */
tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
return;
}
child = idmap_child();
subreq = dcerpc_wbint_GetNssInfo_send(
state, state->ev, child->binding_handle, info);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, wb_queryuser_done, req);
}
static void wb_queryuser_done(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct wb_queryuser_state *state = tevent_req_data(
req, struct wb_queryuser_state);
struct wbint_userinfo *info = state->info;
NTSTATUS status, result;
status = dcerpc_wbint_QueryUser_recv(subreq, state->info, &result);
status = dcerpc_wbint_GetNssInfo_recv(subreq, info, &result);
TALLOC_FREE(subreq);
if (any_nt_status_not_ok(status, result, &status)) {
tevent_req_nterror(req, status);
if (tevent_req_nterror(req, status)) {
return;
}
if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
!state->tried_dclookup) {
subreq = wb_dsgetdcname_send(
state, state->ev, state->info->domain_name, NULL, NULL,
DS_RETURN_DNS_NAME);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, wb_queryuser_got_dc, req);
return;
}
/*
* Ignore failure in "result" here. We'll try to fill in stuff
* that misses further down.
*/
if (state->info->primary_gid == (gid_t)-1) {
subreq = wb_sids2xids_send(
state, state->ev, &info->group_sid, 1);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, wb_queryuser_got_gid, req);
return;
}
if (state->info->primary_group_name == NULL) {
subreq = wb_lookupsid_send(state, state->ev, &info->group_sid);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
req);
return;
}
tevent_req_done(req);
}
static void wb_queryuser_got_dc(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct wb_queryuser_state *state = tevent_req_data(
req, struct wb_queryuser_state);
struct wbint_userinfo *info = state->info;
struct netr_DsRGetDCNameInfo *dcinfo;
struct winbindd_child *child;
NTSTATUS status;
status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
state->tried_dclookup = true;
status = wb_dsgetdcname_gencache_set(info->domain_name, dcinfo);
if (tevent_req_nterror(req, status)) {
return;
}
child = idmap_child();
subreq = dcerpc_wbint_GetNssInfo_send(
state, state->ev, child->binding_handle, info);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, wb_queryuser_done, req);
}
static void wb_queryuser_got_gid(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct wb_queryuser_state *state = tevent_req_data(
req, struct wb_queryuser_state);
struct unixid xid;
NTSTATUS status;
status = wb_sids2xids_recv(subreq, &xid, 1);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
if ((xid.type != ID_TYPE_GID) && (xid.type != ID_TYPE_BOTH)) {
tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
return;
}
state->info->primary_gid = xid.id;
if (state->info->primary_group_name == NULL) {
subreq = wb_lookupsid_send(state, state->ev,
&state->info->group_sid);
if (tevent_req_nomem(subreq, req)) {
return;
}
tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
req);
return;
}
tevent_req_done(req);
}
static void wb_queryuser_got_group_name(struct tevent_req *subreq)
{
struct tevent_req *req = tevent_req_callback_data(
subreq, struct tevent_req);
struct wb_queryuser_state *state = tevent_req_data(
req, struct wb_queryuser_state);
enum lsa_SidType type;
NTSTATUS status;
const char *domain_name;
status = wb_lookupsid_recv(subreq, state, &type, &domain_name,
&state->info->primary_group_name);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
return;
}
tevent_req_done(req);