From 16c99d3114523122247d85312e3c006d16be309e Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 25 Sep 2017 13:25:57 +0200 Subject: [PATCH 1/4] winbindd: add domain SID to idmap mapping domains Fetch the domain SID for every domain in the idmap-domain map. This is in preperation of passing the domain SID as an additional argument to xid2sid requests to the idmap child. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13052 Signed-off-by: Ralph Boehme Reviewed-by: Volker Lendecke (cherry picked from commit 59438bfd3d3551195582cf88bd1109c3cbc7e12a) --- source3/winbindd/wb_xids2sids.c | 162 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 147 insertions(+), 15 deletions(-) diff --git a/source3/winbindd/wb_xids2sids.c b/source3/winbindd/wb_xids2sids.c index 15e94c4203f..8850e63c8b4 100644 --- a/source3/winbindd/wb_xids2sids.c +++ b/source3/winbindd/wb_xids2sids.c @@ -23,11 +23,13 @@ #include "idmap_cache.h" #include "librpc/gen_ndr/ndr_winbind_c.h" #include "librpc/gen_ndr/ndr_netlogon.h" +#include "passdb/lookup_sid.h" struct wb_xids2sids_dom_map { unsigned low_id; unsigned high_id; const char *name; + struct dom_sid sid; }; /* @@ -93,6 +95,7 @@ static bool wb_xids2sids_add_dom(const char *domname, dom_maps = tmp; map = &dom_maps[num_maps]; + ZERO_STRUCTP(map); map->name = talloc_move(dom_maps, &name); } @@ -102,30 +105,138 @@ static bool wb_xids2sids_add_dom(const char *domname, return false; } -static void wb_xids2sids_init_dom_maps(void) +struct wb_xids2sids_init_dom_maps_state { + struct tevent_context *ev; + struct tevent_req *req; + size_t dom_idx; +}; + +static void wb_xids2sids_init_dom_maps_lookupname_next( + struct wb_xids2sids_init_dom_maps_state *state); + +static void wb_xids2sids_init_dom_maps_lookupname_done( + struct tevent_req *subreq); + +static struct tevent_req *wb_xids2sids_init_dom_maps_send( + TALLOC_CTX *mem_ctx, struct tevent_context *ev) { - if (dom_maps != NULL) { - return; + struct tevent_req *req = NULL; + struct wb_xids2sids_init_dom_maps_state *state = NULL; + + req = tevent_req_create(mem_ctx, &state, + struct wb_xids2sids_init_dom_maps_state); + if (req == NULL) { + return NULL; } + *state = (struct wb_xids2sids_init_dom_maps_state) { + .ev = ev, + .req = req, + .dom_idx = 0, + }; + if (dom_maps != NULL) { + tevent_req_done(req); + return tevent_req_post(req, ev); + } /* * Put the passdb idmap domain first. We always need to try * there first. */ - dom_maps = talloc_array(NULL, struct wb_xids2sids_dom_map, 1); - if (dom_maps == NULL) { - return; + dom_maps = talloc_zero_array(NULL, struct wb_xids2sids_dom_map, 1); + if (tevent_req_nomem(dom_maps, req)) { + return tevent_req_post(req, ev); } dom_maps[0].low_id = 0; dom_maps[0].high_id = UINT_MAX; dom_maps[0].name = talloc_strdup(dom_maps, get_global_sam_name()); - if (dom_maps[0].name == NULL) { + if (tevent_req_nomem(dom_maps[0].name, req)) { TALLOC_FREE(dom_maps); - return; + return tevent_req_post(req, ev); } lp_scan_idmap_domains(wb_xids2sids_add_dom, NULL); + + wb_xids2sids_init_dom_maps_lookupname_next(state); + if (!tevent_req_is_in_progress(req)) { + tevent_req_post(req, ev); + } + return req; +} + +static void wb_xids2sids_init_dom_maps_lookupname_next( + struct wb_xids2sids_init_dom_maps_state *state) +{ + struct tevent_req *subreq = NULL; + + if (state->dom_idx == talloc_array_length(dom_maps)) { + tevent_req_done(state->req); + return; + } + + if (strequal(dom_maps[state->dom_idx].name, "*")) { + state->dom_idx++; + if (state->dom_idx == talloc_array_length(dom_maps)) { + tevent_req_done(state->req); + return; + } + } + + subreq = wb_lookupname_send(state, + state->ev, + dom_maps[state->dom_idx].name, + "", + LOOKUP_NAME_NO_NSS); + if (tevent_req_nomem(subreq, state->req)) { + return; + } + tevent_req_set_callback(subreq, + wb_xids2sids_init_dom_maps_lookupname_done, + state->req); +} + +static void wb_xids2sids_init_dom_maps_lookupname_done( + struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_xids2sids_init_dom_maps_state *state = tevent_req_data( + req, struct wb_xids2sids_init_dom_maps_state); + enum lsa_SidType type; + NTSTATUS status; + + status = wb_lookupname_recv(subreq, + &dom_maps[state->dom_idx].sid, + &type); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("Lookup domain name '%s' failed '%s'\n", + dom_maps[state->dom_idx].name, + nt_errstr(status)); + + state->dom_idx++; + wb_xids2sids_init_dom_maps_lookupname_next(state); + return; + } + + if (type != SID_NAME_DOMAIN) { + DBG_WARNING("SID %s for idmap domain name '%s' " + "not a domain SID\n", + sid_string_dbg(&dom_maps[state->dom_idx].sid), + dom_maps[state->dom_idx].name); + + ZERO_STRUCT(dom_maps[state->dom_idx].sid); + } + + state->dom_idx++; + wb_xids2sids_init_dom_maps_lookupname_next(state); + + return; +} + +static NTSTATUS wb_xids2sids_init_dom_maps_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); } struct wb_xids2sids_dom_state { @@ -185,7 +296,6 @@ static struct tevent_req *wb_xids2sids_dom_send( /* already mapped */ continue; } - state->dom_xids[state->num_dom_xids++] = id; } @@ -321,6 +431,7 @@ struct wb_xids2sids_state { }; static void wb_xids2sids_done(struct tevent_req *subreq); +static void wb_xids2sids_init_dom_maps_done(struct tevent_req *subreq); struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, @@ -329,7 +440,6 @@ struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req, *subreq; struct wb_xids2sids_state *state; - size_t num_domains; req = tevent_req_create(mem_ctx, &state, struct wb_xids2sids_state); @@ -371,22 +481,44 @@ struct tevent_req *wb_xids2sids_send(TALLOC_CTX *mem_ctx, } } - wb_xids2sids_init_dom_maps(); - num_domains = talloc_array_length(dom_maps); + subreq = wb_xids2sids_init_dom_maps_send( + state, state->ev); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, wb_xids2sids_init_dom_maps_done, req); + return req; +} + +static void wb_xids2sids_init_dom_maps_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct wb_xids2sids_state *state = tevent_req_data( + req, struct wb_xids2sids_state); + size_t num_domains; + NTSTATUS status; + + status = wb_xids2sids_init_dom_maps_recv(subreq); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + num_domains = talloc_array_length(dom_maps); if (num_domains == 0) { tevent_req_done(req); - return tevent_req_post(req, ev); + return; } subreq = wb_xids2sids_dom_send( state, state->ev, &dom_maps[state->dom_idx], state->xids, state->num_xids, state->sids); if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); + return; } tevent_req_set_callback(subreq, wb_xids2sids_done, req); - return req; + return; } static void wb_xids2sids_done(struct tevent_req *subreq) -- 2.13.5 From 4f8cbe1ae8b3b589b70b58d5a55b840eb58f75b2 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 25 Sep 2017 15:39:39 +0200 Subject: [PATCH 2/4] winbindd: pass domain SID to wbint_UnixIDs2Sids This makes the domain SID available to the idmap child for wbint_UnixIDs2Sids mapping request. It's not used yet anywhere, this comes in the next commit. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13052 Signed-off-by: Ralph Boehme Reviewed-by: Volker Lendecke (cherry picked from commit 71f99cb132f4c26f9febac6cb7dcd79f4940216a) --- librpc/idl/winbind.idl | 1 + source3/include/idmap.h | 5 +++++ source3/winbindd/idmap.c | 4 +++- source3/winbindd/idmap_proto.h | 3 ++- source3/winbindd/wb_xids2sids.c | 5 +++-- source3/winbindd/winbindd_dual_srv.c | 3 ++- 6 files changed, 16 insertions(+), 5 deletions(-) diff --git a/librpc/idl/winbind.idl b/librpc/idl/winbind.idl index 737d66abe70..f5e3507bff5 100644 --- a/librpc/idl/winbind.idl +++ b/librpc/idl/winbind.idl @@ -58,6 +58,7 @@ interface winbind NTSTATUS wbint_UnixIDs2Sids( [in,string,charset(UTF8)] char *domain_name, + [in] dom_sid domain_sid, [in] uint32 num_ids, [in,out] unixid xids[num_ids], [out] dom_sid sids[num_ids] diff --git a/source3/include/idmap.h b/source3/include/idmap.h index 75d2e45b174..8d80643e6e9 100644 --- a/source3/include/idmap.h +++ b/source3/include/idmap.h @@ -37,6 +37,11 @@ struct wbint_userinfo; struct idmap_domain { const char *name; + /* + * dom_sid is currently only initialized in the unixids_to_sids request, + * so don't rely on this being filled out everywhere! + */ + struct dom_sid dom_sid; struct idmap_methods *methods; NTSTATUS (*query_user)(struct idmap_domain *domain, struct wbint_userinfo *info); diff --git a/source3/winbindd/idmap.c b/source3/winbindd/idmap.c index 70f35aeee07..cee065bdd9a 100644 --- a/source3/winbindd/idmap.c +++ b/source3/winbindd/idmap.c @@ -605,7 +605,8 @@ NTSTATUS idmap_allocate_gid(struct unixid *id) } NTSTATUS idmap_backend_unixids_to_sids(struct id_map **maps, - const char *domain_name) + const char *domain_name, + struct dom_sid domain_sid) { struct idmap_domain *dom = NULL; NTSTATUS status; @@ -626,6 +627,7 @@ NTSTATUS idmap_backend_unixids_to_sids(struct id_map **maps, return NT_STATUS_NONE_MAPPED; } + dom->dom_sid = domain_sid; status = dom->methods->unixids_to_sids(dom, maps); DBG_DEBUG("unixid_to_sids for domain %s returned %s\n", diff --git a/source3/winbindd/idmap_proto.h b/source3/winbindd/idmap_proto.h index 596c22f6060..a51560d825c 100644 --- a/source3/winbindd/idmap_proto.h +++ b/source3/winbindd/idmap_proto.h @@ -35,7 +35,8 @@ void idmap_close(void); NTSTATUS idmap_allocate_uid(struct unixid *id); NTSTATUS idmap_allocate_gid(struct unixid *id); NTSTATUS idmap_backend_unixids_to_sids(struct id_map **maps, - const char *domain_name); + const char *domain_name, + struct dom_sid domain_sid); struct idmap_domain *idmap_find_domain(const char *domname); /* The following definitions come from winbindd/idmap_nss.c */ diff --git a/source3/winbindd/wb_xids2sids.c b/source3/winbindd/wb_xids2sids.c index 8850e63c8b4..a2a4493bde8 100644 --- a/source3/winbindd/wb_xids2sids.c +++ b/source3/winbindd/wb_xids2sids.c @@ -306,7 +306,7 @@ static struct tevent_req *wb_xids2sids_dom_send( child = idmap_child(); subreq = dcerpc_wbint_UnixIDs2Sids_send( - state, ev, child->binding_handle, dom_map->name, + state, ev, child->binding_handle, dom_map->name, dom_map->sid, state->num_dom_xids, state->dom_xids, state->dom_sids); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); @@ -409,7 +409,8 @@ static void wb_xids2sids_dom_gotdc(struct tevent_req *subreq) child = idmap_child(); subreq = dcerpc_wbint_UnixIDs2Sids_send( state, state->ev, child->binding_handle, state->dom_map->name, - state->num_dom_xids, state->dom_xids, state->dom_sids); + state->dom_map->sid, state->num_dom_xids, + state->dom_xids, state->dom_sids); if (tevent_req_nomem(subreq, req)) { return; } diff --git a/source3/winbindd/winbindd_dual_srv.c b/source3/winbindd/winbindd_dual_srv.c index 5e953e7c3c6..a5ac2bb8169 100644 --- a/source3/winbindd/winbindd_dual_srv.c +++ b/source3/winbindd/winbindd_dual_srv.c @@ -230,7 +230,8 @@ NTSTATUS _wbint_UnixIDs2Sids(struct pipes_struct *p, maps[i]->xid = r->in.xids[i]; } - status = idmap_backend_unixids_to_sids(maps, r->in.domain_name); + status = idmap_backend_unixids_to_sids(maps, r->in.domain_name, + r->in.domain_sid); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(maps); return status; -- 2.13.5 From 60fb83ad1d88b7f0e4c03da8289ad5e04ee537dd Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 25 Sep 2017 15:42:08 +0200 Subject: [PATCH 3/4] winbindd: idmap_rid: don't rely on the static domain list The domain list in the idmap child is inherited from the parent winbindd process and may not contain all domains in case enumerating trusted domains didn't finish before the first winbind request that triggers the idmap child fork comes along. The previous commits added the domain SID as an additional argument to the wbint_UnixIDs2Sids request, storing the domain SID in struct idmap_domain. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13052 Signed-off-by: Ralph Boehme Reviewed-by: Volker Lendecke (cherry picked from commit 108675c4cf4c3d5bd29468255743423a56bd1471) --- source3/winbindd/idmap_rid.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source3/winbindd/idmap_rid.c b/source3/winbindd/idmap_rid.c index 10088b5a27a..6ebb4a191a8 100644 --- a/source3/winbindd/idmap_rid.c +++ b/source3/winbindd/idmap_rid.c @@ -54,7 +54,6 @@ static NTSTATUS idmap_rid_initialize(struct idmap_domain *dom) static NTSTATUS idmap_rid_id_to_sid(struct idmap_domain *dom, struct id_map *map) { - struct winbindd_domain *domain; struct idmap_rid_context *ctx; ctx = talloc_get_type(dom->private_data, struct idmap_rid_context); @@ -66,12 +65,13 @@ static NTSTATUS idmap_rid_id_to_sid(struct idmap_domain *dom, struct id_map *map return NT_STATUS_NONE_MAPPED; } - domain = find_domain_from_name_noinit(dom->name); - if (domain == NULL ) { + if (is_null_sid(&dom->dom_sid)) { + DBG_INFO("idmap domain '%s' without SID\n", dom->name); return NT_STATUS_NO_SUCH_DOMAIN; } - sid_compose(map->sid, &domain->sid, map->xid.id - dom->low_id + ctx->base_rid); + sid_compose(map->sid, &dom->dom_sid, + map->xid.id - dom->low_id + ctx->base_rid); map->status = ID_MAPPED; map->xid.type = ID_TYPE_BOTH; -- 2.13.5 From 61989f15ee1a692f5fd96161e24c35d9b233dc4a Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 9 Oct 2017 13:29:05 +0200 Subject: [PATCH 4/4] winbindd: idmap_rid: error code for failing id-to-sid mapping request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NT_STATUS_NO_SUCH_DOMAIN triggers complete request failure in the parent winbindd. By returning NT_STATUS_NONE_MAPPED winbindd lets the individual mapping fail but keeps processing any remaining mapping requests. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13052 Signed-off-by: Ralph Boehme Reviewed-by: Volker Lendecke Autobuild-User(master): Ralph Böhme Autobuild-Date(master): Tue Oct 10 19:57:37 CEST 2017 on sn-devel-144 (cherry picked from commit 490c35df35bad6c2f1c4acd2f056d6fdc480ec1f) --- source3/winbindd/idmap_rid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/winbindd/idmap_rid.c b/source3/winbindd/idmap_rid.c index 6ebb4a191a8..b066ba3c50f 100644 --- a/source3/winbindd/idmap_rid.c +++ b/source3/winbindd/idmap_rid.c @@ -67,7 +67,7 @@ static NTSTATUS idmap_rid_id_to_sid(struct idmap_domain *dom, struct id_map *map if (is_null_sid(&dom->dom_sid)) { DBG_INFO("idmap domain '%s' without SID\n", dom->name); - return NT_STATUS_NO_SUCH_DOMAIN; + return NT_STATUS_NONE_MAPPED; } sid_compose(map->sid, &dom->dom_sid, -- 2.13.5