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_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
258 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
259 cope with possible corruption where the backlink has
260 already been removed */
261 DEBUG(0,("WARNING: backlink from %s already removed from %s - %s\n",
262 ldb_dn_get_linearized(target_dn),
263 ldb_dn_get_linearized(source_dn),
264 ldb_errstring(ldb)));
266 } else if (ret != LDB_SUCCESS) {
267 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
268 bl->active?"add":"remove",
269 ldb_dn_get_linearized(source_dn),
270 ldb_dn_get_linearized(target_dn),
272 talloc_free(tmp_ctx);
275 talloc_free(tmp_ctx);
280 add a backlink to the list of backlinks to add/delete in the prepare
283 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
284 struct GUID *forward_guid, struct GUID *target_guid,
285 bool active, const struct dsdb_attribute *schema_attr, bool immediate)
287 const struct dsdb_attribute *target_attr;
288 struct la_backlink *bl;
289 struct replmd_private *replmd_private =
290 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
292 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
295 * windows 2003 has a broken schema where the
296 * definition of msDS-IsDomainFor is missing (which is
297 * supposed to be the backlink of the
298 * msDS-HasDomainNCs attribute
303 /* see if its already in the list */
304 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
305 if (GUID_equal(forward_guid, &bl->forward_guid) &&
306 GUID_equal(target_guid, &bl->target_guid) &&
307 (target_attr->lDAPDisplayName == bl->attr_name ||
308 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
314 /* we found an existing one */
315 if (bl->active == active) {
318 DLIST_REMOVE(replmd_private->la_backlinks, bl);
323 if (replmd_private->bl_ctx == NULL) {
324 replmd_private->bl_ctx = talloc_new(replmd_private);
325 if (replmd_private->bl_ctx == NULL) {
326 ldb_module_oom(module);
327 return LDB_ERR_OPERATIONS_ERROR;
332 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
334 ldb_module_oom(module);
335 return LDB_ERR_OPERATIONS_ERROR;
338 /* Ensure the schema does not go away before the bl->attr_name is used */
339 if (!talloc_reference(bl, schema)) {
341 ldb_module_oom(module);
342 return LDB_ERR_OPERATIONS_ERROR;
345 bl->attr_name = target_attr->lDAPDisplayName;
346 bl->forward_guid = *forward_guid;
347 bl->target_guid = *target_guid;
350 /* the caller may ask for this backlink to be processed
353 int ret = replmd_process_backlink(module, bl, NULL);
358 DLIST_ADD(replmd_private->la_backlinks, bl);
365 * Callback for most write operations in this module:
367 * notify the repl task that a object has changed. The notifies are
368 * gathered up in the replmd_private structure then written to the
369 * @REPLCHANGED object in each partition during the prepare_commit
371 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
374 struct replmd_replicated_request *ac =
375 talloc_get_type_abort(req->context, struct replmd_replicated_request);
376 struct replmd_private *replmd_private =
377 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
378 struct nc_entry *modified_partition;
379 struct ldb_control *partition_ctrl;
380 const struct dsdb_control_current_partition *partition;
382 struct ldb_control **controls;
384 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
386 controls = ares->controls;
387 if (ldb_request_get_control(ac->req,
388 DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
390 * Remove the current partition control from what we pass up
391 * the chain if it hasn't been requested manually.
393 controls = ldb_controls_except_specified(ares->controls, ares,
397 if (ares->error != LDB_SUCCESS) {
398 DEBUG(0,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
399 return ldb_module_done(ac->req, controls,
400 ares->response, ares->error);
403 if (ares->type != LDB_REPLY_DONE) {
404 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
405 return ldb_module_done(ac->req, NULL,
406 NULL, LDB_ERR_OPERATIONS_ERROR);
409 if (!partition_ctrl) {
410 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
411 return ldb_module_done(ac->req, NULL,
412 NULL, LDB_ERR_OPERATIONS_ERROR);
415 partition = talloc_get_type_abort(partition_ctrl->data,
416 struct dsdb_control_current_partition);
418 if (ac->seq_num > 0) {
419 for (modified_partition = replmd_private->ncs; modified_partition;
420 modified_partition = modified_partition->next) {
421 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
426 if (modified_partition == NULL) {
427 modified_partition = talloc_zero(replmd_private, struct nc_entry);
428 if (!modified_partition) {
429 ldb_oom(ldb_module_get_ctx(ac->module));
430 return ldb_module_done(ac->req, NULL,
431 NULL, LDB_ERR_OPERATIONS_ERROR);
433 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
434 if (!modified_partition->dn) {
435 ldb_oom(ldb_module_get_ctx(ac->module));
436 return ldb_module_done(ac->req, NULL,
437 NULL, LDB_ERR_OPERATIONS_ERROR);
439 DLIST_ADD(replmd_private->ncs, modified_partition);
442 if (ac->seq_num > modified_partition->mod_usn) {
443 modified_partition->mod_usn = ac->seq_num;
445 modified_partition->mod_usn_urgent = ac->seq_num;
450 if (ac->apply_mode) {
454 ret = replmd_replicated_apply_next(ac);
455 if (ret != LDB_SUCCESS) {
456 return ldb_module_done(ac->req, NULL, NULL, ret);
460 /* free the partition control container here, for the
461 * common path. Other cases will have it cleaned up
462 * eventually with the ares */
463 talloc_free(partition_ctrl);
464 return ldb_module_done(ac->req, controls,
465 ares->response, LDB_SUCCESS);
471 * update a @REPLCHANGED record in each partition if there have been
472 * any writes of replicated data in the partition
474 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
476 struct replmd_private *replmd_private =
477 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
479 while (replmd_private->ncs) {
481 struct nc_entry *modified_partition = replmd_private->ncs;
483 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
484 modified_partition->mod_usn,
485 modified_partition->mod_usn_urgent, parent);
486 if (ret != LDB_SUCCESS) {
487 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
488 ldb_dn_get_linearized(modified_partition->dn)));
491 DLIST_REMOVE(replmd_private->ncs, modified_partition);
492 talloc_free(modified_partition);
500 created a replmd_replicated_request context
502 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
503 struct ldb_request *req)
505 struct ldb_context *ldb;
506 struct replmd_replicated_request *ac;
508 ldb = ldb_module_get_ctx(module);
510 ac = talloc_zero(req, struct replmd_replicated_request);
519 ac->schema = dsdb_get_schema(ldb, ac);
521 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
522 "replmd_modify: no dsdb_schema loaded");
523 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
531 add a time element to a record
533 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
535 struct ldb_message_element *el;
539 if (ldb_msg_find_element(msg, attr) != NULL) {
543 s = ldb_timestring(msg, t);
545 return LDB_ERR_OPERATIONS_ERROR;
548 ret = ldb_msg_add_string(msg, attr, s);
549 if (ret != LDB_SUCCESS) {
553 el = ldb_msg_find_element(msg, attr);
554 /* always set as replace. This works because on add ops, the flag
556 el->flags = LDB_FLAG_MOD_REPLACE;
562 add a uint64_t element to a record
564 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
565 const char *attr, uint64_t v)
567 struct ldb_message_element *el;
570 if (ldb_msg_find_element(msg, attr) != NULL) {
574 ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
575 if (ret != LDB_SUCCESS) {
579 el = ldb_msg_find_element(msg, attr);
580 /* always set as replace. This works because on add ops, the flag
582 el->flags = LDB_FLAG_MOD_REPLACE;
587 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
588 const struct replPropertyMetaData1 *m2,
589 const uint32_t *rdn_attid)
591 if (m1->attid == m2->attid) {
596 * the rdn attribute should be at the end!
597 * so we need to return a value greater than zero
598 * which means m1 is greater than m2
600 if (m1->attid == *rdn_attid) {
605 * the rdn attribute should be at the end!
606 * so we need to return a value less than zero
607 * which means m2 is greater than m1
609 if (m2->attid == *rdn_attid) {
613 return m1->attid > m2->attid ? 1 : -1;
616 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
617 const struct dsdb_schema *schema,
620 const char *rdn_name;
621 const struct dsdb_attribute *rdn_sa;
623 rdn_name = ldb_dn_get_rdn_name(dn);
625 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
626 return LDB_ERR_OPERATIONS_ERROR;
629 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
630 if (rdn_sa == NULL) {
631 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
632 return LDB_ERR_OPERATIONS_ERROR;
635 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
636 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
638 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
643 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
644 const struct ldb_message_element *e2,
645 const struct dsdb_schema *schema)
647 const struct dsdb_attribute *a1;
648 const struct dsdb_attribute *a2;
651 * TODO: make this faster by caching the dsdb_attribute pointer
652 * on the ldb_messag_element
655 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
656 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
659 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
663 return strcasecmp(e1->name, e2->name);
665 if (a1->attributeID_id == a2->attributeID_id) {
668 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
671 static void replmd_ldb_message_sort(struct ldb_message *msg,
672 const struct dsdb_schema *schema)
674 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
677 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
678 const struct GUID *invocation_id, uint64_t seq_num,
679 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
683 fix up linked attributes in replmd_add.
684 This involves setting up the right meta-data in extended DN
685 components, and creating backlinks to the object
687 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
688 uint64_t seq_num, const struct GUID *invocationId, time_t t,
689 struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
692 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
693 struct ldb_context *ldb = ldb_module_get_ctx(module);
695 /* We will take a reference to the schema in replmd_add_backlink */
696 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
699 unix_to_nt_time(&now, t);
701 for (i=0; i<el->num_values; i++) {
702 struct ldb_val *v = &el->values[i];
703 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
704 struct GUID target_guid;
708 /* note that the DN already has the extended
709 components from the extended_dn_store module */
710 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
711 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
712 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
713 if (ret != LDB_SUCCESS) {
714 talloc_free(tmp_ctx);
717 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
718 if (ret != LDB_SUCCESS) {
719 talloc_free(tmp_ctx);
724 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
725 seq_num, seq_num, now, 0, false);
726 if (ret != LDB_SUCCESS) {
727 talloc_free(tmp_ctx);
731 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
732 if (ret != LDB_SUCCESS) {
733 talloc_free(tmp_ctx);
738 talloc_free(tmp_ctx);
744 intercept add requests
746 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
748 struct ldb_context *ldb;
749 struct ldb_control *control;
750 struct replmd_replicated_request *ac;
751 enum ndr_err_code ndr_err;
752 struct ldb_request *down_req;
753 struct ldb_message *msg;
754 const DATA_BLOB *guid_blob;
756 struct replPropertyMetaDataBlob nmd;
757 struct ldb_val nmd_value;
758 const struct GUID *our_invocation_id;
759 time_t t = time(NULL);
764 unsigned int functional_level;
766 bool allow_add_guid = false;
767 bool remove_current_guid = false;
768 bool is_urgent = false;
769 struct ldb_message_element *objectclass_el;
771 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
772 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
774 allow_add_guid = true;
777 /* do not manipulate our control entries */
778 if (ldb_dn_is_special(req->op.add.message->dn)) {
779 return ldb_next_request(module, req);
782 ldb = ldb_module_get_ctx(module);
784 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
786 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
787 if (guid_blob != NULL) {
788 if (!allow_add_guid) {
789 ldb_set_errstring(ldb,
790 "replmd_add: it's not allowed to add an object with objectGUID!");
791 return LDB_ERR_UNWILLING_TO_PERFORM;
793 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
794 if (!NT_STATUS_IS_OK(status)) {
795 ldb_set_errstring(ldb,
796 "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
797 return LDB_ERR_UNWILLING_TO_PERFORM;
799 /* we remove this attribute as it can be a string and
800 * will not be treated correctly and then we will re-add
801 * it later on in the good format */
802 remove_current_guid = true;
806 guid = GUID_random();
809 ac = replmd_ctx_init(module, req);
811 return ldb_module_oom(module);
814 functional_level = dsdb_functional_level(ldb);
816 /* Get a sequence number from the backend */
817 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
818 if (ret != LDB_SUCCESS) {
823 /* get our invocationId */
824 our_invocation_id = samdb_ntds_invocation_id(ldb);
825 if (!our_invocation_id) {
826 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
827 "replmd_add: unable to find invocationId\n");
829 return LDB_ERR_OPERATIONS_ERROR;
832 /* we have to copy the message as the caller might have it as a const */
833 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
837 return LDB_ERR_OPERATIONS_ERROR;
840 /* generated times */
841 unix_to_nt_time(&now, t);
842 time_str = ldb_timestring(msg, t);
846 return LDB_ERR_OPERATIONS_ERROR;
848 if (remove_current_guid) {
849 ldb_msg_remove_attr(msg,"objectGUID");
853 * remove autogenerated attributes
855 ldb_msg_remove_attr(msg, "whenCreated");
856 ldb_msg_remove_attr(msg, "whenChanged");
857 ldb_msg_remove_attr(msg, "uSNCreated");
858 ldb_msg_remove_attr(msg, "uSNChanged");
859 ldb_msg_remove_attr(msg, "replPropertyMetaData");
862 * readd replicated attributes
864 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
865 if (ret != LDB_SUCCESS) {
871 /* build the replication meta_data */
874 nmd.ctr.ctr1.count = msg->num_elements;
875 nmd.ctr.ctr1.array = talloc_array(msg,
876 struct replPropertyMetaData1,
878 if (!nmd.ctr.ctr1.array) {
881 return LDB_ERR_OPERATIONS_ERROR;
884 for (i=0; i < msg->num_elements; i++) {
885 struct ldb_message_element *e = &msg->elements[i];
886 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
887 const struct dsdb_attribute *sa;
889 if (e->name[0] == '@') continue;
891 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
893 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
894 "replmd_add: attribute '%s' not defined in schema\n",
897 return LDB_ERR_NO_SUCH_ATTRIBUTE;
900 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
901 /* if the attribute is not replicated (0x00000001)
902 * or constructed (0x00000004) it has no metadata
907 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
908 ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa, req);
909 if (ret != LDB_SUCCESS) {
913 /* linked attributes are not stored in
914 replPropertyMetaData in FL above w2k */
918 m->attid = sa->attributeID_id;
920 m->originating_change_time = now;
921 m->originating_invocation_id = *our_invocation_id;
922 m->originating_usn = ac->seq_num;
923 m->local_usn = ac->seq_num;
927 /* fix meta data count */
928 nmd.ctr.ctr1.count = ni;
931 * sort meta data array, and move the rdn attribute entry to the end
933 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
934 if (ret != LDB_SUCCESS) {
939 /* generated NDR encoded values */
940 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
942 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
943 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
946 return LDB_ERR_OPERATIONS_ERROR;
950 * add the autogenerated values
952 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
953 if (ret != LDB_SUCCESS) {
958 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
959 if (ret != LDB_SUCCESS) {
964 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
965 if (ret != LDB_SUCCESS) {
970 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
971 if (ret != LDB_SUCCESS) {
976 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
977 if (ret != LDB_SUCCESS) {
984 * sort the attributes by attid before storing the object
986 replmd_ldb_message_sort(msg, ac->schema);
988 objectclass_el = ldb_msg_find_element(msg, "objectClass");
989 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
990 REPL_URGENT_ON_CREATE);
992 ac->is_urgent = is_urgent;
993 ret = ldb_build_add_req(&down_req, ldb, ac,
996 ac, replmd_op_callback,
999 LDB_REQ_SET_LOCATION(down_req);
1000 if (ret != LDB_SUCCESS) {
1005 /* current partition control is needed by "replmd_op_callback" */
1006 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1007 ret = ldb_request_add_control(down_req,
1008 DSDB_CONTROL_CURRENT_PARTITION_OID,
1010 if (ret != LDB_SUCCESS) {
1016 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1017 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1018 if (ret != LDB_SUCCESS) {
1024 /* mark the control done */
1026 control->critical = 0;
1029 /* go on with the call chain */
1030 return ldb_next_request(module, down_req);
1035 * update the replPropertyMetaData for one element
1037 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1038 struct ldb_message *msg,
1039 struct ldb_message_element *el,
1040 struct ldb_message_element *old_el,
1041 struct replPropertyMetaDataBlob *omd,
1042 const struct dsdb_schema *schema,
1044 const struct GUID *our_invocation_id,
1048 const struct dsdb_attribute *a;
1049 struct replPropertyMetaData1 *md1;
1051 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1053 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1055 return LDB_ERR_OPERATIONS_ERROR;
1058 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1062 /* if the attribute's value haven't changed then return LDB_SUCCESS */
1063 if (old_el != NULL && ldb_msg_element_compare(el, old_el) == 0) {
1067 for (i=0; i<omd->ctr.ctr1.count; i++) {
1068 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1071 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1072 /* linked attributes are not stored in
1073 replPropertyMetaData in FL above w2k, but we do
1074 raise the seqnum for the object */
1075 if (*seq_num == 0 &&
1076 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1077 return LDB_ERR_OPERATIONS_ERROR;
1082 if (i == omd->ctr.ctr1.count) {
1083 /* we need to add a new one */
1084 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1085 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1086 if (omd->ctr.ctr1.array == NULL) {
1088 return LDB_ERR_OPERATIONS_ERROR;
1090 omd->ctr.ctr1.count++;
1091 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1094 /* Get a new sequence number from the backend. We only do this
1095 * if we have a change that requires a new
1096 * replPropertyMetaData element
1098 if (*seq_num == 0) {
1099 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1100 if (ret != LDB_SUCCESS) {
1101 return LDB_ERR_OPERATIONS_ERROR;
1105 md1 = &omd->ctr.ctr1.array[i];
1107 md1->attid = a->attributeID_id;
1108 md1->originating_change_time = now;
1109 md1->originating_invocation_id = *our_invocation_id;
1110 md1->originating_usn = *seq_num;
1111 md1->local_usn = *seq_num;
1116 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1118 uint32_t count = omd.ctr.ctr1.count;
1121 for (i=0; i < count; i++) {
1122 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1123 if (max < m.local_usn) {
1131 * update the replPropertyMetaData object each time we modify an
1132 * object. This is needed for DRS replication, as the merge on the
1133 * client is based on this object
1135 static int replmd_update_rpmd(struct ldb_module *module,
1136 const struct dsdb_schema *schema,
1137 struct ldb_request *req,
1138 const char * const *rename_attrs,
1139 struct ldb_message *msg, uint64_t *seq_num,
1143 const struct ldb_val *omd_value;
1144 enum ndr_err_code ndr_err;
1145 struct replPropertyMetaDataBlob omd;
1148 const struct GUID *our_invocation_id;
1150 const char * const *attrs = NULL;
1151 const char * const attrs1[] = { "replPropertyMetaData", "*", NULL };
1152 const char * const attrs2[] = { "uSNChanged", "objectClass", NULL };
1153 struct ldb_result *res;
1154 struct ldb_context *ldb;
1155 struct ldb_message_element *objectclass_el;
1156 enum urgent_situation situation;
1157 bool rodc, rmd_is_provided;
1160 attrs = rename_attrs;
1165 ldb = ldb_module_get_ctx(module);
1167 our_invocation_id = samdb_ntds_invocation_id(ldb);
1168 if (!our_invocation_id) {
1169 /* this happens during an initial vampire while
1170 updating the schema */
1171 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1175 unix_to_nt_time(&now, t);
1177 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1178 rmd_is_provided = true;
1180 rmd_is_provided = false;
1183 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1184 * otherwise we consider we are updating */
1185 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1186 situation = REPL_URGENT_ON_DELETE;
1187 } else if (rename_attrs) {
1188 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1190 situation = REPL_URGENT_ON_UPDATE;
1193 if (rmd_is_provided) {
1194 /* In this case the change_replmetadata control was supplied */
1195 /* We check that it's the only attribute that is provided
1196 * (it's a rare case so it's better to keep the code simplier)
1197 * We also check that the highest local_usn is bigger than
1200 if( msg->num_elements != 1 ||
1201 strncmp(msg->elements[0].name,
1202 "replPropertyMetaData", 20) ) {
1203 DEBUG(0,(__location__ ": changereplmetada control called without "\
1204 "a specified replPropertyMetaData attribute or with others\n"));
1205 return LDB_ERR_OPERATIONS_ERROR;
1207 if (situation != REPL_URGENT_ON_UPDATE) {
1208 DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1209 return LDB_ERR_OPERATIONS_ERROR;
1211 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1213 DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1214 ldb_dn_get_linearized(msg->dn)));
1215 return LDB_ERR_OPERATIONS_ERROR;
1217 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1218 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1219 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1220 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1221 ldb_dn_get_linearized(msg->dn)));
1222 return LDB_ERR_OPERATIONS_ERROR;
1224 *seq_num = find_max_local_usn(omd);
1226 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1227 DSDB_FLAG_NEXT_MODULE |
1228 DSDB_SEARCH_SHOW_RECYCLED |
1229 DSDB_SEARCH_SHOW_EXTENDED_DN |
1230 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1231 DSDB_SEARCH_REVEAL_INTERNALS, req);
1233 if (ret != LDB_SUCCESS || res->count != 1) {
1234 DEBUG(0,(__location__ ": Object %s failed to find uSNChanged\n",
1235 ldb_dn_get_linearized(msg->dn)));
1236 return LDB_ERR_OPERATIONS_ERROR;
1239 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1240 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1245 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1246 if (*seq_num <= db_seq) {
1247 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\
1248 " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n",
1249 (long long)*seq_num, (long long)db_seq));
1250 return LDB_ERR_OPERATIONS_ERROR;
1254 /* search for the existing replPropertyMetaDataBlob. We need
1255 * to use REVEAL and ask for DNs in storage format to support
1256 * the check for values being the same in
1257 * replmd_update_rpmd_element()
1259 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1260 DSDB_FLAG_NEXT_MODULE |
1261 DSDB_SEARCH_SHOW_RECYCLED |
1262 DSDB_SEARCH_SHOW_EXTENDED_DN |
1263 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1264 DSDB_SEARCH_REVEAL_INTERNALS, req);
1265 if (ret != LDB_SUCCESS || res->count != 1) {
1266 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1267 ldb_dn_get_linearized(msg->dn)));
1268 return LDB_ERR_OPERATIONS_ERROR;
1271 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1272 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1277 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1279 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1280 ldb_dn_get_linearized(msg->dn)));
1281 return LDB_ERR_OPERATIONS_ERROR;
1284 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1285 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1286 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1287 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1288 ldb_dn_get_linearized(msg->dn)));
1289 return LDB_ERR_OPERATIONS_ERROR;
1292 if (omd.version != 1) {
1293 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1294 omd.version, ldb_dn_get_linearized(msg->dn)));
1295 return LDB_ERR_OPERATIONS_ERROR;
1298 for (i=0; i<msg->num_elements; i++) {
1299 struct ldb_message_element *old_el;
1300 old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1301 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1302 our_invocation_id, now);
1303 if (ret != LDB_SUCCESS) {
1307 if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1308 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1314 * replmd_update_rpmd_element has done an update if the
1317 if (*seq_num != 0) {
1318 struct ldb_val *md_value;
1319 struct ldb_message_element *el;
1321 /*if we are RODC and this is a DRSR update then its ok*/
1322 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1323 ret = samdb_rodc(ldb, &rodc);
1324 if (ret != LDB_SUCCESS) {
1325 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1327 ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n");
1328 return LDB_ERR_REFERRAL;
1332 md_value = talloc(msg, struct ldb_val);
1333 if (md_value == NULL) {
1335 return LDB_ERR_OPERATIONS_ERROR;
1338 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1339 if (ret != LDB_SUCCESS) {
1343 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1344 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1345 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1346 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1347 ldb_dn_get_linearized(msg->dn)));
1348 return LDB_ERR_OPERATIONS_ERROR;
1351 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1352 if (ret != LDB_SUCCESS) {
1353 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1354 ldb_dn_get_linearized(msg->dn)));
1359 el->values = md_value;
1366 struct dsdb_dn *dsdb_dn;
1371 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1373 return GUID_compare(pdn1->guid, pdn2->guid);
1376 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1377 unsigned int count, struct GUID *guid,
1380 struct parsed_dn *ret;
1382 if (dn && GUID_all_zero(guid)) {
1383 /* when updating a link using DRS, we sometimes get a
1384 NULL GUID. We then need to try and match by DN */
1385 for (i=0; i<count; i++) {
1386 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1387 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1393 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1398 get a series of message element values as an array of DNs and GUIDs
1399 the result is sorted by GUID
1401 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1402 struct ldb_message_element *el, struct parsed_dn **pdn,
1403 const char *ldap_oid, struct ldb_request *parent)
1406 struct ldb_context *ldb = ldb_module_get_ctx(module);
1413 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1415 ldb_module_oom(module);
1416 return LDB_ERR_OPERATIONS_ERROR;
1419 for (i=0; i<el->num_values; i++) {
1420 struct ldb_val *v = &el->values[i];
1423 struct parsed_dn *p;
1427 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1428 if (p->dsdb_dn == NULL) {
1429 return LDB_ERR_INVALID_DN_SYNTAX;
1432 dn = p->dsdb_dn->dn;
1434 p->guid = talloc(*pdn, struct GUID);
1435 if (p->guid == NULL) {
1436 ldb_module_oom(module);
1437 return LDB_ERR_OPERATIONS_ERROR;
1440 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1441 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1442 /* we got a DN without a GUID - go find the GUID */
1443 int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1444 if (ret != LDB_SUCCESS) {
1445 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1446 ldb_dn_get_linearized(dn));
1449 ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1450 if (ret != LDB_SUCCESS) {
1453 } else if (!NT_STATUS_IS_OK(status)) {
1454 return LDB_ERR_OPERATIONS_ERROR;
1457 /* keep a pointer to the original ldb_val */
1461 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1467 build a new extended DN, including all meta data fields
1469 RMD_FLAGS = DSDB_RMD_FLAG_* bits
1470 RMD_ADDTIME = originating_add_time
1471 RMD_INVOCID = originating_invocation_id
1472 RMD_CHANGETIME = originating_change_time
1473 RMD_ORIGINATING_USN = originating_usn
1474 RMD_LOCAL_USN = local_usn
1475 RMD_VERSION = version
1477 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1478 const struct GUID *invocation_id, uint64_t seq_num,
1479 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1481 struct ldb_dn *dn = dsdb_dn->dn;
1482 const char *tstring, *usn_string, *flags_string;
1483 struct ldb_val tval;
1485 struct ldb_val usnv, local_usnv;
1486 struct ldb_val vers, flagsv;
1489 const char *dnstring;
1491 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1493 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1495 return LDB_ERR_OPERATIONS_ERROR;
1497 tval = data_blob_string_const(tstring);
1499 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1501 return LDB_ERR_OPERATIONS_ERROR;
1503 usnv = data_blob_string_const(usn_string);
1505 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1507 return LDB_ERR_OPERATIONS_ERROR;
1509 local_usnv = data_blob_string_const(usn_string);
1511 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1513 return LDB_ERR_OPERATIONS_ERROR;
1515 vers = data_blob_string_const(vstring);
1517 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1518 if (!NT_STATUS_IS_OK(status)) {
1519 return LDB_ERR_OPERATIONS_ERROR;
1522 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1523 if (!flags_string) {
1524 return LDB_ERR_OPERATIONS_ERROR;
1526 flagsv = data_blob_string_const(flags_string);
1528 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1529 if (ret != LDB_SUCCESS) return ret;
1530 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1531 if (ret != LDB_SUCCESS) return ret;
1532 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1533 if (ret != LDB_SUCCESS) return ret;
1534 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1535 if (ret != LDB_SUCCESS) return ret;
1536 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1537 if (ret != LDB_SUCCESS) return ret;
1538 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1539 if (ret != LDB_SUCCESS) return ret;
1540 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1541 if (ret != LDB_SUCCESS) return ret;
1543 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1544 if (dnstring == NULL) {
1545 return LDB_ERR_OPERATIONS_ERROR;
1547 *v = data_blob_string_const(dnstring);
1552 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1553 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1554 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1555 uint32_t version, bool deleted);
1558 check if any links need upgrading from w2k format
1560 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.
1562 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1565 for (i=0; i<count; i++) {
1570 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1571 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1575 /* it's an old one that needs upgrading */
1576 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1578 if (ret != LDB_SUCCESS) {
1586 update an extended DN, including all meta data fields
1588 see replmd_build_la_val for value names
1590 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1591 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1592 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1593 uint32_t version, bool deleted)
1595 struct ldb_dn *dn = dsdb_dn->dn;
1596 const char *tstring, *usn_string, *flags_string;
1597 struct ldb_val tval;
1599 struct ldb_val usnv, local_usnv;
1600 struct ldb_val vers, flagsv;
1601 const struct ldb_val *old_addtime;
1602 uint32_t old_version;
1605 const char *dnstring;
1607 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1609 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1611 return LDB_ERR_OPERATIONS_ERROR;
1613 tval = data_blob_string_const(tstring);
1615 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1617 return LDB_ERR_OPERATIONS_ERROR;
1619 usnv = data_blob_string_const(usn_string);
1621 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1623 return LDB_ERR_OPERATIONS_ERROR;
1625 local_usnv = data_blob_string_const(usn_string);
1627 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1628 if (!NT_STATUS_IS_OK(status)) {
1629 return LDB_ERR_OPERATIONS_ERROR;
1632 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1633 if (!flags_string) {
1634 return LDB_ERR_OPERATIONS_ERROR;
1636 flagsv = data_blob_string_const(flags_string);
1638 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1639 if (ret != LDB_SUCCESS) return ret;
1641 /* get the ADDTIME from the original */
1642 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1643 if (old_addtime == NULL) {
1644 old_addtime = &tval;
1646 if (dsdb_dn != old_dsdb_dn) {
1647 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1648 if (ret != LDB_SUCCESS) return ret;
1651 /* use our invocation id */
1652 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1653 if (ret != LDB_SUCCESS) return ret;
1655 /* changetime is the current time */
1656 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1657 if (ret != LDB_SUCCESS) return ret;
1659 /* update the USN */
1660 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1661 if (ret != LDB_SUCCESS) return ret;
1663 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1664 if (ret != LDB_SUCCESS) return ret;
1666 /* increase the version by 1 */
1667 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1668 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1669 version = old_version+1;
1671 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1672 vers = data_blob_string_const(vstring);
1673 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1674 if (ret != LDB_SUCCESS) return ret;
1676 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1677 if (dnstring == NULL) {
1678 return LDB_ERR_OPERATIONS_ERROR;
1680 *v = data_blob_string_const(dnstring);
1686 handle adding a linked attribute
1688 static int replmd_modify_la_add(struct ldb_module *module,
1689 const struct dsdb_schema *schema,
1690 struct ldb_message *msg,
1691 struct ldb_message_element *el,
1692 struct ldb_message_element *old_el,
1693 const struct dsdb_attribute *schema_attr,
1696 struct GUID *msg_guid,
1697 struct ldb_request *parent)
1700 struct parsed_dn *dns, *old_dns;
1701 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1703 struct ldb_val *new_values = NULL;
1704 unsigned int num_new_values = 0;
1705 unsigned old_num_values = old_el?old_el->num_values:0;
1706 const struct GUID *invocation_id;
1707 struct ldb_context *ldb = ldb_module_get_ctx(module);
1710 unix_to_nt_time(&now, t);
1712 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1713 if (ret != LDB_SUCCESS) {
1714 talloc_free(tmp_ctx);
1718 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1719 if (ret != LDB_SUCCESS) {
1720 talloc_free(tmp_ctx);
1724 invocation_id = samdb_ntds_invocation_id(ldb);
1725 if (!invocation_id) {
1726 talloc_free(tmp_ctx);
1727 return LDB_ERR_OPERATIONS_ERROR;
1730 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1731 if (ret != LDB_SUCCESS) {
1732 talloc_free(tmp_ctx);
1736 /* for each new value, see if it exists already with the same GUID */
1737 for (i=0; i<el->num_values; i++) {
1738 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1740 /* this is a new linked attribute value */
1741 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1742 if (new_values == NULL) {
1743 ldb_module_oom(module);
1744 talloc_free(tmp_ctx);
1745 return LDB_ERR_OPERATIONS_ERROR;
1747 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1748 invocation_id, seq_num, seq_num, now, 0, false);
1749 if (ret != LDB_SUCCESS) {
1750 talloc_free(tmp_ctx);
1755 /* this is only allowed if the GUID was
1756 previously deleted. */
1757 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1759 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1760 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1761 el->name, GUID_string(tmp_ctx, p->guid));
1762 talloc_free(tmp_ctx);
1763 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1765 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1766 invocation_id, seq_num, seq_num, now, 0, false);
1767 if (ret != LDB_SUCCESS) {
1768 talloc_free(tmp_ctx);
1773 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1774 if (ret != LDB_SUCCESS) {
1775 talloc_free(tmp_ctx);
1780 /* add the new ones on to the end of the old values, constructing a new el->values */
1781 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1783 old_num_values+num_new_values);
1784 if (el->values == NULL) {
1785 ldb_module_oom(module);
1786 return LDB_ERR_OPERATIONS_ERROR;
1789 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1790 el->num_values = old_num_values + num_new_values;
1792 talloc_steal(msg->elements, el->values);
1793 talloc_steal(el->values, new_values);
1795 talloc_free(tmp_ctx);
1797 /* we now tell the backend to replace all existing values
1798 with the one we have constructed */
1799 el->flags = LDB_FLAG_MOD_REPLACE;
1806 handle deleting all active linked attributes
1808 static int replmd_modify_la_delete(struct ldb_module *module,
1809 const struct dsdb_schema *schema,
1810 struct ldb_message *msg,
1811 struct ldb_message_element *el,
1812 struct ldb_message_element *old_el,
1813 const struct dsdb_attribute *schema_attr,
1816 struct GUID *msg_guid,
1817 struct ldb_request *parent)
1820 struct parsed_dn *dns, *old_dns;
1821 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1823 const struct GUID *invocation_id;
1824 struct ldb_context *ldb = ldb_module_get_ctx(module);
1827 unix_to_nt_time(&now, t);
1829 /* check if there is nothing to delete */
1830 if ((!old_el || old_el->num_values == 0) &&
1831 el->num_values == 0) {
1835 if (!old_el || old_el->num_values == 0) {
1836 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1839 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1840 if (ret != LDB_SUCCESS) {
1841 talloc_free(tmp_ctx);
1845 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1846 if (ret != LDB_SUCCESS) {
1847 talloc_free(tmp_ctx);
1851 invocation_id = samdb_ntds_invocation_id(ldb);
1852 if (!invocation_id) {
1853 return LDB_ERR_OPERATIONS_ERROR;
1856 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1857 if (ret != LDB_SUCCESS) {
1858 talloc_free(tmp_ctx);
1864 /* see if we are being asked to delete any links that
1865 don't exist or are already deleted */
1866 for (i=0; i<el->num_values; i++) {
1867 struct parsed_dn *p = &dns[i];
1868 struct parsed_dn *p2;
1871 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1873 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1874 el->name, GUID_string(tmp_ctx, p->guid));
1875 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1877 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1878 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1879 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1880 el->name, GUID_string(tmp_ctx, p->guid));
1881 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1885 /* for each new value, see if it exists already with the same GUID
1886 if it is not already deleted and matches the delete list then delete it
1888 for (i=0; i<old_el->num_values; i++) {
1889 struct parsed_dn *p = &old_dns[i];
1892 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1896 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1897 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1899 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1900 invocation_id, seq_num, seq_num, now, 0, true);
1901 if (ret != LDB_SUCCESS) {
1902 talloc_free(tmp_ctx);
1906 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1907 if (ret != LDB_SUCCESS) {
1908 talloc_free(tmp_ctx);
1913 el->values = talloc_steal(msg->elements, old_el->values);
1914 el->num_values = old_el->num_values;
1916 talloc_free(tmp_ctx);
1918 /* we now tell the backend to replace all existing values
1919 with the one we have constructed */
1920 el->flags = LDB_FLAG_MOD_REPLACE;
1926 handle replacing a linked attribute
1928 static int replmd_modify_la_replace(struct ldb_module *module,
1929 const struct dsdb_schema *schema,
1930 struct ldb_message *msg,
1931 struct ldb_message_element *el,
1932 struct ldb_message_element *old_el,
1933 const struct dsdb_attribute *schema_attr,
1936 struct GUID *msg_guid,
1937 struct ldb_request *parent)
1940 struct parsed_dn *dns, *old_dns;
1941 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1943 const struct GUID *invocation_id;
1944 struct ldb_context *ldb = ldb_module_get_ctx(module);
1945 struct ldb_val *new_values = NULL;
1946 unsigned int num_new_values = 0;
1947 unsigned int old_num_values = old_el?old_el->num_values:0;
1950 unix_to_nt_time(&now, t);
1952 /* check if there is nothing to replace */
1953 if ((!old_el || old_el->num_values == 0) &&
1954 el->num_values == 0) {
1958 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1959 if (ret != LDB_SUCCESS) {
1960 talloc_free(tmp_ctx);
1964 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1965 if (ret != LDB_SUCCESS) {
1966 talloc_free(tmp_ctx);
1970 invocation_id = samdb_ntds_invocation_id(ldb);
1971 if (!invocation_id) {
1972 return LDB_ERR_OPERATIONS_ERROR;
1975 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1976 if (ret != LDB_SUCCESS) {
1977 talloc_free(tmp_ctx);
1981 /* mark all the old ones as deleted */
1982 for (i=0; i<old_num_values; i++) {
1983 struct parsed_dn *old_p = &old_dns[i];
1984 struct parsed_dn *p;
1985 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1987 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1989 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1990 if (ret != LDB_SUCCESS) {
1991 talloc_free(tmp_ctx);
1995 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1997 /* we don't delete it if we are re-adding it */
2001 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2002 invocation_id, seq_num, seq_num, now, 0, true);
2003 if (ret != LDB_SUCCESS) {
2004 talloc_free(tmp_ctx);
2009 /* for each new value, either update its meta-data, or add it
2012 for (i=0; i<el->num_values; i++) {
2013 struct parsed_dn *p = &dns[i], *old_p;
2016 (old_p = parsed_dn_find(old_dns,
2017 old_num_values, p->guid, NULL)) != NULL) {
2018 /* update in place */
2019 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
2020 old_p->dsdb_dn, invocation_id,
2021 seq_num, seq_num, now, 0, false);
2022 if (ret != LDB_SUCCESS) {
2023 talloc_free(tmp_ctx);
2028 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2030 if (new_values == NULL) {
2031 ldb_module_oom(module);
2032 talloc_free(tmp_ctx);
2033 return LDB_ERR_OPERATIONS_ERROR;
2035 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2036 invocation_id, seq_num, seq_num, now, 0, false);
2037 if (ret != LDB_SUCCESS) {
2038 talloc_free(tmp_ctx);
2044 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2045 if (ret != LDB_SUCCESS) {
2046 talloc_free(tmp_ctx);
2051 /* add the new values to the end of old_el */
2052 if (num_new_values != 0) {
2053 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2054 struct ldb_val, old_num_values+num_new_values);
2055 if (el->values == NULL) {
2056 ldb_module_oom(module);
2057 return LDB_ERR_OPERATIONS_ERROR;
2059 memcpy(&el->values[old_num_values], &new_values[0],
2060 sizeof(struct ldb_val)*num_new_values);
2061 el->num_values = old_num_values + num_new_values;
2062 talloc_steal(msg->elements, new_values);
2064 el->values = old_el->values;
2065 el->num_values = old_el->num_values;
2066 talloc_steal(msg->elements, el->values);
2069 talloc_free(tmp_ctx);
2071 /* we now tell the backend to replace all existing values
2072 with the one we have constructed */
2073 el->flags = LDB_FLAG_MOD_REPLACE;
2080 handle linked attributes in modify requests
2082 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2083 struct ldb_message *msg,
2084 uint64_t seq_num, time_t t,
2085 struct ldb_request *parent)
2087 struct ldb_result *res;
2090 struct ldb_context *ldb = ldb_module_get_ctx(module);
2091 struct ldb_message *old_msg;
2093 const struct dsdb_schema *schema;
2094 struct GUID old_guid;
2097 /* there the replmd_update_rpmd code has already
2098 * checked and saw that there are no linked
2103 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2104 /* don't do anything special for linked attributes */
2108 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2109 DSDB_FLAG_NEXT_MODULE |
2110 DSDB_SEARCH_SHOW_RECYCLED |
2111 DSDB_SEARCH_REVEAL_INTERNALS |
2112 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2114 if (ret != LDB_SUCCESS) {
2117 schema = dsdb_get_schema(ldb, res);
2119 return LDB_ERR_OPERATIONS_ERROR;
2122 old_msg = res->msgs[0];
2124 old_guid = samdb_result_guid(old_msg, "objectGUID");
2126 for (i=0; i<msg->num_elements; i++) {
2127 struct ldb_message_element *el = &msg->elements[i];
2128 struct ldb_message_element *old_el, *new_el;
2129 const struct dsdb_attribute *schema_attr
2130 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2132 ldb_asprintf_errstring(ldb,
2133 "%s: attribute %s is not a valid attribute in schema",
2134 __FUNCTION__, el->name);
2135 return LDB_ERR_OBJECT_CLASS_VIOLATION;
2137 if (schema_attr->linkID == 0) {
2140 if ((schema_attr->linkID & 1) == 1) {
2141 /* Odd is for the target. Illegal to modify */
2142 ldb_asprintf_errstring(ldb,
2143 "attribute %s must not be modified directly, it is a linked attribute", el->name);
2144 return LDB_ERR_UNWILLING_TO_PERFORM;
2146 old_el = ldb_msg_find_element(old_msg, el->name);
2147 switch (el->flags & LDB_FLAG_MOD_MASK) {
2148 case LDB_FLAG_MOD_REPLACE:
2149 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2151 case LDB_FLAG_MOD_DELETE:
2152 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2154 case LDB_FLAG_MOD_ADD:
2155 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2158 ldb_asprintf_errstring(ldb,
2159 "invalid flags 0x%x for %s linked attribute",
2160 el->flags, el->name);
2161 return LDB_ERR_UNWILLING_TO_PERFORM;
2163 if (ret != LDB_SUCCESS) {
2167 ldb_msg_remove_attr(old_msg, el->name);
2169 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2170 new_el->num_values = el->num_values;
2171 new_el->values = talloc_steal(msg->elements, el->values);
2173 /* TODO: this relises a bit too heavily on the exact
2174 behaviour of ldb_msg_find_element and
2175 ldb_msg_remove_element */
2176 old_el = ldb_msg_find_element(msg, el->name);
2178 ldb_msg_remove_element(msg, old_el);
2189 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2191 struct ldb_context *ldb;
2192 struct replmd_replicated_request *ac;
2193 struct ldb_request *down_req;
2194 struct ldb_message *msg;
2195 time_t t = time(NULL);
2197 bool is_urgent = false;
2198 struct loadparm_context *lp_ctx;
2200 unsigned int functional_level;
2201 const DATA_BLOB *guid_blob;
2203 /* do not manipulate our control entries */
2204 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2205 return ldb_next_request(module, req);
2208 ldb = ldb_module_get_ctx(module);
2210 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2212 guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2213 if ( guid_blob != NULL ) {
2214 ldb_set_errstring(ldb,
2215 "replmd_modify: it's not allowed to change the objectGUID!");
2216 return LDB_ERR_CONSTRAINT_VIOLATION;
2219 ac = replmd_ctx_init(module, req);
2221 return ldb_module_oom(module);
2224 functional_level = dsdb_functional_level(ldb);
2226 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2227 struct loadparm_context);
2229 /* we have to copy the message as the caller might have it as a const */
2230 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2234 return LDB_ERR_OPERATIONS_ERROR;
2237 ldb_msg_remove_attr(msg, "whenChanged");
2238 ldb_msg_remove_attr(msg, "uSNChanged");
2240 ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2241 msg, &ac->seq_num, t, &is_urgent);
2242 if (ret == LDB_ERR_REFERRAL) {
2243 referral = talloc_asprintf(req,
2245 lpcfg_dnsdomain(lp_ctx),
2246 ldb_dn_get_linearized(msg->dn));
2247 ret = ldb_module_send_referral(req, referral);
2249 return ldb_module_done(req, NULL, NULL, ret);
2252 if (ret != LDB_SUCCESS) {
2257 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2258 if (ret != LDB_SUCCESS) {
2264 * - replace the old object with the newly constructed one
2267 ac->is_urgent = is_urgent;
2269 ret = ldb_build_mod_req(&down_req, ldb, ac,
2272 ac, replmd_op_callback,
2274 LDB_REQ_SET_LOCATION(down_req);
2275 if (ret != LDB_SUCCESS) {
2280 /* current partition control is needed by "replmd_op_callback" */
2281 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2282 ret = ldb_request_add_control(down_req,
2283 DSDB_CONTROL_CURRENT_PARTITION_OID,
2285 if (ret != LDB_SUCCESS) {
2291 /* If we are in functional level 2000, then
2292 * replmd_modify_handle_linked_attribs will have done
2294 if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2295 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2296 if (ret != LDB_SUCCESS) {
2302 talloc_steal(down_req, msg);
2304 /* we only change whenChanged and uSNChanged if the seq_num
2306 if (ac->seq_num != 0) {
2307 ret = add_time_element(msg, "whenChanged", t);
2308 if (ret != LDB_SUCCESS) {
2313 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2314 if (ret != LDB_SUCCESS) {
2320 /* go on with the call chain */
2321 return ldb_next_request(module, down_req);
2324 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2327 handle a rename request
2329 On a rename we need to do an extra ldb_modify which sets the
2330 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2332 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2334 struct ldb_context *ldb;
2335 struct replmd_replicated_request *ac;
2337 struct ldb_request *down_req;
2339 /* do not manipulate our control entries */
2340 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2341 return ldb_next_request(module, req);
2344 ldb = ldb_module_get_ctx(module);
2346 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2348 ac = replmd_ctx_init(module, req);
2350 return ldb_module_oom(module);
2353 ret = ldb_build_rename_req(&down_req, ldb, ac,
2354 ac->req->op.rename.olddn,
2355 ac->req->op.rename.newdn,
2357 ac, replmd_rename_callback,
2359 LDB_REQ_SET_LOCATION(down_req);
2360 if (ret != LDB_SUCCESS) {
2365 /* go on with the call chain */
2366 return ldb_next_request(module, down_req);
2369 /* After the rename is compleated, update the whenchanged etc */
2370 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2372 struct ldb_context *ldb;
2373 struct replmd_replicated_request *ac;
2374 struct ldb_request *down_req;
2375 struct ldb_message *msg;
2376 const struct dsdb_attribute *rdn_attr;
2377 const char *rdn_name;
2378 const struct ldb_val *rdn_val;
2379 const char *attrs[4] = { NULL, };
2380 time_t t = time(NULL);
2382 bool is_urgent = false;
2384 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2385 ldb = ldb_module_get_ctx(ac->module);
2387 if (ares->error != LDB_SUCCESS) {
2388 return ldb_module_done(ac->req, ares->controls,
2389 ares->response, ares->error);
2392 if (ares->type != LDB_REPLY_DONE) {
2393 ldb_set_errstring(ldb,
2394 "invalid ldb_reply_type in callback");
2396 return ldb_module_done(ac->req, NULL, NULL,
2397 LDB_ERR_OPERATIONS_ERROR);
2401 * - replace the old object with the newly constructed one
2404 msg = ldb_msg_new(ac);
2407 return LDB_ERR_OPERATIONS_ERROR;
2410 msg->dn = ac->req->op.rename.newdn;
2412 rdn_name = ldb_dn_get_rdn_name(msg->dn);
2413 if (rdn_name == NULL) {
2415 return ldb_module_done(ac->req, NULL, NULL,
2419 /* normalize the rdn attribute name */
2420 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2421 if (rdn_attr == NULL) {
2423 return ldb_module_done(ac->req, NULL, NULL,
2426 rdn_name = rdn_attr->lDAPDisplayName;
2428 rdn_val = ldb_dn_get_rdn_val(msg->dn);
2429 if (rdn_val == NULL) {
2431 return ldb_module_done(ac->req, NULL, NULL,
2435 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2437 return ldb_module_done(ac->req, NULL, NULL,
2440 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2442 return ldb_module_done(ac->req, NULL, NULL,
2445 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2447 return ldb_module_done(ac->req, NULL, NULL,
2450 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2452 return ldb_module_done(ac->req, NULL, NULL,
2457 * here we let replmd_update_rpmd() only search for
2458 * the existing "replPropertyMetaData" and rdn_name attributes.
2460 * We do not want the existing "name" attribute as
2461 * the "name" attribute needs to get the version
2462 * updated on rename even if the rdn value hasn't changed.
2464 * This is the diff of the meta data, for a moved user
2465 * on a w2k8r2 server:
2468 * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2469 * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2470 * replPropertyMetaData: NDR: struct replPropertyMetaDataBlob
2471 * version : 0x00000001 (1)
2472 * reserved : 0x00000000 (0)
2473 * @@ -66,11 +66,11 @@ replPropertyMetaData: NDR: struct re
2474 * local_usn : 0x00000000000037a5 (14245)
2475 * array: struct replPropertyMetaData1
2476 * attid : DRSUAPI_ATTID_name (0x90001)
2477 * - version : 0x00000001 (1)
2478 * - originating_change_time : Wed Feb 9 17:20:49 2011 CET
2479 * + version : 0x00000002 (2)
2480 * + originating_change_time : Wed Apr 6 15:21:01 2011 CEST
2481 * originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2482 * - originating_usn : 0x00000000000037a5 (14245)
2483 * - local_usn : 0x00000000000037a5 (14245)
2484 * + originating_usn : 0x0000000000003834 (14388)
2485 * + local_usn : 0x0000000000003834 (14388)
2486 * array: struct replPropertyMetaData1
2487 * attid : DRSUAPI_ATTID_userAccountControl (0x90008)
2488 * version : 0x00000004 (4)
2490 attrs[0] = "replPropertyMetaData";
2491 attrs[1] = "objectClass";
2492 attrs[2] = rdn_name;
2495 ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2496 msg, &ac->seq_num, t, &is_urgent);
2497 if (ret == LDB_ERR_REFERRAL) {
2498 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2499 struct loadparm_context *lp_ctx;
2502 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2503 struct loadparm_context);
2505 referral = talloc_asprintf(req,
2507 lpcfg_dnsdomain(lp_ctx),
2508 ldb_dn_get_linearized(olddn));
2509 ret = ldb_module_send_referral(req, referral);
2511 return ldb_module_done(req, NULL, NULL, ret);
2514 if (ret != LDB_SUCCESS) {
2516 return ldb_module_done(ac->req, NULL, NULL,
2518 "failed to call replmd_update_rpmd()"));
2521 if (ac->seq_num == 0) {
2523 return ldb_module_done(ac->req, NULL, NULL,
2525 "internal error seq_num == 0"));
2527 ac->is_urgent = is_urgent;
2529 ret = ldb_build_mod_req(&down_req, ldb, ac,
2532 ac, replmd_op_callback,
2534 LDB_REQ_SET_LOCATION(down_req);
2535 if (ret != LDB_SUCCESS) {
2540 /* current partition control is needed by "replmd_op_callback" */
2541 if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2542 ret = ldb_request_add_control(down_req,
2543 DSDB_CONTROL_CURRENT_PARTITION_OID,
2545 if (ret != LDB_SUCCESS) {
2551 talloc_steal(down_req, msg);
2553 ret = add_time_element(msg, "whenChanged", t);
2554 if (ret != LDB_SUCCESS) {
2559 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2560 if (ret != LDB_SUCCESS) {
2565 /* go on with the call chain - do the modify after the rename */
2566 return ldb_next_request(ac->module, down_req);
2570 remove links from objects that point at this object when an object
2573 static int replmd_delete_remove_link(struct ldb_module *module,
2574 const struct dsdb_schema *schema,
2576 struct ldb_message_element *el,
2577 const struct dsdb_attribute *sa,
2578 struct ldb_request *parent)
2581 TALLOC_CTX *tmp_ctx = talloc_new(module);
2582 struct ldb_context *ldb = ldb_module_get_ctx(module);
2584 for (i=0; i<el->num_values; i++) {
2585 struct dsdb_dn *dsdb_dn;
2589 struct ldb_message *msg;
2590 const struct dsdb_attribute *target_attr;
2591 struct ldb_message_element *el2;
2592 struct ldb_val dn_val;
2594 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2598 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2600 talloc_free(tmp_ctx);
2601 return LDB_ERR_OPERATIONS_ERROR;
2604 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2605 if (!NT_STATUS_IS_OK(status)) {
2606 talloc_free(tmp_ctx);
2607 return LDB_ERR_OPERATIONS_ERROR;
2610 /* remove the link */
2611 msg = ldb_msg_new(tmp_ctx);
2613 ldb_module_oom(module);
2614 talloc_free(tmp_ctx);
2615 return LDB_ERR_OPERATIONS_ERROR;
2619 msg->dn = dsdb_dn->dn;
2621 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2622 if (target_attr == NULL) {
2626 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2627 if (ret != LDB_SUCCESS) {
2628 ldb_module_oom(module);
2629 talloc_free(tmp_ctx);
2630 return LDB_ERR_OPERATIONS_ERROR;
2632 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2633 el2->values = &dn_val;
2634 el2->num_values = 1;
2636 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2637 if (ret != LDB_SUCCESS) {
2638 talloc_free(tmp_ctx);
2642 talloc_free(tmp_ctx);
2648 handle update of replication meta data for deletion of objects
2650 This also handles the mapping of delete to a rename operation
2651 to allow deletes to be replicated.
2653 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2655 int ret = LDB_ERR_OTHER;
2656 bool retb, disallow_move_on_delete;
2657 struct ldb_dn *old_dn, *new_dn;
2658 const char *rdn_name;
2659 const struct ldb_val *rdn_value, *new_rdn_value;
2661 struct ldb_context *ldb = ldb_module_get_ctx(module);
2662 const struct dsdb_schema *schema;
2663 struct ldb_message *msg, *old_msg;
2664 struct ldb_message_element *el;
2665 TALLOC_CTX *tmp_ctx;
2666 struct ldb_result *res, *parent_res;
2667 const char *preserved_attrs[] = {
2668 /* yes, this really is a hard coded list. See MS-ADTS
2669 section 3.1.1.5.5.1.1 */
2670 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2671 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2672 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2673 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2674 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2675 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2676 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2677 "whenChanged", NULL};
2678 unsigned int i, el_count = 0;
2679 enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2680 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2681 enum deletion_state deletion_state, next_deletion_state;
2684 if (ldb_dn_is_special(req->op.del.dn)) {
2685 return ldb_next_request(module, req);
2688 tmp_ctx = talloc_new(ldb);
2691 return LDB_ERR_OPERATIONS_ERROR;
2694 schema = dsdb_get_schema(ldb, tmp_ctx);
2696 return LDB_ERR_OPERATIONS_ERROR;
2699 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2701 /* we need the complete msg off disk, so we can work out which
2702 attributes need to be removed */
2703 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2704 DSDB_FLAG_NEXT_MODULE |
2705 DSDB_SEARCH_SHOW_RECYCLED |
2706 DSDB_SEARCH_REVEAL_INTERNALS |
2707 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2708 if (ret != LDB_SUCCESS) {
2709 talloc_free(tmp_ctx);
2712 old_msg = res->msgs[0];
2715 ret = dsdb_recyclebin_enabled(module, &enabled);
2716 if (ret != LDB_SUCCESS) {
2717 talloc_free(tmp_ctx);
2721 if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2723 deletion_state = OBJECT_TOMBSTONE;
2724 next_deletion_state = OBJECT_REMOVED;
2725 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2726 deletion_state = OBJECT_RECYCLED;
2727 next_deletion_state = OBJECT_REMOVED;
2729 deletion_state = OBJECT_DELETED;
2730 next_deletion_state = OBJECT_RECYCLED;
2733 deletion_state = OBJECT_NOT_DELETED;
2735 next_deletion_state = OBJECT_DELETED;
2737 next_deletion_state = OBJECT_TOMBSTONE;
2741 if (next_deletion_state == OBJECT_REMOVED) {
2742 struct auth_session_info *session_info =
2743 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2744 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2745 ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2746 ldb_dn_get_linearized(old_msg->dn));
2747 return LDB_ERR_UNWILLING_TO_PERFORM;
2750 /* it is already deleted - really remove it this time */
2751 talloc_free(tmp_ctx);
2752 return ldb_next_request(module, req);
2755 rdn_name = ldb_dn_get_rdn_name(old_dn);
2756 rdn_value = ldb_dn_get_rdn_val(old_dn);
2757 if ((rdn_name == NULL) || (rdn_value == NULL)) {
2758 talloc_free(tmp_ctx);
2759 return ldb_operr(ldb);
2762 msg = ldb_msg_new(tmp_ctx);
2764 ldb_module_oom(module);
2765 talloc_free(tmp_ctx);
2766 return LDB_ERR_OPERATIONS_ERROR;
2771 if (deletion_state == OBJECT_NOT_DELETED){
2772 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2773 disallow_move_on_delete =
2774 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2775 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2777 /* work out where we will be renaming this object to */
2778 if (!disallow_move_on_delete) {
2779 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2781 if (ret != LDB_SUCCESS) {
2782 /* this is probably an attempted delete on a partition
2783 * that doesn't allow delete operations, such as the
2784 * schema partition */
2785 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2786 ldb_dn_get_linearized(old_dn));
2787 talloc_free(tmp_ctx);
2788 return LDB_ERR_UNWILLING_TO_PERFORM;
2791 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2792 if (new_dn == NULL) {
2793 ldb_module_oom(module);
2794 talloc_free(tmp_ctx);
2795 return LDB_ERR_OPERATIONS_ERROR;
2799 /* get the objects GUID from the search we just did */
2800 guid = samdb_result_guid(old_msg, "objectGUID");
2802 /* Add a formatted child */
2803 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2805 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2806 GUID_string(tmp_ctx, &guid));
2808 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2809 ldb_dn_get_linearized(new_dn)));
2810 talloc_free(tmp_ctx);
2811 return LDB_ERR_OPERATIONS_ERROR;
2814 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2815 if (ret != LDB_SUCCESS) {
2816 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2817 ldb_module_oom(module);
2818 talloc_free(tmp_ctx);
2821 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2825 now we need to modify the object in the following ways:
2827 - add isDeleted=TRUE
2828 - update rDN and name, with new rDN
2829 - remove linked attributes
2830 - remove objectCategory and sAMAccountType
2831 - remove attribs not on the preserved list
2832 - preserved if in above list, or is rDN
2833 - remove all linked attribs from this object
2834 - remove all links from other objects to this object
2835 - add lastKnownParent
2836 - update replPropertyMetaData?
2838 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2841 /* we need the storage form of the parent GUID */
2842 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2843 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2844 DSDB_FLAG_NEXT_MODULE |
2845 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2846 DSDB_SEARCH_REVEAL_INTERNALS|
2847 DSDB_SEARCH_SHOW_RECYCLED, req);
2848 if (ret != LDB_SUCCESS) {
2849 talloc_free(tmp_ctx);
2853 if (deletion_state == OBJECT_NOT_DELETED){
2854 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2855 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2856 if (ret != LDB_SUCCESS) {
2857 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2858 ldb_module_oom(module);
2859 talloc_free(tmp_ctx);
2862 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2865 switch (next_deletion_state){
2867 case OBJECT_DELETED:
2869 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2870 if (ret != LDB_SUCCESS) {
2871 DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2872 ldb_module_oom(module);
2873 talloc_free(tmp_ctx);
2876 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2878 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_DELETE, NULL);
2879 if (ret != LDB_SUCCESS) {
2880 talloc_free(tmp_ctx);
2881 ldb_module_oom(module);
2885 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_DELETE, NULL);
2886 if (ret != LDB_SUCCESS) {
2887 talloc_free(tmp_ctx);
2888 ldb_module_oom(module);
2894 case OBJECT_RECYCLED:
2895 case OBJECT_TOMBSTONE:
2897 /* we also mark it as recycled, meaning this object can't be
2898 recovered (we are stripping its attributes) */
2899 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2900 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2901 if (ret != LDB_SUCCESS) {
2902 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2903 ldb_module_oom(module);
2904 talloc_free(tmp_ctx);
2907 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2910 /* work out which of the old attributes we will be removing */
2911 for (i=0; i<old_msg->num_elements; i++) {
2912 const struct dsdb_attribute *sa;
2913 el = &old_msg->elements[i];
2914 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2916 talloc_free(tmp_ctx);
2917 return LDB_ERR_OPERATIONS_ERROR;
2919 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2920 /* don't remove the rDN */
2923 if (sa->linkID && sa->linkID & 1) {
2924 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
2925 if (ret != LDB_SUCCESS) {
2926 talloc_free(tmp_ctx);
2927 return LDB_ERR_OPERATIONS_ERROR;
2931 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2934 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2935 if (ret != LDB_SUCCESS) {
2936 talloc_free(tmp_ctx);
2937 ldb_module_oom(module);
2947 if (deletion_state == OBJECT_NOT_DELETED) {
2948 const struct dsdb_attribute *sa;
2950 /* work out what the new rdn value is, for updating the
2951 rDN and name fields */
2952 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2953 if (new_rdn_value == NULL) {
2954 talloc_free(tmp_ctx);
2955 return ldb_operr(ldb);
2958 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
2960 talloc_free(tmp_ctx);
2961 return LDB_ERR_OPERATIONS_ERROR;
2964 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
2966 if (ret != LDB_SUCCESS) {
2967 talloc_free(tmp_ctx);
2970 el->flags = LDB_FLAG_MOD_REPLACE;
2972 el = ldb_msg_find_element(old_msg, "name");
2974 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2975 if (ret != LDB_SUCCESS) {
2976 talloc_free(tmp_ctx);
2979 el->flags = LDB_FLAG_MOD_REPLACE;
2983 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
2984 if (ret != LDB_SUCCESS) {
2985 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2986 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2987 talloc_free(tmp_ctx);
2991 if (deletion_state == OBJECT_NOT_DELETED) {
2992 /* now rename onto the new DN */
2993 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
2994 if (ret != LDB_SUCCESS){
2995 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2996 ldb_dn_get_linearized(old_dn),
2997 ldb_dn_get_linearized(new_dn),
2998 ldb_errstring(ldb)));
2999 talloc_free(tmp_ctx);
3004 talloc_free(tmp_ctx);
3006 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3011 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3016 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3018 int ret = LDB_ERR_OTHER;
3019 /* TODO: do some error mapping */
3024 static struct replPropertyMetaData1 *
3025 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3026 enum drsuapi_DsAttributeId attid)
3029 struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3031 for (i = 0; i < rpmd_ctr->count; i++) {
3032 if (rpmd_ctr->array[i].attid == attid) {
3033 return &rpmd_ctr->array[i];
3041 return true if an update is newer than an existing entry
3042 see section 5.11 of MS-ADTS
3044 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3045 const struct GUID *update_invocation_id,
3046 uint32_t current_version,
3047 uint32_t update_version,
3048 NTTIME current_change_time,
3049 NTTIME update_change_time)
3051 if (update_version != current_version) {
3052 return update_version > current_version;
3054 if (update_change_time != current_change_time) {
3055 return update_change_time > current_change_time;
3057 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3060 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3061 struct replPropertyMetaData1 *new_m)
3063 return replmd_update_is_newer(&cur_m->originating_invocation_id,
3064 &new_m->originating_invocation_id,
3067 cur_m->originating_change_time,
3068 new_m->originating_change_time);
3075 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3077 const struct ldb_val *rdn_val;
3078 const char *rdn_name;
3079 struct ldb_dn *new_dn;
3081 rdn_val = ldb_dn_get_rdn_val(dn);
3082 rdn_name = ldb_dn_get_rdn_name(dn);
3083 if (!rdn_val || !rdn_name) {
3087 new_dn = ldb_dn_copy(mem_ctx, dn);
3092 if (!ldb_dn_remove_child_components(new_dn, 1)) {
3096 if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3098 ldb_dn_escape_value(new_dn, *rdn_val),
3099 GUID_string(new_dn, guid))) {
3108 perform a modify operation which sets the rDN and name attributes to
3109 their current values. This has the effect of changing these
3110 attributes to have been last updated by the current DC. This is
3111 needed to ensure that renames performed as part of conflict
3112 resolution are propogated to other DCs
3114 static int replmd_name_modify(struct replmd_replicated_request *ar,
3115 struct ldb_request *req, struct ldb_dn *dn)
3117 struct ldb_message *msg;
3118 const char *rdn_name;
3119 const struct ldb_val *rdn_val;
3120 const struct dsdb_attribute *rdn_attr;
3123 msg = ldb_msg_new(req);
3129 rdn_name = ldb_dn_get_rdn_name(dn);
3130 if (rdn_name == NULL) {
3134 /* normalize the rdn attribute name */
3135 rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3136 if (rdn_attr == NULL) {
3139 rdn_name = rdn_attr->lDAPDisplayName;
3141 rdn_val = ldb_dn_get_rdn_val(dn);
3142 if (rdn_val == NULL) {
3146 if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3149 if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3152 if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3155 if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3159 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3160 if (ret != LDB_SUCCESS) {
3161 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3162 ldb_dn_get_linearized(dn),
3163 ldb_errstring(ldb_module_get_ctx(ar->module))));
3173 DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3174 ldb_dn_get_linearized(dn)));
3175 return LDB_ERR_OPERATIONS_ERROR;
3180 callback for conflict DN handling where we have renamed the incoming
3181 record. After renaming it, we need to ensure the change of name and
3182 rDN for the incoming record is seen as an originating update by this DC.
3184 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3186 struct replmd_replicated_request *ar =
3187 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3190 if (ares->error != LDB_SUCCESS) {
3191 /* call the normal callback for everything except success */
3192 return replmd_op_callback(req, ares);
3195 /* perform a modify of the rDN and name of the record */
3196 ret = replmd_name_modify(ar, req, req->op.add.message->dn);
3197 if (ret != LDB_SUCCESS) {
3199 return replmd_op_callback(req, ares);
3202 return replmd_op_callback(req, ares);
3206 callback for replmd_replicated_apply_add()
3207 This copes with the creation of conflict records in the case where
3208 the DN exists, but with a different objectGUID
3210 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3212 struct ldb_dn *conflict_dn;
3213 struct replmd_replicated_request *ar =
3214 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3215 struct ldb_result *res;
3216 const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3218 const struct ldb_val *rmd_value, *omd_value;
3219 struct replPropertyMetaDataBlob omd, rmd;
3220 enum ndr_err_code ndr_err;
3221 bool rename_incoming_record;
3222 struct replPropertyMetaData1 *rmd_name, *omd_name;
3224 if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3225 /* call the normal callback for everything except
3227 return replmd_op_callback(req, ares);
3231 * we have a conflict, and need to decide if we will keep the
3232 * new record or the old record
3234 conflict_dn = req->op.add.message->dn;
3237 * first we need the replPropertyMetaData attribute from the
3240 ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3242 DSDB_FLAG_NEXT_MODULE |
3243 DSDB_SEARCH_SHOW_DELETED |
3244 DSDB_SEARCH_SHOW_RECYCLED, req);
3245 if (ret != LDB_SUCCESS) {
3246 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3247 ldb_dn_get_linearized(conflict_dn)));
3251 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3252 if (omd_value == NULL) {
3253 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3254 ldb_dn_get_linearized(conflict_dn)));
3258 ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3259 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3260 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3261 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3262 ldb_dn_get_linearized(conflict_dn)));
3267 * and the replPropertyMetaData attribute from the
3270 rmd_value = ldb_msg_find_ldb_val(req->op.add.message, "replPropertyMetaData");
3271 if (rmd_value == NULL) {
3272 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for new record '%s'\n",
3273 ldb_dn_get_linearized(conflict_dn)));
3277 ndr_err = ndr_pull_struct_blob(rmd_value, req, &rmd,
3278 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3279 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3280 DEBUG(0,(__location__ ": Failed to parse new replPropertyMetaData for %s\n",
3281 ldb_dn_get_linearized(conflict_dn)));
3285 /* we decide which is newer based on the RPMD on the name
3286 attribute. See [MS-DRSR] ResolveNameConflict */
3287 rmd_name = replmd_replPropertyMetaData1_find_attid(&rmd, DRSUAPI_ATTID_name);
3288 omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3289 if (!rmd_name || !omd_name) {
3290 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3291 ldb_dn_get_linearized(conflict_dn)));
3295 rename_incoming_record = !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3297 if (rename_incoming_record) {
3299 struct ldb_dn *new_dn;
3300 struct ldb_message *new_msg;
3302 guid = samdb_result_guid(req->op.add.message, "objectGUID");
3303 if (GUID_all_zero(&guid)) {
3304 DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3305 ldb_dn_get_linearized(conflict_dn)));
3308 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3309 if (new_dn == NULL) {
3310 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3311 ldb_dn_get_linearized(conflict_dn)));
3315 DEBUG(1,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3316 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3318 /* re-submit the request, but with a different
3319 callback, so we don't loop forever. */
3320 new_msg = ldb_msg_copy_shallow(req, req->op.add.message);
3323 DEBUG(0,(__location__ ": Failed to copy conflict DN message for %s\n",
3324 ldb_dn_get_linearized(conflict_dn)));
3326 new_msg->dn = new_dn;
3327 req->op.add.message = new_msg;
3328 req->callback = replmd_op_name_modify_callback;
3330 return ldb_next_request(ar->module, req);
3332 /* we are renaming the existing record */
3334 struct ldb_dn *new_dn;
3336 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3337 if (GUID_all_zero(&guid)) {
3338 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3339 ldb_dn_get_linearized(conflict_dn)));
3343 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3344 if (new_dn == NULL) {
3345 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3346 ldb_dn_get_linearized(conflict_dn)));
3350 DEBUG(1,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
3351 ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3353 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3354 DSDB_FLAG_OWN_MODULE, req);
3355 if (ret != LDB_SUCCESS) {
3356 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3357 ldb_dn_get_linearized(conflict_dn),
3358 ldb_dn_get_linearized(new_dn),
3359 ldb_errstring(ldb_module_get_ctx(ar->module))));
3364 * now we need to ensure that the rename is seen as an
3365 * originating update. We do that with a modify.
3367 ret = replmd_name_modify(ar, req, new_dn);
3368 if (ret != LDB_SUCCESS) {
3372 req->callback = replmd_op_callback;
3374 return ldb_next_request(ar->module, req);
3378 /* on failure do the original callback. This means replication
3379 * will stop with an error, but there is not much else we can
3382 return replmd_op_callback(req, ares);
3386 this is called when a new object comes in over DRS
3388 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3390 struct ldb_context *ldb;
3391 struct ldb_request *change_req;
3392 enum ndr_err_code ndr_err;
3393 struct ldb_message *msg;
3394 struct replPropertyMetaDataBlob *md;
3395 struct ldb_val md_value;
3400 * TODO: check if the parent object exist
3404 * TODO: handle the conflict case where an object with the
3408 ldb = ldb_module_get_ctx(ar->module);
3409 msg = ar->objs->objects[ar->index_current].msg;
3410 md = ar->objs->objects[ar->index_current].meta_data;
3412 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3413 if (ret != LDB_SUCCESS) {
3414 return replmd_replicated_request_error(ar, ret);
3417 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
3418 if (ret != LDB_SUCCESS) {
3419 return replmd_replicated_request_error(ar, ret);
3422 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3423 if (ret != LDB_SUCCESS) {
3424 return replmd_replicated_request_error(ar, ret);
3427 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
3428 if (ret != LDB_SUCCESS) {
3429 return replmd_replicated_request_error(ar, ret);
3432 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3433 if (ret != LDB_SUCCESS) {
3434 return replmd_replicated_request_error(ar, ret);
3437 /* remove any message elements that have zero values */
3438 for (i=0; i<msg->num_elements; i++) {
3439 struct ldb_message_element *el = &msg->elements[i];
3441 if (el->num_values == 0) {
3442 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
3444 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
3445 msg->num_elements--;
3452 * the meta data array is already sorted by the caller
3454 for (i=0; i < md->ctr.ctr1.count; i++) {
3455 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3457 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3458 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3459 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3460 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3461 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3463 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3464 if (ret != LDB_SUCCESS) {
3465 return replmd_replicated_request_error(ar, ret);
3468 replmd_ldb_message_sort(msg, ar->schema);
3471 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3472 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3476 ret = ldb_build_add_req(&change_req,
3482 replmd_op_add_callback,
3484 LDB_REQ_SET_LOCATION(change_req);
3485 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3487 /* current partition control needed by "repmd_op_callback" */
3488 ret = ldb_request_add_control(change_req,
3489 DSDB_CONTROL_CURRENT_PARTITION_OID,
3491 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3493 return ldb_next_request(ar->module, change_req);
3497 handle renames that come in over DRS replication
3499 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
3500 struct ldb_message *msg,
3501 struct replPropertyMetaDataBlob *rmd,
3502 struct replPropertyMetaDataBlob *omd,
3503 struct ldb_request *parent)
3505 struct replPropertyMetaData1 *md_remote;
3506 struct replPropertyMetaData1 *md_local;
3508 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3513 /* now we need to check for double renames. We could have a
3514 * local rename pending which our replication partner hasn't
3515 * received yet. We choose which one wins by looking at the
3516 * attribute stamps on the two objects, the newer one wins
3518 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3519 md_local = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3520 /* if there is no name attribute then we have to assume the
3521 object we've received is in fact newer */
3522 if (!md_remote || !md_local ||
3523 replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3524 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3525 ldb_dn_get_linearized(ar->search_msg->dn),
3526 ldb_dn_get_linearized(msg->dn)));
3527 /* pass rename to the next module
3528 * so it doesn't appear as an originating update */
3529 return dsdb_module_rename(ar->module,
3530 ar->search_msg->dn, msg->dn,
3531 DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX, parent);
3534 /* we're going to keep our old object */
3535 DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
3536 ldb_dn_get_linearized(ar->search_msg->dn),
3537 ldb_dn_get_linearized(msg->dn)));
3542 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
3544 struct ldb_context *ldb;
3545 struct ldb_request *change_req;
3546 enum ndr_err_code ndr_err;
3547 struct ldb_message *msg;
3548 struct replPropertyMetaDataBlob *rmd;
3549 struct replPropertyMetaDataBlob omd;
3550 const struct ldb_val *omd_value;
3551 struct replPropertyMetaDataBlob nmd;
3552 struct ldb_val nmd_value;
3555 unsigned int removed_attrs = 0;
3558 ldb = ldb_module_get_ctx(ar->module);
3559 msg = ar->objs->objects[ar->index_current].msg;
3560 rmd = ar->objs->objects[ar->index_current].meta_data;
3564 /* find existing meta data */
3565 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
3567 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
3568 (ndr_pull_flags_fn_t)ndr_pull_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));
3574 if (omd.version != 1) {
3575 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3579 /* handle renames that come in over DRS */
3580 ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
3581 if (ret != LDB_SUCCESS) {
3582 ldb_debug(ldb, LDB_DEBUG_FATAL,
3583 "replmd_replicated_request rename %s => %s failed - %s\n",
3584 ldb_dn_get_linearized(ar->search_msg->dn),
3585 ldb_dn_get_linearized(msg->dn),
3586 ldb_errstring(ldb));
3587 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
3592 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
3593 nmd.ctr.ctr1.array = talloc_array(ar,
3594 struct replPropertyMetaData1,
3595 nmd.ctr.ctr1.count);
3596 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3598 /* first copy the old meta data */
3599 for (i=0; i < omd.ctr.ctr1.count; i++) {
3600 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
3605 /* now merge in the new meta data */
3606 for (i=0; i < rmd->ctr.ctr1.count; i++) {
3609 for (j=0; j < ni; j++) {
3612 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
3616 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
3617 &rmd->ctr.ctr1.array[i]);
3619 /* replace the entry */
3620 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
3621 if (ar->seq_num == 0) {
3622 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3623 if (ret != LDB_SUCCESS) {
3624 return replmd_replicated_request_error(ar, ret);
3627 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
3632 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
3633 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
3634 msg->elements[i-removed_attrs].name,
3635 ldb_dn_get_linearized(msg->dn),
3636 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
3639 /* we don't want to apply this change so remove the attribute */
3640 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
3647 if (found) continue;
3649 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
3650 if (ar->seq_num == 0) {
3651 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3652 if (ret != LDB_SUCCESS) {
3653 return replmd_replicated_request_error(ar, ret);
3656 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
3661 * finally correct the size of the meta_data array
3663 nmd.ctr.ctr1.count = ni;
3666 * the rdn attribute (the alias for the name attribute),
3667 * 'cn' for most objects is the last entry in the meta data array
3670 * sort the new meta data array
3672 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
3673 if (ret != LDB_SUCCESS) {
3678 * check if some replicated attributes left, otherwise skip the ldb_modify() call
3680 if (msg->num_elements == 0) {
3681 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
3684 ar->index_current++;
3685 return replmd_replicated_apply_next(ar);
3688 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
3689 ar->index_current, msg->num_elements);
3691 /* create the meta data value */
3692 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
3693 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3694 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3695 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3696 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3700 * when we know that we'll modify the record, add the whenChanged, uSNChanged
3701 * and replPopertyMetaData attributes
3703 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3704 if (ret != LDB_SUCCESS) {
3705 return replmd_replicated_request_error(ar, ret);
3707 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3708 if (ret != LDB_SUCCESS) {
3709 return replmd_replicated_request_error(ar, ret);
3711 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
3712 if (ret != LDB_SUCCESS) {
3713 return replmd_replicated_request_error(ar, ret);
3716 replmd_ldb_message_sort(msg, ar->schema);
3718 /* we want to replace the old values */
3719 for (i=0; i < msg->num_elements; i++) {
3720 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3724 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3725 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
3729 ret = ldb_build_mod_req(&change_req,
3737 LDB_REQ_SET_LOCATION(change_req);
3738 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3740 /* current partition control needed by "repmd_op_callback" */
3741 ret = ldb_request_add_control(change_req,
3742 DSDB_CONTROL_CURRENT_PARTITION_OID,
3744 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3746 return ldb_next_request(ar->module, change_req);
3749 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
3750 struct ldb_reply *ares)
3752 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3753 struct replmd_replicated_request);
3757 return ldb_module_done(ar->req, NULL, NULL,
3758 LDB_ERR_OPERATIONS_ERROR);
3760 if (ares->error != LDB_SUCCESS &&
3761 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3762 return ldb_module_done(ar->req, ares->controls,
3763 ares->response, ares->error);
3766 switch (ares->type) {
3767 case LDB_REPLY_ENTRY:
3768 ar->search_msg = talloc_steal(ar, ares->message);
3771 case LDB_REPLY_REFERRAL:
3772 /* we ignore referrals */
3775 case LDB_REPLY_DONE:
3776 if (ar->search_msg != NULL) {
3777 ret = replmd_replicated_apply_merge(ar);
3779 ret = replmd_replicated_apply_add(ar);
3781 if (ret != LDB_SUCCESS) {
3782 return ldb_module_done(ar->req, NULL, NULL, ret);
3790 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3792 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3794 struct ldb_context *ldb;
3798 struct ldb_request *search_req;
3799 struct ldb_search_options_control *options;
3801 if (ar->index_current >= ar->objs->num_objects) {
3802 /* done with it, go to next stage */
3803 return replmd_replicated_uptodate_vector(ar);
3806 ldb = ldb_module_get_ctx(ar->module);
3807 ar->search_msg = NULL;
3809 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3810 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3812 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3813 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3814 talloc_free(tmp_str);
3816 ret = ldb_build_search_req(&search_req,
3825 replmd_replicated_apply_search_callback,
3827 LDB_REQ_SET_LOCATION(search_req);
3829 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
3831 if (ret != LDB_SUCCESS) {
3835 /* we need to cope with cross-partition links, so search for
3836 the GUID over all partitions */
3837 options = talloc(search_req, struct ldb_search_options_control);
3838 if (options == NULL) {
3839 DEBUG(0, (__location__ ": out of memory\n"));
3840 return LDB_ERR_OPERATIONS_ERROR;
3842 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3844 ret = ldb_request_add_control(search_req,
3845 LDB_CONTROL_SEARCH_OPTIONS_OID,
3847 if (ret != LDB_SUCCESS) {
3851 return ldb_next_request(ar->module, search_req);
3854 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
3855 struct ldb_reply *ares)
3857 struct ldb_context *ldb;
3858 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3859 struct replmd_replicated_request);
3860 ldb = ldb_module_get_ctx(ar->module);
3863 return ldb_module_done(ar->req, NULL, NULL,
3864 LDB_ERR_OPERATIONS_ERROR);
3866 if (ares->error != LDB_SUCCESS) {
3867 return ldb_module_done(ar->req, ares->controls,
3868 ares->response, ares->error);
3871 if (ares->type != LDB_REPLY_DONE) {
3872 ldb_set_errstring(ldb, "Invalid reply type\n!");
3873 return ldb_module_done(ar->req, NULL, NULL,
3874 LDB_ERR_OPERATIONS_ERROR);
3879 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3882 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3884 struct ldb_context *ldb;
3885 struct ldb_request *change_req;
3886 enum ndr_err_code ndr_err;
3887 struct ldb_message *msg;
3888 struct replUpToDateVectorBlob ouv;
3889 const struct ldb_val *ouv_value;
3890 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3891 struct replUpToDateVectorBlob nuv;
3892 struct ldb_val nuv_value;
3893 struct ldb_message_element *nuv_el = NULL;
3894 const struct GUID *our_invocation_id;
3895 struct ldb_message_element *orf_el = NULL;
3896 struct repsFromToBlob nrf;
3897 struct ldb_val *nrf_value = NULL;
3898 struct ldb_message_element *nrf_el = NULL;
3902 time_t t = time(NULL);
3905 uint32_t instanceType;
3907 ldb = ldb_module_get_ctx(ar->module);
3908 ruv = ar->objs->uptodateness_vector;
3914 unix_to_nt_time(&now, t);
3916 instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
3917 if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
3918 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
3919 ldb_dn_get_linearized(ar->search_msg->dn)));
3920 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3924 * first create the new replUpToDateVector
3926 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
3928 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
3929 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3930 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3931 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3932 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3935 if (ouv.version != 2) {
3936 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3941 * the new uptodateness vector will at least
3942 * contain 1 entry, one for the source_dsa
3944 * plus optional values from our old vector and the one from the source_dsa
3946 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
3947 if (ruv) nuv.ctr.ctr2.count += ruv->count;
3948 nuv.ctr.ctr2.cursors = talloc_array(ar,
3949 struct drsuapi_DsReplicaCursor2,
3950 nuv.ctr.ctr2.count);
3951 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3953 /* first copy the old vector */
3954 for (i=0; i < ouv.ctr.ctr2.count; i++) {
3955 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
3959 /* get our invocation_id if we have one already attached to the ldb */
3960 our_invocation_id = samdb_ntds_invocation_id(ldb);
3962 /* merge in the source_dsa vector is available */
3963 for (i=0; (ruv && i < ruv->count); i++) {
3966 if (our_invocation_id &&
3967 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3968 our_invocation_id)) {
3972 for (j=0; j < ni; j++) {
3973 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3974 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3981 * we update only the highest_usn and not the latest_sync_success time,
3982 * because the last success stands for direct replication
3984 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3985 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3990 if (found) continue;
3992 /* if it's not there yet, add it */
3993 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3998 * merge in the current highwatermark for the source_dsa
4001 for (j=0; j < ni; j++) {
4002 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
4003 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4010 * here we update the highest_usn and last_sync_success time
4011 * because we're directly replicating from the source_dsa
4013 * and use the tmp_highest_usn because this is what we have just applied
4016 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4017 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
4022 * here we update the highest_usn and last_sync_success time
4023 * because we're directly replicating from the source_dsa
4025 * and use the tmp_highest_usn because this is what we have just applied
4028 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
4029 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4030 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
4035 * finally correct the size of the cursors array
4037 nuv.ctr.ctr2.count = ni;
4042 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
4045 * create the change ldb_message
4047 msg = ldb_msg_new(ar);
4048 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4049 msg->dn = ar->search_msg->dn;
4051 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
4052 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
4053 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4054 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4055 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4057 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
4058 if (ret != LDB_SUCCESS) {
4059 return replmd_replicated_request_error(ar, ret);
4061 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
4064 * now create the new repsFrom value from the given repsFromTo1 structure
4068 nrf.ctr.ctr1 = *ar->objs->source_dsa;
4069 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
4072 * first see if we already have a repsFrom value for the current source dsa
4073 * if so we'll later replace this value
4075 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
4077 for (i=0; i < orf_el->num_values; i++) {
4078 struct repsFromToBlob *trf;
4080 trf = talloc(ar, struct repsFromToBlob);
4081 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4083 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
4084 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
4085 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4086 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4087 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4090 if (trf->version != 1) {
4091 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4095 * we compare the source dsa objectGUID not the invocation_id
4096 * because we want only one repsFrom value per source dsa
4097 * and when the invocation_id of the source dsa has changed we don't need
4098 * the old repsFrom with the old invocation_id
4100 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
4101 &ar->objs->source_dsa->source_dsa_obj_guid)) {
4107 nrf_value = &orf_el->values[i];
4112 * copy over all old values to the new ldb_message
4114 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
4115 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4120 * if we haven't found an old repsFrom value for the current source dsa
4121 * we'll add a new value
4124 struct ldb_val zero_value;
4125 ZERO_STRUCT(zero_value);
4126 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
4127 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4129 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
4132 /* we now fill the value which is already attached to ldb_message */
4133 ndr_err = ndr_push_struct_blob(nrf_value, msg,
4135 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
4136 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4137 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4138 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4142 * the ldb_message_element for the attribute, has all the old values and the new one
4143 * so we'll replace the whole attribute with all values
4145 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
4148 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4149 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
4153 /* prepare the ldb_modify() request */
4154 ret = ldb_build_mod_req(&change_req,
4160 replmd_replicated_uptodate_modify_callback,
4162 LDB_REQ_SET_LOCATION(change_req);
4163 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4165 return ldb_next_request(ar->module, change_req);
4168 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
4169 struct ldb_reply *ares)
4171 struct replmd_replicated_request *ar = talloc_get_type(req->context,
4172 struct replmd_replicated_request);
4176 return ldb_module_done(ar->req, NULL, NULL,
4177 LDB_ERR_OPERATIONS_ERROR);
4179 if (ares->error != LDB_SUCCESS &&
4180 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4181 return ldb_module_done(ar->req, ares->controls,
4182 ares->response, ares->error);
4185 switch (ares->type) {
4186 case LDB_REPLY_ENTRY:
4187 ar->search_msg = talloc_steal(ar, ares->message);
4190 case LDB_REPLY_REFERRAL:
4191 /* we ignore referrals */
4194 case LDB_REPLY_DONE:
4195 if (ar->search_msg == NULL) {
4196 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4198 ret = replmd_replicated_uptodate_modify(ar);
4200 if (ret != LDB_SUCCESS) {
4201 return ldb_module_done(ar->req, NULL, NULL, ret);
4210 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
4212 struct ldb_context *ldb;
4214 static const char *attrs[] = {
4215 "replUpToDateVector",
4220 struct ldb_request *search_req;
4222 ldb = ldb_module_get_ctx(ar->module);
4223 ar->search_msg = NULL;
4225 ret = ldb_build_search_req(&search_req,
4228 ar->objs->partition_dn,
4234 replmd_replicated_uptodate_search_callback,
4236 LDB_REQ_SET_LOCATION(search_req);
4237 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4239 return ldb_next_request(ar->module, search_req);
4244 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
4246 struct ldb_context *ldb;
4247 struct dsdb_extended_replicated_objects *objs;
4248 struct replmd_replicated_request *ar;
4249 struct ldb_control **ctrls;
4252 struct replmd_private *replmd_private =
4253 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4255 ldb = ldb_module_get_ctx(module);
4257 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
4259 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
4261 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
4262 return LDB_ERR_PROTOCOL_ERROR;
4265 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
4266 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
4267 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
4268 return LDB_ERR_PROTOCOL_ERROR;
4271 ar = replmd_ctx_init(module, req);
4273 return LDB_ERR_OPERATIONS_ERROR;
4275 /* Set the flags to have the replmd_op_callback run over the full set of objects */
4276 ar->apply_mode = true;
4278 ar->schema = dsdb_get_schema(ldb, ar);
4280 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
4282 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4283 return LDB_ERR_CONSTRAINT_VIOLATION;
4286 ctrls = req->controls;
4288 if (req->controls) {
4289 req->controls = talloc_memdup(ar, req->controls,
4290 talloc_get_size(req->controls));
4291 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4294 /* This allows layers further down to know if a change came in over replication */
4295 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
4296 if (ret != LDB_SUCCESS) {
4300 /* If this change contained linked attributes in the body
4301 * (rather than in the links section) we need to update
4302 * backlinks in linked_attributes */
4303 ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
4304 if (ret != LDB_SUCCESS) {
4308 ar->controls = req->controls;
4309 req->controls = ctrls;
4311 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
4313 /* save away the linked attributes for the end of the
4315 for (i=0; i<ar->objs->linked_attributes_count; i++) {
4316 struct la_entry *la_entry;
4318 if (replmd_private->la_ctx == NULL) {
4319 replmd_private->la_ctx = talloc_new(replmd_private);
4321 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
4322 if (la_entry == NULL) {
4324 return LDB_ERR_OPERATIONS_ERROR;
4326 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
4327 if (la_entry->la == NULL) {
4328 talloc_free(la_entry);
4330 return LDB_ERR_OPERATIONS_ERROR;
4332 *la_entry->la = ar->objs->linked_attributes[i];
4334 /* we need to steal the non-scalars so they stay
4335 around until the end of the transaction */
4336 talloc_steal(la_entry->la, la_entry->la->identifier);
4337 talloc_steal(la_entry->la, la_entry->la->value.blob);
4339 DLIST_ADD(replmd_private->la_list, la_entry);
4342 return replmd_replicated_apply_next(ar);
4346 process one linked attribute structure
4348 static int replmd_process_linked_attribute(struct ldb_module *module,
4349 struct la_entry *la_entry,
4350 struct ldb_request *parent)
4352 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
4353 struct ldb_context *ldb = ldb_module_get_ctx(module);
4354 struct ldb_message *msg;
4355 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
4356 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
4358 const struct dsdb_attribute *attr;
4359 struct dsdb_dn *dsdb_dn;
4360 uint64_t seq_num = 0;
4361 struct ldb_message_element *old_el;
4363 time_t t = time(NULL);
4364 struct ldb_result *res;
4365 const char *attrs[2];
4366 struct parsed_dn *pdn_list, *pdn;
4367 struct GUID guid = GUID_zero();
4369 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
4370 const struct GUID *our_invocation_id;
4373 linked_attributes[0]:
4374 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
4376 identifier: struct drsuapi_DsReplicaObjectIdentifier
4377 __ndr_size : 0x0000003a (58)
4378 __ndr_size_sid : 0x00000000 (0)
4379 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
4381 __ndr_size_dn : 0x00000000 (0)
4383 attid : DRSUAPI_ATTID_member (0x1F)
4384 value: struct drsuapi_DsAttributeValue
4385 __ndr_size : 0x0000007e (126)
4387 blob : DATA_BLOB length=126
4388 flags : 0x00000001 (1)
4389 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
4390 originating_add_time : Wed Sep 2 22:20:01 2009 EST
4391 meta_data: struct drsuapi_DsReplicaMetaData
4392 version : 0x00000015 (21)
4393 originating_change_time : Wed Sep 2 23:39:07 2009 EST
4394 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
4395 originating_usn : 0x000000000001e19c (123292)
4397 (for cases where the link is to a normal DN)
4398 &target: struct drsuapi_DsReplicaObjectIdentifier3
4399 __ndr_size : 0x0000007e (126)
4400 __ndr_size_sid : 0x0000001c (28)
4401 guid : 7639e594-db75-4086-b0d4-67890ae46031
4402 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
4403 __ndr_size_dn : 0x00000022 (34)
4404 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
4407 /* find the attribute being modified */
4408 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
4410 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
4411 talloc_free(tmp_ctx);
4412 return LDB_ERR_OPERATIONS_ERROR;
4415 attrs[0] = attr->lDAPDisplayName;
4418 /* get the existing message from the db for the object with
4419 this GUID, returning attribute being modified. We will then
4420 use this msg as the basis for a modify call */
4421 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
4422 DSDB_FLAG_NEXT_MODULE |
4423 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
4424 DSDB_SEARCH_SHOW_RECYCLED |
4425 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4426 DSDB_SEARCH_REVEAL_INTERNALS,
4428 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
4429 if (ret != LDB_SUCCESS) {
4430 talloc_free(tmp_ctx);
4433 if (res->count != 1) {
4434 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
4435 GUID_string(tmp_ctx, &la->identifier->guid));
4436 talloc_free(tmp_ctx);
4437 return LDB_ERR_NO_SUCH_OBJECT;
4441 if (msg->num_elements == 0) {
4442 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
4443 if (ret != LDB_SUCCESS) {
4444 ldb_module_oom(module);
4445 talloc_free(tmp_ctx);
4446 return LDB_ERR_OPERATIONS_ERROR;
4449 old_el = &msg->elements[0];
4450 old_el->flags = LDB_FLAG_MOD_REPLACE;
4453 /* parse the existing links */
4454 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
4455 if (ret != LDB_SUCCESS) {
4456 talloc_free(tmp_ctx);
4460 /* get our invocationId */
4461 our_invocation_id = samdb_ntds_invocation_id(ldb);
4462 if (!our_invocation_id) {
4463 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
4464 talloc_free(tmp_ctx);
4465 return LDB_ERR_OPERATIONS_ERROR;
4468 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
4469 if (ret != LDB_SUCCESS) {
4470 talloc_free(tmp_ctx);
4474 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
4475 if (!W_ERROR_IS_OK(status)) {
4476 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
4477 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
4478 return LDB_ERR_OPERATIONS_ERROR;
4481 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
4482 if (!NT_STATUS_IS_OK(ntstatus) && active) {
4483 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
4485 ldb_dn_get_linearized(dsdb_dn->dn),
4486 ldb_dn_get_linearized(msg->dn));
4487 return LDB_ERR_OPERATIONS_ERROR;
4490 /* re-resolve the DN by GUID, as the DRS server may give us an
4492 ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
4493 if (ret != LDB_SUCCESS) {
4494 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s",
4495 GUID_string(tmp_ctx, &guid),
4496 ldb_dn_get_linearized(dsdb_dn->dn)));
4499 /* see if this link already exists */
4500 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
4502 /* see if this update is newer than what we have already */
4503 struct GUID invocation_id = GUID_zero();
4504 uint32_t version = 0;
4505 uint32_t originating_usn = 0;
4506 NTTIME change_time = 0;
4507 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
4509 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
4510 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
4511 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
4512 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
4514 if (!replmd_update_is_newer(&invocation_id,
4515 &la->meta_data.originating_invocation_id,
4517 la->meta_data.version,
4519 la->meta_data.originating_change_time)) {
4520 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
4521 old_el->name, ldb_dn_get_linearized(msg->dn),
4522 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
4523 talloc_free(tmp_ctx);
4527 /* get a seq_num for this change */
4528 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4529 if (ret != LDB_SUCCESS) {
4530 talloc_free(tmp_ctx);
4534 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
4535 /* remove the existing backlink */
4536 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
4537 if (ret != LDB_SUCCESS) {
4538 talloc_free(tmp_ctx);
4543 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
4544 &la->meta_data.originating_invocation_id,
4545 la->meta_data.originating_usn, seq_num,
4546 la->meta_data.originating_change_time,
4547 la->meta_data.version,
4549 if (ret != LDB_SUCCESS) {
4550 talloc_free(tmp_ctx);
4555 /* add the new backlink */
4556 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
4557 if (ret != LDB_SUCCESS) {
4558 talloc_free(tmp_ctx);
4563 /* get a seq_num for this change */
4564 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4565 if (ret != LDB_SUCCESS) {
4566 talloc_free(tmp_ctx);
4570 old_el->values = talloc_realloc(msg->elements, old_el->values,
4571 struct ldb_val, old_el->num_values+1);
4572 if (!old_el->values) {
4573 ldb_module_oom(module);
4574 return LDB_ERR_OPERATIONS_ERROR;
4576 old_el->num_values++;
4578 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
4579 &la->meta_data.originating_invocation_id,
4580 la->meta_data.originating_usn, seq_num,
4581 la->meta_data.originating_change_time,
4582 la->meta_data.version,
4583 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
4584 if (ret != LDB_SUCCESS) {
4585 talloc_free(tmp_ctx);
4590 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
4592 if (ret != LDB_SUCCESS) {
4593 talloc_free(tmp_ctx);
4599 /* we only change whenChanged and uSNChanged if the seq_num
4601 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
4602 talloc_free(tmp_ctx);
4603 return ldb_operr(ldb);
4606 if (add_uint64_element(ldb, msg, "uSNChanged",
4607 seq_num) != LDB_SUCCESS) {
4608 talloc_free(tmp_ctx);
4609 return ldb_operr(ldb);
4612 old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
4613 if (old_el == NULL) {
4614 talloc_free(tmp_ctx);
4615 return ldb_operr(ldb);
4618 ret = dsdb_check_single_valued_link(attr, old_el);
4619 if (ret != LDB_SUCCESS) {
4620 talloc_free(tmp_ctx);
4624 old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
4626 ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
4627 if (ret != LDB_SUCCESS) {
4628 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
4630 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
4631 talloc_free(tmp_ctx);
4635 talloc_free(tmp_ctx);
4640 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
4642 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
4643 return replmd_extended_replicated_objects(module, req);
4646 return ldb_next_request(module, req);
4651 we hook into the transaction operations to allow us to
4652 perform the linked attribute updates at the end of the whole
4653 transaction. This allows a forward linked attribute to be created
4654 before the object is created. During a vampire, w2k8 sends us linked
4655 attributes before the objects they are part of.
4657 static int replmd_start_transaction(struct ldb_module *module)
4659 /* create our private structure for this transaction */
4660 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
4661 struct replmd_private);
4662 replmd_txn_cleanup(replmd_private);
4664 /* free any leftover mod_usn records from cancelled
4666 while (replmd_private->ncs) {
4667 struct nc_entry *e = replmd_private->ncs;
4668 DLIST_REMOVE(replmd_private->ncs, e);
4672 return ldb_next_start_trans(module);
4676 on prepare commit we loop over our queued la_context structures and
4679 static int replmd_prepare_commit(struct ldb_module *module)
4681 struct replmd_private *replmd_private =
4682 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4683 struct la_entry *la, *prev;
4684 struct la_backlink *bl;
4687 /* walk the list backwards, to do the first entry first, as we
4688 * added the entries with DLIST_ADD() which puts them at the
4689 * start of the list */
4690 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
4691 prev = DLIST_PREV(la);
4692 DLIST_REMOVE(replmd_private->la_list, la);
4693 ret = replmd_process_linked_attribute(module, la, NULL);
4694 if (ret != LDB_SUCCESS) {
4695 replmd_txn_cleanup(replmd_private);
4700 /* process our backlink list, creating and deleting backlinks
4702 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
4703 ret = replmd_process_backlink(module, bl, NULL);
4704 if (ret != LDB_SUCCESS) {
4705 replmd_txn_cleanup(replmd_private);
4710 replmd_txn_cleanup(replmd_private);
4712 /* possibly change @REPLCHANGED */
4713 ret = replmd_notify_store(module, NULL);
4714 if (ret != LDB_SUCCESS) {
4718 return ldb_next_prepare_commit(module);
4721 static int replmd_del_transaction(struct ldb_module *module)
4723 struct replmd_private *replmd_private =
4724 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4725 replmd_txn_cleanup(replmd_private);
4727 return ldb_next_del_trans(module);
4731 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
4732 .name = "repl_meta_data",
4733 .init_context = replmd_init,
4735 .modify = replmd_modify,
4736 .rename = replmd_rename,
4737 .del = replmd_delete,
4738 .extended = replmd_extended,
4739 .start_transaction = replmd_start_transaction,
4740 .prepare_commit = replmd_prepare_commit,
4741 .del_transaction = replmd_del_transaction,
4744 int ldb_repl_meta_data_module_init(const char *version)
4746 LDB_MODULE_CHECK_VERSION(version);
4747 return ldb_register_module(&ldb_repl_meta_data_module_ops);