diff options
Diffstat (limited to 'source4/dsdb')
-rw-r--r-- | source4/dsdb/common/util.c | 111 | ||||
-rw-r--r-- | source4/dsdb/kcc/kcc_periodic.c | 116 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 68 |
3 files changed, 221 insertions, 74 deletions
diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 6da02b0b6a..b5005444cc 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -36,6 +36,7 @@ #include "libcli/ldap/ldap_ndr.h" #include "param/param.h" #include "libcli/auth/libcli_auth.h" +#include "librpc/gen_ndr/ndr_drsblobs.h" /* search the sam for the specified attributes in a specific domain, filter on @@ -2146,3 +2147,113 @@ int dsdb_find_guid_by_dn(struct ldb_context *ldb, talloc_free(tmp_ctx); return LDB_SUCCESS; } + + + +/* + load a repsFromTo blob list for a given partition GUID + attr must be "repsFrom" or "repsTo" + */ +WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, + const char *attr, struct repsFromToBlob **r, uint32_t *count) +{ + const char *attrs[] = { attr, NULL }; + struct ldb_result *res = NULL; + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + int i; + struct ldb_message_element *el; + + *r = NULL; + *count = 0; + + if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS || + res->count < 1) { + DEBUG(0,("dsdb_loadreps: failed to read partition object\n")); + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + el = ldb_msg_find_element(res->msgs[0], attr); + if (el == NULL) { + /* it's OK to be empty */ + talloc_free(tmp_ctx); + return WERR_OK; + } + + *count = el->num_values; + *r = talloc_array(mem_ctx, struct repsFromToBlob, *count); + if (*r == NULL) { + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + for (i=0; i<(*count); i++) { + enum ndr_err_code ndr_err; + ndr_err = ndr_pull_struct_blob(&el->values[i], + mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")), + &(*r)[i], + (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; + } + } + + talloc_free(tmp_ctx); + + return WERR_OK; +} + +/* + save the repsFromTo blob list for a given partition GUID + attr must be "repsFrom" or "repsTo" + */ +WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn, + const char *attr, struct repsFromToBlob *r, uint32_t count) +{ + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + struct ldb_message *msg; + struct ldb_message_element *el; + int i; + + msg = ldb_msg_new(tmp_ctx); + msg->dn = dn; + if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) { + goto failed; + } + + el->values = talloc_array(msg, struct ldb_val, count); + if (!el->values) { + goto failed; + } + + for (i=0; i<count; i++) { + struct ldb_val v; + enum ndr_err_code ndr_err; + + ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")), + &r[i], + (ndr_push_flags_fn_t)ndr_push_repsFromToBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + goto failed; + } + + el->num_values++; + el->values[i] = v; + } + + if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) { + DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx))); + goto failed; + } + + talloc_free(tmp_ctx); + + return WERR_OK; + +failed: + talloc_free(tmp_ctx); + return WERR_DS_DRA_INTERNAL_ERROR; +} + + diff --git a/source4/dsdb/kcc/kcc_periodic.c b/source4/dsdb/kcc/kcc_periodic.c index 649efd51ca..3af79d8b89 100644 --- a/source4/dsdb/kcc/kcc_periodic.c +++ b/source4/dsdb/kcc/kcc_periodic.c @@ -35,11 +35,71 @@ #include "param/param.h" /* - * add a repsFrom to all our partitions + * see if a repsFromToBlob is in a list */ +static bool reps_in_list(struct repsFromToBlob *r, struct repsFromToBlob *reps, uint32_t count) +{ + int i; + for (i=0; i<count; i++) { + if (strcmp(r->ctr.ctr1.other_info->dns_name, + reps[i].ctr.ctr1.other_info->dns_name) == 0 && + GUID_compare(&r->ctr.ctr1.source_dsa_obj_guid, + &reps[i].ctr.ctr1.source_dsa_obj_guid) == 0) { + return true; + } + } + return false; +} /* + * add any missing repsFrom structures to our partitions + */ +static NTSTATUS kccsrv_add_repsFrom(struct kccsrv_service *s, TALLOC_CTX *mem_ctx, + struct repsFromToBlob *reps, uint32_t count) +{ + struct kccsrv_partition *p; + + /* update the repsFrom on all partitions */ + for (p=s->partitions; p; p=p->next) { + struct repsFromToBlob *old_reps; + uint32_t old_count; + WERROR werr; + int i; + bool modified = false; + + werr = dsdb_loadreps(s->samdb, mem_ctx, p->dn, "repsFrom", &old_reps, &old_count); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(0,(__location__ ": Failed to load repsFrom from %s - %s\n", + ldb_dn_get_linearized(p->dn), ldb_errstring(s->samdb))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + for (i=0; i<count; i++) { + if (!reps_in_list(&reps[i], old_reps, old_count)) { + old_reps = talloc_realloc(mem_ctx, old_reps, struct repsFromToBlob, old_count+1); + NT_STATUS_HAVE_NO_MEMORY(old_reps); + old_reps[old_count] = reps[i]; + old_count++; + modified = true; + } + } + + if (modified) { + werr = dsdb_savereps(s->samdb, mem_ctx, p->dn, "repsFrom", old_reps, old_count); + if (!W_ERROR_IS_OK(werr)) { + DEBUG(0,(__location__ ": Failed to save repsFrom to %s - %s\n", + ldb_dn_get_linearized(p->dn), ldb_errstring(s->samdb))); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + } + } + + return NT_STATUS_OK; + +} + +/* this is the core of our initial simple KCC We just add a repsFrom entry for all DCs we find that have nTDSDSA objects, except for ourselves @@ -49,9 +109,8 @@ static NTSTATUS kccsrv_simple_update(struct kccsrv_service *s, TALLOC_CTX *mem_c struct ldb_result *res; int ret, i; const char *attrs[] = { "objectGUID", "invocationID", NULL }; - struct ldb_message *msg; - struct ldb_message_element *el; - struct kccsrv_partition *p; + struct repsFromToBlob *reps = NULL; + uint32_t count = 0; ret = ldb_search(s->samdb, mem_ctx, &res, s->config_dn, LDB_SCOPE_SUBTREE, attrs, "objectClass=nTDSDSA"); @@ -60,21 +119,10 @@ static NTSTATUS kccsrv_simple_update(struct kccsrv_service *s, TALLOC_CTX *mem_c return NT_STATUS_INTERNAL_DB_CORRUPTION; } - msg = ldb_msg_new(mem_ctx); - NT_STATUS_HAVE_NO_MEMORY(msg); - - ret = ldb_msg_add_empty(msg, "repsFrom", LDB_FLAG_MOD_REPLACE, &el); - if (ret != LDB_SUCCESS) { - return NT_STATUS_NO_MEMORY; - } - for (i=0; i<res->count; i++) { - struct repsFromToBlob r; struct repsFromTo1 *r1; struct repsFromTo1OtherInfo oi; struct GUID ntds_guid, invocation_id; - struct ldb_val v; - enum ndr_err_code ndr_err; ntds_guid = samdb_result_guid(res->msgs[i], "objectGUID"); if (GUID_compare(&ntds_guid, &s->ntds_guid) == 0) { @@ -84,10 +132,13 @@ static NTSTATUS kccsrv_simple_update(struct kccsrv_service *s, TALLOC_CTX *mem_c invocation_id = samdb_result_guid(res->msgs[i], "invocationID"); - ZERO_STRUCT(r); + reps = talloc_realloc(mem_ctx, reps, struct repsFromToBlob, count+1); + NT_STATUS_HAVE_NO_MEMORY(reps); + + ZERO_STRUCT(reps[count]); ZERO_STRUCT(oi); - r.version = 1; - r1 = &r.ctr.ctr1; + reps[count].version = 1; + r1 = &reps[count].ctr.ctr1; oi.dns_name = talloc_asprintf(mem_ctx, "%s._msdcs.%s", GUID_string(mem_ctx, &ntds_guid), @@ -100,35 +151,10 @@ static NTSTATUS kccsrv_simple_update(struct kccsrv_service *s, TALLOC_CTX *mem_c DRSUAPI_DS_REPLICA_NEIGHBOUR_SYNC_ON_STARTUP | DRSUAPI_DS_REPLICA_NEIGHBOUR_DO_SCHEDULED_SYNCS; memset(r1->schedule, 0x11, sizeof(r1->schedule)); - - - ndr_err = ndr_push_struct_blob(&v, mem_ctx, - lp_iconv_convenience(s->task->lp_ctx), - &r, - (ndr_push_flags_fn_t)ndr_push_repsFromToBlob); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(0,(__location__ ": Failed tp push repsFrom blob\n")); - return NT_STATUS_INTERNAL_ERROR; - } - - el->values = talloc_realloc(msg, el->values, struct ldb_val, el->num_values+1); - NT_STATUS_HAVE_NO_MEMORY(el->values); - el->values[el->num_values] = v; - el->num_values++; - } - - /* replace the repsFrom on all partitions */ - for (p=s->partitions; p; p=p->next) { - msg->dn = p->dn; - ret = ldb_modify(s->samdb, msg); - if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ ": Failed to store repsFrom for %s - %s\n", - ldb_dn_get_linearized(msg->dn), ldb_errstring(s->samdb))); - return NT_STATUS_INTERNAL_ERROR; - } + count++; } - return NT_STATUS_OK; + return kccsrv_add_repsFrom(s, mem_ctx, reps, count); } diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index fbcde764cc..e7ca074779 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -280,7 +280,7 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) schema = dsdb_get_schema(ldb); if (!schema) { ldb_debug_set(ldb, LDB_DEBUG_FATAL, - "replmd_modify: no dsdb_schema loaded"); + "replmd_add: no dsdb_schema loaded"); return LDB_ERR_CONSTRAINT_VIOLATION; } @@ -475,10 +475,9 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, struct ldb_message_element *el, struct replPropertyMetaDataBlob *omd, struct dsdb_schema *schema, - uint64_t seq_num, + uint64_t *seq_num, const struct GUID *our_invocation_id, - NTTIME now, - bool *modified) + NTTIME now) { int i; const struct dsdb_attribute *a; @@ -512,15 +511,25 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, omd->ctr.ctr1.count++; } + /* Get a new sequence number from the backend. We only do this + * if we have a change that requires a new + * replPropertyMetaData element + */ + if (*seq_num == 0) { + int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num); + if (ret != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + } + md1 = &omd->ctr.ctr1.array[i]; md1->version = 1; md1->attid = a->attributeID_id; md1->originating_change_time = now; md1->originating_invocation_id = *our_invocation_id; - md1->originating_usn = seq_num; - md1->local_usn = seq_num; + md1->originating_usn = *seq_num; + md1->local_usn = *seq_num; - *modified = true; return LDB_SUCCESS; } @@ -530,13 +539,12 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, * client is based on this object */ static int replmd_update_rpmd(struct ldb_context *ldb, struct ldb_message *msg, - uint64_t seq_num) + uint64_t *seq_num) { const struct ldb_val *omd_value; enum ndr_err_code ndr_err; struct replPropertyMetaDataBlob omd; int i; - bool modified = false; struct dsdb_schema *schema; time_t t = time(NULL); NTTIME now; @@ -590,13 +598,17 @@ static int replmd_update_rpmd(struct ldb_context *ldb, struct ldb_message *msg, for (i=0; i<msg->num_elements; i++) { ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num, - our_invocation_id, now, &modified); + our_invocation_id, now); if (ret != LDB_SUCCESS) { return ret; } } - if (modified) { + /* + * replmd_update_rpmd_element has done an update if the + * seq_num is set + */ + if (*seq_num != 0) { struct ldb_val *md_value; struct ldb_message_element *el; @@ -640,7 +652,7 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) struct ldb_message *msg; int ret; time_t t = time(NULL); - uint64_t seq_num; + uint64_t seq_num = 0; /* do not manipulate our control entries */ if (ldb_dn_is_special(req->op.mod.message->dn)) { @@ -683,27 +695,11 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) * attribute was changed */ - /* Get a sequence number from the backend */ - ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num); - if (ret != LDB_SUCCESS) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = replmd_update_rpmd(ldb, msg, seq_num); + ret = replmd_update_rpmd(ldb, msg, &seq_num); if (ret != LDB_SUCCESS) { return ret; } - if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) { - talloc_free(ac); - return LDB_ERR_OPERATIONS_ERROR; - } - - if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) { - talloc_free(ac); - return LDB_ERR_OPERATIONS_ERROR; - } - /* TODO: * - sort the attributes by attid with replmd_ldb_message_sort() * - replace the old object with the newly constructed one @@ -719,6 +715,20 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) } talloc_steal(down_req, msg); + /* we only change whenChanged and uSNChanged if the seq_num + has changed */ + if (seq_num != 0) { + if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) { + talloc_free(ac); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) { + talloc_free(ac); + return LDB_ERR_OPERATIONS_ERROR; + } + } + /* go on with the call chain */ return ldb_next_request(module, down_req); } |