4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * Component: ldb repl_meta_data module
28 * Description: - add a unique objectGUID onto every new record,
29 * - handle whenCreated, whenChanged timestamps
30 * - handle uSNCreated, uSNChanged numbers
31 * - handle replPropertyMetaData attribute
34 * Author: Stefan Metzmacher
38 #include "ldb_module.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "dsdb/common/proto.h"
41 #include "../libds/common/flags.h"
42 #include "librpc/gen_ndr/ndr_misc.h"
43 #include "librpc/gen_ndr/ndr_drsuapi.h"
44 #include "librpc/gen_ndr/ndr_drsblobs.h"
45 #include "param/param.h"
46 #include "libcli/security/dom_sid.h"
47 #include "lib/util/dlinklist.h"
48 #include "dsdb/samdb/ldb_modules/util.h"
49 #include "lib/util/binsearch.h"
50 #include "libcli/security/security.h"
51 #include "lib/util/tsort.h"
53 #define W2K3_LINKED_ATTRIBUTES 1
55 struct replmd_private {
57 struct la_entry *la_list;
59 struct la_backlink *la_backlinks;
61 struct nc_entry *prev, *next;
64 uint64_t mod_usn_urgent;
69 struct la_entry *next, *prev;
70 struct drsuapi_DsReplicaLinkedAttribute *la;
73 struct replmd_replicated_request {
74 struct ldb_module *module;
75 struct ldb_request *req;
77 const struct dsdb_schema *schema;
79 /* the controls we pass down */
80 struct ldb_control **controls;
82 /* details for the mode where we apply a bunch of inbound replication meessages */
84 uint32_t index_current;
85 struct dsdb_extended_replicated_objects *objs;
87 struct ldb_message *search_msg;
93 enum urgent_situation {
94 REPL_URGENT_ON_CREATE = 1,
95 REPL_URGENT_ON_UPDATE = 2,
96 REPL_URGENT_ON_DELETE = 4
100 static const struct {
101 const char *update_name;
102 enum urgent_situation repl_situation;
103 } urgent_objects[] = {
104 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
105 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
106 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
107 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
108 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
109 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
113 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
114 static const char *urgent_attrs[] = {
117 "userAccountControl",
122 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
123 enum urgent_situation situation)
126 for (i=0; urgent_objects[i].update_name; i++) {
128 if ((situation & urgent_objects[i].repl_situation) == 0) {
132 for (j=0; j<objectclass_el->num_values; j++) {
133 const struct ldb_val *v = &objectclass_el->values[j];
134 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
142 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
144 if (ldb_attr_in_list(urgent_attrs, el->name)) {
151 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
154 initialise the module
155 allocate the private structure and build the list
156 of partition DNs for use by replmd_notify()
158 static int replmd_init(struct ldb_module *module)
160 struct replmd_private *replmd_private;
161 struct ldb_context *ldb = ldb_module_get_ctx(module);
163 replmd_private = talloc_zero(module, struct replmd_private);
164 if (replmd_private == NULL) {
166 return LDB_ERR_OPERATIONS_ERROR;
168 ldb_module_set_private(module, replmd_private);
170 return ldb_next_init(module);
174 cleanup our per-transaction contexts
176 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
178 talloc_free(replmd_private->la_ctx);
179 replmd_private->la_list = NULL;
180 replmd_private->la_ctx = NULL;
182 talloc_free(replmd_private->bl_ctx);
183 replmd_private->la_backlinks = NULL;
184 replmd_private->bl_ctx = NULL;
189 struct la_backlink *next, *prev;
190 const char *attr_name;
191 struct GUID forward_guid, target_guid;
196 process a backlinks we accumulated during a transaction, adding and
197 deleting the backlinks from the target objects
199 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl)
201 struct ldb_dn *target_dn, *source_dn;
203 struct ldb_context *ldb = ldb_module_get_ctx(module);
204 struct ldb_message *msg;
205 TALLOC_CTX *tmp_ctx = talloc_new(bl);
211 - construct ldb_message
212 - either an add or a delete
214 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn);
215 if (ret != LDB_SUCCESS) {
216 ldb_asprintf_errstring(ldb, "Failed to find target DN for linked attribute with GUID %s\n",
217 GUID_string(bl, &bl->target_guid));
218 talloc_free(tmp_ctx);
222 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn);
223 if (ret != LDB_SUCCESS) {
224 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
225 GUID_string(bl, &bl->forward_guid));
226 talloc_free(tmp_ctx);
230 msg = ldb_msg_new(tmp_ctx);
232 ldb_module_oom(module);
233 talloc_free(tmp_ctx);
234 return LDB_ERR_OPERATIONS_ERROR;
237 /* construct a ldb_message for adding/deleting the backlink */
239 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
241 ldb_module_oom(module);
242 talloc_free(tmp_ctx);
243 return LDB_ERR_OPERATIONS_ERROR;
245 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
246 if (ret != LDB_SUCCESS) {
247 talloc_free(tmp_ctx);
250 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
252 ret = dsdb_module_modify(module, msg, 0);
253 if (ret != LDB_SUCCESS) {
254 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
255 bl->active?"add":"remove",
256 ldb_dn_get_linearized(source_dn),
257 ldb_dn_get_linearized(target_dn),
259 talloc_free(tmp_ctx);
262 talloc_free(tmp_ctx);
267 add a backlink to the list of backlinks to add/delete in the prepare
270 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
271 struct GUID *forward_guid, struct GUID *target_guid,
272 bool active, const struct dsdb_attribute *schema_attr, bool immediate)
274 const struct dsdb_attribute *target_attr;
275 struct la_backlink *bl;
276 struct replmd_private *replmd_private =
277 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
279 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
282 * windows 2003 has a broken schema where the
283 * definition of msDS-IsDomainFor is missing (which is
284 * supposed to be the backlink of the
285 * msDS-HasDomainNCs attribute
290 /* see if its already in the list */
291 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
292 if (GUID_equal(forward_guid, &bl->forward_guid) &&
293 GUID_equal(target_guid, &bl->target_guid) &&
294 (target_attr->lDAPDisplayName == bl->attr_name ||
295 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
301 /* we found an existing one */
302 if (bl->active == active) {
305 DLIST_REMOVE(replmd_private->la_backlinks, bl);
310 if (replmd_private->bl_ctx == NULL) {
311 replmd_private->bl_ctx = talloc_new(replmd_private);
312 if (replmd_private->bl_ctx == NULL) {
313 ldb_module_oom(module);
314 return LDB_ERR_OPERATIONS_ERROR;
319 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
321 ldb_module_oom(module);
322 return LDB_ERR_OPERATIONS_ERROR;
325 bl->attr_name = target_attr->lDAPDisplayName;
326 bl->forward_guid = *forward_guid;
327 bl->target_guid = *target_guid;
330 /* the caller may ask for this backlink to be processed
333 int ret = replmd_process_backlink(module, bl);
338 DLIST_ADD(replmd_private->la_backlinks, bl);
345 * Callback for most write operations in this module:
347 * notify the repl task that a object has changed. The notifies are
348 * gathered up in the replmd_private structure then written to the
349 * @REPLCHANGED object in each partition during the prepare_commit
351 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
354 struct replmd_replicated_request *ac =
355 talloc_get_type_abort(req->context, struct replmd_replicated_request);
356 struct replmd_private *replmd_private =
357 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
358 struct nc_entry *modified_partition;
359 struct ldb_control *partition_ctrl;
360 const struct dsdb_control_current_partition *partition;
362 struct ldb_control **controls;
364 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
366 /* Remove the 'partition' control from what we pass up the chain */
367 controls = controls_except_specified(ares->controls, ares, partition_ctrl);
369 if (ares->error != LDB_SUCCESS) {
370 return ldb_module_done(ac->req, controls,
371 ares->response, ares->error);
374 if (ares->type != LDB_REPLY_DONE) {
375 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
376 return ldb_module_done(ac->req, NULL,
377 NULL, LDB_ERR_OPERATIONS_ERROR);
380 if (!partition_ctrl) {
381 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
382 return ldb_module_done(ac->req, NULL,
383 NULL, LDB_ERR_OPERATIONS_ERROR);
386 partition = talloc_get_type_abort(partition_ctrl->data,
387 struct dsdb_control_current_partition);
389 if (ac->seq_num > 0) {
390 for (modified_partition = replmd_private->ncs; modified_partition;
391 modified_partition = modified_partition->next) {
392 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
397 if (modified_partition == NULL) {
398 modified_partition = talloc_zero(replmd_private, struct nc_entry);
399 if (!modified_partition) {
400 ldb_oom(ldb_module_get_ctx(ac->module));
401 return ldb_module_done(ac->req, NULL,
402 NULL, LDB_ERR_OPERATIONS_ERROR);
404 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
405 if (!modified_partition->dn) {
406 ldb_oom(ldb_module_get_ctx(ac->module));
407 return ldb_module_done(ac->req, NULL,
408 NULL, LDB_ERR_OPERATIONS_ERROR);
410 DLIST_ADD(replmd_private->ncs, modified_partition);
413 if (ac->seq_num > modified_partition->mod_usn) {
414 modified_partition->mod_usn = ac->seq_num;
416 modified_partition->mod_usn_urgent = ac->seq_num;
421 if (ac->apply_mode) {
425 ret = replmd_replicated_apply_next(ac);
426 if (ret != LDB_SUCCESS) {
427 return ldb_module_done(ac->req, NULL, NULL, ret);
431 /* free the partition control container here, for the
432 * common path. Other cases will have it cleaned up
433 * eventually with the ares */
434 talloc_free(partition_ctrl);
435 return ldb_module_done(ac->req,
436 controls_except_specified(controls, ares, partition_ctrl),
437 ares->response, LDB_SUCCESS);
443 * update a @REPLCHANGED record in each partition if there have been
444 * any writes of replicated data in the partition
446 static int replmd_notify_store(struct ldb_module *module)
448 struct replmd_private *replmd_private =
449 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
450 struct ldb_context *ldb = ldb_module_get_ctx(module);
452 while (replmd_private->ncs) {
454 struct nc_entry *modified_partition = replmd_private->ncs;
456 ret = dsdb_save_partition_usn(ldb, modified_partition->dn,
457 modified_partition->mod_usn,
458 modified_partition->mod_usn_urgent);
459 if (ret != LDB_SUCCESS) {
460 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
461 ldb_dn_get_linearized(modified_partition->dn)));
464 DLIST_REMOVE(replmd_private->ncs, modified_partition);
465 talloc_free(modified_partition);
473 created a replmd_replicated_request context
475 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
476 struct ldb_request *req)
478 struct ldb_context *ldb;
479 struct replmd_replicated_request *ac;
481 ldb = ldb_module_get_ctx(module);
483 ac = talloc_zero(req, struct replmd_replicated_request);
492 ac->schema = dsdb_get_schema(ldb);
494 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
495 "replmd_modify: no dsdb_schema loaded");
496 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
504 add a time element to a record
506 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
508 struct ldb_message_element *el;
511 if (ldb_msg_find_element(msg, attr) != NULL) {
515 s = ldb_timestring(msg, t);
517 return LDB_ERR_OPERATIONS_ERROR;
520 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
521 return LDB_ERR_OPERATIONS_ERROR;
524 el = ldb_msg_find_element(msg, attr);
525 /* always set as replace. This works because on add ops, the flag
527 el->flags = LDB_FLAG_MOD_REPLACE;
533 add a uint64_t element to a record
535 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
537 struct ldb_message_element *el;
539 if (ldb_msg_find_element(msg, attr) != NULL) {
543 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
544 return LDB_ERR_OPERATIONS_ERROR;
547 el = ldb_msg_find_element(msg, attr);
548 /* always set as replace. This works because on add ops, the flag
550 el->flags = LDB_FLAG_MOD_REPLACE;
555 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
556 const struct replPropertyMetaData1 *m2,
557 const uint32_t *rdn_attid)
559 if (m1->attid == m2->attid) {
564 * the rdn attribute should be at the end!
565 * so we need to return a value greater than zero
566 * which means m1 is greater than m2
568 if (m1->attid == *rdn_attid) {
573 * the rdn attribute should be at the end!
574 * so we need to return a value less than zero
575 * which means m2 is greater than m1
577 if (m2->attid == *rdn_attid) {
581 return m1->attid > m2->attid ? 1 : -1;
584 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
585 const struct dsdb_schema *schema,
588 const char *rdn_name;
589 const struct dsdb_attribute *rdn_sa;
591 rdn_name = ldb_dn_get_rdn_name(dn);
593 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
594 return LDB_ERR_OPERATIONS_ERROR;
597 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
598 if (rdn_sa == NULL) {
599 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
600 return LDB_ERR_OPERATIONS_ERROR;
603 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
604 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
606 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
611 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
612 const struct ldb_message_element *e2,
613 const struct dsdb_schema *schema)
615 const struct dsdb_attribute *a1;
616 const struct dsdb_attribute *a2;
619 * TODO: make this faster by caching the dsdb_attribute pointer
620 * on the ldb_messag_element
623 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
624 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
627 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
631 return strcasecmp(e1->name, e2->name);
633 if (a1->attributeID_id == a2->attributeID_id) {
636 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
639 static void replmd_ldb_message_sort(struct ldb_message *msg,
640 const struct dsdb_schema *schema)
642 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
645 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
646 const struct GUID *invocation_id, uint64_t seq_num,
647 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
651 fix up linked attributes in replmd_add.
652 This involves setting up the right meta-data in extended DN
653 components, and creating backlinks to the object
655 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
656 uint64_t seq_num, const struct GUID *invocationId, time_t t,
657 struct GUID *guid, const struct dsdb_attribute *sa)
660 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
661 struct ldb_context *ldb = ldb_module_get_ctx(module);
662 struct dsdb_schema *schema = dsdb_get_schema(ldb);
665 unix_to_nt_time(&now, t);
667 for (i=0; i<el->num_values; i++) {
668 struct ldb_val *v = &el->values[i];
669 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
670 struct GUID target_guid;
674 /* note that the DN already has the extended
675 components from the extended_dn_store module */
676 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
677 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
678 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid);
679 if (ret != LDB_SUCCESS) {
680 talloc_free(tmp_ctx);
683 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
684 if (ret != LDB_SUCCESS) {
685 talloc_free(tmp_ctx);
690 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
691 seq_num, seq_num, now, 0, false);
692 if (ret != LDB_SUCCESS) {
693 talloc_free(tmp_ctx);
697 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
698 if (ret != LDB_SUCCESS) {
699 talloc_free(tmp_ctx);
704 talloc_free(tmp_ctx);
710 intercept add requests
712 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
714 struct ldb_context *ldb;
715 struct ldb_control *control;
716 struct replmd_replicated_request *ac;
717 enum ndr_err_code ndr_err;
718 struct ldb_request *down_req;
719 struct ldb_message *msg;
720 const DATA_BLOB *guid_blob;
722 struct replPropertyMetaDataBlob nmd;
723 struct ldb_val nmd_value;
724 const struct GUID *our_invocation_id;
725 time_t t = time(NULL);
730 bool allow_add_guid = false;
731 bool remove_current_guid = false;
732 bool is_urgent = false;
733 struct ldb_message_element *objectclass_el;
735 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
736 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
738 allow_add_guid = true;
741 /* do not manipulate our control entries */
742 if (ldb_dn_is_special(req->op.add.message->dn)) {
743 return ldb_next_request(module, req);
746 ldb = ldb_module_get_ctx(module);
748 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
750 ac = replmd_ctx_init(module, req);
752 return LDB_ERR_OPERATIONS_ERROR;
755 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
756 if ( guid_blob != NULL ) {
757 if( !allow_add_guid ) {
758 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
759 "replmd_add: it's not allowed to add an object with objectGUID\n");
761 return LDB_ERR_UNWILLING_TO_PERFORM;
763 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
764 if ( !NT_STATUS_IS_OK(status)) {
765 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
766 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
768 return LDB_ERR_UNWILLING_TO_PERFORM;
770 /* we remove this attribute as it can be a string and will not be treated
771 correctly and then we will readd it latter on in the good format*/
772 remove_current_guid = true;
776 guid = GUID_random();
779 /* Get a sequence number from the backend */
780 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
781 if (ret != LDB_SUCCESS) {
786 /* get our invocationId */
787 our_invocation_id = samdb_ntds_invocation_id(ldb);
788 if (!our_invocation_id) {
789 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
790 "replmd_add: unable to find invocationId\n");
792 return LDB_ERR_OPERATIONS_ERROR;
795 /* we have to copy the message as the caller might have it as a const */
796 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
800 return LDB_ERR_OPERATIONS_ERROR;
803 /* generated times */
804 unix_to_nt_time(&now, t);
805 time_str = ldb_timestring(msg, t);
809 return LDB_ERR_OPERATIONS_ERROR;
811 if (remove_current_guid) {
812 ldb_msg_remove_attr(msg,"objectGUID");
816 * remove autogenerated attributes
818 ldb_msg_remove_attr(msg, "whenCreated");
819 ldb_msg_remove_attr(msg, "whenChanged");
820 ldb_msg_remove_attr(msg, "uSNCreated");
821 ldb_msg_remove_attr(msg, "uSNChanged");
822 ldb_msg_remove_attr(msg, "replPropertyMetaData");
825 * readd replicated attributes
827 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
828 if (ret != LDB_SUCCESS) {
834 /* build the replication meta_data */
837 nmd.ctr.ctr1.count = msg->num_elements;
838 nmd.ctr.ctr1.array = talloc_array(msg,
839 struct replPropertyMetaData1,
841 if (!nmd.ctr.ctr1.array) {
844 return LDB_ERR_OPERATIONS_ERROR;
847 for (i=0; i < msg->num_elements; i++) {
848 struct ldb_message_element *e = &msg->elements[i];
849 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
850 const struct dsdb_attribute *sa;
852 if (e->name[0] == '@') continue;
854 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
856 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
857 "replmd_add: attribute '%s' not defined in schema\n",
860 return LDB_ERR_NO_SUCH_ATTRIBUTE;
863 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
864 /* if the attribute is not replicated (0x00000001)
865 * or constructed (0x00000004) it has no metadata
870 #if W2K3_LINKED_ATTRIBUTES
871 if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
872 ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa);
873 if (ret != LDB_SUCCESS) {
877 /* linked attributes are not stored in
878 replPropertyMetaData in FL above w2k */
883 m->attid = sa->attributeID_id;
885 m->originating_change_time = now;
886 m->originating_invocation_id = *our_invocation_id;
887 m->originating_usn = ac->seq_num;
888 m->local_usn = ac->seq_num;
892 /* fix meta data count */
893 nmd.ctr.ctr1.count = ni;
896 * sort meta data array, and move the rdn attribute entry to the end
898 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
899 if (ret != LDB_SUCCESS) {
904 /* generated NDR encoded values */
905 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
906 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
908 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
909 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
912 return LDB_ERR_OPERATIONS_ERROR;
916 * add the autogenerated values
918 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
919 if (ret != LDB_SUCCESS) {
924 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
925 if (ret != LDB_SUCCESS) {
930 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
931 if (ret != LDB_SUCCESS) {
936 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
937 if (ret != LDB_SUCCESS) {
942 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
943 if (ret != LDB_SUCCESS) {
950 * sort the attributes by attid before storing the object
952 replmd_ldb_message_sort(msg, ac->schema);
954 objectclass_el = ldb_msg_find_element(msg, "objectClass");
955 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
956 REPL_URGENT_ON_CREATE);
958 ac->is_urgent = is_urgent;
959 ret = ldb_build_add_req(&down_req, ldb, ac,
962 ac, replmd_op_callback,
965 if (ret != LDB_SUCCESS) {
970 /* mark the control done */
972 control->critical = 0;
975 /* go on with the call chain */
976 return ldb_next_request(module, down_req);
981 * update the replPropertyMetaData for one element
983 static int replmd_update_rpmd_element(struct ldb_context *ldb,
984 struct ldb_message *msg,
985 struct ldb_message_element *el,
986 struct replPropertyMetaDataBlob *omd,
987 const struct dsdb_schema *schema,
989 const struct GUID *our_invocation_id,
993 const struct dsdb_attribute *a;
994 struct replPropertyMetaData1 *md1;
996 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
998 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1000 return LDB_ERR_OPERATIONS_ERROR;
1003 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1007 for (i=0; i<omd->ctr.ctr1.count; i++) {
1008 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1011 #if W2K3_LINKED_ATTRIBUTES
1012 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1013 /* linked attributes are not stored in
1014 replPropertyMetaData in FL above w2k, but we do
1015 raise the seqnum for the object */
1016 if (*seq_num == 0 &&
1017 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1018 return LDB_ERR_OPERATIONS_ERROR;
1024 if (i == omd->ctr.ctr1.count) {
1025 /* we need to add a new one */
1026 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1027 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1028 if (omd->ctr.ctr1.array == NULL) {
1030 return LDB_ERR_OPERATIONS_ERROR;
1032 omd->ctr.ctr1.count++;
1033 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1036 /* Get a new sequence number from the backend. We only do this
1037 * if we have a change that requires a new
1038 * replPropertyMetaData element
1040 if (*seq_num == 0) {
1041 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1042 if (ret != LDB_SUCCESS) {
1043 return LDB_ERR_OPERATIONS_ERROR;
1047 md1 = &omd->ctr.ctr1.array[i];
1049 md1->attid = a->attributeID_id;
1050 md1->originating_change_time = now;
1051 md1->originating_invocation_id = *our_invocation_id;
1052 md1->originating_usn = *seq_num;
1053 md1->local_usn = *seq_num;
1059 * update the replPropertyMetaData object each time we modify an
1060 * object. This is needed for DRS replication, as the merge on the
1061 * client is based on this object
1063 static int replmd_update_rpmd(struct ldb_module *module,
1064 const struct dsdb_schema *schema,
1065 struct ldb_message *msg, uint64_t *seq_num,
1069 const struct ldb_val *omd_value;
1070 enum ndr_err_code ndr_err;
1071 struct replPropertyMetaDataBlob omd;
1074 const struct GUID *our_invocation_id;
1076 const char *attrs[] = { "replPropertyMetaData" , "objectClass", NULL };
1077 struct ldb_result *res;
1078 struct ldb_context *ldb;
1079 struct ldb_message_element *objectclass_el;
1080 enum urgent_situation situation;
1082 ldb = ldb_module_get_ctx(module);
1084 our_invocation_id = samdb_ntds_invocation_id(ldb);
1085 if (!our_invocation_id) {
1086 /* this happens during an initial vampire while
1087 updating the schema */
1088 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1092 unix_to_nt_time(&now, t);
1094 /* search for the existing replPropertyMetaDataBlob */
1095 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
1096 if (ret != LDB_SUCCESS || res->count != 1) {
1097 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1098 ldb_dn_get_linearized(msg->dn)));
1099 return LDB_ERR_OPERATIONS_ERROR;
1102 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1103 * otherwise we consider we are updating */
1104 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1105 situation = REPL_URGENT_ON_DELETE;
1107 situation = REPL_URGENT_ON_UPDATE;
1110 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1111 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1116 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1118 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1119 ldb_dn_get_linearized(msg->dn)));
1120 return LDB_ERR_OPERATIONS_ERROR;
1123 ndr_err = ndr_pull_struct_blob(omd_value, msg,
1124 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1125 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1126 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1127 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1128 ldb_dn_get_linearized(msg->dn)));
1129 return LDB_ERR_OPERATIONS_ERROR;
1132 if (omd.version != 1) {
1133 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1134 omd.version, ldb_dn_get_linearized(msg->dn)));
1135 return LDB_ERR_OPERATIONS_ERROR;
1138 for (i=0; i<msg->num_elements; i++) {
1139 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
1140 our_invocation_id, now);
1141 if (ret != LDB_SUCCESS) {
1145 if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1146 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1152 * replmd_update_rpmd_element has done an update if the
1155 if (*seq_num != 0) {
1156 struct ldb_val *md_value;
1157 struct ldb_message_element *el;
1159 md_value = talloc(msg, struct ldb_val);
1160 if (md_value == NULL) {
1162 return LDB_ERR_OPERATIONS_ERROR;
1165 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1166 if (ret != LDB_SUCCESS) {
1170 ndr_err = ndr_push_struct_blob(md_value, msg,
1171 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1173 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1174 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1175 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1176 ldb_dn_get_linearized(msg->dn)));
1177 return LDB_ERR_OPERATIONS_ERROR;
1180 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1181 if (ret != LDB_SUCCESS) {
1182 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1183 ldb_dn_get_linearized(msg->dn)));
1188 el->values = md_value;
1195 struct dsdb_dn *dsdb_dn;
1200 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1202 return GUID_compare(pdn1->guid, pdn2->guid);
1205 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid, struct ldb_dn *dn)
1207 struct parsed_dn *ret;
1208 if (dn && GUID_all_zero(guid)) {
1209 /* when updating a link using DRS, we sometimes get a
1210 NULL GUID. We then need to try and match by DN */
1212 for (i=0; i<count; i++) {
1213 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1214 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1220 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1225 get a series of message element values as an array of DNs and GUIDs
1226 the result is sorted by GUID
1228 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1229 struct ldb_message_element *el, struct parsed_dn **pdn,
1230 const char *ldap_oid)
1233 struct ldb_context *ldb = ldb_module_get_ctx(module);
1240 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1242 ldb_module_oom(module);
1243 return LDB_ERR_OPERATIONS_ERROR;
1246 for (i=0; i<el->num_values; i++) {
1247 struct ldb_val *v = &el->values[i];
1250 struct parsed_dn *p;
1254 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1255 if (p->dsdb_dn == NULL) {
1256 return LDB_ERR_INVALID_DN_SYNTAX;
1259 dn = p->dsdb_dn->dn;
1261 p->guid = talloc(*pdn, struct GUID);
1262 if (p->guid == NULL) {
1263 ldb_module_oom(module);
1264 return LDB_ERR_OPERATIONS_ERROR;
1267 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1268 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1269 /* we got a DN without a GUID - go find the GUID */
1270 int ret = dsdb_module_guid_by_dn(module, dn, p->guid);
1271 if (ret != LDB_SUCCESS) {
1272 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1273 ldb_dn_get_linearized(dn));
1276 ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1277 if (ret != LDB_SUCCESS) {
1280 } else if (!NT_STATUS_IS_OK(status)) {
1281 return LDB_ERR_OPERATIONS_ERROR;
1284 /* keep a pointer to the original ldb_val */
1288 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1294 build a new extended DN, including all meta data fields
1296 RMD_FLAGS = DSDB_RMD_FLAG_* bits
1297 RMD_ADDTIME = originating_add_time
1298 RMD_INVOCID = originating_invocation_id
1299 RMD_CHANGETIME = originating_change_time
1300 RMD_ORIGINATING_USN = originating_usn
1301 RMD_LOCAL_USN = local_usn
1302 RMD_VERSION = version
1304 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1305 const struct GUID *invocation_id, uint64_t seq_num,
1306 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1308 struct ldb_dn *dn = dsdb_dn->dn;
1309 const char *tstring, *usn_string, *flags_string;
1310 struct ldb_val tval;
1312 struct ldb_val usnv, local_usnv;
1313 struct ldb_val vers, flagsv;
1316 const char *dnstring;
1318 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1320 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1322 return LDB_ERR_OPERATIONS_ERROR;
1324 tval = data_blob_string_const(tstring);
1326 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1328 return LDB_ERR_OPERATIONS_ERROR;
1330 usnv = data_blob_string_const(usn_string);
1332 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1334 return LDB_ERR_OPERATIONS_ERROR;
1336 local_usnv = data_blob_string_const(usn_string);
1338 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1340 return LDB_ERR_OPERATIONS_ERROR;
1342 vers = data_blob_string_const(vstring);
1344 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1345 if (!NT_STATUS_IS_OK(status)) {
1346 return LDB_ERR_OPERATIONS_ERROR;
1349 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1350 if (!flags_string) {
1351 return LDB_ERR_OPERATIONS_ERROR;
1353 flagsv = data_blob_string_const(flags_string);
1355 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1356 if (ret != LDB_SUCCESS) return ret;
1357 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1358 if (ret != LDB_SUCCESS) return ret;
1359 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1360 if (ret != LDB_SUCCESS) return ret;
1361 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1362 if (ret != LDB_SUCCESS) return ret;
1363 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1364 if (ret != LDB_SUCCESS) return ret;
1365 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1366 if (ret != LDB_SUCCESS) return ret;
1367 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1368 if (ret != LDB_SUCCESS) return ret;
1370 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1371 if (dnstring == NULL) {
1372 return LDB_ERR_OPERATIONS_ERROR;
1374 *v = data_blob_string_const(dnstring);
1379 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1380 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1381 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1382 uint32_t version, bool deleted);
1385 check if any links need upgrading from w2k format
1387 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, const struct GUID *invocation_id)
1390 for (i=0; i<count; i++) {
1395 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1396 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1400 /* it's an old one that needs upgrading */
1401 ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1403 if (ret != LDB_SUCCESS) {
1411 update an extended DN, including all meta data fields
1413 see replmd_build_la_val for value names
1415 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1416 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1417 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1418 uint32_t version, bool deleted)
1420 struct ldb_dn *dn = dsdb_dn->dn;
1421 const char *tstring, *usn_string, *flags_string;
1422 struct ldb_val tval;
1424 struct ldb_val usnv, local_usnv;
1425 struct ldb_val vers, flagsv;
1426 const struct ldb_val *old_addtime;
1427 uint32_t old_version;
1430 const char *dnstring;
1432 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1434 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1436 return LDB_ERR_OPERATIONS_ERROR;
1438 tval = data_blob_string_const(tstring);
1440 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1442 return LDB_ERR_OPERATIONS_ERROR;
1444 usnv = data_blob_string_const(usn_string);
1446 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1448 return LDB_ERR_OPERATIONS_ERROR;
1450 local_usnv = data_blob_string_const(usn_string);
1452 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1453 if (!NT_STATUS_IS_OK(status)) {
1454 return LDB_ERR_OPERATIONS_ERROR;
1457 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1458 if (!flags_string) {
1459 return LDB_ERR_OPERATIONS_ERROR;
1461 flagsv = data_blob_string_const(flags_string);
1463 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1464 if (ret != LDB_SUCCESS) return ret;
1466 /* get the ADDTIME from the original */
1467 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1468 if (old_addtime == NULL) {
1469 old_addtime = &tval;
1471 if (dsdb_dn != old_dsdb_dn) {
1472 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1473 if (ret != LDB_SUCCESS) return ret;
1476 /* use our invocation id */
1477 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1478 if (ret != LDB_SUCCESS) return ret;
1480 /* changetime is the current time */
1481 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1482 if (ret != LDB_SUCCESS) return ret;
1484 /* update the USN */
1485 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1486 if (ret != LDB_SUCCESS) return ret;
1488 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1489 if (ret != LDB_SUCCESS) return ret;
1491 /* increase the version by 1 */
1492 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1493 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1494 version = old_version+1;
1496 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1497 vers = data_blob_string_const(vstring);
1498 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1499 if (ret != LDB_SUCCESS) return ret;
1501 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1502 if (dnstring == NULL) {
1503 return LDB_ERR_OPERATIONS_ERROR;
1505 *v = data_blob_string_const(dnstring);
1511 handle adding a linked attribute
1513 static int replmd_modify_la_add(struct ldb_module *module,
1514 struct dsdb_schema *schema,
1515 struct ldb_message *msg,
1516 struct ldb_message_element *el,
1517 struct ldb_message_element *old_el,
1518 const struct dsdb_attribute *schema_attr,
1521 struct GUID *msg_guid)
1524 struct parsed_dn *dns, *old_dns;
1525 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1527 struct ldb_val *new_values = NULL;
1528 unsigned int num_new_values = 0;
1529 unsigned old_num_values = old_el?old_el->num_values:0;
1530 const struct GUID *invocation_id;
1531 struct ldb_context *ldb = ldb_module_get_ctx(module);
1534 unix_to_nt_time(&now, t);
1536 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1537 if (ret != LDB_SUCCESS) {
1538 talloc_free(tmp_ctx);
1542 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1543 if (ret != LDB_SUCCESS) {
1544 talloc_free(tmp_ctx);
1548 invocation_id = samdb_ntds_invocation_id(ldb);
1549 if (!invocation_id) {
1550 talloc_free(tmp_ctx);
1551 return LDB_ERR_OPERATIONS_ERROR;
1554 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1555 if (ret != LDB_SUCCESS) {
1556 talloc_free(tmp_ctx);
1560 /* for each new value, see if it exists already with the same GUID */
1561 for (i=0; i<el->num_values; i++) {
1562 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1564 /* this is a new linked attribute value */
1565 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1566 if (new_values == NULL) {
1567 ldb_module_oom(module);
1568 talloc_free(tmp_ctx);
1569 return LDB_ERR_OPERATIONS_ERROR;
1571 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1572 invocation_id, seq_num, seq_num, now, 0, false);
1573 if (ret != LDB_SUCCESS) {
1574 talloc_free(tmp_ctx);
1579 /* this is only allowed if the GUID was
1580 previously deleted. */
1581 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1583 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1584 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1585 el->name, GUID_string(tmp_ctx, p->guid));
1586 talloc_free(tmp_ctx);
1587 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1589 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1590 invocation_id, seq_num, seq_num, now, 0, false);
1591 if (ret != LDB_SUCCESS) {
1592 talloc_free(tmp_ctx);
1597 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1598 if (ret != LDB_SUCCESS) {
1599 talloc_free(tmp_ctx);
1604 /* add the new ones on to the end of the old values, constructing a new el->values */
1605 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1607 old_num_values+num_new_values);
1608 if (el->values == NULL) {
1609 ldb_module_oom(module);
1610 return LDB_ERR_OPERATIONS_ERROR;
1613 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1614 el->num_values = old_num_values + num_new_values;
1616 talloc_steal(msg->elements, el->values);
1617 talloc_steal(el->values, new_values);
1619 talloc_free(tmp_ctx);
1621 /* we now tell the backend to replace all existing values
1622 with the one we have constructed */
1623 el->flags = LDB_FLAG_MOD_REPLACE;
1630 handle deleting all active linked attributes
1632 static int replmd_modify_la_delete(struct ldb_module *module,
1633 struct dsdb_schema *schema,
1634 struct ldb_message *msg,
1635 struct ldb_message_element *el,
1636 struct ldb_message_element *old_el,
1637 const struct dsdb_attribute *schema_attr,
1640 struct GUID *msg_guid)
1643 struct parsed_dn *dns, *old_dns;
1644 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1646 const struct GUID *invocation_id;
1647 struct ldb_context *ldb = ldb_module_get_ctx(module);
1650 unix_to_nt_time(&now, t);
1652 /* check if there is nothing to delete */
1653 if ((!old_el || old_el->num_values == 0) &&
1654 el->num_values == 0) {
1658 if (!old_el || old_el->num_values == 0) {
1659 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1662 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1663 if (ret != LDB_SUCCESS) {
1664 talloc_free(tmp_ctx);
1668 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1669 if (ret != LDB_SUCCESS) {
1670 talloc_free(tmp_ctx);
1674 invocation_id = samdb_ntds_invocation_id(ldb);
1675 if (!invocation_id) {
1676 return LDB_ERR_OPERATIONS_ERROR;
1679 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, invocation_id);
1680 if (ret != LDB_SUCCESS) {
1681 talloc_free(tmp_ctx);
1687 /* see if we are being asked to delete any links that
1688 don't exist or are already deleted */
1689 for (i=0; i<el->num_values; i++) {
1690 struct parsed_dn *p = &dns[i];
1691 struct parsed_dn *p2;
1694 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1696 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1697 el->name, GUID_string(tmp_ctx, p->guid));
1698 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1700 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1701 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1702 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1703 el->name, GUID_string(tmp_ctx, p->guid));
1704 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1708 /* for each new value, see if it exists already with the same GUID
1709 if it is not already deleted and matches the delete list then delete it
1711 for (i=0; i<old_el->num_values; i++) {
1712 struct parsed_dn *p = &old_dns[i];
1715 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1719 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1720 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1722 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1723 invocation_id, seq_num, seq_num, now, 0, true);
1724 if (ret != LDB_SUCCESS) {
1725 talloc_free(tmp_ctx);
1729 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1730 if (ret != LDB_SUCCESS) {
1731 talloc_free(tmp_ctx);
1736 el->values = talloc_steal(msg->elements, old_el->values);
1737 el->num_values = old_el->num_values;
1739 talloc_free(tmp_ctx);
1741 /* we now tell the backend to replace all existing values
1742 with the one we have constructed */
1743 el->flags = LDB_FLAG_MOD_REPLACE;
1749 handle replacing a linked attribute
1751 static int replmd_modify_la_replace(struct ldb_module *module,
1752 struct dsdb_schema *schema,
1753 struct ldb_message *msg,
1754 struct ldb_message_element *el,
1755 struct ldb_message_element *old_el,
1756 const struct dsdb_attribute *schema_attr,
1759 struct GUID *msg_guid)
1762 struct parsed_dn *dns, *old_dns;
1763 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1765 const struct GUID *invocation_id;
1766 struct ldb_context *ldb = ldb_module_get_ctx(module);
1767 struct ldb_val *new_values = NULL;
1768 uint32_t num_new_values = 0;
1769 unsigned old_num_values = old_el?old_el->num_values:0;
1772 unix_to_nt_time(&now, t);
1774 /* check if there is nothing to replace */
1775 if ((!old_el || old_el->num_values == 0) &&
1776 el->num_values == 0) {
1780 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1781 if (ret != LDB_SUCCESS) {
1782 talloc_free(tmp_ctx);
1786 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1787 if (ret != LDB_SUCCESS) {
1788 talloc_free(tmp_ctx);
1792 invocation_id = samdb_ntds_invocation_id(ldb);
1793 if (!invocation_id) {
1794 return LDB_ERR_OPERATIONS_ERROR;
1797 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1798 if (ret != LDB_SUCCESS) {
1799 talloc_free(tmp_ctx);
1803 /* mark all the old ones as deleted */
1804 for (i=0; i<old_num_values; i++) {
1805 struct parsed_dn *old_p = &old_dns[i];
1806 struct parsed_dn *p;
1807 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1809 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1811 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1812 if (ret != LDB_SUCCESS) {
1813 talloc_free(tmp_ctx);
1817 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1819 /* we don't delete it if we are re-adding it */
1823 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1824 invocation_id, seq_num, seq_num, now, 0, true);
1825 if (ret != LDB_SUCCESS) {
1826 talloc_free(tmp_ctx);
1831 /* for each new value, either update its meta-data, or add it
1834 for (i=0; i<el->num_values; i++) {
1835 struct parsed_dn *p = &dns[i], *old_p;
1838 (old_p = parsed_dn_find(old_dns,
1839 old_num_values, p->guid, NULL)) != NULL) {
1840 /* update in place */
1841 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1842 old_p->dsdb_dn, invocation_id,
1843 seq_num, seq_num, now, 0, false);
1844 if (ret != LDB_SUCCESS) {
1845 talloc_free(tmp_ctx);
1850 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1852 if (new_values == NULL) {
1853 ldb_module_oom(module);
1854 talloc_free(tmp_ctx);
1855 return LDB_ERR_OPERATIONS_ERROR;
1857 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1858 invocation_id, seq_num, seq_num, now, 0, false);
1859 if (ret != LDB_SUCCESS) {
1860 talloc_free(tmp_ctx);
1866 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1867 if (ret != LDB_SUCCESS) {
1868 talloc_free(tmp_ctx);
1873 /* add the new values to the end of old_el */
1874 if (num_new_values != 0) {
1875 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1876 struct ldb_val, old_num_values+num_new_values);
1877 if (el->values == NULL) {
1878 ldb_module_oom(module);
1879 return LDB_ERR_OPERATIONS_ERROR;
1881 memcpy(&el->values[old_num_values], &new_values[0],
1882 sizeof(struct ldb_val)*num_new_values);
1883 el->num_values = old_num_values + num_new_values;
1884 talloc_steal(msg->elements, new_values);
1886 el->values = old_el->values;
1887 el->num_values = old_el->num_values;
1888 talloc_steal(msg->elements, el->values);
1891 talloc_free(tmp_ctx);
1893 /* we now tell the backend to replace all existing values
1894 with the one we have constructed */
1895 el->flags = LDB_FLAG_MOD_REPLACE;
1902 handle linked attributes in modify requests
1904 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1905 struct ldb_message *msg,
1906 uint64_t seq_num, time_t t)
1908 struct ldb_result *res;
1910 struct ldb_context *ldb = ldb_module_get_ctx(module);
1911 struct ldb_message *old_msg;
1912 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1913 struct GUID old_guid;
1916 /* there the replmd_update_rpmd code has already
1917 * checked and saw that there are no linked
1922 #if !W2K3_LINKED_ATTRIBUTES
1926 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1927 /* don't do anything special for linked attributes */
1931 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1932 DSDB_SEARCH_SHOW_DELETED |
1933 DSDB_SEARCH_REVEAL_INTERNALS |
1934 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1935 if (ret != LDB_SUCCESS) {
1938 old_msg = res->msgs[0];
1940 old_guid = samdb_result_guid(old_msg, "objectGUID");
1942 for (i=0; i<msg->num_elements; i++) {
1943 struct ldb_message_element *el = &msg->elements[i];
1944 struct ldb_message_element *old_el, *new_el;
1945 const struct dsdb_attribute *schema_attr
1946 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1948 ldb_asprintf_errstring(ldb,
1949 "attribute %s is not a valid attribute in schema", el->name);
1950 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1952 if (schema_attr->linkID == 0) {
1955 if ((schema_attr->linkID & 1) == 1) {
1956 /* Odd is for the target. Illegal to modify */
1957 ldb_asprintf_errstring(ldb,
1958 "attribute %s must not be modified directly, it is a linked attribute", el->name);
1959 return LDB_ERR_UNWILLING_TO_PERFORM;
1961 old_el = ldb_msg_find_element(old_msg, el->name);
1962 switch (el->flags & LDB_FLAG_MOD_MASK) {
1963 case LDB_FLAG_MOD_REPLACE:
1964 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1966 case LDB_FLAG_MOD_DELETE:
1967 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1969 case LDB_FLAG_MOD_ADD:
1970 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1973 ldb_asprintf_errstring(ldb,
1974 "invalid flags 0x%x for %s linked attribute",
1975 el->flags, el->name);
1976 return LDB_ERR_UNWILLING_TO_PERFORM;
1978 if (ret != LDB_SUCCESS) {
1982 ldb_msg_remove_attr(old_msg, el->name);
1984 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
1985 new_el->num_values = el->num_values;
1986 new_el->values = talloc_steal(msg->elements, el->values);
1988 /* TODO: this relises a bit too heavily on the exact
1989 behaviour of ldb_msg_find_element and
1990 ldb_msg_remove_element */
1991 old_el = ldb_msg_find_element(msg, el->name);
1993 ldb_msg_remove_element(msg, old_el);
2004 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2006 struct ldb_context *ldb;
2007 struct replmd_replicated_request *ac;
2008 struct ldb_request *down_req;
2009 struct ldb_message *msg;
2010 time_t t = time(NULL);
2012 bool is_urgent = false;
2014 /* do not manipulate our control entries */
2015 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2016 return ldb_next_request(module, req);
2019 ldb = ldb_module_get_ctx(module);
2021 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2023 ac = replmd_ctx_init(module, req);
2025 return LDB_ERR_OPERATIONS_ERROR;
2028 /* we have to copy the message as the caller might have it as a const */
2029 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2033 return LDB_ERR_OPERATIONS_ERROR;
2036 ldb_msg_remove_attr(msg, "whenChanged");
2037 ldb_msg_remove_attr(msg, "uSNChanged");
2039 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t, &is_urgent);
2040 if (ret != LDB_SUCCESS) {
2045 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
2046 if (ret != LDB_SUCCESS) {
2052 * - replace the old object with the newly constructed one
2055 ac->is_urgent = is_urgent;
2057 ret = ldb_build_mod_req(&down_req, ldb, ac,
2060 ac, replmd_op_callback,
2062 if (ret != LDB_SUCCESS) {
2066 talloc_steal(down_req, msg);
2068 /* we only change whenChanged and uSNChanged if the seq_num
2070 if (ac->seq_num != 0) {
2071 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2076 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2082 /* go on with the call chain */
2083 return ldb_next_request(module, down_req);
2086 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2089 handle a rename request
2091 On a rename we need to do an extra ldb_modify which sets the
2092 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2094 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2096 struct ldb_context *ldb;
2097 struct replmd_replicated_request *ac;
2099 struct ldb_request *down_req;
2101 /* do not manipulate our control entries */
2102 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2103 return ldb_next_request(module, req);
2106 ldb = ldb_module_get_ctx(module);
2108 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2110 ac = replmd_ctx_init(module, req);
2112 return LDB_ERR_OPERATIONS_ERROR;
2114 ret = ldb_build_rename_req(&down_req, ldb, ac,
2115 ac->req->op.rename.olddn,
2116 ac->req->op.rename.newdn,
2118 ac, replmd_rename_callback,
2121 if (ret != LDB_SUCCESS) {
2126 /* go on with the call chain */
2127 return ldb_next_request(module, down_req);
2130 /* After the rename is compleated, update the whenchanged etc */
2131 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2133 struct ldb_context *ldb;
2134 struct replmd_replicated_request *ac;
2135 struct ldb_request *down_req;
2136 struct ldb_message *msg;
2137 time_t t = time(NULL);
2140 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2141 ldb = ldb_module_get_ctx(ac->module);
2143 if (ares->error != LDB_SUCCESS) {
2144 return ldb_module_done(ac->req, ares->controls,
2145 ares->response, ares->error);
2148 if (ares->type != LDB_REPLY_DONE) {
2149 ldb_set_errstring(ldb,
2150 "invalid ldb_reply_type in callback");
2152 return ldb_module_done(ac->req, NULL, NULL,
2153 LDB_ERR_OPERATIONS_ERROR);
2156 /* Get a sequence number from the backend */
2157 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2158 if (ret != LDB_SUCCESS) {
2163 * - replace the old object with the newly constructed one
2166 msg = ldb_msg_new(ac);
2169 return LDB_ERR_OPERATIONS_ERROR;
2172 msg->dn = ac->req->op.rename.newdn;
2174 ret = ldb_build_mod_req(&down_req, ldb, ac,
2177 ac, replmd_op_callback,
2180 if (ret != LDB_SUCCESS) {
2184 talloc_steal(down_req, msg);
2186 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2191 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2196 /* go on with the call chain - do the modify after the rename */
2197 return ldb_next_request(ac->module, down_req);
2201 remove links from objects that point at this object when an object
2204 static int replmd_delete_remove_link(struct ldb_module *module,
2205 struct dsdb_schema *schema,
2207 struct ldb_message_element *el,
2208 const struct dsdb_attribute *sa)
2211 TALLOC_CTX *tmp_ctx = talloc_new(module);
2212 struct ldb_context *ldb = ldb_module_get_ctx(module);
2214 for (i=0; i<el->num_values; i++) {
2215 struct dsdb_dn *dsdb_dn;
2219 struct ldb_message *msg;
2220 const struct dsdb_attribute *target_attr;
2221 struct ldb_message_element *el2;
2222 struct ldb_val dn_val;
2224 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2228 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2230 talloc_free(tmp_ctx);
2231 return LDB_ERR_OPERATIONS_ERROR;
2234 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2235 if (!NT_STATUS_IS_OK(status)) {
2236 talloc_free(tmp_ctx);
2237 return LDB_ERR_OPERATIONS_ERROR;
2240 /* remove the link */
2241 msg = ldb_msg_new(tmp_ctx);
2243 ldb_module_oom(module);
2244 talloc_free(tmp_ctx);
2245 return LDB_ERR_OPERATIONS_ERROR;
2249 msg->dn = dsdb_dn->dn;
2251 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2252 if (target_attr == NULL) {
2256 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2257 if (ret != LDB_SUCCESS) {
2258 ldb_module_oom(module);
2259 talloc_free(tmp_ctx);
2260 return LDB_ERR_OPERATIONS_ERROR;
2262 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2263 el2->values = &dn_val;
2264 el2->num_values = 1;
2266 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2267 if (ret != LDB_SUCCESS) {
2268 talloc_free(tmp_ctx);
2272 talloc_free(tmp_ctx);
2278 handle update of replication meta data for deletion of objects
2280 This also handles the mapping of delete to a rename operation
2281 to allow deletes to be replicated.
2283 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2285 int ret = LDB_ERR_OTHER;
2287 struct ldb_dn *old_dn, *new_dn;
2288 const char *rdn_name;
2289 const struct ldb_val *rdn_value, *new_rdn_value;
2291 struct ldb_context *ldb = ldb_module_get_ctx(module);
2292 struct dsdb_schema *schema = dsdb_get_schema(ldb);
2293 struct ldb_message *msg, *old_msg;
2294 struct ldb_message_element *el;
2295 TALLOC_CTX *tmp_ctx;
2296 struct ldb_result *res, *parent_res;
2297 const char *preserved_attrs[] = {
2298 /* yes, this really is a hard coded list. See MS-ADTS
2299 section 3.1.1.5.5.1.1 */
2300 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2301 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2302 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2303 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2304 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2305 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2306 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2307 "whenChanged", NULL};
2308 uint32_t el_count = 0;
2311 if (ldb_dn_is_special(req->op.del.dn)) {
2312 return ldb_next_request(module, req);
2315 tmp_ctx = talloc_new(ldb);
2317 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2319 /* we need the complete msg off disk, so we can work out which
2320 attributes need to be removed */
2321 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2322 DSDB_SEARCH_SHOW_DELETED |
2323 DSDB_SEARCH_REVEAL_INTERNALS |
2324 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2325 if (ret != LDB_SUCCESS) {
2326 talloc_free(tmp_ctx);
2329 old_msg = res->msgs[0];
2331 if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2332 struct auth_session_info *session_info =
2333 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2334 if (security_session_user_level(session_info) != SECURITY_SYSTEM) {
2335 ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2336 ldb_dn_get_linearized(old_msg->dn));
2337 return LDB_ERR_UNWILLING_TO_PERFORM;
2340 /* it is already deleted - really remove it this time */
2341 talloc_free(tmp_ctx);
2342 return ldb_next_request(module, req);
2345 /* work out where we will be renaming this object to */
2346 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2347 if (ret != LDB_SUCCESS) {
2348 /* this is probably an attempted delete on a partition
2349 * that doesn't allow delete operations, such as the
2350 * schema partition */
2351 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2352 ldb_dn_get_linearized(old_dn));
2353 talloc_free(tmp_ctx);
2354 return LDB_ERR_UNWILLING_TO_PERFORM;
2357 rdn_name = ldb_dn_get_rdn_name(old_dn);
2358 rdn_value = ldb_dn_get_rdn_val(old_dn);
2360 /* get the objects GUID from the search we just did */
2361 guid = samdb_result_guid(old_msg, "objectGUID");
2363 /* Add a formatted child */
2364 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2367 GUID_string(tmp_ctx, &guid));
2369 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2370 ldb_dn_get_linearized(new_dn)));
2371 talloc_free(tmp_ctx);
2372 return LDB_ERR_OPERATIONS_ERROR;
2376 now we need to modify the object in the following ways:
2378 - add isDeleted=TRUE
2379 - update rDN and name, with new rDN
2380 - remove linked attributes
2381 - remove objectCategory and sAMAccountType
2382 - remove attribs not on the preserved list
2383 - preserved if in above list, or is rDN
2384 - remove all linked attribs from this object
2385 - remove all links from other objects to this object
2386 - add lastKnownParent
2387 - update replPropertyMetaData?
2389 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2392 msg = ldb_msg_new(tmp_ctx);
2394 ldb_module_oom(module);
2395 talloc_free(tmp_ctx);
2396 return LDB_ERR_OPERATIONS_ERROR;
2401 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2402 if (ret != LDB_SUCCESS) {
2403 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2404 ldb_module_oom(module);
2405 talloc_free(tmp_ctx);
2408 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2410 /* we also mark it as recycled, meaning this object can't be
2411 recovered (we are stripping its attributes) */
2412 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2413 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2414 if (ret != LDB_SUCCESS) {
2415 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2416 ldb_module_oom(module);
2417 talloc_free(tmp_ctx);
2420 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2423 /* we need the storage form of the parent GUID */
2424 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2425 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2426 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2427 DSDB_SEARCH_REVEAL_INTERNALS);
2428 if (ret != LDB_SUCCESS) {
2429 talloc_free(tmp_ctx);
2433 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2434 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2435 if (ret != LDB_SUCCESS) {
2436 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2437 ldb_module_oom(module);
2438 talloc_free(tmp_ctx);
2441 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2443 /* work out which of the old attributes we will be removing */
2444 for (i=0; i<old_msg->num_elements; i++) {
2445 const struct dsdb_attribute *sa;
2446 el = &old_msg->elements[i];
2447 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2449 talloc_free(tmp_ctx);
2450 return LDB_ERR_OPERATIONS_ERROR;
2452 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2453 /* don't remove the rDN */
2457 if (sa->linkID && sa->linkID & 1) {
2458 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2459 if (ret != LDB_SUCCESS) {
2460 talloc_free(tmp_ctx);
2461 return LDB_ERR_OPERATIONS_ERROR;
2466 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2470 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2471 if (ret != LDB_SUCCESS) {
2472 talloc_free(tmp_ctx);
2473 ldb_module_oom(module);
2478 /* work out what the new rdn value is, for updating the
2479 rDN and name fields */
2480 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2481 ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el);
2482 if (ret != LDB_SUCCESS) {
2483 talloc_free(tmp_ctx);
2486 el->flags = LDB_FLAG_MOD_REPLACE;
2488 el = ldb_msg_find_element(old_msg, "name");
2490 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2491 if (ret != LDB_SUCCESS) {
2492 talloc_free(tmp_ctx);
2495 el->flags = LDB_FLAG_MOD_REPLACE;
2498 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2499 if (ret != LDB_SUCCESS) {
2500 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2501 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2502 talloc_free(tmp_ctx);
2506 /* now rename onto the new DN */
2507 ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2508 if (ret != LDB_SUCCESS){
2509 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2510 ldb_dn_get_linearized(old_dn),
2511 ldb_dn_get_linearized(new_dn),
2512 ldb_errstring(ldb)));
2513 talloc_free(tmp_ctx);
2517 talloc_free(tmp_ctx);
2519 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2524 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2529 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2531 int ret = LDB_ERR_OTHER;
2532 /* TODO: do some error mapping */
2536 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2538 struct ldb_context *ldb;
2539 struct ldb_request *change_req;
2540 enum ndr_err_code ndr_err;
2541 struct ldb_message *msg;
2542 struct replPropertyMetaDataBlob *md;
2543 struct ldb_val md_value;
2548 * TODO: check if the parent object exist
2552 * TODO: handle the conflict case where an object with the
2556 ldb = ldb_module_get_ctx(ar->module);
2557 msg = ar->objs->objects[ar->index_current].msg;
2558 md = ar->objs->objects[ar->index_current].meta_data;
2560 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2561 if (ret != LDB_SUCCESS) {
2562 return replmd_replicated_request_error(ar, ret);
2565 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2566 if (ret != LDB_SUCCESS) {
2567 return replmd_replicated_request_error(ar, ret);
2570 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2571 if (ret != LDB_SUCCESS) {
2572 return replmd_replicated_request_error(ar, ret);
2575 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2576 if (ret != LDB_SUCCESS) {
2577 return replmd_replicated_request_error(ar, ret);
2580 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2581 if (ret != LDB_SUCCESS) {
2582 return replmd_replicated_request_error(ar, ret);
2585 /* remove any message elements that have zero values */
2586 for (i=0; i<msg->num_elements; i++) {
2587 struct ldb_message_element *el = &msg->elements[i];
2589 if (el->num_values == 0) {
2590 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2592 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2593 msg->num_elements--;
2600 * the meta data array is already sorted by the caller
2602 for (i=0; i < md->ctr.ctr1.count; i++) {
2603 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2605 ndr_err = ndr_push_struct_blob(&md_value, msg,
2606 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2608 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2609 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2610 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2611 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2613 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2614 if (ret != LDB_SUCCESS) {
2615 return replmd_replicated_request_error(ar, ret);
2618 replmd_ldb_message_sort(msg, ar->schema);
2621 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2622 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2626 ret = ldb_build_add_req(&change_req,
2634 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2636 return ldb_next_request(ar->module, change_req);
2640 return true if an update is newer than an existing entry
2641 see section 5.11 of MS-ADTS
2643 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2644 const struct GUID *update_invocation_id,
2645 uint32_t current_version,
2646 uint32_t update_version,
2647 NTTIME current_change_time,
2648 NTTIME update_change_time)
2650 if (update_version != current_version) {
2651 return update_version > current_version;
2653 if (update_change_time > current_change_time) {
2656 if (update_change_time == current_change_time) {
2657 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2662 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2663 struct replPropertyMetaData1 *new_m)
2665 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2666 &new_m->originating_invocation_id,
2669 cur_m->originating_change_time,
2670 new_m->originating_change_time);
2673 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2675 struct ldb_context *ldb;
2676 struct ldb_request *change_req;
2677 enum ndr_err_code ndr_err;
2678 struct ldb_message *msg;
2679 struct replPropertyMetaDataBlob *rmd;
2680 struct replPropertyMetaDataBlob omd;
2681 const struct ldb_val *omd_value;
2682 struct replPropertyMetaDataBlob nmd;
2683 struct ldb_val nmd_value;
2685 uint32_t removed_attrs = 0;
2688 ldb = ldb_module_get_ctx(ar->module);
2689 msg = ar->objs->objects[ar->index_current].msg;
2690 rmd = ar->objs->objects[ar->index_current].meta_data;
2695 * TODO: check repl data is correct after a rename
2697 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2698 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2699 ldb_dn_get_linearized(ar->search_msg->dn),
2700 ldb_dn_get_linearized(msg->dn));
2701 if (dsdb_module_rename(ar->module,
2702 ar->search_msg->dn, msg->dn,
2703 DSDB_FLAG_OWN_MODULE) != LDB_SUCCESS) {
2704 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2705 ldb_dn_get_linearized(ar->search_msg->dn),
2706 ldb_dn_get_linearized(msg->dn),
2707 ldb_errstring(ldb));
2708 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2712 /* find existing meta data */
2713 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2715 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2716 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2717 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2718 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2719 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2720 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2723 if (omd.version != 1) {
2724 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2730 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2731 nmd.ctr.ctr1.array = talloc_array(ar,
2732 struct replPropertyMetaData1,
2733 nmd.ctr.ctr1.count);
2734 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2736 /* first copy the old meta data */
2737 for (i=0; i < omd.ctr.ctr1.count; i++) {
2738 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2742 /* now merge in the new meta data */
2743 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2746 for (j=0; j < ni; j++) {
2749 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2753 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2754 &rmd->ctr.ctr1.array[i]);
2756 /* replace the entry */
2757 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2762 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType) {
2763 DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n",
2764 msg->elements[i-removed_attrs].name,
2765 ldb_dn_get_linearized(msg->dn),
2766 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2769 /* we don't want to apply this change so remove the attribute */
2770 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2777 if (found) continue;
2779 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2784 * finally correct the size of the meta_data array
2786 nmd.ctr.ctr1.count = ni;
2789 * the rdn attribute (the alias for the name attribute),
2790 * 'cn' for most objects is the last entry in the meta data array
2793 * sort the new meta data array
2795 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2796 if (ret != LDB_SUCCESS) {
2801 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2803 if (msg->num_elements == 0) {
2804 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2807 ar->index_current++;
2808 return replmd_replicated_apply_next(ar);
2811 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2812 ar->index_current, msg->num_elements);
2814 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2815 if (ret != LDB_SUCCESS) {
2816 return replmd_replicated_request_error(ar, ret);
2819 for (i=0; i<ni; i++) {
2820 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2823 /* create the meta data value */
2824 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
2825 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2827 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2828 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2829 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2830 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2834 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2835 * and replPopertyMetaData attributes
2837 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2838 if (ret != LDB_SUCCESS) {
2839 return replmd_replicated_request_error(ar, ret);
2841 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2842 if (ret != LDB_SUCCESS) {
2843 return replmd_replicated_request_error(ar, ret);
2845 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2846 if (ret != LDB_SUCCESS) {
2847 return replmd_replicated_request_error(ar, ret);
2850 replmd_ldb_message_sort(msg, ar->schema);
2852 /* we want to replace the old values */
2853 for (i=0; i < msg->num_elements; i++) {
2854 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2858 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2859 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2863 ret = ldb_build_mod_req(&change_req,
2871 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2873 return ldb_next_request(ar->module, change_req);
2876 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2877 struct ldb_reply *ares)
2879 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2880 struct replmd_replicated_request);
2884 return ldb_module_done(ar->req, NULL, NULL,
2885 LDB_ERR_OPERATIONS_ERROR);
2887 if (ares->error != LDB_SUCCESS &&
2888 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2889 return ldb_module_done(ar->req, ares->controls,
2890 ares->response, ares->error);
2893 switch (ares->type) {
2894 case LDB_REPLY_ENTRY:
2895 ar->search_msg = talloc_steal(ar, ares->message);
2898 case LDB_REPLY_REFERRAL:
2899 /* we ignore referrals */
2902 case LDB_REPLY_DONE:
2903 if (ar->search_msg != NULL) {
2904 ret = replmd_replicated_apply_merge(ar);
2906 ret = replmd_replicated_apply_add(ar);
2908 if (ret != LDB_SUCCESS) {
2909 return ldb_module_done(ar->req, NULL, NULL, ret);
2917 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2919 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2921 struct ldb_context *ldb;
2925 struct ldb_request *search_req;
2926 struct ldb_search_options_control *options;
2928 if (ar->index_current >= ar->objs->num_objects) {
2929 /* done with it, go to next stage */
2930 return replmd_replicated_uptodate_vector(ar);
2933 ldb = ldb_module_get_ctx(ar->module);
2934 ar->search_msg = NULL;
2936 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2937 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2939 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2940 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2941 talloc_free(tmp_str);
2943 ret = ldb_build_search_req(&search_req,
2952 replmd_replicated_apply_search_callback,
2955 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2956 if (ret != LDB_SUCCESS) {
2960 /* we need to cope with cross-partition links, so search for
2961 the GUID over all partitions */
2962 options = talloc(search_req, struct ldb_search_options_control);
2963 if (options == NULL) {
2964 DEBUG(0, (__location__ ": out of memory\n"));
2965 return LDB_ERR_OPERATIONS_ERROR;
2967 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2969 ret = ldb_request_add_control(search_req,
2970 LDB_CONTROL_SEARCH_OPTIONS_OID,
2972 if (ret != LDB_SUCCESS) {
2976 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2978 return ldb_next_request(ar->module, search_req);
2981 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2982 struct ldb_reply *ares)
2984 struct ldb_context *ldb;
2985 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2986 struct replmd_replicated_request);
2987 ldb = ldb_module_get_ctx(ar->module);
2990 return ldb_module_done(ar->req, NULL, NULL,
2991 LDB_ERR_OPERATIONS_ERROR);
2993 if (ares->error != LDB_SUCCESS) {
2994 return ldb_module_done(ar->req, ares->controls,
2995 ares->response, ares->error);
2998 if (ares->type != LDB_REPLY_DONE) {
2999 ldb_set_errstring(ldb, "Invalid reply type\n!");
3000 return ldb_module_done(ar->req, NULL, NULL,
3001 LDB_ERR_OPERATIONS_ERROR);
3006 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3009 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3011 struct ldb_context *ldb;
3012 struct ldb_request *change_req;
3013 enum ndr_err_code ndr_err;
3014 struct ldb_message *msg;
3015 struct replUpToDateVectorBlob ouv;
3016 const struct ldb_val *ouv_value;
3017 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3018 struct replUpToDateVectorBlob nuv;
3019 struct ldb_val nuv_value;
3020 struct ldb_message_element *nuv_el = NULL;
3021 const struct GUID *our_invocation_id;
3022 struct ldb_message_element *orf_el = NULL;
3023 struct repsFromToBlob nrf;
3024 struct ldb_val *nrf_value = NULL;
3025 struct ldb_message_element *nrf_el = NULL;
3028 time_t t = time(NULL);
3032 ldb = ldb_module_get_ctx(ar->module);
3033 ruv = ar->objs->uptodateness_vector;
3039 unix_to_nt_time(&now, t);
3042 * first create the new replUpToDateVector
3044 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
3046 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
3047 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
3048 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3049 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3050 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3051 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3054 if (ouv.version != 2) {
3055 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3060 * the new uptodateness vector will at least
3061 * contain 1 entry, one for the source_dsa
3063 * plus optional values from our old vector and the one from the source_dsa
3065 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
3066 if (ruv) nuv.ctr.ctr2.count += ruv->count;
3067 nuv.ctr.ctr2.cursors = talloc_array(ar,
3068 struct drsuapi_DsReplicaCursor2,
3069 nuv.ctr.ctr2.count);
3070 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3072 /* first copy the old vector */
3073 for (i=0; i < ouv.ctr.ctr2.count; i++) {
3074 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
3078 /* get our invocation_id if we have one already attached to the ldb */
3079 our_invocation_id = samdb_ntds_invocation_id(ldb);
3081 /* merge in the source_dsa vector is available */
3082 for (i=0; (ruv && i < ruv->count); i++) {
3085 if (our_invocation_id &&
3086 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3087 our_invocation_id)) {
3091 for (j=0; j < ni; j++) {
3092 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3093 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3100 * we update only the highest_usn and not the latest_sync_success time,
3101 * because the last success stands for direct replication
3103 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3104 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3109 if (found) continue;
3111 /* if it's not there yet, add it */
3112 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3117 * merge in the current highwatermark for the source_dsa
3120 for (j=0; j < ni; j++) {
3121 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
3122 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3129 * here we update the highest_usn and last_sync_success time
3130 * because we're directly replicating from the source_dsa
3132 * and use the tmp_highest_usn because this is what we have just applied
3135 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3136 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
3141 * here we update the highest_usn and last_sync_success time
3142 * because we're directly replicating from the source_dsa
3144 * and use the tmp_highest_usn because this is what we have just applied
3147 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
3148 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3149 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
3154 * finally correct the size of the cursors array
3156 nuv.ctr.ctr2.count = ni;
3161 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
3164 * create the change ldb_message
3166 msg = ldb_msg_new(ar);
3167 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3168 msg->dn = ar->search_msg->dn;
3170 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
3171 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3173 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3174 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3175 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3176 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3178 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3179 if (ret != LDB_SUCCESS) {
3180 return replmd_replicated_request_error(ar, ret);
3182 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3185 * now create the new repsFrom value from the given repsFromTo1 structure
3189 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3190 /* and fix some values... */
3191 nrf.ctr.ctr1.consecutive_sync_failures = 0;
3192 nrf.ctr.ctr1.last_success = now;
3193 nrf.ctr.ctr1.last_attempt = now;
3194 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
3195 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3198 * first see if we already have a repsFrom value for the current source dsa
3199 * if so we'll later replace this value
3201 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3203 for (i=0; i < orf_el->num_values; i++) {
3204 struct repsFromToBlob *trf;
3206 trf = talloc(ar, struct repsFromToBlob);
3207 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3209 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
3210 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3211 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3212 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3213 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3216 if (trf->version != 1) {
3217 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3221 * we compare the source dsa objectGUID not the invocation_id
3222 * because we want only one repsFrom value per source dsa
3223 * and when the invocation_id of the source dsa has changed we don't need
3224 * the old repsFrom with the old invocation_id
3226 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3227 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3233 nrf_value = &orf_el->values[i];
3238 * copy over all old values to the new ldb_message
3240 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3241 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3246 * if we haven't found an old repsFrom value for the current source dsa
3247 * we'll add a new value
3250 struct ldb_val zero_value;
3251 ZERO_STRUCT(zero_value);
3252 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3253 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3255 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3258 /* we now fill the value which is already attached to ldb_message */
3259 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3260 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3262 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3263 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3264 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3265 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3269 * the ldb_message_element for the attribute, has all the old values and the new one
3270 * so we'll replace the whole attribute with all values
3272 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3275 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3276 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3280 /* prepare the ldb_modify() request */
3281 ret = ldb_build_mod_req(&change_req,
3287 replmd_replicated_uptodate_modify_callback,
3289 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3291 return ldb_next_request(ar->module, change_req);
3294 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3295 struct ldb_reply *ares)
3297 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3298 struct replmd_replicated_request);
3302 return ldb_module_done(ar->req, NULL, NULL,
3303 LDB_ERR_OPERATIONS_ERROR);
3305 if (ares->error != LDB_SUCCESS &&
3306 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3307 return ldb_module_done(ar->req, ares->controls,
3308 ares->response, ares->error);
3311 switch (ares->type) {
3312 case LDB_REPLY_ENTRY:
3313 ar->search_msg = talloc_steal(ar, ares->message);
3316 case LDB_REPLY_REFERRAL:
3317 /* we ignore referrals */
3320 case LDB_REPLY_DONE:
3321 if (ar->search_msg == NULL) {
3322 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3324 ret = replmd_replicated_uptodate_modify(ar);
3326 if (ret != LDB_SUCCESS) {
3327 return ldb_module_done(ar->req, NULL, NULL, ret);
3336 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3338 struct ldb_context *ldb;
3340 static const char *attrs[] = {
3341 "replUpToDateVector",
3345 struct ldb_request *search_req;
3347 ldb = ldb_module_get_ctx(ar->module);
3348 ar->search_msg = NULL;
3350 ret = ldb_build_search_req(&search_req,
3353 ar->objs->partition_dn,
3359 replmd_replicated_uptodate_search_callback,
3361 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3363 return ldb_next_request(ar->module, search_req);
3368 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3370 struct ldb_context *ldb;
3371 struct dsdb_extended_replicated_objects *objs;
3372 struct replmd_replicated_request *ar;
3373 struct ldb_control **ctrls;
3375 struct replmd_private *replmd_private =
3376 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3378 ldb = ldb_module_get_ctx(module);
3380 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3382 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3384 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3385 return LDB_ERR_PROTOCOL_ERROR;
3388 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3389 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3390 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3391 return LDB_ERR_PROTOCOL_ERROR;
3394 ar = replmd_ctx_init(module, req);
3396 return LDB_ERR_OPERATIONS_ERROR;
3398 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3399 ar->apply_mode = true;
3401 ar->schema = dsdb_get_schema(ldb);
3403 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3405 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3406 return LDB_ERR_CONSTRAINT_VIOLATION;
3409 ctrls = req->controls;
3411 if (req->controls) {
3412 req->controls = talloc_memdup(ar, req->controls,
3413 talloc_get_size(req->controls));
3414 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3417 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3418 if (ret != LDB_SUCCESS) {
3422 ar->controls = req->controls;
3423 req->controls = ctrls;
3425 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3427 /* save away the linked attributes for the end of the
3429 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3430 struct la_entry *la_entry;
3432 if (replmd_private->la_ctx == NULL) {
3433 replmd_private->la_ctx = talloc_new(replmd_private);
3435 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3436 if (la_entry == NULL) {
3438 return LDB_ERR_OPERATIONS_ERROR;
3440 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3441 if (la_entry->la == NULL) {
3442 talloc_free(la_entry);
3444 return LDB_ERR_OPERATIONS_ERROR;
3446 *la_entry->la = ar->objs->linked_attributes[i];
3448 /* we need to steal the non-scalars so they stay
3449 around until the end of the transaction */
3450 talloc_steal(la_entry->la, la_entry->la->identifier);
3451 talloc_steal(la_entry->la, la_entry->la->value.blob);
3453 DLIST_ADD(replmd_private->la_list, la_entry);
3456 return replmd_replicated_apply_next(ar);
3460 process one linked attribute structure
3462 static int replmd_process_linked_attribute(struct ldb_module *module,
3463 struct la_entry *la_entry)
3465 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3466 struct ldb_context *ldb = ldb_module_get_ctx(module);
3467 struct dsdb_schema *schema = dsdb_get_schema(ldb);
3468 struct ldb_message *msg;
3469 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3471 const struct dsdb_attribute *attr;
3472 struct dsdb_dn *dsdb_dn;
3473 uint64_t seq_num = 0;
3474 struct ldb_message_element *old_el;
3476 time_t t = time(NULL);
3477 struct ldb_result *res;
3478 const char *attrs[2];
3479 struct parsed_dn *pdn_list, *pdn;
3480 struct GUID guid = GUID_zero();
3482 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3483 const struct GUID *our_invocation_id;
3486 linked_attributes[0]:
3487 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3489 identifier: struct drsuapi_DsReplicaObjectIdentifier
3490 __ndr_size : 0x0000003a (58)
3491 __ndr_size_sid : 0x00000000 (0)
3492 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3494 __ndr_size_dn : 0x00000000 (0)
3496 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3497 value: struct drsuapi_DsAttributeValue
3498 __ndr_size : 0x0000007e (126)
3500 blob : DATA_BLOB length=126
3501 flags : 0x00000001 (1)
3502 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3503 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3504 meta_data: struct drsuapi_DsReplicaMetaData
3505 version : 0x00000015 (21)
3506 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3507 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3508 originating_usn : 0x000000000001e19c (123292)
3510 (for cases where the link is to a normal DN)
3511 &target: struct drsuapi_DsReplicaObjectIdentifier3
3512 __ndr_size : 0x0000007e (126)
3513 __ndr_size_sid : 0x0000001c (28)
3514 guid : 7639e594-db75-4086-b0d4-67890ae46031
3515 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3516 __ndr_size_dn : 0x00000022 (34)
3517 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3520 /* find the attribute being modified */
3521 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3523 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3524 talloc_free(tmp_ctx);
3525 return LDB_ERR_OPERATIONS_ERROR;
3528 attrs[0] = attr->lDAPDisplayName;
3531 /* get the existing message from the db for the object with
3532 this GUID, returning attribute being modified. We will then
3533 use this msg as the basis for a modify call */
3534 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3535 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3536 DSDB_SEARCH_SHOW_DELETED |
3537 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3538 DSDB_SEARCH_REVEAL_INTERNALS,
3539 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3540 if (ret != LDB_SUCCESS) {
3541 talloc_free(tmp_ctx);
3544 if (res->count != 1) {
3545 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3546 GUID_string(tmp_ctx, &la->identifier->guid));
3547 talloc_free(tmp_ctx);
3548 return LDB_ERR_NO_SUCH_OBJECT;
3552 if (msg->num_elements == 0) {
3553 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3554 if (ret != LDB_SUCCESS) {
3555 ldb_module_oom(module);
3556 talloc_free(tmp_ctx);
3557 return LDB_ERR_OPERATIONS_ERROR;
3560 old_el = &msg->elements[0];
3561 old_el->flags = LDB_FLAG_MOD_REPLACE;
3564 /* parse the existing links */
3565 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3566 if (ret != LDB_SUCCESS) {
3567 talloc_free(tmp_ctx);
3571 /* get our invocationId */
3572 our_invocation_id = samdb_ntds_invocation_id(ldb);
3573 if (!our_invocation_id) {
3574 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
3575 talloc_free(tmp_ctx);
3576 return LDB_ERR_OPERATIONS_ERROR;
3579 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, our_invocation_id);
3580 if (ret != LDB_SUCCESS) {
3581 talloc_free(tmp_ctx);
3585 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
3586 if (!W_ERROR_IS_OK(status)) {
3587 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
3588 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
3589 return LDB_ERR_OPERATIONS_ERROR;
3592 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3593 if (!NT_STATUS_IS_OK(ntstatus) && active) {
3594 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
3596 ldb_dn_get_linearized(dsdb_dn->dn),
3597 ldb_dn_get_linearized(msg->dn));
3598 return LDB_ERR_OPERATIONS_ERROR;
3601 /* re-resolve the DN by GUID, as the DRS server may give us an
3603 ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn);
3604 if (ret != LDB_SUCCESS) {
3605 ldb_asprintf_errstring(ldb, __location__ ": Failed to re-resolve GUID %s",
3606 GUID_string(tmp_ctx, &guid));
3607 talloc_free(tmp_ctx);
3611 /* see if this link already exists */
3612 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
3614 /* see if this update is newer than what we have already */
3615 struct GUID invocation_id = GUID_zero();
3616 uint32_t version = 0;
3617 NTTIME change_time = 0;
3618 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
3620 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3621 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3622 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3624 if (!replmd_update_is_newer(&invocation_id,
3625 &la->meta_data.originating_invocation_id,
3627 la->meta_data.version,
3629 la->meta_data.originating_change_time)) {
3630 DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3631 old_el->name, ldb_dn_get_linearized(msg->dn),
3632 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3633 talloc_free(tmp_ctx);
3637 /* get a seq_num for this change */
3638 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3639 if (ret != LDB_SUCCESS) {
3640 talloc_free(tmp_ctx);
3644 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
3645 /* remove the existing backlink */
3646 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3647 if (ret != LDB_SUCCESS) {
3648 talloc_free(tmp_ctx);
3653 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3654 &la->meta_data.originating_invocation_id,
3655 la->meta_data.originating_usn, seq_num,
3656 la->meta_data.originating_change_time,
3657 la->meta_data.version,
3659 if (ret != LDB_SUCCESS) {
3660 talloc_free(tmp_ctx);
3665 /* add the new backlink */
3666 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3667 if (ret != LDB_SUCCESS) {
3668 talloc_free(tmp_ctx);
3673 /* get a seq_num for this change */
3674 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3675 if (ret != LDB_SUCCESS) {
3676 talloc_free(tmp_ctx);
3680 old_el->values = talloc_realloc(msg->elements, old_el->values,
3681 struct ldb_val, old_el->num_values+1);
3682 if (!old_el->values) {
3683 ldb_module_oom(module);
3684 return LDB_ERR_OPERATIONS_ERROR;
3686 old_el->num_values++;
3688 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3689 &la->meta_data.originating_invocation_id,
3690 la->meta_data.originating_usn, seq_num,
3691 la->meta_data.originating_change_time,
3692 la->meta_data.version,
3693 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3694 if (ret != LDB_SUCCESS) {
3695 talloc_free(tmp_ctx);
3700 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3702 if (ret != LDB_SUCCESS) {
3703 talloc_free(tmp_ctx);
3709 /* we only change whenChanged and uSNChanged if the seq_num
3711 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3712 talloc_free(tmp_ctx);
3713 return LDB_ERR_OPERATIONS_ERROR;
3716 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3717 talloc_free(tmp_ctx);
3718 return LDB_ERR_OPERATIONS_ERROR;
3721 ret = dsdb_check_single_valued_link(attr, old_el);
3722 if (ret != LDB_SUCCESS) {
3723 talloc_free(tmp_ctx);
3727 ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
3728 if (ret != LDB_SUCCESS) {
3729 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
3731 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3732 talloc_free(tmp_ctx);
3736 talloc_free(tmp_ctx);
3741 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3743 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3744 return replmd_extended_replicated_objects(module, req);
3747 return ldb_next_request(module, req);
3752 we hook into the transaction operations to allow us to
3753 perform the linked attribute updates at the end of the whole
3754 transaction. This allows a forward linked attribute to be created
3755 before the object is created. During a vampire, w2k8 sends us linked
3756 attributes before the objects they are part of.
3758 static int replmd_start_transaction(struct ldb_module *module)
3760 /* create our private structure for this transaction */
3761 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3762 struct replmd_private);
3763 replmd_txn_cleanup(replmd_private);
3765 /* free any leftover mod_usn records from cancelled
3767 while (replmd_private->ncs) {
3768 struct nc_entry *e = replmd_private->ncs;
3769 DLIST_REMOVE(replmd_private->ncs, e);
3773 return ldb_next_start_trans(module);
3777 on prepare commit we loop over our queued la_context structures and
3780 static int replmd_prepare_commit(struct ldb_module *module)
3782 struct replmd_private *replmd_private =
3783 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3784 struct la_entry *la, *prev;
3785 struct la_backlink *bl;
3788 /* walk the list backwards, to do the first entry first, as we
3789 * added the entries with DLIST_ADD() which puts them at the
3790 * start of the list */
3791 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
3792 prev = DLIST_PREV(la);
3793 DLIST_REMOVE(replmd_private->la_list, la);
3794 ret = replmd_process_linked_attribute(module, la);
3795 if (ret != LDB_SUCCESS) {
3796 replmd_txn_cleanup(replmd_private);
3801 /* process our backlink list, creating and deleting backlinks
3803 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3804 ret = replmd_process_backlink(module, bl);
3805 if (ret != LDB_SUCCESS) {
3806 replmd_txn_cleanup(replmd_private);
3811 replmd_txn_cleanup(replmd_private);
3813 /* possibly change @REPLCHANGED */
3814 ret = replmd_notify_store(module);
3815 if (ret != LDB_SUCCESS) {
3819 return ldb_next_prepare_commit(module);
3822 static int replmd_del_transaction(struct ldb_module *module)
3824 struct replmd_private *replmd_private =
3825 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3826 replmd_txn_cleanup(replmd_private);
3828 return ldb_next_del_trans(module);
3832 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3833 .name = "repl_meta_data",
3834 .init_context = replmd_init,
3836 .modify = replmd_modify,
3837 .rename = replmd_rename,
3838 .del = replmd_delete,
3839 .extended = replmd_extended,
3840 .start_transaction = replmd_start_transaction,
3841 .prepare_commit = replmd_prepare_commit,
3842 .del_transaction = replmd_del_transaction,