1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-25 23:21:54 +03:00

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 <abartlet@samba.org>
This commit is contained in:
Andrew Tridgell 2009-12-16 11:34:33 +11:00
parent dee6b6fb3d
commit 3b056061ff

View File

@ -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; i<msg->num_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);
}