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 const char * const *rename_attrs,
1130 struct ldb_message *msg, uint64_t *seq_num,
1134 const struct ldb_val *omd_value;
1135 enum ndr_err_code ndr_err;
1136 struct replPropertyMetaDataBlob omd;
1139 const struct GUID *our_invocation_id;
1141 const char * const *attrs = NULL;
1142 const char * const attrs1[] = { "replPropertyMetaData", "*", NULL };
1143 const char * const attrs2[] = { "uSNChanged", "objectClass", NULL };
1144 struct ldb_result *res;
1145 struct ldb_context *ldb;
1146 struct ldb_message_element *objectclass_el;
1147 enum urgent_situation situation;
1148 bool rodc, rmd_is_provided;
1151 attrs = rename_attrs;
1156 ldb = ldb_module_get_ctx(module);
1158 our_invocation_id = samdb_ntds_invocation_id(ldb);
1159 if (!our_invocation_id) {
1160 /* this happens during an initial vampire while
1161 updating the schema */
1162 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1166 unix_to_nt_time(&now, t);
1168 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1169 rmd_is_provided = true;
1171 rmd_is_provided = false;
1174 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1175 * otherwise we consider we are updating */
1176 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1177 situation = REPL_URGENT_ON_DELETE;
1178 } else if (rename_attrs) {
1179 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1181 situation = REPL_URGENT_ON_UPDATE;
1184 if (rmd_is_provided) {
1185 /* In this case the change_replmetadata control was supplied */
1186 /* We check that it's the only attribute that is provided
1187 * (it's a rare case so it's better to keep the code simplier)
1188 * We also check that the highest local_usn is bigger than
1191 if( msg->num_elements != 1 ||
1192 strncmp(msg->elements[0].name,
1193 "replPropertyMetaData", 20) ) {
1194 DEBUG(0,(__location__ ": changereplmetada control called without "\
1195 "a specified replPropertyMetaData attribute or with others\n"));
1196 return LDB_ERR_OPERATIONS_ERROR;
1198 if (situation != REPL_URGENT_ON_UPDATE) {
1199 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1200 return LDB_ERR_OPERATIONS_ERROR;
1202 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1204 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1205 ldb_dn_get_linearized(msg->dn)));
1206 return LDB_ERR_OPERATIONS_ERROR;
1208 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1209 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1210 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1211 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1212 ldb_dn_get_linearized(msg->dn)));
1213 return LDB_ERR_OPERATIONS_ERROR;
1215 *seq_num = find_max_local_usn(omd);
1217 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1218 DSDB_FLAG_NEXT_MODULE |
1219 DSDB_SEARCH_SHOW_RECYCLED |
1220 DSDB_SEARCH_SHOW_EXTENDED_DN |
1221 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1222 DSDB_SEARCH_REVEAL_INTERNALS, req);
1224 if (ret != LDB_SUCCESS || res->count != 1) {
1225 DEBUG(0,(__location__ ": Object %s failed to find uSNChanged\n",
1226 ldb_dn_get_linearized(msg->dn)));
1227 return LDB_ERR_OPERATIONS_ERROR;
1230 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1231 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1236 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1237 if (*seq_num <= db_seq) {
1238 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\
1239 " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n",
1240 (long long)*seq_num, (long long)db_seq));
1241 return LDB_ERR_OPERATIONS_ERROR;
1245 /* search for the existing replPropertyMetaDataBlob. We need
1246 * to use REVEAL and ask for DNs in storage format to support
1247 * the check for values being the same in
1248 * replmd_update_rpmd_element()
1250 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1251 DSDB_FLAG_NEXT_MODULE |
1252 DSDB_SEARCH_SHOW_RECYCLED |
1253 DSDB_SEARCH_SHOW_EXTENDED_DN |
1254 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1255 DSDB_SEARCH_REVEAL_INTERNALS, req);
1256 if (ret != LDB_SUCCESS || res->count != 1) {
1257 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1258 ldb_dn_get_linearized(msg->dn)));
1259 return LDB_ERR_OPERATIONS_ERROR;
1262 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1263 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1268 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1270 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1271 ldb_dn_get_linearized(msg->dn)));
1272 return LDB_ERR_OPERATIONS_ERROR;
1275 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1276 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1278 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1279 ldb_dn_get_linearized(msg->dn)));
1280 return LDB_ERR_OPERATIONS_ERROR;
1283 if (omd.version != 1) {
1284 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1285 omd.version, ldb_dn_get_linearized(msg->dn)));
1286 return LDB_ERR_OPERATIONS_ERROR;
1289 for (i=0; i<msg->num_elements; i++) {
1290 struct ldb_message_element *old_el;
1291 old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1292 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1293 our_invocation_id, now);
1294 if (ret != LDB_SUCCESS) {
1298 if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1299 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1305 * replmd_update_rpmd_element has done an update if the
1308 if (*seq_num != 0) {
1309 struct ldb_val *md_value;
1310 struct ldb_message_element *el;
1312 /*if we are RODC and this is a DRSR update then its ok*/
1313 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1314 ret = samdb_rodc(ldb, &rodc);
1315 if (ret != LDB_SUCCESS) {
1316 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1318 ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n");
1319 return LDB_ERR_REFERRAL;
1323 md_value = talloc(msg, struct ldb_val);
1324 if (md_value == NULL) {
1326 return LDB_ERR_OPERATIONS_ERROR;
1329 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1330 if (ret != LDB_SUCCESS) {
1334 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1335 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1336 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1337 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1338 ldb_dn_get_linearized(msg->dn)));
1339 return LDB_ERR_OPERATIONS_ERROR;
1342 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1343 if (ret != LDB_SUCCESS) {
1344 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1345 ldb_dn_get_linearized(msg->dn)));
1350 el->values = md_value;
1357 struct dsdb_dn *dsdb_dn;
1362 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1364 return GUID_compare(pdn1->guid, pdn2->guid);
1367 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1368 unsigned int count, struct GUID *guid,
1371 struct parsed_dn *ret;
1373 if (dn && GUID_all_zero(guid)) {
1374 /* when updating a link using DRS, we sometimes get a
1375 NULL GUID. We then need to try and match by DN */
1376 for (i=0; i<count; i++) {
1377 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1378 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1384 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1389 get a series of message element values as an array of DNs and GUIDs
1390 the result is sorted by GUID
1392 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1393 struct ldb_message_element *el, struct parsed_dn **pdn,
1394 const char *ldap_oid, struct ldb_request *parent)
1397 struct ldb_context *ldb = ldb_module_get_ctx(module);
1404 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1406 ldb_module_oom(module);
1407 return LDB_ERR_OPERATIONS_ERROR;
1410 for (i=0; i<el->num_values; i++) {
1411 struct ldb_val *v = &el->values[i];
1414 struct parsed_dn *p;
1418 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1419 if (p->dsdb_dn == NULL) {
1420 return LDB_ERR_INVALID_DN_SYNTAX;
1423 dn = p->dsdb_dn->dn;
1425 p->guid = talloc(*pdn, struct GUID);
1426 if (p->guid == NULL) {
1427 ldb_module_oom(module);
1428 return LDB_ERR_OPERATIONS_ERROR;
1431 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1432 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1433 /* we got a DN without a GUID - go find the GUID */
1434 int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1435 if (ret != LDB_SUCCESS) {
1436 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1437 ldb_dn_get_linearized(dn));
1440 ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1441 if (ret != LDB_SUCCESS) {
1444 } else if (!NT_STATUS_IS_OK(status)) {
1445 return LDB_ERR_OPERATIONS_ERROR;
1448 /* keep a pointer to the original ldb_val */
1452 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1458 build a new extended DN, including all meta data fields
1460 RMD_FLAGS = DSDB_RMD_FLAG_* bits
1461 RMD_ADDTIME = originating_add_time
1462 RMD_INVOCID = originating_invocation_id
1463 RMD_CHANGETIME = originating_change_time
1464 RMD_ORIGINATING_USN = originating_usn
1465 RMD_LOCAL_USN = local_usn
1466 RMD_VERSION = version
1468 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1469 const struct GUID *invocation_id, uint64_t seq_num,
1470 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1472 struct ldb_dn *dn = dsdb_dn->dn;
1473 const char *tstring, *usn_string, *flags_string;
1474 struct ldb_val tval;
1476 struct ldb_val usnv, local_usnv;
1477 struct ldb_val vers, flagsv;
1480 const char *dnstring;
1482 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1484 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1486 return LDB_ERR_OPERATIONS_ERROR;
1488 tval = data_blob_string_const(tstring);
1490 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1492 return LDB_ERR_OPERATIONS_ERROR;
1494 usnv = data_blob_string_const(usn_string);
1496 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1498 return LDB_ERR_OPERATIONS_ERROR;
1500 local_usnv = data_blob_string_const(usn_string);
1502 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1504 return LDB_ERR_OPERATIONS_ERROR;
1506 vers = data_blob_string_const(vstring);
1508 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1509 if (!NT_STATUS_IS_OK(status)) {
1510 return LDB_ERR_OPERATIONS_ERROR;
1513 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1514 if (!flags_string) {
1515 return LDB_ERR_OPERATIONS_ERROR;
1517 flagsv = data_blob_string_const(flags_string);
1519 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1520 if (ret != LDB_SUCCESS) return ret;
1521 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1522 if (ret != LDB_SUCCESS) return ret;
1523 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1524 if (ret != LDB_SUCCESS) return ret;
1525 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1526 if (ret != LDB_SUCCESS) return ret;
1527 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1528 if (ret != LDB_SUCCESS) return ret;
1529 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1530 if (ret != LDB_SUCCESS) return ret;
1531 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1532 if (ret != LDB_SUCCESS) return ret;
1534 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1535 if (dnstring == NULL) {
1536 return LDB_ERR_OPERATIONS_ERROR;
1538 *v = data_blob_string_const(dnstring);
1543 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1544 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1545 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1546 uint32_t version, bool deleted);
1549 check if any links need upgrading from w2k format
1551 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.
1553 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1556 for (i=0; i<count; i++) {
1561 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1562 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1566 /* it's an old one that needs upgrading */
1567 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1569 if (ret != LDB_SUCCESS) {
1577 update an extended DN, including all meta data fields
1579 see replmd_build_la_val for value names
1581 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1582 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1583 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1584 uint32_t version, bool deleted)
1586 struct ldb_dn *dn = dsdb_dn->dn;
1587 const char *tstring, *usn_string, *flags_string;
1588 struct ldb_val tval;
1590 struct ldb_val usnv, local_usnv;
1591 struct ldb_val vers, flagsv;
1592 const struct ldb_val *old_addtime;
1593 uint32_t old_version;
1596 const char *dnstring;
1598 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1600 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1602 return LDB_ERR_OPERATIONS_ERROR;
1604 tval = data_blob_string_const(tstring);
1606 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1608 return LDB_ERR_OPERATIONS_ERROR;
1610 usnv = data_blob_string_const(usn_string);
1612 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1614 return LDB_ERR_OPERATIONS_ERROR;
1616 local_usnv = data_blob_string_const(usn_string);
1618 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1619 if (!NT_STATUS_IS_OK(status)) {
1620 return LDB_ERR_OPERATIONS_ERROR;
1623 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1624 if (!flags_string) {
1625 return LDB_ERR_OPERATIONS_ERROR;
1627 flagsv = data_blob_string_const(flags_string);
1629 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1630 if (ret != LDB_SUCCESS) return ret;
1632 /* get the ADDTIME from the original */
1633 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1634 if (old_addtime == NULL) {
1635 old_addtime = &tval;
1637 if (dsdb_dn != old_dsdb_dn) {
1638 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1639 if (ret != LDB_SUCCESS) return ret;
1642 /* use our invocation id */
1643 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1644 if (ret != LDB_SUCCESS) return ret;
1646 /* changetime is the current time */
1647 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1648 if (ret != LDB_SUCCESS) return ret;
1650 /* update the USN */
1651 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1652 if (ret != LDB_SUCCESS) return ret;
1654 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1655 if (ret != LDB_SUCCESS) return ret;
1657 /* increase the version by 1 */
1658 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1659 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1660 version = old_version+1;
1662 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1663 vers = data_blob_string_const(vstring);
1664 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1665 if (ret != LDB_SUCCESS) return ret;
1667 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1668 if (dnstring == NULL) {
1669 return LDB_ERR_OPERATIONS_ERROR;
1671 *v = data_blob_string_const(dnstring);
1677 handle adding a linked attribute
1679 static int replmd_modify_la_add(struct ldb_module *module,
1680 const struct dsdb_schema *schema,
1681 struct ldb_message *msg,
1682 struct ldb_message_element *el,
1683 struct ldb_message_element *old_el,
1684 const struct dsdb_attribute *schema_attr,
1687 struct GUID *msg_guid,
1688 struct ldb_request *parent)
1691 struct parsed_dn *dns, *old_dns;
1692 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1694 struct ldb_val *new_values = NULL;
1695 unsigned int num_new_values = 0;
1696 unsigned old_num_values = old_el?old_el->num_values:0;
1697 const struct GUID *invocation_id;
1698 struct ldb_context *ldb = ldb_module_get_ctx(module);
1701 unix_to_nt_time(&now, t);
1703 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1704 if (ret != LDB_SUCCESS) {
1705 talloc_free(tmp_ctx);
1709 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1710 if (ret != LDB_SUCCESS) {
1711 talloc_free(tmp_ctx);
1715 invocation_id = samdb_ntds_invocation_id(ldb);
1716 if (!invocation_id) {
1717 talloc_free(tmp_ctx);
1718 return LDB_ERR_OPERATIONS_ERROR;
1721 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1722 if (ret != LDB_SUCCESS) {
1723 talloc_free(tmp_ctx);
1727 /* for each new value, see if it exists already with the same GUID */
1728 for (i=0; i<el->num_values; i++) {
1729 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1731 /* this is a new linked attribute value */
1732 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1733 if (new_values == NULL) {
1734 ldb_module_oom(module);
1735 talloc_free(tmp_ctx);
1736 return LDB_ERR_OPERATIONS_ERROR;
1738 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1739 invocation_id, seq_num, seq_num, now, 0, false);
1740 if (ret != LDB_SUCCESS) {
1741 talloc_free(tmp_ctx);
1746 /* this is only allowed if the GUID was
1747 previously deleted. */
1748 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1750 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1751 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1752 el->name, GUID_string(tmp_ctx, p->guid));
1753 talloc_free(tmp_ctx);
1754 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1756 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1757 invocation_id, seq_num, seq_num, now, 0, false);
1758 if (ret != LDB_SUCCESS) {
1759 talloc_free(tmp_ctx);
1764 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1765 if (ret != LDB_SUCCESS) {
1766 talloc_free(tmp_ctx);
1771 /* add the new ones on to the end of the old values, constructing a new el->values */
1772 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1774 old_num_values+num_new_values);
1775 if (el->values == NULL) {
1776 ldb_module_oom(module);
1777 return LDB_ERR_OPERATIONS_ERROR;
1780 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1781 el->num_values = old_num_values + num_new_values;
1783 talloc_steal(msg->elements, el->values);
1784 talloc_steal(el->values, new_values);
1786 talloc_free(tmp_ctx);
1788 /* we now tell the backend to replace all existing values
1789 with the one we have constructed */
1790 el->flags = LDB_FLAG_MOD_REPLACE;
1797 handle deleting all active linked attributes
1799 static int replmd_modify_la_delete(struct ldb_module *module,
1800 const struct dsdb_schema *schema,
1801 struct ldb_message *msg,
1802 struct ldb_message_element *el,
1803 struct ldb_message_element *old_el,
1804 const struct dsdb_attribute *schema_attr,
1807 struct GUID *msg_guid,
1808 struct ldb_request *parent)
1811 struct parsed_dn *dns, *old_dns;
1812 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1814 const struct GUID *invocation_id;
1815 struct ldb_context *ldb = ldb_module_get_ctx(module);
1818 unix_to_nt_time(&now, t);
1820 /* check if there is nothing to delete */
1821 if ((!old_el || old_el->num_values == 0) &&
1822 el->num_values == 0) {
1826 if (!old_el || old_el->num_values == 0) {
1827 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1830 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1831 if (ret != LDB_SUCCESS) {
1832 talloc_free(tmp_ctx);
1836 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1837 if (ret != LDB_SUCCESS) {
1838 talloc_free(tmp_ctx);
1842 invocation_id = samdb_ntds_invocation_id(ldb);
1843 if (!invocation_id) {
1844 return LDB_ERR_OPERATIONS_ERROR;
1847 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1848 if (ret != LDB_SUCCESS) {
1849 talloc_free(tmp_ctx);
1855 /* see if we are being asked to delete any links that
1856 don't exist or are already deleted */
1857 for (i=0; i<el->num_values; i++) {
1858 struct parsed_dn *p = &dns[i];
1859 struct parsed_dn *p2;
1862 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1864 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1865 el->name, GUID_string(tmp_ctx, p->guid));
1866 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1868 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1869 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1870 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1871 el->name, GUID_string(tmp_ctx, p->guid));
1872 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1876 /* for each new value, see if it exists already with the same GUID
1877 if it is not already deleted and matches the delete list then delete it
1879 for (i=0; i<old_el->num_values; i++) {
1880 struct parsed_dn *p = &old_dns[i];
1883 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1887 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1888 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1890 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1891 invocation_id, seq_num, seq_num, now, 0, true);
1892 if (ret != LDB_SUCCESS) {
1893 talloc_free(tmp_ctx);
1897 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1898 if (ret != LDB_SUCCESS) {
1899 talloc_free(tmp_ctx);
1904 el->values = talloc_steal(msg->elements, old_el->values);
1905 el->num_values = old_el->num_values;
1907 talloc_free(tmp_ctx);
1909 /* we now tell the backend to replace all existing values
1910 with the one we have constructed */
1911 el->flags = LDB_FLAG_MOD_REPLACE;
1917 handle replacing a linked attribute
1919 static int replmd_modify_la_replace(struct ldb_module *module,
1920 const struct dsdb_schema *schema,
1921 struct ldb_message *msg,
1922 struct ldb_message_element *el,
1923 struct ldb_message_element *old_el,
1924 const struct dsdb_attribute *schema_attr,
1927 struct GUID *msg_guid,
1928 struct ldb_request *parent)
1931 struct parsed_dn *dns, *old_dns;
1932 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1934 const struct GUID *invocation_id;
1935 struct ldb_context *ldb = ldb_module_get_ctx(module);
1936 struct ldb_val *new_values = NULL;
1937 unsigned int num_new_values = 0;
1938 unsigned int old_num_values = old_el?old_el->num_values:0;
1941 unix_to_nt_time(&now, t);
1943 /* check if there is nothing to replace */
1944 if ((!old_el || old_el->num_values == 0) &&
1945 el->num_values == 0) {
1949 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1950 if (ret != LDB_SUCCESS) {
1951 talloc_free(tmp_ctx);
1955 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1956 if (ret != LDB_SUCCESS) {
1957 talloc_free(tmp_ctx);
1961 invocation_id = samdb_ntds_invocation_id(ldb);
1962 if (!invocation_id) {
1963 return LDB_ERR_OPERATIONS_ERROR;
1966 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1967 if (ret != LDB_SUCCESS) {
1968 talloc_free(tmp_ctx);
1972 /* mark all the old ones as deleted */
1973 for (i=0; i<old_num_values; i++) {
1974 struct parsed_dn *old_p = &old_dns[i];
1975 struct parsed_dn *p;
1976 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1978 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1980 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1981 if (ret != LDB_SUCCESS) {
1982 talloc_free(tmp_ctx);
1986 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1988 /* we don't delete it if we are re-adding it */
1992 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1993 invocation_id, seq_num, seq_num, now, 0, true);
1994 if (ret != LDB_SUCCESS) {
1995 talloc_free(tmp_ctx);
2000 /* for each new value, either update its meta-data, or add it
2003 for (i=0; i<el->num_values; i++) {
2004 struct parsed_dn *p = &dns[i], *old_p;
2007 (old_p = parsed_dn_find(old_dns,
2008 old_num_values, p->guid, NULL)) != NULL) {
2009 /* update in place */
2010 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
2011 old_p->dsdb_dn, invocation_id,
2012 seq_num, seq_num, now, 0, false);
2013 if (ret != LDB_SUCCESS) {
2014 talloc_free(tmp_ctx);
2019 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2021 if (new_values == NULL) {
2022 ldb_module_oom(module);
2023 talloc_free(tmp_ctx);
2024 return LDB_ERR_OPERATIONS_ERROR;
2026 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2027 invocation_id, seq_num, seq_num, now, 0, false);
2028 if (ret != LDB_SUCCESS) {
2029 talloc_free(tmp_ctx);
2035 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2036 if (ret != LDB_SUCCESS) {
2037 talloc_free(tmp_ctx);
2042 /* add the new values to the end of old_el */
2043 if (num_new_values != 0) {
2044 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2045 struct ldb_val, old_num_values+num_new_values);
2046 if (el->values == NULL) {
2047 ldb_module_oom(module);
2048 return LDB_ERR_OPERATIONS_ERROR;
2050 memcpy(&el->values[old_num_values], &new_values[0],
2051 sizeof(struct ldb_val)*num_new_values);
2052 el->num_values = old_num_values + num_new_values;
2053 talloc_steal(msg->elements, new_values);
2055 el->values = old_el->values;
2056 el->num_values = old_el->num_values;
2057 talloc_steal(msg->elements, el->values);
2060 talloc_free(tmp_ctx);
2062 /* we now tell the backend to replace all existing values
2063 with the one we have constructed */
2064 el->flags = LDB_FLAG_MOD_REPLACE;
2071 handle linked attributes in modify requests
2073 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2074 struct ldb_message *msg,
2075 uint64_t seq_num, time_t t,
2076 struct ldb_request *parent)
2078 struct ldb_result *res;
2081 struct ldb_context *ldb = ldb_module_get_ctx(module);
2082 struct ldb_message *old_msg;
2084 const struct dsdb_schema *schema;
2085 struct GUID old_guid;
2088 /* there the replmd_update_rpmd code has already
2089 * checked and saw that there are no linked
2094 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2095 /* don't do anything special for linked attributes */
2099 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2100 DSDB_FLAG_NEXT_MODULE |
2101 DSDB_SEARCH_SHOW_RECYCLED |
2102 DSDB_SEARCH_REVEAL_INTERNALS |
2103 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2105 if (ret != LDB_SUCCESS) {
2108 schema = dsdb_get_schema(ldb, res);
2110 return LDB_ERR_OPERATIONS_ERROR;
2113 old_msg = res->msgs[0];
2115 old_guid = samdb_result_guid(old_msg, "objectGUID");
2117 for (i=0; i<msg->num_elements; i++) {
2118 struct ldb_message_element *el = &msg->elements[i];
2119 struct ldb_message_element *old_el, *new_el;
2120 const struct dsdb_attribute *schema_attr
2121 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2123 ldb_asprintf_errstring(ldb,
2124 "%s: attribute %s is not a valid attribute in schema",
2125 __FUNCTION__, el->name);
2126 return LDB_ERR_OBJECT_CLASS_VIOLATION;
2128 if (schema_attr->linkID == 0) {
2131 if ((schema_attr->linkID & 1) == 1) {
2132 /* Odd is for the target. Illegal to modify */
2133 ldb_asprintf_errstring(ldb,
2134 "attribute %s must not be modified directly, it is a linked attribute", el->name);
2135 return LDB_ERR_UNWILLING_TO_PERFORM;
2137 old_el = ldb_msg_find_element(old_msg, el->name);
2138 switch (el->flags & LDB_FLAG_MOD_MASK) {
2139 case LDB_FLAG_MOD_REPLACE:
2140 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2142 case LDB_FLAG_MOD_DELETE:
2143 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2145 case LDB_FLAG_MOD_ADD:
2146 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2149 ldb_asprintf_errstring(ldb,
2150 "invalid flags 0x%x for %s linked attribute",
2151 el->flags, el->name);
2152 return LDB_ERR_UNWILLING_TO_PERFORM;
2154 if (ret != LDB_SUCCESS) {
2158 ldb_msg_remove_attr(old_msg, el->name);
2160 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2161 new_el->num_values = el->num_values;
2162 new_el->values = talloc_steal(msg->elements, el->values);
2164 /* TODO: this relises a bit too heavily on the exact
2165 behaviour of ldb_msg_find_element and
2166 ldb_msg_remove_element */
2167 old_el = ldb_msg_find_element(msg, el->name);
2169 ldb_msg_remove_element(msg, old_el);
2180 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2182 struct ldb_context *ldb;
2183 struct replmd_replicated_request *ac;
2184 struct ldb_request *down_req;
2185 struct ldb_message *msg;
2186 time_t t = time(NULL);
2188 bool is_urgent = false;
2189 struct loadparm_context *lp_ctx;
2191 unsigned int functional_level;
2192 const DATA_BLOB *guid_blob;
2194 /* do not manipulate our control entries */
2195 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2196 return ldb_next_request(module, req);
2199 ldb = ldb_module_get_ctx(module);
2201 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2203 guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2204 if ( guid_blob != NULL ) {
2205 ldb_set_errstring(ldb,
2206 "replmd_modify: it's not allowed to change the objectGUID!");
2207 return LDB_ERR_CONSTRAINT_VIOLATION;
2210 ac = replmd_ctx_init(module, req);
2212 return ldb_module_oom(module);
2215 functional_level = dsdb_functional_level(ldb);
2217 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2218 struct loadparm_context);
2220 /* we have to copy the message as the caller might have it as a const */
2221 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2225 return LDB_ERR_OPERATIONS_ERROR;
2228 ldb_msg_remove_attr(msg, "whenChanged");
2229 ldb_msg_remove_attr(msg, "uSNChanged");
2231 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2232 msg, &ac->seq_num, t, &is_urgent);
2233 if (ret == LDB_ERR_REFERRAL) {
2234 referral = talloc_asprintf(req,
2236 lpcfg_dnsdomain(lp_ctx),
2237 ldb_dn_get_linearized(msg->dn));
2238 ret = ldb_module_send_referral(req, referral);
2240 return ldb_module_done(req, NULL, NULL, ret);
2243 if (ret != LDB_SUCCESS) {
2248 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2249 if (ret != LDB_SUCCESS) {
2255 * - replace the old object with the newly constructed one
2258 ac->is_urgent = is_urgent;
2260 ret = ldb_build_mod_req(&down_req, ldb, ac,
2263 ac, replmd_op_callback,
2265 LDB_REQ_SET_LOCATION(down_req);
2266 if (ret != LDB_SUCCESS) {
2271 /* current partition control is needed by "replmd_op_callback" */
2272 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2273 ret = ldb_request_add_control(down_req,
2274 DSDB_CONTROL_CURRENT_PARTITION_OID,
2276 if (ret != LDB_SUCCESS) {
2282 /* If we are in functional level 2000, then
2283 * replmd_modify_handle_linked_attribs will have done
2285 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2286 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2287 if (ret != LDB_SUCCESS) {
2293 talloc_steal(down_req, msg);
2295 /* we only change whenChanged and uSNChanged if the seq_num
2297 if (ac->seq_num != 0) {
2298 ret = add_time_element(msg, "whenChanged", t);
2299 if (ret != LDB_SUCCESS) {
2304 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2305 if (ret != LDB_SUCCESS) {
2311 /* go on with the call chain */
2312 return ldb_next_request(module, down_req);
2315 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2318 handle a rename request
2320 On a rename we need to do an extra ldb_modify which sets the
2321 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2323 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2325 struct ldb_context *ldb;
2326 struct replmd_replicated_request *ac;
2328 struct ldb_request *down_req;
2330 /* do not manipulate our control entries */
2331 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2332 return ldb_next_request(module, req);
2335 ldb = ldb_module_get_ctx(module);
2337 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2339 ac = replmd_ctx_init(module, req);
2341 return ldb_module_oom(module);
2344 ret = ldb_build_rename_req(&down_req, ldb, ac,
2345 ac->req->op.rename.olddn,
2346 ac->req->op.rename.newdn,
2348 ac, replmd_rename_callback,
2350 LDB_REQ_SET_LOCATION(down_req);
2351 if (ret != LDB_SUCCESS) {
2356 /* go on with the call chain */
2357 return ldb_next_request(module, down_req);
2360 /* After the rename is compleated, update the whenchanged etc */
2361 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2363 struct ldb_context *ldb;
2364 struct replmd_replicated_request *ac;
2365 struct ldb_request *down_req;
2366 struct ldb_message *msg;
2367 time_t t = time(NULL);
2370 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2371 ldb = ldb_module_get_ctx(ac->module);
2373 if (ares->error != LDB_SUCCESS) {
2374 return ldb_module_done(ac->req, ares->controls,
2375 ares->response, ares->error);
2378 if (ares->type != LDB_REPLY_DONE) {
2379 ldb_set_errstring(ldb,
2380 "invalid ldb_reply_type in callback");
2382 return ldb_module_done(ac->req, NULL, NULL,
2383 LDB_ERR_OPERATIONS_ERROR);
2386 /* Get a sequence number from the backend */
2387 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2388 if (ret != LDB_SUCCESS) {
2393 * - replace the old object with the newly constructed one
2396 msg = ldb_msg_new(ac);
2399 return LDB_ERR_OPERATIONS_ERROR;
2402 msg->dn = ac->req->op.rename.newdn;
2404 ret = ldb_build_mod_req(&down_req, ldb, ac,
2407 ac, replmd_op_callback,
2409 LDB_REQ_SET_LOCATION(down_req);
2410 if (ret != LDB_SUCCESS) {
2415 /* current partition control is needed by "replmd_op_callback" */
2416 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2417 ret = ldb_request_add_control(down_req,
2418 DSDB_CONTROL_CURRENT_PARTITION_OID,
2420 if (ret != LDB_SUCCESS) {
2426 talloc_steal(down_req, msg);
2428 ret = add_time_element(msg, "whenChanged", t);
2429 if (ret != LDB_SUCCESS) {
2434 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2435 if (ret != LDB_SUCCESS) {
2440 /* go on with the call chain - do the modify after the rename */
2441 return ldb_next_request(ac->module, down_req);
2445 remove links from objects that point at this object when an object
2448 static int replmd_delete_remove_link(struct ldb_module *module,
2449 const struct dsdb_schema *schema,
2451 struct ldb_message_element *el,
2452 const struct dsdb_attribute *sa,
2453 struct ldb_request *parent)
2456 TALLOC_CTX *tmp_ctx = talloc_new(module);
2457 struct ldb_context *ldb = ldb_module_get_ctx(module);
2459 for (i=0; i<el->num_values; i++) {
2460 struct dsdb_dn *dsdb_dn;
2464 struct ldb_message *msg;
2465 const struct dsdb_attribute *target_attr;
2466 struct ldb_message_element *el2;
2467 struct ldb_val dn_val;
2469 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2473 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2475 talloc_free(tmp_ctx);
2476 return LDB_ERR_OPERATIONS_ERROR;
2479 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2480 if (!NT_STATUS_IS_OK(status)) {
2481 talloc_free(tmp_ctx);
2482 return LDB_ERR_OPERATIONS_ERROR;
2485 /* remove the link */
2486 msg = ldb_msg_new(tmp_ctx);
2488 ldb_module_oom(module);
2489 talloc_free(tmp_ctx);
2490 return LDB_ERR_OPERATIONS_ERROR;
2494 msg->dn = dsdb_dn->dn;
2496 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2497 if (target_attr == NULL) {
2501 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2502 if (ret != LDB_SUCCESS) {
2503 ldb_module_oom(module);
2504 talloc_free(tmp_ctx);
2505 return LDB_ERR_OPERATIONS_ERROR;
2507 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2508 el2->values = &dn_val;
2509 el2->num_values = 1;
2511 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2512 if (ret != LDB_SUCCESS) {
2513 talloc_free(tmp_ctx);
2517 talloc_free(tmp_ctx);
2523 handle update of replication meta data for deletion of objects
2525 This also handles the mapping of delete to a rename operation
2526 to allow deletes to be replicated.
2528 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2530 int ret = LDB_ERR_OTHER;
2531 bool retb, disallow_move_on_delete;
2532 struct ldb_dn *old_dn, *new_dn;
2533 const char *rdn_name;
2534 const struct ldb_val *rdn_value, *new_rdn_value;
2536 struct ldb_context *ldb = ldb_module_get_ctx(module);
2537 const struct dsdb_schema *schema;
2538 struct ldb_message *msg, *old_msg;
2539 struct ldb_message_element *el;
2540 TALLOC_CTX *tmp_ctx;
2541 struct ldb_result *res, *parent_res;
2542 const char *preserved_attrs[] = {
2543 /* yes, this really is a hard coded list. See MS-ADTS
2544 section 3.1.1.5.5.1.1 */
2545 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2546 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2547 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2548 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2549 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2550 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2551 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2552 "whenChanged", NULL};
2553 unsigned int i, el_count = 0;
2554 enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2555 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2556 enum deletion_state deletion_state, next_deletion_state;
2559 if (ldb_dn_is_special(req->op.del.dn)) {
2560 return ldb_next_request(module, req);
2563 tmp_ctx = talloc_new(ldb);
2566 return LDB_ERR_OPERATIONS_ERROR;
2569 schema = dsdb_get_schema(ldb, tmp_ctx);
2571 return LDB_ERR_OPERATIONS_ERROR;
2574 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2576 /* we need the complete msg off disk, so we can work out which
2577 attributes need to be removed */
2578 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2579 DSDB_FLAG_NEXT_MODULE |
2580 DSDB_SEARCH_SHOW_RECYCLED |
2581 DSDB_SEARCH_REVEAL_INTERNALS |
2582 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2583 if (ret != LDB_SUCCESS) {
2584 talloc_free(tmp_ctx);
2587 old_msg = res->msgs[0];
2590 ret = dsdb_recyclebin_enabled(module, &enabled);
2591 if (ret != LDB_SUCCESS) {
2592 talloc_free(tmp_ctx);
2596 if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2598 deletion_state = OBJECT_TOMBSTONE;
2599 next_deletion_state = OBJECT_REMOVED;
2600 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2601 deletion_state = OBJECT_RECYCLED;
2602 next_deletion_state = OBJECT_REMOVED;
2604 deletion_state = OBJECT_DELETED;
2605 next_deletion_state = OBJECT_RECYCLED;
2608 deletion_state = OBJECT_NOT_DELETED;
2610 next_deletion_state = OBJECT_DELETED;
2612 next_deletion_state = OBJECT_TOMBSTONE;
2616 if (next_deletion_state == OBJECT_REMOVED) {
2617 struct auth_session_info *session_info =
2618 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2619 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2620 ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2621 ldb_dn_get_linearized(old_msg->dn));
2622 return LDB_ERR_UNWILLING_TO_PERFORM;
2625 /* it is already deleted - really remove it this time */
2626 talloc_free(tmp_ctx);
2627 return ldb_next_request(module, req);
2630 rdn_name = ldb_dn_get_rdn_name(old_dn);
2631 rdn_value = ldb_dn_get_rdn_val(old_dn);
2632 if ((rdn_name == NULL) || (rdn_value == NULL)) {
2633 talloc_free(tmp_ctx);
2634 return ldb_operr(ldb);
2637 msg = ldb_msg_new(tmp_ctx);
2639 ldb_module_oom(module);
2640 talloc_free(tmp_ctx);
2641 return LDB_ERR_OPERATIONS_ERROR;
2646 if (deletion_state == OBJECT_NOT_DELETED){
2647 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2648 disallow_move_on_delete =
2649 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2650 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2652 /* work out where we will be renaming this object to */
2653 if (!disallow_move_on_delete) {
2654 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2656 if (ret != LDB_SUCCESS) {
2657 /* this is probably an attempted delete on a partition
2658 * that doesn't allow delete operations, such as the
2659 * schema partition */
2660 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2661 ldb_dn_get_linearized(old_dn));
2662 talloc_free(tmp_ctx);
2663 return LDB_ERR_UNWILLING_TO_PERFORM;
2666 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2667 if (new_dn == NULL) {
2668 ldb_module_oom(module);
2669 talloc_free(tmp_ctx);
2670 return LDB_ERR_OPERATIONS_ERROR;
2674 /* get the objects GUID from the search we just did */
2675 guid = samdb_result_guid(old_msg, "objectGUID");
2677 /* Add a formatted child */
2678 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2680 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2681 GUID_string(tmp_ctx, &guid));
2683 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2684 ldb_dn_get_linearized(new_dn)));
2685 talloc_free(tmp_ctx);
2686 return LDB_ERR_OPERATIONS_ERROR;
2689 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2690 if (ret != LDB_SUCCESS) {
2691 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2692 ldb_module_oom(module);
2693 talloc_free(tmp_ctx);
2696 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2700 now we need to modify the object in the following ways:
2702 - add isDeleted=TRUE
2703 - update rDN and name, with new rDN
2704 - remove linked attributes
2705 - remove objectCategory and sAMAccountType
2706 - remove attribs not on the preserved list
2707 - preserved if in above list, or is rDN
2708 - remove all linked attribs from this object
2709 - remove all links from other objects to this object
2710 - add lastKnownParent
2711 - update replPropertyMetaData?
2713 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2716 /* we need the storage form of the parent GUID */
2717 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2718 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2719 DSDB_FLAG_NEXT_MODULE |
2720 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2721 DSDB_SEARCH_REVEAL_INTERNALS|
2722 DSDB_SEARCH_SHOW_RECYCLED, req);
2723 if (ret != LDB_SUCCESS) {
2724 talloc_free(tmp_ctx);
2728 if (deletion_state == OBJECT_NOT_DELETED){
2729 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2730 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2731 if (ret != LDB_SUCCESS) {
2732 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2733 ldb_module_oom(module);
2734 talloc_free(tmp_ctx);
2737 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2740 switch (next_deletion_state){
2742 case OBJECT_DELETED:
2744 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2745 if (ret != LDB_SUCCESS) {
2746 DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2747 ldb_module_oom(module);
2748 talloc_free(tmp_ctx);
2751 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2753 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_DELETE, NULL);
2754 if (ret != LDB_SUCCESS) {
2755 talloc_free(tmp_ctx);
2756 ldb_module_oom(module);
2760 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_DELETE, NULL);
2761 if (ret != LDB_SUCCESS) {
2762 talloc_free(tmp_ctx);
2763 ldb_module_oom(module);
2769 case OBJECT_RECYCLED:
2770 case OBJECT_TOMBSTONE:
2772 /* we also mark it as recycled, meaning this object can't be
2773 recovered (we are stripping its attributes) */
2774 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2775 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2776 if (ret != LDB_SUCCESS) {
2777 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2778 ldb_module_oom(module);
2779 talloc_free(tmp_ctx);
2782 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2785 /* work out which of the old attributes we will be removing */
2786 for (i=0; i<old_msg->num_elements; i++) {
2787 const struct dsdb_attribute *sa;
2788 el = &old_msg->elements[i];
2789 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2791 talloc_free(tmp_ctx);
2792 return LDB_ERR_OPERATIONS_ERROR;
2794 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2795 /* don't remove the rDN */
2798 if (sa->linkID && sa->linkID & 1) {
2799 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
2800 if (ret != LDB_SUCCESS) {
2801 talloc_free(tmp_ctx);
2802 return LDB_ERR_OPERATIONS_ERROR;
2806 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2809 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2810 if (ret != LDB_SUCCESS) {
2811 talloc_free(tmp_ctx);
2812 ldb_module_oom(module);
2822 if (deletion_state == OBJECT_NOT_DELETED) {
2823 const struct dsdb_attribute *sa;
2825 /* work out what the new rdn value is, for updating the
2826 rDN and name fields */
2827 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2828 if (new_rdn_value == NULL) {
2829 talloc_free(tmp_ctx);
2830 return ldb_operr(ldb);
2833 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
2835 talloc_free(tmp_ctx);
2836 return LDB_ERR_OPERATIONS_ERROR;
2839 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
2841 if (ret != LDB_SUCCESS) {
2842 talloc_free(tmp_ctx);
2845 el->flags = LDB_FLAG_MOD_REPLACE;
2847 el = ldb_msg_find_element(old_msg, "name");
2849 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2850 if (ret != LDB_SUCCESS) {
2851 talloc_free(tmp_ctx);
2854 el->flags = LDB_FLAG_MOD_REPLACE;
2858 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
2859 if (ret != LDB_SUCCESS) {
2860 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2861 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2862 talloc_free(tmp_ctx);
2866 if (deletion_state == OBJECT_NOT_DELETED) {
2867 /* now rename onto the new DN */
2868 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
2869 if (ret != LDB_SUCCESS){
2870 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2871 ldb_dn_get_linearized(old_dn),
2872 ldb_dn_get_linearized(new_dn),
2873 ldb_errstring(ldb)));
2874 talloc_free(tmp_ctx);
2879 talloc_free(tmp_ctx);
2881 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2886 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2891 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2893 int ret = LDB_ERR_OTHER;
2894 /* TODO: do some error mapping */
2899 static struct replPropertyMetaData1 *
2900 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
2901 enum drsuapi_DsAttributeId attid)
2904 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
2906 for (i = 0; i < rpmd_ctr->count; i++) {
2907 if (rpmd_ctr->array[i].attid == attid) {
2908 return &rpmd_ctr->array[i];
2916 return true if an update is newer than an existing entry
2917 see section 5.11 of MS-ADTS
2919 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2920 const struct GUID *update_invocation_id,
2921 uint32_t current_version,
2922 uint32_t update_version,
2923 NTTIME current_change_time,
2924 NTTIME update_change_time)
2926 if (update_version != current_version) {
2927 return update_version > current_version;
2929 if (update_change_time != current_change_time) {
2930 return update_change_time > current_change_time;
2932 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2935 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2936 struct replPropertyMetaData1 *new_m)
2938 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2939 &new_m->originating_invocation_id,
2942 cur_m->originating_change_time,
2943 new_m->originating_change_time);
2950 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
2952 const struct ldb_val *rdn_val;
2953 const char *rdn_name;
2954 struct ldb_dn *new_dn;
2956 rdn_val = ldb_dn_get_rdn_val(dn);
2957 rdn_name = ldb_dn_get_rdn_name(dn);
2958 if (!rdn_val || !rdn_name) {
2962 new_dn = ldb_dn_copy(mem_ctx, dn);
2967 if (!ldb_dn_remove_child_components(new_dn, 1)) {
2971 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
2973 ldb_dn_escape_value(new_dn, *rdn_val),
2974 GUID_string(new_dn, guid))) {
2983 perform a modify operation which sets the rDN and name attributes to
2984 their current values. This has the effect of changing these
2985 attributes to have been last updated by the current DC. This is
2986 needed to ensure that renames performed as part of conflict
2987 resolution are propogated to other DCs
2989 static int replmd_name_modify(struct replmd_replicated_request *ar,
2990 struct ldb_request *req, struct ldb_dn *dn)
2992 struct ldb_message *msg;
2993 const char *rdn_name;
2994 const struct ldb_val *rdn_val;
2995 const struct dsdb_attribute *rdn_attr;
2998 msg = ldb_msg_new(req);
3004 rdn_name = ldb_dn_get_rdn_name(dn);
3005 if (rdn_name == NULL) {
3009 /* normalize the rdn attribute name */
3010 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3011 if (rdn_attr == NULL) {
3014 rdn_name = rdn_attr->lDAPDisplayName;
3016 rdn_val = ldb_dn_get_rdn_val(dn);
3017 if (rdn_val == NULL) {
3021 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3024 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3027 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3030 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3034 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3035 if (ret != LDB_SUCCESS) {
3036 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3037 ldb_dn_get_linearized(dn),
3038 ldb_errstring(ldb_module_get_ctx(ar->module))));
3048 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3049 ldb_dn_get_linearized(dn)));
3050 return LDB_ERR_OPERATIONS_ERROR;
3055 callback for conflict DN handling where we have renamed the incoming
3056 record. After renaming it, we need to ensure the change of name and
3057 rDN for the incoming record is seen as an originating update by this DC.
3059 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3061 struct replmd_replicated_request *ar =
3062 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3065 if (ares->error != LDB_SUCCESS) {
3066 /* call the normal callback for everything except success */
3067 return replmd_op_callback(req, ares);
3070 /* perform a modify of the rDN and name of the record */
3071 ret = replmd_name_modify(ar, req, req->op.add.message->dn);
3072 if (ret != LDB_SUCCESS) {
3074 return replmd_op_callback(req, ares);
3077 return replmd_op_callback(req, ares);
3081 callback for replmd_replicated_apply_add()
3082 This copes with the creation of conflict records in the case where
3083 the DN exists, but with a different objectGUID
3085 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3087 struct ldb_dn *conflict_dn;
3088 struct replmd_replicated_request *ar =
3089 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3090 struct ldb_result *res;
3091 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3093 const struct ldb_val *rmd_value, *omd_value;
3094 struct replPropertyMetaDataBlob omd, rmd;
3095 enum ndr_err_code ndr_err;
3096 bool rename_incoming_record;
3097 struct replPropertyMetaData1 *rmd_name, *omd_name;
3099 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3100 /* call the normal callback for everything except
3102 return replmd_op_callback(req, ares);
3106 * we have a conflict, and need to decide if we will keep the
3107 * new record or the old record
3109 conflict_dn = req->op.add.message->dn;
3112 * first we need the replPropertyMetaData attribute from the
3115 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3117 DSDB_FLAG_NEXT_MODULE |
3118 DSDB_SEARCH_SHOW_DELETED |
3119 DSDB_SEARCH_SHOW_RECYCLED, req);
3120 if (ret != LDB_SUCCESS) {
3121 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3122 ldb_dn_get_linearized(conflict_dn)));
3126 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3127 if (omd_value == NULL) {
3128 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3129 ldb_dn_get_linearized(conflict_dn)));
3133 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3134 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3135 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3136 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3137 ldb_dn_get_linearized(conflict_dn)));
3142 * and the replPropertyMetaData attribute from the
3145 rmd_value = ldb_msg_find_ldb_val(req->op.add.message, "replPropertyMetaData");
3146 if (rmd_value == NULL) {
3147 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for new record '%s'\n",
3148 ldb_dn_get_linearized(conflict_dn)));
3152 ndr_err = ndr_pull_struct_blob(rmd_value, req, &rmd,
3153 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3154 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3155 DEBUG(0,(__location__ ": Failed to parse new replPropertyMetaData for %s\n",
3156 ldb_dn_get_linearized(conflict_dn)));
3160 /* we decide which is newer based on the RPMD on the name
3161 attribute. See [MS-DRSR] ResolveNameConflict */
3162 rmd_name = replmd_replPropertyMetaData1_find_attid(&rmd, DRSUAPI_ATTID_name);
3163 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3164 if (!rmd_name || !omd_name) {
3165 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3166 ldb_dn_get_linearized(conflict_dn)));
3170 rename_incoming_record = !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3172 if (rename_incoming_record) {
3174 struct ldb_dn *new_dn;
3175 struct ldb_message *new_msg;
3177 guid = samdb_result_guid(req->op.add.message, "objectGUID");
3178 if (GUID_all_zero(&guid)) {
3179 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3180 ldb_dn_get_linearized(conflict_dn)));
3183 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3184 if (new_dn == NULL) {
3185 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3186 ldb_dn_get_linearized(conflict_dn)));
3190 DEBUG(1,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3191 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3193 /* re-submit the request, but with a different
3194 callback, so we don't loop forever. */
3195 new_msg = ldb_msg_copy_shallow(req, req->op.add.message);
3198 DEBUG(0,(__location__ ": Failed to copy conflict DN message for %s\n",
3199 ldb_dn_get_linearized(conflict_dn)));
3201 new_msg->dn = new_dn;
3202 req->op.add.message = new_msg;
3203 req->callback = replmd_op_name_modify_callback;
3205 return ldb_next_request(ar->module, req);
3207 /* we are renaming the existing record */
3209 struct ldb_dn *new_dn;
3211 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3212 if (GUID_all_zero(&guid)) {
3213 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3214 ldb_dn_get_linearized(conflict_dn)));
3218 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3219 if (new_dn == NULL) {
3220 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3221 ldb_dn_get_linearized(conflict_dn)));
3225 DEBUG(1,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
3226 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3228 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3229 DSDB_FLAG_OWN_MODULE, req);
3230 if (ret != LDB_SUCCESS) {
3231 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3232 ldb_dn_get_linearized(conflict_dn),
3233 ldb_dn_get_linearized(new_dn),
3234 ldb_errstring(ldb_module_get_ctx(ar->module))));
3239 * now we need to ensure that the rename is seen as an
3240 * originating update. We do that with a modify.
3242 ret = replmd_name_modify(ar, req, new_dn);
3243 if (ret != LDB_SUCCESS) {
3247 req->callback = replmd_op_callback;
3249 return ldb_next_request(ar->module, req);
3253 /* on failure do the original callback. This means replication
3254 * will stop with an error, but there is not much else we can
3257 return replmd_op_callback(req, ares);
3261 this is called when a new object comes in over DRS
3263 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3265 struct ldb_context *ldb;
3266 struct ldb_request *change_req;
3267 enum ndr_err_code ndr_err;
3268 struct ldb_message *msg;
3269 struct replPropertyMetaDataBlob *md;
3270 struct ldb_val md_value;
3275 * TODO: check if the parent object exist
3279 * TODO: handle the conflict case where an object with the
3283 ldb = ldb_module_get_ctx(ar->module);
3284 msg = ar->objs->objects[ar->index_current].msg;
3285 md = ar->objs->objects[ar->index_current].meta_data;
3287 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3288 if (ret != LDB_SUCCESS) {
3289 return replmd_replicated_request_error(ar, ret);
3292 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
3293 if (ret != LDB_SUCCESS) {
3294 return replmd_replicated_request_error(ar, ret);
3297 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3298 if (ret != LDB_SUCCESS) {
3299 return replmd_replicated_request_error(ar, ret);
3302 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
3303 if (ret != LDB_SUCCESS) {
3304 return replmd_replicated_request_error(ar, ret);
3307 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3308 if (ret != LDB_SUCCESS) {
3309 return replmd_replicated_request_error(ar, ret);
3312 /* remove any message elements that have zero values */
3313 for (i=0; i<msg->num_elements; i++) {
3314 struct ldb_message_element *el = &msg->elements[i];
3316 if (el->num_values == 0) {
3317 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
3319 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
3320 msg->num_elements--;
3327 * the meta data array is already sorted by the caller
3329 for (i=0; i < md->ctr.ctr1.count; i++) {
3330 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3332 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3333 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3334 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3335 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3336 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3338 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3339 if (ret != LDB_SUCCESS) {
3340 return replmd_replicated_request_error(ar, ret);
3343 replmd_ldb_message_sort(msg, ar->schema);
3346 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3347 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3351 ret = ldb_build_add_req(&change_req,
3357 replmd_op_add_callback,
3359 LDB_REQ_SET_LOCATION(change_req);
3360 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3362 /* current partition control needed by "repmd_op_callback" */
3363 ret = ldb_request_add_control(change_req,
3364 DSDB_CONTROL_CURRENT_PARTITION_OID,
3366 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3368 return ldb_next_request(ar->module, change_req);
3372 handle renames that come in over DRS replication
3374 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
3375 struct ldb_message *msg,
3376 struct replPropertyMetaDataBlob *rmd,
3377 struct replPropertyMetaDataBlob *omd,
3378 struct ldb_request *parent)
3380 struct replPropertyMetaData1 *md_remote;
3381 struct replPropertyMetaData1 *md_local;
3383 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3388 /* now we need to check for double renames. We could have a
3389 * local rename pending which our replication partner hasn't
3390 * received yet. We choose which one wins by looking at the
3391 * attribute stamps on the two objects, the newer one wins
3393 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3394 md_local = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3395 /* if there is no name attribute then we have to assume the
3396 object we've received is in fact newer */
3397 if (!md_remote || !md_local ||
3398 replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3399 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3400 ldb_dn_get_linearized(ar->search_msg->dn),
3401 ldb_dn_get_linearized(msg->dn)));
3402 /* pass rename to the next module
3403 * so it doesn't appear as an originating update */
3404 return dsdb_module_rename(ar->module,
3405 ar->search_msg->dn, msg->dn,
3406 DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX, parent);
3409 /* we're going to keep our old object */
3410 DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
3411 ldb_dn_get_linearized(ar->search_msg->dn),
3412 ldb_dn_get_linearized(msg->dn)));
3417 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
3419 struct ldb_context *ldb;
3420 struct ldb_request *change_req;
3421 enum ndr_err_code ndr_err;
3422 struct ldb_message *msg;
3423 struct replPropertyMetaDataBlob *rmd;
3424 struct replPropertyMetaDataBlob omd;
3425 const struct ldb_val *omd_value;
3426 struct replPropertyMetaDataBlob nmd;
3427 struct ldb_val nmd_value;
3430 unsigned int removed_attrs = 0;
3433 ldb = ldb_module_get_ctx(ar->module);
3434 msg = ar->objs->objects[ar->index_current].msg;
3435 rmd = ar->objs->objects[ar->index_current].meta_data;
3439 /* find existing meta data */
3440 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
3442 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
3443 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3444 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3445 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3446 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3449 if (omd.version != 1) {
3450 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3454 /* handle renames that come in over DRS */
3455 ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
3456 if (ret != LDB_SUCCESS) {
3457 ldb_debug(ldb, LDB_DEBUG_FATAL,
3458 "replmd_replicated_request rename %s => %s failed - %s\n",
3459 ldb_dn_get_linearized(ar->search_msg->dn),
3460 ldb_dn_get_linearized(msg->dn),
3461 ldb_errstring(ldb));
3462 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
3467 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
3468 nmd.ctr.ctr1.array = talloc_array(ar,
3469 struct replPropertyMetaData1,
3470 nmd.ctr.ctr1.count);
3471 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3473 /* first copy the old meta data */
3474 for (i=0; i < omd.ctr.ctr1.count; i++) {
3475 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
3480 /* now merge in the new meta data */
3481 for (i=0; i < rmd->ctr.ctr1.count; i++) {
3484 for (j=0; j < ni; j++) {
3487 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
3491 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
3492 &rmd->ctr.ctr1.array[i]);
3494 /* replace the entry */
3495 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
3496 if (ar->seq_num == 0) {
3497 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3498 if (ret != LDB_SUCCESS) {
3499 return replmd_replicated_request_error(ar, ret);
3502 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
3507 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
3508 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
3509 msg->elements[i-removed_attrs].name,
3510 ldb_dn_get_linearized(msg->dn),
3511 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
3514 /* we don't want to apply this change so remove the attribute */
3515 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
3522 if (found) continue;
3524 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
3525 if (ar->seq_num == 0) {
3526 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3527 if (ret != LDB_SUCCESS) {
3528 return replmd_replicated_request_error(ar, ret);
3531 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
3536 * finally correct the size of the meta_data array
3538 nmd.ctr.ctr1.count = ni;
3541 * the rdn attribute (the alias for the name attribute),
3542 * 'cn' for most objects is the last entry in the meta data array
3545 * sort the new meta data array
3547 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
3548 if (ret != LDB_SUCCESS) {
3553 * check if some replicated attributes left, otherwise skip the ldb_modify() call
3555 if (msg->num_elements == 0) {
3556 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
3559 ar->index_current++;
3560 return replmd_replicated_apply_next(ar);
3563 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
3564 ar->index_current, msg->num_elements);
3566 /* create the meta data value */
3567 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
3568 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3569 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3570 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3571 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3575 * when we know that we'll modify the record, add the whenChanged, uSNChanged
3576 * and replPopertyMetaData attributes
3578 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3579 if (ret != LDB_SUCCESS) {
3580 return replmd_replicated_request_error(ar, ret);
3582 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3583 if (ret != LDB_SUCCESS) {
3584 return replmd_replicated_request_error(ar, ret);
3586 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
3587 if (ret != LDB_SUCCESS) {
3588 return replmd_replicated_request_error(ar, ret);
3591 replmd_ldb_message_sort(msg, ar->schema);
3593 /* we want to replace the old values */
3594 for (i=0; i < msg->num_elements; i++) {
3595 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3599 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3600 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
3604 ret = ldb_build_mod_req(&change_req,
3612 LDB_REQ_SET_LOCATION(change_req);
3613 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3615 /* current partition control needed by "repmd_op_callback" */
3616 ret = ldb_request_add_control(change_req,
3617 DSDB_CONTROL_CURRENT_PARTITION_OID,
3619 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3621 return ldb_next_request(ar->module, change_req);
3624 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
3625 struct ldb_reply *ares)
3627 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3628 struct replmd_replicated_request);
3632 return ldb_module_done(ar->req, NULL, NULL,
3633 LDB_ERR_OPERATIONS_ERROR);
3635 if (ares->error != LDB_SUCCESS &&
3636 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3637 return ldb_module_done(ar->req, ares->controls,
3638 ares->response, ares->error);
3641 switch (ares->type) {
3642 case LDB_REPLY_ENTRY:
3643 ar->search_msg = talloc_steal(ar, ares->message);
3646 case LDB_REPLY_REFERRAL:
3647 /* we ignore referrals */
3650 case LDB_REPLY_DONE:
3651 if (ar->search_msg != NULL) {
3652 ret = replmd_replicated_apply_merge(ar);
3654 ret = replmd_replicated_apply_add(ar);
3656 if (ret != LDB_SUCCESS) {
3657 return ldb_module_done(ar->req, NULL, NULL, ret);
3665 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3667 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3669 struct ldb_context *ldb;
3673 struct ldb_request *search_req;
3674 struct ldb_search_options_control *options;
3676 if (ar->index_current >= ar->objs->num_objects) {
3677 /* done with it, go to next stage */
3678 return replmd_replicated_uptodate_vector(ar);
3681 ldb = ldb_module_get_ctx(ar->module);
3682 ar->search_msg = NULL;
3684 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3685 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3687 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3688 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3689 talloc_free(tmp_str);
3691 ret = ldb_build_search_req(&search_req,
3700 replmd_replicated_apply_search_callback,
3702 LDB_REQ_SET_LOCATION(search_req);
3704 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
3706 if (ret != LDB_SUCCESS) {
3710 /* we need to cope with cross-partition links, so search for
3711 the GUID over all partitions */
3712 options = talloc(search_req, struct ldb_search_options_control);
3713 if (options == NULL) {
3714 DEBUG(0, (__location__ ": out of memory\n"));
3715 return LDB_ERR_OPERATIONS_ERROR;
3717 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3719 ret = ldb_request_add_control(search_req,
3720 LDB_CONTROL_SEARCH_OPTIONS_OID,
3722 if (ret != LDB_SUCCESS) {
3726 return ldb_next_request(ar->module, search_req);
3729 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
3730 struct ldb_reply *ares)
3732 struct ldb_context *ldb;
3733 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3734 struct replmd_replicated_request);
3735 ldb = ldb_module_get_ctx(ar->module);
3738 return ldb_module_done(ar->req, NULL, NULL,
3739 LDB_ERR_OPERATIONS_ERROR);
3741 if (ares->error != LDB_SUCCESS) {
3742 return ldb_module_done(ar->req, ares->controls,
3743 ares->response, ares->error);
3746 if (ares->type != LDB_REPLY_DONE) {
3747 ldb_set_errstring(ldb, "Invalid reply type\n!");
3748 return ldb_module_done(ar->req, NULL, NULL,
3749 LDB_ERR_OPERATIONS_ERROR);
3754 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3757 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3759 struct ldb_context *ldb;
3760 struct ldb_request *change_req;
3761 enum ndr_err_code ndr_err;
3762 struct ldb_message *msg;
3763 struct replUpToDateVectorBlob ouv;
3764 const struct ldb_val *ouv_value;
3765 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3766 struct replUpToDateVectorBlob nuv;
3767 struct ldb_val nuv_value;
3768 struct ldb_message_element *nuv_el = NULL;
3769 const struct GUID *our_invocation_id;
3770 struct ldb_message_element *orf_el = NULL;
3771 struct repsFromToBlob nrf;
3772 struct ldb_val *nrf_value = NULL;
3773 struct ldb_message_element *nrf_el = NULL;
3777 time_t t = time(NULL);
3780 uint32_t instanceType;
3782 ldb = ldb_module_get_ctx(ar->module);
3783 ruv = ar->objs->uptodateness_vector;
3789 unix_to_nt_time(&now, t);
3791 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
3792 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
3793 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
3794 ldb_dn_get_linearized(ar->search_msg->dn)));
3795 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3799 * first create the new replUpToDateVector
3801 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
3803 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
3804 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3805 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3806 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3807 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3810 if (ouv.version != 2) {
3811 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3816 * the new uptodateness vector will at least
3817 * contain 1 entry, one for the source_dsa
3819 * plus optional values from our old vector and the one from the source_dsa
3821 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
3822 if (ruv) nuv.ctr.ctr2.count += ruv->count;
3823 nuv.ctr.ctr2.cursors = talloc_array(ar,
3824 struct drsuapi_DsReplicaCursor2,
3825 nuv.ctr.ctr2.count);
3826 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3828 /* first copy the old vector */
3829 for (i=0; i < ouv.ctr.ctr2.count; i++) {
3830 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
3834 /* get our invocation_id if we have one already attached to the ldb */
3835 our_invocation_id = samdb_ntds_invocation_id(ldb);
3837 /* merge in the source_dsa vector is available */
3838 for (i=0; (ruv && i < ruv->count); i++) {
3841 if (our_invocation_id &&
3842 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3843 our_invocation_id)) {
3847 for (j=0; j < ni; j++) {
3848 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3849 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3856 * we update only the highest_usn and not the latest_sync_success time,
3857 * because the last success stands for direct replication
3859 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3860 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3865 if (found) continue;
3867 /* if it's not there yet, add it */
3868 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3873 * merge in the current highwatermark for the source_dsa
3876 for (j=0; j < ni; j++) {
3877 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
3878 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3885 * here we update the highest_usn and last_sync_success time
3886 * because we're directly replicating from the source_dsa
3888 * and use the tmp_highest_usn because this is what we have just applied
3891 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3892 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
3897 * here we update the highest_usn and last_sync_success time
3898 * because we're directly replicating from the source_dsa
3900 * and use the tmp_highest_usn because this is what we have just applied
3903 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
3904 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3905 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
3910 * finally correct the size of the cursors array
3912 nuv.ctr.ctr2.count = ni;
3917 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
3920 * create the change ldb_message
3922 msg = ldb_msg_new(ar);
3923 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3924 msg->dn = ar->search_msg->dn;
3926 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
3927 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3928 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3929 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3930 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3932 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3933 if (ret != LDB_SUCCESS) {
3934 return replmd_replicated_request_error(ar, ret);
3936 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3939 * now create the new repsFrom value from the given repsFromTo1 structure
3943 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3944 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3947 * first see if we already have a repsFrom value for the current source dsa
3948 * if so we'll later replace this value
3950 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3952 for (i=0; i < orf_el->num_values; i++) {
3953 struct repsFromToBlob *trf;
3955 trf = talloc(ar, struct repsFromToBlob);
3956 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3958 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
3959 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3960 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3961 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3962 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3965 if (trf->version != 1) {
3966 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3970 * we compare the source dsa objectGUID not the invocation_id
3971 * because we want only one repsFrom value per source dsa
3972 * and when the invocation_id of the source dsa has changed we don't need
3973 * the old repsFrom with the old invocation_id
3975 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3976 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3982 nrf_value = &orf_el->values[i];
3987 * copy over all old values to the new ldb_message
3989 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3990 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3995 * if we haven't found an old repsFrom value for the current source dsa
3996 * we'll add a new value
3999 struct ldb_val zero_value;
4000 ZERO_STRUCT(zero_value);
4001 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
4002 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4004 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
4007 /* we now fill the value which is already attached to ldb_message */
4008 ndr_err = ndr_push_struct_blob(nrf_value, msg,
4010 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
4011 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4012 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4013 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4017 * the ldb_message_element for the attribute, has all the old values and the new one
4018 * so we'll replace the whole attribute with all values
4020 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
4023 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4024 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
4028 /* prepare the ldb_modify() request */
4029 ret = ldb_build_mod_req(&change_req,
4035 replmd_replicated_uptodate_modify_callback,
4037 LDB_REQ_SET_LOCATION(change_req);
4038 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4040 return ldb_next_request(ar->module, change_req);
4043 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
4044 struct ldb_reply *ares)
4046 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4047 struct replmd_replicated_request);
4051 return ldb_module_done(ar->req, NULL, NULL,
4052 LDB_ERR_OPERATIONS_ERROR);
4054 if (ares->error != LDB_SUCCESS &&
4055 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4056 return ldb_module_done(ar->req, ares->controls,
4057 ares->response, ares->error);
4060 switch (ares->type) {
4061 case LDB_REPLY_ENTRY:
4062 ar->search_msg = talloc_steal(ar, ares->message);
4065 case LDB_REPLY_REFERRAL:
4066 /* we ignore referrals */
4069 case LDB_REPLY_DONE:
4070 if (ar->search_msg == NULL) {
4071 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4073 ret = replmd_replicated_uptodate_modify(ar);
4075 if (ret != LDB_SUCCESS) {
4076 return ldb_module_done(ar->req, NULL, NULL, ret);
4085 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
4087 struct ldb_context *ldb;
4089 static const char *attrs[] = {
4090 "replUpToDateVector",
4095 struct ldb_request *search_req;
4097 ldb = ldb_module_get_ctx(ar->module);
4098 ar->search_msg = NULL;
4100 ret = ldb_build_search_req(&search_req,
4103 ar->objs->partition_dn,
4109 replmd_replicated_uptodate_search_callback,
4111 LDB_REQ_SET_LOCATION(search_req);
4112 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4114 return ldb_next_request(ar->module, search_req);
4119 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
4121 struct ldb_context *ldb;
4122 struct dsdb_extended_replicated_objects *objs;
4123 struct replmd_replicated_request *ar;
4124 struct ldb_control **ctrls;
4127 struct replmd_private *replmd_private =
4128 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4130 ldb = ldb_module_get_ctx(module);
4132 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
4134 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
4136 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
4137 return LDB_ERR_PROTOCOL_ERROR;
4140 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
4141 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
4142 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
4143 return LDB_ERR_PROTOCOL_ERROR;
4146 ar = replmd_ctx_init(module, req);
4148 return LDB_ERR_OPERATIONS_ERROR;
4150 /* Set the flags to have the replmd_op_callback run over the full set of objects */
4151 ar->apply_mode = true;
4153 ar->schema = dsdb_get_schema(ldb, ar);
4155 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
4157 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4158 return LDB_ERR_CONSTRAINT_VIOLATION;
4161 ctrls = req->controls;
4163 if (req->controls) {
4164 req->controls = talloc_memdup(ar, req->controls,
4165 talloc_get_size(req->controls));
4166 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4169 /* This allows layers further down to know if a change came in over replication */
4170 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
4171 if (ret != LDB_SUCCESS) {
4175 /* If this change contained linked attributes in the body
4176 * (rather than in the links section) we need to update
4177 * backlinks in linked_attributes */
4178 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
4179 if (ret != LDB_SUCCESS) {
4183 ar->controls = req->controls;
4184 req->controls = ctrls;
4186 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
4188 /* save away the linked attributes for the end of the
4190 for (i=0; i<ar->objs->linked_attributes_count; i++) {
4191 struct la_entry *la_entry;
4193 if (replmd_private->la_ctx == NULL) {
4194 replmd_private->la_ctx = talloc_new(replmd_private);
4196 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
4197 if (la_entry == NULL) {
4199 return LDB_ERR_OPERATIONS_ERROR;
4201 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
4202 if (la_entry->la == NULL) {
4203 talloc_free(la_entry);
4205 return LDB_ERR_OPERATIONS_ERROR;
4207 *la_entry->la = ar->objs->linked_attributes[i];
4209 /* we need to steal the non-scalars so they stay
4210 around until the end of the transaction */
4211 talloc_steal(la_entry->la, la_entry->la->identifier);
4212 talloc_steal(la_entry->la, la_entry->la->value.blob);
4214 DLIST_ADD(replmd_private->la_list, la_entry);
4217 return replmd_replicated_apply_next(ar);
4221 process one linked attribute structure
4223 static int replmd_process_linked_attribute(struct ldb_module *module,
4224 struct la_entry *la_entry,
4225 struct ldb_request *parent)
4227 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
4228 struct ldb_context *ldb = ldb_module_get_ctx(module);
4229 struct ldb_message *msg;
4230 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
4231 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
4233 const struct dsdb_attribute *attr;
4234 struct dsdb_dn *dsdb_dn;
4235 uint64_t seq_num = 0;
4236 struct ldb_message_element *old_el;
4238 time_t t = time(NULL);
4239 struct ldb_result *res;
4240 const char *attrs[2];
4241 struct parsed_dn *pdn_list, *pdn;
4242 struct GUID guid = GUID_zero();
4244 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
4245 const struct GUID *our_invocation_id;
4248 linked_attributes[0]:
4249 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
4251 identifier: struct drsuapi_DsReplicaObjectIdentifier
4252 __ndr_size : 0x0000003a (58)
4253 __ndr_size_sid : 0x00000000 (0)
4254 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
4256 __ndr_size_dn : 0x00000000 (0)
4258 attid : DRSUAPI_ATTID_member (0x1F)
4259 value: struct drsuapi_DsAttributeValue
4260 __ndr_size : 0x0000007e (126)
4262 blob : DATA_BLOB length=126
4263 flags : 0x00000001 (1)
4264 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
4265 originating_add_time : Wed Sep 2 22:20:01 2009 EST
4266 meta_data: struct drsuapi_DsReplicaMetaData
4267 version : 0x00000015 (21)
4268 originating_change_time : Wed Sep 2 23:39:07 2009 EST
4269 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
4270 originating_usn : 0x000000000001e19c (123292)
4272 (for cases where the link is to a normal DN)
4273 &target: struct drsuapi_DsReplicaObjectIdentifier3
4274 __ndr_size : 0x0000007e (126)
4275 __ndr_size_sid : 0x0000001c (28)
4276 guid : 7639e594-db75-4086-b0d4-67890ae46031
4277 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
4278 __ndr_size_dn : 0x00000022 (34)
4279 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
4282 /* find the attribute being modified */
4283 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
4285 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
4286 talloc_free(tmp_ctx);
4287 return LDB_ERR_OPERATIONS_ERROR;
4290 attrs[0] = attr->lDAPDisplayName;
4293 /* get the existing message from the db for the object with
4294 this GUID, returning attribute being modified. We will then
4295 use this msg as the basis for a modify call */
4296 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
4297 DSDB_FLAG_NEXT_MODULE |
4298 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
4299 DSDB_SEARCH_SHOW_RECYCLED |
4300 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4301 DSDB_SEARCH_REVEAL_INTERNALS,
4303 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
4304 if (ret != LDB_SUCCESS) {
4305 talloc_free(tmp_ctx);
4308 if (res->count != 1) {
4309 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
4310 GUID_string(tmp_ctx, &la->identifier->guid));
4311 talloc_free(tmp_ctx);
4312 return LDB_ERR_NO_SUCH_OBJECT;
4316 if (msg->num_elements == 0) {
4317 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
4318 if (ret != LDB_SUCCESS) {
4319 ldb_module_oom(module);
4320 talloc_free(tmp_ctx);
4321 return LDB_ERR_OPERATIONS_ERROR;
4324 old_el = &msg->elements[0];
4325 old_el->flags = LDB_FLAG_MOD_REPLACE;
4328 /* parse the existing links */
4329 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
4330 if (ret != LDB_SUCCESS) {
4331 talloc_free(tmp_ctx);
4335 /* get our invocationId */
4336 our_invocation_id = samdb_ntds_invocation_id(ldb);
4337 if (!our_invocation_id) {
4338 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
4339 talloc_free(tmp_ctx);
4340 return LDB_ERR_OPERATIONS_ERROR;
4343 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
4344 if (ret != LDB_SUCCESS) {
4345 talloc_free(tmp_ctx);
4349 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
4350 if (!W_ERROR_IS_OK(status)) {
4351 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
4352 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
4353 return LDB_ERR_OPERATIONS_ERROR;
4356 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
4357 if (!NT_STATUS_IS_OK(ntstatus) && active) {
4358 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
4360 ldb_dn_get_linearized(dsdb_dn->dn),
4361 ldb_dn_get_linearized(msg->dn));
4362 return LDB_ERR_OPERATIONS_ERROR;
4365 /* re-resolve the DN by GUID, as the DRS server may give us an
4367 ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
4368 if (ret != LDB_SUCCESS) {
4369 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s",
4370 GUID_string(tmp_ctx, &guid),
4371 ldb_dn_get_linearized(dsdb_dn->dn)));
4374 /* see if this link already exists */
4375 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
4377 /* see if this update is newer than what we have already */
4378 struct GUID invocation_id = GUID_zero();
4379 uint32_t version = 0;
4380 uint32_t originating_usn = 0;
4381 NTTIME change_time = 0;
4382 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
4384 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
4385 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
4386 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
4387 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
4389 if (!replmd_update_is_newer(&invocation_id,
4390 &la->meta_data.originating_invocation_id,
4392 la->meta_data.version,
4394 la->meta_data.originating_change_time)) {
4395 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
4396 old_el->name, ldb_dn_get_linearized(msg->dn),
4397 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
4398 talloc_free(tmp_ctx);
4402 /* get a seq_num for this change */
4403 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4404 if (ret != LDB_SUCCESS) {
4405 talloc_free(tmp_ctx);
4409 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
4410 /* remove the existing backlink */
4411 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
4412 if (ret != LDB_SUCCESS) {
4413 talloc_free(tmp_ctx);
4418 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
4419 &la->meta_data.originating_invocation_id,
4420 la->meta_data.originating_usn, seq_num,
4421 la->meta_data.originating_change_time,
4422 la->meta_data.version,
4424 if (ret != LDB_SUCCESS) {
4425 talloc_free(tmp_ctx);
4430 /* add the new backlink */
4431 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
4432 if (ret != LDB_SUCCESS) {
4433 talloc_free(tmp_ctx);
4438 /* get a seq_num for this change */
4439 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4440 if (ret != LDB_SUCCESS) {
4441 talloc_free(tmp_ctx);
4445 old_el->values = talloc_realloc(msg->elements, old_el->values,
4446 struct ldb_val, old_el->num_values+1);
4447 if (!old_el->values) {
4448 ldb_module_oom(module);
4449 return LDB_ERR_OPERATIONS_ERROR;
4451 old_el->num_values++;
4453 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
4454 &la->meta_data.originating_invocation_id,
4455 la->meta_data.originating_usn, seq_num,
4456 la->meta_data.originating_change_time,
4457 la->meta_data.version,
4458 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
4459 if (ret != LDB_SUCCESS) {
4460 talloc_free(tmp_ctx);
4465 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
4467 if (ret != LDB_SUCCESS) {
4468 talloc_free(tmp_ctx);
4474 /* we only change whenChanged and uSNChanged if the seq_num
4476 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
4477 talloc_free(tmp_ctx);
4478 return ldb_operr(ldb);
4481 if (add_uint64_element(ldb, msg, "uSNChanged",
4482 seq_num) != LDB_SUCCESS) {
4483 talloc_free(tmp_ctx);
4484 return ldb_operr(ldb);
4487 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
4488 if (old_el == NULL) {
4489 talloc_free(tmp_ctx);
4490 return ldb_operr(ldb);
4493 ret = dsdb_check_single_valued_link(attr, old_el);
4494 if (ret != LDB_SUCCESS) {
4495 talloc_free(tmp_ctx);
4499 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
4501 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
4502 if (ret != LDB_SUCCESS) {
4503 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
4505 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
4506 talloc_free(tmp_ctx);
4510 talloc_free(tmp_ctx);
4515 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
4517 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
4518 return replmd_extended_replicated_objects(module, req);
4521 return ldb_next_request(module, req);
4526 we hook into the transaction operations to allow us to
4527 perform the linked attribute updates at the end of the whole
4528 transaction. This allows a forward linked attribute to be created
4529 before the object is created. During a vampire, w2k8 sends us linked
4530 attributes before the objects they are part of.
4532 static int replmd_start_transaction(struct ldb_module *module)
4534 /* create our private structure for this transaction */
4535 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
4536 struct replmd_private);
4537 replmd_txn_cleanup(replmd_private);
4539 /* free any leftover mod_usn records from cancelled
4541 while (replmd_private->ncs) {
4542 struct nc_entry *e = replmd_private->ncs;
4543 DLIST_REMOVE(replmd_private->ncs, e);
4547 return ldb_next_start_trans(module);
4551 on prepare commit we loop over our queued la_context structures and
4554 static int replmd_prepare_commit(struct ldb_module *module)
4556 struct replmd_private *replmd_private =
4557 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4558 struct la_entry *la, *prev;
4559 struct la_backlink *bl;
4562 /* walk the list backwards, to do the first entry first, as we
4563 * added the entries with DLIST_ADD() which puts them at the
4564 * start of the list */
4565 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
4566 prev = DLIST_PREV(la);
4567 DLIST_REMOVE(replmd_private->la_list, la);
4568 ret = replmd_process_linked_attribute(module, la, NULL);
4569 if (ret != LDB_SUCCESS) {
4570 replmd_txn_cleanup(replmd_private);
4575 /* process our backlink list, creating and deleting backlinks
4577 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
4578 ret = replmd_process_backlink(module, bl, NULL);
4579 if (ret != LDB_SUCCESS) {
4580 replmd_txn_cleanup(replmd_private);
4585 replmd_txn_cleanup(replmd_private);
4587 /* possibly change @REPLCHANGED */
4588 ret = replmd_notify_store(module, NULL);
4589 if (ret != LDB_SUCCESS) {
4593 return ldb_next_prepare_commit(module);
4596 static int replmd_del_transaction(struct ldb_module *module)
4598 struct replmd_private *replmd_private =
4599 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4600 replmd_txn_cleanup(replmd_private);
4602 return ldb_next_del_trans(module);
4606 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
4607 .name = "repl_meta_data",
4608 .init_context = replmd_init,
4610 .modify = replmd_modify,
4611 .rename = replmd_rename,
4612 .del = replmd_delete,
4613 .extended = replmd_extended,
4614 .start_transaction = replmd_start_transaction,
4615 .prepare_commit = replmd_prepare_commit,
4616 .del_transaction = replmd_del_transaction,
4619 int ldb_repl_meta_data_module_init(const char *version)
4621 LDB_MODULE_CHECK_VERSION(version);
4622 return ldb_register_module(&ldb_repl_meta_data_module_ops);