From 57bcdf008fa44d4c550819cbceada968b11be63c Mon Sep 17 00:00:00 2001 From: Fernando J V da Silva Date: Thu, 15 Apr 2010 17:37:40 -0300 Subject: s4-drs: samdb_is_rodc() function and new samdb_rodc() function This patch creates the samdb_is_rodc() function, which looks for the NTDSDSA object for a DC that has a specific invocationId and if msDS-isRODC is present on such object and it is TRUE, then consider the DC as a RODC. The new samdb_rodc() function uses the samdb_is_rodc() function for the local server. Signed-off-by: Andrew Tridgell --- source4/dsdb/common/util.c | 73 +++++++++++++++++-------------- source4/dsdb/kcc/kcc_topology.c | 18 ++++++-- source4/dsdb/repl/drepl_out_helpers.c | 5 ++- source4/dsdb/repl/drepl_service.c | 5 ++- source4/rpc_server/drsuapi/getncchanges.c | 14 +++++- source4/rpc_server/lsa/dcesrv_lsa.c | 4 +- 6 files changed, 80 insertions(+), 39 deletions(-) diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 30cb5c5c99..842f56b3ed 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2618,50 +2618,59 @@ int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1, return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id); } + /* - see if we are a RODC + see if a computer identified by its invocationId is a RODC */ -bool samdb_rodc(struct ldb_context *sam_ctx) -{ - TALLOC_CTX *tmp_ctx; - const char *obj_category; - struct ldb_dn *obj_category_dn; - const struct ldb_val *obj_category_dn_rdn_val; +int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *invocationId, bool *is_rodc) +{ + /* 1) find the DN for this servers NTDSDSA object + 2) search for the msDS-isRODC attribute + 3) if not present then not a RODC + 4) if present and TRUE then is a RODC + */ + struct ldb_dn *config_dn; + const char *attrs[] = { "msDS-isRODC", NULL }; + int ret; + struct ldb_result *res; + TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx); - tmp_ctx = talloc_new(sam_ctx); - if (tmp_ctx == NULL) { - DEBUG(1,("samdb_rodc: Failed to talloc new context.\n")); - goto failed; + config_dn = samdb_config_dn(sam_ctx); + if (!config_dn) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; } - obj_category = samdb_ntds_object_category(tmp_ctx, sam_ctx); - if (!obj_category) { - DEBUG(1,("samdb_rodc: Failed to get object category.\n")); - goto failed; + ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs, + DSDB_SEARCH_ONE_ONLY, "invocationID=%s", GUID_string(tmp_ctx, invocationId)); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; } - obj_category_dn = ldb_dn_new(tmp_ctx, sam_ctx, obj_category); - if (!obj_category_dn) { - DEBUG(1,("samdb_rodc: Failed to create object category dn.\n")); - goto failed; - } + ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0); + *is_rodc = (ret == 1); - obj_category_dn_rdn_val = ldb_dn_get_rdn_val(obj_category_dn); - if (!obj_category_dn_rdn_val) { - DEBUG(1, ("samdb_rodc: Failed to get object category dn rdn value.\n")); - goto failed; - } + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} - if (strequal((const char*)obj_category_dn_rdn_val->data, "NTDS-DSA-RO")) { - talloc_free(tmp_ctx); - return true; - } -failed: - talloc_free(tmp_ctx); - return false; +/* + see if we are a RODC +*/ +int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc) +{ + const struct GUID *invocationId; + invocationId = samdb_ntds_invocation_id(sam_ctx); + if (!invocationId) { + return LDB_ERR_OPERATIONS_ERROR; + } + return samdb_is_rodc(sam_ctx, invocationId, am_rodc); } + + /* return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1 diff --git a/source4/dsdb/kcc/kcc_topology.c b/source4/dsdb/kcc/kcc_topology.c index 72eb5e1137..215cc4d47e 100644 --- a/source4/dsdb/kcc/kcc_topology.c +++ b/source4/dsdb/kcc/kcc_topology.c @@ -1155,7 +1155,13 @@ static NTSTATUS kcctpl_get_all_bridgehead_dcs(struct ldb_context *ldb, el = ldb_msg_find_element(transport, "bridgeheadServerListBL"); - rodc = samdb_rodc(ldb); + ret = samdb_rodc(ldb, &rodc); + if (ret != LDB_SUCCESS) { + DEBUG(1, (__location__ ": unable to tell if we are an RODC: %s\n", + ldb_strerror(ret))); + talloc_free(tmp_ctx); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } transport_name = samdb_result_string(transport, "name", NULL); if (!transport_name) { @@ -3155,6 +3161,7 @@ static NTSTATUS kcctpl_create_connections(struct ldb_context *ldb, struct ldb_dn *transports_dn; const char * const attrs[] = { "bridgeheadServerListBL", "name", "transportAddressAttribute", NULL }; + int ret; connected = true; @@ -3223,14 +3230,19 @@ static NTSTATUS kcctpl_create_connections(struct ldb_context *ldb, return NT_STATUS_INTERNAL_DB_CORRUPTION; } - rodc = samdb_rodc(ldb); + ret = samdb_rodc(ldb, &rodc); + if (ret != LDB_SUCCESS) { + DEBUG(1, (__location__ ": Unable to tell if we are an RODC: %s\n", + ldb_strerror(ret))); + talloc_free(tmp_ctx); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } for (i = 0; i < st_edge_list.count; i++) { struct kcctpl_multi_edge *edge; struct GUID other_site_id; struct kcctpl_vertex *other_site_vertex; struct ldb_result *res; - int ret; struct ldb_message *transport, *r_bridgehead, *l_bridgehead; uint8_t schedule[84]; uint32_t first_available, j, interval; diff --git a/source4/dsdb/repl/drepl_out_helpers.c b/source4/dsdb/repl/drepl_out_helpers.c index a12481b897..07fb0b3d62 100644 --- a/source4/dsdb/repl/drepl_out_helpers.c +++ b/source4/dsdb/repl/drepl_out_helpers.c @@ -542,6 +542,8 @@ static void dreplsrv_update_refs_trigger(struct tevent_req *req) char *ntds_guid_str; char *ntds_dns_name; struct tevent_req *subreq; + bool am_rodc; + int ret; r = talloc(state, struct drsuapi_DsReplicaUpdateRefs); if (tevent_req_nomem(r, req)) { @@ -566,7 +568,8 @@ static void dreplsrv_update_refs_trigger(struct tevent_req *req) r->in.req.req1.dest_dsa_dns_name = ntds_dns_name; r->in.req.req1.dest_dsa_guid = service->ntds_guid; r->in.req.req1.options = DRSUAPI_DRS_ADD_REF | DRSUAPI_DRS_DEL_REF; - if (!samdb_rodc(service->samdb)) { + ret = samdb_rodc(service->samdb, &am_rodc); + if (ret == LDB_SUCCESS && !am_rodc) { r->in.req.req1.options |= DRSUAPI_DRS_WRIT_REP; } diff --git a/source4/dsdb/repl/drepl_service.c b/source4/dsdb/repl/drepl_service.c index 4196f94234..59436d6c0c 100644 --- a/source4/dsdb/repl/drepl_service.c +++ b/source4/dsdb/repl/drepl_service.c @@ -132,6 +132,8 @@ static void dreplsrv_task_init(struct task_server *task) WERROR status; struct dreplsrv_service *service; uint32_t periodic_startup_interval; + bool am_rodc; + int ret; switch (lp_server_role(task->lp_ctx)) { case ROLE_STANDALONE: @@ -194,7 +196,8 @@ static void dreplsrv_task_init(struct task_server *task) } /* if we are a RODC then we do not send DSReplicaSync*/ - if (!samdb_rodc(service->samdb)) { + ret = samdb_rodc(service->samdb, &am_rodc); + if (ret == LDB_SUCCESS && !am_rodc) { service->notify.interval = lp_parm_int(task->lp_ctx, NULL, "dreplsrv", "notify_interval", 5); /* in seconds */ status = dreplsrv_notify_schedule(service, service->notify.interval); diff --git a/source4/rpc_server/drsuapi/getncchanges.c b/source4/rpc_server/drsuapi/getncchanges.c index e70e863c36..56c061d2e8 100644 --- a/source4/rpc_server/drsuapi/getncchanges.c +++ b/source4/rpc_server/drsuapi/getncchanges.c @@ -684,6 +684,7 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ uint32_t options; uint32_t max_objects; struct ldb_dn *search_dn = NULL; + bool am_rodc; DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE); b_state = h->data; @@ -699,7 +700,8 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ r->out.ctr->ctr6.uptodateness_vector = NULL; /* a RODC doesn't allow for any replication */ - if (samdb_rodc(b_state->sam_ctx)) { + ret = samdb_rodc(b_state->sam_ctx, &am_rodc); + if (ret == LDB_SUCCESS && am_rodc) { DEBUG(0,(__location__ ": DsGetNCChanges attempt on RODC\n")); return WERR_DS_DRA_SOURCE_DISABLED; } @@ -733,6 +735,16 @@ WERROR dcesrv_drsuapi_DsGetNCChanges(struct dcesrv_call_state *dce_call, TALLOC_ return WERR_DS_DRA_SOURCE_DISABLED; } + if (req8->replica_flags & DRSUAPI_DRS_WRIT_REP) { + bool is_rodc; + ret = samdb_is_rodc(b_state->sam_ctx, &req8->source_dsa_invocation_id, &is_rodc); + if (ret != LDB_SUCCESS || is_rodc) { + DEBUG(0,(__location__ ": Attempt to do writeable replication by RODC %s\n", + GUID_string(mem_ctx, &req8->source_dsa_invocation_id))); + return WERR_DS_DRA_INVALID_PARAMETER; + } + } + if (req8->replica_flags & DRSUAPI_DRS_FULL_SYNC_PACKET) { /* Ignore the _in_ uptpdateness vector*/ diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c index 792b016e93..e683348140 100644 --- a/source4/rpc_server/lsa/dcesrv_lsa.c +++ b/source4/rpc_server/lsa/dcesrv_lsa.c @@ -1636,6 +1636,7 @@ static NTSTATUS setInfoTrustedDomain_base(struct dcesrv_call_state *dce_call, bool del_incoming = false; bool in_transaction = false; int ret; + bool am_rodc; switch (level) { case LSA_TRUSTED_DOMAIN_INFO_POSIX_OFFSET: @@ -1697,7 +1698,8 @@ static NTSTATUS setInfoTrustedDomain_base(struct dcesrv_call_state *dce_call, } } - if (samdb_rodc(p_state->sam_ldb)) { + ret = samdb_rodc(p_state->sam_ldb, &am_rodc); + if (ret == LDB_SUCCESS && am_rodc) { return NT_STATUS_NO_SUCH_DOMAIN; } -- cgit