TODO: add protection against DC restores
authorStefan Metzmacher <metze@samba.org>
Thu, 19 Apr 2018 12:38:38 +0000 (14:38 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 18 Feb 2019 10:31:19 +0000 (11:31 +0100)
source4/dsdb/repl/replicated_objects.c
source4/rpc_server/drsuapi/getncchanges.c

index 372fb2d6928625ae0a8373901b817a6fe195a342..7eb6e16319dece194645fc63c770c4cb0128e18d 100644 (file)
@@ -384,6 +384,57 @@ static bool dsdb_attid_in_list(const uint32_t attid_list[], uint32_t attid)
        return false;
 }
 
+static WERROR dsdb_verify_repl_meta_data(const struct drsuapi_DsReplicaMetaData *d,
+                                        const struct GUID *dst_invocation_id,
+                                        const struct GUID *src_invocation_id,
+                                        uint64_t src_last_hwm,
+                                        const * const char *error_hint)
+{
+       bool match;
+
+       *error_hint = NULL;
+
+       match = GUID_all_zero(&d->originating_invocation_id);
+       if (match) {
+               *error_hint = "got zero invocationID";
+               return WERR_DS_SRC_GUID_MISMATCH;
+       }
+
+       // TODO detect restored backup on source or destination dsa
+       // ERROR_DS_DRA_SOURCE_REINSTALLED
+       // ERROR_DS_EPOCH_MISMATCH
+       // ERROR_DS_SRC_GUID_MISMATCH
+       // ERROR_DS_OUT_OF_VERSION_STORE
+       // ERROR_DS_DIFFERENT_REPL_EPOCHS
+       // ERROR_DS_DRS_EXTENSIONS_CHANGED
+       // ERROR_DS_DUPLICATE_ID_FOUND
+       // ERROR_DS_DRA_OUT_SCHEDULE_WINDOW
+       // ERROR_DS_REPL_LIFETIME_EXCEEDED
+       // ERROR_DS_NO_NTDSA_OBJECT
+       // ERROR_DS_DRA_SOURCE_REINSTALLED
+       // ERROR_DS_DRA_INCONSISTENT_DIT
+
+       if (dst_invocation_id != NULL) {
+               match = GUID_equal(&d->originating_invocation_id,
+                                  dst_invocation_id);
+               if (match) {
+                       *error_hint = "got destination(local) invocationID";
+                       return WERR_DS_DRA_INCONSISTENT_DIT;
+               }
+       }
+
+       if (src_invocation_id != NULL) {
+               match = GUID_equal(&d->originating_invocation_id,
+                                  src_invocation_id);
+               if (match && d->originating_usn < src_last_hwm) {
+                       *error_hint = "got old source(remote) dsa stamp";
+                       return WERR_DS_DRA_SOURCE_REINSTALLED;
+               }
+       }
+
+       return WERR_OK;
+}
+
 WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
                              const struct dsdb_schema *schema,
                              struct ldb_dn *partition_dn,
@@ -458,6 +509,7 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
                struct replPropertyMetaData1 *m;
                struct ldb_message_element *e;
                uint32_t j;
+               const char *error_hint = NULL;
 
                a = &in->object.attribute_ctr.attributes[i];
                d = &in->meta_data_ctr->meta_data[i];
@@ -469,12 +521,17 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
                        continue;
                }
 
-               if (GUID_all_zero(&d->originating_invocation_id)) {
-                       status = WERR_DS_SRC_GUID_MISMATCH;
-                       DEBUG(0, ("Refusing replication of object containing invalid zero invocationID on attribute %d of %s: %s\n",
+               status = dsdb_verify_repl_meta_data(d,
+                                                   dst_invocation_id,
+                                                   src_invocation_id,
+                                                   src_last_hwm,
+                                                   &error_hint);
+               if (!W_ERROR_IS_OK(werr)) {
+                       DEBUG(0, ("Refusing replication of object on attribute %d of %s: %s - %s\n",
                                  a->attid,
                                  ldb_dn_get_linearized(msg->dn),
-                                 win_errstr(status)));
+                                 win_errstr(status),
+                                 error_hint));
                        return status;
                }
 
@@ -808,6 +865,20 @@ WERROR dsdb_replicated_objects_convert(struct ldb_context *ldb,
                                 i, ra->attid, win_errstr(status)));
                        return status;
                }
+
+               status = dsdb_verify_repl_meta_data(&la->meta_data,
+                                                   dst_invocation_id,
+                                                   src_invocation_id,
+                                                   src_last_hwm,
+                                                   &error_hint);
+               if (!W_ERROR_IS_OK(werr)) {
+                       DEBUG(0, ("Refusing replication of linked on attribute %d of <GUID=%s>: %s - %s\n",
+                                 la->attid,
+                                 GUID_string(out, &la->identifier->guid),,
+                                 win_errstr(status),
+                                 error_hint));
+                       return status;
+               }
        }
 
        out->linked_attributes_count = linked_attributes_count;
index 9a4da547e04fee64014c98d47d651bd11d374659..d49e07c6593b4e6d4d4c1dbeb6d40c6b1289b474 100644 (file)
@@ -2877,6 +2877,7 @@ allowed:
        }
 
        if (!GUID_equal(&req10->source_dsa_invocation_id, &invocation_id)) {
+               // TODO ERROR_DS_DRA_SOURCE_REINSTALLED ???
                /*
                 * The given highwatermark is only valid relative to the
                 * specified source_dsa_invocation_id.
@@ -2884,6 +2885,10 @@ allowed:
                ZERO_STRUCT(req10->highwatermark);
        }
 
+       if (req10->highwatermark.highest_usn > higest_local_usn) {
+               return WERR_DS_DRA_SOURCE_REINSTALLED;
+       }
+
        getnc_state = b_state->getncchanges_state;
 
        /* see if a previous replication has been abandoned */
@@ -3077,6 +3082,13 @@ allowed:
                                const struct drsuapi_DsReplicaCursor *cur =
                                        &udv->cursors[i];
 
+                               match = GUID_equal(&cur->source_dsa_invocation_id,
+                                                  dst_invocation_id);
+                               if (match) {
+                                       dst_highest_usn = cur->highest_usn;
+                                       continue;
+                               }
+
                                match = GUID_equal(&invocation_id,
                                                   &cur->source_dsa_invocation_id);
                                if (!match) {
@@ -3095,6 +3107,10 @@ allowed:
 
                getnc_state->max_usn = getnc_state->min_usn;
 
+               if (getnc_state->min_usn > higest_local_usn) {
+                       return WERR_DS_DRA_SOURCE_REINSTALLED;
+               }
+
                getnc_state->final_udv = talloc_zero(getnc_state,
                                        struct drsuapi_DsReplicaCursor2CtrEx);
                if (getnc_state->final_udv == NULL) {
@@ -3106,6 +3122,21 @@ allowed:
                        return werr;
                }
 
+               for (i = 0; i < getnc_state->final_udv->count; i++) {
+                       bool match;
+                       const struct drsuapi_DsReplicaCursor *cur =
+                                       &udv->cursors[i];
+
+                       match = GUID_equal(&cur->source_dsa_invocation_id,
+                                          dst_invocation_id);
+                       if (!match) {
+                               continue;
+                       }
+                       if (dst_highest_usn < cur->highest_usn) {
+                               return ERROR_DS_DUPLICATE_ID_FOUND;
+                       }
+               }
+
                if (req10->extended_op == DRSUAPI_EXOP_NONE) {
                        werr = getncchanges_collect_objects(b_state, mem_ctx, req10,
                                                            search_dn, extra_filter,