diff options
author | Stefan Metzmacher <metze@samba.org> | 2015-03-25 19:11:12 +0000 |
---|---|---|
committer | Günther Deschner <gd@samba.org> | 2015-03-30 13:41:25 +0200 |
commit | 654d63b94b8f5802a6efe1db6c1367dd8cf8cf04 (patch) | |
tree | ca40ef5ae6976ab7db84938bf3fd5b9d5bf4e425 /source4/rpc_server/lsa | |
parent | a09f9cfd2f95667dae96f34b81023360d40a1783 (diff) | |
download | samba-654d63b94b8f5802a6efe1db6c1367dd8cf8cf04.tar.gz |
s4:rpc_server/lsa: implement the policy security descriptor
We now check the requested access mask in OpenPolicy*()
and return NT_STATUS_ACCESS_DENIED if the request is not granted.
E.g. validating a domain trust via the Windows gui requires this
in order prompt the user for the credentials. Otherwise
we fail any other call with ACCESS_DENIED later and the
gui just displays a strange error message.
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Guenther Deschner <gd@samba.org>
Diffstat (limited to 'source4/rpc_server/lsa')
-rw-r--r-- | source4/rpc_server/lsa/dcesrv_lsa.c | 41 | ||||
-rw-r--r-- | source4/rpc_server/lsa/lsa.h | 3 | ||||
-rw-r--r-- | source4/rpc_server/lsa/lsa_init.c | 81 | ||||
-rw-r--r-- | source4/rpc_server/lsa/lsa_lookup.c | 8 |
4 files changed, 115 insertions, 18 deletions
diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c index 2a465d4d812..bbd2a727b0a 100644 --- a/source4/rpc_server/lsa/dcesrv_lsa.c +++ b/source4/rpc_server/lsa/dcesrv_lsa.c @@ -349,7 +349,9 @@ static NTSTATUS dcesrv_lsa_QuerySecurity(struct dcesrv_call_state *dce_call, TAL struct lsa_QuerySecurity *r) { struct dcesrv_handle *h; - struct security_descriptor *sd; + const struct security_descriptor *sd = NULL; + uint32_t access_granted = 0; + struct sec_desc_buf *sdbuf = NULL; NTSTATUS status; struct dom_sid *sid; @@ -358,19 +360,38 @@ static NTSTATUS dcesrv_lsa_QuerySecurity(struct dcesrv_call_state *dce_call, TAL sid = &dce_call->conn->auth_state.session_info->security_token->sids[PRIMARY_USER_SID_INDEX]; if (h->wire_handle.handle_type == LSA_HANDLE_POLICY) { - status = dcesrv_build_lsa_sd(mem_ctx, &sd, sid, 0); - } else if (h->wire_handle.handle_type == LSA_HANDLE_ACCOUNT) { - status = dcesrv_build_lsa_sd(mem_ctx, &sd, sid, + struct lsa_policy_state *pstate = h->data; + + sd = pstate->sd; + access_granted = pstate->access_mask; + + } else if (h->wire_handle.handle_type == LSA_HANDLE_ACCOUNT) { + struct lsa_account_state *astate = h->data; + struct security_descriptor *_sd = NULL; + + status = dcesrv_build_lsa_sd(mem_ctx, &_sd, sid, LSA_ACCOUNT_ALL_ACCESS); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + sd = _sd; + access_granted = astate->access_mask; } else { return NT_STATUS_INVALID_HANDLE; } - NT_STATUS_NOT_OK_RETURN(status); - (*r->out.sdbuf) = talloc(mem_ctx, struct sec_desc_buf); - NT_STATUS_HAVE_NO_MEMORY(*r->out.sdbuf); + sdbuf = talloc_zero(mem_ctx, struct sec_desc_buf); + if (sdbuf == NULL) { + return NT_STATUS_NO_MEMORY; + } + + status = security_descriptor_for_client(sdbuf, sd, r->in.sec_info, + access_granted, &sdbuf->sd); + if (!NT_STATUS_IS_OK(status)) { + return status; + } - (*r->out.sdbuf)->sd = sd; + *r->out.sdbuf = sdbuf; return NT_STATUS_OK; } @@ -421,7 +442,9 @@ static WERROR dcesrv_dssetup_DsRoleGetPrimaryDomainInformation(struct dcesrv_cal struct GUID domain_guid; struct lsa_policy_state *state; - NTSTATUS status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state); + NTSTATUS status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, + 0, /* we skip access checks */ + &state); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); } diff --git a/source4/rpc_server/lsa/lsa.h b/source4/rpc_server/lsa/lsa.h index dc0c7d67950..5c00ba548b6 100644 --- a/source4/rpc_server/lsa/lsa.h +++ b/source4/rpc_server/lsa/lsa.h @@ -41,7 +41,6 @@ struct lsa_policy_state { struct dcesrv_handle *handle; struct ldb_context *sam_ldb; struct ldb_context *pdb; - uint32_t access_mask; struct ldb_dn *domain_dn; struct ldb_dn *forest_dn; struct ldb_dn *builtin_dn; @@ -56,6 +55,8 @@ struct lsa_policy_state { struct dom_sid *creator_owner_domain_sid; struct dom_sid *world_domain_sid; int mixed_domain; + struct security_descriptor *sd; + uint32_t access_mask; }; enum lsa_handle { diff --git a/source4/rpc_server/lsa/lsa_init.c b/source4/rpc_server/lsa/lsa_init.c index 4cf79a23460..5628c5b45b8 100644 --- a/source4/rpc_server/lsa/lsa_init.c +++ b/source4/rpc_server/lsa/lsa_init.c @@ -22,9 +22,36 @@ #include "rpc_server/lsa/lsa.h" -NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, +/* + * This matches a Windows 2012R2 dc in + * a domain with function level 2012R2. + */ +#define DCESRV_LSA_POLICY_SD_SDDL \ + "O:BAG:SY" \ + "D:" \ + "(D;;0x00000800;;;AN)" \ + "(A;;GA;;;BA)" \ + "(A;;GX;;;WD)" \ + "(A;;0x00000801;;;AN)" \ + "(A;;0x00001000;;;LS)" \ + "(A;;0x00001000;;;NS)" \ + "(A;;0x00001000;;;IS)" \ + "(A;;0x00000801;;;S-1-15-2-1)" + +static const struct generic_mapping dcesrv_lsa_policy_mapping = { + LSA_POLICY_READ, + LSA_POLICY_WRITE, + LSA_POLICY_EXECUTE, + LSA_POLICY_ALL_ACCESS +}; + +NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, + TALLOC_CTX *mem_ctx, + uint32_t access_desired, struct lsa_policy_state **_state) { + struct auth_session_info *session_info = dce_call->conn->auth_state.session_info; + enum security_user_level security_level; struct lsa_policy_state *state; struct ldb_result *dom_res; const char *dom_attrs[] = { @@ -37,7 +64,7 @@ NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_ char *p; int ret; - state = talloc(mem_ctx, struct lsa_policy_state); + state = talloc_zero(mem_ctx, struct lsa_policy_state); if (!state) { return NT_STATUS_NO_MEMORY; } @@ -143,6 +170,49 @@ NTSTATUS dcesrv_lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_ return NT_STATUS_NO_SUCH_DOMAIN; } + state->sd = sddl_decode(state, DCESRV_LSA_POLICY_SD_SDDL, + state->domain_sid); + if (state->sd == NULL) { + return NT_STATUS_NO_MEMORY; + } + state->sd->dacl->revision = SECURITY_ACL_REVISION_NT4; + + se_map_generic(&access_desired, &dcesrv_lsa_policy_mapping); + security_acl_map_generic(state->sd->dacl, &dcesrv_lsa_policy_mapping); + + security_level = security_session_user_level(session_info, NULL); + if (security_level >= SECURITY_SYSTEM) { + /* + * The security descriptor doesn't allow system, + * but we want to allow system via ncalrpc as root. + */ + state->access_mask = access_desired; + if (state->access_mask & SEC_FLAG_MAXIMUM_ALLOWED) { + state->access_mask &= ~SEC_FLAG_MAXIMUM_ALLOWED; + state->access_mask |= LSA_POLICY_ALL_ACCESS; + } + } else { + NTSTATUS status; + + status = se_access_check(state->sd, + session_info->security_token, + access_desired, + &state->access_mask); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(2,("%s: access desired[0x%08X] rejected[0x%08X] - %s\n", + __func__, + (unsigned)access_desired, + (unsigned)state->access_mask, + nt_errstr(status))); + return status; + } + } + + DEBUG(10,("%s: access desired[0x%08X] granted[0x%08X] - success.\n", + __func__, + (unsigned)access_desired, + (unsigned)state->access_mask)); + *_state = state; return NT_STATUS_OK; @@ -172,7 +242,9 @@ NTSTATUS dcesrv_lsa_OpenPolicy2(struct dcesrv_call_state *dce_call, TALLOC_CTX * return NT_STATUS_INVALID_PARAMETER; } - status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &state); + status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, + r->in.access_mask, + &state); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -184,9 +256,6 @@ NTSTATUS dcesrv_lsa_OpenPolicy2(struct dcesrv_call_state *dce_call, TALLOC_CTX * handle->data = talloc_steal(handle, state); - /* need to check the access mask against - need ACLs - fails - WSPP test */ - state->access_mask = r->in.access_mask; state->handle = handle; *r->out.handle = handle->wire_handle; diff --git a/source4/rpc_server/lsa/lsa_lookup.c b/source4/rpc_server/lsa/lsa_lookup.c index 8d92ba89d06..9a8fdfb74ca 100644 --- a/source4/rpc_server/lsa/lsa_lookup.c +++ b/source4/rpc_server/lsa/lsa_lookup.c @@ -736,7 +736,9 @@ NTSTATUS dcesrv_lsa_LookupSids3(struct dcesrv_call_state *dce_call, DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } - status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &policy_state); + status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, + 0, /* we skip access checks */ + &policy_state); if (!NT_STATUS_IS_OK(status)) { return status; } @@ -962,7 +964,9 @@ NTSTATUS dcesrv_lsa_LookupNames4(struct dcesrv_call_state *dce_call, TALLOC_CTX DCESRV_FAULT(DCERPC_FAULT_ACCESS_DENIED); } - status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, &policy_state); + status = dcesrv_lsa_get_policy_state(dce_call, mem_ctx, + 0, /* we skip access checks */ + &policy_state); if (!NT_STATUS_IS_OK(status)) { return status; } |