return LDB_SUCCESS;
}
-/*
- process one linked attribute structure
+/**
+ * Processes one linked attribute received via replication.
+ * @param msg the source object for the link. For optimization, the same msg
+ * can be used across multiple calls to replmd_process_linked_attribute().
+ * @note this function should not add or remove any msg attributes (it should
+ * only add/modify values for the linked attribute being processed). Otherwise
+ * msg->elements is realloc'd and old_el/pdn_list pointers will be invalidated
+ * @param attr schema info for the linked attribute
+ * @param la_entry the linked attribute info received via DRS
+ * @param old_el the corresponding msg->element[] for the linked attribute
+ * @param pdn_list a (binary-searchable) parsed DN array for the existing link
+ * values in the msg. E.g. for a group, this is the existing members.
+ * @param change what got modified: either nothing, an existing link value was
+ * modified, or a new link value was added.
+ * @returns LDB_SUCCESS if OK, an error otherwise
*/
static int replmd_process_linked_attribute(struct ldb_module *module,
TALLOC_CTX *mem_ctx,
/**
* Processes a group of linked attributes that apply to the same source-object
- * and attribute-ID
+ * and attribute-ID (and were received in the same replication chunk).
*/
static int replmd_process_la_group(struct ldb_module *module,
struct replmd_private *replmd_private,
struct la_entry *la = NULL;
struct la_entry *prev = NULL;
int ret;
- TALLOC_CTX *tmp_ctx = talloc_new(la_group);
+ TALLOC_CTX *tmp_ctx = NULL;
struct la_entry *first_la = DLIST_TAIL(la_group->la_entries);
struct ldb_message *msg = NULL;
enum deletion_state deletion_state = OBJECT_NOT_DELETED;
time_t t;
uint64_t seq_num = 0;
+ tmp_ctx = talloc_new(la_group);
+ if (tmp_ctx == NULL) {
+ return ldb_oom(ldb);
+ }
+
/*
* get the attribute being modified and the search result for the
* source object
ldb_msg_remove_attr(msg, "isDeleted");
ldb_msg_remove_attr(msg, "isRecycled");
+ /* get the msg->element[] for the link attribute being processed */
old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
if (old_el == NULL) {
ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName,
old_el->flags = LDB_FLAG_MOD_REPLACE;
}
- /* go through and process the link targets for this source object */
+ /*
+ * go through and process the link target value(s) for this particular
+ * source object and attribute
+ */
for (la = DLIST_TAIL(la_group->la_entries); la; la=prev) {
prev = DLIST_PREV(la);
DLIST_REMOVE(la_group->la_entries, la);
- /* parse the existing links */
+ /*
+ * parse the existing links (this can be costly for a large
+ * group, so we try to minimize the times we do it)
+ */
if (pdn_list == NULL) {
ret = get_parsed_dns_trusted(module, replmd_private,
tmp_ctx, old_el,
return LDB_SUCCESS;
}
+ /*
+ * Note that adding the whenChanged/etc attributes below will realloc
+ * msg->elements, invalidating the existing element/parsed-DN pointers
+ */
+ old_el = NULL;
+ TALLOC_FREE(pdn_list);
+
/* update whenChanged/uSNChanged as the object has changed */
t = time(NULL);
ret = ldb_sequence_number(ldb, LDB_SEQ_HIGHEST_SEQ,