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
8 Copyright (C) Matthieu Patou <mat@samba.org> 2010
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 * Component: ldb repl_meta_data module
29 * Description: - add a unique objectGUID onto every new record,
30 * - handle whenCreated, whenChanged timestamps
31 * - handle uSNCreated, uSNChanged numbers
32 * - handle replPropertyMetaData attribute
35 * Author: Stefan Metzmacher
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "../libds/common/flags.h"
43 #include "librpc/gen_ndr/ndr_misc.h"
44 #include "librpc/gen_ndr/ndr_drsuapi.h"
45 #include "librpc/gen_ndr/ndr_drsblobs.h"
46 #include "param/param.h"
47 #include "libcli/security/security.h"
48 #include "lib/util/dlinklist.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
50 #include "lib/util/binsearch.h"
51 #include "lib/util/tsort.h"
53 struct replmd_private {
55 struct la_entry *la_list;
57 struct la_backlink *la_backlinks;
59 struct nc_entry *prev, *next;
62 uint64_t mod_usn_urgent;
67 struct la_entry *next, *prev;
68 struct drsuapi_DsReplicaLinkedAttribute *la;
71 struct replmd_replicated_request {
72 struct ldb_module *module;
73 struct ldb_request *req;
75 const struct dsdb_schema *schema;
77 /* the controls we pass down */
78 struct ldb_control **controls;
80 /* details for the mode where we apply a bunch of inbound replication meessages */
82 uint32_t index_current;
83 struct dsdb_extended_replicated_objects *objs;
85 struct ldb_message *search_msg;
91 enum urgent_situation {
92 REPL_URGENT_ON_CREATE = 1,
93 REPL_URGENT_ON_UPDATE = 2,
94 REPL_URGENT_ON_DELETE = 4
99 const char *update_name;
100 enum urgent_situation repl_situation;
101 } urgent_objects[] = {
102 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
103 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
104 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
105 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
106 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
107 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
111 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
112 static const char *urgent_attrs[] = {
115 "userAccountControl",
120 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
121 enum urgent_situation situation)
124 for (i=0; urgent_objects[i].update_name; i++) {
126 if ((situation & urgent_objects[i].repl_situation) == 0) {
130 for (j=0; j<objectclass_el->num_values; j++) {
131 const struct ldb_val *v = &objectclass_el->values[j];
132 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
140 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
142 if (ldb_attr_in_list(urgent_attrs, el->name)) {
149 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
152 initialise the module
153 allocate the private structure and build the list
154 of partition DNs for use by replmd_notify()
156 static int replmd_init(struct ldb_module *module)
158 struct replmd_private *replmd_private;
159 struct ldb_context *ldb = ldb_module_get_ctx(module);
161 replmd_private = talloc_zero(module, struct replmd_private);
162 if (replmd_private == NULL) {
164 return LDB_ERR_OPERATIONS_ERROR;
166 ldb_module_set_private(module, replmd_private);
168 return ldb_next_init(module);
172 cleanup our per-transaction contexts
174 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
176 talloc_free(replmd_private->la_ctx);
177 replmd_private->la_list = NULL;
178 replmd_private->la_ctx = NULL;
180 talloc_free(replmd_private->bl_ctx);
181 replmd_private->la_backlinks = NULL;
182 replmd_private->bl_ctx = NULL;
187 struct la_backlink *next, *prev;
188 const char *attr_name;
189 struct GUID forward_guid, target_guid;
194 process a backlinks we accumulated during a transaction, adding and
195 deleting the backlinks from the target objects
197 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
199 struct ldb_dn *target_dn, *source_dn;
201 struct ldb_context *ldb = ldb_module_get_ctx(module);
202 struct ldb_message *msg;
203 TALLOC_CTX *tmp_ctx = talloc_new(bl);
209 - construct ldb_message
210 - either an add or a delete
212 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
213 if (ret != LDB_SUCCESS) {
214 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
215 GUID_string(bl, &bl->target_guid)));
219 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
220 if (ret != LDB_SUCCESS) {
221 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
222 GUID_string(bl, &bl->forward_guid));
223 talloc_free(tmp_ctx);
227 msg = ldb_msg_new(tmp_ctx);
229 ldb_module_oom(module);
230 talloc_free(tmp_ctx);
231 return LDB_ERR_OPERATIONS_ERROR;
234 /* construct a ldb_message for adding/deleting the backlink */
236 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
238 ldb_module_oom(module);
239 talloc_free(tmp_ctx);
240 return LDB_ERR_OPERATIONS_ERROR;
242 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
243 if (ret != LDB_SUCCESS) {
244 talloc_free(tmp_ctx);
247 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
249 /* a backlink should never be single valued. Unfortunately the
250 exchange schema has a attribute
251 msExchBridgeheadedLocalConnectorsDNBL which is single
252 valued and a backlink. We need to cope with that by
253 ignoring the single value flag */
254 msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
256 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
257 if (ret != LDB_SUCCESS) {
258 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
259 bl->active?"add":"remove",
260 ldb_dn_get_linearized(source_dn),
261 ldb_dn_get_linearized(target_dn),
263 talloc_free(tmp_ctx);
266 talloc_free(tmp_ctx);
271 add a backlink to the list of backlinks to add/delete in the prepare
274 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
275 struct GUID *forward_guid, struct GUID *target_guid,
276 bool active, const struct dsdb_attribute *schema_attr, bool immediate)
278 const struct dsdb_attribute *target_attr;
279 struct la_backlink *bl;
280 struct replmd_private *replmd_private =
281 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
283 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
286 * windows 2003 has a broken schema where the
287 * definition of msDS-IsDomainFor is missing (which is
288 * supposed to be the backlink of the
289 * msDS-HasDomainNCs attribute
294 /* see if its already in the list */
295 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
296 if (GUID_equal(forward_guid, &bl->forward_guid) &&
297 GUID_equal(target_guid, &bl->target_guid) &&
298 (target_attr->lDAPDisplayName == bl->attr_name ||
299 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
305 /* we found an existing one */
306 if (bl->active == active) {
309 DLIST_REMOVE(replmd_private->la_backlinks, bl);
314 if (replmd_private->bl_ctx == NULL) {
315 replmd_private->bl_ctx = talloc_new(replmd_private);
316 if (replmd_private->bl_ctx == NULL) {
317 ldb_module_oom(module);
318 return LDB_ERR_OPERATIONS_ERROR;
323 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
325 ldb_module_oom(module);
326 return LDB_ERR_OPERATIONS_ERROR;
329 /* Ensure the schema does not go away before the bl->attr_name is used */
330 if (!talloc_reference(bl, schema)) {
332 ldb_module_oom(module);
333 return LDB_ERR_OPERATIONS_ERROR;
336 bl->attr_name = target_attr->lDAPDisplayName;
337 bl->forward_guid = *forward_guid;
338 bl->target_guid = *target_guid;
341 /* the caller may ask for this backlink to be processed
344 int ret = replmd_process_backlink(module, bl, NULL);
349 DLIST_ADD(replmd_private->la_backlinks, bl);
356 * Callback for most write operations in this module:
358 * notify the repl task that a object has changed. The notifies are
359 * gathered up in the replmd_private structure then written to the
360 * @REPLCHANGED object in each partition during the prepare_commit
362 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
365 struct replmd_replicated_request *ac =
366 talloc_get_type_abort(req->context, struct replmd_replicated_request);
367 struct replmd_private *replmd_private =
368 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
369 struct nc_entry *modified_partition;
370 struct ldb_control *partition_ctrl;
371 const struct dsdb_control_current_partition *partition;
373 struct ldb_control **controls;
375 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
377 controls = ares->controls;
378 if (ldb_request_get_control(ac->req,
379 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
381 * Remove the current partition control from what we pass up
382 * the chain if it hasn't been requested manually.
384 controls = ldb_controls_except_specified(ares->controls, ares,
388 if (ares->error != LDB_SUCCESS) {
389 DEBUG(0,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
390 return ldb_module_done(ac->req, controls,
391 ares->response, ares->error);
394 if (ares->type != LDB_REPLY_DONE) {
395 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
396 return ldb_module_done(ac->req, NULL,
397 NULL, LDB_ERR_OPERATIONS_ERROR);
400 if (!partition_ctrl) {
401 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
402 return ldb_module_done(ac->req, NULL,
403 NULL, LDB_ERR_OPERATIONS_ERROR);
406 partition = talloc_get_type_abort(partition_ctrl->data,
407 struct dsdb_control_current_partition);
409 if (ac->seq_num > 0) {
410 for (modified_partition = replmd_private->ncs; modified_partition;
411 modified_partition = modified_partition->next) {
412 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
417 if (modified_partition == NULL) {
418 modified_partition = talloc_zero(replmd_private, struct nc_entry);
419 if (!modified_partition) {
420 ldb_oom(ldb_module_get_ctx(ac->module));
421 return ldb_module_done(ac->req, NULL,
422 NULL, LDB_ERR_OPERATIONS_ERROR);
424 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
425 if (!modified_partition->dn) {
426 ldb_oom(ldb_module_get_ctx(ac->module));
427 return ldb_module_done(ac->req, NULL,
428 NULL, LDB_ERR_OPERATIONS_ERROR);
430 DLIST_ADD(replmd_private->ncs, modified_partition);
433 if (ac->seq_num > modified_partition->mod_usn) {
434 modified_partition->mod_usn = ac->seq_num;
436 modified_partition->mod_usn_urgent = ac->seq_num;
441 if (ac->apply_mode) {
445 ret = replmd_replicated_apply_next(ac);
446 if (ret != LDB_SUCCESS) {
447 return ldb_module_done(ac->req, NULL, NULL, ret);
451 /* free the partition control container here, for the
452 * common path. Other cases will have it cleaned up
453 * eventually with the ares */
454 talloc_free(partition_ctrl);
455 return ldb_module_done(ac->req, controls,
456 ares->response, LDB_SUCCESS);
462 * update a @REPLCHANGED record in each partition if there have been
463 * any writes of replicated data in the partition
465 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
467 struct replmd_private *replmd_private =
468 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
470 while (replmd_private->ncs) {
472 struct nc_entry *modified_partition = replmd_private->ncs;
474 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
475 modified_partition->mod_usn,
476 modified_partition->mod_usn_urgent, parent);
477 if (ret != LDB_SUCCESS) {
478 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
479 ldb_dn_get_linearized(modified_partition->dn)));
482 DLIST_REMOVE(replmd_private->ncs, modified_partition);
483 talloc_free(modified_partition);
491 created a replmd_replicated_request context
493 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
494 struct ldb_request *req)
496 struct ldb_context *ldb;
497 struct replmd_replicated_request *ac;
499 ldb = ldb_module_get_ctx(module);
501 ac = talloc_zero(req, struct replmd_replicated_request);
510 ac->schema = dsdb_get_schema(ldb, ac);
512 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
513 "replmd_modify: no dsdb_schema loaded");
514 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
522 add a time element to a record
524 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
526 struct ldb_message_element *el;
530 if (ldb_msg_find_element(msg, attr) != NULL) {
534 s = ldb_timestring(msg, t);
536 return LDB_ERR_OPERATIONS_ERROR;
539 ret = ldb_msg_add_string(msg, attr, s);
540 if (ret != LDB_SUCCESS) {
544 el = ldb_msg_find_element(msg, attr);
545 /* always set as replace. This works because on add ops, the flag
547 el->flags = LDB_FLAG_MOD_REPLACE;
553 add a uint64_t element to a record
555 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
556 const char *attr, uint64_t v)
558 struct ldb_message_element *el;
561 if (ldb_msg_find_element(msg, attr) != NULL) {
565 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
566 if (ret != LDB_SUCCESS) {
570 el = ldb_msg_find_element(msg, attr);
571 /* always set as replace. This works because on add ops, the flag
573 el->flags = LDB_FLAG_MOD_REPLACE;
578 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
579 const struct replPropertyMetaData1 *m2,
580 const uint32_t *rdn_attid)
582 if (m1->attid == m2->attid) {
587 * the rdn attribute should be at the end!
588 * so we need to return a value greater than zero
589 * which means m1 is greater than m2
591 if (m1->attid == *rdn_attid) {
596 * the rdn attribute should be at the end!
597 * so we need to return a value less than zero
598 * which means m2 is greater than m1
600 if (m2->attid == *rdn_attid) {
604 return m1->attid > m2->attid ? 1 : -1;
607 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
608 const struct dsdb_schema *schema,
611 const char *rdn_name;
612 const struct dsdb_attribute *rdn_sa;
614 rdn_name = ldb_dn_get_rdn_name(dn);
616 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
617 return LDB_ERR_OPERATIONS_ERROR;
620 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
621 if (rdn_sa == NULL) {
622 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
623 return LDB_ERR_OPERATIONS_ERROR;
626 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
627 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
629 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
634 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
635 const struct ldb_message_element *e2,
636 const struct dsdb_schema *schema)
638 const struct dsdb_attribute *a1;
639 const struct dsdb_attribute *a2;
642 * TODO: make this faster by caching the dsdb_attribute pointer
643 * on the ldb_messag_element
646 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
647 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
650 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
654 return strcasecmp(e1->name, e2->name);
656 if (a1->attributeID_id == a2->attributeID_id) {
659 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
662 static void replmd_ldb_message_sort(struct ldb_message *msg,
663 const struct dsdb_schema *schema)
665 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
668 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
669 const struct GUID *invocation_id, uint64_t seq_num,
670 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
674 fix up linked attributes in replmd_add.
675 This involves setting up the right meta-data in extended DN
676 components, and creating backlinks to the object
678 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
679 uint64_t seq_num, const struct GUID *invocationId, time_t t,
680 struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
683 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
684 struct ldb_context *ldb = ldb_module_get_ctx(module);
686 /* We will take a reference to the schema in replmd_add_backlink */
687 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
690 unix_to_nt_time(&now, t);
692 for (i=0; i<el->num_values; i++) {
693 struct ldb_val *v = &el->values[i];
694 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
695 struct GUID target_guid;
699 /* note that the DN already has the extended
700 components from the extended_dn_store module */
701 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
702 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
703 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
704 if (ret != LDB_SUCCESS) {
705 talloc_free(tmp_ctx);
708 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
709 if (ret != LDB_SUCCESS) {
710 talloc_free(tmp_ctx);
715 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
716 seq_num, seq_num, now, 0, false);
717 if (ret != LDB_SUCCESS) {
718 talloc_free(tmp_ctx);
722 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
723 if (ret != LDB_SUCCESS) {
724 talloc_free(tmp_ctx);
729 talloc_free(tmp_ctx);
735 intercept add requests
737 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
739 struct ldb_context *ldb;
740 struct ldb_control *control;
741 struct replmd_replicated_request *ac;
742 enum ndr_err_code ndr_err;
743 struct ldb_request *down_req;
744 struct ldb_message *msg;
745 const DATA_BLOB *guid_blob;
747 struct replPropertyMetaDataBlob nmd;
748 struct ldb_val nmd_value;
749 const struct GUID *our_invocation_id;
750 time_t t = time(NULL);
755 unsigned int functional_level;
757 bool allow_add_guid = false;
758 bool remove_current_guid = false;
759 bool is_urgent = false;
760 struct ldb_message_element *objectclass_el;
762 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
763 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
765 allow_add_guid = true;
768 /* do not manipulate our control entries */
769 if (ldb_dn_is_special(req->op.add.message->dn)) {
770 return ldb_next_request(module, req);
773 ldb = ldb_module_get_ctx(module);
775 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
777 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
778 if (guid_blob != NULL) {
779 if (!allow_add_guid) {
780 ldb_set_errstring(ldb,
781 "replmd_add: it's not allowed to add an object with objectGUID!");
782 return LDB_ERR_UNWILLING_TO_PERFORM;
784 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
785 if (!NT_STATUS_IS_OK(status)) {
786 ldb_set_errstring(ldb,
787 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
788 return LDB_ERR_UNWILLING_TO_PERFORM;
790 /* we remove this attribute as it can be a string and
791 * will not be treated correctly and then we will re-add
792 * it later on in the good format */
793 remove_current_guid = true;
797 guid = GUID_random();
800 ac = replmd_ctx_init(module, req);
802 return ldb_module_oom(module);
805 functional_level = dsdb_functional_level(ldb);
807 /* Get a sequence number from the backend */
808 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
809 if (ret != LDB_SUCCESS) {
814 /* get our invocationId */
815 our_invocation_id = samdb_ntds_invocation_id(ldb);
816 if (!our_invocation_id) {
817 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
818 "replmd_add: unable to find invocationId\n");
820 return LDB_ERR_OPERATIONS_ERROR;
823 /* we have to copy the message as the caller might have it as a const */
824 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
828 return LDB_ERR_OPERATIONS_ERROR;
831 /* generated times */
832 unix_to_nt_time(&now, t);
833 time_str = ldb_timestring(msg, t);
837 return LDB_ERR_OPERATIONS_ERROR;
839 if (remove_current_guid) {
840 ldb_msg_remove_attr(msg,"objectGUID");
844 * remove autogenerated attributes
846 ldb_msg_remove_attr(msg, "whenCreated");
847 ldb_msg_remove_attr(msg, "whenChanged");
848 ldb_msg_remove_attr(msg, "uSNCreated");
849 ldb_msg_remove_attr(msg, "uSNChanged");
850 ldb_msg_remove_attr(msg, "replPropertyMetaData");
853 * readd replicated attributes
855 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
856 if (ret != LDB_SUCCESS) {
862 /* build the replication meta_data */
865 nmd.ctr.ctr1.count = msg->num_elements;
866 nmd.ctr.ctr1.array = talloc_array(msg,
867 struct replPropertyMetaData1,
869 if (!nmd.ctr.ctr1.array) {
872 return LDB_ERR_OPERATIONS_ERROR;
875 for (i=0; i < msg->num_elements; i++) {
876 struct ldb_message_element *e = &msg->elements[i];
877 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
878 const struct dsdb_attribute *sa;
880 if (e->name[0] == '@') continue;
882 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
884 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
885 "replmd_add: attribute '%s' not defined in schema\n",
888 return LDB_ERR_NO_SUCH_ATTRIBUTE;
891 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
892 /* if the attribute is not replicated (0x00000001)
893 * or constructed (0x00000004) it has no metadata
898 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
899 ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa, req);
900 if (ret != LDB_SUCCESS) {
904 /* linked attributes are not stored in
905 replPropertyMetaData in FL above w2k */
909 m->attid = sa->attributeID_id;
911 m->originating_change_time = now;
912 m->originating_invocation_id = *our_invocation_id;
913 m->originating_usn = ac->seq_num;
914 m->local_usn = ac->seq_num;
918 /* fix meta data count */
919 nmd.ctr.ctr1.count = ni;
922 * sort meta data array, and move the rdn attribute entry to the end
924 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
925 if (ret != LDB_SUCCESS) {
930 /* generated NDR encoded values */
931 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
933 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
934 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
937 return LDB_ERR_OPERATIONS_ERROR;
941 * add the autogenerated values
943 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
944 if (ret != LDB_SUCCESS) {
949 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
950 if (ret != LDB_SUCCESS) {
955 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
956 if (ret != LDB_SUCCESS) {
961 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
962 if (ret != LDB_SUCCESS) {
967 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
968 if (ret != LDB_SUCCESS) {
975 * sort the attributes by attid before storing the object
977 replmd_ldb_message_sort(msg, ac->schema);
979 objectclass_el = ldb_msg_find_element(msg, "objectClass");
980 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
981 REPL_URGENT_ON_CREATE);
983 ac->is_urgent = is_urgent;
984 ret = ldb_build_add_req(&down_req, ldb, ac,
987 ac, replmd_op_callback,
990 LDB_REQ_SET_LOCATION(down_req);
991 if (ret != LDB_SUCCESS) {
996 /* current partition control is needed by "replmd_op_callback" */
997 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
998 ret = ldb_request_add_control(down_req,
999 DSDB_CONTROL_CURRENT_PARTITION_OID,
1001 if (ret != LDB_SUCCESS) {
1007 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1008 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1009 if (ret != LDB_SUCCESS) {
1015 /* mark the control done */
1017 control->critical = 0;
1020 /* go on with the call chain */
1021 return ldb_next_request(module, down_req);
1026 * update the replPropertyMetaData for one element
1028 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1029 struct ldb_message *msg,
1030 struct ldb_message_element *el,
1031 struct ldb_message_element *old_el,
1032 struct replPropertyMetaDataBlob *omd,
1033 const struct dsdb_schema *schema,
1035 const struct GUID *our_invocation_id,
1039 const struct dsdb_attribute *a;
1040 struct replPropertyMetaData1 *md1;
1042 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1044 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1046 return LDB_ERR_OPERATIONS_ERROR;
1049 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1053 /* if the attribute's value haven't changed then return LDB_SUCCESS */
1054 if (old_el != NULL && ldb_msg_element_compare(el, old_el) == 0) {
1058 for (i=0; i<omd->ctr.ctr1.count; i++) {
1059 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1062 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1063 /* linked attributes are not stored in
1064 replPropertyMetaData in FL above w2k, but we do
1065 raise the seqnum for the object */
1066 if (*seq_num == 0 &&
1067 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1068 return LDB_ERR_OPERATIONS_ERROR;
1073 if (i == omd->ctr.ctr1.count) {
1074 /* we need to add a new one */
1075 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1076 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1077 if (omd->ctr.ctr1.array == NULL) {
1079 return LDB_ERR_OPERATIONS_ERROR;
1081 omd->ctr.ctr1.count++;
1082 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1085 /* Get a new sequence number from the backend. We only do this
1086 * if we have a change that requires a new
1087 * replPropertyMetaData element
1089 if (*seq_num == 0) {
1090 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1091 if (ret != LDB_SUCCESS) {
1092 return LDB_ERR_OPERATIONS_ERROR;
1096 md1 = &omd->ctr.ctr1.array[i];
1098 md1->attid = a->attributeID_id;
1099 md1->originating_change_time = now;
1100 md1->originating_invocation_id = *our_invocation_id;
1101 md1->originating_usn = *seq_num;
1102 md1->local_usn = *seq_num;
1107 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1109 uint32_t count = omd.ctr.ctr1.count;
1112 for (i=0; i < count; i++) {
1113 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1114 if (max < m.local_usn) {
1122 * update the replPropertyMetaData object each time we modify an
1123 * object. This is needed for DRS replication, as the merge on the
1124 * client is based on this object
1126 static int replmd_update_rpmd(struct ldb_module *module,
1127 const struct dsdb_schema *schema,
1128 struct ldb_request *req,
1129 struct ldb_message *msg, uint64_t *seq_num,
1133 const struct ldb_val *omd_value;
1134 enum ndr_err_code ndr_err;
1135 struct replPropertyMetaDataBlob omd;
1138 const struct GUID *our_invocation_id;
1140 const char *attrs[] = { "replPropertyMetaData", "*", NULL };
1141 const char *attrs2[] = { "uSNChanged", "objectClass", NULL };
1142 struct ldb_result *res;
1143 struct ldb_context *ldb;
1144 struct ldb_message_element *objectclass_el;
1145 enum urgent_situation situation;
1146 bool rodc, rmd_is_provided;
1148 ldb = ldb_module_get_ctx(module);
1150 our_invocation_id = samdb_ntds_invocation_id(ldb);
1151 if (!our_invocation_id) {
1152 /* this happens during an initial vampire while
1153 updating the schema */
1154 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1158 unix_to_nt_time(&now, t);
1160 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1161 rmd_is_provided = true;
1163 rmd_is_provided = false;
1166 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1167 * otherwise we consider we are updating */
1168 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1169 situation = REPL_URGENT_ON_DELETE;
1171 situation = REPL_URGENT_ON_UPDATE;
1174 if (rmd_is_provided) {
1175 /* In this case the change_replmetadata control was supplied */
1176 /* We check that it's the only attribute that is provided
1177 * (it's a rare case so it's better to keep the code simplier)
1178 * We also check that the highest local_usn is bigger than
1181 if( msg->num_elements != 1 ||
1182 strncmp(msg->elements[0].name,
1183 "replPropertyMetaData", 20) ) {
1184 DEBUG(0,(__location__ ": changereplmetada control called without "\
1185 "a specified replPropertyMetaData attribute or with others\n"));
1186 return LDB_ERR_OPERATIONS_ERROR;
1188 if (situation == REPL_URGENT_ON_DELETE) {
1189 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1190 return LDB_ERR_OPERATIONS_ERROR;
1192 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1194 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1195 ldb_dn_get_linearized(msg->dn)));
1196 return LDB_ERR_OPERATIONS_ERROR;
1198 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1199 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1200 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1201 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1202 ldb_dn_get_linearized(msg->dn)));
1203 return LDB_ERR_OPERATIONS_ERROR;
1205 *seq_num = find_max_local_usn(omd);
1207 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1208 DSDB_FLAG_NEXT_MODULE |
1209 DSDB_SEARCH_SHOW_RECYCLED |
1210 DSDB_SEARCH_SHOW_EXTENDED_DN |
1211 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1212 DSDB_SEARCH_REVEAL_INTERNALS, req);
1214 if (ret != LDB_SUCCESS || res->count != 1) {
1215 DEBUG(0,(__location__ ": Object %s failed to find uSNChanged\n",
1216 ldb_dn_get_linearized(msg->dn)));
1217 return LDB_ERR_OPERATIONS_ERROR;
1220 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1221 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1226 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1227 if (*seq_num <= db_seq) {
1228 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\
1229 " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n",
1230 (long long)*seq_num, (long long)db_seq));
1231 return LDB_ERR_OPERATIONS_ERROR;
1235 /* search for the existing replPropertyMetaDataBlob. We need
1236 * to use REVEAL and ask for DNs in storage format to support
1237 * the check for values being the same in
1238 * replmd_update_rpmd_element()
1240 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1241 DSDB_FLAG_NEXT_MODULE |
1242 DSDB_SEARCH_SHOW_RECYCLED |
1243 DSDB_SEARCH_SHOW_EXTENDED_DN |
1244 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1245 DSDB_SEARCH_REVEAL_INTERNALS, req);
1246 if (ret != LDB_SUCCESS || res->count != 1) {
1247 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1248 ldb_dn_get_linearized(msg->dn)));
1249 return LDB_ERR_OPERATIONS_ERROR;
1252 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1253 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1258 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1260 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1261 ldb_dn_get_linearized(msg->dn)));
1262 return LDB_ERR_OPERATIONS_ERROR;
1265 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1266 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1267 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1268 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1269 ldb_dn_get_linearized(msg->dn)));
1270 return LDB_ERR_OPERATIONS_ERROR;
1273 if (omd.version != 1) {
1274 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1275 omd.version, ldb_dn_get_linearized(msg->dn)));
1276 return LDB_ERR_OPERATIONS_ERROR;
1279 for (i=0; i<msg->num_elements; i++) {
1280 struct ldb_message_element *old_el;
1281 old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1282 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1283 our_invocation_id, now);
1284 if (ret != LDB_SUCCESS) {
1288 if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1289 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1295 * replmd_update_rpmd_element has done an update if the
1298 if (*seq_num != 0) {
1299 struct ldb_val *md_value;
1300 struct ldb_message_element *el;
1302 /*if we are RODC and this is a DRSR update then its ok*/
1303 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1304 ret = samdb_rodc(ldb, &rodc);
1305 if (ret != LDB_SUCCESS) {
1306 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1308 ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n");
1309 return LDB_ERR_REFERRAL;
1313 md_value = talloc(msg, struct ldb_val);
1314 if (md_value == NULL) {
1316 return LDB_ERR_OPERATIONS_ERROR;
1319 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1320 if (ret != LDB_SUCCESS) {
1324 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1325 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1326 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1327 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1328 ldb_dn_get_linearized(msg->dn)));
1329 return LDB_ERR_OPERATIONS_ERROR;
1332 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1333 if (ret != LDB_SUCCESS) {
1334 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1335 ldb_dn_get_linearized(msg->dn)));
1340 el->values = md_value;
1347 struct dsdb_dn *dsdb_dn;
1352 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1354 return GUID_compare(pdn1->guid, pdn2->guid);
1357 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1358 unsigned int count, struct GUID *guid,
1361 struct parsed_dn *ret;
1363 if (dn && GUID_all_zero(guid)) {
1364 /* when updating a link using DRS, we sometimes get a
1365 NULL GUID. We then need to try and match by DN */
1366 for (i=0; i<count; i++) {
1367 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1368 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1374 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1379 get a series of message element values as an array of DNs and GUIDs
1380 the result is sorted by GUID
1382 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1383 struct ldb_message_element *el, struct parsed_dn **pdn,
1384 const char *ldap_oid, struct ldb_request *parent)
1387 struct ldb_context *ldb = ldb_module_get_ctx(module);
1394 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1396 ldb_module_oom(module);
1397 return LDB_ERR_OPERATIONS_ERROR;
1400 for (i=0; i<el->num_values; i++) {
1401 struct ldb_val *v = &el->values[i];
1404 struct parsed_dn *p;
1408 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1409 if (p->dsdb_dn == NULL) {
1410 return LDB_ERR_INVALID_DN_SYNTAX;
1413 dn = p->dsdb_dn->dn;
1415 p->guid = talloc(*pdn, struct GUID);
1416 if (p->guid == NULL) {
1417 ldb_module_oom(module);
1418 return LDB_ERR_OPERATIONS_ERROR;
1421 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1422 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1423 /* we got a DN without a GUID - go find the GUID */
1424 int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1425 if (ret != LDB_SUCCESS) {
1426 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1427 ldb_dn_get_linearized(dn));
1430 ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1431 if (ret != LDB_SUCCESS) {
1434 } else if (!NT_STATUS_IS_OK(status)) {
1435 return LDB_ERR_OPERATIONS_ERROR;
1438 /* keep a pointer to the original ldb_val */
1442 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1448 build a new extended DN, including all meta data fields
1450 RMD_FLAGS = DSDB_RMD_FLAG_* bits
1451 RMD_ADDTIME = originating_add_time
1452 RMD_INVOCID = originating_invocation_id
1453 RMD_CHANGETIME = originating_change_time
1454 RMD_ORIGINATING_USN = originating_usn
1455 RMD_LOCAL_USN = local_usn
1456 RMD_VERSION = version
1458 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1459 const struct GUID *invocation_id, uint64_t seq_num,
1460 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1462 struct ldb_dn *dn = dsdb_dn->dn;
1463 const char *tstring, *usn_string, *flags_string;
1464 struct ldb_val tval;
1466 struct ldb_val usnv, local_usnv;
1467 struct ldb_val vers, flagsv;
1470 const char *dnstring;
1472 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1474 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1476 return LDB_ERR_OPERATIONS_ERROR;
1478 tval = data_blob_string_const(tstring);
1480 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1482 return LDB_ERR_OPERATIONS_ERROR;
1484 usnv = data_blob_string_const(usn_string);
1486 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1488 return LDB_ERR_OPERATIONS_ERROR;
1490 local_usnv = data_blob_string_const(usn_string);
1492 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1494 return LDB_ERR_OPERATIONS_ERROR;
1496 vers = data_blob_string_const(vstring);
1498 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1499 if (!NT_STATUS_IS_OK(status)) {
1500 return LDB_ERR_OPERATIONS_ERROR;
1503 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1504 if (!flags_string) {
1505 return LDB_ERR_OPERATIONS_ERROR;
1507 flagsv = data_blob_string_const(flags_string);
1509 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1510 if (ret != LDB_SUCCESS) return ret;
1511 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1512 if (ret != LDB_SUCCESS) return ret;
1513 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1514 if (ret != LDB_SUCCESS) return ret;
1515 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1516 if (ret != LDB_SUCCESS) return ret;
1517 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1518 if (ret != LDB_SUCCESS) return ret;
1519 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1520 if (ret != LDB_SUCCESS) return ret;
1521 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1522 if (ret != LDB_SUCCESS) return ret;
1524 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1525 if (dnstring == NULL) {
1526 return LDB_ERR_OPERATIONS_ERROR;
1528 *v = data_blob_string_const(dnstring);
1533 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1534 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1535 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1536 uint32_t version, bool deleted);
1539 check if any links need upgrading from w2k format
1541 The parent_ctx is the ldb_message_element which contains the values array that dns[i].v points at, and which should be used for allocating any new value.
1543 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1546 for (i=0; i<count; i++) {
1551 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1552 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1556 /* it's an old one that needs upgrading */
1557 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1559 if (ret != LDB_SUCCESS) {
1567 update an extended DN, including all meta data fields
1569 see replmd_build_la_val for value names
1571 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1572 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1573 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1574 uint32_t version, bool deleted)
1576 struct ldb_dn *dn = dsdb_dn->dn;
1577 const char *tstring, *usn_string, *flags_string;
1578 struct ldb_val tval;
1580 struct ldb_val usnv, local_usnv;
1581 struct ldb_val vers, flagsv;
1582 const struct ldb_val *old_addtime;
1583 uint32_t old_version;
1586 const char *dnstring;
1588 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1590 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1592 return LDB_ERR_OPERATIONS_ERROR;
1594 tval = data_blob_string_const(tstring);
1596 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1598 return LDB_ERR_OPERATIONS_ERROR;
1600 usnv = data_blob_string_const(usn_string);
1602 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1604 return LDB_ERR_OPERATIONS_ERROR;
1606 local_usnv = data_blob_string_const(usn_string);
1608 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1609 if (!NT_STATUS_IS_OK(status)) {
1610 return LDB_ERR_OPERATIONS_ERROR;
1613 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1614 if (!flags_string) {
1615 return LDB_ERR_OPERATIONS_ERROR;
1617 flagsv = data_blob_string_const(flags_string);
1619 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1620 if (ret != LDB_SUCCESS) return ret;
1622 /* get the ADDTIME from the original */
1623 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1624 if (old_addtime == NULL) {
1625 old_addtime = &tval;
1627 if (dsdb_dn != old_dsdb_dn) {
1628 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1629 if (ret != LDB_SUCCESS) return ret;
1632 /* use our invocation id */
1633 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1634 if (ret != LDB_SUCCESS) return ret;
1636 /* changetime is the current time */
1637 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1638 if (ret != LDB_SUCCESS) return ret;
1640 /* update the USN */
1641 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1642 if (ret != LDB_SUCCESS) return ret;
1644 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1645 if (ret != LDB_SUCCESS) return ret;
1647 /* increase the version by 1 */
1648 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1649 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1650 version = old_version+1;
1652 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1653 vers = data_blob_string_const(vstring);
1654 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1655 if (ret != LDB_SUCCESS) return ret;
1657 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1658 if (dnstring == NULL) {
1659 return LDB_ERR_OPERATIONS_ERROR;
1661 *v = data_blob_string_const(dnstring);
1667 handle adding a linked attribute
1669 static int replmd_modify_la_add(struct ldb_module *module,
1670 const struct dsdb_schema *schema,
1671 struct ldb_message *msg,
1672 struct ldb_message_element *el,
1673 struct ldb_message_element *old_el,
1674 const struct dsdb_attribute *schema_attr,
1677 struct GUID *msg_guid,
1678 struct ldb_request *parent)
1681 struct parsed_dn *dns, *old_dns;
1682 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1684 struct ldb_val *new_values = NULL;
1685 unsigned int num_new_values = 0;
1686 unsigned old_num_values = old_el?old_el->num_values:0;
1687 const struct GUID *invocation_id;
1688 struct ldb_context *ldb = ldb_module_get_ctx(module);
1691 unix_to_nt_time(&now, t);
1693 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1694 if (ret != LDB_SUCCESS) {
1695 talloc_free(tmp_ctx);
1699 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1700 if (ret != LDB_SUCCESS) {
1701 talloc_free(tmp_ctx);
1705 invocation_id = samdb_ntds_invocation_id(ldb);
1706 if (!invocation_id) {
1707 talloc_free(tmp_ctx);
1708 return LDB_ERR_OPERATIONS_ERROR;
1711 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1712 if (ret != LDB_SUCCESS) {
1713 talloc_free(tmp_ctx);
1717 /* for each new value, see if it exists already with the same GUID */
1718 for (i=0; i<el->num_values; i++) {
1719 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1721 /* this is a new linked attribute value */
1722 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1723 if (new_values == NULL) {
1724 ldb_module_oom(module);
1725 talloc_free(tmp_ctx);
1726 return LDB_ERR_OPERATIONS_ERROR;
1728 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1729 invocation_id, seq_num, seq_num, now, 0, false);
1730 if (ret != LDB_SUCCESS) {
1731 talloc_free(tmp_ctx);
1736 /* this is only allowed if the GUID was
1737 previously deleted. */
1738 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1740 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1741 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1742 el->name, GUID_string(tmp_ctx, p->guid));
1743 talloc_free(tmp_ctx);
1744 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1746 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1747 invocation_id, seq_num, seq_num, now, 0, false);
1748 if (ret != LDB_SUCCESS) {
1749 talloc_free(tmp_ctx);
1754 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1755 if (ret != LDB_SUCCESS) {
1756 talloc_free(tmp_ctx);
1761 /* add the new ones on to the end of the old values, constructing a new el->values */
1762 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1764 old_num_values+num_new_values);
1765 if (el->values == NULL) {
1766 ldb_module_oom(module);
1767 return LDB_ERR_OPERATIONS_ERROR;
1770 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1771 el->num_values = old_num_values + num_new_values;
1773 talloc_steal(msg->elements, el->values);
1774 talloc_steal(el->values, new_values);
1776 talloc_free(tmp_ctx);
1778 /* we now tell the backend to replace all existing values
1779 with the one we have constructed */
1780 el->flags = LDB_FLAG_MOD_REPLACE;
1787 handle deleting all active linked attributes
1789 static int replmd_modify_la_delete(struct ldb_module *module,
1790 const struct dsdb_schema *schema,
1791 struct ldb_message *msg,
1792 struct ldb_message_element *el,
1793 struct ldb_message_element *old_el,
1794 const struct dsdb_attribute *schema_attr,
1797 struct GUID *msg_guid,
1798 struct ldb_request *parent)
1801 struct parsed_dn *dns, *old_dns;
1802 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1804 const struct GUID *invocation_id;
1805 struct ldb_context *ldb = ldb_module_get_ctx(module);
1808 unix_to_nt_time(&now, t);
1810 /* check if there is nothing to delete */
1811 if ((!old_el || old_el->num_values == 0) &&
1812 el->num_values == 0) {
1816 if (!old_el || old_el->num_values == 0) {
1817 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1820 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1821 if (ret != LDB_SUCCESS) {
1822 talloc_free(tmp_ctx);
1826 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1827 if (ret != LDB_SUCCESS) {
1828 talloc_free(tmp_ctx);
1832 invocation_id = samdb_ntds_invocation_id(ldb);
1833 if (!invocation_id) {
1834 return LDB_ERR_OPERATIONS_ERROR;
1837 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1838 if (ret != LDB_SUCCESS) {
1839 talloc_free(tmp_ctx);
1845 /* see if we are being asked to delete any links that
1846 don't exist or are already deleted */
1847 for (i=0; i<el->num_values; i++) {
1848 struct parsed_dn *p = &dns[i];
1849 struct parsed_dn *p2;
1852 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1854 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1855 el->name, GUID_string(tmp_ctx, p->guid));
1856 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1858 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1859 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1860 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1861 el->name, GUID_string(tmp_ctx, p->guid));
1862 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1866 /* for each new value, see if it exists already with the same GUID
1867 if it is not already deleted and matches the delete list then delete it
1869 for (i=0; i<old_el->num_values; i++) {
1870 struct parsed_dn *p = &old_dns[i];
1873 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1877 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1878 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1880 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1881 invocation_id, seq_num, seq_num, now, 0, true);
1882 if (ret != LDB_SUCCESS) {
1883 talloc_free(tmp_ctx);
1887 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1888 if (ret != LDB_SUCCESS) {
1889 talloc_free(tmp_ctx);
1894 el->values = talloc_steal(msg->elements, old_el->values);
1895 el->num_values = old_el->num_values;
1897 talloc_free(tmp_ctx);
1899 /* we now tell the backend to replace all existing values
1900 with the one we have constructed */
1901 el->flags = LDB_FLAG_MOD_REPLACE;
1907 handle replacing a linked attribute
1909 static int replmd_modify_la_replace(struct ldb_module *module,
1910 const struct dsdb_schema *schema,
1911 struct ldb_message *msg,
1912 struct ldb_message_element *el,
1913 struct ldb_message_element *old_el,
1914 const struct dsdb_attribute *schema_attr,
1917 struct GUID *msg_guid,
1918 struct ldb_request *parent)
1921 struct parsed_dn *dns, *old_dns;
1922 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1924 const struct GUID *invocation_id;
1925 struct ldb_context *ldb = ldb_module_get_ctx(module);
1926 struct ldb_val *new_values = NULL;
1927 unsigned int num_new_values = 0;
1928 unsigned int old_num_values = old_el?old_el->num_values:0;
1931 unix_to_nt_time(&now, t);
1933 /* check if there is nothing to replace */
1934 if ((!old_el || old_el->num_values == 0) &&
1935 el->num_values == 0) {
1939 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1940 if (ret != LDB_SUCCESS) {
1941 talloc_free(tmp_ctx);
1945 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1946 if (ret != LDB_SUCCESS) {
1947 talloc_free(tmp_ctx);
1951 invocation_id = samdb_ntds_invocation_id(ldb);
1952 if (!invocation_id) {
1953 return LDB_ERR_OPERATIONS_ERROR;
1956 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1957 if (ret != LDB_SUCCESS) {
1958 talloc_free(tmp_ctx);
1962 /* mark all the old ones as deleted */
1963 for (i=0; i<old_num_values; i++) {
1964 struct parsed_dn *old_p = &old_dns[i];
1965 struct parsed_dn *p;
1966 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1968 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1970 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1971 if (ret != LDB_SUCCESS) {
1972 talloc_free(tmp_ctx);
1976 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1978 /* we don't delete it if we are re-adding it */
1982 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1983 invocation_id, seq_num, seq_num, now, 0, true);
1984 if (ret != LDB_SUCCESS) {
1985 talloc_free(tmp_ctx);
1990 /* for each new value, either update its meta-data, or add it
1993 for (i=0; i<el->num_values; i++) {
1994 struct parsed_dn *p = &dns[i], *old_p;
1997 (old_p = parsed_dn_find(old_dns,
1998 old_num_values, p->guid, NULL)) != NULL) {
1999 /* update in place */
2000 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
2001 old_p->dsdb_dn, invocation_id,
2002 seq_num, seq_num, now, 0, false);
2003 if (ret != LDB_SUCCESS) {
2004 talloc_free(tmp_ctx);
2009 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2011 if (new_values == NULL) {
2012 ldb_module_oom(module);
2013 talloc_free(tmp_ctx);
2014 return LDB_ERR_OPERATIONS_ERROR;
2016 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2017 invocation_id, seq_num, seq_num, now, 0, false);
2018 if (ret != LDB_SUCCESS) {
2019 talloc_free(tmp_ctx);
2025 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2026 if (ret != LDB_SUCCESS) {
2027 talloc_free(tmp_ctx);
2032 /* add the new values to the end of old_el */
2033 if (num_new_values != 0) {
2034 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2035 struct ldb_val, old_num_values+num_new_values);
2036 if (el->values == NULL) {
2037 ldb_module_oom(module);
2038 return LDB_ERR_OPERATIONS_ERROR;
2040 memcpy(&el->values[old_num_values], &new_values[0],
2041 sizeof(struct ldb_val)*num_new_values);
2042 el->num_values = old_num_values + num_new_values;
2043 talloc_steal(msg->elements, new_values);
2045 el->values = old_el->values;
2046 el->num_values = old_el->num_values;
2047 talloc_steal(msg->elements, el->values);
2050 talloc_free(tmp_ctx);
2052 /* we now tell the backend to replace all existing values
2053 with the one we have constructed */
2054 el->flags = LDB_FLAG_MOD_REPLACE;
2061 handle linked attributes in modify requests
2063 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2064 struct ldb_message *msg,
2065 uint64_t seq_num, time_t t,
2066 struct ldb_request *parent)
2068 struct ldb_result *res;
2071 struct ldb_context *ldb = ldb_module_get_ctx(module);
2072 struct ldb_message *old_msg;
2074 const struct dsdb_schema *schema;
2075 struct GUID old_guid;
2078 /* there the replmd_update_rpmd code has already
2079 * checked and saw that there are no linked
2084 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2085 /* don't do anything special for linked attributes */
2089 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2090 DSDB_FLAG_NEXT_MODULE |
2091 DSDB_SEARCH_SHOW_RECYCLED |
2092 DSDB_SEARCH_REVEAL_INTERNALS |
2093 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2095 if (ret != LDB_SUCCESS) {
2098 schema = dsdb_get_schema(ldb, res);
2100 return LDB_ERR_OPERATIONS_ERROR;
2103 old_msg = res->msgs[0];
2105 old_guid = samdb_result_guid(old_msg, "objectGUID");
2107 for (i=0; i<msg->num_elements; i++) {
2108 struct ldb_message_element *el = &msg->elements[i];
2109 struct ldb_message_element *old_el, *new_el;
2110 const struct dsdb_attribute *schema_attr
2111 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2113 ldb_asprintf_errstring(ldb,
2114 "%s: attribute %s is not a valid attribute in schema",
2115 __FUNCTION__, el->name);
2116 return LDB_ERR_OBJECT_CLASS_VIOLATION;
2118 if (schema_attr->linkID == 0) {
2121 if ((schema_attr->linkID & 1) == 1) {
2122 /* Odd is for the target. Illegal to modify */
2123 ldb_asprintf_errstring(ldb,
2124 "attribute %s must not be modified directly, it is a linked attribute", el->name);
2125 return LDB_ERR_UNWILLING_TO_PERFORM;
2127 old_el = ldb_msg_find_element(old_msg, el->name);
2128 switch (el->flags & LDB_FLAG_MOD_MASK) {
2129 case LDB_FLAG_MOD_REPLACE:
2130 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2132 case LDB_FLAG_MOD_DELETE:
2133 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2135 case LDB_FLAG_MOD_ADD:
2136 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2139 ldb_asprintf_errstring(ldb,
2140 "invalid flags 0x%x for %s linked attribute",
2141 el->flags, el->name);
2142 return LDB_ERR_UNWILLING_TO_PERFORM;
2144 if (ret != LDB_SUCCESS) {
2148 ldb_msg_remove_attr(old_msg, el->name);
2150 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2151 new_el->num_values = el->num_values;
2152 new_el->values = talloc_steal(msg->elements, el->values);
2154 /* TODO: this relises a bit too heavily on the exact
2155 behaviour of ldb_msg_find_element and
2156 ldb_msg_remove_element */
2157 old_el = ldb_msg_find_element(msg, el->name);
2159 ldb_msg_remove_element(msg, old_el);
2170 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2172 struct ldb_context *ldb;
2173 struct replmd_replicated_request *ac;
2174 struct ldb_request *down_req;
2175 struct ldb_message *msg;
2176 time_t t = time(NULL);
2178 bool is_urgent = false;
2179 struct loadparm_context *lp_ctx;
2181 unsigned int functional_level;
2182 const DATA_BLOB *guid_blob;
2184 /* do not manipulate our control entries */
2185 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2186 return ldb_next_request(module, req);
2189 ldb = ldb_module_get_ctx(module);
2191 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2193 guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2194 if ( guid_blob != NULL ) {
2195 ldb_set_errstring(ldb,
2196 "replmd_modify: it's not allowed to change the objectGUID!");
2197 return LDB_ERR_CONSTRAINT_VIOLATION;
2200 ac = replmd_ctx_init(module, req);
2202 return ldb_module_oom(module);
2205 functional_level = dsdb_functional_level(ldb);
2207 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2208 struct loadparm_context);
2210 /* we have to copy the message as the caller might have it as a const */
2211 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2215 return LDB_ERR_OPERATIONS_ERROR;
2218 ldb_msg_remove_attr(msg, "whenChanged");
2219 ldb_msg_remove_attr(msg, "uSNChanged");
2221 ret = replmd_update_rpmd(module, ac->schema, req, msg, &ac->seq_num, t, &is_urgent);
2222 if (ret == LDB_ERR_REFERRAL) {
2223 referral = talloc_asprintf(req,
2225 lpcfg_dnsdomain(lp_ctx),
2226 ldb_dn_get_linearized(msg->dn));
2227 ret = ldb_module_send_referral(req, referral);
2229 return ldb_module_done(req, NULL, NULL, ret);
2232 if (ret != LDB_SUCCESS) {
2237 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2238 if (ret != LDB_SUCCESS) {
2244 * - replace the old object with the newly constructed one
2247 ac->is_urgent = is_urgent;
2249 ret = ldb_build_mod_req(&down_req, ldb, ac,
2252 ac, replmd_op_callback,
2254 LDB_REQ_SET_LOCATION(down_req);
2255 if (ret != LDB_SUCCESS) {
2260 /* current partition control is needed by "replmd_op_callback" */
2261 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2262 ret = ldb_request_add_control(down_req,
2263 DSDB_CONTROL_CURRENT_PARTITION_OID,
2265 if (ret != LDB_SUCCESS) {
2271 /* If we are in functional level 2000, then
2272 * replmd_modify_handle_linked_attribs will have done
2274 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2275 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2276 if (ret != LDB_SUCCESS) {
2282 talloc_steal(down_req, msg);
2284 /* we only change whenChanged and uSNChanged if the seq_num
2286 if (ac->seq_num != 0) {
2287 ret = add_time_element(msg, "whenChanged", t);
2288 if (ret != LDB_SUCCESS) {
2293 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2294 if (ret != LDB_SUCCESS) {
2300 /* go on with the call chain */
2301 return ldb_next_request(module, down_req);
2304 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2307 handle a rename request
2309 On a rename we need to do an extra ldb_modify which sets the
2310 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2312 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2314 struct ldb_context *ldb;
2315 struct replmd_replicated_request *ac;
2317 struct ldb_request *down_req;
2319 /* do not manipulate our control entries */
2320 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2321 return ldb_next_request(module, req);
2324 ldb = ldb_module_get_ctx(module);
2326 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2328 ac = replmd_ctx_init(module, req);
2330 return ldb_module_oom(module);
2333 ret = ldb_build_rename_req(&down_req, ldb, ac,
2334 ac->req->op.rename.olddn,
2335 ac->req->op.rename.newdn,
2337 ac, replmd_rename_callback,
2339 LDB_REQ_SET_LOCATION(down_req);
2340 if (ret != LDB_SUCCESS) {
2345 /* go on with the call chain */
2346 return ldb_next_request(module, down_req);
2349 /* After the rename is compleated, update the whenchanged etc */
2350 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2352 struct ldb_context *ldb;
2353 struct replmd_replicated_request *ac;
2354 struct ldb_request *down_req;
2355 struct ldb_message *msg;
2356 time_t t = time(NULL);
2359 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2360 ldb = ldb_module_get_ctx(ac->module);
2362 if (ares->error != LDB_SUCCESS) {
2363 return ldb_module_done(ac->req, ares->controls,
2364 ares->response, ares->error);
2367 if (ares->type != LDB_REPLY_DONE) {
2368 ldb_set_errstring(ldb,
2369 "invalid ldb_reply_type in callback");
2371 return ldb_module_done(ac->req, NULL, NULL,
2372 LDB_ERR_OPERATIONS_ERROR);
2375 /* Get a sequence number from the backend */
2376 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2377 if (ret != LDB_SUCCESS) {
2382 * - replace the old object with the newly constructed one
2385 msg = ldb_msg_new(ac);
2388 return LDB_ERR_OPERATIONS_ERROR;
2391 msg->dn = ac->req->op.rename.newdn;
2393 ret = ldb_build_mod_req(&down_req, ldb, ac,
2396 ac, replmd_op_callback,
2398 LDB_REQ_SET_LOCATION(down_req);
2399 if (ret != LDB_SUCCESS) {
2404 /* current partition control is needed by "replmd_op_callback" */
2405 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2406 ret = ldb_request_add_control(down_req,
2407 DSDB_CONTROL_CURRENT_PARTITION_OID,
2409 if (ret != LDB_SUCCESS) {
2415 talloc_steal(down_req, msg);
2417 ret = add_time_element(msg, "whenChanged", t);
2418 if (ret != LDB_SUCCESS) {
2423 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2424 if (ret != LDB_SUCCESS) {
2429 /* go on with the call chain - do the modify after the rename */
2430 return ldb_next_request(ac->module, down_req);
2434 remove links from objects that point at this object when an object
2437 static int replmd_delete_remove_link(struct ldb_module *module,
2438 const struct dsdb_schema *schema,
2440 struct ldb_message_element *el,
2441 const struct dsdb_attribute *sa,
2442 struct ldb_request *parent)
2445 TALLOC_CTX *tmp_ctx = talloc_new(module);
2446 struct ldb_context *ldb = ldb_module_get_ctx(module);
2448 for (i=0; i<el->num_values; i++) {
2449 struct dsdb_dn *dsdb_dn;
2453 struct ldb_message *msg;
2454 const struct dsdb_attribute *target_attr;
2455 struct ldb_message_element *el2;
2456 struct ldb_val dn_val;
2458 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2462 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2464 talloc_free(tmp_ctx);
2465 return LDB_ERR_OPERATIONS_ERROR;
2468 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2469 if (!NT_STATUS_IS_OK(status)) {
2470 talloc_free(tmp_ctx);
2471 return LDB_ERR_OPERATIONS_ERROR;
2474 /* remove the link */
2475 msg = ldb_msg_new(tmp_ctx);
2477 ldb_module_oom(module);
2478 talloc_free(tmp_ctx);
2479 return LDB_ERR_OPERATIONS_ERROR;
2483 msg->dn = dsdb_dn->dn;
2485 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2486 if (target_attr == NULL) {
2490 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2491 if (ret != LDB_SUCCESS) {
2492 ldb_module_oom(module);
2493 talloc_free(tmp_ctx);
2494 return LDB_ERR_OPERATIONS_ERROR;
2496 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2497 el2->values = &dn_val;
2498 el2->num_values = 1;
2500 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2501 if (ret != LDB_SUCCESS) {
2502 talloc_free(tmp_ctx);
2506 talloc_free(tmp_ctx);
2512 handle update of replication meta data for deletion of objects
2514 This also handles the mapping of delete to a rename operation
2515 to allow deletes to be replicated.
2517 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2519 int ret = LDB_ERR_OTHER;
2520 bool retb, disallow_move_on_delete;
2521 struct ldb_dn *old_dn, *new_dn;
2522 const char *rdn_name;
2523 const struct ldb_val *rdn_value, *new_rdn_value;
2525 struct ldb_context *ldb = ldb_module_get_ctx(module);
2526 const struct dsdb_schema *schema;
2527 struct ldb_message *msg, *old_msg;
2528 struct ldb_message_element *el;
2529 TALLOC_CTX *tmp_ctx;
2530 struct ldb_result *res, *parent_res;
2531 const char *preserved_attrs[] = {
2532 /* yes, this really is a hard coded list. See MS-ADTS
2533 section 3.1.1.5.5.1.1 */
2534 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2535 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2536 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2537 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2538 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2539 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2540 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2541 "whenChanged", NULL};
2542 unsigned int i, el_count = 0;
2543 enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2544 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2545 enum deletion_state deletion_state, next_deletion_state;
2548 if (ldb_dn_is_special(req->op.del.dn)) {
2549 return ldb_next_request(module, req);
2552 tmp_ctx = talloc_new(ldb);
2555 return LDB_ERR_OPERATIONS_ERROR;
2558 schema = dsdb_get_schema(ldb, tmp_ctx);
2560 return LDB_ERR_OPERATIONS_ERROR;
2563 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2565 /* we need the complete msg off disk, so we can work out which
2566 attributes need to be removed */
2567 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2568 DSDB_FLAG_NEXT_MODULE |
2569 DSDB_SEARCH_SHOW_RECYCLED |
2570 DSDB_SEARCH_REVEAL_INTERNALS |
2571 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2572 if (ret != LDB_SUCCESS) {
2573 talloc_free(tmp_ctx);
2576 old_msg = res->msgs[0];
2579 ret = dsdb_recyclebin_enabled(module, &enabled);
2580 if (ret != LDB_SUCCESS) {
2581 talloc_free(tmp_ctx);
2585 if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2587 deletion_state = OBJECT_TOMBSTONE;
2588 next_deletion_state = OBJECT_REMOVED;
2589 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2590 deletion_state = OBJECT_RECYCLED;
2591 next_deletion_state = OBJECT_REMOVED;
2593 deletion_state = OBJECT_DELETED;
2594 next_deletion_state = OBJECT_RECYCLED;
2597 deletion_state = OBJECT_NOT_DELETED;
2599 next_deletion_state = OBJECT_DELETED;
2601 next_deletion_state = OBJECT_TOMBSTONE;
2605 if (next_deletion_state == OBJECT_REMOVED) {
2606 struct auth_session_info *session_info =
2607 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2608 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2609 ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2610 ldb_dn_get_linearized(old_msg->dn));
2611 return LDB_ERR_UNWILLING_TO_PERFORM;
2614 /* it is already deleted - really remove it this time */
2615 talloc_free(tmp_ctx);
2616 return ldb_next_request(module, req);
2619 rdn_name = ldb_dn_get_rdn_name(old_dn);
2620 rdn_value = ldb_dn_get_rdn_val(old_dn);
2621 if ((rdn_name == NULL) || (rdn_value == NULL)) {
2622 talloc_free(tmp_ctx);
2623 return ldb_operr(ldb);
2626 msg = ldb_msg_new(tmp_ctx);
2628 ldb_module_oom(module);
2629 talloc_free(tmp_ctx);
2630 return LDB_ERR_OPERATIONS_ERROR;
2635 if (deletion_state == OBJECT_NOT_DELETED){
2636 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2637 disallow_move_on_delete =
2638 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2639 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2641 /* work out where we will be renaming this object to */
2642 if (!disallow_move_on_delete) {
2643 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2645 if (ret != LDB_SUCCESS) {
2646 /* this is probably an attempted delete on a partition
2647 * that doesn't allow delete operations, such as the
2648 * schema partition */
2649 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2650 ldb_dn_get_linearized(old_dn));
2651 talloc_free(tmp_ctx);
2652 return LDB_ERR_UNWILLING_TO_PERFORM;
2655 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2656 if (new_dn == NULL) {
2657 ldb_module_oom(module);
2658 talloc_free(tmp_ctx);
2659 return LDB_ERR_OPERATIONS_ERROR;
2663 /* get the objects GUID from the search we just did */
2664 guid = samdb_result_guid(old_msg, "objectGUID");
2666 /* Add a formatted child */
2667 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2669 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2670 GUID_string(tmp_ctx, &guid));
2672 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2673 ldb_dn_get_linearized(new_dn)));
2674 talloc_free(tmp_ctx);
2675 return LDB_ERR_OPERATIONS_ERROR;
2678 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2679 if (ret != LDB_SUCCESS) {
2680 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2681 ldb_module_oom(module);
2682 talloc_free(tmp_ctx);
2685 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2689 now we need to modify the object in the following ways:
2691 - add isDeleted=TRUE
2692 - update rDN and name, with new rDN
2693 - remove linked attributes
2694 - remove objectCategory and sAMAccountType
2695 - remove attribs not on the preserved list
2696 - preserved if in above list, or is rDN
2697 - remove all linked attribs from this object
2698 - remove all links from other objects to this object
2699 - add lastKnownParent
2700 - update replPropertyMetaData?
2702 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2705 /* we need the storage form of the parent GUID */
2706 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2707 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2708 DSDB_FLAG_NEXT_MODULE |
2709 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2710 DSDB_SEARCH_REVEAL_INTERNALS|
2711 DSDB_SEARCH_SHOW_RECYCLED, req);
2712 if (ret != LDB_SUCCESS) {
2713 talloc_free(tmp_ctx);
2717 if (deletion_state == OBJECT_NOT_DELETED){
2718 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2719 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2720 if (ret != LDB_SUCCESS) {
2721 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2722 ldb_module_oom(module);
2723 talloc_free(tmp_ctx);
2726 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2729 switch (next_deletion_state){
2731 case OBJECT_DELETED:
2733 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2734 if (ret != LDB_SUCCESS) {
2735 DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2736 ldb_module_oom(module);
2737 talloc_free(tmp_ctx);
2740 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2742 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_DELETE, NULL);
2743 if (ret != LDB_SUCCESS) {
2744 talloc_free(tmp_ctx);
2745 ldb_module_oom(module);
2749 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_DELETE, NULL);
2750 if (ret != LDB_SUCCESS) {
2751 talloc_free(tmp_ctx);
2752 ldb_module_oom(module);
2758 case OBJECT_RECYCLED:
2759 case OBJECT_TOMBSTONE:
2761 /* we also mark it as recycled, meaning this object can't be
2762 recovered (we are stripping its attributes) */
2763 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2764 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2765 if (ret != LDB_SUCCESS) {
2766 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2767 ldb_module_oom(module);
2768 talloc_free(tmp_ctx);
2771 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2774 /* work out which of the old attributes we will be removing */
2775 for (i=0; i<old_msg->num_elements; i++) {
2776 const struct dsdb_attribute *sa;
2777 el = &old_msg->elements[i];
2778 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2780 talloc_free(tmp_ctx);
2781 return LDB_ERR_OPERATIONS_ERROR;
2783 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2784 /* don't remove the rDN */
2787 if (sa->linkID && sa->linkID & 1) {
2788 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
2789 if (ret != LDB_SUCCESS) {
2790 talloc_free(tmp_ctx);
2791 return LDB_ERR_OPERATIONS_ERROR;
2795 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2798 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2799 if (ret != LDB_SUCCESS) {
2800 talloc_free(tmp_ctx);
2801 ldb_module_oom(module);
2811 if (deletion_state == OBJECT_NOT_DELETED) {
2812 const struct dsdb_attribute *sa;
2814 /* work out what the new rdn value is, for updating the
2815 rDN and name fields */
2816 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2817 if (new_rdn_value == NULL) {
2818 talloc_free(tmp_ctx);
2819 return ldb_operr(ldb);
2822 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
2824 talloc_free(tmp_ctx);
2825 return LDB_ERR_OPERATIONS_ERROR;
2828 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
2830 if (ret != LDB_SUCCESS) {
2831 talloc_free(tmp_ctx);
2834 el->flags = LDB_FLAG_MOD_REPLACE;
2836 el = ldb_msg_find_element(old_msg, "name");
2838 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2839 if (ret != LDB_SUCCESS) {
2840 talloc_free(tmp_ctx);
2843 el->flags = LDB_FLAG_MOD_REPLACE;
2847 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
2848 if (ret != LDB_SUCCESS) {
2849 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2850 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2851 talloc_free(tmp_ctx);
2855 if (deletion_state == OBJECT_NOT_DELETED) {
2856 /* now rename onto the new DN */
2857 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
2858 if (ret != LDB_SUCCESS){
2859 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2860 ldb_dn_get_linearized(old_dn),
2861 ldb_dn_get_linearized(new_dn),
2862 ldb_errstring(ldb)));
2863 talloc_free(tmp_ctx);
2868 talloc_free(tmp_ctx);
2870 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2875 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2880 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2882 int ret = LDB_ERR_OTHER;
2883 /* TODO: do some error mapping */
2888 static struct replPropertyMetaData1 *
2889 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
2890 enum drsuapi_DsAttributeId attid)
2893 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
2895 for (i = 0; i < rpmd_ctr->count; i++) {
2896 if (rpmd_ctr->array[i].attid == attid) {
2897 return &rpmd_ctr->array[i];
2905 return true if an update is newer than an existing entry
2906 see section 5.11 of MS-ADTS
2908 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2909 const struct GUID *update_invocation_id,
2910 uint32_t current_version,
2911 uint32_t update_version,
2912 NTTIME current_change_time,
2913 NTTIME update_change_time)
2915 if (update_version != current_version) {
2916 return update_version > current_version;
2918 if (update_change_time != current_change_time) {
2919 return update_change_time > current_change_time;
2921 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2924 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2925 struct replPropertyMetaData1 *new_m)
2927 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2928 &new_m->originating_invocation_id,
2931 cur_m->originating_change_time,
2932 new_m->originating_change_time);
2939 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
2941 const struct ldb_val *rdn_val;
2942 const char *rdn_name;
2943 struct ldb_dn *new_dn;
2945 rdn_val = ldb_dn_get_rdn_val(dn);
2946 rdn_name = ldb_dn_get_rdn_name(dn);
2947 if (!rdn_val || !rdn_name) {
2951 new_dn = ldb_dn_copy(mem_ctx, dn);
2956 if (!ldb_dn_remove_child_components(new_dn, 1)) {
2960 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
2962 ldb_dn_escape_value(new_dn, *rdn_val),
2963 GUID_string(new_dn, guid))) {
2972 perform a modify operation which sets the rDN and name attributes to
2973 their current values. This has the effect of changing these
2974 attributes to have been last updated by the current DC. This is
2975 needed to ensure that renames performed as part of conflict
2976 resolution are propogated to other DCs
2978 static int replmd_name_modify(struct replmd_replicated_request *ar,
2979 struct ldb_request *req, struct ldb_dn *dn)
2981 struct ldb_message *msg;
2982 const char *rdn_name;
2983 const struct ldb_val *rdn_val;
2984 const struct dsdb_attribute *rdn_attr;
2987 msg = ldb_msg_new(req);
2993 rdn_name = ldb_dn_get_rdn_name(dn);
2994 if (rdn_name == NULL) {
2998 /* normalize the rdn attribute name */
2999 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3000 if (rdn_attr == NULL) {
3003 rdn_name = rdn_attr->lDAPDisplayName;
3005 rdn_val = ldb_dn_get_rdn_val(dn);
3006 if (rdn_val == NULL) {
3010 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3013 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3016 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3019 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3023 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3024 if (ret != LDB_SUCCESS) {
3025 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3026 ldb_dn_get_linearized(dn),
3027 ldb_errstring(ldb_module_get_ctx(ar->module))));
3037 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3038 ldb_dn_get_linearized(dn)));
3039 return LDB_ERR_OPERATIONS_ERROR;
3044 callback for conflict DN handling where we have renamed the incoming
3045 record. After renaming it, we need to ensure the change of name and
3046 rDN for the incoming record is seen as an originating update by this DC.
3048 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3050 struct replmd_replicated_request *ar =
3051 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3054 if (ares->error != LDB_SUCCESS) {
3055 /* call the normal callback for everything except success */
3056 return replmd_op_callback(req, ares);
3059 /* perform a modify of the rDN and name of the record */
3060 ret = replmd_name_modify(ar, req, req->op.add.message->dn);
3061 if (ret != LDB_SUCCESS) {
3063 return replmd_op_callback(req, ares);
3066 return replmd_op_callback(req, ares);
3070 callback for replmd_replicated_apply_add()
3071 This copes with the creation of conflict records in the case where
3072 the DN exists, but with a different objectGUID
3074 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3076 struct ldb_dn *conflict_dn;
3077 struct replmd_replicated_request *ar =
3078 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3079 struct ldb_result *res;
3080 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3082 const struct ldb_val *rmd_value, *omd_value;
3083 struct replPropertyMetaDataBlob omd, rmd;
3084 enum ndr_err_code ndr_err;
3085 bool rename_incoming_record;
3086 struct replPropertyMetaData1 *rmd_name, *omd_name;
3088 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3089 /* call the normal callback for everything except
3091 return replmd_op_callback(req, ares);
3095 * we have a conflict, and need to decide if we will keep the
3096 * new record or the old record
3098 conflict_dn = req->op.add.message->dn;
3101 * first we need the replPropertyMetaData attribute from the
3104 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3106 DSDB_FLAG_NEXT_MODULE |
3107 DSDB_SEARCH_SHOW_DELETED |
3108 DSDB_SEARCH_SHOW_RECYCLED, req);
3109 if (ret != LDB_SUCCESS) {
3110 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3111 ldb_dn_get_linearized(conflict_dn)));
3115 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3116 if (omd_value == NULL) {
3117 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3118 ldb_dn_get_linearized(conflict_dn)));
3122 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3123 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3124 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3125 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3126 ldb_dn_get_linearized(conflict_dn)));
3131 * and the replPropertyMetaData attribute from the
3134 rmd_value = ldb_msg_find_ldb_val(req->op.add.message, "replPropertyMetaData");
3135 if (rmd_value == NULL) {
3136 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for new record '%s'\n",
3137 ldb_dn_get_linearized(conflict_dn)));
3141 ndr_err = ndr_pull_struct_blob(rmd_value, req, &rmd,
3142 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3143 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3144 DEBUG(0,(__location__ ": Failed to parse new replPropertyMetaData for %s\n",
3145 ldb_dn_get_linearized(conflict_dn)));
3149 /* we decide which is newer based on the RPMD on the name
3150 attribute. See [MS-DRSR] ResolveNameConflict */
3151 rmd_name = replmd_replPropertyMetaData1_find_attid(&rmd, DRSUAPI_ATTID_name);
3152 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3153 if (!rmd_name || !omd_name) {
3154 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3155 ldb_dn_get_linearized(conflict_dn)));
3159 rename_incoming_record = !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3161 if (rename_incoming_record) {
3163 struct ldb_dn *new_dn;
3164 struct ldb_message *new_msg;
3166 guid = samdb_result_guid(req->op.add.message, "objectGUID");
3167 if (GUID_all_zero(&guid)) {
3168 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3169 ldb_dn_get_linearized(conflict_dn)));
3172 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3173 if (new_dn == NULL) {
3174 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3175 ldb_dn_get_linearized(conflict_dn)));
3179 DEBUG(1,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3180 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3182 /* re-submit the request, but with a different
3183 callback, so we don't loop forever. */
3184 new_msg = ldb_msg_copy_shallow(req, req->op.add.message);
3187 DEBUG(0,(__location__ ": Failed to copy conflict DN message for %s\n",
3188 ldb_dn_get_linearized(conflict_dn)));
3190 new_msg->dn = new_dn;
3191 req->op.add.message = new_msg;
3192 req->callback = replmd_op_name_modify_callback;
3194 return ldb_next_request(ar->module, req);
3196 /* we are renaming the existing record */
3198 struct ldb_dn *new_dn;
3200 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3201 if (GUID_all_zero(&guid)) {
3202 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3203 ldb_dn_get_linearized(conflict_dn)));
3207 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3208 if (new_dn == NULL) {
3209 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3210 ldb_dn_get_linearized(conflict_dn)));
3214 DEBUG(1,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
3215 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3217 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3218 DSDB_FLAG_OWN_MODULE, req);
3219 if (ret != LDB_SUCCESS) {
3220 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3221 ldb_dn_get_linearized(conflict_dn),
3222 ldb_dn_get_linearized(new_dn),
3223 ldb_errstring(ldb_module_get_ctx(ar->module))));
3228 * now we need to ensure that the rename is seen as an
3229 * originating update. We do that with a modify.
3231 ret = replmd_name_modify(ar, req, new_dn);
3232 if (ret != LDB_SUCCESS) {
3236 req->callback = replmd_op_callback;
3238 return ldb_next_request(ar->module, req);
3242 /* on failure do the original callback. This means replication
3243 * will stop with an error, but there is not much else we can
3246 return replmd_op_callback(req, ares);
3250 this is called when a new object comes in over DRS
3252 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3254 struct ldb_context *ldb;
3255 struct ldb_request *change_req;
3256 enum ndr_err_code ndr_err;
3257 struct ldb_message *msg;
3258 struct replPropertyMetaDataBlob *md;
3259 struct ldb_val md_value;
3264 * TODO: check if the parent object exist
3268 * TODO: handle the conflict case where an object with the
3272 ldb = ldb_module_get_ctx(ar->module);
3273 msg = ar->objs->objects[ar->index_current].msg;
3274 md = ar->objs->objects[ar->index_current].meta_data;
3276 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3277 if (ret != LDB_SUCCESS) {
3278 return replmd_replicated_request_error(ar, ret);
3281 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
3282 if (ret != LDB_SUCCESS) {
3283 return replmd_replicated_request_error(ar, ret);
3286 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3287 if (ret != LDB_SUCCESS) {
3288 return replmd_replicated_request_error(ar, ret);
3291 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
3292 if (ret != LDB_SUCCESS) {
3293 return replmd_replicated_request_error(ar, ret);
3296 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3297 if (ret != LDB_SUCCESS) {
3298 return replmd_replicated_request_error(ar, ret);
3301 /* remove any message elements that have zero values */
3302 for (i=0; i<msg->num_elements; i++) {
3303 struct ldb_message_element *el = &msg->elements[i];
3305 if (el->num_values == 0) {
3306 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
3308 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
3309 msg->num_elements--;
3316 * the meta data array is already sorted by the caller
3318 for (i=0; i < md->ctr.ctr1.count; i++) {
3319 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3321 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3322 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3323 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3324 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3325 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3327 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3328 if (ret != LDB_SUCCESS) {
3329 return replmd_replicated_request_error(ar, ret);
3332 replmd_ldb_message_sort(msg, ar->schema);
3335 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3336 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3340 ret = ldb_build_add_req(&change_req,
3346 replmd_op_add_callback,
3348 LDB_REQ_SET_LOCATION(change_req);
3349 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3351 /* current partition control needed by "repmd_op_callback" */
3352 ret = ldb_request_add_control(change_req,
3353 DSDB_CONTROL_CURRENT_PARTITION_OID,
3355 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3357 return ldb_next_request(ar->module, change_req);
3361 handle renames that come in over DRS replication
3363 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
3364 struct ldb_message *msg,
3365 struct replPropertyMetaDataBlob *rmd,
3366 struct replPropertyMetaDataBlob *omd,
3367 struct ldb_request *parent)
3369 struct replPropertyMetaData1 *md_remote;
3370 struct replPropertyMetaData1 *md_local;
3372 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3377 /* now we need to check for double renames. We could have a
3378 * local rename pending which our replication partner hasn't
3379 * received yet. We choose which one wins by looking at the
3380 * attribute stamps on the two objects, the newer one wins
3382 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3383 md_local = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3384 /* if there is no name attribute then we have to assume the
3385 object we've received is in fact newer */
3386 if (!md_remote || !md_local ||
3387 replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3388 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3389 ldb_dn_get_linearized(ar->search_msg->dn),
3390 ldb_dn_get_linearized(msg->dn)));
3391 /* pass rename to the next module
3392 * so it doesn't appear as an originating update */
3393 return dsdb_module_rename(ar->module,
3394 ar->search_msg->dn, msg->dn,
3395 DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX, parent);
3398 /* we're going to keep our old object */
3399 DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
3400 ldb_dn_get_linearized(ar->search_msg->dn),
3401 ldb_dn_get_linearized(msg->dn)));
3406 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
3408 struct ldb_context *ldb;
3409 struct ldb_request *change_req;
3410 enum ndr_err_code ndr_err;
3411 struct ldb_message *msg;
3412 struct replPropertyMetaDataBlob *rmd;
3413 struct replPropertyMetaDataBlob omd;
3414 const struct ldb_val *omd_value;
3415 struct replPropertyMetaDataBlob nmd;
3416 struct ldb_val nmd_value;
3419 unsigned int removed_attrs = 0;
3422 ldb = ldb_module_get_ctx(ar->module);
3423 msg = ar->objs->objects[ar->index_current].msg;
3424 rmd = ar->objs->objects[ar->index_current].meta_data;
3428 /* find existing meta data */
3429 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
3431 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
3432 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3433 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3434 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3435 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3438 if (omd.version != 1) {
3439 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3443 /* handle renames that come in over DRS */
3444 ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
3445 if (ret != LDB_SUCCESS) {
3446 ldb_debug(ldb, LDB_DEBUG_FATAL,
3447 "replmd_replicated_request rename %s => %s failed - %s\n",
3448 ldb_dn_get_linearized(ar->search_msg->dn),
3449 ldb_dn_get_linearized(msg->dn),
3450 ldb_errstring(ldb));
3451 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
3456 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
3457 nmd.ctr.ctr1.array = talloc_array(ar,
3458 struct replPropertyMetaData1,
3459 nmd.ctr.ctr1.count);
3460 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3462 /* first copy the old meta data */
3463 for (i=0; i < omd.ctr.ctr1.count; i++) {
3464 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
3469 /* now merge in the new meta data */
3470 for (i=0; i < rmd->ctr.ctr1.count; i++) {
3473 for (j=0; j < ni; j++) {
3476 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
3480 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
3481 &rmd->ctr.ctr1.array[i]);
3483 /* replace the entry */
3484 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
3485 if (ar->seq_num == 0) {
3486 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3487 if (ret != LDB_SUCCESS) {
3488 return replmd_replicated_request_error(ar, ret);
3491 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
3496 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
3497 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
3498 msg->elements[i-removed_attrs].name,
3499 ldb_dn_get_linearized(msg->dn),
3500 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
3503 /* we don't want to apply this change so remove the attribute */
3504 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
3511 if (found) continue;
3513 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
3514 if (ar->seq_num == 0) {
3515 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3516 if (ret != LDB_SUCCESS) {
3517 return replmd_replicated_request_error(ar, ret);
3520 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
3525 * finally correct the size of the meta_data array
3527 nmd.ctr.ctr1.count = ni;
3530 * the rdn attribute (the alias for the name attribute),
3531 * 'cn' for most objects is the last entry in the meta data array
3534 * sort the new meta data array
3536 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
3537 if (ret != LDB_SUCCESS) {
3542 * check if some replicated attributes left, otherwise skip the ldb_modify() call
3544 if (msg->num_elements == 0) {
3545 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
3548 ar->index_current++;
3549 return replmd_replicated_apply_next(ar);
3552 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
3553 ar->index_current, msg->num_elements);
3555 /* create the meta data value */
3556 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
3557 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3558 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3559 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3560 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3564 * when we know that we'll modify the record, add the whenChanged, uSNChanged
3565 * and replPopertyMetaData attributes
3567 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3568 if (ret != LDB_SUCCESS) {
3569 return replmd_replicated_request_error(ar, ret);
3571 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3572 if (ret != LDB_SUCCESS) {
3573 return replmd_replicated_request_error(ar, ret);
3575 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
3576 if (ret != LDB_SUCCESS) {
3577 return replmd_replicated_request_error(ar, ret);
3580 replmd_ldb_message_sort(msg, ar->schema);
3582 /* we want to replace the old values */
3583 for (i=0; i < msg->num_elements; i++) {
3584 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3588 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3589 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
3593 ret = ldb_build_mod_req(&change_req,
3601 LDB_REQ_SET_LOCATION(change_req);
3602 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3604 /* current partition control needed by "repmd_op_callback" */
3605 ret = ldb_request_add_control(change_req,
3606 DSDB_CONTROL_CURRENT_PARTITION_OID,
3608 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3610 return ldb_next_request(ar->module, change_req);
3613 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
3614 struct ldb_reply *ares)
3616 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3617 struct replmd_replicated_request);
3621 return ldb_module_done(ar->req, NULL, NULL,
3622 LDB_ERR_OPERATIONS_ERROR);
3624 if (ares->error != LDB_SUCCESS &&
3625 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3626 return ldb_module_done(ar->req, ares->controls,
3627 ares->response, ares->error);
3630 switch (ares->type) {
3631 case LDB_REPLY_ENTRY:
3632 ar->search_msg = talloc_steal(ar, ares->message);
3635 case LDB_REPLY_REFERRAL:
3636 /* we ignore referrals */
3639 case LDB_REPLY_DONE:
3640 if (ar->search_msg != NULL) {
3641 ret = replmd_replicated_apply_merge(ar);
3643 ret = replmd_replicated_apply_add(ar);
3645 if (ret != LDB_SUCCESS) {
3646 return ldb_module_done(ar->req, NULL, NULL, ret);
3654 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3656 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3658 struct ldb_context *ldb;
3662 struct ldb_request *search_req;
3663 struct ldb_search_options_control *options;
3665 if (ar->index_current >= ar->objs->num_objects) {
3666 /* done with it, go to next stage */
3667 return replmd_replicated_uptodate_vector(ar);
3670 ldb = ldb_module_get_ctx(ar->module);
3671 ar->search_msg = NULL;
3673 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3674 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3676 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3677 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3678 talloc_free(tmp_str);
3680 ret = ldb_build_search_req(&search_req,
3689 replmd_replicated_apply_search_callback,
3691 LDB_REQ_SET_LOCATION(search_req);
3693 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
3695 if (ret != LDB_SUCCESS) {
3699 /* we need to cope with cross-partition links, so search for
3700 the GUID over all partitions */
3701 options = talloc(search_req, struct ldb_search_options_control);
3702 if (options == NULL) {
3703 DEBUG(0, (__location__ ": out of memory\n"));
3704 return LDB_ERR_OPERATIONS_ERROR;
3706 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3708 ret = ldb_request_add_control(search_req,
3709 LDB_CONTROL_SEARCH_OPTIONS_OID,
3711 if (ret != LDB_SUCCESS) {
3715 return ldb_next_request(ar->module, search_req);
3718 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
3719 struct ldb_reply *ares)
3721 struct ldb_context *ldb;
3722 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3723 struct replmd_replicated_request);
3724 ldb = ldb_module_get_ctx(ar->module);
3727 return ldb_module_done(ar->req, NULL, NULL,
3728 LDB_ERR_OPERATIONS_ERROR);
3730 if (ares->error != LDB_SUCCESS) {
3731 return ldb_module_done(ar->req, ares->controls,
3732 ares->response, ares->error);
3735 if (ares->type != LDB_REPLY_DONE) {
3736 ldb_set_errstring(ldb, "Invalid reply type\n!");
3737 return ldb_module_done(ar->req, NULL, NULL,
3738 LDB_ERR_OPERATIONS_ERROR);
3743 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3746 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3748 struct ldb_context *ldb;
3749 struct ldb_request *change_req;
3750 enum ndr_err_code ndr_err;
3751 struct ldb_message *msg;
3752 struct replUpToDateVectorBlob ouv;
3753 const struct ldb_val *ouv_value;
3754 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3755 struct replUpToDateVectorBlob nuv;
3756 struct ldb_val nuv_value;
3757 struct ldb_message_element *nuv_el = NULL;
3758 const struct GUID *our_invocation_id;
3759 struct ldb_message_element *orf_el = NULL;
3760 struct repsFromToBlob nrf;
3761 struct ldb_val *nrf_value = NULL;
3762 struct ldb_message_element *nrf_el = NULL;
3766 time_t t = time(NULL);
3769 uint32_t instanceType;
3771 ldb = ldb_module_get_ctx(ar->module);
3772 ruv = ar->objs->uptodateness_vector;
3778 unix_to_nt_time(&now, t);
3780 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
3781 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
3782 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
3783 ldb_dn_get_linearized(ar->search_msg->dn)));
3784 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3788 * first create the new replUpToDateVector
3790 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
3792 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
3793 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3794 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3795 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3796 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3799 if (ouv.version != 2) {
3800 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3805 * the new uptodateness vector will at least
3806 * contain 1 entry, one for the source_dsa
3808 * plus optional values from our old vector and the one from the source_dsa
3810 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
3811 if (ruv) nuv.ctr.ctr2.count += ruv->count;
3812 nuv.ctr.ctr2.cursors = talloc_array(ar,
3813 struct drsuapi_DsReplicaCursor2,
3814 nuv.ctr.ctr2.count);
3815 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3817 /* first copy the old vector */
3818 for (i=0; i < ouv.ctr.ctr2.count; i++) {
3819 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
3823 /* get our invocation_id if we have one already attached to the ldb */
3824 our_invocation_id = samdb_ntds_invocation_id(ldb);
3826 /* merge in the source_dsa vector is available */
3827 for (i=0; (ruv && i < ruv->count); i++) {
3830 if (our_invocation_id &&
3831 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3832 our_invocation_id)) {
3836 for (j=0; j < ni; j++) {
3837 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3838 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3845 * we update only the highest_usn and not the latest_sync_success time,
3846 * because the last success stands for direct replication
3848 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3849 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3854 if (found) continue;
3856 /* if it's not there yet, add it */
3857 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3862 * merge in the current highwatermark for the source_dsa
3865 for (j=0; j < ni; j++) {
3866 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
3867 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3874 * here we update the highest_usn and last_sync_success time
3875 * because we're directly replicating from the source_dsa
3877 * and use the tmp_highest_usn because this is what we have just applied
3880 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3881 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
3886 * here we update the highest_usn and last_sync_success time
3887 * because we're directly replicating from the source_dsa
3889 * and use the tmp_highest_usn because this is what we have just applied
3892 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
3893 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3894 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
3899 * finally correct the size of the cursors array
3901 nuv.ctr.ctr2.count = ni;
3906 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
3909 * create the change ldb_message
3911 msg = ldb_msg_new(ar);
3912 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3913 msg->dn = ar->search_msg->dn;
3915 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
3916 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3917 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3918 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3919 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3921 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3922 if (ret != LDB_SUCCESS) {
3923 return replmd_replicated_request_error(ar, ret);
3925 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3928 * now create the new repsFrom value from the given repsFromTo1 structure
3932 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3933 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3936 * first see if we already have a repsFrom value for the current source dsa
3937 * if so we'll later replace this value
3939 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3941 for (i=0; i < orf_el->num_values; i++) {
3942 struct repsFromToBlob *trf;
3944 trf = talloc(ar, struct repsFromToBlob);
3945 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3947 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
3948 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3949 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3950 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3951 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3954 if (trf->version != 1) {
3955 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3959 * we compare the source dsa objectGUID not the invocation_id
3960 * because we want only one repsFrom value per source dsa
3961 * and when the invocation_id of the source dsa has changed we don't need
3962 * the old repsFrom with the old invocation_id
3964 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3965 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3971 nrf_value = &orf_el->values[i];
3976 * copy over all old values to the new ldb_message
3978 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3979 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3984 * if we haven't found an old repsFrom value for the current source dsa
3985 * we'll add a new value
3988 struct ldb_val zero_value;
3989 ZERO_STRUCT(zero_value);
3990 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3991 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3993 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3996 /* we now fill the value which is already attached to ldb_message */
3997 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3999 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
4000 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4001 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4002 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4006 * the ldb_message_element for the attribute, has all the old values and the new one
4007 * so we'll replace the whole attribute with all values
4009 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
4012 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4013 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
4017 /* prepare the ldb_modify() request */
4018 ret = ldb_build_mod_req(&change_req,
4024 replmd_replicated_uptodate_modify_callback,
4026 LDB_REQ_SET_LOCATION(change_req);
4027 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4029 return ldb_next_request(ar->module, change_req);
4032 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
4033 struct ldb_reply *ares)
4035 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4036 struct replmd_replicated_request);
4040 return ldb_module_done(ar->req, NULL, NULL,
4041 LDB_ERR_OPERATIONS_ERROR);
4043 if (ares->error != LDB_SUCCESS &&
4044 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4045 return ldb_module_done(ar->req, ares->controls,
4046 ares->response, ares->error);
4049 switch (ares->type) {
4050 case LDB_REPLY_ENTRY:
4051 ar->search_msg = talloc_steal(ar, ares->message);
4054 case LDB_REPLY_REFERRAL:
4055 /* we ignore referrals */
4058 case LDB_REPLY_DONE:
4059 if (ar->search_msg == NULL) {
4060 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4062 ret = replmd_replicated_uptodate_modify(ar);
4064 if (ret != LDB_SUCCESS) {
4065 return ldb_module_done(ar->req, NULL, NULL, ret);
4074 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
4076 struct ldb_context *ldb;
4078 static const char *attrs[] = {
4079 "replUpToDateVector",
4084 struct ldb_request *search_req;
4086 ldb = ldb_module_get_ctx(ar->module);
4087 ar->search_msg = NULL;
4089 ret = ldb_build_search_req(&search_req,
4092 ar->objs->partition_dn,
4098 replmd_replicated_uptodate_search_callback,
4100 LDB_REQ_SET_LOCATION(search_req);
4101 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4103 return ldb_next_request(ar->module, search_req);
4108 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
4110 struct ldb_context *ldb;
4111 struct dsdb_extended_replicated_objects *objs;
4112 struct replmd_replicated_request *ar;
4113 struct ldb_control **ctrls;
4116 struct replmd_private *replmd_private =
4117 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4119 ldb = ldb_module_get_ctx(module);
4121 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
4123 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
4125 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
4126 return LDB_ERR_PROTOCOL_ERROR;
4129 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
4130 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
4131 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
4132 return LDB_ERR_PROTOCOL_ERROR;
4135 ar = replmd_ctx_init(module, req);
4137 return LDB_ERR_OPERATIONS_ERROR;
4139 /* Set the flags to have the replmd_op_callback run over the full set of objects */
4140 ar->apply_mode = true;
4142 ar->schema = dsdb_get_schema(ldb, ar);
4144 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
4146 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4147 return LDB_ERR_CONSTRAINT_VIOLATION;
4150 ctrls = req->controls;
4152 if (req->controls) {
4153 req->controls = talloc_memdup(ar, req->controls,
4154 talloc_get_size(req->controls));
4155 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4158 /* This allows layers further down to know if a change came in over replication */
4159 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
4160 if (ret != LDB_SUCCESS) {
4164 /* If this change contained linked attributes in the body
4165 * (rather than in the links section) we need to update
4166 * backlinks in linked_attributes */
4167 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
4168 if (ret != LDB_SUCCESS) {
4172 ar->controls = req->controls;
4173 req->controls = ctrls;
4175 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
4177 /* save away the linked attributes for the end of the
4179 for (i=0; i<ar->objs->linked_attributes_count; i++) {
4180 struct la_entry *la_entry;
4182 if (replmd_private->la_ctx == NULL) {
4183 replmd_private->la_ctx = talloc_new(replmd_private);
4185 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
4186 if (la_entry == NULL) {
4188 return LDB_ERR_OPERATIONS_ERROR;
4190 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
4191 if (la_entry->la == NULL) {
4192 talloc_free(la_entry);
4194 return LDB_ERR_OPERATIONS_ERROR;
4196 *la_entry->la = ar->objs->linked_attributes[i];
4198 /* we need to steal the non-scalars so they stay
4199 around until the end of the transaction */
4200 talloc_steal(la_entry->la, la_entry->la->identifier);
4201 talloc_steal(la_entry->la, la_entry->la->value.blob);
4203 DLIST_ADD(replmd_private->la_list, la_entry);
4206 return replmd_replicated_apply_next(ar);
4210 process one linked attribute structure
4212 static int replmd_process_linked_attribute(struct ldb_module *module,
4213 struct la_entry *la_entry,
4214 struct ldb_request *parent)
4216 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
4217 struct ldb_context *ldb = ldb_module_get_ctx(module);
4218 struct ldb_message *msg;
4219 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
4220 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
4222 const struct dsdb_attribute *attr;
4223 struct dsdb_dn *dsdb_dn;
4224 uint64_t seq_num = 0;
4225 struct ldb_message_element *old_el;
4227 time_t t = time(NULL);
4228 struct ldb_result *res;
4229 const char *attrs[2];
4230 struct parsed_dn *pdn_list, *pdn;
4231 struct GUID guid = GUID_zero();
4233 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
4234 const struct GUID *our_invocation_id;
4237 linked_attributes[0]:
4238 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
4240 identifier: struct drsuapi_DsReplicaObjectIdentifier
4241 __ndr_size : 0x0000003a (58)
4242 __ndr_size_sid : 0x00000000 (0)
4243 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
4245 __ndr_size_dn : 0x00000000 (0)
4247 attid : DRSUAPI_ATTID_member (0x1F)
4248 value: struct drsuapi_DsAttributeValue
4249 __ndr_size : 0x0000007e (126)
4251 blob : DATA_BLOB length=126
4252 flags : 0x00000001 (1)
4253 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
4254 originating_add_time : Wed Sep 2 22:20:01 2009 EST
4255 meta_data: struct drsuapi_DsReplicaMetaData
4256 version : 0x00000015 (21)
4257 originating_change_time : Wed Sep 2 23:39:07 2009 EST
4258 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
4259 originating_usn : 0x000000000001e19c (123292)
4261 (for cases where the link is to a normal DN)
4262 &target: struct drsuapi_DsReplicaObjectIdentifier3
4263 __ndr_size : 0x0000007e (126)
4264 __ndr_size_sid : 0x0000001c (28)
4265 guid : 7639e594-db75-4086-b0d4-67890ae46031
4266 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
4267 __ndr_size_dn : 0x00000022 (34)
4268 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
4271 /* find the attribute being modified */
4272 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
4274 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
4275 talloc_free(tmp_ctx);
4276 return LDB_ERR_OPERATIONS_ERROR;
4279 attrs[0] = attr->lDAPDisplayName;
4282 /* get the existing message from the db for the object with
4283 this GUID, returning attribute being modified. We will then
4284 use this msg as the basis for a modify call */
4285 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
4286 DSDB_FLAG_NEXT_MODULE |
4287 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
4288 DSDB_SEARCH_SHOW_RECYCLED |
4289 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4290 DSDB_SEARCH_REVEAL_INTERNALS,
4292 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
4293 if (ret != LDB_SUCCESS) {
4294 talloc_free(tmp_ctx);
4297 if (res->count != 1) {
4298 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
4299 GUID_string(tmp_ctx, &la->identifier->guid));
4300 talloc_free(tmp_ctx);
4301 return LDB_ERR_NO_SUCH_OBJECT;
4305 if (msg->num_elements == 0) {
4306 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
4307 if (ret != LDB_SUCCESS) {
4308 ldb_module_oom(module);
4309 talloc_free(tmp_ctx);
4310 return LDB_ERR_OPERATIONS_ERROR;
4313 old_el = &msg->elements[0];
4314 old_el->flags = LDB_FLAG_MOD_REPLACE;
4317 /* parse the existing links */
4318 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
4319 if (ret != LDB_SUCCESS) {
4320 talloc_free(tmp_ctx);
4324 /* get our invocationId */
4325 our_invocation_id = samdb_ntds_invocation_id(ldb);
4326 if (!our_invocation_id) {
4327 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
4328 talloc_free(tmp_ctx);
4329 return LDB_ERR_OPERATIONS_ERROR;
4332 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
4333 if (ret != LDB_SUCCESS) {
4334 talloc_free(tmp_ctx);
4338 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
4339 if (!W_ERROR_IS_OK(status)) {
4340 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
4341 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
4342 return LDB_ERR_OPERATIONS_ERROR;
4345 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
4346 if (!NT_STATUS_IS_OK(ntstatus) && active) {
4347 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
4349 ldb_dn_get_linearized(dsdb_dn->dn),
4350 ldb_dn_get_linearized(msg->dn));
4351 return LDB_ERR_OPERATIONS_ERROR;
4354 /* re-resolve the DN by GUID, as the DRS server may give us an
4356 ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
4357 if (ret != LDB_SUCCESS) {
4358 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s",
4359 GUID_string(tmp_ctx, &guid),
4360 ldb_dn_get_linearized(dsdb_dn->dn)));
4363 /* see if this link already exists */
4364 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
4366 /* see if this update is newer than what we have already */
4367 struct GUID invocation_id = GUID_zero();
4368 uint32_t version = 0;
4369 uint32_t originating_usn = 0;
4370 NTTIME change_time = 0;
4371 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
4373 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
4374 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
4375 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
4376 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
4378 if (!replmd_update_is_newer(&invocation_id,
4379 &la->meta_data.originating_invocation_id,
4381 la->meta_data.version,
4383 la->meta_data.originating_change_time)) {
4384 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
4385 old_el->name, ldb_dn_get_linearized(msg->dn),
4386 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
4387 talloc_free(tmp_ctx);
4391 /* get a seq_num for this change */
4392 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4393 if (ret != LDB_SUCCESS) {
4394 talloc_free(tmp_ctx);
4398 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
4399 /* remove the existing backlink */
4400 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
4401 if (ret != LDB_SUCCESS) {
4402 talloc_free(tmp_ctx);
4407 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
4408 &la->meta_data.originating_invocation_id,
4409 la->meta_data.originating_usn, seq_num,
4410 la->meta_data.originating_change_time,
4411 la->meta_data.version,
4413 if (ret != LDB_SUCCESS) {
4414 talloc_free(tmp_ctx);
4419 /* add the new backlink */
4420 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
4421 if (ret != LDB_SUCCESS) {
4422 talloc_free(tmp_ctx);
4427 /* get a seq_num for this change */
4428 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4429 if (ret != LDB_SUCCESS) {
4430 talloc_free(tmp_ctx);
4434 old_el->values = talloc_realloc(msg->elements, old_el->values,
4435 struct ldb_val, old_el->num_values+1);
4436 if (!old_el->values) {
4437 ldb_module_oom(module);
4438 return LDB_ERR_OPERATIONS_ERROR;
4440 old_el->num_values++;
4442 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
4443 &la->meta_data.originating_invocation_id,
4444 la->meta_data.originating_usn, seq_num,
4445 la->meta_data.originating_change_time,
4446 la->meta_data.version,
4447 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
4448 if (ret != LDB_SUCCESS) {
4449 talloc_free(tmp_ctx);
4454 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
4456 if (ret != LDB_SUCCESS) {
4457 talloc_free(tmp_ctx);
4463 /* we only change whenChanged and uSNChanged if the seq_num
4465 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
4466 talloc_free(tmp_ctx);
4467 return ldb_operr(ldb);
4470 if (add_uint64_element(ldb, msg, "uSNChanged",
4471 seq_num) != LDB_SUCCESS) {
4472 talloc_free(tmp_ctx);
4473 return ldb_operr(ldb);
4476 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
4477 if (old_el == NULL) {
4478 talloc_free(tmp_ctx);
4479 return ldb_operr(ldb);
4482 ret = dsdb_check_single_valued_link(attr, old_el);
4483 if (ret != LDB_SUCCESS) {
4484 talloc_free(tmp_ctx);
4488 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
4490 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
4491 if (ret != LDB_SUCCESS) {
4492 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
4494 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
4495 talloc_free(tmp_ctx);
4499 talloc_free(tmp_ctx);
4504 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
4506 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
4507 return replmd_extended_replicated_objects(module, req);
4510 return ldb_next_request(module, req);
4515 we hook into the transaction operations to allow us to
4516 perform the linked attribute updates at the end of the whole
4517 transaction. This allows a forward linked attribute to be created
4518 before the object is created. During a vampire, w2k8 sends us linked
4519 attributes before the objects they are part of.
4521 static int replmd_start_transaction(struct ldb_module *module)
4523 /* create our private structure for this transaction */
4524 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
4525 struct replmd_private);
4526 replmd_txn_cleanup(replmd_private);
4528 /* free any leftover mod_usn records from cancelled
4530 while (replmd_private->ncs) {
4531 struct nc_entry *e = replmd_private->ncs;
4532 DLIST_REMOVE(replmd_private->ncs, e);
4536 return ldb_next_start_trans(module);
4540 on prepare commit we loop over our queued la_context structures and
4543 static int replmd_prepare_commit(struct ldb_module *module)
4545 struct replmd_private *replmd_private =
4546 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4547 struct la_entry *la, *prev;
4548 struct la_backlink *bl;
4551 /* walk the list backwards, to do the first entry first, as we
4552 * added the entries with DLIST_ADD() which puts them at the
4553 * start of the list */
4554 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
4555 prev = DLIST_PREV(la);
4556 DLIST_REMOVE(replmd_private->la_list, la);
4557 ret = replmd_process_linked_attribute(module, la, NULL);
4558 if (ret != LDB_SUCCESS) {
4559 replmd_txn_cleanup(replmd_private);
4564 /* process our backlink list, creating and deleting backlinks
4566 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
4567 ret = replmd_process_backlink(module, bl, NULL);
4568 if (ret != LDB_SUCCESS) {
4569 replmd_txn_cleanup(replmd_private);
4574 replmd_txn_cleanup(replmd_private);
4576 /* possibly change @REPLCHANGED */
4577 ret = replmd_notify_store(module, NULL);
4578 if (ret != LDB_SUCCESS) {
4582 return ldb_next_prepare_commit(module);
4585 static int replmd_del_transaction(struct ldb_module *module)
4587 struct replmd_private *replmd_private =
4588 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4589 replmd_txn_cleanup(replmd_private);
4591 return ldb_next_del_trans(module);
4595 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
4596 .name = "repl_meta_data",
4597 .init_context = replmd_init,
4599 .modify = replmd_modify,
4600 .rename = replmd_rename,
4601 .del = replmd_delete,
4602 .extended = replmd_extended,
4603 .start_transaction = replmd_start_transaction,
4604 .prepare_commit = replmd_prepare_commit,
4605 .del_transaction = replmd_del_transaction,
4608 int ldb_repl_meta_data_module_init(const char *version)
4610 LDB_MODULE_CHECK_VERSION(version);
4611 return ldb_register_module(&ldb_repl_meta_data_module_ops);