From 797e16f63a7fba0270bc52d043b0fb17c63c1da7 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 20 Feb 2018 15:57:37 +0100 Subject: [PATCH 01/22] rpcclient: fix variable initialisation and add parenthesis to if clauses Just a few README.Coding fixes. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Ralph Boehme Reviewed-by: Stefan Metzmacher (cherry picked from commit 9ccc6eef145c1f67e24cbb1c21402714f612c607) --- source3/rpcclient/cmd_lsarpc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c index 2fa04a27752..058583d943a 100644 --- a/source3/rpcclient/cmd_lsarpc.c +++ b/source3/rpcclient/cmd_lsarpc.c @@ -272,8 +272,8 @@ static NTSTATUS cmd_lsa_lookup_names_level(struct rpc_pipe_client *cli, { struct policy_handle pol; NTSTATUS status, result; - struct dom_sid *sids; - enum lsa_SidType *types; + struct dom_sid *sids = NULL; + enum lsa_SidType *types = NULL; int i, level; struct dcerpc_binding_handle *b = cli->binding_handle; @@ -285,9 +285,9 @@ static NTSTATUS cmd_lsa_lookup_names_level(struct rpc_pipe_client *cli, status = rpccli_lsa_open_policy(cli, mem_ctx, True, SEC_FLAG_MAXIMUM_ALLOWED, &pol); - - if (!NT_STATUS_IS_OK(status)) + if (!NT_STATUS_IS_OK(status)) { goto done; + } level = atoi(argv[1]); @@ -296,7 +296,9 @@ static NTSTATUS cmd_lsa_lookup_names_level(struct rpc_pipe_client *cli, if (!NT_STATUS_IS_OK(status) && NT_STATUS_V(status) != NT_STATUS_V(STATUS_SOME_UNMAPPED)) + { goto done; + } status = NT_STATUS_OK; -- 2.13.6 From a5d1e44a0cafb1a060ac3ee3f11af46ed7089fbb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 25 Jan 2018 11:24:25 +0100 Subject: [PATCH 02/22] rpcclient: add lookupsids_level command Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 76868818e8b98a0cd4881d319e0735de5091b8b1) --- source3/rpcclient/cmd_lsarpc.c | 93 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/source3/rpcclient/cmd_lsarpc.c b/source3/rpcclient/cmd_lsarpc.c index 058583d943a..462ed06e007 100644 --- a/source3/rpcclient/cmd_lsarpc.c +++ b/source3/rpcclient/cmd_lsarpc.c @@ -454,6 +454,98 @@ static NTSTATUS cmd_lsa_lookup_sids(struct rpc_pipe_client *cli, TALLOC_CTX *mem return status; } +static NTSTATUS cmd_lsa_lookup_sids_level(struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, int argc, + const char **argv) +{ + struct policy_handle pol; + NTSTATUS status, result; + struct dom_sid *sids = NULL; + char **domains = NULL; + char **names = NULL; + enum lsa_SidType *types = NULL; + int i, level; + struct dcerpc_binding_handle *b = cli->binding_handle; + + if (argc < 3) { + printf("Usage: %s [level] [sid1 [sid2 [...]]]\n", argv[0]); + return NT_STATUS_OK; + } + + status = rpccli_lsa_open_policy(cli, mem_ctx, True, + SEC_FLAG_MAXIMUM_ALLOWED, + &pol); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + level = atoi(argv[1]); + + /* Convert arguments to sids */ + + sids = talloc_array(mem_ctx, struct dom_sid, argc - 2); + if (sids == NULL) { + printf("could not allocate memory for %d sids\n", argc - 2); + goto done; + } + + for (i = 0; i < argc - 2; i++) { + if (!string_to_sid(&sids[i], argv[i + 2])) { + status = NT_STATUS_INVALID_SID; + goto done; + } + } + + /* Lookup the SIDs */ + + status = dcerpc_lsa_lookup_sids_generic(cli->binding_handle, + mem_ctx, + &pol, + argc - 2, + sids, + level, + &domains, + &names, + &types, + false, + &result); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + status = result; + + if (!NT_STATUS_IS_OK(status) && NT_STATUS_V(status) != + NT_STATUS_V(STATUS_SOME_UNMAPPED)) + { + goto done; + } + + status = NT_STATUS_OK; + + /* Print results */ + + for (i = 0; i < (argc - 2); i++) { + fstring sid_str; + + sid_to_fstring(sid_str, &sids[i]); + if (types[i] == SID_NAME_DOMAIN) { + printf("%s %s (%d)\n", sid_str, + domains[i] ? domains[i] : "*unknown*", + types[i]); + } else { + printf("%s %s\\%s (%d)\n", sid_str, + domains[i] ? domains[i] : "*unknown*", + names[i] ? names[i] : "*unknown*", + types[i]); + } + } + + dcerpc_lsa_Close(b, mem_ctx, &pol, &result); + + done: + return status; +} + /* Resolve a list of SIDs to a list of names */ static NTSTATUS cmd_lsa_lookup_sids3(struct rpc_pipe_client *cli, @@ -2281,6 +2373,7 @@ struct cmd_set lsarpc_commands[] = { { "lsaquery", RPC_RTYPE_NTSTATUS, cmd_lsa_query_info_policy, NULL, &ndr_table_lsarpc, NULL, "Query info policy", "" }, { "lookupsids", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_sids, NULL, &ndr_table_lsarpc, NULL, "Convert SIDs to names", "" }, { "lookupsids3", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_sids3, NULL, &ndr_table_lsarpc, NULL, "Convert SIDs to names", "" }, + { "lookupsids_level", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_sids_level, NULL, &ndr_table_lsarpc, NULL, "Convert SIDs to names", "" }, { "lookupnames", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_names, NULL, &ndr_table_lsarpc, NULL, "Convert names to SIDs", "" }, { "lookupnames4", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_names4, NULL, &ndr_table_lsarpc, NULL, "Convert names to SIDs", "" }, { "lookupnames_level", RPC_RTYPE_NTSTATUS, cmd_lsa_lookup_names_level, NULL, &ndr_table_lsarpc, NULL, "Convert names to SIDs", "" }, -- 2.13.6 From 6698bd305506ddeff0cc6a7c8c45e3dd2ff293db Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 20 Mar 2017 12:56:00 +0100 Subject: [PATCH 03/22] s4:rpc_server/lsa: use LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES/LSA_CLIENT_REVISION_1 in compat code Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 3909f8fcfe6b82575ad8974acacde3270ce849fe) --- source4/rpc_server/lsa/lsa_lookup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index f54b118b5e8..d0361417ef9 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -797,8 +797,8 @@ NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *m r2.in.names = NULL; r2.in.level = r->in.level; r2.in.count = r->in.count; - r2.in.lookup_options = 0; - r2.in.client_revision = 0; + r2.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; + r2.in.client_revision = LSA_CLIENT_REVISION_1; r2.out.count = r->out.count; r2.out.names = NULL; r2.out.domains = r->out.domains; @@ -1124,8 +1124,8 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * r2.in.sids = NULL; r2.in.level = r->in.level; r2.in.count = r->in.count; - r2.in.lookup_options = 0; - r2.in.client_revision = 0; + r2.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; + r2.in.client_revision = LSA_CLIENT_REVISION_1; r2.out.count = r->out.count; r2.out.domains = r->out.domains; -- 2.13.6 From 2c5c18ec38ba3c0b1e4de8faf0108727bf035c48 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 20 Mar 2017 12:56:00 +0100 Subject: [PATCH 04/22] s4:rpc_server/lsa: make sure dcesrv_lsa_LookupSids_common() gets prepared [ref] pointers Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit f6e60d2c2e1f0a4eb6426c7da683abaa11babd05) --- source4/rpc_server/lsa/lsa_lookup.c | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index d0361417ef9..c2931c182c4 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -596,13 +596,16 @@ static NTSTATUS dcesrv_lsa_LookupSids_common(struct dcesrv_call_state *dce_call, NTSTATUS status = NT_STATUS_OK; uint32_t i; + *r->out.domains = NULL; + r->out.names->count = 0; + r->out.names->names = NULL; + *r->out.count = 0; + if (r->in.level < LSA_LOOKUP_NAMES_ALL || r->in.level > LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC) { return NT_STATUS_INVALID_PARAMETER; } - *r->out.domains = NULL; - /* NOTE: the WSPP test suite tries SIDs with invalid revision numbers, and expects NT_STATUS_INVALID_PARAMETER back - we just treat it as an unknown SID. We could add a SID validator here. (tridge) @@ -615,13 +618,6 @@ static NTSTATUS dcesrv_lsa_LookupSids_common(struct dcesrv_call_state *dce_call, } *r->out.domains = domains; - r->out.names = talloc_zero(mem_ctx, struct lsa_TransNameArray2); - if (r->out.names == NULL) { - return NT_STATUS_NO_MEMORY; - } - - *r->out.count = 0; - r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName2, r->in.sids->num_sids); if (r->out.names->names == NULL) { @@ -739,6 +735,11 @@ NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call, DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } + *r->out.domains = NULL; + r->out.names->count = 0; + r->out.names->names = NULL; + *r->out.count = 0; + status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, 0, /* we skip access checks */ &policy_state); @@ -790,17 +791,28 @@ NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *m DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } + *r->out.domains = NULL; + r->out.names->count = 0; + r->out.names->names = NULL; + *r->out.count = 0; + ZERO_STRUCT(r2); r2.in.handle = r->in.handle; r2.in.sids = r->in.sids; - r2.in.names = NULL; + r2.in.names = talloc_zero(mem_ctx, struct lsa_TransNameArray2); + if (r2.in.names == NULL) { + return NT_STATUS_NO_MEMORY; + } r2.in.level = r->in.level; r2.in.count = r->in.count; r2.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; r2.in.client_revision = LSA_CLIENT_REVISION_1; r2.out.count = r->out.count; - r2.out.names = NULL; + r2.out.names = talloc_zero(mem_ctx, struct lsa_TransNameArray2); + if (r2.out.names == NULL) { + return NT_STATUS_NO_MEMORY; + } r2.out.domains = r->out.domains; status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2); -- 2.13.6 From 390cb9fb695661de9e9fb4ce76c970e5d75e38fd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 20 Mar 2017 12:56:00 +0100 Subject: [PATCH 05/22] s4:rpc_server/lsa: expect prepared [ref] pointers in dcesrv_lsa_LookupNames_common() Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 3339a1c57266181570d5ca5e389719951f26b41d) --- source4/rpc_server/lsa/lsa_lookup.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index c2931c182c4..8c100144cd0 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -853,26 +853,22 @@ static NTSTATUS dcesrv_lsa_LookupNames_common(struct dcesrv_call_state *dce_call struct lsa_RefDomainList *domains; uint32_t i; + *r->out.domains = NULL; + r->out.sids->count = 0; + r->out.sids->sids = NULL; + *r->out.count = 0; + if (r->in.level < LSA_LOOKUP_NAMES_ALL || r->in.level > LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC) { return NT_STATUS_INVALID_PARAMETER; } - *r->out.domains = NULL; - - domains = talloc_zero(mem_ctx, struct lsa_RefDomainList); + domains = talloc_zero(r->out.domains, struct lsa_RefDomainList); if (domains == NULL) { return NT_STATUS_NO_MEMORY; } *r->out.domains = domains; - r->out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3); - if (r->out.sids == NULL) { - return NT_STATUS_NO_MEMORY; - } - - *r->out.count = 0; - r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid3, r->in.num_names); if (r->out.sids->sids == NULL) { @@ -979,6 +975,11 @@ NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } + *r->out.domains = NULL; + r->out.sids->count = 0; + r->out.sids->sids = NULL; + *r->out.count = 0; + status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, 0, /* we skip access checks */ &policy_state); -- 2.13.6 From 1511ada71d2762ed95da729608d7afdbf2ba2ad0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 20 Mar 2017 12:56:00 +0100 Subject: [PATCH 06/22] s4:rpc_server/lsa: make sure dcesrv_lsa_LookupNames2() gets prepared [ref] pointers Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit fe43dd8678e4f598e0ae802e3d93ad9b28988783) --- source4/rpc_server/lsa/lsa_lookup.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index 8c100144cd0..219e30194b7 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -1035,10 +1035,13 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } - *r->out.domains = NULL; - DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY); + *r->out.domains = NULL; + r->out.sids->count = 0; + r->out.sids->sids = NULL; + *r->out.count = 0; + if (r->in.level < LSA_LOOKUP_NAMES_ALL || r->in.level > LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC) { return NT_STATUS_INVALID_PARAMETER; @@ -1046,19 +1049,12 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, state = h->data; - domains = talloc_zero(mem_ctx, struct lsa_RefDomainList); + domains = talloc_zero(r->out.domains, struct lsa_RefDomainList); if (domains == NULL) { return NT_STATUS_NO_MEMORY; } *r->out.domains = domains; - r->out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray2); - if (r->out.sids == NULL) { - return NT_STATUS_NO_MEMORY; - } - - *r->out.count = 0; - r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid2, r->in.num_names); if (r->out.sids->sids == NULL) { @@ -1129,17 +1125,29 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } + *r->out.domains = NULL; + r->out.sids->count = 0; + r->out.sids->sids = NULL; + *r->out.count = 0; + ZERO_STRUCT(r2); r2.in.handle = r->in.handle; r2.in.num_names = r->in.num_names; r2.in.names = r->in.names; - r2.in.sids = NULL; + r2.in.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray2); + if (r2.in.sids == NULL) { + return NT_STATUS_NO_MEMORY; + } r2.in.level = r->in.level; r2.in.count = r->in.count; r2.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; r2.in.client_revision = LSA_CLIENT_REVISION_1; r2.out.count = r->out.count; + r2.out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray2); + if (r2.out.sids == NULL) { + return NT_STATUS_NO_MEMORY; + } r2.out.domains = r->out.domains; status = dcesrv_lsa_LookupNames2(dce_call, mem_ctx, &r2); -- 2.13.6 From f1ea21743ce28725849c5f3e56b99bd47b6c85c0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 20 Mar 2017 12:56:00 +0100 Subject: [PATCH 07/22] s4:rpc_server/lsa: remove unused 'status' variable in dcesrv_lsa_LookupSids_common() Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit e8a0223633fd2e6ebb3d864570b76932bc3e293a) --- source4/rpc_server/lsa/lsa_lookup.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index 219e30194b7..a8a136b1266 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -593,7 +593,6 @@ static NTSTATUS dcesrv_lsa_LookupSids_common(struct dcesrv_call_state *dce_call, struct lsa_LookupSids2 *r) { struct lsa_RefDomainList *domains = NULL; - NTSTATUS status = NT_STATUS_OK; uint32_t i; *r->out.domains = NULL; @@ -641,14 +640,12 @@ static NTSTATUS dcesrv_lsa_LookupSids_common(struct dcesrv_call_state *dce_call, if (sid_str == NULL) { r->out.names->names[i].name.string = "(SIDERROR)"; - status = STATUS_SOME_UNMAPPED; continue; } status2 = dcesrv_lsa_lookup_sid(state, mem_ctx, sid, sid_str, &authority_name, &name, &rtype); if (!NT_STATUS_IS_OK(status2)) { - status = STATUS_SOME_UNMAPPED; continue; } @@ -675,7 +672,7 @@ static NTSTATUS dcesrv_lsa_LookupSids_common(struct dcesrv_call_state *dce_call, return STATUS_SOME_UNMAPPED; } - return status; + return NT_STATUS_OK; } /* -- 2.13.6 From 3f81a05c900a3ba91dce6b78f1fc1e5ab824ab23 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 20 Mar 2017 12:56:00 +0100 Subject: [PATCH 08/22] s4:rpc_server/lsa: simplify [ref] pointer handling in dcesrv_lsa_LookupSids() Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 5d868fd875803e361653ccca4e61c5c25dc114aa) --- source4/rpc_server/lsa/lsa_lookup.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index a8a136b1266..400b5214a1a 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -793,6 +793,13 @@ NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *m r->out.names->names = NULL; *r->out.count = 0; + r->out.names->names = talloc_zero_array(r->out.names, + struct lsa_TranslatedName, + r->in.sids->num_sids); + if (r->out.names->names == NULL) { + return NT_STATUS_NO_MEMORY; + } + ZERO_STRUCT(r2); r2.in.handle = r->in.handle; @@ -816,27 +823,13 @@ NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *m /* we deliberately don't check for error from the above, as even on error we are supposed to return the names */ - r->out.domains = r2.out.domains; - if (!r2.out.names) { - r->out.names = NULL; - return status; - } - - r->out.names = talloc(mem_ctx, struct lsa_TransNameArray); - if (r->out.names == NULL) { - return NT_STATUS_NO_MEMORY; - } - r->out.names->count = r2.out.names->count; - r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName, - r->out.names->count); - if (r->out.names->names == NULL) { - return NT_STATUS_NO_MEMORY; - } - for (i=0;iout.names->count;i++) { + SMB_ASSERT(r2.out.names->count <= r->in.sids->num_sids); + for (i=0;icount;i++) { r->out.names->names[i].sid_type = r2.out.names->names[i].sid_type; r->out.names->names[i].name.string = r2.out.names->names[i].name.string; r->out.names->names[i].sid_index = r2.out.names->names[i].sid_index; } + r->out.names->count = r2.out.names->count; return status; } -- 2.13.6 From 5213ccdfdb03eeb86f94413dc4a198207e88abef Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 20 Mar 2017 12:56:00 +0100 Subject: [PATCH 09/22] s4:rpc_server/lsa: simplify [ref] pointer handling in dcesrv_lsa_LookupNames() Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 7c1c9bf53ffc24a25038326767e33f008c7a5552) --- source4/rpc_server/lsa/lsa_lookup.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index 400b5214a1a..defcef5089a 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -1120,6 +1120,13 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * r->out.sids->sids = NULL; *r->out.count = 0; + r->out.sids->sids = talloc_zero_array(r->out.sids, + struct lsa_TranslatedSid, + r->in.num_names); + if (r->out.sids->sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + ZERO_STRUCT(r2); r2.in.handle = r->in.handle; @@ -1141,25 +1148,14 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * r2.out.domains = r->out.domains; status = dcesrv_lsa_LookupNames2(dce_call, mem_ctx, &r2); - if (r2.out.sids == NULL) { - return status; - } - r->out.sids = talloc(mem_ctx, struct lsa_TransSidArray); - if (r->out.sids == NULL) { - return NT_STATUS_NO_MEMORY; - } - r->out.sids->count = r2.out.sids->count; - r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid, - r->out.sids->count); - if (r->out.sids->sids == NULL) { - return NT_STATUS_NO_MEMORY; - } - for (i=0;iout.sids->count;i++) { + SMB_ASSERT(r2.out.sids->count <= r->in.num_names); + for (i=0;icount;i++) { r->out.sids->sids[i].sid_type = r2.out.sids->sids[i].sid_type; r->out.sids->sids[i].rid = r2.out.sids->sids[i].rid; r->out.sids->sids[i].sid_index = r2.out.sids->sids[i].sid_index; } + r->out.sids->count = r2.out.sids->count; return status; } -- 2.13.6 From 0b2c7c16f6fa7c74a5ac047a79cfda0a32de31ed Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 22 Jan 2018 09:27:49 +0100 Subject: [PATCH 10/22] s4:rpc_server/lsa: rename 'state' variable to 'policy_state' in dcesrv_lsa_LookupSids_common() Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit c0f6103ddea9a825f0f0dcf169e70a5f6a55c2e2) --- source4/rpc_server/lsa/lsa_lookup.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index defcef5089a..378aff055e8 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -589,7 +589,7 @@ static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX static NTSTATUS dcesrv_lsa_LookupSids_common(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, - struct lsa_policy_state *state, + struct lsa_policy_state *policy_state, struct lsa_LookupSids2 *r) { struct lsa_RefDomainList *domains = NULL; @@ -643,15 +643,15 @@ static NTSTATUS dcesrv_lsa_LookupSids_common(struct dcesrv_call_state *dce_call, continue; } - status2 = dcesrv_lsa_lookup_sid(state, mem_ctx, sid, sid_str, + status2 = dcesrv_lsa_lookup_sid(policy_state, mem_ctx, sid, sid_str, &authority_name, &name, &rtype); if (!NT_STATUS_IS_OK(status2)) { continue; } /* set up the authority table */ - status2 = dcesrv_lsa_authority_list(state, mem_ctx, rtype, - authority_name, sid, + status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, rtype, + authority_name, sid, domains, &sid_index); if (!NT_STATUS_IS_OK(status2)) { continue; -- 2.13.6 From 431f4f628115301d2b305e6829cf7a342e6b903f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 22 Jan 2018 09:27:49 +0100 Subject: [PATCH 11/22] s4:rpc_server/lsa: rename 'state' variable to 'policy_state' in dcesrv_lsa_LookupSids2() Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit c78c17dc2fbaf523d1957bb748aa75ecd81e793b) --- source4/rpc_server/lsa/lsa_lookup.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index 378aff055e8..65c664ebfb8 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -684,20 +684,20 @@ NTSTATUS dcesrv_lsa_LookupSids2(struct dcesrv_call_state *dce_call, { enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); - struct lsa_policy_state *state; - struct dcesrv_handle *h; + struct lsa_policy_state *policy_state = NULL; + struct dcesrv_handle *policy_handle = NULL; if (transport != NCACN_NP && transport != NCALRPC) { DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } - DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY); + DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY); - state = h->data; + policy_state = policy_handle->data; return dcesrv_lsa_LookupSids_common(dce_call, mem_ctx, - state, + policy_state, r); } -- 2.13.6 From 824586641d74b845c9710d2729eda33d0061c5fa Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 22 Jan 2018 09:27:49 +0100 Subject: [PATCH 12/22] s4:rpc_server/lsa: rename 'state' variable to 'policy_state' in dcesrv_lsa_LookupNames2() Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit ec55c18ceda5c430eaec97c5d7e594941e3a31fc) --- source4/rpc_server/lsa/lsa_lookup.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index 65c664ebfb8..cefc48fcd8b 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -1015,8 +1015,8 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, { enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); - struct lsa_policy_state *state; - struct dcesrv_handle *h; + struct lsa_policy_state *policy_state = NULL; + struct dcesrv_handle *policy_handle = NULL; uint32_t i; struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; struct lsa_RefDomainList *domains; @@ -1025,7 +1025,9 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } - DCESRV_PULL_HANDLE(h, r->in.handle, LSA_HANDLE_POLICY); + DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY); + + policy_state = policy_handle->data; *r->out.domains = NULL; r->out.sids->count = 0; @@ -1037,8 +1039,6 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, return NT_STATUS_INVALID_PARAMETER; } - state = h->data; - domains = talloc_zero(r->out.domains, struct lsa_RefDomainList); if (domains == NULL) { return NT_STATUS_NO_MEMORY; @@ -1069,14 +1069,17 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, r->out.sids->sids[i].sid_index = 0xFFFFFFFF; r->out.sids->sids[i].unknown = 0; - status2 = dcesrv_lsa_lookup_name(dce_call->event_ctx, lp_ctx, state, mem_ctx, name, - &authority_name, &sid, &rtype, &rid); + status2 = dcesrv_lsa_lookup_name(dce_call->event_ctx, lp_ctx, + policy_state, mem_ctx, name, + &authority_name, &sid, &rtype, + &rid); if (!NT_STATUS_IS_OK(status2)) { continue; } - status2 = dcesrv_lsa_authority_list(state, mem_ctx, rtype, authority_name, - sid, domains, &sid_index); + status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, + rtype, authority_name, sid, + domains, &sid_index); if (!NT_STATUS_IS_OK(status2)) { continue; } -- 2.13.6 From 0004db17a238bbdc0ce290473a82f4ff7ee1c768 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 22 Jan 2018 20:21:14 +0100 Subject: [PATCH 13/22] s4:rpc_server/lsa: base dcesrv_lsa_LookupNames() on dcesrv_lsa_LookupNames_common() Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 37cb34d16406d27831be74e952ee744e58b79fb4) --- source4/rpc_server/lsa/lsa_lookup.c | 43 +++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index cefc48fcd8b..1e9b4c6cd9e 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -1110,7 +1110,9 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * { enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); - struct lsa_LookupNames2 r2; + struct lsa_policy_state *policy_state = NULL; + struct dcesrv_handle *policy_handle = NULL; + struct lsa_LookupNames3 r2; NTSTATUS status; uint32_t i; @@ -1118,6 +1120,10 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } + DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY); + + policy_state = policy_handle->data; + *r->out.domains = NULL; r->out.sids->count = 0; r->out.sids->sids = NULL; @@ -1135,7 +1141,7 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * r2.in.handle = r->in.handle; r2.in.num_names = r->in.num_names; r2.in.names = r->in.names; - r2.in.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray2); + r2.in.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3); if (r2.in.sids == NULL) { return NT_STATUS_NO_MEMORY; } @@ -1144,19 +1150,42 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * r2.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; r2.in.client_revision = LSA_CLIENT_REVISION_1; r2.out.count = r->out.count; - r2.out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray2); + r2.out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3); if (r2.out.sids == NULL) { return NT_STATUS_NO_MEMORY; } r2.out.domains = r->out.domains; - status = dcesrv_lsa_LookupNames2(dce_call, mem_ctx, &r2); + status = dcesrv_lsa_LookupNames_common(dce_call, + mem_ctx, + policy_state, + &r2); SMB_ASSERT(r2.out.sids->count <= r->in.num_names); for (i=0;icount;i++) { - r->out.sids->sids[i].sid_type = r2.out.sids->sids[i].sid_type; - r->out.sids->sids[i].rid = r2.out.sids->sids[i].rid; - r->out.sids->sids[i].sid_index = r2.out.sids->sids[i].sid_index; + struct lsa_TranslatedSid3 *s3 = + &r2.out.sids->sids[i]; + struct lsa_TranslatedSid *s = + &r->out.sids->sids[i]; + + s->sid_type = s3->sid_type; + if (s3->sid_type == SID_NAME_DOMAIN) { + s->rid = UINT32_MAX; + } else if (s3->flags & 0x00000004) { + s->rid = UINT32_MAX; + } else if (s3->sid == NULL) { + /* + * MS-LSAT 3.1.4.7 - rid zero is considered + * equivalent to sid NULL - so we should return + * 0 rid for unmapped entries + */ + s->rid = 0; + } else { + s->rid = 0; + dom_sid_split_rid(NULL, s3->sid, + NULL, &s->rid); + } + s->sid_index = s3->sid_index; } r->out.sids->count = r2.out.sids->count; -- 2.13.6 From 666732ecd4be7f1468c3ab9e96f4a1ae9dc98bd7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 22 Jan 2018 20:21:14 +0100 Subject: [PATCH 14/22] s4:rpc_server/lsa: base dcesrv_lsa_LookupNames2() on dcesrv_lsa_LookupNames_common() Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit e6c9984bd563525dc312b67fe69ea7e4be04ee4e) --- source4/rpc_server/lsa/lsa_lookup.c | 114 ++++++++++++++++++------------------ 1 file changed, 58 insertions(+), 56 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index 1e9b4c6cd9e..bb14cf7a16b 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -1017,9 +1017,9 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); struct lsa_policy_state *policy_state = NULL; struct dcesrv_handle *policy_handle = NULL; + struct lsa_LookupNames3 r2; + NTSTATUS status; uint32_t i; - struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; - struct lsa_RefDomainList *domains; if (transport != NCACN_NP && transport != NCALRPC) { DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); @@ -1034,72 +1034,74 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, r->out.sids->sids = NULL; *r->out.count = 0; - if (r->in.level < LSA_LOOKUP_NAMES_ALL || - r->in.level > LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC) { - return NT_STATUS_INVALID_PARAMETER; + r->out.sids->sids = talloc_zero_array(r->out.sids, + struct lsa_TranslatedSid2, + r->in.num_names); + if (r->out.sids->sids == NULL) { + return NT_STATUS_NO_MEMORY; } - domains = talloc_zero(r->out.domains, struct lsa_RefDomainList); - if (domains == NULL) { + ZERO_STRUCT(r2); + + r2.in.handle = r->in.handle; + r2.in.num_names = r->in.num_names; + r2.in.names = r->in.names; + r2.in.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3); + if (r2.in.sids == NULL) { return NT_STATUS_NO_MEMORY; } - *r->out.domains = domains; - - r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid2, - r->in.num_names); - if (r->out.sids->sids == NULL) { + r2.in.level = r->in.level; + r2.in.count = r->in.count; + /* + * MS-LSAT 3.1.4.7: + * + * The LookupOptions and ClientRevision parameters MUST be ignored. + * Message processing MUST happen as if LookupOptions is set to + * 0x00000000 and ClientRevision is set to 0x00000002. + */ + r2.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; + r2.in.client_revision = LSA_CLIENT_REVISION_2; + r2.out.count = r->out.count; + r2.out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3); + if (r2.out.sids == NULL) { return NT_STATUS_NO_MEMORY; } + r2.out.domains = r->out.domains; - for (i=0;iin.num_names;i++) { - const char *name = r->in.names[i].string; - const char *authority_name; - struct dom_sid *sid; - uint32_t sid_index, rid=0; - enum lsa_SidType rtype; - NTSTATUS status2; - - r->out.sids->count++; - - r->out.sids->sids[i].sid_type = SID_NAME_UNKNOWN; - /* MS-LSAT 3.1.4.7 - rid zero is considered equivalent - to sid NULL - so we should return 0 rid for - unmapped entries */ - r->out.sids->sids[i].rid = 0; - r->out.sids->sids[i].sid_index = 0xFFFFFFFF; - r->out.sids->sids[i].unknown = 0; + status = dcesrv_lsa_LookupNames_common(dce_call, + mem_ctx, + policy_state, + &r2); - status2 = dcesrv_lsa_lookup_name(dce_call->event_ctx, lp_ctx, - policy_state, mem_ctx, name, - &authority_name, &sid, &rtype, - &rid); - if (!NT_STATUS_IS_OK(status2)) { - continue; - } + SMB_ASSERT(r2.out.sids->count <= r->in.num_names); + for (i=0;icount;i++) { + struct lsa_TranslatedSid3 *s3 = + &r2.out.sids->sids[i]; + struct lsa_TranslatedSid2 *s2 = + &r->out.sids->sids[i]; - status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, - rtype, authority_name, sid, - domains, &sid_index); - if (!NT_STATUS_IS_OK(status2)) { - continue; + s2->sid_type = s3->sid_type; + if (s3->sid_type == SID_NAME_DOMAIN) { + s2->rid = UINT32_MAX; + } else if (s3->flags & 0x00000004) { + s2->rid = UINT32_MAX; + } else if (s3->sid == NULL) { + /* + * MS-LSAT 3.1.4.7 - rid zero is considered + * equivalent to sid NULL - so we should return + * 0 rid for unmapped entries + */ + s2->rid = 0; + } else { + s2->rid = 0; + dom_sid_split_rid(NULL, s3->sid, + NULL, &s2->rid); } - - r->out.sids->sids[i].sid_type = rtype; - r->out.sids->sids[i].rid = rid; - r->out.sids->sids[i].sid_index = sid_index; - r->out.sids->sids[i].unknown = 0; - - (*r->out.count)++; - } - - if (*r->out.count == 0) { - return NT_STATUS_NONE_MAPPED; - } - if (*r->out.count != r->in.num_names) { - return STATUS_SOME_UNMAPPED; + s2->sid_index = s3->sid_index; } + r->out.sids->count = r2.out.sids->count; - return NT_STATUS_OK; + return status; } /* -- 2.13.6 From 38fe3d8ba0781480a03e6732daa2768fd5b2a5e4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 19 Jan 2018 13:42:40 +0100 Subject: [PATCH 15/22] s4:rpc_server/lsa: prepare dcesrv_lsa_LookupSids* for async processing Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit ab7988aa2fd1a43f576a4b73a6893c61c7ef1957) --- source4/rpc_server/lsa/lsa_lookup.c | 215 ++++++++++++++++++++++++++---------- 1 file changed, 157 insertions(+), 58 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index bb14cf7a16b..62d29d3173e 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -587,11 +587,27 @@ static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX return NT_STATUS_OK; } -static NTSTATUS dcesrv_lsa_LookupSids_common(struct dcesrv_call_state *dce_call, - TALLOC_CTX *mem_ctx, - struct lsa_policy_state *policy_state, - struct lsa_LookupSids2 *r) +struct dcesrv_lsa_LookupSids_base_state { + struct dcesrv_call_state *dce_call; + + TALLOC_CTX *mem_ctx; + + struct lsa_policy_state *policy_state; + + struct lsa_LookupSids3 r; + + struct { + struct lsa_LookupSids *l; + struct lsa_LookupSids2 *l2; + struct lsa_LookupSids3 *l3; + } _r; +}; + +static NTSTATUS dcesrv_lsa_LookupSids_base_call(struct dcesrv_lsa_LookupSids_base_state *state) { + struct lsa_policy_state *policy_state = state->policy_state; + TALLOC_CTX *mem_ctx = state->mem_ctx; + struct lsa_LookupSids3 *r = &state->r; struct lsa_RefDomainList *domains = NULL; uint32_t i; @@ -675,6 +691,45 @@ static NTSTATUS dcesrv_lsa_LookupSids_common(struct dcesrv_call_state *dce_call, return NT_STATUS_OK; } +static void dcesrv_lsa_LookupSids_base_map( + struct dcesrv_lsa_LookupSids_base_state *state) +{ + if (state->_r.l3 != NULL) { + struct lsa_LookupSids3 *r = state->_r.l3; + + r->out.result = state->r.out.result; + return; + } + + if (state->_r.l2 != NULL) { + struct lsa_LookupSids2 *r = state->_r.l2; + + r->out.result = state->r.out.result; + return; + } + + if (state->_r.l != NULL) { + struct lsa_LookupSids *r = state->_r.l; + uint32_t i; + + r->out.result = state->r.out.result; + + SMB_ASSERT(state->r.out.names->count <= r->in.sids->num_sids); + for (i = 0; i < state->r.out.names->count; i++) { + struct lsa_TranslatedName2 *n2 = + &state->r.out.names->names[i]; + struct lsa_TranslatedName *n = + &r->out.names->names[i]; + + n->sid_type = n2->sid_type; + n->name = n2->name; + n->sid_index = n2->sid_index; + } + r->out.names->count = state->r.out.names->count; + return; + } +} + /* lsa_LookupSids2 */ @@ -684,8 +739,9 @@ NTSTATUS dcesrv_lsa_LookupSids2(struct dcesrv_call_state *dce_call, { enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); - struct lsa_policy_state *policy_state = NULL; + struct dcesrv_lsa_LookupSids_base_state *state = NULL; struct dcesrv_handle *policy_handle = NULL; + NTSTATUS status; if (transport != NCACN_NP && transport != NCALRPC) { DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); @@ -693,12 +749,43 @@ NTSTATUS dcesrv_lsa_LookupSids2(struct dcesrv_call_state *dce_call, DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY); - policy_state = policy_handle->data; + *r->out.domains = NULL; + r->out.names->count = 0; + r->out.names->names = NULL; + *r->out.count = 0; + + state = talloc_zero(mem_ctx, struct dcesrv_lsa_LookupSids_base_state); + if (state == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->dce_call = dce_call; + state->mem_ctx = mem_ctx; + + state->policy_state = policy_handle->data; + + state->r.in.sids = r->in.sids; + state->r.in.level = r->in.level; + state->r.in.lookup_options = r->in.lookup_options; + state->r.in.client_revision = r->in.client_revision; + state->r.in.names = r->in.names; + state->r.in.count = r->in.count; + state->r.out.domains = r->out.domains; + state->r.out.names = r->out.names; + state->r.out.count = r->out.count; + + state->_r.l2 = r; - return dcesrv_lsa_LookupSids_common(dce_call, - mem_ctx, - policy_state, - r); + status = dcesrv_lsa_LookupSids_base_call(state); + + if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) { + return status; + } + + state->r.out.result = status; + dcesrv_lsa_LookupSids_base_map(state); + TALLOC_FREE(state); + return status; } @@ -715,8 +802,7 @@ NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call, enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); const struct dcesrv_auth *auth = &dce_call->conn->auth_state; - struct lsa_policy_state *policy_state; - struct lsa_LookupSids2 q; + struct dcesrv_lsa_LookupSids_base_state *state = NULL; NTSTATUS status; if (transport != NCACN_IP_TCP) { @@ -737,37 +823,42 @@ NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call, r->out.names->names = NULL; *r->out.count = 0; - status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, + state = talloc_zero(mem_ctx, struct dcesrv_lsa_LookupSids_base_state); + if (state == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->dce_call = dce_call; + state->mem_ctx = mem_ctx; + + status = dcesrv_lsa_get_policy_state(state->dce_call, mem_ctx, 0, /* we skip access checks */ - &policy_state); + &state->policy_state); if (!NT_STATUS_IS_OK(status)) { return status; } - ZERO_STRUCT(q); + state->r.in.sids = r->in.sids; + state->r.in.level = r->in.level; + state->r.in.lookup_options = r->in.lookup_options; + state->r.in.client_revision = r->in.client_revision; + state->r.in.names = r->in.names; + state->r.in.count = r->in.count; + state->r.out.domains = r->out.domains; + state->r.out.names = r->out.names; + state->r.out.count = r->out.count; - q.in.handle = NULL; - q.in.sids = r->in.sids; - q.in.names = r->in.names; - q.in.level = r->in.level; - q.in.count = r->in.count; - q.in.lookup_options = r->in.lookup_options; - q.in.client_revision = r->in.client_revision; - q.out.count = r->out.count; - q.out.names = r->out.names; - q.out.domains = r->out.domains; + state->_r.l3 = r; - status = dcesrv_lsa_LookupSids_common(dce_call, - mem_ctx, - policy_state, - &q); - - talloc_free(policy_state); + status = dcesrv_lsa_LookupSids_base_call(state); - r->out.count = q.out.count; - r->out.names = q.out.names; - r->out.domains = q.out.domains; + if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) { + return status; + } + state->r.out.result = status; + dcesrv_lsa_LookupSids_base_map(state); + TALLOC_FREE(state); return status; } @@ -780,14 +871,16 @@ NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *m { enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); - struct lsa_LookupSids2 r2; + struct dcesrv_lsa_LookupSids_base_state *state = NULL; + struct dcesrv_handle *policy_handle = NULL; NTSTATUS status; - uint32_t i; if (transport != NCACN_NP && transport != NCALRPC) { DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } + DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY); + *r->out.domains = NULL; r->out.names->count = 0; r->out.names->names = NULL; @@ -800,37 +893,43 @@ NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *m return NT_STATUS_NO_MEMORY; } - ZERO_STRUCT(r2); + state = talloc_zero(mem_ctx, struct dcesrv_lsa_LookupSids_base_state); + if (state == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->dce_call = dce_call; + state->mem_ctx = mem_ctx; + + state->policy_state = policy_handle->data; - r2.in.handle = r->in.handle; - r2.in.sids = r->in.sids; - r2.in.names = talloc_zero(mem_ctx, struct lsa_TransNameArray2); - if (r2.in.names == NULL) { + state->r.in.sids = r->in.sids; + state->r.in.level = r->in.level; + state->r.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; + state->r.in.client_revision = LSA_CLIENT_REVISION_1; + state->r.in.names = talloc_zero(state, struct lsa_TransNameArray2); + if (state->r.in.names == NULL) { return NT_STATUS_NO_MEMORY; } - r2.in.level = r->in.level; - r2.in.count = r->in.count; - r2.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; - r2.in.client_revision = LSA_CLIENT_REVISION_1; - r2.out.count = r->out.count; - r2.out.names = talloc_zero(mem_ctx, struct lsa_TransNameArray2); - if (r2.out.names == NULL) { + state->r.in.count = r->in.count; + state->r.out.domains = r->out.domains; + state->r.out.names = talloc_zero(state, struct lsa_TransNameArray2); + if (state->r.out.names == NULL) { return NT_STATUS_NO_MEMORY; } - r2.out.domains = r->out.domains; + state->r.out.count = r->out.count; - status = dcesrv_lsa_LookupSids2(dce_call, mem_ctx, &r2); - /* we deliberately don't check for error from the above, - as even on error we are supposed to return the names */ + state->_r.l = r; - SMB_ASSERT(r2.out.names->count <= r->in.sids->num_sids); - for (i=0;icount;i++) { - r->out.names->names[i].sid_type = r2.out.names->names[i].sid_type; - r->out.names->names[i].name.string = r2.out.names->names[i].name.string; - r->out.names->names[i].sid_index = r2.out.names->names[i].sid_index; + status = dcesrv_lsa_LookupSids_base_call(state); + + if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) { + return status; } - r->out.names->count = r2.out.names->count; + state->r.out.result = status; + dcesrv_lsa_LookupSids_base_map(state); + TALLOC_FREE(state); return status; } -- 2.13.6 From 74cd9c8dbdbf41421b4e9bd4128a604f39781f15 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 19 Jan 2018 13:42:40 +0100 Subject: [PATCH 16/22] s4:rpc_server/lsa: prepare dcesrv_lsa_LookupNames* for async processing Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 9b6a0b1a63f2ebfbd578047401dfbe38606c8c44) --- source4/rpc_server/lsa/lsa_lookup.c | 392 +++++++++++++++++++++++------------- 1 file changed, 250 insertions(+), 142 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index 62d29d3173e..83043cbe17e 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -933,13 +933,32 @@ NTSTATUS dcesrv_lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *m return status; } -static NTSTATUS dcesrv_lsa_LookupNames_common(struct dcesrv_call_state *dce_call, - TALLOC_CTX *mem_ctx, - struct lsa_policy_state *policy_state, - struct lsa_LookupNames3 *r) +struct dcesrv_lsa_LookupNames_base_state { + struct dcesrv_call_state *dce_call; + + TALLOC_CTX *mem_ctx; + + struct lsa_policy_state *policy_state; + + struct lsa_LookupNames4 r; + + struct { + struct lsa_LookupNames *l; + struct lsa_LookupNames2 *l2; + struct lsa_LookupNames3 *l3; + struct lsa_LookupNames4 *l4; + } _r; +}; + + +static NTSTATUS dcesrv_lsa_LookupNames_base_call(struct dcesrv_lsa_LookupNames_base_state *state) { - struct loadparm_context *lp_ctx = dce_call->conn->dce_ctx->lp_ctx; - struct lsa_RefDomainList *domains; + struct loadparm_context *lp_ctx = state->dce_call->conn->dce_ctx->lp_ctx; + struct dcesrv_call_state *dce_call = state->dce_call; + struct lsa_policy_state *policy_state = state->policy_state; + TALLOC_CTX *mem_ctx = state->mem_ctx; + struct lsa_LookupNames4 *r = &state->r; + struct lsa_RefDomainList *domains = NULL; uint32_t i; *r->out.domains = NULL; @@ -1009,6 +1028,97 @@ static NTSTATUS dcesrv_lsa_LookupNames_common(struct dcesrv_call_state *dce_call return NT_STATUS_OK; } +static void dcesrv_lsa_LookupNames_base_map( + struct dcesrv_lsa_LookupNames_base_state *state) +{ + if (state->_r.l4 != NULL) { + struct lsa_LookupNames4 *r = state->_r.l4; + + r->out.result = state->r.out.result; + return; + } + + if (state->_r.l3 != NULL) { + struct lsa_LookupNames3 *r = state->_r.l3; + + r->out.result = state->r.out.result; + return; + } + + if (state->_r.l2 != NULL) { + struct lsa_LookupNames2 *r = state->_r.l2; + uint32_t i; + + r->out.result = state->r.out.result; + + SMB_ASSERT(state->r.out.sids->count <= r->in.num_names); + for (i = 0; i < state->r.out.sids->count; i++) { + const struct lsa_TranslatedSid3 *s3 = + &state->r.out.sids->sids[i]; + struct lsa_TranslatedSid2 *s2 = + &r->out.sids->sids[i]; + + s2->sid_type = s3->sid_type; + if (s3->sid_type == SID_NAME_DOMAIN) { + s2->rid = UINT32_MAX; + } else if (s3->flags & 0x00000004) { + s2->rid = UINT32_MAX; + } else if (s3->sid == NULL) { + /* + * MS-LSAT 3.1.4.7 - rid zero is considered + * equivalent to sid NULL - so we should return + * 0 rid for unmapped entries + */ + s2->rid = 0; + } else { + s2->rid = 0; + dom_sid_split_rid(NULL, s3->sid, + NULL, &s2->rid); + } + s2->sid_index = s3->sid_index; + s2->unknown = s3->flags; + } + r->out.sids->count = state->r.out.sids->count; + return; + } + + if (state->_r.l != NULL) { + struct lsa_LookupNames *r = state->_r.l; + uint32_t i; + + r->out.result = state->r.out.result; + + SMB_ASSERT(state->r.out.sids->count <= r->in.num_names); + for (i = 0; i < state->r.out.sids->count; i++) { + struct lsa_TranslatedSid3 *s3 = + &state->r.out.sids->sids[i]; + struct lsa_TranslatedSid *s = + &r->out.sids->sids[i]; + + s->sid_type = s3->sid_type; + if (s3->sid_type == SID_NAME_DOMAIN) { + s->rid = UINT32_MAX; + } else if (s3->flags & 0x00000004) { + s->rid = UINT32_MAX; + } else if (s3->sid == NULL) { + /* + * MS-LSAT 3.1.4.7 - rid zero is considered + * equivalent to sid NULL - so we should return + * 0 rid for unmapped entries + */ + s->rid = 0; + } else { + s->rid = 0; + dom_sid_split_rid(NULL, s3->sid, + NULL, &s->rid); + } + s->sid_index = s3->sid_index; + } + r->out.sids->count = state->r.out.sids->count; + return; + } +} + /* lsa_LookupNames3 */ @@ -1018,8 +1128,9 @@ NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call, { enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); - struct lsa_policy_state *policy_state; - struct dcesrv_handle *policy_handle; + struct dcesrv_lsa_LookupNames_base_state *state = NULL; + struct dcesrv_handle *policy_handle = NULL; + NTSTATUS status; if (transport != NCACN_NP && transport != NCALRPC) { DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); @@ -1027,12 +1138,44 @@ NTSTATUS dcesrv_lsa_LookupNames3(struct dcesrv_call_state *dce_call, DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY); - policy_state = policy_handle->data; + *r->out.domains = NULL; + r->out.sids->count = 0; + r->out.sids->sids = NULL; + *r->out.count = 0; + + state = talloc_zero(mem_ctx, struct dcesrv_lsa_LookupNames_base_state); + if (state == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->dce_call = dce_call; + state->mem_ctx = mem_ctx; + + state->policy_state = policy_handle->data; + + state->r.in.num_names = r->in.num_names; + state->r.in.names = r->in.names; + state->r.in.level = r->in.level; + state->r.in.lookup_options = r->in.lookup_options; + state->r.in.client_revision = r->in.client_revision; + state->r.in.sids = r->in.sids; + state->r.in.count = r->in.count; + state->r.out.domains = r->out.domains; + state->r.out.sids = r->out.sids; + state->r.out.count = r->out.count; + + state->_r.l3 = r; + + status = dcesrv_lsa_LookupNames_base_call(state); - return dcesrv_lsa_LookupNames_common(dce_call, - mem_ctx, - policy_state, - r); + if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) { + return status; + } + + state->r.out.result = status; + dcesrv_lsa_LookupNames_base_map(state); + TALLOC_FREE(state); + return status; } /* @@ -1047,8 +1190,7 @@ NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); const struct dcesrv_auth *auth = &dce_call->conn->auth_state; - struct lsa_policy_state *policy_state; - struct lsa_LookupNames3 q; + struct dcesrv_lsa_LookupNames_base_state *state = NULL; NTSTATUS status; if (transport != NCACN_IP_TCP) { @@ -1069,39 +1211,43 @@ NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX r->out.sids->sids = NULL; *r->out.count = 0; - status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, + state = talloc_zero(mem_ctx, struct dcesrv_lsa_LookupNames_base_state); + if (state == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->dce_call = dce_call; + state->mem_ctx = mem_ctx; + + status = dcesrv_lsa_get_policy_state(state->dce_call, state, 0, /* we skip access checks */ - &policy_state); + &state->policy_state); if (!NT_STATUS_IS_OK(status)) { return status; } - ZERO_STRUCT(q); - - q.in.handle = NULL; - q.in.num_names = r->in.num_names; - q.in.names = r->in.names; - q.in.level = r->in.level; - q.in.sids = r->in.sids; - q.in.count = r->in.count; - q.in.lookup_options = r->in.lookup_options; - q.in.client_revision = r->in.client_revision; - - q.out.count = r->out.count; - q.out.sids = r->out.sids; - q.out.domains = r->out.domains; + state->r.in.num_names = r->in.num_names; + state->r.in.names = r->in.names; + state->r.in.level = r->in.level; + state->r.in.lookup_options = r->in.lookup_options; + state->r.in.client_revision = r->in.client_revision; + state->r.in.sids = r->in.sids; + state->r.in.count = r->in.count; + state->r.out.domains = r->out.domains; + state->r.out.sids = r->out.sids; + state->r.out.count = r->out.count; - status = dcesrv_lsa_LookupNames_common(dce_call, - mem_ctx, - policy_state, - &q); + state->_r.l4 = r; - talloc_free(policy_state); + status = dcesrv_lsa_LookupNames_base_call(state); - r->out.count = q.out.count; - r->out.sids = q.out.sids; - r->out.domains = q.out.domains; + if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) { + return status; + } + state->r.out.result = status; + dcesrv_lsa_LookupNames_base_map(state); + TALLOC_FREE(state); return status; } @@ -1114,11 +1260,9 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, { enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); - struct lsa_policy_state *policy_state = NULL; + struct dcesrv_lsa_LookupNames_base_state *state = NULL; struct dcesrv_handle *policy_handle = NULL; - struct lsa_LookupNames3 r2; NTSTATUS status; - uint32_t i; if (transport != NCACN_NP && transport != NCALRPC) { DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); @@ -1126,8 +1270,6 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY); - policy_state = policy_handle->data; - *r->out.domains = NULL; r->out.sids->count = 0; r->out.sids->sids = NULL; @@ -1140,17 +1282,19 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, return NT_STATUS_NO_MEMORY; } - ZERO_STRUCT(r2); - - r2.in.handle = r->in.handle; - r2.in.num_names = r->in.num_names; - r2.in.names = r->in.names; - r2.in.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3); - if (r2.in.sids == NULL) { + state = talloc_zero(mem_ctx, struct dcesrv_lsa_LookupNames_base_state); + if (state == NULL) { return NT_STATUS_NO_MEMORY; } - r2.in.level = r->in.level; - r2.in.count = r->in.count; + + state->dce_call = dce_call; + state->mem_ctx = mem_ctx; + + state->policy_state = policy_handle->data; + + state->r.in.num_names = r->in.num_names; + state->r.in.names = r->in.names; + state->r.in.level = r->in.level; /* * MS-LSAT 3.1.4.7: * @@ -1158,48 +1302,31 @@ NTSTATUS dcesrv_lsa_LookupNames2(struct dcesrv_call_state *dce_call, * Message processing MUST happen as if LookupOptions is set to * 0x00000000 and ClientRevision is set to 0x00000002. */ - r2.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; - r2.in.client_revision = LSA_CLIENT_REVISION_2; - r2.out.count = r->out.count; - r2.out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3); - if (r2.out.sids == NULL) { + state->r.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; + state->r.in.client_revision = LSA_CLIENT_REVISION_2; + state->r.in.sids = talloc_zero(state, struct lsa_TransSidArray3); + if (state->r.in.sids == NULL) { return NT_STATUS_NO_MEMORY; } - r2.out.domains = r->out.domains; - - status = dcesrv_lsa_LookupNames_common(dce_call, - mem_ctx, - policy_state, - &r2); - - SMB_ASSERT(r2.out.sids->count <= r->in.num_names); - for (i=0;icount;i++) { - struct lsa_TranslatedSid3 *s3 = - &r2.out.sids->sids[i]; - struct lsa_TranslatedSid2 *s2 = - &r->out.sids->sids[i]; - - s2->sid_type = s3->sid_type; - if (s3->sid_type == SID_NAME_DOMAIN) { - s2->rid = UINT32_MAX; - } else if (s3->flags & 0x00000004) { - s2->rid = UINT32_MAX; - } else if (s3->sid == NULL) { - /* - * MS-LSAT 3.1.4.7 - rid zero is considered - * equivalent to sid NULL - so we should return - * 0 rid for unmapped entries - */ - s2->rid = 0; - } else { - s2->rid = 0; - dom_sid_split_rid(NULL, s3->sid, - NULL, &s2->rid); - } - s2->sid_index = s3->sid_index; + state->r.in.count = r->in.count; + state->r.out.domains = r->out.domains; + state->r.out.sids = talloc_zero(state, struct lsa_TransSidArray3); + if (state->r.out.sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + state->r.out.count = r->out.count; + + state->_r.l2 = r; + + status = dcesrv_lsa_LookupNames_base_call(state); + + if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) { + return status; } - r->out.sids->count = r2.out.sids->count; + state->r.out.result = status; + dcesrv_lsa_LookupNames_base_map(state); + TALLOC_FREE(state); return status; } @@ -1211,11 +1338,9 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * { enum dcerpc_transport_t transport = dcerpc_binding_get_transport(dce_call->conn->endpoint->ep_description); - struct lsa_policy_state *policy_state = NULL; + struct dcesrv_lsa_LookupNames_base_state *state = NULL; struct dcesrv_handle *policy_handle = NULL; - struct lsa_LookupNames3 r2; NTSTATUS status; - uint32_t i; if (transport != NCACN_NP && transport != NCALRPC) { DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); @@ -1223,8 +1348,6 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY); - policy_state = policy_handle->data; - *r->out.domains = NULL; r->out.sids->count = 0; r->out.sids->sids = NULL; @@ -1237,59 +1360,44 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * return NT_STATUS_NO_MEMORY; } - ZERO_STRUCT(r2); + state = talloc_zero(mem_ctx, struct dcesrv_lsa_LookupNames_base_state); + if (state == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->dce_call = dce_call; + state->mem_ctx = mem_ctx; + + state->policy_state = policy_handle->data; - r2.in.handle = r->in.handle; - r2.in.num_names = r->in.num_names; - r2.in.names = r->in.names; - r2.in.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3); - if (r2.in.sids == NULL) { + state->r.in.num_names = r->in.num_names; + state->r.in.names = r->in.names; + state->r.in.level = r->in.level; + state->r.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; + state->r.in.client_revision = LSA_CLIENT_REVISION_1; + state->r.in.sids = talloc_zero(state, struct lsa_TransSidArray3); + if (state->r.in.sids == NULL) { return NT_STATUS_NO_MEMORY; } - r2.in.level = r->in.level; - r2.in.count = r->in.count; - r2.in.lookup_options = LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES; - r2.in.client_revision = LSA_CLIENT_REVISION_1; - r2.out.count = r->out.count; - r2.out.sids = talloc_zero(mem_ctx, struct lsa_TransSidArray3); - if (r2.out.sids == NULL) { + state->r.in.count = r->in.count; + state->r.out.domains = r->out.domains; + state->r.out.sids = talloc_zero(state, struct lsa_TransSidArray3); + if (state->r.out.sids == NULL) { return NT_STATUS_NO_MEMORY; } - r2.out.domains = r->out.domains; - - status = dcesrv_lsa_LookupNames_common(dce_call, - mem_ctx, - policy_state, - &r2); - - SMB_ASSERT(r2.out.sids->count <= r->in.num_names); - for (i=0;icount;i++) { - struct lsa_TranslatedSid3 *s3 = - &r2.out.sids->sids[i]; - struct lsa_TranslatedSid *s = - &r->out.sids->sids[i]; - - s->sid_type = s3->sid_type; - if (s3->sid_type == SID_NAME_DOMAIN) { - s->rid = UINT32_MAX; - } else if (s3->flags & 0x00000004) { - s->rid = UINT32_MAX; - } else if (s3->sid == NULL) { - /* - * MS-LSAT 3.1.4.7 - rid zero is considered - * equivalent to sid NULL - so we should return - * 0 rid for unmapped entries - */ - s->rid = 0; - } else { - s->rid = 0; - dom_sid_split_rid(NULL, s3->sid, - NULL, &s->rid); - } - s->sid_index = s3->sid_index; + state->r.out.count = r->out.count; + + state->_r.l = r; + + status = dcesrv_lsa_LookupNames_base_call(state); + + if (dce_call->state_flags & DCESRV_CALL_STATE_FLAG_ASYNC) { + return status; } - r->out.sids->count = r2.out.sids->count; + state->r.out.result = status; + dcesrv_lsa_LookupNames_base_map(state); + TALLOC_FREE(state); return status; } -- 2.13.6 From 9dedb68a6251a7b82c25a78e907e4db77a57fada Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 16 Feb 2018 01:14:00 +0100 Subject: [PATCH 17/22] s4:dsdb: add dsdb_trust_domain_by_{sid,name}() This gets the lsa_ForestTrustDomainInfo for the searched domain as well as the lsa_TrustDomainInfoInfoEx for the direct trust (which might be the same for external trust or the forest root domain). Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit e9ace1852ff88ebb7778e8db9a49bc5c61512d16) --- source4/dsdb/common/util_trusts.c | 222 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) diff --git a/source4/dsdb/common/util_trusts.c b/source4/dsdb/common/util_trusts.c index 1534829199b..7dcbea2ce6d 100644 --- a/source4/dsdb/common/util_trusts.c +++ b/source4/dsdb/common/util_trusts.c @@ -2822,6 +2822,9 @@ struct dsdb_trust_routing_domain { struct dsdb_trust_routing_domain *prev, *next; struct lsa_TrustDomainInfoInfoEx *tdo; + + struct lsa_ForestTrustDomainInfo di; + struct lsa_ForestTrustInformation *fti; }; @@ -2881,6 +2884,10 @@ NTSTATUS dsdb_trust_routing_table_load(struct ldb_context *sam_ctx, return status; } + d->di.domain_sid = d->tdo->sid; + d->di.netbios_domain_name.string = d->tdo->netbios_name.string; + d->di.dns_domain_name.string = d->tdo->domain_name.string; + if (root_trust_tdo != NULL) { root_direction_tdo = root_trust_tdo; } else if (trust_parent_tdo != NULL) { @@ -2923,6 +2930,10 @@ NTSTATUS dsdb_trust_routing_table_load(struct ldb_context *sam_ctx, return status; } + d->di.domain_sid = d->tdo->sid; + d->di.netbios_domain_name.string = d->tdo->netbios_name.string; + d->di.dns_domain_name.string = d->tdo->domain_name.string; + DLIST_ADD_END(table->domains, d); if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) { @@ -3197,3 +3208,214 @@ const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_routing_by_name( return NULL; } + +const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_domain_by_sid( + const struct dsdb_trust_routing_table *table, + const struct dom_sid *sid, + const struct lsa_ForestTrustDomainInfo **pdi) +{ + const struct dsdb_trust_routing_domain *d = NULL; + + if (pdi != NULL) { + *pdi = NULL; + } + + if (sid == NULL) { + return NULL; + } + + for (d = table->domains; d != NULL; d = d->next) { + bool transitive = false; + uint32_t i; + + if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) { + transitive = true; + } + + if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) { + transitive = true; + } + + if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) { + transitive = false; + } + + if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) { + transitive = false; + } + + if (!transitive || d->fti == NULL) { + bool match = false; + + match = dom_sid_equal(d->di.domain_sid, sid); + if (match) { + /* + * exact match, it's the domain itself. + */ + if (pdi != NULL) { + *pdi = &d->di; + } + return d->tdo; + } + continue; + } + + for (i = 0; i < d->fti->count; i++ ) { + const struct lsa_ForestTrustRecord *f = d->fti->entries[i]; + const struct lsa_ForestTrustDomainInfo *di = NULL; + const struct dom_sid *fti_sid = NULL; + bool match = false; + + if (f == NULL) { + /* broken record */ + continue; + } + + if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) { + continue; + } + + if (f->flags & LSA_SID_DISABLED_MASK) { + /* + * any flag disables the entry. + */ + continue; + } + + di = &f->forest_trust_data.domain_info; + fti_sid = di->domain_sid; + if (fti_sid == NULL) { + /* broken record */ + continue; + } + + match = dom_sid_equal(fti_sid, sid); + if (match) { + /* + * exact match, it's a domain in the forest. + */ + if (pdi != NULL) { + *pdi = di; + } + return d->tdo; + } + } + } + + return NULL; +} + +const struct lsa_TrustDomainInfoInfoEx *dsdb_trust_domain_by_name( + const struct dsdb_trust_routing_table *table, + const char *name, + const struct lsa_ForestTrustDomainInfo **pdi) +{ + const struct dsdb_trust_routing_domain *d = NULL; + + if (pdi != NULL) { + *pdi = NULL; + } + + if (name == NULL) { + return NULL; + } + + for (d = table->domains; d != NULL; d = d->next) { + bool transitive = false; + uint32_t i; + + if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) { + transitive = true; + } + + if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) { + transitive = true; + } + + if (d->tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) { + transitive = false; + } + + if (d->tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) { + transitive = false; + } + + if (!transitive || d->fti == NULL) { + bool match = false; + + match = strequal_m(d->di.netbios_domain_name.string, + name); + if (match) { + /* + * exact match for netbios name, + * it's the domain itself. + */ + if (pdi != NULL) { + *pdi = &d->di; + } + return d->tdo; + } + match = strequal_m(d->di.dns_domain_name.string, + name); + if (match) { + /* + * exact match for dns name, + * it's the domain itself. + */ + if (pdi != NULL) { + *pdi = &d->di; + } + return d->tdo; + } + continue; + } + + for (i = 0; i < d->fti->count; i++ ) { + const struct lsa_ForestTrustRecord *f = d->fti->entries[i]; + const struct lsa_ForestTrustDomainInfo *di = NULL; + bool match = false; + + if (f == NULL) { + /* broken record */ + continue; + } + + if (f->type != LSA_FOREST_TRUST_DOMAIN_INFO) { + continue; + } + di = &f->forest_trust_data.domain_info; + + if (!(f->flags & LSA_NB_DISABLED_MASK)) { + match = strequal_m(di->netbios_domain_name.string, + name); + if (match) { + /* + * exact match for netbios name, + * it's a domain in the forest. + */ + if (pdi != NULL) { + *pdi = di; + } + return d->tdo; + } + } + + if (!(f->flags & LSA_TLN_DISABLED_MASK)) { + match = strequal_m(di->dns_domain_name.string, + name); + if (match) { + /* + * exact match for dns name, + * it's a domain in the forest. + */ + if (pdi != NULL) { + *pdi = di; + } + return d->tdo; + } + } + } + } + + return NULL; +} -- 2.13.6 From ec8c9aed8a4cd8879885611c81463d217670f36d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 20 Mar 2017 12:55:44 +0100 Subject: [PATCH 18/22] libcli/security: add dom_sid_lookup_predefined_{sid,name}() This basically implements [MS-LSAT] 3.1.1.1.1 Predefined Translation Database and Corresponding View. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit d7780c66866144eba59408c03af50256825165ba) --- libcli/security/dom_sid.h | 13 ++ libcli/security/util_sid.c | 499 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 512 insertions(+) diff --git a/libcli/security/dom_sid.h b/libcli/security/dom_sid.h index bdcec941d3f..6c3225e267d 100644 --- a/libcli/security/dom_sid.h +++ b/libcli/security/dom_sid.h @@ -62,6 +62,19 @@ extern const struct dom_sid global_sid_Unix_NFS_Groups; extern const struct dom_sid global_sid_Unix_NFS_Mode; extern const struct dom_sid global_sid_Unix_NFS_Other; +enum lsa_SidType; + +NTSTATUS dom_sid_lookup_predefined_name(const char *name, + const struct dom_sid **sid, + enum lsa_SidType *type, + const struct dom_sid **authority_sid, + const char **authority_name); +NTSTATUS dom_sid_lookup_predefined_sid(const struct dom_sid *sid, + const char **name, + enum lsa_SidType *type, + const struct dom_sid **authority_sid, + const char **authority_name); + int dom_sid_compare_auth(const struct dom_sid *sid1, const struct dom_sid *sid2); int dom_sid_compare(const struct dom_sid *sid1, const struct dom_sid *sid2); diff --git a/libcli/security/util_sid.c b/libcli/security/util_sid.c index e84cfb48265..4e4a8fa0d3e 100644 --- a/libcli/security/util_sid.c +++ b/libcli/security/util_sid.c @@ -434,3 +434,502 @@ bool is_null_sid(const struct dom_sid *sid) const struct dom_sid null_sid = {0}; return dom_sid_equal(sid, &null_sid); } + +/* + * See [MS-LSAT] 3.1.1.1.1 Predefined Translation Database and Corresponding View + */ +struct predefined_name_mapping { + const char *name; + enum lsa_SidType type; + struct dom_sid sid; +}; + +struct predefined_domain_mapping { + const char *domain; + struct dom_sid sid; + size_t num_names; + const struct predefined_name_mapping *names; +}; + +/* S-1-${AUTHORITY} */ +#define _SID0(authority) \ + { 1, 0, {0,0,0,0,0,authority}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}} +/* S-1-${AUTHORITY}-${SUB1} */ +#define _SID1(authority,sub1) \ + { 1, 1, {0,0,0,0,0,authority}, {sub1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}} +/* S-1-${AUTHORITY}-${SUB1}-${SUB2} */ +#define _SID2(authority,sub1,sub2) \ + { 1, 2, {0,0,0,0,0,authority}, {sub1,sub2,0,0,0,0,0,0,0,0,0,0,0,0,0}} + +/* + * S-1-0 + */ +static const struct predefined_name_mapping predefined_names_S_1_0[] = { + { + .name = "NULL SID", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(0, 0), /* S-1-0-0 */ + }, +}; + +/* + * S-1-1 + */ +static const struct predefined_name_mapping predefined_names_S_1_1[] = { + { + .name = "Everyone", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(1, 0), /* S-1-1-0 */ + }, +}; + +/* + * S-1-2 + */ +static const struct predefined_name_mapping predefined_names_S_1_2[] = { + { + .name = "LOCAL", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(2, 0), /* S-1-2-0 */ + }, +}; + +/* + * S-1-3 + */ +static const struct predefined_name_mapping predefined_names_S_1_3[] = { + { + .name = "CREATOR OWNER", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(3, 0), /* S-1-3-0 */ + }, + { + .name = "CREATOR GROUP", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(3, 1), /* S-1-3-1 */ + }, + { + .name = "CREATOR OWNER SERVER", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(3, 0), /* S-1-3-2 */ + }, + { + .name = "CREATOR GROUP SERVER", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(3, 1), /* S-1-3-3 */ + }, + { + .name = "OWNER RIGHTS", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(3, 4), /* S-1-3-4 */ + }, +}; + +/* + * S-1-5 only 'NT Pseudo Domain' + */ +static const struct predefined_name_mapping predefined_names_S_1_5p[] = { + { + .name = "NT Pseudo Domain", + .type = SID_NAME_DOMAIN, + .sid = _SID0(5), /* S-1-5 */ + }, +}; + +/* + * S-1-5 'NT AUTHORITY' + */ +static const struct predefined_name_mapping predefined_names_S_1_5a[] = { + { + .name = "DIALUP", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 1), /* S-1-5-1 */ + }, + { + .name = "NETWORK", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 2), /* S-1-5-2 */ + }, + { + .name = "BATCH", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 3), /* S-1-5-3 */ + }, + { + .name = "INTERACTIVE", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 4), /* S-1-5-4 */ + }, + { + .name = "SERVICE", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 6), /* S-1-5-6 */ + }, + { + .name = "ANONYMOUS LOGON", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 7), /* S-1-5-7 */ + }, + { + .name = "PROXY", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 8), /* S-1-5-8 */ + }, + { + .name = "ENTERPRISE DOMAIN CONTROLLERS", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 9), /* S-1-5-9 */ + }, + { + .name = "SELF", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 10), /* S-1-5-10 */ + }, + { + .name = "Authenticated Users", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 11), /* S-1-5-11 */ + }, + { + .name = "RESTRICTED", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 12), /* S-1-5-12 */ + }, + { + .name = "TERMINAL SERVER USER", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 13), /* S-1-5-13 */ + }, + { + .name = "REMOTE INTERACTIVE LOGON", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 14), /* S-1-5-14 */ + }, + { + .name = "This Organization", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 15), /* S-1-5-15 */ + }, + { + .name = "IUSR", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 17), /* S-1-5-17 */ + }, + { + .name = "SYSTEM", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 18), /* S-1-5-18 */ + }, + { + .name = "LOCAL SERVICE", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 19), /* S-1-5-19 */ + }, + { + .name = "NETWORK SERVICE", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 20), /* S-1-5-20 */ + }, + { + .name = "WRITE RESTRICTED", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 33), /* S-1-5-33 */ + }, + { + .name = "Other Organization", + .type = SID_NAME_WKN_GRP, + .sid = _SID1(5, 1000), /* S-1-5-1000 */ + }, +}; + +/* + * S-1-5-32 + */ +static const struct predefined_name_mapping predefined_names_S_1_5_32[] = { + { + .name = "BUILTIN", + .type = SID_NAME_DOMAIN, + .sid = _SID1(5, 32), /* S-1-5-32 */ + }, +}; + +/* + * S-1-5-64 + */ +static const struct predefined_name_mapping predefined_names_S_1_5_64[] = { + { + .name = "NTLM Authentication", + .type = SID_NAME_WKN_GRP, + .sid = _SID2(5, 64, 10), /* S-1-5-64-10 */ + }, + { + .name = "SChannel Authentication", + .type = SID_NAME_WKN_GRP, + .sid = _SID2(5, 64, 14), /* S-1-5-64-14 */ + }, + { + .name = "Digest Authentication", + .type = SID_NAME_WKN_GRP, + .sid = _SID2(5, 64, 21), /* S-1-5-64-21 */ + }, +}; + +/* + * S-1-7 + */ +static const struct predefined_name_mapping predefined_names_S_1_7[] = { + { + .name = "Internet$", + .type = SID_NAME_DOMAIN, + .sid = _SID0(7), /* S-1-7 */ + }, +}; + +/* + * S-1-16 + */ +static const struct predefined_name_mapping predefined_names_S_1_16[] = { + { + .name = "Mandatory Label", + .type = SID_NAME_DOMAIN, + .sid = _SID0(16), /* S-1-16 */ + }, + { + .name = "Untrusted Mandatory Level", + .type = SID_NAME_LABEL, + .sid = _SID1(16, 0), /* S-1-16-0 */ + }, + { + .name = "Low Mandatory Level", + .type = SID_NAME_LABEL, + .sid = _SID1(16, 4096), /* S-1-16-4096 */ + }, + { + .name = "Medium Mandatory Level", + .type = SID_NAME_LABEL, + .sid = _SID1(16, 8192), /* S-1-16-8192 */ + }, + { + .name = "High Mandatory Level", + .type = SID_NAME_LABEL, + .sid = _SID1(16, 12288), /* S-1-16-12288 */ + }, + { + .name = "System Mandatory Level", + .type = SID_NAME_LABEL, + .sid = _SID1(16, 16384), /* S-1-16-16384 */ + }, + { + .name = "Protected Process Mandatory Level", + .type = SID_NAME_LABEL, + .sid = _SID1(16, 20480), /* S-1-16-20480 */ + }, +}; + +static const struct predefined_domain_mapping predefined_domains[] = { + { + .domain = "", + .sid = _SID0(0), /* S-1-0 */ + .num_names = ARRAY_SIZE(predefined_names_S_1_0), + .names = predefined_names_S_1_0, + }, + { + .domain = "", + .sid = _SID0(1), /* S-1-1 */ + .num_names = ARRAY_SIZE(predefined_names_S_1_1), + .names = predefined_names_S_1_1, + }, + { + .domain = "", + .sid = _SID0(2), /* S-1-2 */ + .num_names = ARRAY_SIZE(predefined_names_S_1_2), + .names = predefined_names_S_1_2, + }, + { + .domain = "", + .sid = _SID0(3), /* S-1-3 */ + .num_names = ARRAY_SIZE(predefined_names_S_1_3), + .names = predefined_names_S_1_3, + }, + { + .domain = "", + .sid = _SID0(3), /* S-1-3 */ + .num_names = ARRAY_SIZE(predefined_names_S_1_3), + .names = predefined_names_S_1_3, + }, + /* + * S-1-5 is split here + * + * 'NT Pseudo Domain' has precedence before 'NT AUTHORITY'. + * + * In a LookupSids with multiple sids e.g. S-1-5 and S-1-5-7 + * the domain section (struct lsa_DomainInfo) gets + * 'NT Pseudo Domain' with S-1-5. If asked in reversed order + * S-1-5-7 and then S-1-5, you get struct lsa_DomainInfo + * with 'NT AUTHORITY' and S-1-5. + */ + { + .domain = "NT Pseudo Domain", + .sid = _SID0(5), /* S-1-5 */ + .num_names = ARRAY_SIZE(predefined_names_S_1_5p), + .names = predefined_names_S_1_5p, + }, + { + .domain = "NT AUTHORITY", + .sid = _SID0(5), /* S-1-5 */ + .num_names = ARRAY_SIZE(predefined_names_S_1_5a), + .names = predefined_names_S_1_5a, + }, + { + .domain = "BUILTIN", + .sid = _SID1(5, 32), /* S-1-5-32 */ + .num_names = ARRAY_SIZE(predefined_names_S_1_5_32), + .names = predefined_names_S_1_5_32, + }, + /* + * 'NT AUTHORITY' again with S-1-5-64 this time + */ + { + .domain = "NT AUTHORITY", + .sid = _SID1(5, 64), /* S-1-5-64 */ + .num_names = ARRAY_SIZE(predefined_names_S_1_5_64), + .names = predefined_names_S_1_5_64, + }, + { + .domain = "Internet$", + .sid = _SID0(7), /* S-1-7 */ + .num_names = ARRAY_SIZE(predefined_names_S_1_7), + .names = predefined_names_S_1_7, + }, + { + .domain = "Mandatory Label", + .sid = _SID0(16), /* S-1-16 */ + .num_names = ARRAY_SIZE(predefined_names_S_1_16), + .names = predefined_names_S_1_16, + }, +}; + +NTSTATUS dom_sid_lookup_predefined_name(const char *name, + const struct dom_sid **sid, + enum lsa_SidType *type, + const struct dom_sid **authority_sid, + const char **authority_name) +{ + size_t di; + const char *domain = ""; + size_t domain_len = 0; + const char *p; + bool match; + + *sid = NULL; + *type = SID_NAME_UNKNOWN; + *authority_sid = NULL; + *authority_name = NULL; + + if (name == NULL) { + name = ""; + } + + p = strchr(name, '\\'); + if (p != NULL) { + domain = name; + domain_len = PTR_DIFF(p, domain); + name = p + 1; + } + + match = strequal(name, ""); + if (match) { + /* + * Strange, but that's what W2012R2 does. + */ + name = "BUILTIN"; + } + + for (di = 0; di < ARRAY_SIZE(predefined_domains); di++) { + const struct predefined_domain_mapping *d = + &predefined_domains[di]; + size_t ni; + + if (domain_len != 0) { + int cmp; + + cmp = strncasecmp(d->domain, domain, domain_len); + if (cmp != 0) { + continue; + } + } + + for (ni = 0; ni < d->num_names; ni++) { + const struct predefined_name_mapping *n = + &d->names[ni]; + + match = strequal(n->name, name); + if (!match) { + continue; + } + + *sid = &n->sid; + *type = n->type; + *authority_sid = &d->sid; + *authority_name = d->domain; + return NT_STATUS_OK; + } + } + + return NT_STATUS_NONE_MAPPED; +} + +NTSTATUS dom_sid_lookup_predefined_sid(const struct dom_sid *sid, + const char **name, + enum lsa_SidType *type, + const struct dom_sid **authority_sid, + const char **authority_name) +{ + size_t di; + bool match_domain = false; + + *name = NULL; + *type = SID_NAME_UNKNOWN; + *authority_sid = NULL; + *authority_name = NULL; + + if (sid == NULL) { + return NT_STATUS_INVALID_SID; + } + + for (di = 0; di < ARRAY_SIZE(predefined_domains); di++) { + const struct predefined_domain_mapping *d = + &predefined_domains[di]; + size_t ni; + int cmp; + + cmp = dom_sid_compare_auth(&d->sid, sid); + if (cmp != 0) { + continue; + } + + match_domain = true; + + for (ni = 0; ni < d->num_names; ni++) { + const struct predefined_name_mapping *n = + &d->names[ni]; + + cmp = dom_sid_compare(&n->sid, sid); + if (cmp != 0) { + continue; + } + + *name = n->name; + *type = n->type; + *authority_sid = &d->sid; + *authority_name = d->domain; + return NT_STATUS_OK; + } + } + + if (!match_domain) { + return NT_STATUS_INVALID_SID; + } + + return NT_STATUS_NONE_MAPPED; +} -- 2.13.6 From bdd4573449c862edb5f4e3baed3760724162cd91 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 15 Feb 2018 10:30:28 +0100 Subject: [PATCH 19/22] test_trust_ntlm.sh: add lookup name tests Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 475a761637bbcc93edbe8d83fc13037e1087941a) --- selftest/knownfail.d/s3-lsa-server | 1 + selftest/knownfail.d/s4-lsa-server | 2 + testprogs/blackbox/test_trust_ntlm.sh | 77 +++++++++++++++++++++++++++-------- 3 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 selftest/knownfail.d/s3-lsa-server create mode 100644 selftest/knownfail.d/s4-lsa-server diff --git a/selftest/knownfail.d/s3-lsa-server b/selftest/knownfail.d/s3-lsa-server new file mode 100644 index 00000000000..de1244f6746 --- /dev/null +++ b/selftest/knownfail.d/s3-lsa-server @@ -0,0 +1 @@ +^samba4.blackbox.trust_ntlm.Test08.rpcclient.lookupnames.with.ADDOM.SAMBA.EXAMPLE.COM\(ad_member:local\) diff --git a/selftest/knownfail.d/s4-lsa-server b/selftest/knownfail.d/s4-lsa-server new file mode 100644 index 00000000000..86365e2868c --- /dev/null +++ b/selftest/knownfail.d/s4-lsa-server @@ -0,0 +1,2 @@ +^samba4.blackbox.trust_ntlm.Test07.rpcclient.lookupnames.with.ADDOMAIN.*fl20 +^samba4.blackbox.trust_ntlm.Test08.rpcclient.lookupnames.with.ADDOM.SAMBA.EXAMPLE.COM.*fl20 diff --git a/testprogs/blackbox/test_trust_ntlm.sh b/testprogs/blackbox/test_trust_ntlm.sh index 44946bb9262..101303ede26 100755 --- a/testprogs/blackbox/test_trust_ntlm.sh +++ b/testprogs/blackbox/test_trust_ntlm.sh @@ -36,19 +36,35 @@ unc="//$SERVER/tmp" . `dirname $0`/subunit.sh . `dirname $0`/common_test_fns.inc -CREDS="$DOMAIN\\$USERNAME%$PASSWORD" -WBCREDS="$DOMAIN/$USERNAME%$PASSWORD" +DNAME="$DOMAIN" +NAME="$DNAME\\$USERNAME" +WBNAME="$DNAME/$USERNAME" +CREDS="$NAME%$PASSWORD" +WBCREDS="$WBNAME%$PASSWORD" EXPCREDS="Account Name: $USERNAME, Authority Name: $DOMAIN" +EXPSID="(User: 1)" +EXPDSID="(Domain: 3)" test_rpcclient_grep "Test01 rpcclient getusername with $CREDS" getusername "$SERVER" "$EXPCREDS" -U$CREDS || failed=`expr $failed + 1` test_smbclient "Test01 smbclient with $CREDS" 'ls' "$unc" -U$CREDS || failed=`expr $failed + 1` testit "Test01 wbinfo -a with $WBCREDS" $VALGRIND $wbinfo -a $WBCREDS || failed=`expr $failed + 1` - -CREDS="$REALM\\$USERNAME%$PASSWORD" -WBCREDS="$REALM/$USERNAME%$PASSWORD" +test_rpcclient_grep "Test01 rpcclient lookupnames with $NAME" "lookupnames_level 1 '$NAME'" "$SERVER" "$EXPSID" -U$CREDS || failed=`expr $failed + 1` +testit "Test01 wbinfo -n with $WBNAME" $VALGRIND $wbinfo -n "$WBNAME" || failed=`expr $failed + 1` +test_rpcclient_grep "Test01 rpcclient lookupnames with $DNAME" "lookupnames_level 1 '$DNAME'" "$SERVER" "$EXPDSID" -U$CREDS || failed=`expr $failed + 1` + +DNAME="$REALM" +NAME="$DNAME\\$USERNAME" +WBNAME="$DNAME/$USERNAME" +CREDS="$NAME%$PASSWORD" +WBCREDS="$WBNAME%$PASSWORD" EXPCREDS="Account Name: $USERNAME, Authority Name: $DOMAIN" +EXPSID="(User: 1)" +EXPDSID="(Domain: 3)" test_rpcclient_grep "Test02 rpcclient getusername with $CREDS" getusername "$SERVER" "$EXPCREDS" -U$CREDS || failed=`expr $failed + 1` test_smbclient "Test02 smbclient with $CREDS" 'ls' "$unc" -U$CREDS || failed=`expr $failed + 1` testit "Test02 wbinfo -a with $WBCREDS" $VALGRIND $wbinfo -a $WBCREDS || failed=`expr $failed + 1` +test_rpcclient_grep "Test02 rpcclient lookupnames with $NAME" "lookupnames_level 1 '$NAME'" "$SERVER" "$EXPSID" -U$CREDS || failed=`expr $failed + 1` +testit "Test02 wbinfo -n with $WBNAME" $VALGRIND $wbinfo -n "$WBNAME" || failed=`expr $failed + 1` +test_rpcclient_grep "Test02 rpcclient lookupnames with $DNAME" "lookupnames_level 1 '$DNAME'" "$SERVER" "$EXPDSID" -U$CREDS || failed=`expr $failed + 1` CREDS="$USERNAME@$DOMAIN%$PASSWORD" WBCREDS="$USERNAME@$DOMAIN%$PASSWORD" @@ -86,12 +102,20 @@ else #testit "Test04 wbinfo -a with $WBCREDS" $VALGRIND $wbinfo -a $WBCREDS || failed=`expr $failed + 1` fi -CREDS="UNKNOWNDOMAIN\\$USERNAME%$PASSWORD" -WBCREDS="UNKNOWNDOMAIN/$USERNAME%$PASSWORD" +DNAME="UNKNOWNDOMAIN" +NAME="$DNAME\\$USERNAME" +WBNAME="$DNAME/$USERNAME" +CREDS="$NAME%$PASSWORD" +WBCREDS="$WBNAME%$PASSWORD" EXPCREDS="Account Name: $USERNAME, Authority Name: $DOMAIN" +EXPSID="NT_STATUS_NONE_MAPPED" +EXPDSID="NT_STATUS_NONE_MAPPED" test_rpcclient_grep "Test05 rpcclient getusername with $CREDS" getusername "$SERVER" "$EXPCREDS" -U$CREDS || failed=`expr $failed + 1` test_smbclient "Test05 smbclient with $CREDS" 'ls' "$unc" -U$CREDS || failed=`expr $failed + 1` testit_expect_failure "Fail05 wbinfo -a with $WBCREDS" $VALGRIND $wbinfo -a $WBCREDS || failed=`expr $failed + 1` +test_rpcclient_expect_failure_grep "Test05 rpcclient lookupnames with $NAME" "lookupnames_level 1 '$NAME'" "$SERVER" "$EXPSID" -U$CREDS || failed=`expr $failed + 1` +testit_expect_failure "Test05 wbinfo -n with $WBNAME" $VALGRIND $wbinfo -n "$WBNAME" || failed=`expr $failed + 1` +test_rpcclient_expect_failure_grep "Test05 rpcclient lookupnames with $DNAME" "lookupnames_level 1 '$DNAME'" "$SERVER" "$EXPDSID" -U$CREDS || failed=`expr $failed + 1` CREDS="$TRUST_DOMAIN\\$USERNAME%$PASSWORD" WBCREDS="$TRUST_DOMAIN/$USERNAME%$PASSWORD" @@ -100,19 +124,35 @@ test_rpcclient_expect_failure_grep "Fail06 rpcclient getusername with $CREDS" ge test_smbclient_expect_failure "Fail06 smbclient with $CREDS" 'ls' "$unc" -U$CREDS && failed=`expr $failed + 1` testit_expect_failure "Fail06 wbinfo -a with $WBCREDS" $VALGRIND $wbinfo -a $WBCREDS && failed=`expr $failed + 1` -CREDS="$TRUST_DOMAIN\\$TRUST_USERNAME%$TRUST_PASSWORD" -WBCREDS="$TRUST_DOMAIN/$TRUST_USERNAME%$TRUST_PASSWORD" +DNAME="$TRUST_DOMAIN" +NAME="$DNAME\\$TRUST_USERNAME" +WBNAME="$DNAME/$TRUST_USERNAME" +CREDS="$NAME%$TRUST_PASSWORD" +WBCREDS="$WBNAME%$TRUST_PASSWORD" EXPCREDS="Account Name: $TRUST_USERNAME, Authority Name: $TRUST_DOMAIN" +EXPSID="(User: 1)" +EXPDSID="(Domain: 3)" test_rpcclient_grep "Test07 rpcclient getusername with $CREDS" getusername "$SERVER" "$EXPCREDS" -U$CREDS || failed=`expr $failed + 1` test_smbclient "Test07 smbclient with $CREDS" 'ls' "$unc" -U$CREDS || failed=`expr $failed + 1` testit "Test07 wbinfo -a with $WBCREDS" $VALGRIND $wbinfo -a $WBCREDS || failed=`expr $failed + 1` - -CREDS="$TRUST_REALM\\$TRUST_USERNAME%$TRUST_PASSWORD" -WBCREDS="$TRUST_REALM/$TRUST_USERNAME%$TRUST_PASSWORD" +test_rpcclient_grep "Test07 rpcclient lookupnames with $NAME" "lookupnames_level 1 '$NAME'" "$SERVER" "$EXPSID" -U$CREDS || failed=`expr $failed + 1` +testit "Test07 wbinfo -n with $WBNAME" $VALGRIND $wbinfo -n "$WBNAME" || failed=`expr $failed + 1` +test_rpcclient_grep "Test07 rpcclient lookupnames with $DNAME" "lookupnames_level 1 '$DNAME'" "$SERVER" "$EXPDSID" -U$CREDS || failed=`expr $failed + 1` + +DNAME="$TRUST_REALM" +NAME="$DNAME\\$TRUST_USERNAME" +WBNAME="$DNAME/$TRUST_USERNAME" +CREDS="$NAME%$TRUST_PASSWORD" +WBCREDS="$WBNAME%$TRUST_PASSWORD" EXPCREDS="Account Name: $TRUST_USERNAME, Authority Name: $TRUST_DOMAIN" +EXPSID="(User: 1)" +EXPDSID="(Domain: 3)" test_rpcclient_grep "Test08 rpcclient getusername with $CREDS" getusername "$SERVER" "$EXPCREDS" -U$CREDS || failed=`expr $failed + 1` test_smbclient "Test08 smbclient with $CREDS" 'ls' "$unc" -U$CREDS || failed=`expr $failed + 1` testit "Test08 wbinfo -a with $WBCREDS" $VALGRIND $wbinfo -a $WBCREDS || failed=`expr $failed + 1` +test_rpcclient_grep "Test08 rpcclient lookupnames with $NAME" "lookupnames_level 1 '$NAME'" "$SERVER" "$EXPSID" -U$CREDS || failed=`expr $failed + 1` +testit "Test08 wbinfo -n with $WBNAME" $VALGRIND $wbinfo -n "$WBNAME" || failed=`expr $failed + 1` +test_rpcclient_grep "Test08 rpcclient lookupnames with $DNAME" "lookupnames_level 1 '$DNAME'" "$SERVER" "$EXPDSID" -U$CREDS || failed=`expr $failed + 1` CREDS="$TRUST_USERNAME@$TRUST_DOMAIN%$TRUST_PASSWORD" WBCREDS="$TRUST_USERNAME@$TRUST_DOMAIN%$TRUST_PASSWORD" @@ -154,11 +194,12 @@ fi lowerrealm=$(echo $TRUST_REALM | tr '[A-Z]' '[a-z]') -if test x$TYPE = x"forest"; then - -fi - -if test x$UNTRUSTED = x"yes"; then +#if test x$TYPE = x"forest"; then +# +#fi +# +#if test x$UNTRUSTED = x"yes"; then +# +#fi -fi exit $failed -- 2.13.6 From 2ef30e6da7cc848fe799874fecb29995ddaa9deb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 23 Jan 2018 00:52:50 +0100 Subject: [PATCH 20/22] s4:rpc_server/lsa: rewrite lookup sids/names code to honor the given lookup level [MS-LSAT] 2.2.16 LSAP_LOOKUP_LEVEL defines the which views each level should consult. Up to now we support some wellknown sids, the builtin domain and our account domain, but all levels query all views. This commit implements 3 views (predefined, builtin, account domain) + a dummy winbind view (which will later be used to implement the gc, forest and trust views).. Depending on the level we select the required views. This might not be perfect in all details, but it's enough to pass all existing tests, which already revealed bugs during the development of this patch. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 3801c417db5891ee4a45b09e8841d8f1ff4500f9) --- source4/rpc_server/lsa/lsa_lookup.c | 1412 +++++++++++++++++++++-------------- 1 file changed, 855 insertions(+), 557 deletions(-) diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index 83043cbe17e..8da537c2951 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -21,473 +21,160 @@ */ #include "rpc_server/lsa/lsa.h" +#include "libds/common/roles.h" #include "libds/common/flag_mapping.h" -static const struct { - const char *domain; +struct dcesrv_lsa_TranslatedItem { + enum lsa_SidType type; + const struct dom_sid *sid; const char *name; - const char *sid; - enum lsa_SidType rtype; -} well_known[] = { - { - .name = "EVERYONE", - .sid = SID_WORLD, - .rtype = SID_NAME_WKN_GRP, - }, - { - .name = "CREATOR OWNER", - .sid = SID_CREATOR_OWNER, - .rtype = SID_NAME_WKN_GRP, - }, - { - .name = "CREATOR GROUP", - .sid = SID_CREATOR_GROUP, - .rtype = SID_NAME_WKN_GRP, - }, - { - .name = "Owner Rights", - .sid = SID_OWNER_RIGHTS, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Dialup", - .sid = SID_NT_DIALUP, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Network", - .sid = SID_NT_NETWORK, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Batch", - .sid = SID_NT_BATCH, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Interactive", - .sid = SID_NT_INTERACTIVE, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Service", - .sid = SID_NT_SERVICE, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "ANONYMOUS LOGON", - .sid = SID_NT_ANONYMOUS, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Proxy", - .sid = SID_NT_PROXY, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "ServerLogon", - .sid = SID_NT_ENTERPRISE_DCS, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Self", - .sid = SID_NT_SELF, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Authenticated Users", - .sid = SID_NT_AUTHENTICATED_USERS, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Restricted", - .sid = SID_NT_RESTRICTED, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Terminal Server User", - .sid = SID_NT_TERMINAL_SERVER_USERS, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Remote Interactive Logon", - .sid = SID_NT_REMOTE_INTERACTIVE, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "This Organization", - .sid = SID_NT_THIS_ORGANISATION, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "SYSTEM", - .sid = SID_NT_SYSTEM, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Local Service", - .sid = SID_NT_LOCAL_SERVICE, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Network Service", - .sid = SID_NT_NETWORK_SERVICE, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Digest Authentication", - .sid = SID_NT_DIGEST_AUTHENTICATION, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Enterprise Domain Controllers", - .sid = SID_NT_ENTERPRISE_DCS, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "NTLM Authentication", - .sid = SID_NT_NTLM_AUTHENTICATION, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "Other Organization", - .sid = SID_NT_OTHER_ORGANISATION, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "SChannel Authentication", - .sid = SID_NT_SCHANNEL_AUTHENTICATION, - .rtype = SID_NAME_WKN_GRP, - }, - { - .domain = "NT AUTHORITY", - .name = "IUSR", - .sid = SID_NT_IUSR, - .rtype = SID_NAME_WKN_GRP, - }, - { - .sid = NULL, - } + const char *authority_name; + const struct dom_sid *authority_sid; + uint32_t flags; + bool done; + struct { + const char *domain; /* only $DOMAIN\ */ + const char *namespace; /* $NAMESPACE\ or @$NAMESPACE */ + const char *principal; /* \$PRINCIPAL or $PRIN@IPAL */ + const char *sid; /* "S-1-5-21-9000-8000-7000-6000" */ + const char *rid; /* "00001770" */ + } hints; }; -static NTSTATUS lookup_well_known_names(TALLOC_CTX *mem_ctx, const char *domain, - const char *name, const char **authority_name, - struct dom_sid **sid, enum lsa_SidType *rtype) -{ - unsigned int i; - for (i=0; well_known[i].sid; i++) { - if (domain) { - if (strcasecmp_m(domain, well_known[i].domain) == 0 - && strcasecmp_m(name, well_known[i].name) == 0) { - *authority_name = well_known[i].domain; - *sid = dom_sid_parse_talloc(mem_ctx, well_known[i].sid); - *rtype = well_known[i].rtype; - return NT_STATUS_OK; - } - } else { - if (strcasecmp_m(name, well_known[i].name) == 0) { - *authority_name = well_known[i].domain; - *sid = dom_sid_parse_talloc(mem_ctx, well_known[i].sid); - *rtype = well_known[i].rtype; - return NT_STATUS_OK; - } - } - } - return NT_STATUS_NOT_FOUND; -} +struct dcesrv_lsa_LookupSids_base_state; +struct dcesrv_lsa_LookupNames_base_state; -static NTSTATUS lookup_well_known_sids(TALLOC_CTX *mem_ctx, - const char *sid_str, const char **authority_name, - const char **name, enum lsa_SidType *rtype) -{ - unsigned int i; - for (i=0; well_known[i].sid; i++) { - if (strcasecmp_m(sid_str, well_known[i].sid) == 0) { - *authority_name = well_known[i].domain; - *name = well_known[i].name; - *rtype = well_known[i].rtype; - return NT_STATUS_OK; - } - } - return NT_STATUS_NOT_FOUND; -} +struct dcesrv_lsa_Lookup_view { + const char *name; + NTSTATUS (*lookup_sid)(struct dcesrv_lsa_LookupSids_base_state *state, + struct dcesrv_lsa_TranslatedItem *item); + NTSTATUS (*lookup_name)(struct dcesrv_lsa_LookupNames_base_state *state, + struct dcesrv_lsa_TranslatedItem *item); +}; + +struct dcesrv_lsa_Lookup_view_table { + const char *name; + size_t count; + const struct dcesrv_lsa_Lookup_view **array; +}; + +static const struct dcesrv_lsa_Lookup_view_table *dcesrv_lsa_view_table( + enum lsa_LookupNamesLevel level); /* lookup a SID for 1 name */ -static NTSTATUS dcesrv_lsa_lookup_name(struct tevent_context *ev_ctx, - struct loadparm_context *lp_ctx, - struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, - const char *name, const char **authority_name, - struct dom_sid **sid, enum lsa_SidType *rtype, - uint32_t *rid) +static NTSTATUS dcesrv_lsa_lookup_name(struct lsa_policy_state *state, + TALLOC_CTX *mem_ctx, + const char *domain_name, + const struct dom_sid *domain_sid, + struct ldb_dn *domain_dn, + const char *principal, + const struct dom_sid **p_sid, + enum lsa_SidType *p_type) { - int ret, i; - uint32_t atype; - struct ldb_message **res; const char * const attrs[] = { "objectSid", "sAMAccountType", NULL}; - const char *p; - const char *domain; - const char *username; - struct ldb_dn *domain_dn; - struct dom_sid *domain_sid; + struct ldb_message **res = NULL; + const char *nt4_account = NULL; + char *encoded_account = NULL; + const char *at = NULL; NTSTATUS status; + const struct dom_sid *sid = NULL; + uint32_t atype; + enum lsa_SidType type; + bool match = false; + int ret; + + if (principal == NULL && principal[0] == '\0') { + return NT_STATUS_NONE_MAPPED; + } + + at = strchr(principal, '@'); + if (at != NULL) { + const char *nt4_domain = NULL; - p = strchr_m(name, '\\'); - if (p != NULL) { - domain = talloc_strndup(mem_ctx, name, p-name); - if (!domain) { - return NT_STATUS_NO_MEMORY; - } - username = p + 1; - } else if (strchr_m(name, '@')) { status = crack_name_to_nt4_name(mem_ctx, state->sam_ldb, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL, - name, &domain, &username); + principal, + &nt4_domain, + &nt4_account); if (!NT_STATUS_IS_OK(status)) { - DEBUG(3, ("Failed to crack name %s into an NT4 name: %s\n", name, nt_errstr(status))); - return status; - } - } else { - domain = NULL; - username = name; - } - - if (!domain) { - /* Look up table of well known names */ - status = lookup_well_known_names(mem_ctx, NULL, username, authority_name, sid, rtype); - if (NT_STATUS_IS_OK(status)) { - dom_sid_split_rid(NULL, *sid, NULL, rid); - return NT_STATUS_OK; - } - - if (username == NULL) { - *authority_name = NAME_BUILTIN; - *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN); - if (*sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - *rtype = SID_NAME_DOMAIN; - *rid = 0xFFFFFFFF; - return NT_STATUS_OK; - } - - if (strcasecmp_m(username, NAME_NT_AUTHORITY) == 0) { - *authority_name = NAME_NT_AUTHORITY; - *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY); - if (*sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - *rtype = SID_NAME_DOMAIN; - dom_sid_split_rid(NULL, *sid, NULL, rid); - return NT_STATUS_OK; - } - if (strcasecmp_m(username, NAME_BUILTIN) == 0) { - *authority_name = NAME_BUILTIN; - *sid = dom_sid_parse_talloc(mem_ctx, SID_BUILTIN); - if (*sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - *rtype = SID_NAME_DOMAIN; - *rid = 0xFFFFFFFF; - return NT_STATUS_OK; - } - if (strcasecmp_m(username, state->domain_dns) == 0) { - *authority_name = talloc_strdup(mem_ctx, - state->domain_name); - if (*authority_name == NULL) { - return NT_STATUS_NO_MEMORY; - } - *sid = dom_sid_dup(mem_ctx, state->domain_sid); - if (*sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - *rtype = SID_NAME_DOMAIN; - *rid = 0xFFFFFFFF; - return NT_STATUS_OK; - } - if (strcasecmp_m(username, state->domain_name) == 0) { - *authority_name = talloc_strdup(mem_ctx, - state->domain_name); - if (*authority_name == NULL) { - return NT_STATUS_NO_MEMORY; - } - *sid = dom_sid_dup(mem_ctx, state->domain_sid); - if (*sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - *rtype = SID_NAME_DOMAIN; - *rid = 0xFFFFFFFF; - return NT_STATUS_OK; - } - - /* Perhaps this is a well known user? */ - name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_NT_AUTHORITY, username); - if (!name) { - return NT_STATUS_NO_MEMORY; - } - status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); - if (NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Failed to crack name %s into an NT4 name: %s\n", + principal, nt_errstr(status))); return status; } - /* Perhaps this is a BUILTIN user? */ - name = talloc_asprintf(mem_ctx, "%s\\%s", NAME_BUILTIN, username); - if (!name) { - return NT_STATUS_NO_MEMORY; - } - status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); - if (NT_STATUS_IS_OK(status)) { - return status; - } - - /* OK, I give up - perhaps we need to assume the user is in our domain? */ - name = talloc_asprintf(mem_ctx, "%s\\%s", state->domain_name, username); - if (!name) { - return NT_STATUS_NO_MEMORY; - } - status = dcesrv_lsa_lookup_name(ev_ctx, lp_ctx, state, mem_ctx, name, authority_name, sid, rtype, rid); - if (NT_STATUS_IS_OK(status)) { - return status; - } - - return STATUS_SOME_UNMAPPED; - } else if (strcasecmp_m(domain, NAME_NT_AUTHORITY) == 0) { - if (!*username) { - *authority_name = NAME_NT_AUTHORITY; - *sid = dom_sid_parse_talloc(mem_ctx, SID_NT_AUTHORITY); - if (*sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - *rtype = SID_NAME_DOMAIN; - dom_sid_split_rid(NULL, *sid, NULL, rid); - return NT_STATUS_OK; - } - - /* Look up table of well known names */ - status = lookup_well_known_names(mem_ctx, domain, username, authority_name, - sid, rtype); - if (NT_STATUS_IS_OK(status)) { - dom_sid_split_rid(NULL, *sid, NULL, rid); + match = strequal(nt4_domain, domain_name); + if (!match) { + /* + * TODO: handle multiple domains in a forest. + */ + return NT_STATUS_NONE_MAPPED; } - return status; - } else if (strcasecmp_m(domain, NAME_BUILTIN) == 0) { - *authority_name = NAME_BUILTIN; - domain_dn = state->builtin_dn; - } else if (strcasecmp_m(domain, state->domain_dns) == 0) { - *authority_name = talloc_strdup(mem_ctx, - state->domain_name); - if (*authority_name == NULL) { - return NT_STATUS_NO_MEMORY; - } - domain_dn = state->domain_dn; - } else if (strcasecmp_m(domain, state->domain_name) == 0) { - *authority_name = talloc_strdup(mem_ctx, - state->domain_name); - if (*authority_name == NULL) { - return NT_STATUS_NO_MEMORY; - } - domain_dn = state->domain_dn; } else { - /* Not local, need to ask winbind in future */ - return STATUS_SOME_UNMAPPED; + nt4_account = principal; } - ret = gendb_search_dn(state->sam_ldb, mem_ctx, domain_dn, &res, attrs); - if (ret != 1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - domain_sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid"); - if (domain_sid == NULL) { - return NT_STATUS_INVALID_SID; + encoded_account = ldb_binary_encode_string(mem_ctx, nt4_account); + if (encoded_account == NULL) { + return NT_STATUS_NO_MEMORY; } - if (!*username) { - *sid = domain_sid; - *rtype = SID_NAME_DOMAIN; - *rid = 0xFFFFFFFF; - return NT_STATUS_OK; - } - ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs, "(&(sAMAccountName=%s)(objectSid=*))", - ldb_binary_encode_string(mem_ctx, username)); + encoded_account); + TALLOC_FREE(encoded_account); if (ret < 0) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; + return NT_STATUS_INTERNAL_DB_ERROR; + } + if (ret == 0) { + return NT_STATUS_NONE_MAPPED; + } + if (ret > 1) { + status = NT_STATUS_INTERNAL_DB_CORRUPTION; + DBG_ERR("nt4_account[%s] found %d times (principal[%s]) - %s\n", + nt4_account, ret, principal, nt_errstr(status)); + return status; } - for (i=0; i < ret; i++) { - *sid = samdb_result_dom_sid(mem_ctx, res[i], "objectSid"); - if (*sid == NULL) { - return NT_STATUS_INVALID_SID; - } - - /* Check that this is in the domain */ - if (!dom_sid_in_domain(domain_sid, *sid)) { - continue; - } - - atype = ldb_msg_find_attr_as_uint(res[i], "sAMAccountType", 0); - - *rtype = ds_atype_map(atype); - if (*rtype == SID_NAME_UNKNOWN) { - return STATUS_SOME_UNMAPPED; - } + sid = samdb_result_dom_sid(mem_ctx, res[0], "objectSid"); + if (sid == NULL) { + return NT_STATUS_NO_MEMORY; + } - dom_sid_split_rid(NULL, *sid, NULL, rid); - return NT_STATUS_OK; + /* Check that this is in the domain */ + match = dom_sid_in_domain(domain_sid, sid); + if (!match) { + return NT_STATUS_NONE_MAPPED; } - /* need to check for an allocated sid */ + atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0); + type = ds_atype_map(atype); + if (type == SID_NAME_UNKNOWN) { + return NT_STATUS_NONE_MAPPED; + } - return NT_STATUS_INVALID_SID; + *p_sid = sid; + *p_type = type; + return NT_STATUS_OK; } /* add to the lsa_RefDomainList for LookupSids and LookupNames */ -static NTSTATUS dcesrv_lsa_authority_list(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, - enum lsa_SidType rtype, - const char *authority_name, - struct dom_sid *sid, +static NTSTATUS dcesrv_lsa_authority_list(const char *authority_name, + const struct dom_sid *authority_sid, struct lsa_RefDomainList *domains, uint32_t *sid_index) { - struct dom_sid *authority_sid; uint32_t i; - if (rtype != SID_NAME_DOMAIN) { - authority_sid = dom_sid_dup(mem_ctx, sid); - if (authority_sid == NULL) { - return NT_STATUS_NO_MEMORY; - } - authority_sid->num_auths--; - } else { - authority_sid = sid; + *sid_index = UINT32_MAX; + + if (authority_name == NULL) { + return NT_STATUS_OK; } /* see if we've already done this authority name */ @@ -505,85 +192,77 @@ static NTSTATUS dcesrv_lsa_authority_list(struct lsa_policy_state *state, TALLOC if (domains->domains == NULL) { return NT_STATUS_NO_MEMORY; } - domains->domains[i].name.string = authority_name; - domains->domains[i].sid = authority_sid; + domains->domains[i].name.string = talloc_strdup(domains->domains, + authority_name); + if (domains->domains[i].name.string == NULL) { + return NT_STATUS_NO_MEMORY; + } + domains->domains[i].sid = dom_sid_dup(domains->domains, + authority_sid); + if (domains->domains[i].sid == NULL) { + return NT_STATUS_NO_MEMORY; + } domains->count++; domains->max_size = LSA_REF_DOMAIN_LIST_MULTIPLIER * domains->count; *sid_index = i; - + return NT_STATUS_OK; } /* lookup a name for 1 SID */ -static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, TALLOC_CTX *mem_ctx, - struct dom_sid *sid, const char *sid_str, - const char **authority_name, - const char **name, enum lsa_SidType *rtype) +static NTSTATUS dcesrv_lsa_lookup_sid(struct lsa_policy_state *state, + TALLOC_CTX *mem_ctx, + const char *domain_name, + const struct dom_sid *domain_sid, + struct ldb_dn *domain_dn, + const struct dom_sid *sid, + const char **p_name, + enum lsa_SidType *p_type) { - NTSTATUS status; - int ret; + const char * const attrs[] = { "sAMAccountName", "sAMAccountType", NULL}; + struct ldb_message **res = NULL; + char *encoded_sid = NULL; + const char *name = NULL; uint32_t atype; - struct ldb_message **res; - struct ldb_dn *domain_dn; - const char * const attrs[] = { "sAMAccountName", "sAMAccountType", "cn", NULL}; - - status = lookup_well_known_sids(mem_ctx, sid_str, authority_name, name, rtype); - if (NT_STATUS_IS_OK(status)) { - return status; - } - - if (dom_sid_equal(state->domain_sid, sid)) { - *authority_name = talloc_strdup(mem_ctx, state->domain_name); - if (*authority_name == NULL) { - return NT_STATUS_NO_MEMORY; - } - *name = NULL; - *rtype = SID_NAME_DOMAIN; - return NT_STATUS_OK; - } - - if (dom_sid_in_domain(state->domain_sid, sid)) { - *authority_name = talloc_strdup(mem_ctx, state->domain_name); - if (*authority_name == NULL) { - return NT_STATUS_NO_MEMORY; - } - domain_dn = state->domain_dn; - } else if (dom_sid_in_domain(state->builtin_sid, sid)) { - *authority_name = NAME_BUILTIN; - domain_dn = state->builtin_dn; - } else { - /* Not well known, our domain or built in */ - - /* In future, we must look at SID histories, and at trusted domains via winbind */ + enum lsa_SidType type; + int ret; - return NT_STATUS_NOT_FOUND; + encoded_sid = ldap_encode_ndr_dom_sid(mem_ctx, sid); + if (encoded_sid == NULL) { + return NT_STATUS_NO_MEMORY; } - /* need to re-add a check for an allocated sid */ - ret = gendb_search(state->sam_ldb, mem_ctx, domain_dn, &res, attrs, - "objectSid=%s", ldap_encode_ndr_dom_sid(mem_ctx, sid)); - if ((ret < 0) || (ret > 1)) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; + "(&(objectSid=%s)(sAMAccountName=*))", encoded_sid); + TALLOC_FREE(encoded_sid); + if (ret < 0) { + return NT_STATUS_INTERNAL_DB_ERROR; } if (ret == 0) { - return NT_STATUS_NOT_FOUND; + return NT_STATUS_NONE_MAPPED; + } + if (ret > 1) { + NTSTATUS status = NT_STATUS_INTERNAL_DB_CORRUPTION; + DBG_ERR("sid[%s] found %d times - %s\n", + dom_sid_string(mem_ctx, sid), ret, nt_errstr(status)); + return status; } - *name = ldb_msg_find_attr_as_string(res[0], "sAMAccountName", NULL); - if (!*name) { - *name = ldb_msg_find_attr_as_string(res[0], "cn", NULL); - if (!*name) { - *name = talloc_strdup(mem_ctx, sid_str); - NT_STATUS_HAVE_NO_MEMORY(*name); - } + name = ldb_msg_find_attr_as_string(res[0], "sAMAccountName", NULL); + if (name == NULL) { + return NT_STATUS_INTERNAL_ERROR; } atype = ldb_msg_find_attr_as_uint(res[0], "sAMAccountType", 0); - *rtype = ds_atype_map(atype); + type = ds_atype_map(atype); + if (type == SID_NAME_UNKNOWN) { + return NT_STATUS_NONE_MAPPED; + } + *p_name = name; + *p_type = type; return NT_STATUS_OK; } @@ -596,6 +275,11 @@ struct dcesrv_lsa_LookupSids_base_state { struct lsa_LookupSids3 r; + const struct dcesrv_lsa_Lookup_view_table *view_table; + struct dcesrv_lsa_TranslatedItem *items; + + struct dsdb_trust_routing_table *routing_table; + struct { struct lsa_LookupSids *l; struct lsa_LookupSids2 *l2; @@ -603,12 +287,15 @@ struct dcesrv_lsa_LookupSids_base_state { } _r; }; +static NTSTATUS dcesrv_lsa_LookupSids_base_finish( + struct dcesrv_lsa_LookupSids_base_state *state); +static void dcesrv_lsa_LookupSids_base_map( + struct dcesrv_lsa_LookupSids_base_state *state); + static NTSTATUS dcesrv_lsa_LookupSids_base_call(struct dcesrv_lsa_LookupSids_base_state *state) { - struct lsa_policy_state *policy_state = state->policy_state; - TALLOC_CTX *mem_ctx = state->mem_ctx; struct lsa_LookupSids3 *r = &state->r; - struct lsa_RefDomainList *domains = NULL; + uint32_t v; uint32_t i; *r->out.domains = NULL; @@ -616,69 +303,119 @@ static NTSTATUS dcesrv_lsa_LookupSids_base_call(struct dcesrv_lsa_LookupSids_bas r->out.names->names = NULL; *r->out.count = 0; - if (r->in.level < LSA_LOOKUP_NAMES_ALL || - r->in.level > LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC) { + state->view_table = dcesrv_lsa_view_table(r->in.level); + if (state->view_table == NULL) { return NT_STATUS_INVALID_PARAMETER; } - /* NOTE: the WSPP test suite tries SIDs with invalid revision numbers, - and expects NT_STATUS_INVALID_PARAMETER back - we just treat it as - an unknown SID. We could add a SID validator here. (tridge) - MS-DTYP 2.4.2 - */ - - domains = talloc_zero(r->out.domains, struct lsa_RefDomainList); - if (domains == NULL) { + *r->out.domains = talloc_zero(r->out.domains, struct lsa_RefDomainList); + if (*r->out.domains == NULL) { return NT_STATUS_NO_MEMORY; } - *r->out.domains = domains; - r->out.names->names = talloc_array(r->out.names, struct lsa_TranslatedName2, - r->in.sids->num_sids); + r->out.names->names = talloc_zero_array(r->out.names, + struct lsa_TranslatedName2, + r->in.sids->num_sids); if (r->out.names->names == NULL) { return NT_STATUS_NO_MEMORY; } + state->items = talloc_zero_array(state, + struct dcesrv_lsa_TranslatedItem, + r->in.sids->num_sids); + if (state->items == NULL) { + return NT_STATUS_NO_MEMORY; + } + for (i=0;iin.sids->num_sids;i++) { - struct dom_sid *sid = r->in.sids->sids[i].sid; - char *sid_str = dom_sid_string(mem_ctx, sid); - const char *name, *authority_name; - enum lsa_SidType rtype; - uint32_t sid_index; - NTSTATUS status2; + struct dcesrv_lsa_TranslatedItem *item = &state->items[i]; + uint32_t rid = 0; - r->out.names->count++; + if (r->in.sids->sids[i].sid == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } - r->out.names->names[i].sid_type = SID_NAME_UNKNOWN; - r->out.names->names[i].name.string = sid_str; - r->out.names->names[i].sid_index = 0xFFFFFFFF; - r->out.names->names[i].unknown = 0; + item->type = SID_NAME_UNKNOWN; + item->sid = r->in.sids->sids[i].sid; - if (sid_str == NULL) { - r->out.names->names[i].name.string = "(SIDERROR)"; - continue; + item->hints.sid = dom_sid_string(state->items, item->sid); + if (item->hints.sid == NULL) { + return NT_STATUS_NO_MEMORY; } - status2 = dcesrv_lsa_lookup_sid(policy_state, mem_ctx, sid, sid_str, - &authority_name, &name, &rtype); - if (!NT_STATUS_IS_OK(status2)) { - continue; + dom_sid_split_rid(state->items, item->sid, NULL, &rid); + item->hints.rid = talloc_asprintf(state->items, + "%08X", (unsigned)rid); + if (item->hints.rid == NULL) { + return NT_STATUS_NO_MEMORY; } + } - /* set up the authority table */ - status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, rtype, - authority_name, sid, - domains, &sid_index); - if (!NT_STATUS_IS_OK(status2)) { - continue; + for (v=0; v < state->view_table->count; v++) { + const struct dcesrv_lsa_Lookup_view *view = + state->view_table->array[v]; + + for (i=0; i < r->in.sids->num_sids; i++) { + struct dcesrv_lsa_TranslatedItem *item = &state->items[i]; + NTSTATUS status; + + if (item->done) { + continue; + } + + status = view->lookup_sid(state, item); + if (NT_STATUS_IS_OK(status)) { + item->done = true; + } else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + status = NT_STATUS_OK; + } else if (NT_STATUS_EQUAL(status, NT_STATUS_SOME_NOT_MAPPED)) { + status = NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + } + + return dcesrv_lsa_LookupSids_base_finish(state); +} + +static NTSTATUS dcesrv_lsa_LookupSids_base_finish( + struct dcesrv_lsa_LookupSids_base_state *state) +{ + struct lsa_LookupSids3 *r = &state->r; + uint32_t i; + + for (i=0;iin.sids->num_sids;i++) { + struct dcesrv_lsa_TranslatedItem *item = &state->items[i]; + NTSTATUS status; + uint32_t sid_index = UINT32_MAX; + + status = dcesrv_lsa_authority_list(item->authority_name, + item->authority_sid, + *r->out.domains, + &sid_index); + if (!NT_STATUS_IS_OK(status)) { + return status; } - r->out.names->names[i].sid_type = rtype; - r->out.names->names[i].name.string = name; + if (item->name == NULL && r->in.level == LSA_LOOKUP_NAMES_ALL) { + if (sid_index == UINT32_MAX) { + item->name = item->hints.sid; + } else { + item->name = item->hints.rid; + } + } + + r->out.names->names[i].sid_type = item->type; + r->out.names->names[i].name.string = item->name; r->out.names->names[i].sid_index = sid_index; - r->out.names->names[i].unknown = 0; + r->out.names->names[i].unknown = item->flags; - (*r->out.count)++; + r->out.names->count++; + if (item->type != SID_NAME_UNKNOWN) { + (*r->out.count)++; + } } if (*r->out.count == 0) { @@ -942,6 +679,11 @@ struct dcesrv_lsa_LookupNames_base_state { struct lsa_LookupNames4 r; + const struct dcesrv_lsa_Lookup_view_table *view_table; + struct dcesrv_lsa_TranslatedItem *items; + + struct dsdb_trust_routing_table *routing_table; + struct { struct lsa_LookupNames *l; struct lsa_LookupNames2 *l2; @@ -950,15 +692,16 @@ struct dcesrv_lsa_LookupNames_base_state { } _r; }; +static NTSTATUS dcesrv_lsa_LookupNames_base_finish( + struct dcesrv_lsa_LookupNames_base_state *state); +static void dcesrv_lsa_LookupNames_base_map( + struct dcesrv_lsa_LookupNames_base_state *state); static NTSTATUS dcesrv_lsa_LookupNames_base_call(struct dcesrv_lsa_LookupNames_base_state *state) { - struct loadparm_context *lp_ctx = state->dce_call->conn->dce_ctx->lp_ctx; - struct dcesrv_call_state *dce_call = state->dce_call; - struct lsa_policy_state *policy_state = state->policy_state; - TALLOC_CTX *mem_ctx = state->mem_ctx; struct lsa_LookupNames4 *r = &state->r; - struct lsa_RefDomainList *domains = NULL; + enum lsa_LookupOptions invalid_lookup_options = 0; + uint32_t v; uint32_t i; *r->out.domains = NULL; @@ -966,58 +709,148 @@ static NTSTATUS dcesrv_lsa_LookupNames_base_call(struct dcesrv_lsa_LookupNames_b r->out.sids->sids = NULL; *r->out.count = 0; - if (r->in.level < LSA_LOOKUP_NAMES_ALL || - r->in.level > LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC) { + if (r->in.level != LSA_LOOKUP_NAMES_ALL) { + invalid_lookup_options |= + LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES_LOCAL; + } + if (r->in.lookup_options & invalid_lookup_options) { return NT_STATUS_INVALID_PARAMETER; } - domains = talloc_zero(r->out.domains, struct lsa_RefDomainList); - if (domains == NULL) { + state->view_table = dcesrv_lsa_view_table(r->in.level); + if (state->view_table == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + *r->out.domains = talloc_zero(r->out.domains, struct lsa_RefDomainList); + if (*r->out.domains == NULL) { return NT_STATUS_NO_MEMORY; } - *r->out.domains = domains; - r->out.sids->sids = talloc_array(r->out.sids, struct lsa_TranslatedSid3, - r->in.num_names); + r->out.sids->sids = talloc_zero_array(r->out.sids, + struct lsa_TranslatedSid3, + r->in.num_names); if (r->out.sids->sids == NULL) { return NT_STATUS_NO_MEMORY; } + state->items = talloc_zero_array(state, + struct dcesrv_lsa_TranslatedItem, + r->in.num_names); + if (state->items == NULL) { + return NT_STATUS_NO_MEMORY; + } + for (i=0;iin.num_names;i++) { - const char *name = r->in.names[i].string; - const char *authority_name; - struct dom_sid *sid; - uint32_t sid_index, rid; - enum lsa_SidType rtype; - NTSTATUS status2; + struct dcesrv_lsa_TranslatedItem *item = &state->items[i]; + char *p = NULL; + + item->type = SID_NAME_UNKNOWN; + item->name = r->in.names[i].string; + /* + * Note: that item->name can be NULL! + * + * See test_LookupNames_NULL() in + * source4/torture/rpc/lsa.c + * + * nt4 returns NT_STATUS_NONE_MAPPED with sid_type + * SID_NAME_UNKNOWN, rid 0, and sid_index -1; + * + * w2k3/w2k8 return NT_STATUS_OK with sid_type + * SID_NAME_DOMAIN, rid -1 and sid_index 0 and BUILTIN domain + */ + if (item->name == NULL) { + continue; + } - r->out.sids->count++; + item->hints.principal = item->name; + p = strchr(item->name, '\\'); + if (p != NULL && p != item->name) { + item->hints.domain = talloc_strndup(state->items, + item->name, + p - item->name); + if (item->hints.domain == NULL) { + return NT_STATUS_NO_MEMORY; + } + item->hints.namespace = item->hints.domain; + p++; + if (p[0] == '\0') { + /* + * This is just 'BUILTIN\'. + */ + item->hints.principal = NULL; + } else { + item->hints.principal = p; + } + } + if (item->hints.domain == NULL) { + p = strchr(item->name, '@'); + if (p != NULL && p != item->name && p[1] != '\0') { + item->hints.namespace = p + 1; + } + } + } - r->out.sids->sids[i].sid_type = SID_NAME_UNKNOWN; - r->out.sids->sids[i].sid = NULL; - r->out.sids->sids[i].sid_index = 0xFFFFFFFF; - r->out.sids->sids[i].flags = 0; + for (v=0; v < state->view_table->count; v++) { + const struct dcesrv_lsa_Lookup_view *view = + state->view_table->array[v]; - status2 = dcesrv_lsa_lookup_name(dce_call->event_ctx, lp_ctx, policy_state, mem_ctx, name, - &authority_name, &sid, &rtype, &rid); - if (!NT_STATUS_IS_OK(status2) || sid->num_auths == 0) { - continue; + for (i=0; i < r->in.num_names; i++) { + struct dcesrv_lsa_TranslatedItem *item = &state->items[i]; + NTSTATUS status; + + if (item->done) { + continue; + } + + status = view->lookup_name(state, item); + if (NT_STATUS_IS_OK(status)) { + item->done = true; + } else if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + status = NT_STATUS_OK; + } else if (NT_STATUS_EQUAL(status, NT_STATUS_SOME_NOT_MAPPED)) { + status = NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } } + } - status2 = dcesrv_lsa_authority_list(policy_state, mem_ctx, rtype, authority_name, - sid, domains, &sid_index); - if (!NT_STATUS_IS_OK(status2)) { - continue; + return dcesrv_lsa_LookupNames_base_finish(state); +} + +static NTSTATUS dcesrv_lsa_LookupNames_base_finish( + struct dcesrv_lsa_LookupNames_base_state *state) +{ + struct lsa_LookupNames4 *r = &state->r; + uint32_t i; + + for (i=0;iin.num_names;i++) { + struct dcesrv_lsa_TranslatedItem *item = &state->items[i]; + NTSTATUS status; + uint32_t sid_index = UINT32_MAX; + + status = dcesrv_lsa_authority_list(item->authority_name, + item->authority_sid, + *r->out.domains, + &sid_index); + if (!NT_STATUS_IS_OK(status)) { + return status; } - r->out.sids->sids[i].sid_type = rtype; - r->out.sids->sids[i].sid = sid; - r->out.sids->sids[i].sid_index = sid_index; - r->out.sids->sids[i].flags = 0; + r->out.sids->sids[i].sid_type = item->type; + r->out.sids->sids[i].sid = discard_const_p(struct dom_sid, + item->sid); + r->out.sids->sids[i].sid_index = sid_index; + r->out.sids->sids[i].flags = item->flags; - (*r->out.count)++; + r->out.sids->count++; + if (item->type != SID_NAME_UNKNOWN) { + (*r->out.count)++; + } } - + if (*r->out.count == 0) { return NT_STATUS_NONE_MAPPED; } @@ -1401,3 +1234,468 @@ NTSTATUS dcesrv_lsa_LookupNames(struct dcesrv_call_state *dce_call, TALLOC_CTX * return status; } +static NTSTATUS dcesrv_lsa_lookup_name_predefined( + struct dcesrv_lsa_LookupNames_base_state *state, + struct dcesrv_lsa_TranslatedItem *item) +{ + NTSTATUS status; + + status = dom_sid_lookup_predefined_name(item->name, + &item->sid, + &item->type, + &item->authority_sid, + &item->authority_name); + if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + return status; + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + +static NTSTATUS dcesrv_lsa_lookup_sid_predefined( + struct dcesrv_lsa_LookupSids_base_state *state, + struct dcesrv_lsa_TranslatedItem *item) +{ + NTSTATUS status; + + status = dom_sid_lookup_predefined_sid(item->sid, + &item->name, + &item->type, + &item->authority_sid, + &item->authority_name); + if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + return status; + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return NT_STATUS_OK; +} + +static const struct dcesrv_lsa_Lookup_view view_predefined = { + .name = "Predefined", + .lookup_sid = dcesrv_lsa_lookup_sid_predefined, + .lookup_name = dcesrv_lsa_lookup_name_predefined, +}; + +static NTSTATUS dcesrv_lsa_lookup_name_builtin( + struct dcesrv_lsa_LookupNames_base_state *state, + struct dcesrv_lsa_TranslatedItem *item) +{ + struct lsa_policy_state *policy_state = state->policy_state; + NTSTATUS status; + bool is_builtin = false; + + if (item->name == NULL) { + /* + * This should not be mapped. + */ + return NT_STATUS_OK; + } + + /* + * The predefined view already handled the BUILTIN domain. + * + * Now we just need to find the principal. + * + * We only allow 'BUILTIN\something' and + * not 'something@BUILTIN. + * + * And we try out best for just 'something'. + */ + is_builtin = strequal(item->hints.domain, NAME_BUILTIN); + if (!is_builtin && item->hints.domain != NULL) { + return NT_STATUS_NONE_MAPPED; + } + + status = dcesrv_lsa_lookup_name(state->policy_state, + state->mem_ctx, + NAME_BUILTIN, + policy_state->builtin_sid, + policy_state->builtin_dn, + item->hints.principal, + &item->sid, + &item->type); + if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + if (!is_builtin) { + return NT_STATUS_NONE_MAPPED; + } + /* + * We know we're authoritive + */ + status = NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + item->authority_name = NAME_BUILTIN; + item->authority_sid = policy_state->builtin_sid; + return NT_STATUS_OK; +} + +static NTSTATUS dcesrv_lsa_lookup_sid_builtin( + struct dcesrv_lsa_LookupSids_base_state *state, + struct dcesrv_lsa_TranslatedItem *item) +{ + struct lsa_policy_state *policy_state = state->policy_state; + NTSTATUS status; + bool is_builtin = false; + + /* + * The predefined view already handled the BUILTIN domain. + * + * Now we just need to find the principal. + */ + is_builtin = dom_sid_in_domain(policy_state->builtin_sid, item->sid); + if (!is_builtin) { + return NT_STATUS_NONE_MAPPED; + } + + status = dcesrv_lsa_lookup_sid(state->policy_state, + state->mem_ctx, + NAME_BUILTIN, + policy_state->builtin_sid, + policy_state->builtin_dn, + item->sid, + &item->name, + &item->type); + if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + /* + * We know we're authoritive + */ + status = NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + item->authority_name = NAME_BUILTIN; + item->authority_sid = policy_state->builtin_sid; + return NT_STATUS_OK; +} + +static const struct dcesrv_lsa_Lookup_view view_builtin = { + .name = "Builtin", + .lookup_sid = dcesrv_lsa_lookup_sid_builtin, + .lookup_name = dcesrv_lsa_lookup_name_builtin, +}; + +static NTSTATUS dcesrv_lsa_lookup_name_account( + struct dcesrv_lsa_LookupNames_base_state *state, + struct dcesrv_lsa_TranslatedItem *item) +{ + struct lsa_policy_state *policy_state = state->policy_state; + struct loadparm_context *lp_ctx = state->dce_call->conn->dce_ctx->lp_ctx; + struct lsa_LookupNames4 *r = &state->r; + NTSTATUS status; + int role; + bool (*is_local_match_fn)(struct loadparm_context *, const char *) = NULL; + bool is_domain = false; + bool try_lookup = false; + const char *check_domain_name = NULL; + + role = lpcfg_server_role(lp_ctx); + if (role == ROLE_ACTIVE_DIRECTORY_DC) { + is_local_match_fn = lpcfg_is_my_domain_or_realm; + } else { + is_local_match_fn = lpcfg_is_myname; + } + + if (item->name == NULL) { + /* + * This should not be mapped. + */ + return NT_STATUS_OK; + } + + if (item->hints.domain != NULL && item->hints.principal == NULL) { + /* + * This is 'DOMAIN\'. + */ + check_domain_name = item->hints.domain; + } else { + /* + * This is just 'DOMAIN'. + */ + check_domain_name = item->name; + } + is_domain = is_local_match_fn(lp_ctx, check_domain_name); + if (is_domain) { + item->type = SID_NAME_DOMAIN; + item->sid = policy_state->domain_sid; + item->authority_name = policy_state->domain_name; + item->authority_sid = policy_state->domain_sid; + return NT_STATUS_OK; + } + + if (r->in.lookup_options & LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES_LOCAL) { + if (item->hints.domain != item->hints.namespace) { + /* + * This means the client asked for an UPN, + * and it should not be mapped. + */ + return NT_STATUS_OK; + } + } + + if (item->hints.namespace != NULL) { + is_domain = is_local_match_fn(lp_ctx, item->hints.namespace); + try_lookup = is_domain; + } else { + try_lookup = true; + } + + if (!try_lookup) { + struct dcesrv_lsa_TranslatedItem tmp; + + tmp = *item; + status = dom_sid_lookup_predefined_name(item->hints.namespace, + &tmp.sid, + &tmp.type, + &tmp.authority_sid, + &tmp.authority_name); + if (NT_STATUS_IS_OK(status)) { + /* + * It should not be handled by us. + */ + return NT_STATUS_NONE_MAPPED; + } + if (!NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + return status; + } + } + + if (!try_lookup) { + const struct lsa_TrustDomainInfoInfoEx *tdo = NULL; + const struct lsa_ForestTrustDomainInfo *di = NULL; + + if (state->routing_table == NULL) { + status = dsdb_trust_routing_table_load(policy_state->sam_ldb, + state, + &state->routing_table); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + tdo = dsdb_trust_domain_by_name(state->routing_table, + item->hints.namespace, + &di); + if (tdo == NULL) { + /* + * The name is not resolvable at all... + */ + return NT_STATUS_OK; + } + + if (!(tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST)) { + /* + * The name is not resolvable here + */ + return NT_STATUS_NONE_MAPPED; + } + + /* + * TODO: handle multiple domains in a forest together with + * LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY + */ + is_domain = true; + try_lookup = true; + } + + if (!try_lookup) { + /* + * It should not be handled by us. + */ + return NT_STATUS_NONE_MAPPED; + } + + /* + * TODO: handle multiple domains in our forest. + */ + + status = dcesrv_lsa_lookup_name(state->policy_state, + state->mem_ctx, + policy_state->domain_name, + policy_state->domain_sid, + policy_state->domain_dn, + item->hints.principal, + &item->sid, + &item->type); + if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + if (!is_domain) { + return NT_STATUS_NONE_MAPPED; + } + /* + * We know we're authoritive + */ + status = NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + item->authority_name = policy_state->domain_name; + item->authority_sid = policy_state->domain_sid; + return NT_STATUS_OK; +} + +static NTSTATUS dcesrv_lsa_lookup_sid_account( + struct dcesrv_lsa_LookupSids_base_state *state, + struct dcesrv_lsa_TranslatedItem *item) +{ + struct lsa_policy_state *policy_state = state->policy_state; + NTSTATUS status; + bool is_domain; + + is_domain = dom_sid_equal(policy_state->domain_sid, item->sid); + if (is_domain) { + item->type = SID_NAME_DOMAIN; + item->name = policy_state->domain_name; + item->authority_name = policy_state->domain_name; + item->authority_sid = policy_state->domain_sid; + return NT_STATUS_OK; + } + is_domain = dom_sid_in_domain(policy_state->domain_sid, item->sid); + if (!is_domain) { + return NT_STATUS_NONE_MAPPED; + } + + status = dcesrv_lsa_lookup_sid(state->policy_state, + state->mem_ctx, + policy_state->domain_name, + policy_state->domain_sid, + policy_state->domain_dn, + item->sid, + &item->name, + &item->type); + if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + /* + * We know we're authoritive + */ + status = NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + item->authority_name = policy_state->domain_name; + item->authority_sid = policy_state->domain_sid; + return NT_STATUS_OK; +} + +static const struct dcesrv_lsa_Lookup_view view_account = { + .name = "Account", + .lookup_sid = dcesrv_lsa_lookup_sid_account, + .lookup_name = dcesrv_lsa_lookup_name_account, +}; + +static NTSTATUS dcesrv_lsa_lookup_name_winbind( + struct dcesrv_lsa_LookupNames_base_state *state, + struct dcesrv_lsa_TranslatedItem *item) +{ + return NT_STATUS_NONE_MAPPED; +} + +static NTSTATUS dcesrv_lsa_lookup_sid_winbind( + struct dcesrv_lsa_LookupSids_base_state *state, + struct dcesrv_lsa_TranslatedItem *item) +{ + return NT_STATUS_NONE_MAPPED; +} + +static const struct dcesrv_lsa_Lookup_view view_winbind = { + .name = "Winbind", + .lookup_sid = dcesrv_lsa_lookup_sid_winbind, + .lookup_name = dcesrv_lsa_lookup_name_winbind, +}; + +static const struct dcesrv_lsa_Lookup_view *table_all_views[] = { + &view_predefined, + &view_builtin, + &view_account, + &view_winbind, +}; + +static const struct dcesrv_lsa_Lookup_view_table table_all = { + .name = "LSA_LOOKUP_NAMES_ALL", + .count = ARRAY_SIZE(table_all_views), + .array = table_all_views, +}; + +static const struct dcesrv_lsa_Lookup_view *table_domains_views[] = { + &view_account, + &view_winbind, +}; + +static const struct dcesrv_lsa_Lookup_view_table table_domains = { + .name = "LSA_LOOKUP_NAMES_DOMAINS_ONLY", + .count = ARRAY_SIZE(table_domains_views), + .array = table_domains_views, +}; + +static const struct dcesrv_lsa_Lookup_view *table_primary_views[] = { + &view_account, +}; + +static const struct dcesrv_lsa_Lookup_view_table table_primary = { + .name = "LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY", + .count = ARRAY_SIZE(table_primary_views), + .array = table_primary_views, +}; + +static const struct dcesrv_lsa_Lookup_view *table_remote_views[] = { + &view_winbind, +}; + +static const struct dcesrv_lsa_Lookup_view_table table_gc = { + .name = "LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY", + .count = ARRAY_SIZE(table_domains_views), + .array = table_domains_views, +}; + +static const struct dcesrv_lsa_Lookup_view_table table_xreferral = { + .name = "LSA_LOOKUP_NAMES_FOREST_TRUSTS_ONLY", + .count = ARRAY_SIZE(table_remote_views), + .array = table_remote_views, +}; + +static const struct dcesrv_lsa_Lookup_view_table table_xresolve = { + .name = "LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2", + .count = ARRAY_SIZE(table_domains_views), + .array = table_domains_views, +}; + +static const struct dcesrv_lsa_Lookup_view_table table_rodc = { + .name = "LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC", + .count = ARRAY_SIZE(table_remote_views), + .array = table_remote_views, +}; + +static const struct dcesrv_lsa_Lookup_view_table *dcesrv_lsa_view_table( + enum lsa_LookupNamesLevel level) +{ + switch (level) { + case LSA_LOOKUP_NAMES_ALL: + return &table_all; + case LSA_LOOKUP_NAMES_DOMAINS_ONLY: + return &table_domains; + case LSA_LOOKUP_NAMES_PRIMARY_DOMAIN_ONLY: + return &table_primary; + case LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY: + return &table_gc; + case LSA_LOOKUP_NAMES_FOREST_TRUSTS_ONLY: + return &table_xreferral; + case LSA_LOOKUP_NAMES_UPLEVEL_TRUSTS_ONLY2: + return &table_xresolve; + case LSA_LOOKUP_NAMES_RODC_REFERRAL_TO_FULL_DC: + return &table_rodc; + } + + return NULL; +} -- 2.13.6 From b9c611fbe152da73c80993de8b2d959dab956647 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 23 Jan 2018 13:19:37 +0100 Subject: [PATCH 21/22] winbindd: implement wb_irpc_lsa_{LookupNames4,LookupSids3}() This will be used by the LSA Server on an AD DC to request remote views from trusts. In future we should implement wb_lookupnames_send/recv similar to wb_lookupsids_send/recv, but for now using wb_lookupname_send/recv in a loop works as a first step. We also need to make use of req->in.level and req->in.client_revision once we want to support more than one domain within our own forest. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit 3ffebee3de4aa313027779bc98cb6326fa17be85) --- source3/winbindd/winbindd_irpc.c | 408 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) diff --git a/source3/winbindd/winbindd_irpc.c b/source3/winbindd/winbindd_irpc.c index 4101469ad99..e03312ec7af 100644 --- a/source3/winbindd/winbindd_irpc.c +++ b/source3/winbindd/winbindd_irpc.c @@ -25,6 +25,10 @@ #include "librpc/gen_ndr/ndr_winbind_c.h" #include "source4/lib/messaging/irpc.h" #include "librpc/gen_ndr/ndr_winbind.h" +#include "librpc/gen_ndr/ndr_lsa.h" +#include "librpc/gen_ndr/ndr_lsa_c.h" +#include "libcli/security/dom_sid.h" +#include "passdb/lookup_sid.h" /* only for LOOKUP_NAME_NO_NSS flag */ struct wb_irpc_forward_state { struct irpc_message *msg; @@ -330,6 +334,398 @@ static NTSTATUS wb_irpc_SendToSam(struct irpc_message *msg, domain, IRPC_CALL_TIMEOUT); } +struct wb_irpc_lsa_LookupSids3_state { + struct irpc_message *msg; + struct lsa_LookupSids3 *req; +}; + +static void wb_irpc_lsa_LookupSids3_done(struct tevent_req *subreq); + +static NTSTATUS wb_irpc_lsa_LookupSids3_call(struct irpc_message *msg, + struct lsa_LookupSids3 *req) +{ + struct wb_irpc_lsa_LookupSids3_state *state = NULL; + struct tevent_req *subreq = NULL; + struct dom_sid *sids = NULL; + uint32_t i; + + state = talloc_zero(msg, struct wb_irpc_lsa_LookupSids3_state); + if (state == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->msg = msg; + state->req = req; + + state->req->out.domains = talloc_zero(state->msg, + struct lsa_RefDomainList *); + if (state->req->out.domains == NULL) { + return NT_STATUS_NO_MEMORY; + } + state->req->out.names = talloc_zero(state->msg, + struct lsa_TransNameArray2); + if (state->req->out.names == NULL) { + return NT_STATUS_NO_MEMORY; + } + state->req->out.count = talloc_zero(state->msg, uint32_t); + if (state->req->out.count == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->req->out.names->names = talloc_zero_array(state->msg, + struct lsa_TranslatedName2, + req->in.sids->num_sids); + if (state->req->out.names->names == NULL) { + return NT_STATUS_NO_MEMORY; + } + + sids = talloc_zero_array(state, struct dom_sid, + req->in.sids->num_sids); + if (sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < req->in.sids->num_sids; i++) { + if (req->in.sids->sids[i].sid == NULL) { + return NT_STATUS_REQUEST_NOT_ACCEPTED; + } + + sids[i] = *req->in.sids->sids[i].sid; + } + + subreq = wb_lookupsids_send(msg, + server_event_context(), + sids, req->in.sids->num_sids); + if (subreq == NULL) { + return NT_STATUS_NO_MEMORY; + } + tevent_req_set_callback(subreq, wb_irpc_lsa_LookupSids3_done, state); + msg->defer_reply = true; + + return NT_STATUS_OK; +} + +static void wb_irpc_lsa_LookupSids3_done(struct tevent_req *subreq) +{ + struct wb_irpc_lsa_LookupSids3_state *state = + tevent_req_callback_data(subreq, + struct wb_irpc_lsa_LookupSids3_state); + struct lsa_RefDomainList *domains = NULL; + struct lsa_TransNameArray *names = NULL; + NTSTATUS status; + uint32_t i; + + status = wb_lookupsids_recv(subreq, state->msg, + &domains, &names); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("RPC callback failed for %s - %s\n", + __func__, nt_errstr(status))); + irpc_send_reply(state->msg, status); + return; + } + + if (names->count > state->req->in.sids->num_sids) { + status = NT_STATUS_INTERNAL_ERROR; + DEBUG(0,("RPC callback failed for %s - %s\n", + __func__, nt_errstr(status))); + irpc_send_reply(state->msg, status); + return; + } + + *state->req->out.domains = domains; + for (i = 0; i < names->count; i++) { + struct lsa_TranslatedName2 *n2 = + &state->req->out.names->names[i]; + + n2->sid_type = names->names[i].sid_type; + n2->name = names->names[i].name; + n2->sid_index = names->names[i].sid_index; + n2->unknown = 0; + + if (n2->sid_type != SID_NAME_UNKNOWN) { + (*state->req->out.count)++; + } + } + state->req->out.names->count = names->count; + + if (*state->req->out.count == 0) { + state->req->out.result = NT_STATUS_NONE_MAPPED; + } else if (*state->req->out.count != names->count) { + state->req->out.result = NT_STATUS_SOME_NOT_MAPPED; + } else { + state->req->out.result = NT_STATUS_OK; + } + + irpc_send_reply(state->msg, NT_STATUS_OK); + return; +} + +struct wb_irpc_lsa_LookupNames4_name { + void *state; + uint32_t idx; + const char *domain; + char *name; + struct dom_sid sid; + enum lsa_SidType type; + struct dom_sid *authority_sid; +}; + +struct wb_irpc_lsa_LookupNames4_state { + struct irpc_message *msg; + struct lsa_LookupNames4 *req; + struct wb_irpc_lsa_LookupNames4_name *names; + uint32_t num_pending; + uint32_t num_domain_sids; + struct dom_sid *domain_sids; +}; + +static void wb_irpc_lsa_LookupNames4_done(struct tevent_req *subreq); + +static NTSTATUS wb_irpc_lsa_LookupNames4_call(struct irpc_message *msg, + struct lsa_LookupNames4 *req) +{ + struct wb_irpc_lsa_LookupNames4_state *state = NULL; + struct tevent_req *subreq = NULL; + uint32_t i; + + + state = talloc_zero(msg, struct wb_irpc_lsa_LookupNames4_state); + if (state == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->msg = msg; + state->req = req; + + state->req->out.domains = talloc_zero(state->msg, + struct lsa_RefDomainList *); + if (state->req->out.domains == NULL) { + return NT_STATUS_NO_MEMORY; + } + state->req->out.sids = talloc_zero(state->msg, + struct lsa_TransSidArray3); + if (state->req->out.sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + state->req->out.count = talloc_zero(state->msg, uint32_t); + if (state->req->out.count == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->req->out.sids->sids = talloc_zero_array(state->msg, + struct lsa_TranslatedSid3, + req->in.num_names); + if (state->req->out.sids->sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->names = talloc_zero_array(state, + struct wb_irpc_lsa_LookupNames4_name, + req->in.num_names); + if (state->names == NULL) { + return NT_STATUS_NO_MEMORY; + } + + for (i = 0; i < req->in.num_names; i++) { + struct wb_irpc_lsa_LookupNames4_name *nstate = + &state->names[i]; + char *p = NULL; + + if (req->in.names[i].string == NULL) { + DBG_ERR("%s: name[%s] NT_STATUS_REQUEST_NOT_ACCEPTED.\n", + __location__, req->in.names[i].string); + return NT_STATUS_REQUEST_NOT_ACCEPTED; + } + nstate->state = state; + nstate->idx = i; + nstate->name = talloc_strdup(state->names, + req->in.names[i].string); + if (nstate->name == NULL) { + return NT_STATUS_NO_MEMORY; + } + nstate->type = SID_NAME_UNKNOWN; + + /* cope with the name being a fully qualified name */ + p = strchr(nstate->name, '\\'); + if (p != NULL) { + *p = 0; + nstate->domain = nstate->name; + nstate->name = p+1; + } else if ((p = strchr(nstate->name, '@')) != NULL) { + /* upn */ + nstate->domain = p + 1; + *p = 0; + } else { + /* + * TODO: select the domain based on + * req->in.level and req->in.client_revision + * + * For now we don't allow this. + */ + DBG_ERR("%s: name[%s] NT_STATUS_REQUEST_NOT_ACCEPTED.\n", + __location__, nstate->name); + return NT_STATUS_REQUEST_NOT_ACCEPTED; + } + + subreq = wb_lookupname_send(msg, + server_event_context(), + nstate->domain, + nstate->name, + LOOKUP_NAME_NO_NSS); + if (subreq == NULL) { + return NT_STATUS_NO_MEMORY; + } + tevent_req_set_callback(subreq, + wb_irpc_lsa_LookupNames4_done, + nstate); + state->num_pending++; + } + + msg->defer_reply = true; + + return NT_STATUS_OK; +} + +static void wb_irpc_lsa_LookupNames4_domains_done(struct tevent_req *subreq); + +static void wb_irpc_lsa_LookupNames4_done(struct tevent_req *subreq) +{ + struct wb_irpc_lsa_LookupNames4_name *nstate = + (struct wb_irpc_lsa_LookupNames4_name *) + tevent_req_callback_data_void(subreq); + struct wb_irpc_lsa_LookupNames4_state *state = + talloc_get_type_abort(nstate->state, + struct wb_irpc_lsa_LookupNames4_state); + NTSTATUS status; + + SMB_ASSERT(state->num_pending > 0); + state->num_pending--; + status = wb_lookupname_recv(subreq, &nstate->sid, &nstate->type); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("RPC callback failed for %s - %s\n", + __func__, nt_errstr(status))); + irpc_send_reply(state->msg, status); + return; + } + + status = dom_sid_split_rid(state, &nstate->sid, + &nstate->authority_sid, NULL); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("dom_sid_split_rid(%s) failed - %s\n", + sid_string_dbg(&nstate->sid), nt_errstr(status)); + irpc_send_reply(state->msg, status); + return; + } + + status = add_sid_to_array_unique(state, + nstate->authority_sid, + &state->domain_sids, + &state->num_domain_sids); + if (!NT_STATUS_IS_OK(status)) { + DBG_ERR("add_sid_to_array_unique(%s) failed - %s\n", + sid_string_dbg(nstate->authority_sid), nt_errstr(status)); + irpc_send_reply(state->msg, status); + return; + } + + if (state->num_pending > 0) { + /* + * wait for more... + */ + return; + } + + /* + * Now resolve all domains back to a name + * to get a good lsa_RefDomainList + */ + subreq = wb_lookupsids_send(state, + server_event_context(), + state->domain_sids, + state->num_domain_sids); + if (subreq == NULL) { + status = NT_STATUS_NO_MEMORY; + DBG_ERR("wb_lookupsids_send - %s\n", + nt_errstr(status)); + irpc_send_reply(state->msg, status); + return; + } + tevent_req_set_callback(subreq, + wb_irpc_lsa_LookupNames4_domains_done, + state); + + return; +} + +static void wb_irpc_lsa_LookupNames4_domains_done(struct tevent_req *subreq) +{ + struct wb_irpc_lsa_LookupNames4_state *state = + tevent_req_callback_data(subreq, + struct wb_irpc_lsa_LookupNames4_state); + struct lsa_RefDomainList *domains = NULL; + struct lsa_TransNameArray *names = NULL; + NTSTATUS status; + uint32_t i; + + status = wb_lookupsids_recv(subreq, state->msg, + &domains, &names); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("RPC callback failed for %s - %s\n", + __func__, nt_errstr(status))); + irpc_send_reply(state->msg, status); + return; + } + + *state->req->out.domains = domains; + for (i = 0; i < state->req->in.num_names; i++) { + struct wb_irpc_lsa_LookupNames4_name *nstate = + &state->names[i]; + struct lsa_TranslatedSid3 *s3 = + &state->req->out.sids->sids[i]; + uint32_t di; + + s3->sid_type = nstate->type; + if (s3->sid_type != SID_NAME_UNKNOWN) { + s3->sid = &nstate->sid; + } else { + s3->sid = NULL; + } + s3->sid_index = UINT32_MAX; + for (di = 0; di < domains->count; di++) { + bool match; + + if (domains->domains[di].sid == NULL) { + continue; + } + + match = dom_sid_equal(nstate->authority_sid, + domains->domains[di].sid); + if (match) { + s3->sid_index = di; + break; + } + } + if (s3->sid_type != SID_NAME_UNKNOWN) { + (*state->req->out.count)++; + } + } + state->req->out.sids->count = state->req->in.num_names; + + if (*state->req->out.count == 0) { + state->req->out.result = NT_STATUS_NONE_MAPPED; + } else if (*state->req->out.count != state->req->in.num_names) { + state->req->out.result = NT_STATUS_SOME_NOT_MAPPED; + } else { + state->req->out.result = NT_STATUS_OK; + } + + irpc_send_reply(state->msg, NT_STATUS_OK); + return; +} + NTSTATUS wb_irpc_register(void) { NTSTATUS status; @@ -361,6 +757,18 @@ NTSTATUS wb_irpc_register(void) if (!NT_STATUS_IS_OK(status)) { return status; } + status = IRPC_REGISTER(winbind_imessaging_context(), + lsarpc, LSA_LOOKUPSIDS3, + wb_irpc_lsa_LookupSids3_call, NULL); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + status = IRPC_REGISTER(winbind_imessaging_context(), + lsarpc, LSA_LOOKUPNAMES4, + wb_irpc_lsa_LookupNames4_call, NULL); + if (!NT_STATUS_IS_OK(status)) { + return status; + } return NT_STATUS_OK; } -- 2.13.6 From 7fe54af5ccce16e1ac1df532789dff8fa36d6650 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 19 Jan 2018 13:42:40 +0100 Subject: [PATCH 22/22] s4:rpc_server/lsa: implement forwarding lsa_Lookup{Sids,Names}() requests to winbindd This might not be perfect yet, but it's enough to allow names from trusted forests/domain to be resolved, which is very important for samba based domain members. Bug: https://bugzilla.samba.org/show_bug.cgi?id=13286 Signed-off-by: Stefan Metzmacher Reviewed-by: Ralph Boehme (cherry picked from commit e9d5b8b6b41155a8a043275ae497bdb87044d476) --- selftest/knownfail.d/s4-lsa-server | 2 - source4/rpc_server/lsa/lsa_lookup.c | 527 +++++++++++++++++++++++++++++++++++- 2 files changed, 525 insertions(+), 4 deletions(-) delete mode 100644 selftest/knownfail.d/s4-lsa-server diff --git a/selftest/knownfail.d/s4-lsa-server b/selftest/knownfail.d/s4-lsa-server deleted file mode 100644 index 86365e2868c..00000000000 --- a/selftest/knownfail.d/s4-lsa-server +++ /dev/null @@ -1,2 +0,0 @@ -^samba4.blackbox.trust_ntlm.Test07.rpcclient.lookupnames.with.ADDOMAIN.*fl20 -^samba4.blackbox.trust_ntlm.Test08.rpcclient.lookupnames.with.ADDOM.SAMBA.EXAMPLE.COM.*fl20 diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index 8da537c2951..3baff1ec11f 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -23,6 +23,8 @@ #include "rpc_server/lsa/lsa.h" #include "libds/common/roles.h" #include "libds/common/flag_mapping.h" +#include "lib/messaging/irpc.h" +#include "librpc/gen_ndr/ndr_lsa_c.h" struct dcesrv_lsa_TranslatedItem { enum lsa_SidType type; @@ -31,6 +33,7 @@ struct dcesrv_lsa_TranslatedItem { const char *authority_name; const struct dom_sid *authority_sid; uint32_t flags; + uint32_t wb_idx; bool done; struct { const char *domain; /* only $DOMAIN\ */ @@ -281,6 +284,15 @@ struct dcesrv_lsa_LookupSids_base_state { struct dsdb_trust_routing_table *routing_table; struct { + struct dcerpc_binding_handle *irpc_handle; + struct lsa_SidArray sids; + struct lsa_RefDomainList *domains; + struct lsa_TransNameArray2 names; + uint32_t count; + NTSTATUS result; + } wb; + + struct { struct lsa_LookupSids *l; struct lsa_LookupSids2 *l2; struct lsa_LookupSids3 *l3; @@ -291,10 +303,12 @@ static NTSTATUS dcesrv_lsa_LookupSids_base_finish( struct dcesrv_lsa_LookupSids_base_state *state); static void dcesrv_lsa_LookupSids_base_map( struct dcesrv_lsa_LookupSids_base_state *state); +static void dcesrv_lsa_LookupSids_base_done(struct tevent_req *subreq); static NTSTATUS dcesrv_lsa_LookupSids_base_call(struct dcesrv_lsa_LookupSids_base_state *state) { struct lsa_LookupSids3 *r = &state->r; + struct tevent_req *subreq = NULL; uint32_t v; uint32_t i; @@ -377,7 +391,47 @@ static NTSTATUS dcesrv_lsa_LookupSids_base_call(struct dcesrv_lsa_LookupSids_bas } } - return dcesrv_lsa_LookupSids_base_finish(state); + if (state->wb.irpc_handle == NULL) { + return dcesrv_lsa_LookupSids_base_finish(state); + } + + state->wb.sids.sids = talloc_zero_array(state, struct lsa_SidPtr, + r->in.sids->num_sids); + if (state->wb.sids.sids == NULL) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0; i < r->in.sids->num_sids; i++) { + struct dcesrv_lsa_TranslatedItem *item = &state->items[i]; + + if (item->done) { + continue; + } + + item->wb_idx = state->wb.sids.num_sids; + state->wb.sids.sids[item->wb_idx] = r->in.sids->sids[i]; + state->wb.sids.num_sids++; + } + + subreq = dcerpc_lsa_LookupSids3_send(state, + state->dce_call->event_ctx, + state->wb.irpc_handle, + &state->wb.sids, + &state->wb.domains, + &state->wb.names, + state->r.in.level, + &state->wb.count, + state->r.in.lookup_options, + state->r.in.client_revision); + if (subreq == NULL) { + return NT_STATUS_NO_MEMORY;; + } + state->dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC; + tevent_req_set_callback(subreq, + dcesrv_lsa_LookupSids_base_done, + state); + + return NT_STATUS_OK; } static NTSTATUS dcesrv_lsa_LookupSids_base_finish( @@ -467,6 +521,91 @@ static void dcesrv_lsa_LookupSids_base_map( } } +static void dcesrv_lsa_LookupSids_base_done(struct tevent_req *subreq) +{ + struct dcesrv_lsa_LookupSids_base_state *state = + tevent_req_callback_data(subreq, + struct dcesrv_lsa_LookupSids_base_state); + struct dcesrv_call_state *dce_call = state->dce_call; + NTSTATUS status; + uint32_t i; + + status = dcerpc_lsa_LookupSids3_recv(subreq, state->mem_ctx, + &state->wb.result); + TALLOC_FREE(subreq); + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { + DEBUG(0,(__location__ ": IRPC callback failed %s\n", + nt_errstr(status))); + goto finished; + } else if (!NT_STATUS_IS_OK(status)) { + state->dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; + DEBUG(0,(__location__ ": IRPC callback failed %s\n", + nt_errstr(status))); + goto finished; + } + + status = state->wb.result; + if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + status = NT_STATUS_OK; + } else if (NT_STATUS_EQUAL(status, NT_STATUS_SOME_NOT_MAPPED)) { + status = NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(status)) { + goto finished; + } + + for (i=0; i < state->r.in.sids->num_sids; i++) { + struct dcesrv_lsa_TranslatedItem *item = &state->items[i]; + struct lsa_TranslatedName2 *s2 = NULL; + struct lsa_DomainInfo *d = NULL; + + if (item->done) { + continue; + } + + if (item->wb_idx >= state->wb.names.count) { + status = NT_STATUS_INTERNAL_ERROR; + goto finished; + } + + s2 = &state->wb.names.names[item->wb_idx]; + + item->type = s2->sid_type; + item->name = s2->name.string; + item->flags = s2->unknown; + + if (s2->sid_index == UINT32_MAX) { + continue; + } + + if (state->wb.domains == NULL) { + status = NT_STATUS_INTERNAL_ERROR; + goto finished; + } + + if (s2->sid_index >= state->wb.domains->count) { + status = NT_STATUS_INTERNAL_ERROR; + goto finished; + } + + d = &state->wb.domains->domains[s2->sid_index]; + + item->authority_name = d->name.string; + item->authority_sid = d->sid; + } + + status = dcesrv_lsa_LookupSids_base_finish(state); + finished: + state->r.out.result = status; + dcesrv_lsa_LookupSids_base_map(state); + TALLOC_FREE(state); + + status = dcesrv_reply(dce_call); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,(__location__ ": dcesrv_reply() failed - %s\n", nt_errstr(status))); + } +} + /* lsa_LookupSids2 */ @@ -685,6 +824,16 @@ struct dcesrv_lsa_LookupNames_base_state { struct dsdb_trust_routing_table *routing_table; struct { + struct dcerpc_binding_handle *irpc_handle; + uint32_t num_names; + struct lsa_String *names; + struct lsa_RefDomainList *domains; + struct lsa_TransSidArray3 sids; + uint32_t count; + NTSTATUS result; + } wb; + + struct { struct lsa_LookupNames *l; struct lsa_LookupNames2 *l2; struct lsa_LookupNames3 *l3; @@ -696,11 +845,13 @@ static NTSTATUS dcesrv_lsa_LookupNames_base_finish( struct dcesrv_lsa_LookupNames_base_state *state); static void dcesrv_lsa_LookupNames_base_map( struct dcesrv_lsa_LookupNames_base_state *state); +static void dcesrv_lsa_LookupNames_base_done(struct tevent_req *subreq); static NTSTATUS dcesrv_lsa_LookupNames_base_call(struct dcesrv_lsa_LookupNames_base_state *state) { struct lsa_LookupNames4 *r = &state->r; enum lsa_LookupOptions invalid_lookup_options = 0; + struct tevent_req *subreq = NULL; uint32_t v; uint32_t i; @@ -817,7 +968,48 @@ static NTSTATUS dcesrv_lsa_LookupNames_base_call(struct dcesrv_lsa_LookupNames_b } } - return dcesrv_lsa_LookupNames_base_finish(state); + if (state->wb.irpc_handle == NULL) { + return dcesrv_lsa_LookupNames_base_finish(state); + } + + state->wb.names = talloc_zero_array(state, struct lsa_String, + r->in.num_names); + if (state->wb.names == NULL) { + return NT_STATUS_NO_MEMORY; + } + + for (i=0;iin.num_names;i++) { + struct dcesrv_lsa_TranslatedItem *item = &state->items[i]; + + if (item->done) { + continue; + } + + item->wb_idx = state->wb.num_names; + state->wb.names[item->wb_idx] = r->in.names[i]; + state->wb.num_names++; + } + + subreq = dcerpc_lsa_LookupNames4_send(state, + state->dce_call->event_ctx, + state->wb.irpc_handle, + state->wb.num_names, + state->wb.names, + &state->wb.domains, + &state->wb.sids, + state->r.in.level, + &state->wb.count, + state->r.in.lookup_options, + state->r.in.client_revision); + if (subreq == NULL) { + return NT_STATUS_NO_MEMORY; + } + state->dce_call->state_flags |= DCESRV_CALL_STATE_FLAG_ASYNC; + tevent_req_set_callback(subreq, + dcesrv_lsa_LookupNames_base_done, + state); + + return NT_STATUS_OK; } static NTSTATUS dcesrv_lsa_LookupNames_base_finish( @@ -952,6 +1144,91 @@ static void dcesrv_lsa_LookupNames_base_map( } } +static void dcesrv_lsa_LookupNames_base_done(struct tevent_req *subreq) +{ + struct dcesrv_lsa_LookupNames_base_state *state = + tevent_req_callback_data(subreq, + struct dcesrv_lsa_LookupNames_base_state); + struct dcesrv_call_state *dce_call = state->dce_call; + NTSTATUS status; + uint32_t i; + + status = dcerpc_lsa_LookupNames4_recv(subreq, state->mem_ctx, + &state->wb.result); + TALLOC_FREE(subreq); + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { + DEBUG(0,(__location__ ": IRPC callback failed %s\n", + nt_errstr(status))); + goto finished; + } else if (!NT_STATUS_IS_OK(status)) { + state->dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; + DEBUG(0,(__location__ ": IRPC callback failed %s\n", + nt_errstr(status))); + goto finished; + } + + status = state->wb.result; + if (NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + status = NT_STATUS_OK; + } else if (NT_STATUS_EQUAL(status, NT_STATUS_SOME_NOT_MAPPED)) { + status = NT_STATUS_OK; + } + if (!NT_STATUS_IS_OK(status)) { + goto finished; + } + + for (i=0; i < state->r.in.num_names;i++) { + struct dcesrv_lsa_TranslatedItem *item = &state->items[i]; + struct lsa_TranslatedSid3 *s3 = NULL; + struct lsa_DomainInfo *d = NULL; + + if (item->done) { + continue; + } + + if (item->wb_idx >= state->wb.sids.count) { + status = NT_STATUS_INTERNAL_ERROR; + goto finished; + } + + s3 = &state->wb.sids.sids[item->wb_idx]; + + item->type = s3->sid_type; + item->sid = s3->sid; + item->flags = s3->flags; + + if (s3->sid_index == UINT32_MAX) { + continue; + } + + if (state->wb.domains == NULL) { + status = NT_STATUS_INTERNAL_ERROR; + goto finished; + } + + if (s3->sid_index >= state->wb.domains->count) { + status = NT_STATUS_INTERNAL_ERROR; + goto finished; + } + + d = &state->wb.domains->domains[s3->sid_index]; + + item->authority_name = d->name.string; + item->authority_sid = d->sid; + } + + status = dcesrv_lsa_LookupNames_base_finish(state); + finished: + state->r.out.result = status; + dcesrv_lsa_LookupNames_base_map(state); + TALLOC_FREE(state); + + status = dcesrv_reply(dce_call); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,(__location__ ": dcesrv_reply() failed - %s\n", nt_errstr(status))); + } +} + /* lsa_LookupNames3 */ @@ -1599,6 +1876,142 @@ static NTSTATUS dcesrv_lsa_lookup_name_winbind( struct dcesrv_lsa_LookupNames_base_state *state, struct dcesrv_lsa_TranslatedItem *item) { + struct lsa_LookupNames4 *r = &state->r; + const struct lsa_TrustDomainInfoInfoEx *tdo = NULL; + const struct lsa_ForestTrustDomainInfo *di = NULL; + NTSTATUS status; + const char *check_domain_name = NULL; + bool expect_domain = false; + + if (item->name == NULL) { + /* + * This should not be mapped. + */ + return NT_STATUS_OK; + } + + if (item->hints.domain != NULL && item->hints.principal == NULL) { + /* + * This is 'DOMAIN\'. + */ + check_domain_name = item->hints.domain; + expect_domain = true; + } else if (item->hints.namespace != NULL) { + /* + * This is 'DOMAIN\someone' + * or 'someone@DOMAIN' + */ + check_domain_name = item->hints.namespace; + } else { + /* + * This is just 'DOMAIN'. + */ + check_domain_name = item->name; + expect_domain = true; + } + + if (state->routing_table == NULL) { + struct lsa_policy_state *policy_state = state->policy_state; + + status = dsdb_trust_routing_table_load(policy_state->sam_ldb, + state, + &state->routing_table); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + tdo = dsdb_trust_domain_by_name(state->routing_table, + check_domain_name, + &di); + if (tdo == NULL) { + /* + * The name is not resolvable at all... + * + * And for now we don't send unqualified names + * to winbindd, as we don't handle them + * there yet. + * + * TODO: how should that work within + * winbindd? + */ + return NT_STATUS_OK; + } + + if (tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) { + /* + * The name should have been resolved in the account view. + * + * TODO: handle multiple domains in a forest... + */ + return NT_STATUS_OK; + } + + if (expect_domain) { + const char *name = NULL; + const struct dom_sid *sid = NULL; + + name = talloc_strdup(state->mem_ctx, + di->netbios_domain_name.string); + if (name == NULL) { + return NT_STATUS_NO_MEMORY; + } + sid = dom_sid_dup(state->mem_ctx, + di->domain_sid); + if (sid == NULL) { + return NT_STATUS_NO_MEMORY; + } + item->type = SID_NAME_DOMAIN; + item->sid = sid; + item->authority_name = name; + item->authority_sid = sid; + return NT_STATUS_OK; + } + + if (r->in.lookup_options & LSA_LOOKUP_OPTION_SEARCH_ISOLATED_NAMES_LOCAL) { + if (item->hints.namespace == NULL) { + /* + * We should not try to resolve isolated names + * remotely. + */ + return NT_STATUS_OK; + } + } + + /* + * We know at least the domain part of the name exists. + * + * For now the rest handled within winbindd. + * + * In future we can optimize it based on + * r->in.level. + * + * We can also try to resolve SID_NAME_DOMAIN + * just based on the routing table. + */ + + if (state->wb.irpc_handle != NULL) { + /* + * already called... + */ + return NT_STATUS_NONE_MAPPED; + } + + state->wb.irpc_handle = irpc_binding_handle_by_name(state, + state->dce_call->msg_ctx, + "winbind_server", + &ndr_table_lsarpc); + if (state->wb.irpc_handle == NULL) { + DEBUG(0,("Failed to get binding_handle for winbind_server task\n")); + state->dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + + /* + * 60 seconds timeout should be enough + */ + dcerpc_binding_handle_set_timeout(state->wb.irpc_handle, 60); + return NT_STATUS_NONE_MAPPED; } @@ -1606,6 +2019,116 @@ static NTSTATUS dcesrv_lsa_lookup_sid_winbind( struct dcesrv_lsa_LookupSids_base_state *state, struct dcesrv_lsa_TranslatedItem *item) { + const struct lsa_TrustDomainInfoInfoEx *tdo = NULL; + const struct lsa_ForestTrustDomainInfo *di = NULL; + struct dcesrv_lsa_TranslatedItem tmp; + struct dom_sid domain_sid = {0,}; + NTSTATUS status; + bool match; + + /* + * Verify the sid is not INVALID. + */ + tmp = *item; + status = dom_sid_lookup_predefined_sid(tmp.sid, + &tmp.name, + &tmp.type, + &tmp.authority_sid, + &tmp.authority_name); + if (NT_STATUS_IS_OK(status)) { + status = NT_STATUS_NONE_MAPPED; + } + if (!NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED)) { + /* + * Typically INVALID_SID + */ + return status; + } + + if (state->routing_table == NULL) { + struct lsa_policy_state *policy_state = state->policy_state; + + status = dsdb_trust_routing_table_load(policy_state->sam_ldb, + state, + &state->routing_table); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + domain_sid = *item->sid; + if (domain_sid.num_auths == 5) { + sid_split_rid(&domain_sid, NULL); + } + + tdo = dsdb_trust_domain_by_sid(state->routing_table, + &domain_sid, &di); + if (tdo == NULL) { + /* + * The sid is not resolvable at all... + */ + return NT_STATUS_OK; + } + + if (tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) { + /* + * The name should have been resolved in the account view. + * + * TODO: handle multiple domains in a forest... + */ + return NT_STATUS_OK; + } + + match = dom_sid_equal(di->domain_sid, item->sid); + if (match) { + const char *name = NULL; + + name = talloc_strdup(state->mem_ctx, + di->netbios_domain_name.string); + if (name == NULL) { + return NT_STATUS_NO_MEMORY; + } + + item->type = SID_NAME_DOMAIN; + item->name = name; + item->authority_name = name; + item->authority_sid = item->sid; + return NT_STATUS_OK; + } + + /* + * We know at least the domain part of the sid exists. + * + * For now the rest handled within winbindd. + * + * In future we can optimize it based on + * r->in.level. + * + * We can also try to resolve SID_NAME_DOMAIN + * just based on the routing table. + */ + if (state->wb.irpc_handle != NULL) { + /* + * already called... + */ + return NT_STATUS_NONE_MAPPED; + } + + state->wb.irpc_handle = irpc_binding_handle_by_name(state, + state->dce_call->msg_ctx, + "winbind_server", + &ndr_table_lsarpc); + if (state->wb.irpc_handle == NULL) { + DEBUG(0,("Failed to get binding_handle for winbind_server task\n")); + state->dce_call->fault_code = DCERPC_FAULT_CANT_PERFORM; + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + + /* + * 60 seconds timeout should be enough + */ + dcerpc_binding_handle_set_timeout(state->wb.irpc_handle, 60); + return NT_STATUS_NONE_MAPPED; } -- 2.13.6