From bb1ba4ff76eb90d0d62dd3edbe288f45cf7a0a1e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 22 Apr 2010 16:48:01 +1000 Subject: s4-drs: added new SECURITY_RO_DOMAIN_CONTROLLER level This is used for allowing operations by RODCs, and denying them operations that should only be allowed for a full DC This required a new domain_sid argument to security_session_user_level() Pair-Programmed-With: Andrew Bartlett Pair-Programmed-With: Rusty Russell --- source4/dsdb/samdb/ldb_modules/kludge_acl.c | 2 +- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 2 +- source4/dsdb/samdb/ldb_modules/rootdse.c | 2 +- source4/dsdb/samdb/ldb_modules/util.c | 2 +- source4/libcli/security/security.h | 11 ++++++----- source4/libcli/security/security_token.c | 13 ++++++++++++- source4/rpc_server/drsuapi/addentry.c | 4 ++-- source4/rpc_server/drsuapi/dcesrv_drsuapi.c | 10 +++++----- source4/rpc_server/drsuapi/dcesrv_drsuapi.h | 3 ++- source4/rpc_server/drsuapi/drsutil.c | 8 +++++--- source4/rpc_server/drsuapi/updaterefs.c | 23 ++++++++++++++++++++--- source4/rpc_server/lsa/dcesrv_lsa.c | 10 +++++----- source4/rpc_server/winreg/rpc_winreg.c | 16 ++++++++-------- 13 files changed, 69 insertions(+), 37 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/kludge_acl.c b/source4/dsdb/samdb/ldb_modules/kludge_acl.c index 72863adebdb..42f0a306f43 100644 --- a/source4/dsdb/samdb/ldb_modules/kludge_acl.c +++ b/source4/dsdb/samdb/ldb_modules/kludge_acl.c @@ -56,7 +56,7 @@ static enum security_user_level what_is_user(struct ldb_module *module) struct ldb_context *ldb = ldb_module_get_ctx(module); struct auth_session_info *session_info = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); - return security_session_user_level(session_info); + return security_session_user_level(session_info, NULL); } static const char *user_name(TALLOC_CTX *mem_ctx, struct ldb_module *module) diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 75aed6ae7e4..efb44bfd4c0 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2402,7 +2402,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) if (next_deletion_state == OBJECT_REMOVED) { struct auth_session_info *session_info = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); - if (security_session_user_level(session_info) != SECURITY_SYSTEM) { + if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) { ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s", ldb_dn_get_linearized(old_msg->dn)); return LDB_ERR_UNWILLING_TO_PERFORM; diff --git a/source4/dsdb/samdb/ldb_modules/rootdse.c b/source4/dsdb/samdb/ldb_modules/rootdse.c index f10a125eb61..5fffef7c864 100644 --- a/source4/dsdb/samdb/ldb_modules/rootdse.c +++ b/source4/dsdb/samdb/ldb_modules/rootdse.c @@ -884,7 +884,7 @@ static int rootdse_enableoptionalfeature(struct ldb_module *module, struct ldb_r int ret; const char *guid_string; - if (security_session_user_level(session_info) != SECURITY_SYSTEM) { + if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) { ldb_asprintf_errstring(ldb, "rootdse: Insufficient rights for enableoptionalfeature"); return LDB_ERR_UNWILLING_TO_PERFORM; } diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index fe0ff7510ba..7913ac8049b 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -799,7 +799,7 @@ bool dsdb_module_am_system(struct ldb_module *module) struct ldb_context *ldb = ldb_module_get_ctx(module); struct auth_session_info *session_info = (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); - return security_session_user_level(session_info) == SECURITY_SYSTEM; + return security_session_user_level(session_info, NULL) == SECURITY_SYSTEM; } /* diff --git a/source4/libcli/security/security.h b/source4/libcli/security/security.h index e3fdb0c7948..585170ed61c 100644 --- a/source4/libcli/security/security.h +++ b/source4/libcli/security/security.h @@ -23,11 +23,12 @@ #include "librpc/gen_ndr/security.h" enum security_user_level { - SECURITY_ANONYMOUS, - SECURITY_USER, - SECURITY_DOMAIN_CONTROLLER, - SECURITY_ADMINISTRATOR, - SECURITY_SYSTEM + SECURITY_ANONYMOUS = 0, + SECURITY_USER = 10, + SECURITY_RO_DOMAIN_CONTROLLER = 20, + SECURITY_DOMAIN_CONTROLLER = 30, + SECURITY_ADMINISTRATOR = 40, + SECURITY_SYSTEM = 50 }; struct auth_session_info; diff --git a/source4/libcli/security/security_token.c b/source4/libcli/security/security_token.c index d3eff93ddb7..f105ed391f9 100644 --- a/source4/libcli/security/security_token.c +++ b/source4/libcli/security/security_token.c @@ -147,7 +147,8 @@ bool security_token_has_enterprise_dcs(const struct security_token *token) return security_token_has_sid_string(token, SID_NT_ENTERPRISE_DCS); } -enum security_user_level security_session_user_level(struct auth_session_info *session_info) +enum security_user_level security_session_user_level(struct auth_session_info *session_info, + const struct dom_sid *domain_sid) { if (!session_info) { return SECURITY_ANONYMOUS; @@ -165,6 +166,16 @@ enum security_user_level security_session_user_level(struct auth_session_info *s return SECURITY_ADMINISTRATOR; } + if (domain_sid && + dom_sid_in_domain(domain_sid, session_info->security_token->user_sid)) { + uint32_t rid; + NTSTATUS status = dom_sid_split_rid(NULL, session_info->security_token->user_sid, + NULL, &rid); + if (NT_STATUS_IS_OK(status) && rid == DOMAIN_RID_ENTERPRISE_READONLY_DCS) { + return SECURITY_RO_DOMAIN_CONTROLLER; + } + } + if (security_token_has_enterprise_dcs(session_info->security_token)) { return SECURITY_DOMAIN_CONTROLLER; } diff --git a/source4/rpc_server/drsuapi/addentry.c b/source4/rpc_server/drsuapi/addentry.c index cfddd80fe4b..e87c9405971 100644 --- a/source4/rpc_server/drsuapi/addentry.c +++ b/source4/rpc_server/drsuapi/addentry.c @@ -27,7 +27,7 @@ #include "param/param.h" #include "rpc_server/drsuapi/dcesrv_drsuapi.h" #include "librpc/gen_ndr/ndr_drsuapi.h" - +#include "libcli/security/security.h" /* add special SPNs needed for DRS replication to machine accounts when @@ -171,7 +171,7 @@ WERROR dcesrv_drsuapi_DsAddEntry(struct dcesrv_call_state *dce_call, TALLOC_CTX DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); b_state = h->data; - status = drs_security_level_check(dce_call, "DsAddEntry"); + status = drs_security_level_check(dce_call, "DsAddEntry", SECURITY_DOMAIN_CONTROLLER); if (!W_ERROR_IS_OK(status)) { return status; } diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c index 270c716d468..5d3c513f3f3 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.c +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.c @@ -65,7 +65,7 @@ static WERROR dcesrv_drsuapi_DsBind(struct dcesrv_call_state *dce_call, TALLOC_C W_ERROR_HAVE_NO_MEMORY(b_state); /* if this is a DC connecting, give them system level access */ - werr = drs_security_level_check(dce_call, NULL); + werr = drs_security_level_check(dce_call, NULL, SECURITY_DOMAIN_CONTROLLER); if (W_ERROR_IS_OK(werr)) { DEBUG(3,(__location__ ": doing DsBind with system_session\n")); auth_info = system_session(dce_call->conn->dce_ctx->lp_ctx); @@ -247,7 +247,7 @@ static WERROR dcesrv_drsuapi_DsReplicaSync(struct dcesrv_call_state *dce_call, T { WERROR status; - status = drs_security_level_check(dce_call, "DsReplicaSync"); + status = drs_security_level_check(dce_call, "DsReplicaSync", SECURITY_DOMAIN_CONTROLLER); if (!W_ERROR_IS_OK(status)) { return status; } @@ -401,7 +401,7 @@ static WERROR dcesrv_drsuapi_DsRemoveDSServer(struct dcesrv_call_state *dce_call *r->out.level_out = 1; - status = drs_security_level_check(dce_call, "DsRemoveDSServer"); + status = drs_security_level_check(dce_call, "DsRemoveDSServer", SECURITY_DOMAIN_CONTROLLER); if (!W_ERROR_IS_OK(status)) { return status; } @@ -726,7 +726,7 @@ static WERROR dcesrv_drsuapi_DsExecuteKCC(struct dcesrv_call_state *dce_call, TA struct drsuapi_DsExecuteKCC *r) { WERROR status; - status = drs_security_level_check(dce_call, "DsExecuteKCC"); + status = drs_security_level_check(dce_call, "DsExecuteKCC", SECURITY_DOMAIN_CONTROLLER); if (!W_ERROR_IS_OK(status)) { return status; @@ -748,7 +748,7 @@ static WERROR dcesrv_drsuapi_DsReplicaGetInfo(struct dcesrv_call_state *dce_call if (!lp_parm_bool(dce_call->conn->dce_ctx->lp_ctx, NULL, "drs", "disable_sec_check", false)) { - level = security_session_user_level(dce_call->conn->auth_state.session_info); + level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL); if (level < SECURITY_ADMINISTRATOR) { DEBUG(1,(__location__ ": Administrator access required for DsReplicaGetInfo\n")); security_token_debug(2, dce_call->conn->auth_state.session_info->security_token); diff --git a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h index ba6bb21145c..3b733deec1b 100644 --- a/source4/rpc_server/drsuapi/dcesrv_drsuapi.h +++ b/source4/rpc_server/drsuapi/dcesrv_drsuapi.h @@ -61,8 +61,9 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb, const char * const *attrs, const char *filter); +enum security_user_level; WERROR drs_security_level_check(struct dcesrv_call_state *dce_call, - const char* call); + const char* call, enum security_user_level minimum_level); void drsuapi_process_secret_attribute(struct drsuapi_DsReplicaAttribute *attr, struct drsuapi_DsReplicaMetaData *meta_data); diff --git a/source4/rpc_server/drsuapi/drsutil.c b/source4/rpc_server/drsuapi/drsutil.c index 28ec7bb8488..11eff25fabe 100644 --- a/source4/rpc_server/drsuapi/drsutil.c +++ b/source4/rpc_server/drsuapi/drsutil.c @@ -101,7 +101,9 @@ int drsuapi_search_with_extended_dn(struct ldb_context *ldb, return ret; } -WERROR drs_security_level_check(struct dcesrv_call_state *dce_call, const char* call) +WERROR drs_security_level_check(struct dcesrv_call_state *dce_call, + const char* call, + enum security_user_level minimum_level) { enum security_user_level level; @@ -110,8 +112,8 @@ WERROR drs_security_level_check(struct dcesrv_call_state *dce_call, const char* return WERR_OK; } - level = security_session_user_level(dce_call->conn->auth_state.session_info); - if (level < SECURITY_DOMAIN_CONTROLLER) { + level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL); + if (level < minimum_level) { if (call) { DEBUG(0,("%s refused for security token (level=%u)\n", call, (unsigned)level)); diff --git a/source4/rpc_server/drsuapi/updaterefs.c b/source4/rpc_server/drsuapi/updaterefs.c index dd3a3342b59..0403db8f88c 100644 --- a/source4/rpc_server/drsuapi/updaterefs.c +++ b/source4/rpc_server/drsuapi/updaterefs.c @@ -23,6 +23,8 @@ #include "rpc_server/dcerpc_server.h" #include "dsdb/samdb/samdb.h" #include "rpc_server/drsuapi/dcesrv_drsuapi.h" +#include "libcli/security/security.h" +#include "auth/session.h" struct repsTo { uint32_t count; @@ -189,11 +191,13 @@ WERROR dcesrv_drsuapi_DsReplicaUpdateRefs(struct dcesrv_call_state *dce_call, TA struct drsuapi_bind_state *b_state; struct drsuapi_DsReplicaUpdateRefsRequest1 *req; WERROR werr; + int ret; + enum security_user_level security_level; DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); b_state = h->data; - werr = drs_security_level_check(dce_call, "DsReplicaUpdateRefs"); + werr = drs_security_level_check(dce_call, "DsReplicaUpdateRefs", SECURITY_RO_DOMAIN_CONTROLLER); if (!W_ERROR_IS_OK(werr)) { return werr; } @@ -205,7 +209,20 @@ WERROR dcesrv_drsuapi_DsReplicaUpdateRefs(struct dcesrv_call_state *dce_call, TA req = &r->in.req.req1; + security_level = security_session_user_level(dce_call->conn->auth_state.session_info, NULL); + if (security_level < SECURITY_ADMINISTRATOR) { + /* check that they are using an invocationId that they own */ + ret = dsdb_validate_invocation_id(b_state->sam_ctx, + &req->dest_dsa_guid, + dce_call->conn->auth_state.session_info->security_token->user_sid); + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Refusing DsReplicaUpdateRefs for sid %s with GUID %s\n", + dom_sid_string(mem_ctx, + dce_call->conn->auth_state.session_info->security_token->user_sid), + GUID_string(mem_ctx, &req->dest_dsa_guid))); + return WERR_DS_DRA_ACCESS_DENIED; + } + } + return drsuapi_UpdateRefs(b_state, mem_ctx, req); } - - diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c index aaa0f7baa2e..8ab3cbfe6bd 100644 --- a/source4/rpc_server/lsa/dcesrv_lsa.c +++ b/source4/rpc_server/lsa/dcesrv_lsa.c @@ -180,7 +180,7 @@ static NTSTATUS dcesrv_lsa_DeleteObject(struct dcesrv_call_state *dce_call, TALL struct lsa_secret_state *secret_state = h->data; /* Ensure user is permitted to delete this... */ - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: @@ -2577,7 +2577,7 @@ static NTSTATUS dcesrv_lsa_AddRemoveAccountRights(struct dcesrv_call_state *dce_ struct lsa_EnumAccountRights r2; char *dnstr; - if (security_session_user_level(dce_call->conn->auth_state.session_info) < + if (security_session_user_level(dce_call->conn->auth_state.session_info, NULL) < SECURITY_ADMINISTRATOR) { DEBUG(0,("lsa_AddRemoveAccount refused for supplied security token\n")); return NT_STATUS_ACCESS_DENIED; @@ -2870,7 +2870,7 @@ static NTSTATUS dcesrv_lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALL DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY); ZERO_STRUCTP(r->out.sec_handle); - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: @@ -3019,7 +3019,7 @@ static NTSTATUS dcesrv_lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC return NT_STATUS_INVALID_PARAMETER; } - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: @@ -3299,7 +3299,7 @@ static NTSTATUS dcesrv_lsa_QuerySecret(struct dcesrv_call_state *dce_call, TALLO DCESRV_PULL_HANDLE(h, r->in.sec_handle, LSA_HANDLE_SECRET); /* Ensure user is permitted to read this... */ - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: diff --git a/source4/rpc_server/winreg/rpc_winreg.c b/source4/rpc_server/winreg/rpc_winreg.c index cfaee091133..c639c634d19 100644 --- a/source4/rpc_server/winreg/rpc_winreg.c +++ b/source4/rpc_server/winreg/rpc_winreg.c @@ -123,7 +123,7 @@ static WERROR dcesrv_winreg_CreateKey(struct dcesrv_call_state *dce_call, newh = dcesrv_handle_new(dce_call->context, HTYPE_REGKEY); - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: @@ -186,7 +186,7 @@ static WERROR dcesrv_winreg_DeleteKey(struct dcesrv_call_state *dce_call, DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY); key = h->data; - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: @@ -213,7 +213,7 @@ static WERROR dcesrv_winreg_DeleteValue(struct dcesrv_call_state *dce_call, DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY); key = h->data; - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: @@ -351,7 +351,7 @@ static WERROR dcesrv_winreg_FlushKey(struct dcesrv_call_state *dce_call, DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY); key = h->data; - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: @@ -413,7 +413,7 @@ static WERROR dcesrv_winreg_OpenKey(struct dcesrv_call_state *dce_call, DCESRV_PULL_HANDLE_FAULT(h, r->in.parent_handle, HTYPE_REGKEY); key = h->data; - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: @@ -454,7 +454,7 @@ static WERROR dcesrv_winreg_QueryInfoKey(struct dcesrv_call_state *dce_call, DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY); key = h->data; - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: @@ -505,7 +505,7 @@ static WERROR dcesrv_winreg_QueryValue(struct dcesrv_call_state *dce_call, DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY); key = h->data; - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: @@ -613,7 +613,7 @@ static WERROR dcesrv_winreg_SetValue(struct dcesrv_call_state *dce_call, DCESRV_PULL_HANDLE_FAULT(h, r->in.handle, HTYPE_REGKEY); key = h->data; - switch (security_session_user_level(dce_call->conn->auth_state.session_info)) + switch (security_session_user_level(dce_call->conn->auth_state.session_info, NULL)) { case SECURITY_SYSTEM: case SECURITY_ADMINISTRATOR: -- cgit v1.2.1