From 882768c8785995acccbdf562be99a68fc0dde33b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 13:47:46 +1100 Subject: s4-dsdb: give us an invocationID when in standalone mode To allow us to use the repl_meta_data module in standalone mode (and thus not have two module stacks to test), we need a invocationID stored somewhere when standalone. This creates a random one, and stores it in @SAMBA_DSDB. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/samba_dsdb.c | 80 ++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c index ee7e42ef9b..bfa2599afe 100644 --- a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c +++ b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c @@ -38,6 +38,7 @@ #include "dsdb/samdb/ldb_modules/util.h" #include "dsdb/samdb/samdb.h" +#include "librpc/ndr/libndr.h" static int read_at_rootdse_record(struct ldb_context *ldb, struct ldb_module *module, TALLOC_CTX *mem_ctx, struct ldb_message **msg) @@ -135,6 +136,55 @@ static int prepare_modules_line(struct ldb_context *ldb, return ret; } + + +/* + initialise the invocationID for a standalone server + */ +static int initialise_invocation_id(struct ldb_module *module, struct GUID *guid) +{ + struct ldb_message *msg; + struct ldb_context *ldb = ldb_module_get_ctx(module); + int ret; + + *guid = GUID_random(); + + msg = ldb_msg_new(module); + if (msg == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + msg->dn = ldb_dn_new(msg, ldb, "@SAMBA_DSDB"); + if (!msg->dn) { + ldb_module_oom(module); + talloc_free(msg); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = dsdb_msg_add_guid(msg, guid, "invocationID"); + if (ret != LDB_SUCCESS) { + ldb_module_oom(module); + talloc_free(msg); + return ret; + } + msg->elements[0].flags = LDB_FLAG_MOD_ADD; + + ret = ldb_modify(ldb, msg); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to setup standalone invocationID - %s", + ldb_errstring(ldb)); + talloc_free(msg); + return ret; + } + + DEBUG(1,("Initialised standalone invocationID to %s\n", + GUID_string(msg, guid))); + + talloc_free(msg); + + return LDB_SUCCESS; +} + + static int samba_dsdb_init(struct ldb_module *module) { struct ldb_context *ldb = ldb_module_get_ctx(module); @@ -213,7 +263,7 @@ static int samba_dsdb_init(struct ldb_module *module) static const char *openldap_backend_modules[] = { "entryuuid", "paged_searches", NULL }; - static const char *samba_dsdb_attrs[] = { "backendType", "serverRole", NULL }; + static const char *samba_dsdb_attrs[] = { "backendType", "serverRole", "invocationID", NULL }; const char *backendType, *serverRole; if (!tmp_ctx) { @@ -248,6 +298,34 @@ static int samba_dsdb_init(struct ldb_module *module) return ret; } + if (strcmp(serverRole, "standalone") == 0 || + strcmp(serverRole, "member server") == 0) { + struct GUID *guid; + + guid = talloc(module, struct GUID); + if (!guid) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + *guid = samdb_result_guid(res->msgs[0], "invocationID"); + if (GUID_all_zero(guid)) { + ret = initialise_invocation_id(module, guid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + + /* cache the domain_sid in the ldb. See the matching + * code in samdb_ntds_invocation_id() */ + ret = ldb_set_opaque(ldb, "cache.invocation_id", guid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + backend_modules = NULL; if (strcasecmp(backendType, "ldb") == 0) { if (strcasecmp(serverRole, "dc") == 0 || strcasecmp(serverRole, "domain controller") == 0) { -- cgit From 2c88ffb8f1f3691d29a88ab263dde5b07f4f400a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 20:54:23 +1100 Subject: s4-dsdb: added two new dsdb_get_extended_dn_*() helper functions Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/common/util.c | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 61d065b85c..774f9a757c 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2734,6 +2734,49 @@ NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid) return GUID_from_ndr_blob(v, guid); } +/* + return a NTTIME from a extended DN structure + */ +NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name) +{ + const struct ldb_val *v; + char *s; + + v = ldb_dn_get_extended_component(dn, component_name); + if (v == NULL) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + s = talloc_strndup(dn, (const char *)v->data, v->length); + NT_STATUS_HAVE_NO_MEMORY(s); + + *nttime = strtoull(s, NULL, 0); + + talloc_free(s); + return NT_STATUS_OK; +} + +/* + return a uint32_t from a extended DN structure + */ +NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name) +{ + const struct ldb_val *v; + char *s; + + v = ldb_dn_get_extended_component(dn, component_name); + if (v == NULL) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + s = talloc_strndup(dn, (const char *)v->data, v->length); + NT_STATUS_HAVE_NO_MEMORY(s); + + *val = strtoul(s, NULL, 0); + + talloc_free(s); + return NT_STATUS_OK; +} + /* return true if a ldb_val containing a DN in storage form is deleted */ -- cgit From e89a2db4f24ee70c45e0636e9baa8b6212a27cde Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 20:55:23 +1100 Subject: s4-dsdb: use varargs expression in dsdb_module_search() Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/util.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index 8d9930a81f..acc1c01959 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -164,15 +164,21 @@ int dsdb_module_search(struct ldb_module *module, struct ldb_dn *basedn, enum ldb_scope scope, const char * const *attrs, int dsdb_flags, - const char *expression) + const char *format, ...) _PRINTF_ATTRIBUTE(8, 9) { int ret; struct ldb_request *req; TALLOC_CTX *tmp_ctx; struct ldb_result *res; + va_list ap; + char *expression; tmp_ctx = talloc_new(mem_ctx); + va_start(ap, format); + expression = talloc_vasprintf(tmp_ctx, format, ap); + va_end(ap); + res = talloc_zero(tmp_ctx, struct ldb_result); if (!res) { return LDB_ERR_OPERATIONS_ERROR; -- cgit From 9d56f656d4f593289340a876445785cdfefd3d91 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 12:23:42 +1100 Subject: s4-dsdb: added dsdb_get_extended_dn_uint64() --- source4/dsdb/common/util.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 774f9a757c..b0f9ef0f35 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2735,9 +2735,9 @@ NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid) } /* - return a NTTIME from a extended DN structure + return a uint64_t from a extended DN structure */ -NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name) +NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name) { const struct ldb_val *v; char *s; @@ -2749,12 +2749,20 @@ NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const ch s = talloc_strndup(dn, (const char *)v->data, v->length); NT_STATUS_HAVE_NO_MEMORY(s); - *nttime = strtoull(s, NULL, 0); + *val = strtoull(s, NULL, 0); talloc_free(s); return NT_STATUS_OK; } +/* + return a NTTIME from a extended DN structure + */ +NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name) +{ + return dsdb_get_extended_dn_uint64(dn, nttime, component_name); +} + /* return a uint32_t from a extended DN structure */ -- cgit From a070119de34274e6122461d9cc0e9829b5fb6865 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 20:56:41 +1100 Subject: s4-dsdb: added DSDB_MODIFY_RELAX flag to the dsdb_module_*() calls --- source4/dsdb/samdb/ldb_modules/util.c | 7 +++++++ source4/dsdb/samdb/ldb_modules/util.h | 1 + 2 files changed, 8 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index acc1c01959..8503584ea6 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -87,6 +87,13 @@ int dsdb_request_add_controls(struct ldb_module *module, struct ldb_request *req } } + if (dsdb_flags & DSDB_MODIFY_RELAX) { + ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL); + if (ret != LDB_SUCCESS) { + return ret; + } + } + return LDB_SUCCESS; } diff --git a/source4/dsdb/samdb/ldb_modules/util.h b/source4/dsdb/samdb/ldb_modules/util.h index 41ed883dc2..cc184eee8f 100644 --- a/source4/dsdb/samdb/ldb_modules/util.h +++ b/source4/dsdb/samdb/ldb_modules/util.h @@ -28,3 +28,4 @@ struct GUID; #define DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT 0x0004 #define DSDB_SEARCH_REVEAL_INTERNALS 0x0008 #define DSDB_SEARCH_SHOW_EXTENDED_DN 0x0010 +#define DSDB_MODIFY_RELAX 0x0020 -- cgit From 47560bfda9932efa6b225a223aba662a4d72e637 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 20:58:00 +1100 Subject: s4-dsdb: don't use a non-constant format string for a printf format --- source4/dsdb/samdb/ldb_modules/util.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index 8503584ea6..b0ccd0341c 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -232,22 +232,15 @@ int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx, { struct ldb_result *res; const char *attrs[] = { NULL }; - char *expression; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); int ret; - expression = talloc_asprintf(tmp_ctx, "objectGUID=%s", GUID_string(tmp_ctx, guid)); - if (!expression) { - ldb_module_oom(module); - return LDB_ERR_OPERATIONS_ERROR; - } - ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs, DSDB_SEARCH_SHOW_DELETED | DSDB_SEARCH_SEARCH_ALL_PARTITIONS | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, - expression); + "objectGUID=%s", GUID_string(tmp_ctx, guid)); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -257,8 +250,8 @@ int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx, return LDB_ERR_NO_SUCH_OBJECT; } if (res->count != 1) { - ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching %s\n", - expression); + ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n", + GUID_string(tmp_ctx, guid)); talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } -- cgit From 2a4a159a8443ebaae53f5902a0f5c1f8536a6edd Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 23:32:48 +1100 Subject: s4-repl: lower debug level of a common message --- source4/dsdb/repl/drepl_notify.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/repl/drepl_notify.c b/source4/dsdb/repl/drepl_notify.c index e8652dcaf1..fe3b2d2497 100644 --- a/source4/dsdb/repl/drepl_notify.c +++ b/source4/dsdb/repl/drepl_notify.c @@ -404,7 +404,7 @@ WERROR dreplsrv_notify_schedule(struct dreplsrv_service *service, uint32_t next_ W_ERROR_HAVE_NO_MEMORY(new_te); tmp_mem = talloc_new(service); - DEBUG(2,("dreplsrv_notify_schedule(%u) %sscheduled for: %s\n", + DEBUG(4,("dreplsrv_notify_schedule(%u) %sscheduled for: %s\n", next_interval, (service->notify.te?"re":""), nt_time_string(tmp_mem, timeval_to_nttime(&next_time)))); -- cgit From d3708109a141f5d6468a89e35176cb56e7a8d821 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 10:26:06 +1100 Subject: s4-drs: another two unsigned comparison bugs --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 3ae165c6da..3d31cc3f49 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -336,7 +336,7 @@ static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMeta return -1; } - return m1->attid - m2->attid; + return m1->attid > m2->attid ? 1 : -1; } static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1, @@ -390,8 +390,10 @@ static int replmd_ldb_message_element_attid_sort(const struct ldb_message_elemen if (!a1 || !a2) { return strcasecmp(e1->name, e2->name); } - - return a1->attributeID_id - a2->attributeID_id; + if (a1->attributeID_id == a2->attributeID_id) { + return 0; + } + return a1->attributeID_id > a2->attributeID_id ? 1 : -1; } static void replmd_ldb_message_sort(struct ldb_message *msg, -- cgit From ec74ffa8f08d85c55ec7fc592101a21340b9a97d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 10:26:21 +1100 Subject: s4-schema: a unsigned comparison bug in the schema code --- source4/dsdb/schema/schema_query.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/schema/schema_query.c b/source4/dsdb/schema/schema_query.c index f563f01272..df17787f38 100644 --- a/source4/dsdb/schema/schema_query.c +++ b/source4/dsdb/schema/schema_query.c @@ -31,7 +31,8 @@ static const char **dsdb_full_attribute_list_internal(TALLOC_CTX *mem_ctx, static int uint32_cmp(uint32_t c1, uint32_t c2) { - return c1 - c2; + if (c1 == c2) return 0; + return c1 > c2 ? 1 : -1; } static int strcasecmp_with_ldb_val(const struct ldb_val *target, const char *str) -- cgit From 60acce584bf75c54c71813c93b6c607ef32c867d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 11:06:23 +1100 Subject: s4-repl: only try to replicate for NCs that we are a master for --- source4/dsdb/repl/drepl_partitions.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/repl/drepl_partitions.c b/source4/dsdb/repl/drepl_partitions.c index 85412a793c..5b8227e7de 100644 --- a/source4/dsdb/repl/drepl_partitions.c +++ b/source4/dsdb/repl/drepl_partitions.c @@ -39,16 +39,15 @@ WERROR dreplsrv_load_partitions(struct dreplsrv_service *s) struct ldb_dn *basedn; struct ldb_result *r; struct ldb_message_element *el; - static const char *attrs[] = { "namingContexts", NULL }; + static const char *attrs[] = { "hasMasterNCs", NULL }; uint32_t i; int ret; - basedn = ldb_dn_new(s, s->samdb, NULL); + basedn = samdb_ntds_settings_dn(s->samdb); W_ERROR_HAVE_NO_MEMORY(basedn); ret = ldb_search(s->samdb, s, &r, basedn, LDB_SCOPE_BASE, attrs, "(objectClass=*)"); - talloc_free(basedn); if (ret != LDB_SUCCESS) { return WERR_FOOBAR; } else if (r->count != 1) { @@ -56,7 +55,7 @@ WERROR dreplsrv_load_partitions(struct dreplsrv_service *s) return WERR_FOOBAR; } - el = ldb_msg_find_element(r->msgs[0], "namingContexts"); + el = ldb_msg_find_element(r->msgs[0], "hasMasterNCs"); if (!el) { return WERR_FOOBAR; } -- cgit From 92d75a4bfb1d666950f39aba19fcc4d97c2234ad Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 20:57:21 +1100 Subject: s4-kcc: don't crash with a NULL ntds connection list --- source4/dsdb/kcc/kcc_connection.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/kcc/kcc_connection.c b/source4/dsdb/kcc/kcc_connection.c index ee9a05a21e..73198040c4 100644 --- a/source4/dsdb/kcc/kcc_connection.c +++ b/source4/dsdb/kcc/kcc_connection.c @@ -133,7 +133,7 @@ void kccsrv_apply_connections(struct kccsrv_service *s, { int i, j, deleted = 0, added = 0, ret; - for (i = 0; i < ntds_list->count; i++) { + for (i = 0; ntds_list && i < ntds_list->count; i++) { struct kcc_connection *ntds = &ntds_list->servers[i]; for (j = 0; j < dsa_list->count; j++) { struct kcc_connection *dsa = &dsa_list->servers[j]; @@ -152,13 +152,13 @@ void kccsrv_apply_connections(struct kccsrv_service *s, for (i = 0; i < dsa_list->count; i++) { struct kcc_connection *dsa = &dsa_list->servers[i]; - for (j = 0; j < ntds_list->count; j++) { + for (j = 0; ntds_list && j < ntds_list->count; j++) { struct kcc_connection *ntds = &ntds_list->servers[j]; if (GUID_equal(&dsa->dsa_guid, &ntds->dsa_guid)) { break; } } - if (j == ntds_list->count) { + if (ntds_list == NULL || j == ntds_list->count) { ret = kccsrv_add_connection(s, dsa); if (ret == LDB_SUCCESS) { added++; -- cgit From 452fc0d6f44eea0876c3671400d8a8713d00ddce Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 20:58:09 +1100 Subject: s4-repl: give a reason why the prepare commit failed --- source4/dsdb/repl/replicated_objects.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c index 1efbd29d93..abd3ac85da 100644 --- a/source4/dsdb/repl/replicated_objects.c +++ b/source4/dsdb/repl/replicated_objects.c @@ -319,7 +319,8 @@ WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb, ret = ldb_transaction_prepare_commit(ldb); if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ " Failed to prepare commit of transaction\n")); + DEBUG(0,(__location__ " Failed to prepare commit of transaction: %s\n", + ldb_errstring(ldb))); return WERR_FOOBAR; } -- cgit From d9606d64ddad4e593b02310b392cd11ff4114aa1 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 03:53:13 +0200 Subject: s4-drs: Fix bug - prefixMap is not updated when adding new OIDs. The bug is that prefixMap is updated only memory when adding new Classs/Attribute that has and OID not in prefixMap already. Signed-off-by: Andrew Tridgell --- source4/dsdb/samdb/ldb_modules/schema_data.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c index ed10ae6d69..dfb322225a 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_data.c +++ b/source4/dsdb/samdb/ldb_modules/schema_data.c @@ -140,7 +140,6 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) const struct ldb_val *governsID = NULL; const char *oid_attr = NULL; const char *oid = NULL; - uint32_t attid; WERROR status; ldb = ldb_module_get_ctx(module); @@ -184,7 +183,7 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - status = dsdb_schema_pfm_make_attid(schema->prefixmap, oid, &attid); + status = dsdb_schema_pfm_find_oid(schema->prefixmap, oid, NULL); if (W_ERROR_IS_OK(status)) { return ldb_next_request(module, req); } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) { -- cgit From 14bac3a3e6a9308d9088559cf8f898b6ac4b4d68 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 03:58:29 +0200 Subject: Revert "s4-drs: cope with bogus empty attributes from w2k8-r2" This reverts commit 1287c1d115fb7e8f3954bc05ff65007968403a9c. Next patch should fix the "not recognized ATTIDs" problem Signed-off-by: Andrew Tridgell --- source4/dsdb/repl/replicated_objects.c | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c index abd3ac85da..c72b107b75 100644 --- a/source4/dsdb/repl/replicated_objects.c +++ b/source4/dsdb/repl/replicated_objects.c @@ -128,15 +128,6 @@ static WERROR dsdb_convert_object_ex(struct ldb_context *ldb, } status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, a, msg->elements, e); - if (!NT_STATUS_IS_OK(status) && a->value_ctr.num_values == 0) { - /* w2k8-r2 occasionally sends bogus empty - attributes with rubbish attribute IDs. The - only think we can do is discard these */ - DEBUG(0,(__location__ ": Discarding bogus empty DsReplicaAttribute with attid 0x%x\n", - a->attid)); - ZERO_STRUCTP(e); - continue; - } W_ERROR_NOT_OK_RETURN(status); m->attid = a->attid; @@ -157,14 +148,6 @@ static WERROR dsdb_convert_object_ex(struct ldb_context *ldb, } } - /* delete any empty elements */ - for (i=0; i < msg->num_elements; i++) { - if (msg->elements[i].name == NULL) { - ldb_msg_remove_element(msg, &msg->elements[i]); - i--; - } - } - if (rdn_m) { struct ldb_message_element *el; el = ldb_msg_find_element(msg, rdn_attr->lDAPDisplayName); -- cgit From 4e8ad284f5813413fdec8426f11e24570d22549b Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 04:08:52 +0200 Subject: s4-schema: Set ATTID in schema cache from "msDS-IntId" According to http://msdn.microsoft.com/en-us/library/cc223224%28PROT.13%29.aspx some Attributes OIDs may not use prefixMap. Setting ATTID in Schema Cache here should work, although this code snippet should be moved in separate function. Signed-off-by: Andrew Tridgell --- source4/dsdb/schema/schema_init.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index 4af36838cd..b8cbedcb7d 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -558,14 +558,19 @@ WERROR dsdb_attribute_from_ldb(struct ldb_context *ldb, /* set an invalid value */ attr->attributeID_id = 0xFFFFFFFF; } else { - status = dsdb_schema_pfm_make_attid(schema->prefixmap, - attr->attributeID_oid, - &attr->attributeID_id); - if (!W_ERROR_IS_OK(status)) { - DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n", - __location__, attr->lDAPDisplayName, attr->attributeID_oid, - win_errstr(status))); - return status; + /* check if msDS-IntId element is set */ + attr->attributeID_id = samdb_result_uint(msg, "msDS-IntId", 0xFFFFFFFF); + if (attr->attributeID_id == 0xFFFFFFFF) { + /* msDS-IntId is not set, make */ + status = dsdb_schema_pfm_make_attid(schema->prefixmap, + attr->attributeID_oid, + &attr->attributeID_id); + if (!W_ERROR_IS_OK(status)) { + DEBUG(0,("%s: '%s': unable to map attributeID %s: %s\n", + __location__, attr->lDAPDisplayName, attr->attributeID_oid, + win_errstr(status))); + return status; + } } } GET_GUID_LDB(msg, "schemaIDGUID", attr, schemaIDGUID); -- cgit From a409c0f0372e5a1d81b4acda5c0fc24ccbe68a7e Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Thu, 17 Dec 2009 23:26:47 +0200 Subject: s4-schema: Constraints on msDS-IntId attribute This attribute can not be modified on existing schema object. msDS-IntId is not allowed during attribute creation also. Signed-off-by: Andrew Tridgell --- source4/dsdb/samdb/ldb_modules/schema_data.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c index dfb322225a..cc609581e4 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_data.c +++ b/source4/dsdb/samdb/ldb_modules/schema_data.c @@ -169,6 +169,11 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) governsID = ldb_msg_find_ldb_val(req->op.add.message, "governsID"); if (attributeID) { + /* Sanity check for not allowed attributes */ + if (ldb_msg_find_ldb_val(req->op.add.message, "msDS-IntId")) { + return LDB_ERR_UNWILLING_TO_PERFORM; + } + oid_attr = "attributeID"; oid = talloc_strndup(req, (const char *)attributeID->data, attributeID->length); } else if (governsID) { @@ -204,6 +209,27 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) return ldb_next_request(module, req); } +static int schema_data_modify(struct ldb_module *module, struct ldb_request *req) +{ + /* special objects should always go through */ + if (ldb_dn_is_special(req->op.mod.message->dn)) { + return ldb_next_request(module, req); + } + + /* replicated update should always go through */ + if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) { + return ldb_next_request(module, req); + } + + /* msDS-IntId is not allowed to be modified */ + if (ldb_msg_find_ldb_val(req->op.mod.message, "msDS-IntId")) { + return LDB_ERR_CONSTRAINT_VIOLATION; + } + + /* go on with the call chain */ + return ldb_next_request(module, req); +} + static int generate_objectClasses(struct ldb_context *ldb, struct ldb_message *msg, const struct dsdb_schema *schema) { @@ -459,5 +485,6 @@ _PUBLIC_ const struct ldb_module_ops ldb_schema_data_module_ops = { .name = "schema_data", .init_context = schema_data_init, .add = schema_data_add, + .modify = schema_data_modify, .search = schema_data_search }; -- cgit From 516316b107e309a32362b7de9b010b73545480e0 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 03:46:39 +0200 Subject: s4-schema: Implement msDS-IntId attribute generation Signed-off-by: Andrew Tridgell --- source4/dsdb/samdb/ldb_modules/schema_data.c | 147 ++++++++++++++++++++++++--- 1 file changed, 133 insertions(+), 14 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/schema_data.c b/source4/dsdb/samdb/ldb_modules/schema_data.c index cc609581e4..2e99113953 100644 --- a/source4/dsdb/samdb/ldb_modules/schema_data.c +++ b/source4/dsdb/samdb/ldb_modules/schema_data.c @@ -92,6 +92,37 @@ struct schema_data_search_data { const struct dsdb_schema *schema; }; +/* context to be used during async operations */ +struct schema_data_context { + struct ldb_module *module; + struct ldb_request *req; + + const struct dsdb_schema *schema; +}; + +/* Create new context using + * ldb_request as memory context */ +static int _schema_data_context_new(struct ldb_module *module, + struct ldb_request *req, + struct schema_data_context **pac) +{ + struct schema_data_context *ac; + struct ldb_context *ldb; + + ldb = ldb_module_get_ctx(module); + + *pac = ac = talloc_zero(req, struct schema_data_context); + if (ac == NULL) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + ac->module = module; + ac->req = req; + ac->schema = dsdb_get_schema(ldb); + + return LDB_SUCCESS; +} + static int schema_data_init(struct ldb_module *module) { struct ldb_context *ldb; @@ -132,6 +163,57 @@ static int schema_data_init(struct ldb_module *module) return LDB_SUCCESS; } + +/* Generate new value for msDs-IntId + * Value should be in 0x80000000..0xBFFFFFFF range + * Generated value is added ldb_msg */ +static int _schema_data_gen_msds_intid(struct schema_data_context *ac, + struct ldb_message *ldb_msg) +{ + uint32_t id; + + /* generate random num in 0x80000000..0xBFFFFFFF */ + id = generate_random() % 0X3FFFFFFF; + id += 0x80000000; + + /* make sure id is unique and adjust if not */ + while (dsdb_attribute_by_attributeID_id(ac->schema, id)) { + id++; + if (id > 0xBFFFFFFF) { + id = 0x80000001; + } + } + + /* add generated msDS-IntId value to ldb_msg */ + return ldb_msg_add_fmt(ldb_msg, "msDS-IntId", "%d", id); +} + +static int _schema_data_add_callback(struct ldb_request *req, + struct ldb_reply *ares) +{ + struct schema_data_context *ac; + + ac = talloc_get_type(req->context, struct schema_data_context); + + if (!ares) { + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + if (ares->error != LDB_SUCCESS) { + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); + } + + if (ares->type != LDB_REPLY_DONE) { + talloc_free(ares); + return ldb_module_done(ac->req, NULL, NULL, + LDB_ERR_OPERATIONS_ERROR); + } + + return ldb_module_done(ac->req, ares->controls, + ares->response, ares->error); +} + static int schema_data_add(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; @@ -187,23 +269,60 @@ static int schema_data_add(struct ldb_module *module, struct ldb_request *req) ldb_oom(ldb); return LDB_ERR_OPERATIONS_ERROR; } - + status = dsdb_schema_pfm_find_oid(schema->prefixmap, oid, NULL); - if (W_ERROR_IS_OK(status)) { - return ldb_next_request(module, req); - } else if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) { - ldb_debug_set(ldb, LDB_DEBUG_ERROR, - "schema_data_add: failed to map %s[%s]: %s\n", - oid_attr, oid, win_errstr(status)); - return LDB_ERR_UNWILLING_TO_PERFORM; + if (!W_ERROR_IS_OK(status)) { + /* check for internal errors */ + if (!W_ERROR_EQUAL(WERR_DS_NO_MSDS_INTID, status)) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, + "schema_data_add: failed to map %s[%s]: %s\n", + oid_attr, oid, win_errstr(status)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + /* Update prefixMap and save it */ + status = dsdb_create_prefix_mapping(ldb, schema, oid); + if (!W_ERROR_IS_OK(status)) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, + "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n", + oid_attr, oid, win_errstr(status)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } } - status = dsdb_create_prefix_mapping(ldb, schema, oid); - if (!W_ERROR_IS_OK(status)) { - ldb_debug_set(ldb, LDB_DEBUG_ERROR, - "schema_data_add: failed to create prefix mapping for %s[%s]: %s\n", - oid_attr, oid, win_errstr(status)); - return LDB_ERR_UNWILLING_TO_PERFORM; + /* generate and add msDS-IntId attr value */ + if (attributeID + && (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2003) + && !(ldb_msg_find_attr_as_uint(req->op.add.message, "systemFlags", 0) & SYSTEM_FLAG_SCHEMA_BASE_OBJECT)) { + struct ldb_message *msg; + struct schema_data_context *ac; + struct ldb_request *add_req; + + if (_schema_data_context_new(module, req, &ac) != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* we have to copy the message as the caller might have it as a const */ + msg = ldb_msg_copy_shallow(ac, req->op.add.message); + if (msg == NULL) { + ldb_oom(ldb); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* generate unique value for msDS-IntId attr value */ + if (_schema_data_gen_msds_intid(ac, msg) != LDB_SUCCESS) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, + "_schema_data_gen_msds_intid() failed to generate msDS-IntId value\n"); + return LDB_ERR_OPERATIONS_ERROR; + } + + ldb_build_add_req(&add_req, ldb, ac, + msg, + req->controls, + ac, _schema_data_add_callback, + req); + + return ldb_next_request(module, add_req); } return ldb_next_request(module, req); -- cgit From 11e2c5777dc1bd8af1f696e04d0712fe43e7a21a Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 18:11:48 +0200 Subject: s4-dsdb-util: Utility function to process ldb_request in transaction This function is to be used later for manually crafted ldb_requests from within dsdb layer Signed-off-by: Andrew Tridgell --- source4/dsdb/common/util.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index b0f9ef0f35..4f7ddde14c 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -996,6 +996,32 @@ int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_m return ldb_modify(sam_ldb, msg); } +/* + * Handle ldb_request in transaction + */ +static int dsdb_autotransaction_request(struct ldb_context *sam_ldb, + struct ldb_request *req) +{ + int ret; + + ret = ldb_transaction_start(sam_ldb); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = ldb_request(sam_ldb, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + if (ret == LDB_SUCCESS) { + return ldb_transaction_commit(sam_ldb); + } + ldb_transaction_cancel(sam_ldb); + + return ret; +} + /* return a default security descriptor */ -- cgit From 7685bbbc4ea2ffc522a1582a561477dad2c862b2 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 18:14:38 +0200 Subject: s4-dsdb-util: Execute ldb_request using LDB_CONTROL_AS_SYSTEM This function is intended to be used when data needs to be modified skipping access checks. Signed-off-by: Andrew Tridgell --- source4/dsdb/common/util.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 4f7ddde14c..561edff94c 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -1022,6 +1022,55 @@ static int dsdb_autotransaction_request(struct ldb_context *sam_ldb, return ret; } +/* + * replace elements in a record using LDB_CONTROL_AS_SYSTEM + * used to skip access checks on operations + * that are performed by the system + */ +int samdb_replace_as_system(struct ldb_context *sam_ldb, + TALLOC_CTX *mem_ctx, + struct ldb_message *msg) +{ + int i; + int ldb_ret; + struct ldb_request *req = NULL; + + /* mark all the message elements as LDB_FLAG_MOD_REPLACE */ + for (i=0;inum_elements;i++) { + msg->elements[i].flags = LDB_FLAG_MOD_REPLACE; + } + + + ldb_ret = ldb_msg_sanity_check(sam_ldb, msg); + if (ldb_ret != LDB_SUCCESS) { + return ldb_ret; + } + + ldb_ret = ldb_build_mod_req(&req, sam_ldb, mem_ctx, + msg, + NULL, + NULL, + ldb_op_default_callback, + NULL); + + if (ldb_ret != LDB_SUCCESS) { + talloc_free(req); + return ldb_ret; + } + + ldb_ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL); + if (ldb_ret != LDB_SUCCESS) { + talloc_free(req); + return ldb_ret; + } + + /* do request and auto start a transaction */ + ldb_ret = dsdb_autotransaction_request(sam_ldb, req); + + talloc_free(req); + return ldb_ret; +} + /* return a default security descriptor */ -- cgit From 9f6c81874f6e63f30432814e4f443a69c4e04429 Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Fri, 18 Dec 2009 18:15:49 +0200 Subject: s4-drs: Save prefix map using LDB_CONTROL_AS_SYSTEM control Signed-off-by: Andrew Tridgell --- source4/dsdb/schema/schema_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/schema/schema_init.c b/source4/dsdb/schema/schema_init.c index b8cbedcb7d..ccdf97cf2d 100644 --- a/source4/dsdb/schema/schema_init.c +++ b/source4/dsdb/schema/schema_init.c @@ -310,7 +310,7 @@ WERROR dsdb_write_prefixes_from_schema_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_co return WERR_NOMEM; } - ldb_ret = samdb_replace( ldb, msg, msg ); + ldb_ret = samdb_replace_as_system(ldb, temp_ctx, msg); talloc_free(temp_ctx); -- cgit From 35b8808b94808f5d689c2b034ff5c21c739c11a4 Mon Sep 17 00:00:00 2001 From: Nadezhda Ivanova Date: Fri, 18 Dec 2009 18:00:15 +0200 Subject: Adapted acl module to skip checks if as_system control is provided. Signed-off-by: Andrew Tridgell --- source4/dsdb/samdb/ldb_modules/acl.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/acl.c b/source4/dsdb/samdb/ldb_modules/acl.c index b70b8956bb..a3298362f3 100644 --- a/source4/dsdb/samdb/ldb_modules/acl.c +++ b/source4/dsdb/samdb/ldb_modules/acl.c @@ -447,8 +447,10 @@ static int acl_allowedAttributes(struct ldb_module *module, if (ac->allowedAttributesEffective) { struct security_descriptor *sd; struct dom_sid *sid = NULL; + struct ldb_control *as_system = ldb_request_get_control(ac->req, + LDB_CONTROL_AS_SYSTEM_OID); ldb_msg_remove_attr(msg, "allowedAttributesEffective"); - if (ac->user_type == SECURITY_SYSTEM) { + if (ac->user_type == SECURITY_SYSTEM || as_system) { for (i=0; attr_list && attr_list[i]; i++) { ldb_msg_add_string(msg, "allowedAttributesEffective", attr_list[i]); } @@ -559,10 +561,12 @@ static int acl_childClassesEffective(struct ldb_module *module, const struct dsdb_schema *schema = dsdb_get_schema(ldb); const struct dsdb_class *sclass; struct security_descriptor *sd; + struct ldb_control *as_system = ldb_request_get_control(ac->req, + LDB_CONTROL_AS_SYSTEM_OID); struct dom_sid *sid = NULL; int i, j, ret; - if (ac->user_type == SECURITY_SYSTEM) { + if (ac->user_type == SECURITY_SYSTEM || as_system) { return acl_childClasses(module, sd_msg, msg, "allowedChildClassesEffective"); } @@ -635,6 +639,8 @@ static int acl_sDRightsEffective(struct ldb_module *module, struct ldb_message_element *rightsEffective; int ret; struct security_descriptor *sd; + struct ldb_control *as_system = ldb_request_get_control(ac->req, + LDB_CONTROL_AS_SYSTEM_OID); struct dom_sid *sid = NULL; uint32_t flags = 0; @@ -644,7 +650,7 @@ static int acl_sDRightsEffective(struct ldb_module *module, if (ret != LDB_SUCCESS) { return ret; } - if (ac->user_type == SECURITY_SYSTEM) { + if (ac->user_type == SECURITY_SYSTEM || as_system) { flags = SECINFO_OWNER | SECINFO_GROUP | SECINFO_SACL | SECINFO_DACL; } else { @@ -699,8 +705,9 @@ static int acl_add(struct ldb_module *module, struct ldb_request *req) const struct GUID *guid; struct object_tree *root = NULL; struct object_tree *new_node = NULL; + struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); - if (what_is_user(module) == SECURITY_SYSTEM) { + if (what_is_user(module) == SECURITY_SYSTEM || as_system) { return ldb_next_request(module, req); } @@ -752,6 +759,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) struct ldb_result *acl_res; struct security_descriptor *sd; struct dom_sid *sid = NULL; + struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); TALLOC_CTX *tmp_ctx = talloc_new(req); static const char *acl_attrs[] = { "nTSecurityDescriptor", @@ -765,7 +773,7 @@ static int acl_modify(struct ldb_module *module, struct ldb_request *req) { DEBUG(10, ("ldb:acl_modify: %s\n", req->op.mod.message->elements[0].name)); } - if (what_is_user(module) == SECURITY_SYSTEM) { + if (what_is_user(module) == SECURITY_SYSTEM || as_system) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.mod.message->dn)) { @@ -890,9 +898,10 @@ static int acl_delete(struct ldb_module *module, struct ldb_request *req) int ret; struct ldb_dn *parent = ldb_dn_get_parent(req, req->op.del.dn); struct ldb_context *ldb; + struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); DEBUG(10, ("ldb:acl_delete: %s\n", ldb_dn_get_linearized(req->op.del.dn))); - if (what_is_user(module) == SECURITY_SYSTEM) { + if (what_is_user(module) == SECURITY_SYSTEM || as_system) { return ldb_next_request(module, req); } @@ -934,6 +943,7 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req) const struct GUID *guid; struct object_tree *root = NULL; struct object_tree *new_node = NULL; + struct ldb_control *as_system = ldb_request_get_control(req, LDB_CONTROL_AS_SYSTEM_OID); TALLOC_CTX *tmp_ctx = talloc_new(req); NTSTATUS status; uint32_t access_granted; @@ -945,7 +955,7 @@ static int acl_rename(struct ldb_module *module, struct ldb_request *req) }; DEBUG(10, ("ldb:acl_rename: %s\n", ldb_dn_get_linearized(req->op.rename.olddn))); - if (what_is_user(module) == SECURITY_SYSTEM) { + if (what_is_user(module) == SECURITY_SYSTEM || as_system) { return ldb_next_request(module, req); } if (ldb_dn_is_special(req->op.rename.olddn)) { -- cgit From ad35153ef40ade858302dab2877353682604265b Mon Sep 17 00:00:00 2001 From: Kamen Mazdrashki Date: Sat, 19 Dec 2009 01:49:31 +0200 Subject: s4-drs: Implement constraints on ATTID values in prefixMap Ref: MS-ADTS, 3.1.1.2.6 ATTRTYP Signed-off-by: Andrew Tridgell --- source4/dsdb/schema/prefixmap.h | 11 +++++++++++ source4/dsdb/schema/schema_prefixmap.c | 24 ++++++++++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/schema/prefixmap.h b/source4/dsdb/schema/prefixmap.h index 816ddcfbb3..74acecb4ff 100644 --- a/source4/dsdb/schema/prefixmap.h +++ b/source4/dsdb/schema/prefixmap.h @@ -22,6 +22,17 @@ #ifndef _DSDB_PREFIXMAP_H #define _DSDB_PREFIXMAP_H +/** + * ATTRTYP ranges + * Ref: MS-ADTS, 3.1.1.2.6 ATTRTYP + */ +enum dsdb_attid_type { + dsdb_attid_type_pfm = 1, /* attid in [0x00000000..0x7FFFFFFF] */ + dsdb_attid_type_intid = 2, /* attid in [0x80000000..0xBFFFFFFF] */ + dsdb_attid_type_reserved = 3, /* attid in [0xC0000000..0xFFFEFFFF] */ + dsdb_attid_type_internal = 4, /* attid in [0xFFFF0000..0xFFFFFFFF] */ +}; + /** * oid-prefix in prefixmap */ diff --git a/source4/dsdb/schema/schema_prefixmap.c b/source4/dsdb/schema/schema_prefixmap.c index 969b357a39..89d33779e4 100644 --- a/source4/dsdb/schema/schema_prefixmap.c +++ b/source4/dsdb/schema/schema_prefixmap.c @@ -26,6 +26,25 @@ #include "../lib/util/asn1.h" +/** + * Determine range type for supplied ATTID + */ +enum dsdb_attid_type dsdb_pfm_get_attid_type(uint32_t attid) +{ + if (attid <= 0x7FFFFFFF) { + return dsdb_attid_type_pfm; + } + else if (attid <= 0xBFFFFFFF) { + return dsdb_attid_type_intid; + } + else if (attid <= 0xFFFEFFFF) { + return dsdb_attid_type_reserved; + } + else { + return dsdb_attid_type_internal; + } +} + /** * Allocates schema_prefixMap object in supplied memory context */ @@ -303,6 +322,11 @@ WERROR dsdb_schema_pfm_oid_from_attid(struct dsdb_schema_prefixmap *pfm, uint32_ struct dsdb_schema_prefixmap_oid *pfm_entry; WERROR werr = WERR_OK; + /* sanity check for attid requested */ + if (dsdb_pfm_get_attid_type(attid) != dsdb_attid_type_pfm) { + return WERR_INVALID_PARAMETER; + } + /* crack attid value */ hi_word = attid >> 16; lo_word = attid & 0xFFFF; -- cgit From 0c362597c0f933b3612bb17328c0a13b73d72e43 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 23:36:23 +1100 Subject: s4-schema: fixed the sorting of schema attributes another case of unsigned int subtracting breaking sorts. This one surfaced now as attributeID_id now can be larger than 2^31 --- source4/dsdb/schema/schema_set.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/schema/schema_set.c b/source4/dsdb/schema/schema_set.c index e65e372623..f59fc32696 100644 --- a/source4/dsdb/schema/schema_set.c +++ b/source4/dsdb/schema/schema_set.c @@ -180,13 +180,19 @@ op_error: return LDB_ERR_OPERATIONS_ERROR; } +static int uint32_cmp(uint32_t c1, uint32_t c2) +{ + if (c1 == c2) return 0; + return c1 > c2 ? 1 : -1; +} + static int dsdb_compare_class_by_lDAPDisplayName(struct dsdb_class **c1, struct dsdb_class **c2) { return strcasecmp((*c1)->lDAPDisplayName, (*c2)->lDAPDisplayName); } static int dsdb_compare_class_by_governsID_id(struct dsdb_class **c1, struct dsdb_class **c2) { - return (*c1)->governsID_id - (*c2)->governsID_id; + return uint32_cmp((*c1)->governsID_id, (*c2)->governsID_id); } static int dsdb_compare_class_by_governsID_oid(struct dsdb_class **c1, struct dsdb_class **c2) { @@ -203,7 +209,7 @@ static int dsdb_compare_attribute_by_lDAPDisplayName(struct dsdb_attribute **a1, } static int dsdb_compare_attribute_by_attributeID_id(struct dsdb_attribute **a1, struct dsdb_attribute **a2) { - return (*a1)->attributeID_id - (*a2)->attributeID_id; + return uint32_cmp((*a1)->attributeID_id, (*a2)->attributeID_id); } static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, struct dsdb_attribute **a2) { @@ -211,7 +217,7 @@ static int dsdb_compare_attribute_by_attributeID_oid(struct dsdb_attribute **a1, } static int dsdb_compare_attribute_by_linkID(struct dsdb_attribute **a1, struct dsdb_attribute **a2) { - return (*a1)->linkID - (*a2)->linkID; + return uint32_cmp((*a1)->linkID, (*a2)->linkID); } /* -- cgit From fbb59b2dcac1ce4d952c17d010ebf3bcfca863cd Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Tue, 29 Dec 2009 16:08:44 +0100 Subject: dsdb: Fix dependencies when building against system ldb. --- source4/dsdb/config.mk | 4 ++-- source4/dsdb/samdb/ldb_modules/config.mk | 17 +++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk index dfc5def64e..c5d1c24e04 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -22,7 +22,7 @@ $(eval $(call proto_header_template,$(dsdbsrcdir)/samdb/samdb_proto.h,$(SAMDB_OB # PUBLIC_HEADERS += dsdb/samdb/samdb.h [SUBSYSTEM::SAMDB_COMMON] -PRIVATE_DEPENDENCIES = LIBLDB +PRIVATE_DEPENDENCIES = LIBLDB NDR_DRSBLOBS LIBCLI_LDAP_NDR UTIL_LDB LIBCLI_AUTH SAMDB_COMMON_OBJ_FILES = $(addprefix $(dsdbsrcdir)/common/, \ util.o \ @@ -31,7 +31,7 @@ SAMDB_COMMON_OBJ_FILES = $(addprefix $(dsdbsrcdir)/common/, \ $(eval $(call proto_header_template,$(dsdbsrcdir)/common/proto.h,$(SAMDB_COMMON_OBJ_FILES:.o=.c))) [SUBSYSTEM::SAMDB_SCHEMA] -PRIVATE_DEPENDENCIES = SAMDB_COMMON NDR_DRSUAPI NDR_DRSBLOBS +PRIVATE_DEPENDENCIES = SAMDB_COMMON NDR_DRSUAPI NDR_DRSBLOBS LDBSAMBA SAMDB_SCHEMA_OBJ_FILES = $(addprefix $(dsdbsrcdir)/schema/, \ schema_init.o \ diff --git a/source4/dsdb/samdb/ldb_modules/config.mk b/source4/dsdb/samdb/ldb_modules/config.mk index 3bd38606ea..6128dc9d65 100644 --- a/source4/dsdb/samdb/ldb_modules/config.mk +++ b/source4/dsdb/samdb/ldb_modules/config.mk @@ -1,7 +1,7 @@ ################################################ # Start SUBSYSTEM DSDB_MODULE_HELPERS [SUBSYSTEM::DSDB_MODULE_HELPERS] -PRIVATE_DEPENDENCIES = LIBLDB +PRIVATE_DEPENDENCIES = LIBLDB LIBNDR SAMDB_SCHEMA DSDB_MODULE_HELPERS_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/util.o @@ -12,7 +12,7 @@ $(eval $(call proto_header_template,$(dsdbsrcdir)/samdb/ldb_modules/util_proto.h # Start MODULE ldb_samba_dsdb [MODULE::ldb_samba_dsdb] SUBSYSTEM = LIBLDB -PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS LIBNDR +PRIVATE_DEPENDENCIES = SAMDB LIBTALLOC LIBEVENTS LIBNDR DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(samba_dsdb) # End MODULE ldb_samba_dsdb ################################################ @@ -119,7 +119,7 @@ ldb_pdc_fsmo_OBJ_FILES = \ # Start MODULE ldb_samldb [MODULE::ldb_samldb] SUBSYSTEM = LIBLDB -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LDAP_ENCODE SAMDB +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LDAP_ENCODE SAMDB DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(samldb) # # End MODULE ldb_samldb @@ -242,7 +242,7 @@ ldb_extended_dn_out_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/extended_dn_out. # Start MODULE ldb_extended_dn_store [MODULE::ldb_extended_dn_store] SUBSYSTEM = LIBLDB -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL SAMDB +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL SAMDB DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(extended_dn_store) # End MODULE ldb_extended_dn_store ################################################ @@ -301,7 +301,7 @@ ldb_update_keytab_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/update_keytab.o [MODULE::ldb_objectclass] INIT_FUNCTION = LDB_MODULE(objectclass) CFLAGS = -Ilib/ldb/include -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB DSDB_MODULE_HELPERS LIBSAMBA-UTIL SUBSYSTEM = LIBLDB # End MODULE ldb_objectclass ################################################ @@ -325,7 +325,7 @@ ldb_subtree_rename_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/subtree_rename.o [MODULE::ldb_subtree_delete] INIT_FUNCTION = LDB_MODULE(subtree_delete) CFLAGS = -Ilib/ldb/include -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSAMBA-UTIL DSDB_MODULE_HELPERS SUBSYSTEM = LIBLDB # End MODULE ldb_subtree_rename ################################################ @@ -385,7 +385,7 @@ ldb_instancetype_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/instancetype.o [MODULE::ldb_operational] SUBSYSTEM = LIBLDB CFLAGS = -Ilib/ldb/include -PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT +PRIVATE_DEPENDENCIES = LIBTALLOC LIBTEVENT LIBSAMBA-UTIL SAMDB_COMMON DSDB_MODULE_HELPERS INIT_FUNCTION = LDB_MODULE(operational) # End MODULE ldb_operational ################################################ @@ -397,7 +397,8 @@ ldb_operational_OBJ_FILES = $(dsdbsrcdir)/samdb/ldb_modules/operational.o [MODULE::ldb_descriptor] INIT_FUNCTION = LDB_MODULE(descriptor) CFLAGS = -Ilib/ldb/include -PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB +PRIVATE_DEPENDENCIES = LIBTALLOC LIBEVENTS LIBSECURITY NDR_SECURITY SAMDB \ + DSDB_MODULE_HELPERS SUBSYSTEM = LIBLDB # End MODULE ldb_descriptor ################################################ -- cgit From 41c3c979ffc6b8eee795ec0616115b31f5dfd636 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 10 Dec 2009 23:48:30 +1100 Subject: s4-dsdb: add support for storing linked attribute meta data in extended DNs When in functional levels above w2k, we need to store much richer meta data about linkked attributes. We also need to keep deleted linked attributes around to allow the deletion to be propogated to other DCs. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 585 +++++++++++++++++++++++- 1 file changed, 566 insertions(+), 19 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 3d31cc3f49..7e1d7189b1 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -46,6 +46,9 @@ #include "libcli/security/dom_sid.h" #include "lib/util/dlinklist.h" #include "dsdb/samdb/ldb_modules/util.h" +#include "lib/util/binsearch.h" + +#define W2K3_LINKED_ATTRIBUTES 1 struct replmd_private { TALLOC_CTX *la_ctx; @@ -680,6 +683,20 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, for (i=0; ictr.ctr1.count; i++) { if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break; } + +#if W2K3_LINKED_ATTRIBUTES + if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) { + /* linked attributes are not stored in + replPropertyMetaData in FL above w2k, but we do + raise the seqnum for the object */ + if (*seq_num == 0 && + ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) { + return LDB_ERR_OPERATIONS_ERROR; + } + return LDB_SUCCESS; + } +#endif + if (i == omd->ctr.ctr1.count) { /* we need to add a new one */ omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array, @@ -721,13 +738,13 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, */ static int replmd_update_rpmd(struct ldb_module *module, const struct dsdb_schema *schema, - struct ldb_message *msg, uint64_t *seq_num) + struct ldb_message *msg, uint64_t *seq_num, + time_t t) { const struct ldb_val *omd_value; enum ndr_err_code ndr_err; struct replPropertyMetaDataBlob omd; int i; - time_t t = time(NULL); NTTIME now; const struct GUID *our_invocation_id; int ret; @@ -830,13 +847,555 @@ static int replmd_update_rpmd(struct ldb_module *module, } +struct parsed_dn { + struct dsdb_dn *dsdb_dn; + struct GUID *guid; + struct ldb_val *v; +}; + +static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2) +{ + return GUID_compare(pdn1->guid, pdn2->guid); +} + +static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid) +{ + struct parsed_dn *ret; + BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret); + return ret; +} + +/* + get a series of message element values as an array of DNs and GUIDs + the result is sorted by GUID + */ +static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, + struct ldb_message_element *el, struct parsed_dn **pdn, + const char *ldap_oid) +{ + int i; + struct ldb_context *ldb = ldb_module_get_ctx(module); + + if (el == NULL) { + *pdn = NULL; + return LDB_SUCCESS; + } + + (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values); + if (!*pdn) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + for (i=0; inum_values; i++) { + struct ldb_val *v = &el->values[i]; + NTSTATUS status; + struct ldb_dn *dn; + struct parsed_dn *p; + + p = &(*pdn)[i]; + + p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid); + if (p->dsdb_dn == NULL) { + return LDB_ERR_INVALID_DN_SYNTAX; + } + + dn = p->dsdb_dn->dn; + + p->guid = talloc(*pdn, struct GUID); + if (p->guid == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + status = dsdb_get_extended_dn_guid(dn, p->guid); + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + /* we got a DN without a GUID - go find the GUID */ + int ret = dsdb_find_guid_by_dn(ldb, dn, p->guid); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n", + ldb_dn_get_linearized(dn)); + return ret; + } + } else if (!NT_STATUS_IS_OK(status)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* keep a pointer to the original ldb_val */ + p->v = v; + } + + qsort(*pdn, el->num_values, sizeof((*pdn)[0]), (comparison_fn_t)parsed_dn_compare); + + return LDB_SUCCESS; +} + +/* + build a new extended DN, including all meta data fields + + DELETED = 1 or missing + RMD_ADDTIME = originating_add_time + RMD_INVOCID = originating_invocation_id + RMD_CHANGETIME = originating_change_time + RMD_USN = originating_usn + RMD_VERSION = version + */ +static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct parsed_dn *p, + const struct GUID *invocation_id, uint64_t seq_num, time_t t) +{ + struct ldb_dn *dn = p->dsdb_dn->dn; + NTTIME now; + const char *tstring, *usn_string; + struct ldb_val tval; + struct ldb_val iid; + struct ldb_val usnv; + struct ldb_val vers; + NTSTATUS status; + int ret; + const char *dnstring; + + unix_to_nt_time(&now, t); + tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now); + if (!tstring) { + return LDB_ERR_OPERATIONS_ERROR; + } + tval = data_blob_string_const(tstring); + + usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num); + if (!usn_string) { + return LDB_ERR_OPERATIONS_ERROR; + } + usnv = data_blob_string_const(usn_string); + + vers = data_blob_string_const("0"); + + status = GUID_to_ndr_blob(invocation_id, dn, &iid); + if (!NT_STATUS_IS_OK(status)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); + if (ret != LDB_SUCCESS) return ret; + + dnstring = dsdb_dn_get_extended_linearized(mem_ctx, p->dsdb_dn, 1); + if (dnstring == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + *v = data_blob_string_const(dnstring); + + return LDB_SUCCESS; +} + + +/* + update an extended DN, including all meta data fields + + see replmd_build_la_val for value names + */ +static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct parsed_dn *p, + struct parsed_dn *old_p, const struct GUID *invocation_id, + uint64_t seq_num, time_t t, bool deleted) +{ + struct ldb_dn *dn = p->dsdb_dn->dn; + NTTIME now; + const char *tstring, *usn_string; + struct ldb_val tval; + struct ldb_val iid; + struct ldb_val usnv; + struct ldb_val vers; + const struct ldb_val *old_addtime, *old_version; + NTSTATUS status; + int ret; + const char *dnstring; + + unix_to_nt_time(&now, t); + tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now); + if (!tstring) { + return LDB_ERR_OPERATIONS_ERROR; + } + tval = data_blob_string_const(tstring); + + usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num); + if (!usn_string) { + return LDB_ERR_OPERATIONS_ERROR; + } + usnv = data_blob_string_const(usn_string); + + status = GUID_to_ndr_blob(invocation_id, dn, &iid); + if (!NT_STATUS_IS_OK(status)) { + return LDB_ERR_OPERATIONS_ERROR; + } + + if (deleted) { + struct ldb_val dv; + dv = data_blob_string_const("1"); + ret = ldb_dn_set_extended_component(dn, "DELETED", &dv); + } else { + ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + } + if (ret != LDB_SUCCESS) return ret; + + /* get the ADDTIME from the original */ + old_addtime = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "RMD_ADDTIME"); + if (old_addtime == NULL) { + old_addtime = &tval; + } + if (p != old_p) { + ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime); + if (ret != LDB_SUCCESS) return ret; + } + + /* use our invocation id */ + ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid); + if (ret != LDB_SUCCESS) return ret; + + /* changetime is the current time */ + ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval); + if (ret != LDB_SUCCESS) return ret; + + /* update the USN */ + ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv); + if (ret != LDB_SUCCESS) return ret; + + /* increase the version by 1 */ + old_version = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "RMD_VERSION"); + if (old_version == NULL) { + vers = data_blob_string_const("0"); + } else { + char *vstring; + vstring = talloc_strndup(dn, (const char *)old_version->data, old_version->length); + if (!vstring) { + return LDB_ERR_OPERATIONS_ERROR; + } + vstring = talloc_asprintf(dn, "%lu", + (unsigned long)strtoul(vstring, NULL, 0)+1); + vers = data_blob_string_const(vstring); + } + ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); + if (ret != LDB_SUCCESS) return ret; + + dnstring = dsdb_dn_get_extended_linearized(mem_ctx, p->dsdb_dn, 1); + if (dnstring == NULL) { + return LDB_ERR_OPERATIONS_ERROR; + } + *v = data_blob_string_const(dnstring); + + return LDB_SUCCESS; +} + +/* + handle adding a linked attribute + */ +static int replmd_modify_la_add(struct ldb_module *module, + struct ldb_message *msg, + struct ldb_message_element *el, + struct ldb_message_element *old_el, + const struct dsdb_attribute *schema_attr, + uint64_t seq_num, + time_t t) +{ + int i; + struct parsed_dn *dns, *old_dns; + TALLOC_CTX *tmp_ctx = talloc_new(msg); + int ret; + struct ldb_val *new_values = NULL; + unsigned int num_new_values = 0; + unsigned old_num_values = old_el?old_el->num_values:0; + const struct GUID *invocation_id; + struct ldb_context *ldb = ldb_module_get_ctx(module); + + ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + invocation_id = samdb_ntds_invocation_id(ldb); + if (!invocation_id) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* for each new value, see if it exists already with the same GUID */ + for (i=0; inum_values; i++) { + struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid); + if (p == NULL) { + /* this is a new linked attribute value */ + new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1); + if (new_values == NULL) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = replmd_build_la_val(new_values, &new_values[num_new_values], &dns[i], + invocation_id, seq_num, t); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + num_new_values++; + } else { + /* this is only allowed if the GUID was + previously deleted. */ + const struct ldb_val *v; + v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); + if (v == NULL) { + ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s", + el->name, GUID_string(tmp_ctx, p->guid)); + talloc_free(tmp_ctx); + return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; + } + ret = replmd_update_la_val(old_el->values, p->v, &dns[i], p, invocation_id, seq_num, t, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + } + + /* add the new ones on to the end of the old values, constructing a new el->values */ + el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL, + struct ldb_val, old_num_values+num_new_values); + if (el->values == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val)); + el->num_values = old_num_values + num_new_values; + + talloc_steal(msg->elements, el->values); + talloc_steal(el->values, new_values); + + talloc_free(tmp_ctx); + + /* we now tell the backend to replace all existing values + with the one we have constructed */ + el->flags = LDB_FLAG_MOD_REPLACE; + + return LDB_SUCCESS; +} + + +/* + handle replacing a linked attribute + */ +static int replmd_modify_la_replace(struct ldb_module *module, + struct ldb_message *msg, + struct ldb_message_element *el, + struct ldb_message_element *old_el, + const struct dsdb_attribute *schema_attr, + uint64_t seq_num, + time_t t) +{ + return LDB_SUCCESS; +} + +/* + handle deleting all active linked attributes + */ +static int replmd_modify_la_delete(struct ldb_module *module, + struct ldb_message *msg, + struct ldb_message_element *el, + struct ldb_message_element *old_el, + const struct dsdb_attribute *schema_attr, + uint64_t seq_num, + time_t t) +{ + int i; + struct parsed_dn *dns, *old_dns; + TALLOC_CTX *tmp_ctx = talloc_new(msg); + int ret; + const struct GUID *invocation_id; + struct ldb_context *ldb = ldb_module_get_ctx(module); + + /* check if there is nothing to delete */ + if ((!old_el || old_el->num_values == 0) && + el->num_values == 0) { + return LDB_SUCCESS; + } + + if (!old_el || old_el->num_values == 0) { + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + + ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + invocation_id = samdb_ntds_invocation_id(ldb); + if (!invocation_id) { + return LDB_ERR_OPERATIONS_ERROR; + } + + el->values = NULL; + + /* see if we are being asked to delete any links that + don't exist or are already deleted */ + for (i=0; inum_values; i++) { + struct parsed_dn *p = &dns[i]; + struct parsed_dn *p2; + const struct ldb_val *v; + + p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid); + if (!p2) { + ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s", + el->name, GUID_string(tmp_ctx, p->guid)); + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); + if (v) { + ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s", + el->name, GUID_string(tmp_ctx, p->guid)); + return LDB_ERR_NO_SUCH_ATTRIBUTE; + } + } + + /* for each new value, see if it exists already with the same GUID + if it is not already deleted and matches the delete list then delete it + */ + for (i=0; inum_values; i++) { + struct parsed_dn *p = &old_dns[i]; + const struct ldb_val *v; + + if (dns && parsed_dn_find(dns, el->num_values, p->guid) == NULL) { + continue; + } + + v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); + if (v != NULL) continue; + + ret = replmd_update_la_val(old_el->values, p->v, p, p, invocation_id, seq_num, t, true); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + + el->values = talloc_steal(msg->elements, old_el->values); + el->num_values = old_el->num_values; + + talloc_free(tmp_ctx); + + /* we now tell the backend to replace all existing values + with the one we have constructed */ + el->flags = LDB_FLAG_MOD_REPLACE; + + return LDB_SUCCESS; +} + + + +/* + handle linked attributes in modify requests + */ +static int replmd_modify_handle_linked_attribs(struct ldb_module *module, + struct ldb_message *msg, + uint64_t seq_num, time_t t) +{ + struct ldb_result *res; + int ret, i; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct ldb_message *old_msg; + struct dsdb_schema *schema = dsdb_get_schema(ldb); + + if (seq_num == 0) { + /* there the replmd_update_rpmd code has already + * checked and saw that there are no linked + * attributes */ + return LDB_SUCCESS; + } + +#if !W2K3_LINKED_ATTRIBUTES + return LDB_SUCCESS; +#endif + + if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) { + /* don't do anything special for linked attributes */ + return LDB_SUCCESS; + } + + ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL, + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + if (ret != LDB_SUCCESS) { + return ret; + } + old_msg = res->msgs[0]; + + for (i=0; inum_elements; i++) { + struct ldb_message_element *el = &msg->elements[i]; + struct ldb_message_element *old_el; + const struct dsdb_attribute *schema_attr + = dsdb_attribute_by_lDAPDisplayName(schema, el->name); + if (!schema_attr) { + ldb_asprintf_errstring(ldb, + "attribute %s is not a valid attribute in schema", el->name); + return LDB_ERR_OBJECT_CLASS_VIOLATION; + } + if (schema_attr->linkID == 0) { + continue; + } + if ((schema_attr->linkID & 1) == 1) { + /* Odd is for the target. Illegal to modify */ + ldb_asprintf_errstring(ldb, + "attribute %s must not be modified directly, it is a linked attribute", el->name); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + old_el = ldb_msg_find_element(old_msg, el->name); + switch (el->flags) { + case LDB_FLAG_MOD_REPLACE: + ret = replmd_modify_la_replace(module, msg, el, old_el, schema_attr, seq_num, t); + break; + case LDB_FLAG_MOD_DELETE: + ret = replmd_modify_la_delete(module, msg, el, old_el, schema_attr, seq_num, t); + break; + case LDB_FLAG_MOD_ADD: + ret = replmd_modify_la_add(module, msg, el, old_el, schema_attr, seq_num, t); + break; + default: + ldb_asprintf_errstring(ldb, + "invalid flags 0x%x for %s linked attribute", + el->flags, el->name); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + } + + talloc_free(res); + return ret; +} + + + static int replmd_modify(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; struct replmd_replicated_request *ac; struct ldb_request *down_req; struct ldb_message *msg; - struct ldb_result *res; time_t t = time(NULL); int ret; @@ -862,24 +1421,13 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - /* TODO: - * - give an error when a readonly attribute should - * be modified - * - merge the changed into the old object - * if the caller set values to the same value - * ignore the attribute, return success when no - * attribute was changed - */ - - ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL, - DSDB_SEARCH_SHOW_DELETED | - DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(ac); return ret; } - ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num); + ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(ac); return ret; @@ -1970,6 +2518,7 @@ static int replmd_process_linked_attribute(struct ldb_module *module, struct ldb_message_element el; const struct ldb_val *guid; WERROR status; + time_t t = time(NULL); drs.value_ctr.num_values = 1; drs.value_ctr.values = &val; @@ -2077,7 +2626,7 @@ linked_attributes[0]: el.values[0] = data_blob_string_const(dsdb_dn_get_extended_linearized(tmp_ctx, dsdb_dn, 1)); } - ret = replmd_update_rpmd(module, schema, msg, &seq_num); + ret = replmd_update_rpmd(module, schema, msg, &seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -2086,8 +2635,6 @@ linked_attributes[0]: /* we only change whenChanged and uSNChanged if the seq_num has changed */ if (seq_num != 0) { - time_t t = time(NULL); - if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; -- cgit From d5020e3d917713549cee82d66fbcc78b88cebd6a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 10 Dec 2009 23:49:02 +1100 Subject: s4-dsdb: add a TODO item for linked attributes in extended_dn_out Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/extended_dn_in.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c index 89ba7bb04b..33931167c5 100644 --- a/source4/dsdb/samdb/ldb_modules/extended_dn_in.c +++ b/source4/dsdb/samdb/ldb_modules/extended_dn_in.c @@ -34,6 +34,11 @@ #include "ldb/include/ldb_errors.h" #include "ldb/include/ldb_module.h" +/* + TODO: if relax is not set then we need to reject the fancy RMD_* and + DELETED extended DN codes + */ + /* search */ struct extended_search_context { struct ldb_module *module; -- cgit From dee6b6fb3db03d371356b6d54d63bfde8ef153ae Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 14 Dec 2009 21:54:41 +1100 Subject: s4-dsdb: implemeneted replmd_modify_la_replace() We now have the core code for handling storage of linked attribute meta-data with local modifies Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 170 +++++++++++++++++++++--- 1 file changed, 152 insertions(+), 18 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 7e1d7189b1..249dd61a4a 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1170,7 +1170,8 @@ static int replmd_modify_la_add(struct ldb_module *module, /* add the new ones on to the end of the old values, constructing a new el->values */ el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL, - struct ldb_val, old_num_values+num_new_values); + struct ldb_val, + old_num_values+num_new_values); if (el->values == NULL) { ldb_module_oom(module); return LDB_ERR_OPERATIONS_ERROR; @@ -1192,20 +1193,6 @@ static int replmd_modify_la_add(struct ldb_module *module, } -/* - handle replacing a linked attribute - */ -static int replmd_modify_la_replace(struct ldb_module *module, - struct ldb_message *msg, - struct ldb_message_element *el, - struct ldb_message_element *old_el, - const struct dsdb_attribute *schema_attr, - uint64_t seq_num, - time_t t) -{ - return LDB_SUCCESS; -} - /* handle deleting all active linked attributes */ @@ -1266,7 +1253,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, el->name, GUID_string(tmp_ctx, p->guid)); return LDB_ERR_NO_SUCH_ATTRIBUTE; } - v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); + v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED"); if (v) { ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s", el->name, GUID_string(tmp_ctx, p->guid)); @@ -1307,6 +1294,134 @@ static int replmd_modify_la_delete(struct ldb_module *module, return LDB_SUCCESS; } +/* + handle replacing a linked attribute + */ +static int replmd_modify_la_replace(struct ldb_module *module, + struct ldb_message *msg, + struct ldb_message_element *el, + struct ldb_message_element *old_el, + const struct dsdb_attribute *schema_attr, + uint64_t seq_num, + time_t t) +{ + int i; + struct parsed_dn *dns, *old_dns; + TALLOC_CTX *tmp_ctx = talloc_new(msg); + int ret; + const struct GUID *invocation_id; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct ldb_val *new_values = NULL; + uint32_t num_new_values = 0; + unsigned old_num_values = old_el?old_el->num_values:0; + + /* check if there is nothing to replace */ + if ((!old_el || old_el->num_values == 0) && + el->num_values == 0) { + return LDB_SUCCESS; + } + + ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + invocation_id = samdb_ntds_invocation_id(ldb); + if (!invocation_id) { + return LDB_ERR_OPERATIONS_ERROR; + } + + /* mark all the old ones as deleted */ + for (i=0; inum_values, old_p->guid); + if (p) { + /* we don't delete it if we are re-adding it */ + continue; + } + v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED"); + if (v) continue; + + ret = replmd_update_la_val(old_el->values, old_p->v, old_p, old_p, + invocation_id, seq_num, t, true); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + + /* for each new value, either update its meta-data, or add it + * to old_el + */ + for (i=0; inum_values; i++) { + struct parsed_dn *p = &dns[i], *old_p; + + if (old_dns && + (old_p = parsed_dn_find(old_dns, + old_num_values, p->guid)) != NULL) { + /* update in place */ + ret = replmd_update_la_val(old_el->values, old_p->v, old_p, + old_p, invocation_id, + seq_num, t, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } else { + /* add a new one */ + new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, + num_new_values+1); + if (new_values == NULL) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = replmd_build_la_val(new_values, &new_values[num_new_values], &dns[i], + invocation_id, seq_num, t); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + num_new_values++; + } + } + + /* add the new values to the end of old_el */ + if (num_new_values != 0) { + el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL, + struct ldb_val, old_num_values+num_new_values); + if (el->values == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + memcpy(&el->values[old_num_values], &new_values[0], + sizeof(struct ldb_val)*num_new_values); + el->num_values = old_num_values + num_new_values; + talloc_steal(msg->elements, new_values); + } else { + el->values = old_el->values; + el->num_values = old_el->num_values; + talloc_steal(msg->elements, el->values); + } + + talloc_free(tmp_ctx); + + /* we now tell the backend to replace all existing values + with the one we have constructed */ + el->flags = LDB_FLAG_MOD_REPLACE; + + return LDB_SUCCESS; +} /* @@ -1340,6 +1455,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL, DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_REVEAL_INTERNALS | DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); if (ret != LDB_SUCCESS) { return ret; @@ -1348,7 +1464,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, for (i=0; inum_elements; i++) { struct ldb_message_element *el = &msg->elements[i]; - struct ldb_message_element *old_el; + struct ldb_message_element *old_el, *new_el; const struct dsdb_attribute *schema_attr = dsdb_attribute_by_lDAPDisplayName(schema, el->name); if (!schema_attr) { @@ -1366,7 +1482,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, return LDB_ERR_UNWILLING_TO_PERFORM; } old_el = ldb_msg_find_element(old_msg, el->name); - switch (el->flags) { + switch (el->flags & LDB_FLAG_MOD_MASK) { case LDB_FLAG_MOD_REPLACE: ret = replmd_modify_la_replace(module, msg, el, old_el, schema_attr, seq_num, t); break; @@ -1382,6 +1498,24 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, el->flags, el->name); return LDB_ERR_UNWILLING_TO_PERFORM; } + if (ret != LDB_SUCCESS) { + return ret; + } + if (old_el) { + ldb_msg_remove_attr(old_msg, el->name); + } + ldb_msg_add_empty(old_msg, el->name, 0, &new_el); + new_el->num_values = el->num_values; + new_el->values = el->values; + + /* TODO: this relises a bit too heavily on the exact + behaviour of ldb_msg_find_element and + ldb_msg_remove_element */ + old_el = ldb_msg_find_element(msg, el->name); + if (old_el != el) { + ldb_msg_remove_element(msg, old_el); + i--; + } } talloc_free(res); -- cgit From 3b056061ff7f11e70532b859320638f9c8f5f2c7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 11:34:33 +1100 Subject: s4-dsdb: added support for backlinks in repl_meta_data backlinks need more careful handling now that we store the additional meta data for deleted links. It is easier to handle this in repl_meta_data than in linked_attributes. Eventually linked_attributes will disappear, with the functionality moved into repl_meta_data. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 244 ++++++++++++++++++++++-- 1 file changed, 224 insertions(+), 20 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 249dd61a4a..7488a1bee9 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -53,6 +53,8 @@ struct replmd_private { TALLOC_CTX *la_ctx; struct la_entry *la_list; + TALLOC_CTX *bl_ctx; + struct la_backlink *la_backlinks; struct nc_entry { struct nc_entry *prev, *next; struct ldb_dn *dn; @@ -87,6 +89,7 @@ struct replmd_replicated_request { static int replmd_replicated_apply_next(struct replmd_replicated_request *ar); + /* initialise the module allocate the private structure and build the list @@ -107,6 +110,169 @@ static int replmd_init(struct ldb_module *module) return ldb_next_init(module); } +/* + cleanup our per-transaction contexts + */ +static void replmd_txn_cleanup(struct replmd_private *replmd_private) +{ + talloc_free(replmd_private->la_ctx); + replmd_private->la_list = NULL; + replmd_private->la_ctx = NULL; + + talloc_free(replmd_private->bl_ctx); + replmd_private->la_backlinks = NULL; + replmd_private->bl_ctx = NULL; +} + + +struct la_backlink { + struct la_backlink *next, *prev; + const char *attr_name; + struct GUID forward_guid, target_guid; + bool active; +}; + +/* + add a backlink to the list of backlinks to add/delete in the prepare + commit + */ +static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema, + struct GUID *forward_guid, struct GUID *target_guid, + bool active, const struct dsdb_attribute *schema_attr) +{ + const struct dsdb_attribute *target_attr; + struct la_backlink *bl; + struct replmd_private *replmd_private = + talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private); + + target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID + 1); + if (!target_attr) { + /* + * windows 2003 has a broken schema where the + * definition of msDS-IsDomainFor is missing (which is + * supposed to be the backlink of the + * msDS-HasDomainNCs attribute + */ + return LDB_SUCCESS; + } + + /* see if its already in the list */ + for (bl=replmd_private->la_backlinks; bl; bl=bl->next) { + if (GUID_equal(forward_guid, &bl->forward_guid) && + GUID_equal(target_guid, &bl->target_guid) && + (target_attr->lDAPDisplayName == bl->attr_name || + strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) { + break; + } + } + + if (bl) { + /* we found an existing one */ + if (bl->active == active) { + return LDB_SUCCESS; + } + DLIST_REMOVE(replmd_private->la_backlinks, bl); + talloc_free(bl); + return LDB_SUCCESS; + } + + if (replmd_private->bl_ctx == NULL) { + replmd_private->bl_ctx = talloc_new(replmd_private); + if (replmd_private->bl_ctx == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + } + + /* its a new one */ + bl = talloc(replmd_private->bl_ctx, struct la_backlink); + if (bl == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + bl->attr_name = target_attr->lDAPDisplayName; + bl->forward_guid = *forward_guid; + bl->target_guid = *target_guid; + bl->active = active; + + DLIST_ADD(replmd_private->la_backlinks, bl); + + return LDB_SUCCESS; +} + +/* + process the list of backlinks we accumulated during + a transaction, adding and deleting the backlinks + from the target objects + */ +static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl) +{ + struct ldb_dn *target_dn, *source_dn; + int ret; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct ldb_message *msg; + TALLOC_CTX *tmp_ctx = talloc_new(bl); + char *dn_string; + + /* + - find DN of target + - find DN of source + - construct ldb_message + - either an add or a delete + */ + ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find target DN for linked attribute with GUID %s\n", + GUID_string(bl, &bl->target_guid)); + talloc_free(tmp_ctx); + return ret; + } + + ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n", + GUID_string(bl, &bl->forward_guid)); + talloc_free(tmp_ctx); + return ret; + } + + msg = ldb_msg_new(tmp_ctx); + if (msg == NULL) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* construct a ldb_message for adding/deleting the backlink */ + msg->dn = target_dn; + dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1); + if (!dn_string) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE; + + ret = dsdb_module_modify(module, msg, 0); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s", + bl->active?"add":"remove", + ldb_dn_get_linearized(source_dn), + ldb_dn_get_linearized(target_dn), + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + talloc_free(tmp_ctx); + return ret; +} + /* * Callback for most write operations in this module: @@ -1097,12 +1263,14 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct p handle adding a linked attribute */ static int replmd_modify_la_add(struct ldb_module *module, + struct dsdb_schema *schema, struct ldb_message *msg, struct ldb_message_element *el, struct ldb_message_element *old_el, const struct dsdb_attribute *schema_attr, uint64_t seq_num, - time_t t) + time_t t, + struct GUID *msg_guid) { int i; struct parsed_dn *dns, *old_dns; @@ -1166,6 +1334,12 @@ static int replmd_modify_la_add(struct ldb_module *module, return ret; } } + + ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } } /* add the new ones on to the end of the old values, constructing a new el->values */ @@ -1197,12 +1371,14 @@ static int replmd_modify_la_add(struct ldb_module *module, handle deleting all active linked attributes */ static int replmd_modify_la_delete(struct ldb_module *module, + struct dsdb_schema *schema, struct ldb_message *msg, struct ldb_message_element *el, struct ldb_message_element *old_el, const struct dsdb_attribute *schema_attr, uint64_t seq_num, - time_t t) + time_t t, + struct GUID *msg_guid) { int i; struct parsed_dn *dns, *old_dns; @@ -1280,6 +1456,12 @@ static int replmd_modify_la_delete(struct ldb_module *module, talloc_free(tmp_ctx); return ret; } + + ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } } el->values = talloc_steal(msg->elements, old_el->values); @@ -1298,12 +1480,14 @@ static int replmd_modify_la_delete(struct ldb_module *module, handle replacing a linked attribute */ static int replmd_modify_la_replace(struct ldb_module *module, + struct dsdb_schema *schema, struct ldb_message *msg, struct ldb_message_element *el, struct ldb_message_element *old_el, const struct dsdb_attribute *schema_attr, uint64_t seq_num, - time_t t) + time_t t, + struct GUID *msg_guid) { int i; struct parsed_dn *dns, *old_dns; @@ -1344,13 +1528,20 @@ static int replmd_modify_la_replace(struct ldb_module *module, struct parsed_dn *p; const struct ldb_val *v; + v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED"); + if (v) continue; + + ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + p = parsed_dn_find(dns, el->num_values, old_p->guid); if (p) { /* we don't delete it if we are re-adding it */ continue; } - v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED"); - if (v) continue; ret = replmd_update_la_val(old_el->values, old_p->v, old_p, old_p, invocation_id, seq_num, t, true); @@ -1394,6 +1585,12 @@ static int replmd_modify_la_replace(struct ldb_module *module, } num_new_values++; } + + ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } } /* add the new values to the end of old_el */ @@ -1436,6 +1633,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, struct ldb_context *ldb = ldb_module_get_ctx(module); struct ldb_message *old_msg; struct dsdb_schema *schema = dsdb_get_schema(ldb); + struct GUID old_guid; if (seq_num == 0) { /* there the replmd_update_rpmd code has already @@ -1462,6 +1660,8 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, } old_msg = res->msgs[0]; + old_guid = samdb_result_guid(old_msg, "objectGUID"); + for (i=0; inum_elements; i++) { struct ldb_message_element *el = &msg->elements[i]; struct ldb_message_element *old_el, *new_el; @@ -1484,13 +1684,13 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, old_el = ldb_msg_find_element(old_msg, el->name); switch (el->flags & LDB_FLAG_MOD_MASK) { case LDB_FLAG_MOD_REPLACE: - ret = replmd_modify_la_replace(module, msg, el, old_el, schema_attr, seq_num, t); + ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid); break; case LDB_FLAG_MOD_DELETE: - ret = replmd_modify_la_delete(module, msg, el, old_el, schema_attr, seq_num, t); + ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid); break; case LDB_FLAG_MOD_ADD: - ret = replmd_modify_la_add(module, msg, el, old_el, schema_attr, seq_num, t); + ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid); break; default: ldb_asprintf_errstring(ldb, @@ -2877,9 +3077,7 @@ static int replmd_start_transaction(struct ldb_module *module) /* create our private structure for this transaction */ struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module), struct replmd_private); - talloc_free(replmd_private->la_ctx); - replmd_private->la_list = NULL; - replmd_private->la_ctx = NULL; + replmd_txn_cleanup(replmd_private); /* free any leftover mod_usn records from cancelled transactions */ @@ -2901,6 +3099,7 @@ static int replmd_prepare_commit(struct ldb_module *module) struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module), struct replmd_private); struct la_entry *la, *prev; + struct la_backlink *bl; int ret; /* walk the list backwards, to do the first entry first, as we @@ -2913,16 +3112,22 @@ static int replmd_prepare_commit(struct ldb_module *module) DLIST_REMOVE(replmd_private->la_list, la); ret = replmd_process_linked_attribute(module, la); if (ret != LDB_SUCCESS) { - talloc_free(replmd_private->la_ctx); - replmd_private->la_list = NULL; - replmd_private->la_ctx = NULL; + replmd_txn_cleanup(replmd_private); return ret; } } - talloc_free(replmd_private->la_ctx); - replmd_private->la_list = NULL; - replmd_private->la_ctx = NULL; + /* process our backlink list, creating and deleting backlinks + as necessary */ + for (bl=replmd_private->la_backlinks; bl; bl=bl->next) { + ret = replmd_process_backlink(module, bl); + if (ret != LDB_SUCCESS) { + replmd_txn_cleanup(replmd_private); + return ret; + } + } + + replmd_txn_cleanup(replmd_private); /* possibly change @REPLCHANGED */ ret = replmd_notify_store(module); @@ -2937,9 +3142,8 @@ static int replmd_del_transaction(struct ldb_module *module) { struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module), struct replmd_private); - talloc_free(replmd_private->la_ctx); - replmd_private->la_list = NULL; - replmd_private->la_ctx = NULL; + replmd_txn_cleanup(replmd_private); + return ldb_next_del_trans(module); } -- cgit From c071af337ae0ff11104ca07ea81a7ffa7a8405bc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 11:34:58 +1100 Subject: s4-dsdb: linked_attributes_modify no longer handles modifies This functionality has moved into repl_meta_data --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 183 --------------------- 1 file changed, 183 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index f54693d809..0abec00a71 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -408,188 +408,6 @@ static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *are } -/* modify */ -static int linked_attributes_modify(struct ldb_module *module, struct ldb_request *req) -{ - /* Look over list of modifications */ - /* Find if any are for linked attributes */ - /* Determine the effect of the modification */ - /* Apply the modify to the linked entry */ - - struct ldb_context *ldb; - int i, j; - struct la_context *ac; - struct ldb_request *search_req; - const char **attrs; - - int ret; - - ldb = ldb_module_get_ctx(module); - - if (ldb_dn_is_special(req->op.mod.message->dn)) { - /* do not manipulate our control entries */ - return ldb_next_request(module, req); - } - - ac = linked_attributes_init(module, req); - if (!ac) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (!ac->schema) { - /* without schema, this doesn't make any sense */ - return ldb_next_request(module, req); - } - - ac->rc = talloc_zero(ac, struct replace_context); - if (!ac->rc) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - for (i=0; i < req->op.mod.message->num_elements; i++) { - bool store_el = false; - const char *attr_name; - const struct dsdb_attribute *target_attr; - const struct ldb_message_element *el = &req->op.mod.message->elements[i]; - const struct dsdb_attribute *schema_attr - = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name); - if (!schema_attr) { - ldb_asprintf_errstring(ldb, - "attribute %s is not a valid attribute in schema", el->name); - return LDB_ERR_OBJECT_CLASS_VIOLATION; - } - /* We have a valid attribute, now find out if it is linked */ - if (schema_attr->linkID == 0) { - continue; - } - - if ((schema_attr->linkID & 1) == 1) { - /* Odd is for the target. Illegal to modify */ - ldb_asprintf_errstring(ldb, - "attribute %s must not be modified directly, it is a linked attribute", el->name); - return LDB_ERR_UNWILLING_TO_PERFORM; - } - - /* Even link IDs are for the originating attribute */ - - /* Now find the target attribute */ - target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1); - if (!target_attr) { - /* - * windows 2003 has a broken schema where - * the definition of msDS-IsDomainFor - * is missing (which is supposed to be - * the backlink of the msDS-HasDomainNCs - * attribute - */ - continue; - } - - attr_name = target_attr->lDAPDisplayName; - - switch (el->flags & LDB_FLAG_MOD_MASK) { - case LDB_FLAG_MOD_REPLACE: - /* treat as just a normal add the delete part is handled by the callback */ - store_el = true; - - /* break intentionally missing */ - - case LDB_FLAG_MOD_ADD: - - /* For each value being added, we need to setup the adds */ - for (j = 0; j < el->num_values; j++) { - ret = la_store_op(ac, LA_OP_ADD, - &el->values[j], - attr_name); - if (ret != LDB_SUCCESS) { - return ret; - } - } - break; - - case LDB_FLAG_MOD_DELETE: - - if (el->num_values) { - /* For each value being deleted, we need to setup the delete */ - for (j = 0; j < el->num_values; j++) { - ret = la_store_op(ac, LA_OP_DEL, - &el->values[j], - attr_name); - if (ret != LDB_SUCCESS) { - return ret; - } - } - } else { - /* Flag that there was a DELETE - * without a value specified, so we - * need to look for the old value */ - store_el = true; - } - - break; - } - - if (store_el) { - struct ldb_message_element *search_el; - - search_el = talloc_realloc(ac->rc, ac->rc->el, - struct ldb_message_element, - ac->rc->num_elements +1); - if (!search_el) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - ac->rc->el = search_el; - - ac->rc->el[ac->rc->num_elements] = *el; - ac->rc->num_elements++; - } - } - - if (ac->ops || ac->rc->el) { - /* both replace and delete without values are handled in the callback - * after the search on the entry to be modified is performed */ - - attrs = talloc_array(ac->rc, const char *, ac->rc->num_elements + 1); - if (!attrs) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - for (i = 0; ac->rc && i < ac->rc->num_elements; i++) { - attrs[i] = ac->rc->el[i].name; - } - attrs[i] = NULL; - - /* The callback does all the hard work here */ - ret = ldb_build_search_req(&search_req, ldb, ac, - req->op.mod.message->dn, - LDB_SCOPE_BASE, - "(objectClass=*)", attrs, - NULL, - ac, la_mod_search_callback, - req); - - /* We need to figure out our own extended DN, to fill in as the backlink target */ - if (ret == LDB_SUCCESS) { - ret = ldb_request_add_control(search_req, - LDB_CONTROL_EXTENDED_DN_OID, - false, NULL); - } - if (ret == LDB_SUCCESS) { - talloc_steal(search_req, attrs); - - ret = ldb_next_request(module, search_req); - } - - } else { - /* nothing to do for this module, proceed */ - talloc_free(ac); - ret = ldb_next_request(module, req); - } - - return ret; -} /* delete */ static int linked_attributes_del(struct ldb_module *module, struct ldb_request *req) @@ -1250,7 +1068,6 @@ static int linked_attributes_del_transaction(struct ldb_module *module) _PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = { .name = "linked_attributes", .add = linked_attributes_add, - .modify = linked_attributes_modify, .del = linked_attributes_del, .rename = linked_attributes_rename, .start_transaction = linked_attributes_start_transaction, -- cgit From 3199e02884af3b14348a88e8d8d7bc852212536f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 12:01:51 +1100 Subject: s4-dsdb: add a comment on the use of ldb_rename() We need to use ldb_rename() and not dsdb_module_rename() here as we need the rename to be processed by the current module --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 7488a1bee9..dadaf32f80 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2078,6 +2078,9 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n", ldb_dn_get_linearized(ar->search_msg->dn), ldb_dn_get_linearized(msg->dn)); + /* we can't use dsdb_module_rename() here as we need + the rename call to be intercepted by this module, to + allow it to process linked attribute changes */ if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n", ldb_dn_get_linearized(ar->search_msg->dn), -- cgit From bd5678f4bebad82f1b949931049bbd8496616777 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 17:14:26 +1100 Subject: s4-dsdb: repl_meta_data now replaces objectguid in all cases We don't want to be debugging two different code paths through the ldb module stack, so better to always do the work of repl_meta_data, even for a standalone server Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/samba_dsdb.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c index bfa2599afe..a461a94806 100644 --- a/source4/dsdb/samdb/ldb_modules/samba_dsdb.c +++ b/source4/dsdb/samdb/ldb_modules/samba_dsdb.c @@ -234,16 +234,11 @@ static int samba_dsdb_init(struct ldb_module *module) "instancetype", NULL }; - const char *objectguid_module; - /* if serverrole == "domain controller": */ - const char *repl_meta_data = "repl_meta_data"; - /* else: */ - const char *objectguid = "objectguid"; - const char **link_modules; static const char *tdb_modules_list[] = { - "subtree_rename", "subtree_delete", + "repl_meta_data", + "subtree_rename", "linked_attributes", NULL}; @@ -328,15 +323,9 @@ static int samba_dsdb_init(struct ldb_module *module) backend_modules = NULL; if (strcasecmp(backendType, "ldb") == 0) { - if (strcasecmp(serverRole, "dc") == 0 || strcasecmp(serverRole, "domain controller") == 0) { - objectguid_module = repl_meta_data; - } else { - objectguid_module = objectguid; - } extended_dn_module = extended_dn_module_ldb; link_modules = tdb_modules_list; } else { - objectguid_module = NULL; link_modules = NULL; if (strcasecmp(backendType, "fedora-ds") == 0) { backend_modules = fedora_ds_backend_modules; @@ -359,9 +348,6 @@ static int samba_dsdb_init(struct ldb_module *module) final_module_list = str_list_copy_const(tmp_ctx, modules_list); CHECK_MODULE_LIST; - final_module_list = str_list_add_const(final_module_list, objectguid_module); - CHECK_MODULE_LIST; - final_module_list = str_list_append_const(final_module_list, link_modules); CHECK_MODULE_LIST; -- cgit From 5964acfa741d691c0196f91c0796122ec025f177 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 17:15:23 +1100 Subject: s4-dsdb: the linked_attributes module no longer handles deletes delete handling is now moved into repl_meta_data Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 53 ---------------------- 1 file changed, 53 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index 0abec00a71..81c6ec90af 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -409,57 +409,6 @@ static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *are -/* delete */ -static int linked_attributes_del(struct ldb_module *module, struct ldb_request *req) -{ - struct ldb_context *ldb; - struct ldb_request *search_req; - struct la_context *ac; - const char **attrs; - WERROR werr; - int ret; - - /* This gets complex: We need to: - - Do a search for the entry - - Wait for these result to appear - - In the callback for the result, issue a modify - request based on the linked attributes found - - Wait for each modify result - - Regain our sainity - */ - - ldb = ldb_module_get_ctx(module); - - ac = linked_attributes_init(module, req); - if (!ac) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (!ac->schema) { - /* without schema, this doesn't make any sense */ - return ldb_next_request(module, req); - } - - werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs); - if (!W_ERROR_IS_OK(werr)) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = ldb_build_search_req(&search_req, ldb, req, - req->op.del.dn, LDB_SCOPE_BASE, - "(objectClass=*)", attrs, - NULL, - ac, la_op_search_callback, - req); - - if (ret != LDB_SUCCESS) { - return ret; - } - - talloc_steal(search_req, attrs); - - return ldb_next_request(module, search_req); -} /* rename */ static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req) @@ -1068,8 +1017,6 @@ static int linked_attributes_del_transaction(struct ldb_module *module) _PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = { .name = "linked_attributes", .add = linked_attributes_add, - .del = linked_attributes_del, - .rename = linked_attributes_rename, .start_transaction = linked_attributes_start_transaction, .prepare_commit = linked_attributes_prepare_commit, .del_transaction = linked_attributes_del_transaction, -- cgit From 348bcfc8ff81a95ff2f1785ba4efdaf2e8a193a4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 16 Dec 2009 17:24:21 +1100 Subject: s4-dsdb: added replmd_delete, based on Eduardos work This implements repmld_delete(), which handles the meta_data updates for an object when deleting. A delete gets mapped to a combination of a rename followed by a modify request, which has the effect of moving the object into the Deleted Objects container. This is based on the code from Eduardo Lima . Eduardo's code was modified to take account of the linked attributes changes that Andrew and I have been working on. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 295 ++++++++++++++++++++++++ 1 file changed, 295 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index dadaf32f80..2a7f472046 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1914,6 +1914,300 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are return ldb_next_request(ac->module, down_req); } +/* remove forwards and backlinks as needed when an object + is deleted */ +static int replmd_delete_remove_link(struct ldb_module *module, + struct dsdb_schema *schema, + struct ldb_dn *dn, + struct ldb_message_element *el, + const struct dsdb_attribute *sa) +{ + int i; + TALLOC_CTX *tmp_ctx = talloc_new(module); + struct ldb_context *ldb = ldb_module_get_ctx(module); + + for (i=0; inum_values; i++) { + struct dsdb_dn *dsdb_dn; + const struct ldb_val *v; + NTSTATUS status; + int ret; + struct GUID guid2; + struct ldb_message *msg; + const struct dsdb_attribute *target_attr; + struct ldb_message_element *el2; + struct ldb_val dn_val; + + if (dsdb_dn_is_deleted_val(&el->values[i])) { + continue; + } + + dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid); + if (!dsdb_dn) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + v = ldb_dn_get_extended_component(dsdb_dn->dn, "GUID"); + if (!v) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + status = GUID_from_ndr_blob(v, &guid2); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* remove the link */ + msg = ldb_msg_new(tmp_ctx); + if (!msg) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + + msg->dn = dsdb_dn->dn; + + if (sa->linkID & 1) { + target_attr = dsdb_attribute_by_linkID(schema, sa->linkID - 1); + } else { + target_attr = dsdb_attribute_by_linkID(schema, sa->linkID + 1); + } + + ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2); + if (ret != LDB_SUCCESS) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + dn_val = data_blob_string_const(ldb_dn_get_linearized(dn)); + el2->values = &dn_val; + el2->num_values = 1; + + ret = dsdb_module_modify(module, msg, 0); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + + +/* + handle update of replication meta data for deletion of objects + + This also handles the mapping of delete to a rename operation + to allow deletes to be replicated. + */ +static int replmd_delete(struct ldb_module *module, struct ldb_request *req) +{ + int ret = LDB_ERR_OTHER; + bool retb; + struct ldb_dn *old_dn, *new_dn; + const char *rdn_name; + const struct ldb_val *rdn_value, *new_rdn_value; + struct GUID guid; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct dsdb_schema *schema = dsdb_get_schema(ldb); + struct ldb_message *msg, *old_msg; + struct ldb_message_element *el; + TALLOC_CTX *tmp_ctx; + struct ldb_result *res, *parent_res; + const char *preserved_attrs[] = { + /* yes, this really is a hard coded list. See MS-ADTS + section 3.1.1.5.5.1.1 */ + "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName", + "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN", + "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID", + "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid", + "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName", + "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection", + "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreate", + NULL}; + uint32_t el_count = 0; + int i; + + tmp_ctx = talloc_new(ldb); + + old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn); + + /* we need the complete msg off disk, so we can work out which + attributes need to be removed */ + ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL, + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_REVEAL_INTERNALS | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + old_msg = res->msgs[0]; + + /* work out where we will be renaming this object to */ + ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn); + if (ret != LDB_SUCCESS) { + /* this is probably an attempted delete on a partition + * that doesn't allow delete operations, such as the + * schema partition */ + ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s", + ldb_dn_get_linearized(old_dn)); + talloc_free(tmp_ctx); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + rdn_name = ldb_dn_get_rdn_name(old_dn); + rdn_value = ldb_dn_get_rdn_val(old_dn); + + /* get the objects GUID from the search we just did */ + guid = samdb_result_guid(old_msg, "objectGUID"); + + /* Add a formatted child */ + retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s", + rdn_name, + rdn_value->data, + GUID_string(tmp_ctx, &guid)); + if (!retb) { + DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s", + ldb_dn_get_linearized(new_dn))); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + /* New DN name generated, renaming the original DN */ + ret = dsdb_module_rename(module, old_dn, new_dn, 0); + if (ret != LDB_SUCCESS){ + DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s'\n", + ldb_dn_get_linearized(old_dn), + ldb_dn_get_linearized(new_dn))); + talloc_free(tmp_ctx); + return ret; + } + + /* + now we need to modify the object in the following ways: + + - add isDeleted=TRUE + - update rDN and name, with new rDN + - remove linked attributes + - remove objectCategory and sAMAccountType + - remove attribs not on the preserved list + - preserved if in above list, or is rDN + - remove all linked attribs from this object + - remove all links from other objects to this object + - add lastKnownParent + - update replPropertyMetaData? + + see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1 + */ + + msg = ldb_msg_new(tmp_ctx); + if (msg == NULL) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + msg->dn = new_dn; + + ret = ldb_msg_add_string(msg, "isDeleted", "TRUE"); + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n")); + ldb_module_oom(module); + talloc_free(tmp_ctx); + return ret; + } + msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD; + + /* we need the storage form of the parent GUID */ + ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res, + ldb_dn_get_parent(tmp_ctx, old_dn), NULL, + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = ldb_msg_add_steal_string(msg, "lastKnownParent", + ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1)); + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n")); + ldb_module_oom(module); + talloc_free(tmp_ctx); + return ret; + } + msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD; + + /* work out which of the old attributes we will be removing */ + for (i=0; inum_elements; i++) { + const struct dsdb_attribute *sa; + el = &old_msg->elements[i]; + sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name); + if (!sa) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + if (ldb_attr_cmp(el->name, rdn_name) == 0) { + /* don't remove the rDN */ + continue; + } + + if (sa->linkID) { + ret = replmd_delete_remove_link(module, schema, old_dn, el, sa); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + } + + if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) { + continue; + } + + ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + ldb_module_oom(module); + return ret; + } + } + + /* work out what the new rdn value is, for updating the + rDN and name fields */ + new_rdn_value = ldb_dn_get_rdn_val(new_dn); + ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + el->flags = LDB_FLAG_MOD_REPLACE; + + el = ldb_msg_find_element(old_msg, "name"); + if (el) { + ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + el->flags = LDB_FLAG_MOD_REPLACE; + } + + ret = dsdb_module_modify(module, msg, 0); + if (ret != LDB_SUCCESS){ + ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s", + ldb_dn_get_linearized(old_dn), ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; + } + + talloc_free(tmp_ctx); + + return ldb_module_done(req, NULL, NULL, LDB_SUCCESS); +} + + static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret) { @@ -3157,6 +3451,7 @@ _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = { .add = replmd_add, .modify = replmd_modify, .rename = replmd_rename, + .del = replmd_delete, .extended = replmd_extended, .start_transaction = replmd_start_transaction, .prepare_commit = replmd_prepare_commit, -- cgit From 9e96ae8ddc49e146323e9a44d38f725f4a5fb663 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 10:42:15 +1100 Subject: s4-dsdb: add linked attributes meta_data handling to replmd_add This also handles the backlink creation that was previously in the linked_attributes module Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 110 ++++++++++++++++++------ 1 file changed, 86 insertions(+), 24 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 2a7f472046..245560f769 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -572,6 +572,59 @@ static void replmd_ldb_message_sort(struct ldb_message *msg, discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort); } +static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, + const struct GUID *invocation_id, uint64_t seq_num, time_t t); + +/* + fix up linked attributes in replmd_add. + This involves setting up the right meta-data in extended DN + components, and creating backlinks to the object + */ +static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el, + uint64_t seq_num, const struct GUID *invocationId, time_t t, + struct GUID *guid, const struct dsdb_attribute *sa) +{ + int i; + TALLOC_CTX *tmp_ctx = talloc_new(el->values); + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct dsdb_schema *schema = dsdb_get_schema(ldb); + + for (i=0; inum_values; i++) { + struct ldb_val *v = &el->values[i]; + struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid); + struct GUID target_guid; + NTSTATUS status; + int ret; + + ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, seq_num, t); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + /* note that the DN already has the extended + components from the extended_dn_store module */ + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + + +/* + intercept add requests + */ static int replmd_add(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; @@ -728,6 +781,19 @@ static int replmd_add(struct ldb_module *module, struct ldb_request *req) continue; } +#if W2K3_LINKED_ATTRIBUTES + if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) { + ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa); + if (ret != LDB_SUCCESS) { + talloc_free(ac); + return ret; + } + /* linked attributes are not stored in + replPropertyMetaData in FL above w2k */ + continue; + } +#endif + m->attid = sa->attributeID_id; m->version = 1; m->originating_change_time = now; @@ -1106,10 +1172,10 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, RMD_USN = originating_usn RMD_VERSION = version */ -static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct parsed_dn *p, +static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, const struct GUID *invocation_id, uint64_t seq_num, time_t t) { - struct ldb_dn *dn = p->dsdb_dn->dn; + struct ldb_dn *dn = dsdb_dn->dn; NTTIME now; const char *tstring, *usn_string; struct ldb_val tval; @@ -1153,7 +1219,7 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct pa ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); if (ret != LDB_SUCCESS) return ret; - dnstring = dsdb_dn_get_extended_linearized(mem_ctx, p->dsdb_dn, 1); + dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1); if (dnstring == NULL) { return LDB_ERR_OPERATIONS_ERROR; } @@ -1168,11 +1234,11 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct pa see replmd_build_la_val for value names */ -static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct parsed_dn *p, - struct parsed_dn *old_p, const struct GUID *invocation_id, +static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, + struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id, uint64_t seq_num, time_t t, bool deleted) { - struct ldb_dn *dn = p->dsdb_dn->dn; + struct ldb_dn *dn = dsdb_dn->dn; NTTIME now; const char *tstring, *usn_string; struct ldb_val tval; @@ -1212,11 +1278,11 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct p if (ret != LDB_SUCCESS) return ret; /* get the ADDTIME from the original */ - old_addtime = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "RMD_ADDTIME"); + old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME"); if (old_addtime == NULL) { old_addtime = &tval; } - if (p != old_p) { + if (dsdb_dn != old_dsdb_dn) { ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime); if (ret != LDB_SUCCESS) return ret; } @@ -1234,7 +1300,7 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct p if (ret != LDB_SUCCESS) return ret; /* increase the version by 1 */ - old_version = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "RMD_VERSION"); + old_version = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_VERSION"); if (old_version == NULL) { vers = data_blob_string_const("0"); } else { @@ -1250,7 +1316,7 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct p ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); if (ret != LDB_SUCCESS) return ret; - dnstring = dsdb_dn_get_extended_linearized(mem_ctx, p->dsdb_dn, 1); + dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1); if (dnstring == NULL) { return LDB_ERR_OPERATIONS_ERROR; } @@ -1310,7 +1376,7 @@ static int replmd_modify_la_add(struct ldb_module *module, talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } - ret = replmd_build_la_val(new_values, &new_values[num_new_values], &dns[i], + ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, invocation_id, seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); @@ -1328,7 +1394,8 @@ static int replmd_modify_la_add(struct ldb_module *module, talloc_free(tmp_ctx); return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; } - ret = replmd_update_la_val(old_el->values, p->v, &dns[i], p, invocation_id, seq_num, t, false); + ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn, + invocation_id, seq_num, t, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1451,7 +1518,8 @@ static int replmd_modify_la_delete(struct ldb_module *module, v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); if (v != NULL) continue; - ret = replmd_update_la_val(old_el->values, p->v, p, p, invocation_id, seq_num, t, true); + ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn, + invocation_id, seq_num, t, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1543,7 +1611,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, continue; } - ret = replmd_update_la_val(old_el->values, old_p->v, old_p, old_p, + ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, invocation_id, seq_num, t, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); @@ -1561,8 +1629,8 @@ static int replmd_modify_la_replace(struct ldb_module *module, (old_p = parsed_dn_find(old_dns, old_num_values, p->guid)) != NULL) { /* update in place */ - ret = replmd_update_la_val(old_el->values, old_p->v, old_p, - old_p, invocation_id, + ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, + old_p->dsdb_dn, invocation_id, seq_num, t, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); @@ -1577,7 +1645,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } - ret = replmd_build_la_val(new_values, &new_values[num_new_values], &dns[i], + ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, invocation_id, seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); @@ -1928,7 +1996,6 @@ static int replmd_delete_remove_link(struct ldb_module *module, for (i=0; inum_values; i++) { struct dsdb_dn *dsdb_dn; - const struct ldb_val *v; NTSTATUS status; int ret; struct GUID guid2; @@ -1947,12 +2014,7 @@ static int replmd_delete_remove_link(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } - v = ldb_dn_get_extended_component(dsdb_dn->dn, "GUID"); - if (!v) { - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } - status = GUID_from_ndr_blob(v, &guid2); + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; -- cgit From 3fe9244796cea72abe8d7ec4ce54acf45ee2da48 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 10:42:44 +1100 Subject: s4-dsdb: remove linked_attributes_add This is now handled in the repl_meta_data module --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 86 ---------------------- 1 file changed, 86 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index 81c6ec90af..2ea5024431 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -196,91 +196,6 @@ static int la_down_req(struct la_context *ac); -/* add */ -static int linked_attributes_add(struct ldb_module *module, struct ldb_request *req) -{ - struct ldb_context *ldb; - const struct dsdb_attribute *target_attr; - struct la_context *ac; - const char *attr_name; - int ret; - int i, j; - - ldb = ldb_module_get_ctx(module); - - if (ldb_dn_is_special(req->op.add.message->dn)) { - /* do not manipulate our control entries */ - return ldb_next_request(module, req); - } - - ac = linked_attributes_init(module, req); - if (!ac) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (!ac->schema) { - /* without schema, this doesn't make any sense */ - talloc_free(ac); - return ldb_next_request(module, req); - } - - /* Need to ensure we only have forward links being specified */ - for (i=0; i < req->op.add.message->num_elements; i++) { - const struct ldb_message_element *el = &req->op.add.message->elements[i]; - const struct dsdb_attribute *schema_attr - = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name); - if (!schema_attr) { - ldb_asprintf_errstring(ldb, - "attribute %s is not a valid attribute in schema", el->name); - return LDB_ERR_OBJECT_CLASS_VIOLATION; - } - /* We have a valid attribute, now find out if it is linked */ - if (schema_attr->linkID == 0) { - continue; - } - - if ((schema_attr->linkID & 1) == 1) { - /* Odd is for the target. Illegal to modify */ - ldb_asprintf_errstring(ldb, - "attribute %s must not be modified directly, it is a linked attribute", el->name); - return LDB_ERR_UNWILLING_TO_PERFORM; - } - - /* Even link IDs are for the originating attribute */ - target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1); - if (!target_attr) { - /* - * windows 2003 has a broken schema where - * the definition of msDS-IsDomainFor - * is missing (which is supposed to be - * the backlink of the msDS-HasDomainNCs - * attribute - */ - continue; - } - - attr_name = target_attr->lDAPDisplayName; - - for (j = 0; j < el->num_values; j++) { - ret = la_store_op(ac, LA_OP_ADD, - &el->values[j], - attr_name); - if (ret != LDB_SUCCESS) { - return ret; - } - } - } - - /* if no linked attributes are present continue */ - if (ac->ops == NULL) { - /* nothing to do for this module, proceed */ - talloc_free(ac); - return ldb_next_request(module, req); - } - - /* start with the original request */ - return la_down_req(ac); -} /* For a delete or rename, we need to find out what linked attributes * are currently on this DN, and then deal with them. This is the @@ -1016,7 +931,6 @@ static int linked_attributes_del_transaction(struct ldb_module *module) _PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = { .name = "linked_attributes", - .add = linked_attributes_add, .start_transaction = linked_attributes_start_transaction, .prepare_commit = linked_attributes_prepare_commit, .del_transaction = linked_attributes_del_transaction, -- cgit From 2b5cd3dba29043281a6ca04398623a7f1972d71b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 10:50:34 +1100 Subject: s4-dsdb: some backlinks can be processed immediately backlinks in add and delete operations can be processed immediately, rather than at the end of a transaction. This can save on backlink list processing time. --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 161 ++++++++++++------------ 1 file changed, 84 insertions(+), 77 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 245560f769..3390f80f13 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -133,78 +133,8 @@ struct la_backlink { }; /* - add a backlink to the list of backlinks to add/delete in the prepare - commit - */ -static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema, - struct GUID *forward_guid, struct GUID *target_guid, - bool active, const struct dsdb_attribute *schema_attr) -{ - const struct dsdb_attribute *target_attr; - struct la_backlink *bl; - struct replmd_private *replmd_private = - talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private); - - target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID + 1); - if (!target_attr) { - /* - * windows 2003 has a broken schema where the - * definition of msDS-IsDomainFor is missing (which is - * supposed to be the backlink of the - * msDS-HasDomainNCs attribute - */ - return LDB_SUCCESS; - } - - /* see if its already in the list */ - for (bl=replmd_private->la_backlinks; bl; bl=bl->next) { - if (GUID_equal(forward_guid, &bl->forward_guid) && - GUID_equal(target_guid, &bl->target_guid) && - (target_attr->lDAPDisplayName == bl->attr_name || - strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) { - break; - } - } - - if (bl) { - /* we found an existing one */ - if (bl->active == active) { - return LDB_SUCCESS; - } - DLIST_REMOVE(replmd_private->la_backlinks, bl); - talloc_free(bl); - return LDB_SUCCESS; - } - - if (replmd_private->bl_ctx == NULL) { - replmd_private->bl_ctx = talloc_new(replmd_private); - if (replmd_private->bl_ctx == NULL) { - ldb_module_oom(module); - return LDB_ERR_OPERATIONS_ERROR; - } - } - - /* its a new one */ - bl = talloc(replmd_private->bl_ctx, struct la_backlink); - if (bl == NULL) { - ldb_module_oom(module); - return LDB_ERR_OPERATIONS_ERROR; - } - - bl->attr_name = target_attr->lDAPDisplayName; - bl->forward_guid = *forward_guid; - bl->target_guid = *target_guid; - bl->active = active; - - DLIST_ADD(replmd_private->la_backlinks, bl); - - return LDB_SUCCESS; -} - -/* - process the list of backlinks we accumulated during - a transaction, adding and deleting the backlinks - from the target objects + process a backlinks we accumulated during a transaction, adding and + deleting the backlinks from the target objects */ static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl) { @@ -273,6 +203,83 @@ static int replmd_process_backlink(struct ldb_module *module, struct la_backlink return ret; } +/* + add a backlink to the list of backlinks to add/delete in the prepare + commit + */ +static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema, + struct GUID *forward_guid, struct GUID *target_guid, + bool active, const struct dsdb_attribute *schema_attr, bool immediate) +{ + const struct dsdb_attribute *target_attr; + struct la_backlink *bl; + struct replmd_private *replmd_private = + talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private); + + target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID + 1); + if (!target_attr) { + /* + * windows 2003 has a broken schema where the + * definition of msDS-IsDomainFor is missing (which is + * supposed to be the backlink of the + * msDS-HasDomainNCs attribute + */ + return LDB_SUCCESS; + } + + /* see if its already in the list */ + for (bl=replmd_private->la_backlinks; bl; bl=bl->next) { + if (GUID_equal(forward_guid, &bl->forward_guid) && + GUID_equal(target_guid, &bl->target_guid) && + (target_attr->lDAPDisplayName == bl->attr_name || + strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) { + break; + } + } + + if (bl) { + /* we found an existing one */ + if (bl->active == active) { + return LDB_SUCCESS; + } + DLIST_REMOVE(replmd_private->la_backlinks, bl); + talloc_free(bl); + return LDB_SUCCESS; + } + + if (replmd_private->bl_ctx == NULL) { + replmd_private->bl_ctx = talloc_new(replmd_private); + if (replmd_private->bl_ctx == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + } + + /* its a new one */ + bl = talloc(replmd_private->bl_ctx, struct la_backlink); + if (bl == NULL) { + ldb_module_oom(module); + return LDB_ERR_OPERATIONS_ERROR; + } + + bl->attr_name = target_attr->lDAPDisplayName; + bl->forward_guid = *forward_guid; + bl->target_guid = *target_guid; + bl->active = active; + + /* the caller may ask for this backlink to be processed + immediately */ + if (immediate) { + int ret = replmd_process_backlink(module, bl); + talloc_free(bl); + return ret; + } + + DLIST_ADD(replmd_private->la_backlinks, bl); + + return LDB_SUCCESS; +} + /* * Callback for most write operations in this module: @@ -610,7 +617,7 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme return LDB_ERR_OPERATIONS_ERROR; } - ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa); + ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1402,7 +1409,7 @@ static int replmd_modify_la_add(struct ldb_module *module, } } - ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr); + ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1525,7 +1532,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, return ret; } - ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr); + ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1599,7 +1606,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED"); if (v) continue; - ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr); + ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1654,7 +1661,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, num_new_values++; } - ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr); + ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; -- cgit From e9699e9cb9c2a5dc43a85c3d1565e12e0e299038 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 23:00:16 +1100 Subject: s4-dsdb: do the rename after the modify in replmd_delete This makes updating the links a bit easier --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 3390f80f13..689b24f398 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -617,7 +617,7 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme return LDB_ERR_OPERATIONS_ERROR; } - ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, true); + ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -2145,16 +2145,6 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - /* New DN name generated, renaming the original DN */ - ret = dsdb_module_rename(module, old_dn, new_dn, 0); - if (ret != LDB_SUCCESS){ - DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s'\n", - ldb_dn_get_linearized(old_dn), - ldb_dn_get_linearized(new_dn))); - talloc_free(tmp_ctx); - return ret; - } - /* now we need to modify the object in the following ways: @@ -2179,7 +2169,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } - msg->dn = new_dn; + msg->dn = old_dn; ret = ldb_msg_add_string(msg, "isDeleted", "TRUE"); if (ret != LDB_SUCCESS) { @@ -2271,6 +2261,17 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) return ret; } + /* now rename onto the new DN */ + ret = dsdb_module_rename(module, old_dn, new_dn, 0); + if (ret != LDB_SUCCESS){ + DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n", + ldb_dn_get_linearized(old_dn), + ldb_dn_get_linearized(new_dn), + ldb_errstring(ldb))); + talloc_free(tmp_ctx); + return ret; + } + talloc_free(tmp_ctx); return ldb_module_done(req, NULL, NULL, LDB_SUCCESS); -- cgit From 5eefff915e0c49cbdbecd764b8e0a2cc15d10d93 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 23:02:08 +1100 Subject: s4-dsdb: simplify the linked_attributes module The linked_attributes module only has to deal with renames now, as other linked attribute updates happen in repl_meta_data. This allows it to be much simpler. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 949 +++------------------ 1 file changed, 96 insertions(+), 853 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index 2ea5024431..edcb2d8167 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -33,905 +33,148 @@ #include "dlinklist.h" #include "dsdb/samdb/samdb.h" #include "librpc/gen_ndr/ndr_misc.h" - -struct la_private { - struct la_context *la_list; -}; - -struct la_op_store { - struct la_op_store *next; - struct la_op_store *prev; - enum la_op {LA_OP_ADD, LA_OP_DEL} op; - struct GUID guid; - char *name; - char *value; -}; - -struct replace_context { - struct la_context *ac; - unsigned int num_elements; - struct ldb_message_element *el; -}; - -struct la_context { - struct la_context *next, *prev; - const struct dsdb_schema *schema; - struct ldb_module *module; - struct ldb_request *req; - struct ldb_dn *partition_dn; - struct ldb_dn *add_dn; - struct ldb_dn *del_dn; - struct replace_context *rc; - struct la_op_store *ops; - struct ldb_extended *op_response; - struct ldb_control **op_controls; -}; - -static struct la_context *linked_attributes_init(struct ldb_module *module, - struct ldb_request *req) -{ - struct ldb_context *ldb; - struct la_context *ac; - const struct ldb_control *partition_ctrl; - - ldb = ldb_module_get_ctx(module); - - ac = talloc_zero(req, struct la_context); - if (ac == NULL) { - ldb_oom(ldb); - return NULL; - } - - ac->schema = dsdb_get_schema(ldb); - ac->module = module; - ac->req = req; - - /* remember the partition DN that came in, if given */ - partition_ctrl = ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID); - if (partition_ctrl) { - const struct dsdb_control_current_partition *partition; - partition = talloc_get_type(partition_ctrl->data, - struct dsdb_control_current_partition); - SMB_ASSERT(partition && partition->version == DSDB_CONTROL_CURRENT_PARTITION_VERSION); - - ac->partition_dn = ldb_dn_copy(ac, partition->dn); - } - - return ac; -} - -/* - turn a DN into a GUID - */ -static int la_guid_from_dn(struct la_context *ac, struct ldb_dn *dn, struct GUID *guid) -{ - int ret; - NTSTATUS status; - - status = dsdb_get_extended_dn_guid(dn, guid); - if (NT_STATUS_IS_OK(status)) { - return LDB_SUCCESS; - } - if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { - DEBUG(4,(__location__ ": Unable to parse GUID for dn %s\n", - ldb_dn_get_linearized(dn))); - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = dsdb_find_guid_by_dn(ldb_module_get_ctx(ac->module), dn, guid); - if (ret != LDB_SUCCESS) { - DEBUG(4,(__location__ ": Failed to find GUID for dn %s\n", - ldb_dn_get_linearized(dn))); - return ret; - } - return LDB_SUCCESS; -} +#include "dsdb/samdb/ldb_modules/util.h" -/* Common routine to handle reading the attributes and creating a - * series of modify requests */ -static int la_store_op(struct la_context *ac, - enum la_op op, struct ldb_val *dn, - const char *name) +static int linked_attributes_fix_links(struct ldb_module *module, + struct ldb_dn *old_dn, struct ldb_dn *new_dn, + struct ldb_message_element *el, struct dsdb_schema *schema, + const struct dsdb_attribute *schema_attr) { - struct ldb_context *ldb; - struct la_op_store *os; - struct ldb_dn *op_dn; - int ret; + int i; + TALLOC_CTX *tmp_ctx = talloc_new(module); + struct ldb_context *ldb = ldb_module_get_ctx(module); + const struct dsdb_attribute *target; + const char *attrs[2]; - ldb = ldb_module_get_ctx(ac->module); - - op_dn = ldb_dn_from_ldb_val(ac, ldb, dn); - if (!op_dn) { - ldb_asprintf_errstring(ldb, - "could not parse attribute as a DN"); - return LDB_ERR_INVALID_DN_SYNTAX; - } - - os = talloc_zero(ac, struct la_op_store); - if (!os) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - os->op = op; - - ret = la_guid_from_dn(ac, op_dn, &os->guid); - if (ret == LDB_ERR_NO_SUCH_OBJECT && ac->req->operation == LDB_DELETE) { - /* we are deleting an object, and we've found it has a - * forward link to a target that no longer - * exists. This is not an error in the delete, and we - * should just not do the deferred delete of the - * target attribute - */ - talloc_free(os); + target = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1); + if (target == NULL) { + /* there is no counterpart link to change */ return LDB_SUCCESS; } - if (ret != LDB_SUCCESS) { - return ret; - } - - os->name = talloc_strdup(os, name); - if (!os->name) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - /* Do deletes before adds */ - if (op == LA_OP_ADD) { - DLIST_ADD_END(ac->ops, os, struct la_op_store *); - } else { - /* By adding to the head of the list, we do deletes before - * adds when processing a replace */ - DLIST_ADD(ac->ops, os); - } - - return LDB_SUCCESS; -} -static int la_op_search_callback(struct ldb_request *req, - struct ldb_reply *ares); -static int la_queue_mod_request(struct la_context *ac); -static int la_down_req(struct la_context *ac); + attrs[0] = target->lDAPDisplayName; + attrs[1] = NULL; + for (i=0; inum_values; i++) { + struct dsdb_dn *dsdb_dn; + int ret, j; + struct ldb_result *res; + struct ldb_message *msg; + struct ldb_message_element *el2; - - -/* For a delete or rename, we need to find out what linked attributes - * are currently on this DN, and then deal with them. This is the - * callback to the base search */ - -static int la_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares) -{ - struct ldb_context *ldb; - const struct dsdb_attribute *schema_attr; - const struct dsdb_attribute *target_attr; - struct ldb_message_element *search_el; - struct replace_context *rc; - struct la_context *ac; - const char *attr_name; - int i, j; - int ret = LDB_SUCCESS; - - ac = talloc_get_type(req->context, struct la_context); - ldb = ldb_module_get_ctx(ac->module); - rc = ac->rc; - - if (!ares) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - /* Only entries are interesting, and we only want the olddn */ - switch (ares->type) { - case LDB_REPLY_ENTRY: - - if (ldb_dn_compare(ares->message->dn, ac->req->op.mod.message->dn) != 0) { - ldb_asprintf_errstring(ldb, - "linked_attributes: %s is not the DN we were looking for", ldb_dn_get_linearized(ares->message->dn)); - /* Guh? We only asked for this DN */ - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); + dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], schema_attr->syntax->ldap_oid); + if (dsdb_dn == NULL) { + talloc_free(tmp_ctx); + return LDB_ERR_INVALID_DN_SYNTAX; } - ac->add_dn = ac->del_dn = talloc_steal(ac, ares->message->dn); - - /* We don't populate 'rc' for ADD - it can't be deleting elements anyway */ - for (i = 0; rc && i < rc->num_elements; i++) { - - schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rc->el[i].name); - if (!schema_attr) { - ldb_asprintf_errstring(ldb, - "attribute %s is not a valid attribute in schema", - rc->el[i].name); - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OBJECT_CLASS_VIOLATION); - } - - search_el = ldb_msg_find_element(ares->message, - rc->el[i].name); - - /* See if this element already exists */ - /* otherwise just ignore as - * the add has already been scheduled */ - if ( ! search_el) { - continue; - } - - target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1); - if (!target_attr) { - /* - * windows 2003 has a broken schema where - * the definition of msDS-IsDomainFor - * is missing (which is supposed to be - * the backlink of the msDS-HasDomainNCs - * attribute - */ - continue; - } - attr_name = target_attr->lDAPDisplayName; - - /* Now we know what was there, we can remove it for the re-add */ - for (j = 0; j < search_el->num_values; j++) { - ret = la_store_op(ac, LA_OP_DEL, - &search_el->values[j], - attr_name); - if (ret != LDB_SUCCESS) { - talloc_free(ares); - return ldb_module_done(ac->req, - NULL, NULL, ret); - } - } - } - - break; - - case LDB_REPLY_REFERRAL: - /* ignore */ - break; - - case LDB_REPLY_DONE: - - talloc_free(ares); - - if (ac->req->operation == LDB_ADD) { - /* Start the modifies to the backlinks */ - ret = la_queue_mod_request(ac); - - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, - ret); - } - } else { - /* Start with the original request */ - ret = la_down_req(ac); - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, ret); - } - } - return LDB_SUCCESS; - } - - talloc_free(ares); - return ret; -} - - - - -/* rename */ -static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req) -{ - struct la_context *ac; - - /* This gets complex: We need to: - - Do a search for the entry - - Wait for these result to appear - - In the callback for the result, issue a modify - request based on the linked attributes found - - Wait for each modify result - - Regain our sainity - */ - - ac = linked_attributes_init(module, req); - if (!ac) { - return LDB_ERR_OPERATIONS_ERROR; - } - - if (!ac->schema) { - /* without schema, this doesn't make any sense */ - return ldb_next_request(module, req); - } - - /* start with the original request */ - return la_down_req(ac); -} - - -static int la_op_search_callback(struct ldb_request *req, - struct ldb_reply *ares) -{ - struct ldb_context *ldb; - struct la_context *ac; - const struct dsdb_attribute *schema_attr; - const struct dsdb_attribute *target_attr; - const struct ldb_message_element *el; - const char *attr_name; - int i, j; - int ret; - - ac = talloc_get_type(req->context, struct la_context); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - /* Only entries are interesting, and we only want the olddn */ - switch (ares->type) { - case LDB_REPLY_ENTRY: - ret = ldb_dn_compare(ares->message->dn, req->op.search.base); - if (ret != 0) { - /* Guh? We only asked for this DN */ - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->message->num_elements == 0) { - /* only bother at all if there were some - * linked attributes found */ - talloc_free(ares); - return LDB_SUCCESS; + ret = dsdb_module_search_dn(module, tmp_ctx, &res, dsdb_dn->dn, + attrs, + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - remote not found - %s", + el->name, target->lDAPDisplayName, + ldb_dn_get_linearized(old_dn), + ldb_dn_get_linearized(dsdb_dn->dn), + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; } + msg = res->msgs[0]; - switch (ac->req->operation) { - case LDB_DELETE: - ac->del_dn = talloc_steal(ac, ares->message->dn); - break; - case LDB_RENAME: - ac->add_dn = talloc_steal(ac, ares->message->dn); - ac->del_dn = talloc_steal(ac, ac->req->op.rename.olddn); - break; - default: - talloc_free(ares); - ldb_set_errstring(ldb, - "operations must be delete or rename"); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); + if (msg->num_elements != 1 || + ldb_attr_cmp(msg->elements[0].name, target->lDAPDisplayName) != 0) { + ldb_set_errstring(ldb, "Bad msg elements in linked_attributes_fix_links"); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; } + el2 = &msg->elements[0]; - for (i = 0; i < ares->message->num_elements; i++) { - el = &ares->message->elements[i]; + el2->flags = LDB_FLAG_MOD_REPLACE; - schema_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, el->name); - if (!schema_attr) { - ldb_asprintf_errstring(ldb, - "attribute %s is not a valid attribute" - " in schema", el->name); - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OBJECT_CLASS_VIOLATION); + /* find our DN in the values */ + for (j=0; jnum_values; j++) { + struct dsdb_dn *dsdb_dn2; + dsdb_dn2 = dsdb_dn_parse(msg, ldb, &el2->values[j], target->syntax->ldap_oid); + if (dsdb_dn2 == NULL) { + talloc_free(tmp_ctx); + return LDB_ERR_INVALID_DN_SYNTAX; } - - /* Valid attribute, now find out if it is linked */ - if (schema_attr->linkID == 0) { - /* Not a linked attribute, skip */ + if (ldb_dn_compare(old_dn, dsdb_dn2->dn) != 0) { continue; } - - if ((schema_attr->linkID & 1) == 0) { - /* Odd is for the target. */ - target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID + 1); - if (!target_attr) { - continue; - } - attr_name = target_attr->lDAPDisplayName; - } else { - target_attr = dsdb_attribute_by_linkID(ac->schema, schema_attr->linkID - 1); - if (!target_attr) { - continue; - } - attr_name = target_attr->lDAPDisplayName; - } - for (j = 0; j < el->num_values; j++) { - ret = la_store_op(ac, LA_OP_DEL, - &el->values[j], - attr_name); - - /* for renames, ensure we add it back */ - if (ret == LDB_SUCCESS - && ac->req->operation == LDB_RENAME) { - ret = la_store_op(ac, LA_OP_ADD, - &el->values[j], - attr_name); - } - if (ret != LDB_SUCCESS) { - talloc_free(ares); - return ldb_module_done(ac->req, - NULL, NULL, ret); - } - } - } - - break; - - case LDB_REPLY_REFERRAL: - /* ignore */ - break; - - case LDB_REPLY_DONE: - - talloc_free(ares); - - - switch (ac->req->operation) { - case LDB_DELETE: - /* start the mod requests chain */ - ret = la_down_req(ac); + ret = ldb_dn_update_components(dsdb_dn2->dn, new_dn); if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, ret); + talloc_free(tmp_ctx); + return ret; } - return ret; - case LDB_RENAME: - /* start the mod requests chain */ - ret = la_queue_mod_request(ac); - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, - ret); - } - return ret; - - default: - talloc_free(ares); - ldb_set_errstring(ldb, - "operations must be delete or rename"); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); + el2->values[j] = data_blob_string_const( + dsdb_dn_get_extended_linearized(el2->values, dsdb_dn2, 1)); } - } - - talloc_free(ares); - return LDB_SUCCESS; -} - -/* queue a linked attributes modify request in the la_private - structure */ -static int la_queue_mod_request(struct la_context *ac) -{ - struct la_private *la_private = - talloc_get_type(ldb_module_get_private(ac->module), struct la_private); - - if (la_private == NULL) { - ldb_debug(ldb_module_get_ctx(ac->module), LDB_DEBUG_ERROR, __location__ ": No la_private transaction setup\n"); - return LDB_ERR_OPERATIONS_ERROR; - } - - talloc_steal(la_private, ac); - DLIST_ADD(la_private->la_list, ac); - - return ldb_module_done(ac->req, ac->op_controls, - ac->op_response, LDB_SUCCESS); -} - -/* Having done the original operation, then try to fix up all the linked attributes for modify and delete */ -static int la_mod_del_callback(struct ldb_request *req, struct ldb_reply *ares) -{ - int ret; - struct la_context *ac; - struct ldb_context *ldb; - - ac = talloc_get_type(req->context, struct la_context); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - if (ares->type != LDB_REPLY_DONE) { - ldb_set_errstring(ldb, - "invalid ldb_reply_type in callback"); - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - - ac->op_controls = talloc_steal(ac, ares->controls); - ac->op_response = talloc_steal(ac, ares->response); - - /* If we have modfies to make, this is the time to do them for modify and delete */ - ret = la_queue_mod_request(ac); - - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, ret); - } - talloc_free(ares); - - /* la_queue_mod_request has already sent the callbacks */ - return LDB_SUCCESS; - -} - -/* Having done the original rename try to fix up all the linked attributes */ -static int la_rename_callback(struct ldb_request *req, struct ldb_reply *ares) -{ - int ret; - struct la_context *ac; - struct ldb_request *search_req; - const char **attrs; - WERROR werr; - struct ldb_context *ldb; - - ac = talloc_get_type(req->context, struct la_context); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - - if (ares->type != LDB_REPLY_DONE) { - ldb_set_errstring(ldb, - "invalid ldb_reply_type in callback"); - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - - werr = dsdb_linked_attribute_lDAPDisplayName_list(ac->schema, ac, &attrs); - if (!W_ERROR_IS_OK(werr)) { - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = ldb_build_search_req(&search_req, ldb, req, - ac->req->op.rename.newdn, LDB_SCOPE_BASE, - "(objectClass=*)", attrs, - NULL, - ac, la_op_search_callback, - req); - - if (ret != LDB_SUCCESS) { - return ret; - } - - talloc_steal(search_req, attrs); - - if (ret == LDB_SUCCESS) { - ret = ldb_request_add_control(search_req, - LDB_CONTROL_EXTENDED_DN_OID, - false, NULL); - } - if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, - ret); - } - - ac->op_controls = talloc_steal(ac, ares->controls); - ac->op_response = talloc_steal(ac, ares->response); - - return ldb_next_request(ac->module, search_req); -} - -/* Having done the original add, then try to fix up all the linked attributes - - This is done after the add so the links can get the extended DNs correctly. - */ -static int la_add_callback(struct ldb_request *req, struct ldb_reply *ares) -{ - int ret; - struct la_context *ac; - struct ldb_context *ldb; - - ac = talloc_get_type(req->context, struct la_context); - ldb = ldb_module_get_ctx(ac->module); - - if (!ares) { - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - if (ares->error != LDB_SUCCESS) { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); - } - if (ares->type != LDB_REPLY_DONE) { - ldb_set_errstring(ldb, - "invalid ldb_reply_type in callback"); - talloc_free(ares); - return ldb_module_done(ac->req, NULL, NULL, - LDB_ERR_OPERATIONS_ERROR); - } - - if (ac->ops) { - struct ldb_request *search_req; - static const char *attrs[] = { NULL }; - - /* The callback does all the hard work here - we need - * the objectGUID and SID of the added record */ - ret = ldb_build_search_req(&search_req, ldb, ac, - ac->req->op.add.message->dn, - LDB_SCOPE_BASE, - "(objectClass=*)", attrs, - NULL, - ac, la_mod_search_callback, - ac->req); - - if (ret == LDB_SUCCESS) { - ret = ldb_request_add_control(search_req, - LDB_CONTROL_EXTENDED_DN_OID, - false, NULL); - } + ret = dsdb_module_modify(module, msg, 0); if (ret != LDB_SUCCESS) { - return ldb_module_done(ac->req, NULL, NULL, - ret); + ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s", + el->name, target->lDAPDisplayName, + ldb_dn_get_linearized(old_dn), + ldb_dn_get_linearized(dsdb_dn->dn), + ldb_errstring(ldb)); + talloc_free(tmp_ctx); + return ret; } - - ac->op_controls = talloc_steal(ac, ares->controls); - ac->op_response = talloc_steal(ac, ares->response); - - return ldb_next_request(ac->module, search_req); - - } else { - return ldb_module_done(ac->req, ares->controls, - ares->response, ares->error); } -} - -/* Reconstruct the original request, but pointing at our local callback to finish things off */ -static int la_down_req(struct la_context *ac) -{ - struct ldb_request *down_req; - int ret; - struct ldb_context *ldb; - - ldb = ldb_module_get_ctx(ac->module); - switch (ac->req->operation) { - case LDB_ADD: - ret = ldb_build_add_req(&down_req, ldb, ac, - ac->req->op.add.message, - ac->req->controls, - ac, la_add_callback, - ac->req); - break; - case LDB_MODIFY: - ret = ldb_build_mod_req(&down_req, ldb, ac, - ac->req->op.mod.message, - ac->req->controls, - ac, la_mod_del_callback, - ac->req); - break; - case LDB_DELETE: - ret = ldb_build_del_req(&down_req, ldb, ac, - ac->req->op.del.dn, - ac->req->controls, - ac, la_mod_del_callback, - ac->req); - break; - case LDB_RENAME: - ret = ldb_build_rename_req(&down_req, ldb, ac, - ac->req->op.rename.olddn, - ac->req->op.rename.newdn, - ac->req->controls, - ac, la_rename_callback, - ac->req); - break; - default: - ret = LDB_ERR_OPERATIONS_ERROR; - } - if (ret != LDB_SUCCESS) { - return ret; - } - - return ldb_next_request(ac->module, down_req); + talloc_free(tmp_ctx); + return LDB_SUCCESS; } -/* - use the GUID part of an extended DN to find the target DN, in case - it has moved - */ -static int la_find_dn_target(struct ldb_module *module, struct la_context *ac, - struct GUID *guid, struct ldb_dn **dn) -{ - return dsdb_find_dn_by_guid(ldb_module_get_ctx(ac->module), ac, GUID_string(ac, guid), dn); -} -/* apply one la_context op change */ -static int la_do_op_request(struct ldb_module *module, struct la_context *ac, struct la_op_store *op) +/* rename */ +static int linked_attributes_rename(struct ldb_module *module, struct ldb_request *req) { - struct ldb_message_element *ret_el; - struct ldb_request *mod_req; - struct ldb_message *new_msg; - struct ldb_context *ldb; - int ret; - - ldb = ldb_module_get_ctx(ac->module); - - /* Create the modify request */ - new_msg = ldb_msg_new(ac); - if (!new_msg) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - - ret = la_find_dn_target(module, ac, &op->guid, &new_msg->dn); - if (ret != LDB_SUCCESS) { - return ret; - } - - if (op->op == LA_OP_ADD) { - ret = ldb_msg_add_empty(new_msg, op->name, - LDB_FLAG_MOD_ADD, &ret_el); - } else { - ret = ldb_msg_add_empty(new_msg, op->name, - LDB_FLAG_MOD_DELETE, &ret_el); - } - if (ret != LDB_SUCCESS) { - return ret; - } - ret_el->values = talloc_array(new_msg, struct ldb_val, 1); - if (!ret_el->values) { - ldb_oom(ldb); - return LDB_ERR_OPERATIONS_ERROR; - } - ret_el->num_values = 1; - if (op->op == LA_OP_ADD) { - ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->add_dn, 1)); - } else { - ret_el->values[0] = data_blob_string_const(ldb_dn_get_extended_linearized(new_msg, ac->del_dn, 1)); - } - -#if 0 - ldb_debug(ldb, LDB_DEBUG_WARNING, - "link on %s %s: %s %s\n", - ldb_dn_get_linearized(new_msg->dn), ret_el->name, - ret_el->values[0].data, ac->ops->op == LA_OP_ADD ? "added" : "deleted"); -#endif - - ret = ldb_build_mod_req(&mod_req, ldb, op, - new_msg, - NULL, - NULL, - ldb_op_default_callback, - NULL); + struct ldb_result *res; + struct ldb_message *msg; + int ret, i; + struct ldb_context *ldb = ldb_module_get_ctx(module); + struct dsdb_schema *schema = dsdb_get_schema(ldb); + /* + - load the current msg + - find any linked attributes + - if its a link then find the target object + - modify the target linked attributes with the new DN + */ + ret = dsdb_module_search_dn(module, req, &res, req->op.rename.olddn, + NULL, DSDB_SEARCH_SHOW_DELETED); if (ret != LDB_SUCCESS) { return ret; } - talloc_steal(mod_req, new_msg); - - if (DEBUGLVL(4)) { - DEBUG(4,("Applying linked attribute change:\n%s\n", - ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg))); - } - - /* Run the new request */ - ret = ldb_next_request(module, mod_req); - - /* we need to wait for this to finish, as we are being called - from the synchronous end_transaction hook of this module */ - if (ret == LDB_SUCCESS) { - ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL); - } + msg = res->msgs[0]; - if (ret != LDB_SUCCESS) { - ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n", - ldb_errstring(ldb), - ldb_ldif_message_string(ldb, op, LDB_CHANGETYPE_MODIFY, new_msg)); - } - - return ret; -} - -/* apply one set of la_context changes */ -static int la_do_mod_request(struct ldb_module *module, struct la_context *ac) -{ - struct la_op_store *op; - - for (op = ac->ops; op; op=op->next) { - int ret = la_do_op_request(module, ac, op); - if (ret != LDB_SUCCESS) { - if (ret != LDB_ERR_NO_SUCH_OBJECT) { - return ret; - } + for (i=0; inum_elements; i++) { + struct ldb_message_element *el = &msg->elements[i]; + const struct dsdb_attribute *schema_attr + = dsdb_attribute_by_lDAPDisplayName(schema, el->name); + if (!schema_attr || schema_attr->linkID == 0) { + continue; } - } - - return LDB_SUCCESS; -} - - -/* - we hook into the transaction operations to allow us to - perform the linked attribute updates at the end of the whole - transaction. This allows a forward linked attribute to be created - before the target is created, as long as the target is created - in the same transaction - */ -static int linked_attributes_start_transaction(struct ldb_module *module) -{ - /* create our private structure for this transaction */ - struct la_private *la_private = talloc_get_type(ldb_module_get_private(module), - struct la_private); - talloc_free(la_private); - la_private = talloc(module, struct la_private); - if (la_private == NULL) { - return LDB_ERR_OPERATIONS_ERROR; - } - la_private->la_list = NULL; - ldb_module_set_private(module, la_private); - return ldb_next_start_trans(module); -} - -/* - on prepare commit we loop over our queued la_context structures - and apply each of them - */ -static int linked_attributes_prepare_commit(struct ldb_module *module) -{ - struct la_private *la_private = - talloc_get_type(ldb_module_get_private(module), struct la_private); - struct la_context *ac; - - if (!la_private) { - /* prepare commit without begin_transaction - let someone else return the error, just don't segfault */ - return ldb_next_prepare_commit(module); - } - /* walk the list backwards, to do the first entry first, as we - * added the entries with DLIST_ADD() which puts them at the - * start of the list */ - for (ac = la_private->la_list; ac && ac->next; ac=ac->next) ; - - for (; ac; ac=ac->prev) { - int ret; - ac->req = NULL; - ret = la_do_mod_request(module, ac); + ret = linked_attributes_fix_links(module, msg->dn, req->op.rename.newdn, el, + schema, schema_attr); if (ret != LDB_SUCCESS) { - DEBUG(0,(__location__ ": Failed mod request ret=%d\n", ret)); - talloc_free(la_private); - ldb_module_set_private(module, NULL); + talloc_free(res); return ret; } } - talloc_free(la_private); - ldb_module_set_private(module, NULL); + talloc_free(res); - return ldb_next_prepare_commit(module); -} - -static int linked_attributes_del_transaction(struct ldb_module *module) -{ - struct la_private *la_private = - talloc_get_type(ldb_module_get_private(module), struct la_private); - talloc_free(la_private); - ldb_module_set_private(module, NULL); - return ldb_next_del_trans(module); + return ldb_next_request(module, req); } _PUBLIC_ const struct ldb_module_ops ldb_linked_attributes_module_ops = { .name = "linked_attributes", - .start_transaction = linked_attributes_start_transaction, - .prepare_commit = linked_attributes_prepare_commit, - .del_transaction = linked_attributes_del_transaction, + .rename = linked_attributes_rename, }; -- cgit From e4a6f5c8b8de0429578cd09913f1d41d0a1fd82f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 17 Dec 2009 23:50:41 +1100 Subject: s4-dsdb: handle links with no backlinks in replmd_delete --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 689b24f398..e184181f01 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2038,10 +2038,9 @@ static int replmd_delete_remove_link(struct ldb_module *module, msg->dn = dsdb_dn->dn; - if (sa->linkID & 1) { - target_attr = dsdb_attribute_by_linkID(schema, sa->linkID - 1); - } else { - target_attr = dsdb_attribute_by_linkID(schema, sa->linkID + 1); + target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1); + if (target_attr == NULL) { + continue; } ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2); -- cgit From f1b6484232cbcd31056b8f905f3b111d0c9069b0 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 12:47:31 +1100 Subject: s4-dsdb: split RMD_USN into RMD_LOCAL_USN and RMD_ORIGINATING_USN We need a separate RMD_LOCAL_USN to allow us to tell what attributes need to be sent in a getncchanges request. Thanks to Metze for pointing this out. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index e184181f01..822ed8868d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1172,12 +1172,13 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, /* build a new extended DN, including all meta data fields - DELETED = 1 or missing - RMD_ADDTIME = originating_add_time - RMD_INVOCID = originating_invocation_id - RMD_CHANGETIME = originating_change_time - RMD_USN = originating_usn - RMD_VERSION = version + DELETED = 1 or missing + RMD_ADDTIME = originating_add_time + RMD_INVOCID = originating_invocation_id + RMD_CHANGETIME = originating_change_time + RMD_ORIGINATING_USN = originating_usn + RMD_LOCAL_USN = local_usn + RMD_VERSION = version */ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, const struct GUID *invocation_id, uint64_t seq_num, time_t t) @@ -1221,7 +1222,9 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval); if (ret != LDB_SUCCESS) return ret; - ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv); + ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &usnv); + if (ret != LDB_SUCCESS) return ret; + ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv); if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); if (ret != LDB_SUCCESS) return ret; @@ -1303,7 +1306,10 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d if (ret != LDB_SUCCESS) return ret; /* update the USN */ - ret = ldb_dn_set_extended_component(dn, "RMD_USN", &usnv); + ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv); + if (ret != LDB_SUCCESS) return ret; + + ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &usnv); if (ret != LDB_SUCCESS) return ret; /* increase the version by 1 */ -- cgit From b1db66a501e3b5e5df66e722ad849a821c667d5b Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 20:51:37 +1100 Subject: s4-dsdb: allow the component name to be specified in dsdb_get_extended_dn_guid() Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/common/util.c | 4 ++-- source4/dsdb/schema/schema_syntax.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 561edff94c..528c68b856 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2797,11 +2797,11 @@ int dsdb_functional_level(struct ldb_context *ldb) /* return a GUID from a extended DN structure */ -NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid) +NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name) { const struct ldb_val *v; - v = ldb_dn_get_extended_component(dn, "GUID"); + v = ldb_dn_get_extended_component(dn, component_name); if (v == NULL) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c index 1989db0699..e958605707 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -1183,7 +1183,7 @@ static WERROR dsdb_syntax_DN_ldb_to_drsuapi(struct ldb_context *ldb, ZERO_STRUCT(id3); - status = dsdb_get_extended_dn_guid(dn, &id3.guid); + status = dsdb_get_extended_dn_guid(dn, &id3.guid, "GUID"); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { talloc_free(tmp_ctx); @@ -1367,7 +1367,7 @@ static WERROR dsdb_syntax_DN_BINARY_ldb_to_drsuapi(struct ldb_context *ldb, ZERO_STRUCT(id3); - status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &id3.guid); + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &id3.guid, "GUID"); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { talloc_free(tmp_ctx); -- cgit From 312ef9df3cdb6461e051dff4f3fe3d4ae1601392 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 20:56:04 +1100 Subject: s4-dsdb: add REVEAL_INTERNALS in the search for linked_attributes Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index edcb2d8167..4113a58154 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -72,7 +72,8 @@ static int linked_attributes_fix_links(struct ldb_module *module, ret = dsdb_module_search_dn(module, tmp_ctx, &res, dsdb_dn->dn, attrs, DSDB_SEARCH_SHOW_DELETED | - DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | + DSDB_SEARCH_REVEAL_INTERNALS); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - remote not found - %s", el->name, target->lDAPDisplayName, -- cgit From 4dbcab45f263e3ccce1d10d20226d7c3c68cdc9a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 18 Dec 2009 20:57:21 +1100 Subject: s4-dsdb: store full meta data from DRS for linked attributes Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 389 +++++++++++++++--------- 1 file changed, 239 insertions(+), 150 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 822ed8868d..95e51d1d8b 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -580,7 +580,9 @@ static void replmd_ldb_message_sort(struct ldb_message *msg, } static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, - const struct GUID *invocation_id, uint64_t seq_num, time_t t); + const struct GUID *invocation_id, uint64_t seq_num, + uint64_t local_usn, NTTIME nttime, bool deleted); + /* fix up linked attributes in replmd_add. @@ -595,6 +597,9 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme TALLOC_CTX *tmp_ctx = talloc_new(el->values); struct ldb_context *ldb = ldb_module_get_ctx(module); struct dsdb_schema *schema = dsdb_get_schema(ldb); + NTTIME now; + + unix_to_nt_time(&now, t); for (i=0; inum_values; i++) { struct ldb_val *v = &el->values[i]; @@ -603,7 +608,8 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme NTSTATUS status; int ret; - ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, seq_num, t); + ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, + seq_num, seq_num, now, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -611,7 +617,7 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme /* note that the DN already has the extended components from the extended_dn_store module */ - status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid); + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID"); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; @@ -1147,7 +1153,7 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, return LDB_ERR_OPERATIONS_ERROR; } - status = dsdb_get_extended_dn_guid(dn, p->guid); + status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID"); if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { /* we got a DN without a GUID - go find the GUID */ int ret = dsdb_find_guid_by_dn(ldb, dn, p->guid); @@ -1181,21 +1187,20 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, RMD_VERSION = version */ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, - const struct GUID *invocation_id, uint64_t seq_num, time_t t) + const struct GUID *invocation_id, uint64_t seq_num, + uint64_t local_usn, NTTIME nttime, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; - NTTIME now; const char *tstring, *usn_string; struct ldb_val tval; struct ldb_val iid; - struct ldb_val usnv; + struct ldb_val usnv, local_usnv; struct ldb_val vers; NTSTATUS status; int ret; const char *dnstring; - unix_to_nt_time(&now, t); - tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now); + tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { return LDB_ERR_OPERATIONS_ERROR; } @@ -1207,6 +1212,12 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds } usnv = data_blob_string_const(usn_string); + usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn); + if (!usn_string) { + return LDB_ERR_OPERATIONS_ERROR; + } + local_usnv = data_blob_string_const(usn_string); + vers = data_blob_string_const("0"); status = GUID_to_ndr_blob(invocation_id, dn, &iid); @@ -1214,7 +1225,13 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds return LDB_ERR_OPERATIONS_ERROR; } - ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + if (deleted) { + struct ldb_val dv; + dv = data_blob_string_const("1"); + ret = ldb_dn_set_extended_component(dn, "DELETED", &dv); + } else { + ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + } if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval); if (ret != LDB_SUCCESS) return ret; @@ -1222,7 +1239,7 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval); if (ret != LDB_SUCCESS) return ret; - ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &usnv); + ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv); if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv); if (ret != LDB_SUCCESS) return ret; @@ -1246,22 +1263,20 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds */ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id, - uint64_t seq_num, time_t t, bool deleted) + uint64_t seq_num, uint64_t local_usn, NTTIME nttime, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; - NTTIME now; const char *tstring, *usn_string; struct ldb_val tval; struct ldb_val iid; - struct ldb_val usnv; + struct ldb_val usnv, local_usnv; struct ldb_val vers; const struct ldb_val *old_addtime, *old_version; NTSTATUS status; int ret; const char *dnstring; - unix_to_nt_time(&now, t); - tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)now); + tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { return LDB_ERR_OPERATIONS_ERROR; } @@ -1273,6 +1288,12 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d } usnv = data_blob_string_const(usn_string); + usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn); + if (!usn_string) { + return LDB_ERR_OPERATIONS_ERROR; + } + local_usnv = data_blob_string_const(usn_string); + status = GUID_to_ndr_blob(invocation_id, dn, &iid); if (!NT_STATUS_IS_OK(status)) { return LDB_ERR_OPERATIONS_ERROR; @@ -1309,7 +1330,7 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv); if (ret != LDB_SUCCESS) return ret; - ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &usnv); + ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv); if (ret != LDB_SUCCESS) return ret; /* increase the version by 1 */ @@ -1360,6 +1381,9 @@ static int replmd_modify_la_add(struct ldb_module *module, unsigned old_num_values = old_el?old_el->num_values:0; const struct GUID *invocation_id; struct ldb_context *ldb = ldb_module_get_ctx(module); + NTTIME now; + + unix_to_nt_time(&now, t); ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid); if (ret != LDB_SUCCESS) { @@ -1390,7 +1414,7 @@ static int replmd_modify_la_add(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, - invocation_id, seq_num, t); + invocation_id, seq_num, seq_num, now, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1408,7 +1432,7 @@ static int replmd_modify_la_add(struct ldb_module *module, return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; } ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn, - invocation_id, seq_num, t, false); + invocation_id, seq_num, seq_num, now, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1466,6 +1490,9 @@ static int replmd_modify_la_delete(struct ldb_module *module, int ret; const struct GUID *invocation_id; struct ldb_context *ldb = ldb_module_get_ctx(module); + NTTIME now; + + unix_to_nt_time(&now, t); /* check if there is nothing to delete */ if ((!old_el || old_el->num_values == 0) && @@ -1532,7 +1559,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, if (v != NULL) continue; ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn, - invocation_id, seq_num, t, true); + invocation_id, seq_num, seq_num, now, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1579,6 +1606,9 @@ static int replmd_modify_la_replace(struct ldb_module *module, struct ldb_val *new_values = NULL; uint32_t num_new_values = 0; unsigned old_num_values = old_el?old_el->num_values:0; + NTTIME now; + + unix_to_nt_time(&now, t); /* check if there is nothing to replace */ if ((!old_el || old_el->num_values == 0) && @@ -1625,7 +1655,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, } ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, - invocation_id, seq_num, t, true); + invocation_id, seq_num, seq_num, now, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1644,7 +1674,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, /* update in place */ ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, invocation_id, - seq_num, t, false); + seq_num, seq_num, now, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1659,7 +1689,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, - invocation_id, seq_num, t); + invocation_id, seq_num, seq_num, now, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -2027,7 +2057,7 @@ static int replmd_delete_remove_link(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } - status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2); + status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID"); if (!NT_STATUS_IS_OK(status)) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; @@ -2188,7 +2218,8 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) /* we need the storage form of the parent GUID */ ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res, ldb_dn_get_parent(tmp_ctx, old_dn), NULL, - DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT); + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | + DSDB_SEARCH_REVEAL_INTERNALS); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -2398,25 +2429,38 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar) return ldb_next_request(ar->module, change_req); } -static int replmd_replPropertyMetaData1_conflict_compare(struct replPropertyMetaData1 *m1, - struct replPropertyMetaData1 *m2) +/* + return true if an update is newer than an existing entry + see section 5.11 of MS-ADTS +*/ +static bool replmd_update_is_newer(const struct GUID *current_invocation_id, + const struct GUID *update_invocation_id, + uint32_t current_version, + uint32_t update_version, + NTTIME current_change_time, + NTTIME update_change_time) { - int ret; - - if (m1->version != m2->version) { - return m1->version - m2->version; + if (update_version != current_version) { + return update_version > current_version; } - - if (m1->originating_change_time != m2->originating_change_time) { - return m1->originating_change_time - m2->originating_change_time; + if (update_change_time > current_change_time) { + return true; } - - ret = GUID_compare(&m1->originating_invocation_id, &m2->originating_invocation_id); - if (ret != 0) { - return ret; + if (update_change_time == current_change_time) { + return GUID_compare(update_invocation_id, current_invocation_id) > 0; } + return false; +} - return m1->originating_usn - m2->originating_usn; +static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m, + struct replPropertyMetaData1 *new_m) +{ + return replmd_update_is_newer(&cur_m->originating_invocation_id, + &new_m->originating_invocation_id, + cur_m->version, + new_m->version, + cur_m->originating_change_time, + new_m->originating_change_time); } static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) @@ -2494,21 +2538,26 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) bool found = false; for (j=0; j < ni; j++) { - int cmp; + bool cmp; if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) { continue; } - cmp = replmd_replPropertyMetaData1_conflict_compare(&rmd->ctr.ctr1.array[i], - &nmd.ctr.ctr1.array[j]); - if (cmp > 0) { + cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j], + &rmd->ctr.ctr1.array[i]); + if (cmp) { /* replace the entry */ nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i]; found = true; break; } + DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n", + msg->elements[i-removed_attrs].name, + ldb_dn_get_linearized(msg->dn), + GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id))); + /* we don't want to apply this change so remove the attribute */ ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]); removed_attrs++; @@ -3210,21 +3259,23 @@ static int replmd_process_linked_attribute(struct ldb_module *module, struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la; struct ldb_context *ldb = ldb_module_get_ctx(module); struct dsdb_schema *schema = dsdb_get_schema(ldb); - struct drsuapi_DsReplicaObjectIdentifier3 target; struct ldb_message *msg; TALLOC_CTX *tmp_ctx = talloc_new(la_entry); - struct ldb_request *mod_req; int ret; const struct dsdb_attribute *attr; - struct ldb_dn *target_dn; struct dsdb_dn *dsdb_dn; uint64_t seq_num = 0; struct drsuapi_DsReplicaAttribute drs; struct drsuapi_DsAttributeValue val; - struct ldb_message_element el; - const struct ldb_val *guid; + struct ldb_message_element new_el, *old_el; WERROR status; time_t t = time(NULL); + struct ldb_result *res; + const char *attrs[2]; + struct parsed_dn *pdn_list, *pdn; + struct GUID guid; + NTSTATUS ntstatus; + bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false; drs.value_ctr.num_values = 1; drs.value_ctr.values = &val; @@ -3273,153 +3324,191 @@ linked_attributes[0]: return LDB_ERR_OPERATIONS_ERROR; } - status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &el); - - /* construct a modify request for this attribute change */ - msg = ldb_msg_new(tmp_ctx); - if (!msg) { - ldb_oom(ldb); - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; - } + attrs[0] = attr->lDAPDisplayName; + attrs[1] = NULL; - ret = dsdb_find_dn_by_guid(ldb, tmp_ctx, - GUID_string(tmp_ctx, &la->identifier->guid), &msg->dn); + /* get the existing message from the db for the object with + this GUID, returning attribute being modified. We will then + use this msg as the basis for a modify call */ + ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs, + DSDB_SEARCH_SEARCH_ALL_PARTITIONS | + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | + DSDB_SEARCH_REVEAL_INTERNALS, + "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid)); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } + if (res->count != 1) { + ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found", + GUID_string(tmp_ctx, &la->identifier->guid)); + talloc_free(tmp_ctx); + return LDB_ERR_NO_SUCH_OBJECT; + } + msg = res->msgs[0]; - el.name = attr->lDAPDisplayName; - if (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) { - ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_ADD); + if (msg->num_elements == 0) { + ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el); + if (ret != LDB_SUCCESS) { + ldb_module_oom(module); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } } else { - ret = ldb_msg_add(msg, &el, LDB_FLAG_MOD_DELETE); + old_el = &msg->elements[0]; + old_el->flags = LDB_FLAG_MOD_REPLACE; } + + /* parse the existing links */ + ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } - dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el.values[0], attr->syntax->ldap_oid); - if (!dsdb_dn) { - DEBUG(0,(__location__ ": Failed to parse just-generated DN\n")); - talloc_free(tmp_ctx); - return LDB_ERR_INVALID_DN_SYNTAX; + status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &new_el); + if (!W_ERROR_IS_OK(status)) { + ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn)); + return LDB_ERR_OPERATIONS_ERROR; } - guid = ldb_dn_get_extended_component(dsdb_dn->dn, "GUID"); - if (!guid) { - DEBUG(0,(__location__ ": Failed to parse GUID from just-generated DN\n")); - talloc_free(tmp_ctx); - return LDB_ERR_INVALID_DN_SYNTAX; + if (new_el.num_values != 1) { + ldb_asprintf_errstring(ldb, "Failed to find value in linked attribute blob for %s on %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn)); + return LDB_ERR_OPERATIONS_ERROR; } - ret = dsdb_find_dn_by_guid(ldb, tmp_ctx, ldb_binary_encode(tmp_ctx, *guid), &target_dn); - if (ret != LDB_SUCCESS) { - /* If this proves to be a problem in the future, then - * just remove the return - perhaps we can just use - * the details the replication peer supplied */ - - DEBUG(0,(__location__ ": Failed to map GUID %s to DN\n", GUID_string(tmp_ctx, &target.guid))); - talloc_free(tmp_ctx); + dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &new_el.values[0], attr->syntax->ldap_oid); + if (!dsdb_dn) { + ldb_asprintf_errstring(ldb, "Failed to parse DN in linked attribute blob for %s on %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn)); return LDB_ERR_OPERATIONS_ERROR; - } else { - - /* Now update with full DN we just found in the DB (including extended components) */ - dsdb_dn->dn = target_dn; - /* Now make a linearized version, using the original binary components (if any) */ - el.values[0] = data_blob_string_const(dsdb_dn_get_extended_linearized(tmp_ctx, dsdb_dn, 1)); } - ret = replmd_update_rpmd(module, schema, msg, &seq_num, t); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return ret; + ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID"); + if (!NT_STATUS_IS_OK(ntstatus)) { + ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn)); + return LDB_ERR_OPERATIONS_ERROR; } - /* 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) { + /* see if this link already exists */ + pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid); + if (pdn != NULL) { + /* see if this update is newer than what we have already */ + struct GUID invocation_id = GUID_zero(); + uint32_t version = 0; + NTTIME change_time = 0; + bool was_active = ldb_dn_get_extended_component(pdn->dsdb_dn->dn, "DELETED") == NULL; + + dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID"); + dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION"); + dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME"); + + if (!replmd_update_is_newer(&invocation_id, + &la->meta_data.originating_invocation_id, + version, + la->meta_data.version, + change_time, + la->meta_data.originating_change_time)) { + DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn), + GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id))); talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; + return LDB_SUCCESS; } - if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) { + /* get a seq_num for this change */ + ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num); + if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; + return ret; } - } - - ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx, - msg, - NULL, - NULL, - ldb_op_default_callback, - NULL); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return ret; - } - talloc_steal(mod_req, msg); - if (DEBUGLVL(4)) { - DEBUG(4,("Applying DRS linked attribute change:\n%s\n", - ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg))); - } - - /* Run the new request */ - ret = ldb_next_request(module, mod_req); + if (was_active) { + /* remove the existing backlink */ + ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } - /* we need to wait for this to finish, as we are being called - from the synchronous end_transaction hook of this module */ - if (ret == LDB_SUCCESS) { - ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL); - } + ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn, + &la->meta_data.originating_invocation_id, + la->meta_data.originating_usn, seq_num, + la->meta_data.originating_change_time, + !active); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } - if (ret == LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS) { - /* the link destination exists, we need to update it - * by deleting the old one for the same DN then adding - * the new one */ - msg->elements = talloc_realloc(msg, msg->elements, - struct ldb_message_element, - msg->num_elements+1); - if (msg->elements == NULL) { - ldb_oom(ldb); + if (active) { + /* add the new backlink */ + ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + } else { + /* get a seq_num for this change */ + ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num); + if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); + return ret; + } + + old_el->values = talloc_realloc(msg->elements, old_el->values, + struct ldb_val, old_el->num_values+1); + if (!old_el->values) { + ldb_module_oom(module); return LDB_ERR_OPERATIONS_ERROR; } - /* this relies on the backend matching the old entry - only by the DN portion of the extended DN */ - msg->elements[1] = msg->elements[0]; - msg->elements[0].flags = LDB_FLAG_MOD_DELETE; - msg->num_elements++; - - ret = ldb_build_mod_req(&mod_req, ldb, tmp_ctx, - msg, - NULL, - NULL, - ldb_op_default_callback, - NULL); + old_el->num_values++; + + ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn, + &la->meta_data.originating_invocation_id, + la->meta_data.originating_usn, seq_num, + la->meta_data.originating_change_time, + (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; } - /* Run the new request */ - ret = ldb_next_request(module, mod_req); - - if (ret == LDB_SUCCESS) { - ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL); + if (active) { + ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, + true, attr, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } } } + /* we only change whenChanged and uSNChanged if the seq_num + has changed */ + if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = dsdb_module_modify(module, msg, 0); if (ret != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n", ldb_errstring(ldb), ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)); - ret = LDB_SUCCESS; + talloc_free(tmp_ctx); + return ret; } talloc_free(tmp_ctx); -- cgit From 809bcfca3d835458010013c0454b16d7f2a9fdf3 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 12:23:22 +1100 Subject: s4-dsdb: minor cleanup in DRS replicated objects code --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 95e51d1d8b..3e6455c089 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2378,14 +2378,15 @@ static int replmd_replicated_apply_add(struct replmd_replicated_request *ar) /* remove any message elements that have zero values */ for (i=0; inum_elements; i++) { - if (msg->elements[i].num_values == 0) { + struct ldb_message_element *el = &msg->elements[i]; + + if (el->num_values == 0) { DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n", - msg->elements[i].name)); - memmove(&msg->elements[i], - &msg->elements[i+1], - sizeof(msg->elements[i])*(msg->num_elements - (i+1))); + el->name)); + memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1))); msg->num_elements--; i--; + continue; } } -- cgit From 26ec526d02d78fb327fb855ce5ff037cb74af303 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 19:57:37 +1100 Subject: s4-dsdb: auto-upgrade w2k formatted linked attributes when modified When any value of a w2k formatted linked attribute is modified, upgrade the links. --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 63 +++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 3e6455c089..7f797752d0 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1255,6 +1255,35 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds return LDB_SUCCESS; } +static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, + struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id, + uint64_t seq_num, uint64_t local_usn, NTTIME nttime, bool deleted); + +/* + check if any links need upgrading from w2k format + */ +static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, const struct GUID *invocation_id) +{ + int i; + for (i=0; idn, &version, "RMD_VERSION"); + if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { + continue; + } + + /* it's an old one that needs upgrading */ + ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id, + 1, 1, 0, false); + if (ret != LDB_SUCCESS) { + return ret; + } + } + return LDB_SUCCESS; +} /* update an extended DN, including all meta data fields @@ -1399,9 +1428,16 @@ static int replmd_modify_la_add(struct ldb_module *module, invocation_id = samdb_ntds_invocation_id(ldb); if (!invocation_id) { + talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } + ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + /* for each new value, see if it exists already with the same GUID */ for (i=0; inum_values; i++) { struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid); @@ -1521,6 +1557,12 @@ static int replmd_modify_la_delete(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } + ret = replmd_check_upgrade_links(old_dns, old_el->num_values, invocation_id); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + el->values = NULL; /* see if we are being asked to delete any links that @@ -1633,6 +1675,12 @@ static int replmd_modify_la_replace(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } + ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + /* mark all the old ones as deleted */ for (i=0; iflags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false; + const struct GUID *our_invocation_id; drs.value_ctr.num_values = 1; drs.value_ctr.values = &val; @@ -3368,6 +3417,20 @@ linked_attributes[0]: return ret; } + /* get our invocationId */ + our_invocation_id = samdb_ntds_invocation_id(ldb); + if (!our_invocation_id) { + ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n"); + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, our_invocation_id); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &new_el); if (!W_ERROR_IS_OK(status)) { ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s\n", -- cgit From 64802c5e2711eec1a0046098955354e5cd978636 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 20:55:46 +1100 Subject: s4-dsdb: added dsdb_dn_is_upgraded_link_val() This is used to detect if a link has been stored in the w2k3 extended format --- source4/dsdb/common/util.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 528c68b856..ef47079f9f 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2874,6 +2874,15 @@ bool dsdb_dn_is_deleted_val(struct ldb_val *val) return false; } +/* + return true if a ldb_val containing a DN in storage form is + in the upgraded w2k3 linked attribute format + */ +bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val) +{ + return memmem(val->data, val->length, " Date: Sat, 19 Dec 2009 21:40:55 +1100 Subject: s4-dsdb: added dsdb_check_single_valued_link() This is used in conjunction with the RELAX control, to check for violations of single value rules for linked attributes --- source4/dsdb/samdb/ldb_modules/util.c | 29 +++++++++++++++++++++++++++++ source4/dsdb/samdb/ldb_modules/util.h | 2 ++ 2 files changed, 31 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index b0ccd0341c..fa451f4bcf 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -371,3 +371,32 @@ const struct dsdb_class * get_last_structural_class(const struct dsdb_schema *sc return last_class; } + +/* + check if a single valued link has multiple non-deleted values + + This is needed when we will be using the RELAX control to stop + ldb_tdb from checking single valued links + */ +int dsdb_check_single_valued_link(const struct dsdb_attribute *attr, + const struct ldb_message_element *el) +{ + bool found_active = false; + int i; + + if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE) || + el->num_values < 2) { + return LDB_SUCCESS; + } + + for (i=0; inum_values; i++) { + if (!dsdb_dn_is_deleted_val(&el->values[i])) { + if (found_active) { + return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; + } + found_active = true; + } + } + + return LDB_SUCCESS; +} diff --git a/source4/dsdb/samdb/ldb_modules/util.h b/source4/dsdb/samdb/ldb_modules/util.h index cc184eee8f..66579ab852 100644 --- a/source4/dsdb/samdb/ldb_modules/util.h +++ b/source4/dsdb/samdb/ldb_modules/util.h @@ -21,6 +21,8 @@ struct dsdb_schema; /* predeclare schema struct */ struct GUID; +struct dsdb_attribute; + #include "dsdb/samdb/ldb_modules/util_proto.h" #define DSDB_SEARCH_SEARCH_ALL_PARTITIONS 0x0001 -- cgit From 5dcb903f26045656372993822debcfbc956827b0 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 19 Dec 2009 21:42:40 +1100 Subject: s4-dsdb: move checking for single valued links to samba modules This uses the RELAX control and checking of single valued attributes in ldb modules to avoid problems with multi-valued links where all values but one are deleted --- source4/dsdb/samdb/ldb_modules/linked_attributes.c | 8 +++++++- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 10 ++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/linked_attributes.c b/source4/dsdb/samdb/ldb_modules/linked_attributes.c index 4113a58154..4c326bc240 100644 --- a/source4/dsdb/samdb/ldb_modules/linked_attributes.c +++ b/source4/dsdb/samdb/ldb_modules/linked_attributes.c @@ -116,7 +116,13 @@ static int linked_attributes_fix_links(struct ldb_module *module, dsdb_dn_get_extended_linearized(el2->values, dsdb_dn2, 1)); } - ret = dsdb_module_modify(module, msg, 0); + ret = dsdb_check_single_valued_link(target, el2); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "Linked attribute %s->%s between %s and %s - update failed - %s", el->name, target->lDAPDisplayName, diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 7f797752d0..d3a7e3791c 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -3566,9 +3566,15 @@ linked_attributes[0]: return LDB_ERR_OPERATIONS_ERROR; } - ret = dsdb_module_modify(module, msg, 0); + ret = dsdb_check_single_valued_link(attr, old_el); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX); if (ret != LDB_SUCCESS) { - ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s' %s\n", + ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n", ldb_errstring(ldb), ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg)); talloc_free(tmp_ctx); -- cgit From bf8ccd21f1f421f8d76f4882f2c3df8d429413b7 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 00:10:40 +1100 Subject: s4-dsdb: fill in the correct version number of links that come over DRS --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 53 +++++++++++++------------ 1 file changed, 27 insertions(+), 26 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index d3a7e3791c..bf4a55054a 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -581,7 +581,7 @@ static void replmd_ldb_message_sort(struct ldb_message *msg, static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, const struct GUID *invocation_id, uint64_t seq_num, - uint64_t local_usn, NTTIME nttime, bool deleted); + uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted); /* @@ -609,7 +609,7 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme int ret; ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, - seq_num, seq_num, now, false); + seq_num, seq_num, now, 0, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1188,7 +1188,7 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, */ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, const struct GUID *invocation_id, uint64_t seq_num, - uint64_t local_usn, NTTIME nttime, bool deleted) + uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; const char *tstring, *usn_string; @@ -1199,6 +1199,7 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds NTSTATUS status; int ret; const char *dnstring; + char *vstring; tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { @@ -1218,7 +1219,8 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds } local_usnv = data_blob_string_const(usn_string); - vers = data_blob_string_const("0"); + vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version); + vers = data_blob_string_const(vstring); status = GUID_to_ndr_blob(invocation_id, dn, &iid); if (!NT_STATUS_IS_OK(status)) { @@ -1257,7 +1259,8 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id, - uint64_t seq_num, uint64_t local_usn, NTTIME nttime, bool deleted); + uint64_t seq_num, uint64_t local_usn, NTTIME nttime, + uint32_t version, bool deleted); /* check if any links need upgrading from w2k format @@ -1277,7 +1280,7 @@ static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, con /* it's an old one that needs upgrading */ ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id, - 1, 1, 0, false); + 1, 1, 0, 0, false); if (ret != LDB_SUCCESS) { return ret; } @@ -1292,7 +1295,8 @@ static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, con */ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn, struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id, - uint64_t seq_num, uint64_t local_usn, NTTIME nttime, bool deleted) + uint64_t seq_num, uint64_t local_usn, NTTIME nttime, + uint32_t version, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; const char *tstring, *usn_string; @@ -1300,10 +1304,12 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d struct ldb_val iid; struct ldb_val usnv, local_usnv; struct ldb_val vers; - const struct ldb_val *old_addtime, *old_version; + const struct ldb_val *old_addtime; + uint32_t old_version; NTSTATUS status; int ret; const char *dnstring; + char *vstring; tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { @@ -1363,19 +1369,12 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d if (ret != LDB_SUCCESS) return ret; /* increase the version by 1 */ - old_version = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_VERSION"); - if (old_version == NULL) { - vers = data_blob_string_const("0"); - } else { - char *vstring; - vstring = talloc_strndup(dn, (const char *)old_version->data, old_version->length); - if (!vstring) { - return LDB_ERR_OPERATIONS_ERROR; - } - vstring = talloc_asprintf(dn, "%lu", - (unsigned long)strtoul(vstring, NULL, 0)+1); - vers = data_blob_string_const(vstring); + status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION"); + if (NT_STATUS_IS_OK(status) && old_version >= version) { + version = old_version+1; } + vstring = talloc_asprintf(dn, "%lu", (unsigned long)version); + vers = data_blob_string_const(vstring); ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers); if (ret != LDB_SUCCESS) return ret; @@ -1450,7 +1449,7 @@ static int replmd_modify_la_add(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, - invocation_id, seq_num, seq_num, now, false); + invocation_id, seq_num, seq_num, now, 0, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1468,7 +1467,7 @@ static int replmd_modify_la_add(struct ldb_module *module, return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS; } ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn, - invocation_id, seq_num, seq_num, now, false); + invocation_id, seq_num, seq_num, now, 0, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1601,7 +1600,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, if (v != NULL) continue; ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn, - invocation_id, seq_num, seq_num, now, true); + invocation_id, seq_num, seq_num, now, 0, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1703,7 +1702,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, } ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, - invocation_id, seq_num, seq_num, now, true); + invocation_id, seq_num, seq_num, now, 0, true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1722,7 +1721,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, /* update in place */ ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, invocation_id, - seq_num, seq_num, now, false); + seq_num, seq_num, now, 0, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -1737,7 +1736,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, return LDB_ERR_OPERATIONS_ERROR; } ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn, - invocation_id, seq_num, seq_num, now, false); + invocation_id, seq_num, seq_num, now, 0, false); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -3504,6 +3503,7 @@ linked_attributes[0]: &la->meta_data.originating_invocation_id, la->meta_data.originating_usn, seq_num, la->meta_data.originating_change_time, + la->meta_data.version, !active); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); @@ -3538,6 +3538,7 @@ linked_attributes[0]: &la->meta_data.originating_invocation_id, la->meta_data.originating_usn, seq_num, la->meta_data.originating_change_time, + la->meta_data.version, (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); -- cgit From dd33a22f1de513277ed1182f70eb81f16eaab543 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sun, 20 Dec 2009 11:53:09 +1100 Subject: s4-dsdb: use a common method for finding a link pair Use ^1 everywhere, to ensure it works for both forward and backward links --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index bf4a55054a..87868354a9 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -216,7 +216,7 @@ static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_sche struct replmd_private *replmd_private = talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private); - target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID + 1); + target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1); if (!target_attr) { /* * windows 2003 has a broken schema where the -- cgit From ca5c3a0a02b18787c089c4f32807d4cdf59578df Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 20:59:08 +1100 Subject: s4-dsdb: added DSDB_FLAG_OWN_MODULE This allows you to call dsdb_module_*() functions while including the current module in the module stack to be used Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/util.c | 52 +++++++++++++++++++++++++++++++++-- source4/dsdb/samdb/ldb_modules/util.h | 1 + 2 files changed, 50 insertions(+), 3 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/util.c b/source4/dsdb/samdb/ldb_modules/util.c index fa451f4bcf..32b79a6701 100644 --- a/source4/dsdb/samdb/ldb_modules/util.c +++ b/source4/dsdb/samdb/ldb_modules/util.c @@ -211,7 +211,12 @@ int dsdb_module_search(struct ldb_module *module, return ret; } - ret = ldb_next_request(module, req); + if (dsdb_flags & DSDB_FLAG_OWN_MODULE) { + const struct ldb_module_ops *ops = ldb_module_get_ops(module); + ret = ops->search(module, req); + } else { + ret = ldb_next_request(module, req); + } if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } @@ -262,6 +267,37 @@ int dsdb_module_dn_by_guid(struct ldb_module *module, TALLOC_CTX *mem_ctx, return LDB_SUCCESS; } +/* + find a GUID given a DN. + */ +int dsdb_module_guid_by_dn(struct ldb_module *module, struct ldb_dn *dn, struct GUID *guid) +{ + const char *attrs[] = { NULL }; + struct ldb_result *res; + TALLOC_CTX *tmp_ctx = talloc_new(module); + int ret; + NTSTATUS status; + + ret = dsdb_module_search_dn(module, tmp_ctx, &res, dn, attrs, + DSDB_SEARCH_SHOW_DELETED| + DSDB_SEARCH_SHOW_EXTENDED_DN); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to find GUID for %s", + ldb_dn_get_linearized(dn)); + talloc_free(tmp_ctx); + return ret; + } + + status = dsdb_get_extended_dn_guid(res->msgs[0]->dn, guid, "GUID"); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return LDB_ERR_OPERATIONS_ERROR; + } + + talloc_free(tmp_ctx); + return LDB_SUCCESS; +} + /* a ldb_modify request operating on modules below the current module @@ -293,7 +329,12 @@ int dsdb_module_modify(struct ldb_module *module, } /* Run the new request */ - ret = ldb_next_request(module, mod_req); + if (dsdb_flags & DSDB_FLAG_OWN_MODULE) { + const struct ldb_module_ops *ops = ldb_module_get_ops(module); + ret = ops->modify(module, mod_req); + } else { + ret = ldb_next_request(module, mod_req); + } if (ret == LDB_SUCCESS) { ret = ldb_wait(mod_req->handle, LDB_WAIT_ALL); } @@ -336,7 +377,12 @@ int dsdb_module_rename(struct ldb_module *module, } /* Run the new request */ - ret = ldb_next_request(module, req); + if (dsdb_flags & DSDB_FLAG_OWN_MODULE) { + const struct ldb_module_ops *ops = ldb_module_get_ops(module); + ret = ops->rename(module, req); + } else { + ret = ldb_next_request(module, req); + } if (ret == LDB_SUCCESS) { ret = ldb_wait(req->handle, LDB_WAIT_ALL); } diff --git a/source4/dsdb/samdb/ldb_modules/util.h b/source4/dsdb/samdb/ldb_modules/util.h index 66579ab852..add39e110a 100644 --- a/source4/dsdb/samdb/ldb_modules/util.h +++ b/source4/dsdb/samdb/ldb_modules/util.h @@ -31,3 +31,4 @@ struct dsdb_attribute; #define DSDB_SEARCH_REVEAL_INTERNALS 0x0008 #define DSDB_SEARCH_SHOW_EXTENDED_DN 0x0010 #define DSDB_MODIFY_RELAX 0x0020 +#define DSDB_FLAG_OWN_MODULE 0x0040 -- cgit From d4853fed00a9f5e6e5eee5dc1ce0eab3cd9bda37 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 20:59:57 +1100 Subject: sd-schema: order DRS classes on the wire in reverse order windows sends objectclasses in DRS in the opposite order to what LDAP uses --- source4/dsdb/schema/schema_syntax.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c index e958605707..0873779811 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -735,7 +735,10 @@ static WERROR _dsdb_syntax_OID_obj_ldb_to_drsuapi(struct ldb_context *ldb, blobs[i] = data_blob_talloc(blobs, NULL, 4); W_ERROR_HAVE_NO_MEMORY(blobs[i].data); - obj_class = dsdb_class_by_lDAPDisplayName(schema, (const char *)in->values[i].data); + /* in DRS windows puts the classes in the opposite + order to the order used in ldap */ + obj_class = dsdb_class_by_lDAPDisplayName(schema, + (const char *)in->values[(in->num_values-1)-i].data); if (!obj_class) { return WERR_FOOBAR; } -- cgit From 9f02898080f5a19930d9adfcce3cf4139e3952e9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:01:33 +1100 Subject: s4-schema: don't fill in the extended DN with a zero GUID sometimes windows sends us a zero GUID in a DRS DN. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/schema/schema_syntax.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c index 0873779811..843b65d59d 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -1077,20 +1077,21 @@ WERROR dsdb_syntax_one_DN_drsuapi_to_ldb(TALLOC_CTX *mem_ctx, struct ldb_context W_ERROR_HAVE_NO_MEMORY(dn); } - status = GUID_to_ndr_blob(&id3.guid, tmp_ctx, &guid_blob); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return ntstatus_to_werror(status); - } + if (!GUID_all_zero(&id3.guid)) { + status = GUID_to_ndr_blob(&id3.guid, tmp_ctx, &guid_blob); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return ntstatus_to_werror(status); + } - ret = ldb_dn_set_extended_component(dn, "GUID", &guid_blob); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return WERR_FOOBAR; + ret = ldb_dn_set_extended_component(dn, "GUID", &guid_blob); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return WERR_FOOBAR; + } + talloc_free(guid_blob.data); } - talloc_free(guid_blob.data); - if (id3.__ndr_size_sid) { DATA_BLOB sid_blob; ndr_err = ndr_push_struct_blob(&sid_blob, tmp_ctx, iconv_convenience, &id3.sid, -- cgit From 0d5d7f58473c989bff4d7f7d65da31f9b037de3a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:18:31 +1100 Subject: s4-drs: treat a zero GUID as not present in replmd_add_fix_la Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 87868354a9..6e0c9b44e5 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -618,9 +618,12 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme /* note that the DN already has the extended components from the extended_dn_store module */ status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID"); - if (!NT_STATUS_IS_OK(status)) { - talloc_free(tmp_ctx); - return LDB_ERR_OPERATIONS_ERROR; + if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) { + ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } } ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false); -- cgit From 2e114484e5abd658b9a8ae1ecb1af6768bd8fc46 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:19:55 +1100 Subject: s4-drs: give an error message in repl_meta_data if we don't get a partition control --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 1 + 1 file changed, 1 insertion(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 6e0c9b44e5..6804c1c764 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -318,6 +318,7 @@ static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares) } if (!partition_ctrl) { + ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply"); return ldb_module_done(ac->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR); } -- cgit From e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:21:55 +1100 Subject: s4-drs: cope better with NULL GUIDS from DRS It is valid to get a NULL GUID over DRS for a deleted forward link. We need to match by DN if possible when seeing if we should update an existing link. Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 36 +++++++++++++++++-------- 1 file changed, 25 insertions(+), 11 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 6804c1c764..8603e1c3dd 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1107,9 +1107,21 @@ static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2) return GUID_compare(pdn1->guid, pdn2->guid); } -static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid) +static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid, struct ldb_dn *dn) { struct parsed_dn *ret; + if (dn && GUID_all_zero(guid)) { + /* when updating a link using DRS, we sometimes get a + NULL GUID. We then need to try and match by DN */ + int i; + for (i=0; idn, dn) == 0) { + dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID"); + return &pdn[i]; + } + } + return NULL; + } BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret); return ret; } @@ -1443,7 +1455,7 @@ static int replmd_modify_la_add(struct ldb_module *module, /* for each new value, see if it exists already with the same GUID */ for (i=0; inum_values; i++) { - struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid); + struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL); if (p == NULL) { /* this is a new linked attribute value */ new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1); @@ -1575,7 +1587,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, struct parsed_dn *p2; const struct ldb_val *v; - p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid); + p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL); if (!p2) { ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s", el->name, GUID_string(tmp_ctx, p->guid)); @@ -1596,7 +1608,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, struct parsed_dn *p = &old_dns[i]; const struct ldb_val *v; - if (dns && parsed_dn_find(dns, el->num_values, p->guid) == NULL) { + if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) { continue; } @@ -1699,7 +1711,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, return ret; } - p = parsed_dn_find(dns, el->num_values, old_p->guid); + p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL); if (p) { /* we don't delete it if we are re-adding it */ continue; @@ -1721,7 +1733,7 @@ static int replmd_modify_la_replace(struct ldb_module *module, if (old_dns && (old_p = parsed_dn_find(old_dns, - old_num_values, p->guid)) != NULL) { + old_num_values, p->guid, NULL)) != NULL) { /* update in place */ ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn, invocation_id, @@ -3325,7 +3337,7 @@ static int replmd_process_linked_attribute(struct ldb_module *module, struct ldb_result *res; const char *attrs[2]; struct parsed_dn *pdn_list, *pdn; - struct GUID guid; + struct GUID guid = GUID_zero(); NTSTATUS ntstatus; bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false; const struct GUID *our_invocation_id; @@ -3455,14 +3467,16 @@ linked_attributes[0]: } ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID"); - if (!NT_STATUS_IS_OK(ntstatus)) { - ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s\n", - old_el->name, ldb_dn_get_linearized(msg->dn)); + if (!NT_STATUS_IS_OK(ntstatus) && active) { + ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s", + old_el->name, + ldb_dn_get_linearized(dsdb_dn->dn), + ldb_dn_get_linearized(msg->dn)); return LDB_ERR_OPERATIONS_ERROR; } /* see if this link already exists */ - pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid); + pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn); if (pdn != NULL) { /* see if this update is newer than what we have already */ struct GUID invocation_id = GUID_zero(); -- cgit From 7a39340c8ecf4ac9475ae91f721dc979b19c030d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:23:18 +1100 Subject: s4-drs: use dsdb_module_guid_by_dn() We should not be going to the top of the module stack --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 8603e1c3dd..4f3ce01cd0 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1172,7 +1172,7 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID"); if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { /* we got a DN without a GUID - go find the GUID */ - int ret = dsdb_find_guid_by_dn(ldb, dn, p->guid); + int ret = dsdb_module_guid_by_dn(module, dn, p->guid); if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n", ldb_dn_get_linearized(dn)); -- cgit From 5b31cb20dd49622fa761fd4ae1869bcc0de0330d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:24:18 +1100 Subject: s4-drs: fixed typo for uSNCreated This broke DRS replication from samba to windows Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 4f3ce01cd0..ba9a9bf3a9 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2192,7 +2192,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid", "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName", "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection", - "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreate", + "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated", NULL}; uint32_t el_count = 0; int i; -- cgit From 9572535940e808d4dd681ee01b04ad589c7e73c9 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:25:27 +1100 Subject: s4-drs: update comment to refect only forward link in this fn This function only update forward links Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index ba9a9bf3a9..ed0a96b14f 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2088,8 +2088,10 @@ static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *are return ldb_next_request(ac->module, down_req); } -/* remove forwards and backlinks as needed when an object - is deleted */ +/* + remove links from objects that point at this object when an object + is deleted + */ static int replmd_delete_remove_link(struct ldb_module *module, struct dsdb_schema *schema, struct ldb_dn *dn, -- cgit From 530503290d029894d3b0f0bc4f3c058752e904fb Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:26:15 +1100 Subject: s4-drs: use DSDB_FLAG_OWN_MODULE We need DRS driven replication changes to update replPropertyMetaData, so it needs to call into the repl_meta_data module logic Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index ed0a96b14f..ae7dcc1954 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2154,7 +2154,7 @@ static int replmd_delete_remove_link(struct ldb_module *module, el2->values = &dn_val; el2->num_values = 1; - ret = dsdb_module_modify(module, msg, 0); + ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return ret; @@ -2354,8 +2354,8 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) el->flags = LDB_FLAG_MOD_REPLACE; } - ret = dsdb_module_modify(module, msg, 0); - if (ret != LDB_SUCCESS){ + ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE); + if (ret != LDB_SUCCESS) { ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s", ldb_dn_get_linearized(old_dn), ldb_errstring(ldb)); talloc_free(tmp_ctx); -- cgit From 0bf7f952735e848700122c9ced064d211831ba7c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:27:16 +1100 Subject: s4-drs: isRecycled only exists in FL W2K8-R2 Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index ae7dcc1954..9994b9566d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2280,6 +2280,19 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) } msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD; + /* we also mark it as recycled, meaning this object can't be + recovered (we are stripping its attributes) */ + if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) { + ret = ldb_msg_add_string(msg, "isRecycled", "TRUE"); + if (ret != LDB_SUCCESS) { + DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n")); + ldb_module_oom(module); + talloc_free(tmp_ctx); + return ret; + } + msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD; + } + /* we need the storage form of the parent GUID */ ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res, ldb_dn_get_parent(tmp_ctx, old_dn), NULL, -- cgit From 9f053d43ded23bb72d4c10162a8c6a211831b068 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 21 Dec 2009 21:28:04 +1100 Subject: s4-drs: don't try to remove backlinks directly backlinks need to be removed as a side effect of removing the forward link Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 9994b9566d..5bf43857cc 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2327,12 +2327,13 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) continue; } - if (sa->linkID) { + if (sa->linkID && sa->linkID & 1) { ret = replmd_delete_remove_link(module, schema, old_dn, el, sa); if (ret != LDB_SUCCESS) { talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } + continue; } if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) { -- cgit From db3f0e8ec1bfc6d3f27195ee38f53489501e731e Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 22 Dec 2009 12:21:02 +1100 Subject: s4-dsdb: fixed valgrind error in replmd modify We are using the values from a search result, so we need to steal them onto the msg before we free the search results Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 5bf43857cc..3c713ec4d9 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1880,7 +1880,7 @@ static int replmd_modify_handle_linked_attribs(struct ldb_module *module, } ldb_msg_add_empty(old_msg, el->name, 0, &new_el); new_el->num_values = el->num_values; - new_el->values = el->values; + new_el->values = talloc_steal(msg->elements, el->values); /* TODO: this relises a bit too heavily on the exact behaviour of ldb_msg_find_element and -- cgit From 5e52c7149fb6f4e79541cde719f7f014d8954922 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 28 Dec 2009 17:18:14 +1100 Subject: s4-dsdb: added parse functions for DRS linked attribute blobs --- source4/dsdb/common/dsdb_dn.c | 69 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/dsdb_dn.c b/source4/dsdb/common/dsdb_dn.c index 660eaf7d40..9023b0347a 100644 --- a/source4/dsdb/common/dsdb_dn.c +++ b/source4/dsdb/common/dsdb_dn.c @@ -325,3 +325,72 @@ int dsdb_dn_string_comparison(struct ldb_context *ldb, void *mem_ctx, { return ldb_any_comparison(ldb, mem_ctx, dsdb_dn_string_canonicalise, v1, v2); } + + +/* + convert a dsdb_dn to a linked attribute data blob +*/ +WERROR dsdb_dn_la_to_blob(struct ldb_context *sam_ctx, + const struct dsdb_attribute *schema_attrib, + const struct dsdb_schema *schema, + TALLOC_CTX *mem_ctx, + struct dsdb_dn *dsdb_dn, DATA_BLOB **blob) +{ + struct ldb_val v; + WERROR werr; + struct ldb_message_element val_el; + struct drsuapi_DsReplicaAttribute drs; + + /* we need a message_element with just one value in it */ + v = data_blob_string_const(dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1)); + + val_el.name = schema_attrib->lDAPDisplayName; + val_el.values = &v; + val_el.num_values = 1; + + werr = schema_attrib->syntax->ldb_to_drsuapi(sam_ctx, schema, schema_attrib, &val_el, mem_ctx, &drs); + W_ERROR_NOT_OK_RETURN(werr); + + if (drs.value_ctr.num_values != 1) { + DEBUG(1,(__location__ ": Failed to build DRS blob for linked attribute %s\n", + schema_attrib->lDAPDisplayName)); + return WERR_DS_DRA_INTERNAL_ERROR; + } + + *blob = drs.value_ctr.values[0].blob; + return WERR_OK; +} + +/* + convert a data blob to a dsdb_dn + */ +WERROR dsdb_dn_la_from_blob(struct ldb_context *sam_ctx, + const struct dsdb_attribute *schema_attrib, + const struct dsdb_schema *schema, + TALLOC_CTX *mem_ctx, + DATA_BLOB *blob, + struct dsdb_dn **dsdb_dn) +{ + WERROR werr; + struct ldb_message_element new_el; + struct drsuapi_DsReplicaAttribute drs; + struct drsuapi_DsAttributeValue val; + + drs.value_ctr.num_values = 1; + drs.value_ctr.values = &val; + val.blob = blob; + + werr = schema_attrib->syntax->drsuapi_to_ldb(sam_ctx, schema, schema_attrib, &drs, mem_ctx, &new_el); + W_ERROR_NOT_OK_RETURN(werr); + + if (new_el.num_values != 1) { + return WERR_INTERNAL_ERROR; + } + + *dsdb_dn = dsdb_dn_parse(mem_ctx, sam_ctx, &new_el.values[0], schema_attrib->syntax->ldap_oid); + if (!*dsdb_dn) { + return WERR_INTERNAL_ERROR; + } + + return WERR_OK; +} -- cgit From 38160deac4d6f4a8ae22fcedcf55114bc0372f31 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 28 Dec 2009 17:19:29 +1100 Subject: s4-drs: use dsdb linked attribute parse functions This makes the code considerably more readable --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 27 ++++--------------------- 1 file changed, 4 insertions(+), 23 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 3c713ec4d9..baae44a30d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -3345,9 +3345,7 @@ static int replmd_process_linked_attribute(struct ldb_module *module, const struct dsdb_attribute *attr; struct dsdb_dn *dsdb_dn; uint64_t seq_num = 0; - struct drsuapi_DsReplicaAttribute drs; - struct drsuapi_DsAttributeValue val; - struct ldb_message_element new_el, *old_el; + struct ldb_message_element *old_el; WERROR status; time_t t = time(NULL); struct ldb_result *res; @@ -3358,10 +3356,6 @@ static int replmd_process_linked_attribute(struct ldb_module *module, bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false; const struct GUID *our_invocation_id; - drs.value_ctr.num_values = 1; - drs.value_ctr.values = &val; - val.blob = la->value.blob; - /* linked_attributes[0]: &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute @@ -3462,23 +3456,10 @@ linked_attributes[0]: return ret; } - status = attr->syntax->drsuapi_to_ldb(ldb, schema, attr, &drs, tmp_ctx, &new_el); + status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn); if (!W_ERROR_IS_OK(status)) { - ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s\n", - old_el->name, ldb_dn_get_linearized(msg->dn)); - return LDB_ERR_OPERATIONS_ERROR; - } - - if (new_el.num_values != 1) { - ldb_asprintf_errstring(ldb, "Failed to find value in linked attribute blob for %s on %s\n", - old_el->name, ldb_dn_get_linearized(msg->dn)); - return LDB_ERR_OPERATIONS_ERROR; - } - - dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &new_el.values[0], attr->syntax->ldap_oid); - if (!dsdb_dn) { - ldb_asprintf_errstring(ldb, "Failed to parse DN in linked attribute blob for %s on %s\n", - old_el->name, ldb_dn_get_linearized(msg->dn)); + ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n", + old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status)); return LDB_ERR_OPERATIONS_ERROR; } -- cgit From 5dd6e089f136d3ce04127b930da59913704bf083 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 28 Dec 2009 17:20:13 +1100 Subject: s4-drs: use dsdb_module_rename() Use the new dsdb_module_rename() for DRS rename handling, instead of ldb_rename(). This stops us going to the top of the module stack on a rename. --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index baae44a30d..b9d9a744f1 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -2571,10 +2571,9 @@ static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar) ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n", ldb_dn_get_linearized(ar->search_msg->dn), ldb_dn_get_linearized(msg->dn)); - /* we can't use dsdb_module_rename() here as we need - the rename call to be intercepted by this module, to - allow it to process linked attribute changes */ - if (ldb_rename(ldb, ar->search_msg->dn, msg->dn) != LDB_SUCCESS) { + if (dsdb_module_rename(ar->module, + ar->search_msg->dn, msg->dn, + DSDB_FLAG_OWN_MODULE) != LDB_SUCCESS) { ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n", ldb_dn_get_linearized(ar->search_msg->dn), ldb_dn_get_linearized(msg->dn), -- cgit From d48237d547470e064b7f5fb464758e7e9eaae17d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 28 Dec 2009 17:22:12 +1100 Subject: s4-drs: re-resolve the DN in linked attribute processing w2k8-r2 sometimes sends the DN with an old target --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index b9d9a744f1..991d8c314d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -3471,6 +3471,16 @@ linked_attributes[0]: return LDB_ERR_OPERATIONS_ERROR; } + /* re-resolve the DN by GUID, as the DRS server may give us an + old DN value */ + ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn); + if (ret != LDB_SUCCESS) { + ldb_asprintf_errstring(ldb, __location__ ": Failed to re-resolve GUID %s", + GUID_string(tmp_ctx, &guid)); + talloc_free(tmp_ctx); + return ret; + } + /* see if this link already exists */ pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn); if (pdn != NULL) { -- cgit From c3061794ef4d03d5b26d4a221a93722b3ed08197 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 29 Dec 2009 11:37:17 +1100 Subject: s4-dsdb: use ldb_val_to_time() instead of ldb_string_to_time() --- source4/dsdb/samdb/ldb_modules/simple_ldap_map.c | 6 +++--- source4/dsdb/schema/schema_syntax.c | 6 +++++- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c index 43402248c0..bf9cd4fdda 100644 --- a/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c +++ b/source4/dsdb/samdb/ldb_modules/simple_ldap_map.c @@ -181,7 +181,7 @@ static struct ldb_val usn_to_entryCSN(struct ldb_module *module, TALLOC_CTX *ctx static unsigned long long entryCSN_to_usn_int(TALLOC_CTX *ctx, const struct ldb_val *val) { - char *entryCSN = talloc_strdup(ctx, (const char *)val->data); + char *entryCSN = talloc_strndup(ctx, (const char *)val->data, val->length); char *mod_per_sec; time_t t; unsigned long long usn; @@ -232,10 +232,10 @@ static struct ldb_val usn_to_timestamp(struct ldb_module *module, TALLOC_CTX *ct static struct ldb_val timestamp_to_usn(struct ldb_module *module, TALLOC_CTX *ctx, const struct ldb_val *val) { struct ldb_val out; - time_t t; + time_t t=0; unsigned long long usn; - t = ldb_string_to_time((const char *)val->data); + ldb_val_to_time(val, &t); usn = ((unsigned long long)t <<24); diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c index 843b65d59d..de52b9c628 100644 --- a/source4/dsdb/schema/schema_syntax.c +++ b/source4/dsdb/schema/schema_syntax.c @@ -488,13 +488,17 @@ static WERROR dsdb_syntax_NTTIME_ldb_to_drsuapi(struct ldb_context *ldb, for (i=0; i < in->num_values; i++) { NTTIME v; time_t t; + int ret; out->value_ctr.values[i].blob = &blobs[i]; blobs[i] = data_blob_talloc(blobs, NULL, 8); W_ERROR_HAVE_NO_MEMORY(blobs[i].data); - t = ldb_string_to_time((const char *)in->values[i].data); + ret = ldb_val_to_time(&in->values[i], &t); + if (ret != LDB_SUCCESS) { + return WERR_DS_INVALID_ATTRIBUTE_SYNTAX; + } unix_to_nt_time(&v, t); v /= 10000000; -- cgit From 6628588dfba353c3d2948d14de2d24edfafc371d Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 10:52:14 +1100 Subject: s4-dsdb: added dsdb_set_extended_dn_guid() --- source4/dsdb/common/util.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index ef47079f9f..25d915d0bc 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2794,6 +2794,25 @@ int dsdb_functional_level(struct ldb_context *ldb) return *domainFunctionality; } +/* + set a GUID in an extended DN structure + */ +int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name) +{ + struct ldb_val v; + NTSTATUS status; + int ret; + + status = GUID_to_ndr_blob(guid, dn, &v); + if (!NT_STATUS_IS_OK(status)) { + return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX; + } + + ret = ldb_dn_set_extended_component(dn, component_name, &v); + data_blob_free(&v); + return ret; +} + /* return a GUID from a extended DN structure */ -- cgit From 4eecfc80bc7f305cc6c57ebc2a56f2aa354a522f Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 10:52:55 +1100 Subject: s4-drs: make sure the DNs we put in the db have a extended GUID --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 991d8c314d..f12b62c14b 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -609,13 +609,6 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme NTSTATUS status; int ret; - ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, - seq_num, seq_num, now, 0, false); - if (ret != LDB_SUCCESS) { - talloc_free(tmp_ctx); - return ret; - } - /* note that the DN already has the extended components from the extended_dn_store module */ status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID"); @@ -625,6 +618,18 @@ static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_eleme talloc_free(tmp_ctx); return ret; } + ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID"); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + } + + ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId, + seq_num, seq_num, now, 0, false); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; } ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false); @@ -1178,6 +1183,10 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, ldb_dn_get_linearized(dn)); return ret; } + ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID"); + if (ret != LDB_SUCCESS) { + return ret; + } } else if (!NT_STATUS_IS_OK(status)) { return LDB_ERR_OPERATIONS_ERROR; } -- cgit From 23eb9f49a75f599a78d2f70fb4b864f1e0c6e0a1 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 18:47:51 +1100 Subject: s4-dsdb: allow system to remove deleted objects This will be used by a periodic job to remove tombstoned objects --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index f12b62c14b..ab412942e9 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -47,6 +47,7 @@ #include "lib/util/dlinklist.h" #include "dsdb/samdb/ldb_modules/util.h" #include "lib/util/binsearch.h" +#include "libcli/security/security.h" #define W2K3_LINKED_ATTRIBUTES 1 @@ -2208,6 +2209,10 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) uint32_t el_count = 0; int i; + if (ldb_dn_is_special(req->op.del.dn)) { + return ldb_next_request(module, req); + } + tmp_ctx = talloc_new(ldb); old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn); @@ -2224,6 +2229,20 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) } old_msg = res->msgs[0]; + if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) { + struct auth_session_info *session_info = + (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo"); + if (security_session_user_level(session_info) != 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; + } + + /* it is already deleted - really remove it this time */ + talloc_free(tmp_ctx); + return ldb_next_request(module, req); + } + /* work out where we will be renaming this object to */ ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn); if (ret != LDB_SUCCESS) { -- cgit From 9819d280d69e5870d61a177923912eae0c573709 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 20:04:17 +1100 Subject: s4-dsdb: added dsdb_tombstone_lifetime() --- source4/dsdb/common/util.c | 26 +++++++++++++++++ source4/dsdb/kcc/kcc_deleted.c | 64 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 source4/dsdb/kcc/kcc_deleted.c (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 25d915d0bc..ea216ec67b 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -3024,3 +3024,29 @@ int dsdb_get_deleted_objects_dn(struct ldb_context *ldb, talloc_free(nc_root); return ret; } + +/* + return the tombstoneLifetime, in days + */ +int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime) +{ + struct ldb_dn *dn; + dn = samdb_config_dn(ldb); + if (!dn) { + return LDB_ERR_NO_SUCH_OBJECT; + } + dn = ldb_dn_copy(ldb, dn); + if (!dn) { + return LDB_ERR_OPERATIONS_ERROR; + } + /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to + be a wellknown GUID for this */ + if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT")) { + talloc_free(dn); + return LDB_ERR_OPERATIONS_ERROR; + } + + *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService"); + talloc_free(dn); + return LDB_SUCCESS; +} diff --git a/source4/dsdb/kcc/kcc_deleted.c b/source4/dsdb/kcc/kcc_deleted.c new file mode 100644 index 0000000000..44f3070261 --- /dev/null +++ b/source4/dsdb/kcc/kcc_deleted.c @@ -0,0 +1,64 @@ +/* + Unix SMB/CIFS implementation. + + handle removal of deleted objects + + Copyright (C) 2009 Andrew Tridgell + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +*/ + +#include "includes.h" +#include "lib/events/events.h" +#include "dsdb/samdb/samdb.h" +#include "auth/auth.h" +#include "smbd/service.h" +#include "lib/messaging/irpc.h" +#include "dsdb/kcc/kcc_connection.h" +#include "dsdb/kcc/kcc_service.h" +#include "lib/ldb/include/ldb_errors.h" +#include "../lib/util/dlinklist.h" +#include "librpc/gen_ndr/ndr_misc.h" +#include "librpc/gen_ndr/ndr_drsuapi.h" +#include "librpc/gen_ndr/ndr_drsblobs.h" +#include "param/param.h" + + +/* + check to see if any deleted objects need scavenging + */ +NTSTATUS kccsrv_check_deleted(struct kccsrv_service *s, TALLOC_CTX *mem_ctx) +{ + struct kccsrv_partition *part; + int ret; + + time_t t = time(NULL); + if (t - s->last_deleted_check < lp_parm_int(task->lp_ctx, NULL, "kccsrv", + "check_deleted_interval", 600)) { + return NT_STATUS_OK; + } + s->last_deleted_check = t; + + for (part=s->partitions; part; part=part->next) { + struct ldb_dn *do_dn; + struct ldb_result *res; + + ret = dsdb_get_deleted_objects_dn(s->samdb, mem_ctx, part->dn, &do_dn); + ret = ldb_search(s->samdb, mem_ctx, &res, do_dn, LDB_SCOPE_SUBTREE, + attrs, "isDeleted=TRUE"); + } + + +} -- cgit From 8eaed073a7c60986ecd02c3cc4beb53bd66772c6 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 20:05:02 +1100 Subject: s4-dsdb: make sure 'whenChanged' is set on modify We also should preserve (and then replace) whenChanged on delete --- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index ab412942e9..202b74e8b4 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1939,6 +1939,9 @@ static int replmd_modify(struct ldb_module *module, struct ldb_request *req) return LDB_ERR_OPERATIONS_ERROR; } + ldb_msg_remove_attr(msg, "whenChanged"); + ldb_msg_remove_attr(msg, "uSNChanged"); + ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t); if (ret != LDB_SUCCESS) { talloc_free(ac); @@ -2205,7 +2208,7 @@ static int replmd_delete(struct ldb_module *module, struct ldb_request *req) "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName", "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection", "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated", - NULL}; + "whenChanged", NULL}; uint32_t el_count = 0; int i; -- cgit From 031460b8a228ced18381ca35379aa4ea02a3f764 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 21:38:21 +1100 Subject: s4-dsdb: fixed samdb_create_foreign_security_principal() to use the wellknown GUID This also fixes a memory leak --- source4/dsdb/common/util.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index ea216ec67b..35f5c80f06 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2061,7 +2061,7 @@ NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TA { struct ldb_message *msg; struct ldb_dn *basedn; - const char *sidstr; + char *sidstr; int ret; sidstr = dom_sid_string(mem_ctx, sid); @@ -2070,45 +2070,47 @@ NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TA /* We might have to create a ForeignSecurityPrincipal, even if this user * is in our own domain */ - msg = ldb_msg_new(mem_ctx); + msg = ldb_msg_new(sidstr); if (msg == NULL) { + talloc_free(sidstr); return NT_STATUS_NO_MEMORY; } - /* TODO: Hmmm. This feels wrong. How do I find the base dn to - * put the ForeignSecurityPrincipals? d_state->domain_dn does - * not work, this is wrong for the Builtin domain, there's no - * cn=For...,cn=Builtin,dc={BASEDN}. -- vl - */ - - basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL, - "(&(objectClass=container)(cn=ForeignSecurityPrincipals))"); - - if (basedn == NULL) { + ret = dsdb_wellknown_dn(sam_ctx, sidstr, samdb_base_dn(sam_ctx), + DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER, + &basedn); + if (ret != LDB_SUCCESS) { DEBUG(0, ("Failed to find DN for " - "ForeignSecurityPrincipal container\n")); + "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx))); + talloc_free(sidstr); return NT_STATUS_INTERNAL_DB_CORRUPTION; } /* add core elements to the ldb_message for the alias */ - msg->dn = ldb_dn_copy(mem_ctx, basedn); - if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) + msg->dn = basedn; + if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) { + talloc_free(sidstr); return NT_STATUS_NO_MEMORY; + } - samdb_msg_add_string(sam_ctx, mem_ctx, msg, + samdb_msg_add_string(sam_ctx, msg, msg, "objectClass", "foreignSecurityPrincipal"); /* create the alias */ ret = ldb_add(sam_ctx, msg); - if (ret != 0) { + if (ret != LDB_SUCCESS) { DEBUG(0,("Failed to create foreignSecurityPrincipal " "record %s: %s\n", ldb_dn_get_linearized(msg->dn), ldb_errstring(sam_ctx))); + talloc_free(sidstr); return NT_STATUS_INTERNAL_DB_CORRUPTION; } - *ret_dn = msg->dn; + + *ret_dn = talloc_steal(mem_ctx, msg->dn); + talloc_free(sidstr); + return NT_STATUS_OK; } -- cgit From 08bad380351e9753adc4330beb06dd2929113cfc Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 21:39:24 +1100 Subject: s4-dsdb: fixed several memory leaks need to be careful with those temporary contexts --- source4/dsdb/common/util.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 35f5c80f06..5d9ec1182f 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2149,14 +2149,16 @@ struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_c if (!ldb_dn_validate(dn)) { DEBUG(2, ("Failed to validated DN %s\n", ldb_dn_get_linearized(dn))); + talloc_free(tmp_ctx); return NULL; } + talloc_free(tmp_ctx); return dn; } + /* Find the DN of a domain, be it the netbios or DNS name */ - struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *domain_name) { @@ -2228,13 +2230,14 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb, return LDB_ERR_OPERATIONS_ERROR; } - res = talloc_zero(mem_ctx, struct ldb_result); + res = talloc_zero(expression, struct ldb_result); if (!res) { DEBUG(0, (__location__ ": out of memory\n")); + talloc_free(expression); return LDB_ERR_OPERATIONS_ERROR; } - ret = ldb_build_search_req(&search_req, ldb, mem_ctx, + ret = ldb_build_search_req(&search_req, ldb, expression, ldb_get_default_basedn(ldb), LDB_SCOPE_SUBTREE, expression, attrs, @@ -2242,6 +2245,7 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb, res, ldb_search_default_callback, NULL); if (ret != LDB_SUCCESS) { + talloc_free(expression); return ret; } @@ -2250,12 +2254,14 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb, options = talloc(search_req, struct ldb_search_options_control); if (options == NULL) { DEBUG(0, (__location__ ": out of memory\n")); + talloc_free(expression); return LDB_ERR_OPERATIONS_ERROR; } options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT; ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL); if (ret != LDB_SUCCESS) { + talloc_free(expression); return ret; } @@ -2263,16 +2269,19 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb, LDB_CONTROL_SEARCH_OPTIONS_OID, true, options); if (ret != LDB_SUCCESS) { + talloc_free(expression); return ret; } ret = ldb_request(ldb, search_req); if (ret != LDB_SUCCESS) { + talloc_free(expression); return ret; } ret = ldb_wait(search_req->handle, LDB_WAIT_ALL); if (ret != LDB_SUCCESS) { + talloc_free(expression); return ret; } @@ -2280,10 +2289,12 @@ int dsdb_find_dn_by_guid(struct ldb_context *ldb, partitions module that can return two here with the search_options control set */ if (res->count < 1) { + talloc_free(expression); return LDB_ERR_NO_SUCH_OBJECT; } - *dn = res->msgs[0]->dn; + *dn = talloc_steal(mem_ctx, res->msgs[0]->dn); + talloc_free(expression); return LDB_SUCCESS; } @@ -2306,6 +2317,7 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb, res = talloc_zero(tmp_ctx, struct ldb_result); if (!res) { + talloc_free(tmp_ctx); return LDB_ERR_OPERATIONS_ERROR; } @@ -2325,6 +2337,7 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb, ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL); if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); return ret; } @@ -2333,8 +2346,8 @@ int dsdb_search_dn_with_deleted(struct ldb_context *ldb, ret = ldb_wait(req->handle, LDB_WAIT_ALL); } - talloc_free(req); *_res = talloc_steal(mem_ctx, res); + talloc_free(tmp_ctx); return ret; } -- cgit From cced56736431094db14d07cfe04fd7606541c339 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 30 Dec 2009 21:40:17 +1100 Subject: s4-kcc: added a preiodic task to remove deleted objects we check for deleted objects in each partition every 10 minutes, using onelevel searches --- source4/dsdb/config.mk | 1 + source4/dsdb/kcc/kcc_deleted.c | 100 ++++++++++++++++++++++++++++++++++++++-- source4/dsdb/kcc/kcc_periodic.c | 5 ++ source4/dsdb/kcc/kcc_service.h | 2 + 4 files changed, 104 insertions(+), 4 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/config.mk b/source4/dsdb/config.mk index c5d1c24e04..35a0c84903 100644 --- a/source4/dsdb/config.mk +++ b/source4/dsdb/config.mk @@ -83,6 +83,7 @@ PRIVATE_DEPENDENCIES = \ KCC_SRV_OBJ_FILES = $(addprefix $(dsdbsrcdir)/kcc/, \ kcc_service.o \ kcc_connection.o \ + kcc_deleted.o \ kcc_periodic.o) $(eval $(call proto_header_template,$(dsdbsrcdir)/kcc/kcc_service_proto.h,$(KCC_SRV_OBJ_FILES:.o=.c))) diff --git a/source4/dsdb/kcc/kcc_deleted.c b/source4/dsdb/kcc/kcc_deleted.c index 44f3070261..d19ac0cac2 100644 --- a/source4/dsdb/kcc/kcc_deleted.c +++ b/source4/dsdb/kcc/kcc_deleted.c @@ -35,6 +35,56 @@ #include "librpc/gen_ndr/ndr_drsblobs.h" #include "param/param.h" +/* + onelevel search with SHOW_DELETED control + */ +static int search_onelevel_with_deleted(struct ldb_context *ldb, + TALLOC_CTX *mem_ctx, + struct ldb_result **_res, + struct ldb_dn *basedn, + const char * const *attrs) +{ + struct ldb_request *req; + TALLOC_CTX *tmp_ctx; + struct ldb_result *res; + int ret; + + tmp_ctx = talloc_new(mem_ctx); + + res = talloc_zero(tmp_ctx, struct ldb_result); + if (!res) { + return LDB_ERR_OPERATIONS_ERROR; + } + + ret = ldb_build_search_req(&req, ldb, tmp_ctx, + basedn, + LDB_SCOPE_ONELEVEL, + NULL, + attrs, + NULL, + res, + ldb_search_default_callback, + NULL); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL); + if (ret != LDB_SUCCESS) { + talloc_free(tmp_ctx); + return ret; + } + + ret = ldb_request(ldb, req); + if (ret == LDB_SUCCESS) { + ret = ldb_wait(req->handle, LDB_WAIT_ALL); + } + + talloc_free(req); + *_res = talloc_steal(mem_ctx, res); + return ret; +} /* check to see if any deleted objects need scavenging @@ -43,22 +93,64 @@ NTSTATUS kccsrv_check_deleted(struct kccsrv_service *s, TALLOC_CTX *mem_ctx) { struct kccsrv_partition *part; int ret; + uint32_t tombstoneLifetime; time_t t = time(NULL); - if (t - s->last_deleted_check < lp_parm_int(task->lp_ctx, NULL, "kccsrv", + if (t - s->last_deleted_check < lp_parm_int(s->task->lp_ctx, NULL, "kccsrv", "check_deleted_interval", 600)) { return NT_STATUS_OK; } s->last_deleted_check = t; + ret = dsdb_tombstone_lifetime(s->samdb, &tombstoneLifetime); + if (ret != LDB_SUCCESS) { + DEBUG(1,(__location__ ": Failed to get tombstone lifetime\n")); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + for (part=s->partitions; part; part=part->next) { struct ldb_dn *do_dn; struct ldb_result *res; + const char *attrs[] = { "whenChanged", NULL }; + int i; ret = dsdb_get_deleted_objects_dn(s->samdb, mem_ctx, part->dn, &do_dn); - ret = ldb_search(s->samdb, mem_ctx, &res, do_dn, LDB_SCOPE_SUBTREE, - attrs, "isDeleted=TRUE"); - } + if (ret != LDB_SUCCESS) { + /* some partitions have no Deleted Objects + container */ + continue; + } + ret = search_onelevel_with_deleted(s->samdb, do_dn, &res, do_dn, attrs); + + if (ret != LDB_SUCCESS) { + DEBUG(1,(__location__ ": Failed to search for deleted objects in %s\n", + ldb_dn_get_linearized(do_dn))); + talloc_free(do_dn); + continue; + } + + for (i=0; icount; i++) { + const char *tstring; + time_t whenChanged = 0; + tstring = samdb_result_string(res->msgs[i], "whenChanged", NULL); + if (tstring) { + whenChanged = ldb_string_to_time(tstring); + } + if (t - whenChanged > tombstoneLifetime*60*60*24) { + ret = ldb_delete(s->samdb, res->msgs[i]->dn); + if (ret != LDB_SUCCESS) { + DEBUG(1,(__location__ ": Failed to remove deleted object %s\n", + ldb_dn_get_linearized(res->msgs[i]->dn))); + } else { + DEBUG(4,("Removed deleted object %s\n", + ldb_dn_get_linearized(res->msgs[i]->dn))); + } + } + } + + talloc_free(do_dn); + } + return NT_STATUS_OK; } diff --git a/source4/dsdb/kcc/kcc_periodic.c b/source4/dsdb/kcc/kcc_periodic.c index d24e5e90a5..3b0d8a0551 100644 --- a/source4/dsdb/kcc/kcc_periodic.c +++ b/source4/dsdb/kcc/kcc_periodic.c @@ -257,5 +257,10 @@ static void kccsrv_periodic_run(struct kccsrv_service *service) if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("kccsrv_simple_update failed - %s\n", nt_errstr(status))); } + + status = kccsrv_check_deleted(service, mem_ctx); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("kccsrv_check_deleted failed - %s\n", nt_errstr(status))); + } talloc_free(mem_ctx); } diff --git a/source4/dsdb/kcc/kcc_service.h b/source4/dsdb/kcc/kcc_service.h index 6a78d37a91..b4ce37bfc5 100644 --- a/source4/dsdb/kcc/kcc_service.h +++ b/source4/dsdb/kcc/kcc_service.h @@ -78,6 +78,8 @@ struct kccsrv_service { /* here we have a reference to the timed event the schedules the periodic stuff */ struct tevent_timer *te; } periodic; + + time_t last_deleted_check; }; #include "dsdb/kcc/kcc_service_proto.h" -- cgit From 00b39c70f57882a453a8d2e6b0f1f37fd39a2d2a Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 2 Jan 2010 08:14:52 +1100 Subject: s4-dsdb: switched to using RMD_FLAGS instead of DELETED in extended DNs This allows for more flags in the future --- source4/dsdb/common/dsdb_dn.h | 5 ++ source4/dsdb/common/util.c | 48 +++++++++++++++--- source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 66 +++++++++++++------------ 3 files changed, 81 insertions(+), 38 deletions(-) (limited to 'source4/dsdb') diff --git a/source4/dsdb/common/dsdb_dn.h b/source4/dsdb/common/dsdb_dn.h index 53e10535c8..b713bdd27b 100644 --- a/source4/dsdb/common/dsdb_dn.h +++ b/source4/dsdb/common/dsdb_dn.h @@ -15,3 +15,8 @@ struct dsdb_dn { #define DSDB_SYNTAX_BINARY_DN "1.2.840.113556.1.4.903" #define DSDB_SYNTAX_STRING_DN "1.2.840.113556.1.4.904" #define DSDB_SYNTAX_OR_NAME "1.2.840.113556.1.4.1221" + + +/* RMD_FLAGS component in a DN */ +#define DSDB_RMD_FLAG_DELETED 1 +#define DSDB_RMD_FLAG_INVISIBLE 2 diff --git a/source4/dsdb/common/util.c b/source4/dsdb/common/util.c index 5d9ec1182f..b8ba26a4ec 100644 --- a/source4/dsdb/common/util.c +++ b/source4/dsdb/common/util.c @@ -2894,18 +2894,52 @@ NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const cha return NT_STATUS_OK; } +/* + return RMD_FLAGS directly from a ldb_dn + returns 0 if not found + */ +uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn) +{ + const struct ldb_val *v; + char buf[32]; + v = ldb_dn_get_extended_component(dn, "RMD_FLAGS"); + if (!v || v->length > sizeof(buf)-1) return 0; + strncpy(buf, (const char *)v->data, v->length); + buf[v->length] = 0; + return strtoul(buf, NULL, 10); +} + +/* + return RMD_FLAGS directly from a ldb_val for a DN + returns 0 if RMD_FLAGS is not found + */ +uint32_t dsdb_dn_val_rmd_flags(struct ldb_val *val) +{ + const char *p; + uint32_t flags; + char *end; + + if (val->length < 13) { + return 0; + } + p = memmem(val->data, val->length-2, " */ + return 0; + } + return flags; +} + /* return true if a ldb_val containing a DN in storage form is deleted */ bool dsdb_dn_is_deleted_val(struct ldb_val *val) { - /* this relies on the sort order and exact format of - linearized extended DNs */ - if (val->length >= 12 && - strncmp((const char *)val->data, ";", 12) == 0) { - return true; - } - return false; + return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0; } /* diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 202b74e8b4..890eb91d6d 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -1204,7 +1204,7 @@ static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx, /* build a new extended DN, including all meta data fields - DELETED = 1 or missing + RMD_FLAGS = DSDB_RMD_FLAG_* bits RMD_ADDTIME = originating_add_time RMD_INVOCID = originating_invocation_id RMD_CHANGETIME = originating_change_time @@ -1217,15 +1217,16 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; - const char *tstring, *usn_string; + const char *tstring, *usn_string, *flags_string; struct ldb_val tval; struct ldb_val iid; struct ldb_val usnv, local_usnv; - struct ldb_val vers; + struct ldb_val vers, flagsv; NTSTATUS status; int ret; const char *dnstring; char *vstring; + uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0; tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { @@ -1246,6 +1247,9 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds local_usnv = data_blob_string_const(usn_string); vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version); + if (!vstring) { + return LDB_ERR_OPERATIONS_ERROR; + } vers = data_blob_string_const(vstring); status = GUID_to_ndr_blob(invocation_id, dn, &iid); @@ -1253,13 +1257,13 @@ static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct ds return LDB_ERR_OPERATIONS_ERROR; } - if (deleted) { - struct ldb_val dv; - dv = data_blob_string_const("1"); - ret = ldb_dn_set_extended_component(dn, "DELETED", &dv); - } else { - ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags); + if (!flags_string) { + return LDB_ERR_OPERATIONS_ERROR; } + flagsv = data_blob_string_const(flags_string); + + ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv); if (ret != LDB_SUCCESS) return ret; ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval); if (ret != LDB_SUCCESS) return ret; @@ -1325,17 +1329,18 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d uint32_t version, bool deleted) { struct ldb_dn *dn = dsdb_dn->dn; - const char *tstring, *usn_string; + const char *tstring, *usn_string, *flags_string; struct ldb_val tval; struct ldb_val iid; struct ldb_val usnv, local_usnv; - struct ldb_val vers; + struct ldb_val vers, flagsv; const struct ldb_val *old_addtime; uint32_t old_version; NTSTATUS status; int ret; const char *dnstring; char *vstring; + uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0; tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime); if (!tstring) { @@ -1360,13 +1365,13 @@ static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct d return LDB_ERR_OPERATIONS_ERROR; } - if (deleted) { - struct ldb_val dv; - dv = data_blob_string_const("1"); - ret = ldb_dn_set_extended_component(dn, "DELETED", &dv); - } else { - ret = ldb_dn_set_extended_component(dn, "DELETED", NULL); + flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags); + if (!flags_string) { + return LDB_ERR_OPERATIONS_ERROR; } + flagsv = data_blob_string_const(flags_string); + + ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv); if (ret != LDB_SUCCESS) return ret; /* get the ADDTIME from the original */ @@ -1484,9 +1489,9 @@ static int replmd_modify_la_add(struct ldb_module *module, } else { /* this is only allowed if the GUID was previously deleted. */ - const struct ldb_val *v; - v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); - if (v == NULL) { + uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn); + + if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) { ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s", el->name, GUID_string(tmp_ctx, p->guid)); talloc_free(tmp_ctx); @@ -1595,7 +1600,7 @@ static int replmd_modify_la_delete(struct ldb_module *module, for (i=0; inum_values; i++) { struct parsed_dn *p = &dns[i]; struct parsed_dn *p2; - const struct ldb_val *v; + uint32_t rmd_flags; p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL); if (!p2) { @@ -1603,8 +1608,8 @@ static int replmd_modify_la_delete(struct ldb_module *module, el->name, GUID_string(tmp_ctx, p->guid)); return LDB_ERR_NO_SUCH_ATTRIBUTE; } - v = ldb_dn_get_extended_component(p2->dsdb_dn->dn, "DELETED"); - if (v) { + rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn); + if (rmd_flags & DSDB_RMD_FLAG_DELETED) { ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s", el->name, GUID_string(tmp_ctx, p->guid)); return LDB_ERR_NO_SUCH_ATTRIBUTE; @@ -1616,14 +1621,14 @@ static int replmd_modify_la_delete(struct ldb_module *module, */ for (i=0; inum_values; i++) { struct parsed_dn *p = &old_dns[i]; - const struct ldb_val *v; + uint32_t rmd_flags; if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) { continue; } - v = ldb_dn_get_extended_component(p->dsdb_dn->dn, "DELETED"); - if (v != NULL) continue; + rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn); + if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue; ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn, invocation_id, seq_num, seq_num, now, 0, true); @@ -1710,10 +1715,9 @@ static int replmd_modify_la_replace(struct ldb_module *module, for (i=0; idsdb_dn->dn); - v = ldb_dn_get_extended_component(old_p->dsdb_dn->dn, "DELETED"); - if (v) continue; + if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue; ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false); if (ret != LDB_SUCCESS) { @@ -3519,7 +3523,7 @@ linked_attributes[0]: struct GUID invocation_id = GUID_zero(); uint32_t version = 0; NTTIME change_time = 0; - bool was_active = ldb_dn_get_extended_component(pdn->dsdb_dn->dn, "DELETED") == NULL; + uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn); dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID"); dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION"); @@ -3545,7 +3549,7 @@ linked_attributes[0]: return ret; } - if (was_active) { + if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) { /* remove the existing backlink */ ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false); if (ret != LDB_SUCCESS) { -- cgit From 504754856eed363dde28cdff821c086754deb7f8 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 2 Jan 2010 16:53:20 +1100 Subject: s4-dsdb: force REVISION_ADS for new and updated ACLs in dsdb w2k8-r2 gives a "schema mismatch" error if the revision is not set to REVISION_ADS and you replicate the ntsecuritydescriptor using DRS. Nadya, please check this! Pair-Programmed-With: Andrew Bartlett --- source4/dsdb/samdb/ldb_modules/descriptor.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'source4/dsdb') diff --git a/source4/dsdb/samdb/ldb_modules/descriptor.c b/source4/dsdb/samdb/ldb_modules/descriptor.c index d5a5e36e0e..f07743c4a2 100644 --- a/source4/dsdb/samdb/ldb_modules/descriptor.c +++ b/source4/dsdb/samdb/ldb_modules/descriptor.c @@ -285,6 +285,14 @@ static DATA_BLOB *get_new_descriptor(struct ldb_module *module, if (!final_sd) { return NULL; } + + if (final_sd->dacl) { + final_sd->dacl->revision = SECURITY_ACL_REVISION_ADS; + } + if (final_sd->sacl) { + final_sd->sacl->revision = SECURITY_ACL_REVISION_ADS; + } + sddl_sd = sddl_encode(mem_ctx, final_sd, domain_sid); DEBUG(10, ("Object %s created with desriptor %s\n\n", ldb_dn_get_linearized(dn), sddl_sd)); -- cgit