4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * Component: ldb repl_meta_data module
28 * Description: - add a unique objectGUID onto every new record,
29 * - handle whenCreated, whenChanged timestamps
30 * - handle uSNCreated, uSNChanged numbers
31 * - handle replPropertyMetaData attribute
34 * Author: Stefan Metzmacher
38 #include "ldb_module.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "dsdb/common/proto.h"
41 #include "../libds/common/flags.h"
42 #include "librpc/gen_ndr/ndr_misc.h"
43 #include "librpc/gen_ndr/ndr_drsuapi.h"
44 #include "librpc/gen_ndr/ndr_drsblobs.h"
45 #include "param/param.h"
46 #include "libcli/security/dom_sid.h"
47 #include "lib/util/dlinklist.h"
48 #include "dsdb/samdb/ldb_modules/util.h"
49 #include "lib/util/binsearch.h"
50 #include "libcli/security/security.h"
52 #define W2K3_LINKED_ATTRIBUTES 1
54 struct replmd_private {
56 struct la_entry *la_list;
58 struct la_backlink *la_backlinks;
60 struct nc_entry *prev, *next;
63 uint64_t mod_usn_urgent;
68 struct la_entry *next, *prev;
69 struct drsuapi_DsReplicaLinkedAttribute *la;
72 struct replmd_replicated_request {
73 struct ldb_module *module;
74 struct ldb_request *req;
76 const struct dsdb_schema *schema;
78 /* the controls we pass down */
79 struct ldb_control **controls;
81 /* details for the mode where we apply a bunch of inbound replication meessages */
83 uint32_t index_current;
84 struct dsdb_extended_replicated_objects *objs;
86 struct ldb_message *search_msg;
92 enum urgent_situation {
93 REPL_URGENT_ON_CREATE = 1,
94 REPL_URGENT_ON_UPDATE = 3, /* activated on creating as well*/
95 REPL_URGENT_ON_DELETE = 4
100 const char *update_name;
101 enum urgent_situation repl_situation;
102 } urgent_objects[] = {
103 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
104 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
105 {"attributeSchema", REPL_URGENT_ON_UPDATE},
106 {"classSchema", REPL_URGENT_ON_UPDATE},
107 {"secret", REPL_URGENT_ON_UPDATE},
108 {"rIDManager", REPL_URGENT_ON_UPDATE},
112 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
113 static const char *urgent_attrs[] = {
116 "userAccountControl",
121 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
122 enum urgent_situation situation)
125 for (i=0; urgent_objects[i].update_name; i++) {
127 if ((situation & urgent_objects[i].repl_situation) == 0) {
131 for (j=0; j<objectclass_el->num_values; j++) {
132 const struct ldb_val *v = &objectclass_el->values[j];
133 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
141 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
143 if (ldb_attr_in_list(urgent_attrs, el->name)) {
150 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
153 initialise the module
154 allocate the private structure and build the list
155 of partition DNs for use by replmd_notify()
157 static int replmd_init(struct ldb_module *module)
159 struct replmd_private *replmd_private;
160 struct ldb_context *ldb = ldb_module_get_ctx(module);
162 replmd_private = talloc_zero(module, struct replmd_private);
163 if (replmd_private == NULL) {
165 return LDB_ERR_OPERATIONS_ERROR;
167 ldb_module_set_private(module, replmd_private);
169 return ldb_next_init(module);
173 cleanup our per-transaction contexts
175 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
177 talloc_free(replmd_private->la_ctx);
178 replmd_private->la_list = NULL;
179 replmd_private->la_ctx = NULL;
181 talloc_free(replmd_private->bl_ctx);
182 replmd_private->la_backlinks = NULL;
183 replmd_private->bl_ctx = NULL;
188 struct la_backlink *next, *prev;
189 const char *attr_name;
190 struct GUID forward_guid, target_guid;
195 process a backlinks we accumulated during a transaction, adding and
196 deleting the backlinks from the target objects
198 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl)
200 struct ldb_dn *target_dn, *source_dn;
202 struct ldb_context *ldb = ldb_module_get_ctx(module);
203 struct ldb_message *msg;
204 TALLOC_CTX *tmp_ctx = talloc_new(bl);
210 - construct ldb_message
211 - either an add or a delete
213 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn);
214 if (ret != LDB_SUCCESS) {
215 ldb_asprintf_errstring(ldb, "Failed to find target DN for linked attribute with GUID %s\n",
216 GUID_string(bl, &bl->target_guid));
217 talloc_free(tmp_ctx);
221 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn);
222 if (ret != LDB_SUCCESS) {
223 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
224 GUID_string(bl, &bl->forward_guid));
225 talloc_free(tmp_ctx);
229 msg = ldb_msg_new(tmp_ctx);
231 ldb_module_oom(module);
232 talloc_free(tmp_ctx);
233 return LDB_ERR_OPERATIONS_ERROR;
236 /* construct a ldb_message for adding/deleting the backlink */
238 dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
240 ldb_module_oom(module);
241 talloc_free(tmp_ctx);
242 return LDB_ERR_OPERATIONS_ERROR;
244 ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
245 if (ret != LDB_SUCCESS) {
246 talloc_free(tmp_ctx);
249 msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
251 ret = dsdb_module_modify(module, msg, 0);
252 if (ret != LDB_SUCCESS) {
253 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
254 bl->active?"add":"remove",
255 ldb_dn_get_linearized(source_dn),
256 ldb_dn_get_linearized(target_dn),
258 talloc_free(tmp_ctx);
261 talloc_free(tmp_ctx);
266 add a backlink to the list of backlinks to add/delete in the prepare
269 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
270 struct GUID *forward_guid, struct GUID *target_guid,
271 bool active, const struct dsdb_attribute *schema_attr, bool immediate)
273 const struct dsdb_attribute *target_attr;
274 struct la_backlink *bl;
275 struct replmd_private *replmd_private =
276 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
278 target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
281 * windows 2003 has a broken schema where the
282 * definition of msDS-IsDomainFor is missing (which is
283 * supposed to be the backlink of the
284 * msDS-HasDomainNCs attribute
289 /* see if its already in the list */
290 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
291 if (GUID_equal(forward_guid, &bl->forward_guid) &&
292 GUID_equal(target_guid, &bl->target_guid) &&
293 (target_attr->lDAPDisplayName == bl->attr_name ||
294 strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
300 /* we found an existing one */
301 if (bl->active == active) {
304 DLIST_REMOVE(replmd_private->la_backlinks, bl);
309 if (replmd_private->bl_ctx == NULL) {
310 replmd_private->bl_ctx = talloc_new(replmd_private);
311 if (replmd_private->bl_ctx == NULL) {
312 ldb_module_oom(module);
313 return LDB_ERR_OPERATIONS_ERROR;
318 bl = talloc(replmd_private->bl_ctx, struct la_backlink);
320 ldb_module_oom(module);
321 return LDB_ERR_OPERATIONS_ERROR;
324 bl->attr_name = target_attr->lDAPDisplayName;
325 bl->forward_guid = *forward_guid;
326 bl->target_guid = *target_guid;
329 /* the caller may ask for this backlink to be processed
332 int ret = replmd_process_backlink(module, bl);
337 DLIST_ADD(replmd_private->la_backlinks, bl);
344 * Callback for most write operations in this module:
346 * notify the repl task that a object has changed. The notifies are
347 * gathered up in the replmd_private structure then written to the
348 * @REPLCHANGED object in each partition during the prepare_commit
350 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
353 struct replmd_replicated_request *ac =
354 talloc_get_type_abort(req->context, struct replmd_replicated_request);
355 struct replmd_private *replmd_private =
356 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
357 struct nc_entry *modified_partition;
358 struct ldb_control *partition_ctrl;
359 const struct dsdb_control_current_partition *partition;
361 struct ldb_control **controls;
363 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
365 /* Remove the 'partition' control from what we pass up the chain */
366 controls = controls_except_specified(ares->controls, ares, partition_ctrl);
368 if (ares->error != LDB_SUCCESS) {
369 return ldb_module_done(ac->req, controls,
370 ares->response, ares->error);
373 if (ares->type != LDB_REPLY_DONE) {
374 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
375 return ldb_module_done(ac->req, NULL,
376 NULL, LDB_ERR_OPERATIONS_ERROR);
379 if (!partition_ctrl) {
380 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
381 return ldb_module_done(ac->req, NULL,
382 NULL, LDB_ERR_OPERATIONS_ERROR);
385 partition = talloc_get_type_abort(partition_ctrl->data,
386 struct dsdb_control_current_partition);
388 if (ac->seq_num > 0) {
389 for (modified_partition = replmd_private->ncs; modified_partition;
390 modified_partition = modified_partition->next) {
391 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
396 if (modified_partition == NULL) {
397 modified_partition = talloc_zero(replmd_private, struct nc_entry);
398 if (!modified_partition) {
399 ldb_oom(ldb_module_get_ctx(ac->module));
400 return ldb_module_done(ac->req, NULL,
401 NULL, LDB_ERR_OPERATIONS_ERROR);
403 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
404 if (!modified_partition->dn) {
405 ldb_oom(ldb_module_get_ctx(ac->module));
406 return ldb_module_done(ac->req, NULL,
407 NULL, LDB_ERR_OPERATIONS_ERROR);
409 DLIST_ADD(replmd_private->ncs, modified_partition);
412 if (ac->seq_num > modified_partition->mod_usn) {
413 modified_partition->mod_usn = ac->seq_num;
415 modified_partition->mod_usn_urgent = ac->seq_num;
420 if (ac->apply_mode) {
424 ret = replmd_replicated_apply_next(ac);
425 if (ret != LDB_SUCCESS) {
426 return ldb_module_done(ac->req, NULL, NULL, ret);
430 /* free the partition control container here, for the
431 * common path. Other cases will have it cleaned up
432 * eventually with the ares */
433 talloc_free(partition_ctrl);
434 return ldb_module_done(ac->req,
435 controls_except_specified(controls, ares, partition_ctrl),
436 ares->response, LDB_SUCCESS);
442 * update a @REPLCHANGED record in each partition if there have been
443 * any writes of replicated data in the partition
445 static int replmd_notify_store(struct ldb_module *module)
447 struct replmd_private *replmd_private =
448 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
449 struct ldb_context *ldb = ldb_module_get_ctx(module);
451 while (replmd_private->ncs) {
453 struct nc_entry *modified_partition = replmd_private->ncs;
455 ret = dsdb_save_partition_usn(ldb, modified_partition->dn,
456 modified_partition->mod_usn,
457 modified_partition->mod_usn_urgent);
458 if (ret != LDB_SUCCESS) {
459 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
460 ldb_dn_get_linearized(modified_partition->dn)));
463 DLIST_REMOVE(replmd_private->ncs, modified_partition);
464 talloc_free(modified_partition);
472 created a replmd_replicated_request context
474 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
475 struct ldb_request *req)
477 struct ldb_context *ldb;
478 struct replmd_replicated_request *ac;
480 ldb = ldb_module_get_ctx(module);
482 ac = talloc_zero(req, struct replmd_replicated_request);
491 ac->schema = dsdb_get_schema(ldb);
493 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
494 "replmd_modify: no dsdb_schema loaded");
495 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
503 add a time element to a record
505 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
507 struct ldb_message_element *el;
510 if (ldb_msg_find_element(msg, attr) != NULL) {
514 s = ldb_timestring(msg, t);
516 return LDB_ERR_OPERATIONS_ERROR;
519 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
520 return LDB_ERR_OPERATIONS_ERROR;
523 el = ldb_msg_find_element(msg, attr);
524 /* always set as replace. This works because on add ops, the flag
526 el->flags = LDB_FLAG_MOD_REPLACE;
532 add a uint64_t element to a record
534 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
536 struct ldb_message_element *el;
538 if (ldb_msg_find_element(msg, attr) != NULL) {
542 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
543 return LDB_ERR_OPERATIONS_ERROR;
546 el = ldb_msg_find_element(msg, attr);
547 /* always set as replace. This works because on add ops, the flag
549 el->flags = LDB_FLAG_MOD_REPLACE;
554 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
555 const struct replPropertyMetaData1 *m2,
556 const uint32_t *rdn_attid)
558 if (m1->attid == m2->attid) {
563 * the rdn attribute should be at the end!
564 * so we need to return a value greater than zero
565 * which means m1 is greater than m2
567 if (m1->attid == *rdn_attid) {
572 * the rdn attribute should be at the end!
573 * so we need to return a value less than zero
574 * which means m2 is greater than m1
576 if (m2->attid == *rdn_attid) {
580 return m1->attid > m2->attid ? 1 : -1;
583 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
584 const struct dsdb_schema *schema,
587 const char *rdn_name;
588 const struct dsdb_attribute *rdn_sa;
590 rdn_name = ldb_dn_get_rdn_name(dn);
592 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
593 return LDB_ERR_OPERATIONS_ERROR;
596 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
597 if (rdn_sa == NULL) {
598 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
599 return LDB_ERR_OPERATIONS_ERROR;
602 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
603 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
605 ldb_qsort(ctr1->array, ctr1->count, sizeof(struct replPropertyMetaData1),
606 discard_const_p(void, &rdn_sa->attributeID_id),
607 (ldb_qsort_cmp_fn_t)replmd_replPropertyMetaData1_attid_sort);
612 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
613 const struct ldb_message_element *e2,
614 const struct dsdb_schema *schema)
616 const struct dsdb_attribute *a1;
617 const struct dsdb_attribute *a2;
620 * TODO: make this faster by caching the dsdb_attribute pointer
621 * on the ldb_messag_element
624 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
625 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
628 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
632 return strcasecmp(e1->name, e2->name);
634 if (a1->attributeID_id == a2->attributeID_id) {
637 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
640 static void replmd_ldb_message_sort(struct ldb_message *msg,
641 const struct dsdb_schema *schema)
643 ldb_qsort(msg->elements, msg->num_elements, sizeof(struct ldb_message_element),
644 discard_const_p(void, schema), (ldb_qsort_cmp_fn_t)replmd_ldb_message_element_attid_sort);
647 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
648 const struct GUID *invocation_id, uint64_t seq_num,
649 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
653 fix up linked attributes in replmd_add.
654 This involves setting up the right meta-data in extended DN
655 components, and creating backlinks to the object
657 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
658 uint64_t seq_num, const struct GUID *invocationId, time_t t,
659 struct GUID *guid, const struct dsdb_attribute *sa)
662 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
663 struct ldb_context *ldb = ldb_module_get_ctx(module);
664 struct dsdb_schema *schema = dsdb_get_schema(ldb);
667 unix_to_nt_time(&now, t);
669 for (i=0; i<el->num_values; i++) {
670 struct ldb_val *v = &el->values[i];
671 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
672 struct GUID target_guid;
676 /* note that the DN already has the extended
677 components from the extended_dn_store module */
678 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
679 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
680 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid);
681 if (ret != LDB_SUCCESS) {
682 talloc_free(tmp_ctx);
685 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
686 if (ret != LDB_SUCCESS) {
687 talloc_free(tmp_ctx);
692 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
693 seq_num, seq_num, now, 0, false);
694 if (ret != LDB_SUCCESS) {
695 talloc_free(tmp_ctx);
699 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
700 if (ret != LDB_SUCCESS) {
701 talloc_free(tmp_ctx);
706 talloc_free(tmp_ctx);
712 intercept add requests
714 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
716 struct ldb_context *ldb;
717 struct ldb_control *control;
718 struct replmd_replicated_request *ac;
719 enum ndr_err_code ndr_err;
720 struct ldb_request *down_req;
721 struct ldb_message *msg;
722 const DATA_BLOB *guid_blob;
724 struct replPropertyMetaDataBlob nmd;
725 struct ldb_val nmd_value;
726 const struct GUID *our_invocation_id;
727 time_t t = time(NULL);
732 bool allow_add_guid = false;
733 bool remove_current_guid = false;
734 bool is_urgent = false;
735 struct ldb_message_element *objectclass_el;
737 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
738 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
740 allow_add_guid = true;
743 /* do not manipulate our control entries */
744 if (ldb_dn_is_special(req->op.add.message->dn)) {
745 return ldb_next_request(module, req);
748 ldb = ldb_module_get_ctx(module);
750 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
752 ac = replmd_ctx_init(module, req);
754 return LDB_ERR_OPERATIONS_ERROR;
757 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
758 if ( guid_blob != NULL ) {
759 if( !allow_add_guid ) {
760 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
761 "replmd_add: it's not allowed to add an object with objectGUID\n");
763 return LDB_ERR_UNWILLING_TO_PERFORM;
765 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
766 if ( !NT_STATUS_IS_OK(status)) {
767 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
768 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
770 return LDB_ERR_UNWILLING_TO_PERFORM;
772 /* we remove this attribute as it can be a string and will not be treated
773 correctly and then we will readd it latter on in the good format*/
774 remove_current_guid = true;
778 guid = GUID_random();
781 /* Get a sequence number from the backend */
782 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
783 if (ret != LDB_SUCCESS) {
788 /* get our invocationId */
789 our_invocation_id = samdb_ntds_invocation_id(ldb);
790 if (!our_invocation_id) {
791 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
792 "replmd_add: unable to find invocationId\n");
794 return LDB_ERR_OPERATIONS_ERROR;
797 /* we have to copy the message as the caller might have it as a const */
798 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
802 return LDB_ERR_OPERATIONS_ERROR;
805 /* generated times */
806 unix_to_nt_time(&now, t);
807 time_str = ldb_timestring(msg, t);
811 return LDB_ERR_OPERATIONS_ERROR;
813 if (remove_current_guid) {
814 ldb_msg_remove_attr(msg,"objectGUID");
818 * remove autogenerated attributes
820 ldb_msg_remove_attr(msg, "whenCreated");
821 ldb_msg_remove_attr(msg, "whenChanged");
822 ldb_msg_remove_attr(msg, "uSNCreated");
823 ldb_msg_remove_attr(msg, "uSNChanged");
824 ldb_msg_remove_attr(msg, "replPropertyMetaData");
827 * readd replicated attributes
829 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
830 if (ret != LDB_SUCCESS) {
836 /* build the replication meta_data */
839 nmd.ctr.ctr1.count = msg->num_elements;
840 nmd.ctr.ctr1.array = talloc_array(msg,
841 struct replPropertyMetaData1,
843 if (!nmd.ctr.ctr1.array) {
846 return LDB_ERR_OPERATIONS_ERROR;
849 for (i=0; i < msg->num_elements; i++) {
850 struct ldb_message_element *e = &msg->elements[i];
851 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
852 const struct dsdb_attribute *sa;
854 if (e->name[0] == '@') continue;
856 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
858 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
859 "replmd_add: attribute '%s' not defined in schema\n",
862 return LDB_ERR_NO_SUCH_ATTRIBUTE;
865 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
866 /* if the attribute is not replicated (0x00000001)
867 * or constructed (0x00000004) it has no metadata
872 #if W2K3_LINKED_ATTRIBUTES
873 if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
874 ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa);
875 if (ret != LDB_SUCCESS) {
879 /* linked attributes are not stored in
880 replPropertyMetaData in FL above w2k */
885 m->attid = sa->attributeID_id;
887 m->originating_change_time = now;
888 m->originating_invocation_id = *our_invocation_id;
889 m->originating_usn = ac->seq_num;
890 m->local_usn = ac->seq_num;
894 /* fix meta data count */
895 nmd.ctr.ctr1.count = ni;
898 * sort meta data array, and move the rdn attribute entry to the end
900 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
901 if (ret != LDB_SUCCESS) {
906 /* generated NDR encoded values */
907 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
908 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
910 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
911 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
914 return LDB_ERR_OPERATIONS_ERROR;
918 * add the autogenerated values
920 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
921 if (ret != LDB_SUCCESS) {
926 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
927 if (ret != LDB_SUCCESS) {
932 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
933 if (ret != LDB_SUCCESS) {
938 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
939 if (ret != LDB_SUCCESS) {
944 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
945 if (ret != LDB_SUCCESS) {
952 * sort the attributes by attid before storing the object
954 replmd_ldb_message_sort(msg, ac->schema);
956 objectclass_el = ldb_msg_find_element(msg, "objectClass");
957 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
958 REPL_URGENT_ON_CREATE);
960 ac->is_urgent = is_urgent;
961 ret = ldb_build_add_req(&down_req, ldb, ac,
964 ac, replmd_op_callback,
967 if (ret != LDB_SUCCESS) {
972 /* mark the control done */
974 control->critical = 0;
977 /* go on with the call chain */
978 return ldb_next_request(module, down_req);
983 * update the replPropertyMetaData for one element
985 static int replmd_update_rpmd_element(struct ldb_context *ldb,
986 struct ldb_message *msg,
987 struct ldb_message_element *el,
988 struct replPropertyMetaDataBlob *omd,
989 const struct dsdb_schema *schema,
991 const struct GUID *our_invocation_id,
995 const struct dsdb_attribute *a;
996 struct replPropertyMetaData1 *md1;
998 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1000 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1002 return LDB_ERR_OPERATIONS_ERROR;
1005 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1009 for (i=0; i<omd->ctr.ctr1.count; i++) {
1010 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1013 #if W2K3_LINKED_ATTRIBUTES
1014 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1015 /* linked attributes are not stored in
1016 replPropertyMetaData in FL above w2k, but we do
1017 raise the seqnum for the object */
1018 if (*seq_num == 0 &&
1019 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1020 return LDB_ERR_OPERATIONS_ERROR;
1026 if (i == omd->ctr.ctr1.count) {
1027 /* we need to add a new one */
1028 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1029 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1030 if (omd->ctr.ctr1.array == NULL) {
1032 return LDB_ERR_OPERATIONS_ERROR;
1034 omd->ctr.ctr1.count++;
1035 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1038 /* Get a new sequence number from the backend. We only do this
1039 * if we have a change that requires a new
1040 * replPropertyMetaData element
1042 if (*seq_num == 0) {
1043 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1044 if (ret != LDB_SUCCESS) {
1045 return LDB_ERR_OPERATIONS_ERROR;
1049 md1 = &omd->ctr.ctr1.array[i];
1051 md1->attid = a->attributeID_id;
1052 md1->originating_change_time = now;
1053 md1->originating_invocation_id = *our_invocation_id;
1054 md1->originating_usn = *seq_num;
1055 md1->local_usn = *seq_num;
1061 * update the replPropertyMetaData object each time we modify an
1062 * object. This is needed for DRS replication, as the merge on the
1063 * client is based on this object
1065 static int replmd_update_rpmd(struct ldb_module *module,
1066 const struct dsdb_schema *schema,
1067 struct ldb_message *msg, uint64_t *seq_num,
1071 const struct ldb_val *omd_value;
1072 enum ndr_err_code ndr_err;
1073 struct replPropertyMetaDataBlob omd;
1076 const struct GUID *our_invocation_id;
1078 const char *attrs[] = { "replPropertyMetaData" , "objectClass", NULL };
1079 struct ldb_result *res;
1080 struct ldb_context *ldb;
1081 struct ldb_message_element *objectclass_el;
1083 ldb = ldb_module_get_ctx(module);
1085 our_invocation_id = samdb_ntds_invocation_id(ldb);
1086 if (!our_invocation_id) {
1087 /* this happens during an initial vampire while
1088 updating the schema */
1089 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1093 unix_to_nt_time(&now, t);
1095 /* search for the existing replPropertyMetaDataBlob */
1096 ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
1097 if (ret != LDB_SUCCESS || res->count != 1) {
1098 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1099 ldb_dn_get_linearized(msg->dn)));
1100 return LDB_ERR_OPERATIONS_ERROR;
1103 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1104 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1105 REPL_URGENT_ON_UPDATE)) {
1109 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1111 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1112 ldb_dn_get_linearized(msg->dn)));
1113 return LDB_ERR_OPERATIONS_ERROR;
1116 ndr_err = ndr_pull_struct_blob(omd_value, msg,
1117 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1118 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1119 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1120 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1121 ldb_dn_get_linearized(msg->dn)));
1122 return LDB_ERR_OPERATIONS_ERROR;
1125 if (omd.version != 1) {
1126 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1127 omd.version, ldb_dn_get_linearized(msg->dn)));
1128 return LDB_ERR_OPERATIONS_ERROR;
1131 for (i=0; i<msg->num_elements; i++) {
1132 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
1133 our_invocation_id, now);
1134 if (ret != LDB_SUCCESS) {
1138 if (is_urgent && !*is_urgent) {
1139 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1145 * replmd_update_rpmd_element has done an update if the
1148 if (*seq_num != 0) {
1149 struct ldb_val *md_value;
1150 struct ldb_message_element *el;
1152 md_value = talloc(msg, struct ldb_val);
1153 if (md_value == NULL) {
1155 return LDB_ERR_OPERATIONS_ERROR;
1158 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1159 if (ret != LDB_SUCCESS) {
1163 ndr_err = ndr_push_struct_blob(md_value, msg,
1164 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1166 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1167 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1168 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1169 ldb_dn_get_linearized(msg->dn)));
1170 return LDB_ERR_OPERATIONS_ERROR;
1173 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1174 if (ret != LDB_SUCCESS) {
1175 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1176 ldb_dn_get_linearized(msg->dn)));
1181 el->values = md_value;
1188 struct dsdb_dn *dsdb_dn;
1193 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1195 return GUID_compare(pdn1->guid, pdn2->guid);
1198 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid, struct ldb_dn *dn)
1200 struct parsed_dn *ret;
1201 if (dn && GUID_all_zero(guid)) {
1202 /* when updating a link using DRS, we sometimes get a
1203 NULL GUID. We then need to try and match by DN */
1205 for (i=0; i<count; i++) {
1206 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1207 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1213 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1218 get a series of message element values as an array of DNs and GUIDs
1219 the result is sorted by GUID
1221 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1222 struct ldb_message_element *el, struct parsed_dn **pdn,
1223 const char *ldap_oid)
1226 struct ldb_context *ldb = ldb_module_get_ctx(module);
1233 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1235 ldb_module_oom(module);
1236 return LDB_ERR_OPERATIONS_ERROR;
1239 for (i=0; i<el->num_values; i++) {
1240 struct ldb_val *v = &el->values[i];
1243 struct parsed_dn *p;
1247 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1248 if (p->dsdb_dn == NULL) {
1249 return LDB_ERR_INVALID_DN_SYNTAX;
1252 dn = p->dsdb_dn->dn;
1254 p->guid = talloc(*pdn, struct GUID);
1255 if (p->guid == NULL) {
1256 ldb_module_oom(module);
1257 return LDB_ERR_OPERATIONS_ERROR;
1260 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1261 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1262 /* we got a DN without a GUID - go find the GUID */
1263 int ret = dsdb_module_guid_by_dn(module, dn, p->guid);
1264 if (ret != LDB_SUCCESS) {
1265 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1266 ldb_dn_get_linearized(dn));
1269 ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1270 if (ret != LDB_SUCCESS) {
1273 } else if (!NT_STATUS_IS_OK(status)) {
1274 return LDB_ERR_OPERATIONS_ERROR;
1277 /* keep a pointer to the original ldb_val */
1281 qsort(*pdn, el->num_values, sizeof((*pdn)[0]), (comparison_fn_t)parsed_dn_compare);
1287 build a new extended DN, including all meta data fields
1289 RMD_FLAGS = DSDB_RMD_FLAG_* bits
1290 RMD_ADDTIME = originating_add_time
1291 RMD_INVOCID = originating_invocation_id
1292 RMD_CHANGETIME = originating_change_time
1293 RMD_ORIGINATING_USN = originating_usn
1294 RMD_LOCAL_USN = local_usn
1295 RMD_VERSION = version
1297 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1298 const struct GUID *invocation_id, uint64_t seq_num,
1299 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1301 struct ldb_dn *dn = dsdb_dn->dn;
1302 const char *tstring, *usn_string, *flags_string;
1303 struct ldb_val tval;
1305 struct ldb_val usnv, local_usnv;
1306 struct ldb_val vers, flagsv;
1309 const char *dnstring;
1311 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1313 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1315 return LDB_ERR_OPERATIONS_ERROR;
1317 tval = data_blob_string_const(tstring);
1319 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1321 return LDB_ERR_OPERATIONS_ERROR;
1323 usnv = data_blob_string_const(usn_string);
1325 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1327 return LDB_ERR_OPERATIONS_ERROR;
1329 local_usnv = data_blob_string_const(usn_string);
1331 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1333 return LDB_ERR_OPERATIONS_ERROR;
1335 vers = data_blob_string_const(vstring);
1337 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1338 if (!NT_STATUS_IS_OK(status)) {
1339 return LDB_ERR_OPERATIONS_ERROR;
1342 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1343 if (!flags_string) {
1344 return LDB_ERR_OPERATIONS_ERROR;
1346 flagsv = data_blob_string_const(flags_string);
1348 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1349 if (ret != LDB_SUCCESS) return ret;
1350 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1351 if (ret != LDB_SUCCESS) return ret;
1352 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1353 if (ret != LDB_SUCCESS) return ret;
1354 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1355 if (ret != LDB_SUCCESS) return ret;
1356 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1357 if (ret != LDB_SUCCESS) return ret;
1358 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1359 if (ret != LDB_SUCCESS) return ret;
1360 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1361 if (ret != LDB_SUCCESS) return ret;
1363 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1364 if (dnstring == NULL) {
1365 return LDB_ERR_OPERATIONS_ERROR;
1367 *v = data_blob_string_const(dnstring);
1372 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1373 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1374 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1375 uint32_t version, bool deleted);
1378 check if any links need upgrading from w2k format
1380 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, const struct GUID *invocation_id)
1383 for (i=0; i<count; i++) {
1388 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1389 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1393 /* it's an old one that needs upgrading */
1394 ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1396 if (ret != LDB_SUCCESS) {
1404 update an extended DN, including all meta data fields
1406 see replmd_build_la_val for value names
1408 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1409 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1410 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1411 uint32_t version, bool deleted)
1413 struct ldb_dn *dn = dsdb_dn->dn;
1414 const char *tstring, *usn_string, *flags_string;
1415 struct ldb_val tval;
1417 struct ldb_val usnv, local_usnv;
1418 struct ldb_val vers, flagsv;
1419 const struct ldb_val *old_addtime;
1420 uint32_t old_version;
1423 const char *dnstring;
1425 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1427 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1429 return LDB_ERR_OPERATIONS_ERROR;
1431 tval = data_blob_string_const(tstring);
1433 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1435 return LDB_ERR_OPERATIONS_ERROR;
1437 usnv = data_blob_string_const(usn_string);
1439 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1441 return LDB_ERR_OPERATIONS_ERROR;
1443 local_usnv = data_blob_string_const(usn_string);
1445 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1446 if (!NT_STATUS_IS_OK(status)) {
1447 return LDB_ERR_OPERATIONS_ERROR;
1450 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1451 if (!flags_string) {
1452 return LDB_ERR_OPERATIONS_ERROR;
1454 flagsv = data_blob_string_const(flags_string);
1456 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1457 if (ret != LDB_SUCCESS) return ret;
1459 /* get the ADDTIME from the original */
1460 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1461 if (old_addtime == NULL) {
1462 old_addtime = &tval;
1464 if (dsdb_dn != old_dsdb_dn) {
1465 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1466 if (ret != LDB_SUCCESS) return ret;
1469 /* use our invocation id */
1470 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1471 if (ret != LDB_SUCCESS) return ret;
1473 /* changetime is the current time */
1474 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1475 if (ret != LDB_SUCCESS) return ret;
1477 /* update the USN */
1478 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1479 if (ret != LDB_SUCCESS) return ret;
1481 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1482 if (ret != LDB_SUCCESS) return ret;
1484 /* increase the version by 1 */
1485 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1486 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1487 version = old_version+1;
1489 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1490 vers = data_blob_string_const(vstring);
1491 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1492 if (ret != LDB_SUCCESS) return ret;
1494 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1495 if (dnstring == NULL) {
1496 return LDB_ERR_OPERATIONS_ERROR;
1498 *v = data_blob_string_const(dnstring);
1504 handle adding a linked attribute
1506 static int replmd_modify_la_add(struct ldb_module *module,
1507 struct dsdb_schema *schema,
1508 struct ldb_message *msg,
1509 struct ldb_message_element *el,
1510 struct ldb_message_element *old_el,
1511 const struct dsdb_attribute *schema_attr,
1514 struct GUID *msg_guid)
1517 struct parsed_dn *dns, *old_dns;
1518 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1520 struct ldb_val *new_values = NULL;
1521 unsigned int num_new_values = 0;
1522 unsigned old_num_values = old_el?old_el->num_values:0;
1523 const struct GUID *invocation_id;
1524 struct ldb_context *ldb = ldb_module_get_ctx(module);
1527 unix_to_nt_time(&now, t);
1529 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1530 if (ret != LDB_SUCCESS) {
1531 talloc_free(tmp_ctx);
1535 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1536 if (ret != LDB_SUCCESS) {
1537 talloc_free(tmp_ctx);
1541 invocation_id = samdb_ntds_invocation_id(ldb);
1542 if (!invocation_id) {
1543 talloc_free(tmp_ctx);
1544 return LDB_ERR_OPERATIONS_ERROR;
1547 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1548 if (ret != LDB_SUCCESS) {
1549 talloc_free(tmp_ctx);
1553 /* for each new value, see if it exists already with the same GUID */
1554 for (i=0; i<el->num_values; i++) {
1555 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1557 /* this is a new linked attribute value */
1558 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1559 if (new_values == NULL) {
1560 ldb_module_oom(module);
1561 talloc_free(tmp_ctx);
1562 return LDB_ERR_OPERATIONS_ERROR;
1564 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1565 invocation_id, seq_num, seq_num, now, 0, false);
1566 if (ret != LDB_SUCCESS) {
1567 talloc_free(tmp_ctx);
1572 /* this is only allowed if the GUID was
1573 previously deleted. */
1574 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1576 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1577 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1578 el->name, GUID_string(tmp_ctx, p->guid));
1579 talloc_free(tmp_ctx);
1580 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1582 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1583 invocation_id, seq_num, seq_num, now, 0, false);
1584 if (ret != LDB_SUCCESS) {
1585 talloc_free(tmp_ctx);
1590 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1591 if (ret != LDB_SUCCESS) {
1592 talloc_free(tmp_ctx);
1597 /* add the new ones on to the end of the old values, constructing a new el->values */
1598 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1600 old_num_values+num_new_values);
1601 if (el->values == NULL) {
1602 ldb_module_oom(module);
1603 return LDB_ERR_OPERATIONS_ERROR;
1606 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1607 el->num_values = old_num_values + num_new_values;
1609 talloc_steal(msg->elements, el->values);
1610 talloc_steal(el->values, new_values);
1612 talloc_free(tmp_ctx);
1614 /* we now tell the backend to replace all existing values
1615 with the one we have constructed */
1616 el->flags = LDB_FLAG_MOD_REPLACE;
1623 handle deleting all active linked attributes
1625 static int replmd_modify_la_delete(struct ldb_module *module,
1626 struct dsdb_schema *schema,
1627 struct ldb_message *msg,
1628 struct ldb_message_element *el,
1629 struct ldb_message_element *old_el,
1630 const struct dsdb_attribute *schema_attr,
1633 struct GUID *msg_guid)
1636 struct parsed_dn *dns, *old_dns;
1637 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1639 const struct GUID *invocation_id;
1640 struct ldb_context *ldb = ldb_module_get_ctx(module);
1643 unix_to_nt_time(&now, t);
1645 /* check if there is nothing to delete */
1646 if ((!old_el || old_el->num_values == 0) &&
1647 el->num_values == 0) {
1651 if (!old_el || old_el->num_values == 0) {
1652 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1655 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1656 if (ret != LDB_SUCCESS) {
1657 talloc_free(tmp_ctx);
1661 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1662 if (ret != LDB_SUCCESS) {
1663 talloc_free(tmp_ctx);
1667 invocation_id = samdb_ntds_invocation_id(ldb);
1668 if (!invocation_id) {
1669 return LDB_ERR_OPERATIONS_ERROR;
1672 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, invocation_id);
1673 if (ret != LDB_SUCCESS) {
1674 talloc_free(tmp_ctx);
1680 /* see if we are being asked to delete any links that
1681 don't exist or are already deleted */
1682 for (i=0; i<el->num_values; i++) {
1683 struct parsed_dn *p = &dns[i];
1684 struct parsed_dn *p2;
1687 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1689 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1690 el->name, GUID_string(tmp_ctx, p->guid));
1691 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1693 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1694 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1695 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1696 el->name, GUID_string(tmp_ctx, p->guid));
1697 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1701 /* for each new value, see if it exists already with the same GUID
1702 if it is not already deleted and matches the delete list then delete it
1704 for (i=0; i<old_el->num_values; i++) {
1705 struct parsed_dn *p = &old_dns[i];
1708 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1712 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1713 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1715 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1716 invocation_id, seq_num, seq_num, now, 0, true);
1717 if (ret != LDB_SUCCESS) {
1718 talloc_free(tmp_ctx);
1722 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1723 if (ret != LDB_SUCCESS) {
1724 talloc_free(tmp_ctx);
1729 el->values = talloc_steal(msg->elements, old_el->values);
1730 el->num_values = old_el->num_values;
1732 talloc_free(tmp_ctx);
1734 /* we now tell the backend to replace all existing values
1735 with the one we have constructed */
1736 el->flags = LDB_FLAG_MOD_REPLACE;
1742 handle replacing a linked attribute
1744 static int replmd_modify_la_replace(struct ldb_module *module,
1745 struct dsdb_schema *schema,
1746 struct ldb_message *msg,
1747 struct ldb_message_element *el,
1748 struct ldb_message_element *old_el,
1749 const struct dsdb_attribute *schema_attr,
1752 struct GUID *msg_guid)
1755 struct parsed_dn *dns, *old_dns;
1756 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1758 const struct GUID *invocation_id;
1759 struct ldb_context *ldb = ldb_module_get_ctx(module);
1760 struct ldb_val *new_values = NULL;
1761 uint32_t num_new_values = 0;
1762 unsigned old_num_values = old_el?old_el->num_values:0;
1765 unix_to_nt_time(&now, t);
1767 /* check if there is nothing to replace */
1768 if ((!old_el || old_el->num_values == 0) &&
1769 el->num_values == 0) {
1773 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1774 if (ret != LDB_SUCCESS) {
1775 talloc_free(tmp_ctx);
1779 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1780 if (ret != LDB_SUCCESS) {
1781 talloc_free(tmp_ctx);
1785 invocation_id = samdb_ntds_invocation_id(ldb);
1786 if (!invocation_id) {
1787 return LDB_ERR_OPERATIONS_ERROR;
1790 ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1791 if (ret != LDB_SUCCESS) {
1792 talloc_free(tmp_ctx);
1796 /* mark all the old ones as deleted */
1797 for (i=0; i<old_num_values; i++) {
1798 struct parsed_dn *old_p = &old_dns[i];
1799 struct parsed_dn *p;
1800 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1802 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1804 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1805 if (ret != LDB_SUCCESS) {
1806 talloc_free(tmp_ctx);
1810 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1812 /* we don't delete it if we are re-adding it */
1816 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1817 invocation_id, seq_num, seq_num, now, 0, true);
1818 if (ret != LDB_SUCCESS) {
1819 talloc_free(tmp_ctx);
1824 /* for each new value, either update its meta-data, or add it
1827 for (i=0; i<el->num_values; i++) {
1828 struct parsed_dn *p = &dns[i], *old_p;
1831 (old_p = parsed_dn_find(old_dns,
1832 old_num_values, p->guid, NULL)) != NULL) {
1833 /* update in place */
1834 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1835 old_p->dsdb_dn, invocation_id,
1836 seq_num, seq_num, now, 0, false);
1837 if (ret != LDB_SUCCESS) {
1838 talloc_free(tmp_ctx);
1843 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1845 if (new_values == NULL) {
1846 ldb_module_oom(module);
1847 talloc_free(tmp_ctx);
1848 return LDB_ERR_OPERATIONS_ERROR;
1850 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1851 invocation_id, seq_num, seq_num, now, 0, false);
1852 if (ret != LDB_SUCCESS) {
1853 talloc_free(tmp_ctx);
1859 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1860 if (ret != LDB_SUCCESS) {
1861 talloc_free(tmp_ctx);
1866 /* add the new values to the end of old_el */
1867 if (num_new_values != 0) {
1868 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1869 struct ldb_val, old_num_values+num_new_values);
1870 if (el->values == NULL) {
1871 ldb_module_oom(module);
1872 return LDB_ERR_OPERATIONS_ERROR;
1874 memcpy(&el->values[old_num_values], &new_values[0],
1875 sizeof(struct ldb_val)*num_new_values);
1876 el->num_values = old_num_values + num_new_values;
1877 talloc_steal(msg->elements, new_values);
1879 el->values = old_el->values;
1880 el->num_values = old_el->num_values;
1881 talloc_steal(msg->elements, el->values);
1884 talloc_free(tmp_ctx);
1886 /* we now tell the backend to replace all existing values
1887 with the one we have constructed */
1888 el->flags = LDB_FLAG_MOD_REPLACE;
1895 handle linked attributes in modify requests
1897 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1898 struct ldb_message *msg,
1899 uint64_t seq_num, time_t t)
1901 struct ldb_result *res;
1903 struct ldb_context *ldb = ldb_module_get_ctx(module);
1904 struct ldb_message *old_msg;
1905 struct dsdb_schema *schema = dsdb_get_schema(ldb);
1906 struct GUID old_guid;
1909 /* there the replmd_update_rpmd code has already
1910 * checked and saw that there are no linked
1915 #if !W2K3_LINKED_ATTRIBUTES
1919 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1920 /* don't do anything special for linked attributes */
1924 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1925 DSDB_SEARCH_SHOW_DELETED |
1926 DSDB_SEARCH_REVEAL_INTERNALS |
1927 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1928 if (ret != LDB_SUCCESS) {
1931 old_msg = res->msgs[0];
1933 old_guid = samdb_result_guid(old_msg, "objectGUID");
1935 for (i=0; i<msg->num_elements; i++) {
1936 struct ldb_message_element *el = &msg->elements[i];
1937 struct ldb_message_element *old_el, *new_el;
1938 const struct dsdb_attribute *schema_attr
1939 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1941 ldb_asprintf_errstring(ldb,
1942 "attribute %s is not a valid attribute in schema", el->name);
1943 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1945 if (schema_attr->linkID == 0) {
1948 if ((schema_attr->linkID & 1) == 1) {
1949 /* Odd is for the target. Illegal to modify */
1950 ldb_asprintf_errstring(ldb,
1951 "attribute %s must not be modified directly, it is a linked attribute", el->name);
1952 return LDB_ERR_UNWILLING_TO_PERFORM;
1954 old_el = ldb_msg_find_element(old_msg, el->name);
1955 switch (el->flags & LDB_FLAG_MOD_MASK) {
1956 case LDB_FLAG_MOD_REPLACE:
1957 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1959 case LDB_FLAG_MOD_DELETE:
1960 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1962 case LDB_FLAG_MOD_ADD:
1963 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1966 ldb_asprintf_errstring(ldb,
1967 "invalid flags 0x%x for %s linked attribute",
1968 el->flags, el->name);
1969 return LDB_ERR_UNWILLING_TO_PERFORM;
1971 if (ret != LDB_SUCCESS) {
1975 ldb_msg_remove_attr(old_msg, el->name);
1977 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
1978 new_el->num_values = el->num_values;
1979 new_el->values = talloc_steal(msg->elements, el->values);
1981 /* TODO: this relises a bit too heavily on the exact
1982 behaviour of ldb_msg_find_element and
1983 ldb_msg_remove_element */
1984 old_el = ldb_msg_find_element(msg, el->name);
1986 ldb_msg_remove_element(msg, old_el);
1997 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
1999 struct ldb_context *ldb;
2000 struct replmd_replicated_request *ac;
2001 struct ldb_request *down_req;
2002 struct ldb_message *msg;
2003 time_t t = time(NULL);
2005 bool is_urgent = false;
2007 /* do not manipulate our control entries */
2008 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2009 return ldb_next_request(module, req);
2012 ldb = ldb_module_get_ctx(module);
2014 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2016 ac = replmd_ctx_init(module, req);
2018 return LDB_ERR_OPERATIONS_ERROR;
2021 /* we have to copy the message as the caller might have it as a const */
2022 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2026 return LDB_ERR_OPERATIONS_ERROR;
2029 ldb_msg_remove_attr(msg, "whenChanged");
2030 ldb_msg_remove_attr(msg, "uSNChanged");
2032 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t, &is_urgent);
2033 if (ret != LDB_SUCCESS) {
2038 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
2039 if (ret != LDB_SUCCESS) {
2045 * - replace the old object with the newly constructed one
2048 ac->is_urgent = is_urgent;
2050 ret = ldb_build_mod_req(&down_req, ldb, ac,
2053 ac, replmd_op_callback,
2055 if (ret != LDB_SUCCESS) {
2059 talloc_steal(down_req, msg);
2061 /* we only change whenChanged and uSNChanged if the seq_num
2063 if (ac->seq_num != 0) {
2064 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2069 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2075 /* go on with the call chain */
2076 return ldb_next_request(module, down_req);
2079 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2082 handle a rename request
2084 On a rename we need to do an extra ldb_modify which sets the
2085 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2087 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2089 struct ldb_context *ldb;
2090 struct replmd_replicated_request *ac;
2092 struct ldb_request *down_req;
2094 /* do not manipulate our control entries */
2095 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2096 return ldb_next_request(module, req);
2099 ldb = ldb_module_get_ctx(module);
2101 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2103 ac = replmd_ctx_init(module, req);
2105 return LDB_ERR_OPERATIONS_ERROR;
2107 ret = ldb_build_rename_req(&down_req, ldb, ac,
2108 ac->req->op.rename.olddn,
2109 ac->req->op.rename.newdn,
2111 ac, replmd_rename_callback,
2114 if (ret != LDB_SUCCESS) {
2119 /* go on with the call chain */
2120 return ldb_next_request(module, down_req);
2123 /* After the rename is compleated, update the whenchanged etc */
2124 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2126 struct ldb_context *ldb;
2127 struct replmd_replicated_request *ac;
2128 struct ldb_request *down_req;
2129 struct ldb_message *msg;
2130 time_t t = time(NULL);
2133 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2134 ldb = ldb_module_get_ctx(ac->module);
2136 if (ares->error != LDB_SUCCESS) {
2137 return ldb_module_done(ac->req, ares->controls,
2138 ares->response, ares->error);
2141 if (ares->type != LDB_REPLY_DONE) {
2142 ldb_set_errstring(ldb,
2143 "invalid ldb_reply_type in callback");
2145 return ldb_module_done(ac->req, NULL, NULL,
2146 LDB_ERR_OPERATIONS_ERROR);
2149 /* Get a sequence number from the backend */
2150 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2151 if (ret != LDB_SUCCESS) {
2156 * - replace the old object with the newly constructed one
2159 msg = ldb_msg_new(ac);
2162 return LDB_ERR_OPERATIONS_ERROR;
2165 msg->dn = ac->req->op.rename.newdn;
2167 ret = ldb_build_mod_req(&down_req, ldb, ac,
2170 ac, replmd_op_callback,
2173 if (ret != LDB_SUCCESS) {
2177 talloc_steal(down_req, msg);
2179 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2184 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2189 /* go on with the call chain - do the modify after the rename */
2190 return ldb_next_request(ac->module, down_req);
2194 remove links from objects that point at this object when an object
2197 static int replmd_delete_remove_link(struct ldb_module *module,
2198 struct dsdb_schema *schema,
2200 struct ldb_message_element *el,
2201 const struct dsdb_attribute *sa)
2204 TALLOC_CTX *tmp_ctx = talloc_new(module);
2205 struct ldb_context *ldb = ldb_module_get_ctx(module);
2207 for (i=0; i<el->num_values; i++) {
2208 struct dsdb_dn *dsdb_dn;
2212 struct ldb_message *msg;
2213 const struct dsdb_attribute *target_attr;
2214 struct ldb_message_element *el2;
2215 struct ldb_val dn_val;
2217 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2221 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2223 talloc_free(tmp_ctx);
2224 return LDB_ERR_OPERATIONS_ERROR;
2227 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2228 if (!NT_STATUS_IS_OK(status)) {
2229 talloc_free(tmp_ctx);
2230 return LDB_ERR_OPERATIONS_ERROR;
2233 /* remove the link */
2234 msg = ldb_msg_new(tmp_ctx);
2236 ldb_module_oom(module);
2237 talloc_free(tmp_ctx);
2238 return LDB_ERR_OPERATIONS_ERROR;
2242 msg->dn = dsdb_dn->dn;
2244 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2245 if (target_attr == NULL) {
2249 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2250 if (ret != LDB_SUCCESS) {
2251 ldb_module_oom(module);
2252 talloc_free(tmp_ctx);
2253 return LDB_ERR_OPERATIONS_ERROR;
2255 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2256 el2->values = &dn_val;
2257 el2->num_values = 1;
2259 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2260 if (ret != LDB_SUCCESS) {
2261 talloc_free(tmp_ctx);
2265 talloc_free(tmp_ctx);
2271 handle update of replication meta data for deletion of objects
2273 This also handles the mapping of delete to a rename operation
2274 to allow deletes to be replicated.
2276 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2278 int ret = LDB_ERR_OTHER;
2280 struct ldb_dn *old_dn, *new_dn;
2281 const char *rdn_name;
2282 const struct ldb_val *rdn_value, *new_rdn_value;
2284 struct ldb_context *ldb = ldb_module_get_ctx(module);
2285 struct dsdb_schema *schema = dsdb_get_schema(ldb);
2286 struct ldb_message *msg, *old_msg;
2287 struct ldb_message_element *el;
2288 TALLOC_CTX *tmp_ctx;
2289 struct ldb_result *res, *parent_res;
2290 const char *preserved_attrs[] = {
2291 /* yes, this really is a hard coded list. See MS-ADTS
2292 section 3.1.1.5.5.1.1 */
2293 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2294 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2295 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2296 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2297 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2298 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2299 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2300 "whenChanged", NULL};
2301 uint32_t el_count = 0;
2304 if (ldb_dn_is_special(req->op.del.dn)) {
2305 return ldb_next_request(module, req);
2308 tmp_ctx = talloc_new(ldb);
2310 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2312 /* we need the complete msg off disk, so we can work out which
2313 attributes need to be removed */
2314 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2315 DSDB_SEARCH_SHOW_DELETED |
2316 DSDB_SEARCH_REVEAL_INTERNALS |
2317 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2318 if (ret != LDB_SUCCESS) {
2319 talloc_free(tmp_ctx);
2322 old_msg = res->msgs[0];
2324 if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2325 struct auth_session_info *session_info =
2326 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2327 if (security_session_user_level(session_info) != SECURITY_SYSTEM) {
2328 ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2329 ldb_dn_get_linearized(old_msg->dn));
2330 return LDB_ERR_UNWILLING_TO_PERFORM;
2333 /* it is already deleted - really remove it this time */
2334 talloc_free(tmp_ctx);
2335 return ldb_next_request(module, req);
2338 /* work out where we will be renaming this object to */
2339 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2340 if (ret != LDB_SUCCESS) {
2341 /* this is probably an attempted delete on a partition
2342 * that doesn't allow delete operations, such as the
2343 * schema partition */
2344 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2345 ldb_dn_get_linearized(old_dn));
2346 talloc_free(tmp_ctx);
2347 return LDB_ERR_UNWILLING_TO_PERFORM;
2350 rdn_name = ldb_dn_get_rdn_name(old_dn);
2351 rdn_value = ldb_dn_get_rdn_val(old_dn);
2353 /* get the objects GUID from the search we just did */
2354 guid = samdb_result_guid(old_msg, "objectGUID");
2356 /* Add a formatted child */
2357 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2360 GUID_string(tmp_ctx, &guid));
2362 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2363 ldb_dn_get_linearized(new_dn)));
2364 talloc_free(tmp_ctx);
2365 return LDB_ERR_OPERATIONS_ERROR;
2369 now we need to modify the object in the following ways:
2371 - add isDeleted=TRUE
2372 - update rDN and name, with new rDN
2373 - remove linked attributes
2374 - remove objectCategory and sAMAccountType
2375 - remove attribs not on the preserved list
2376 - preserved if in above list, or is rDN
2377 - remove all linked attribs from this object
2378 - remove all links from other objects to this object
2379 - add lastKnownParent
2380 - update replPropertyMetaData?
2382 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2385 msg = ldb_msg_new(tmp_ctx);
2387 ldb_module_oom(module);
2388 talloc_free(tmp_ctx);
2389 return LDB_ERR_OPERATIONS_ERROR;
2394 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2395 if (ret != LDB_SUCCESS) {
2396 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2397 ldb_module_oom(module);
2398 talloc_free(tmp_ctx);
2401 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2403 /* we also mark it as recycled, meaning this object can't be
2404 recovered (we are stripping its attributes) */
2405 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2406 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2407 if (ret != LDB_SUCCESS) {
2408 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2409 ldb_module_oom(module);
2410 talloc_free(tmp_ctx);
2413 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2416 /* we need the storage form of the parent GUID */
2417 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2418 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2419 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2420 DSDB_SEARCH_REVEAL_INTERNALS);
2421 if (ret != LDB_SUCCESS) {
2422 talloc_free(tmp_ctx);
2426 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2427 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2428 if (ret != LDB_SUCCESS) {
2429 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2430 ldb_module_oom(module);
2431 talloc_free(tmp_ctx);
2434 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2436 /* work out which of the old attributes we will be removing */
2437 for (i=0; i<old_msg->num_elements; i++) {
2438 const struct dsdb_attribute *sa;
2439 el = &old_msg->elements[i];
2440 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2442 talloc_free(tmp_ctx);
2443 return LDB_ERR_OPERATIONS_ERROR;
2445 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2446 /* don't remove the rDN */
2450 if (sa->linkID && sa->linkID & 1) {
2451 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2452 if (ret != LDB_SUCCESS) {
2453 talloc_free(tmp_ctx);
2454 return LDB_ERR_OPERATIONS_ERROR;
2459 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2463 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2464 if (ret != LDB_SUCCESS) {
2465 talloc_free(tmp_ctx);
2466 ldb_module_oom(module);
2471 /* work out what the new rdn value is, for updating the
2472 rDN and name fields */
2473 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2474 ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el);
2475 if (ret != LDB_SUCCESS) {
2476 talloc_free(tmp_ctx);
2479 el->flags = LDB_FLAG_MOD_REPLACE;
2481 el = ldb_msg_find_element(old_msg, "name");
2483 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2484 if (ret != LDB_SUCCESS) {
2485 talloc_free(tmp_ctx);
2488 el->flags = LDB_FLAG_MOD_REPLACE;
2491 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2492 if (ret != LDB_SUCCESS) {
2493 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2494 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2495 talloc_free(tmp_ctx);
2499 /* now rename onto the new DN */
2500 ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2501 if (ret != LDB_SUCCESS){
2502 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2503 ldb_dn_get_linearized(old_dn),
2504 ldb_dn_get_linearized(new_dn),
2505 ldb_errstring(ldb)));
2506 talloc_free(tmp_ctx);
2510 talloc_free(tmp_ctx);
2512 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2517 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2522 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2524 int ret = LDB_ERR_OTHER;
2525 /* TODO: do some error mapping */
2529 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2531 struct ldb_context *ldb;
2532 struct ldb_request *change_req;
2533 enum ndr_err_code ndr_err;
2534 struct ldb_message *msg;
2535 struct replPropertyMetaDataBlob *md;
2536 struct ldb_val md_value;
2541 * TODO: check if the parent object exist
2545 * TODO: handle the conflict case where an object with the
2549 ldb = ldb_module_get_ctx(ar->module);
2550 msg = ar->objs->objects[ar->index_current].msg;
2551 md = ar->objs->objects[ar->index_current].meta_data;
2553 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2554 if (ret != LDB_SUCCESS) {
2555 return replmd_replicated_request_error(ar, ret);
2558 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2559 if (ret != LDB_SUCCESS) {
2560 return replmd_replicated_request_error(ar, ret);
2563 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2564 if (ret != LDB_SUCCESS) {
2565 return replmd_replicated_request_error(ar, ret);
2568 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2569 if (ret != LDB_SUCCESS) {
2570 return replmd_replicated_request_error(ar, ret);
2573 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2574 if (ret != LDB_SUCCESS) {
2575 return replmd_replicated_request_error(ar, ret);
2578 /* remove any message elements that have zero values */
2579 for (i=0; i<msg->num_elements; i++) {
2580 struct ldb_message_element *el = &msg->elements[i];
2582 if (el->num_values == 0) {
2583 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2585 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2586 msg->num_elements--;
2593 * the meta data array is already sorted by the caller
2595 for (i=0; i < md->ctr.ctr1.count; i++) {
2596 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2598 ndr_err = ndr_push_struct_blob(&md_value, msg,
2599 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2601 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2602 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2603 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2604 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2606 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2607 if (ret != LDB_SUCCESS) {
2608 return replmd_replicated_request_error(ar, ret);
2611 replmd_ldb_message_sort(msg, ar->schema);
2614 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2615 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2619 ret = ldb_build_add_req(&change_req,
2627 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2629 return ldb_next_request(ar->module, change_req);
2633 return true if an update is newer than an existing entry
2634 see section 5.11 of MS-ADTS
2636 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2637 const struct GUID *update_invocation_id,
2638 uint32_t current_version,
2639 uint32_t update_version,
2640 NTTIME current_change_time,
2641 NTTIME update_change_time)
2643 if (update_version != current_version) {
2644 return update_version > current_version;
2646 if (update_change_time > current_change_time) {
2649 if (update_change_time == current_change_time) {
2650 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2655 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2656 struct replPropertyMetaData1 *new_m)
2658 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2659 &new_m->originating_invocation_id,
2662 cur_m->originating_change_time,
2663 new_m->originating_change_time);
2666 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2668 struct ldb_context *ldb;
2669 struct ldb_request *change_req;
2670 enum ndr_err_code ndr_err;
2671 struct ldb_message *msg;
2672 struct replPropertyMetaDataBlob *rmd;
2673 struct replPropertyMetaDataBlob omd;
2674 const struct ldb_val *omd_value;
2675 struct replPropertyMetaDataBlob nmd;
2676 struct ldb_val nmd_value;
2678 uint32_t removed_attrs = 0;
2681 ldb = ldb_module_get_ctx(ar->module);
2682 msg = ar->objs->objects[ar->index_current].msg;
2683 rmd = ar->objs->objects[ar->index_current].meta_data;
2688 * TODO: check repl data is correct after a rename
2690 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2691 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2692 ldb_dn_get_linearized(ar->search_msg->dn),
2693 ldb_dn_get_linearized(msg->dn));
2694 if (dsdb_module_rename(ar->module,
2695 ar->search_msg->dn, msg->dn,
2696 DSDB_FLAG_OWN_MODULE) != LDB_SUCCESS) {
2697 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2698 ldb_dn_get_linearized(ar->search_msg->dn),
2699 ldb_dn_get_linearized(msg->dn),
2700 ldb_errstring(ldb));
2701 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2705 /* find existing meta data */
2706 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2708 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2709 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2710 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2711 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2712 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2713 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2716 if (omd.version != 1) {
2717 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2723 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2724 nmd.ctr.ctr1.array = talloc_array(ar,
2725 struct replPropertyMetaData1,
2726 nmd.ctr.ctr1.count);
2727 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2729 /* first copy the old meta data */
2730 for (i=0; i < omd.ctr.ctr1.count; i++) {
2731 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2735 /* now merge in the new meta data */
2736 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2739 for (j=0; j < ni; j++) {
2742 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2746 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2747 &rmd->ctr.ctr1.array[i]);
2749 /* replace the entry */
2750 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2755 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType) {
2756 DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n",
2757 msg->elements[i-removed_attrs].name,
2758 ldb_dn_get_linearized(msg->dn),
2759 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2762 /* we don't want to apply this change so remove the attribute */
2763 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2770 if (found) continue;
2772 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2777 * finally correct the size of the meta_data array
2779 nmd.ctr.ctr1.count = ni;
2782 * the rdn attribute (the alias for the name attribute),
2783 * 'cn' for most objects is the last entry in the meta data array
2786 * sort the new meta data array
2788 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2789 if (ret != LDB_SUCCESS) {
2794 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2796 if (msg->num_elements == 0) {
2797 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2800 ar->index_current++;
2801 return replmd_replicated_apply_next(ar);
2804 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2805 ar->index_current, msg->num_elements);
2807 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2808 if (ret != LDB_SUCCESS) {
2809 return replmd_replicated_request_error(ar, ret);
2812 for (i=0; i<ni; i++) {
2813 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2816 /* create the meta data value */
2817 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
2818 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2820 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2821 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2822 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2823 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2827 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2828 * and replPopertyMetaData attributes
2830 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2831 if (ret != LDB_SUCCESS) {
2832 return replmd_replicated_request_error(ar, ret);
2834 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2835 if (ret != LDB_SUCCESS) {
2836 return replmd_replicated_request_error(ar, ret);
2838 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2839 if (ret != LDB_SUCCESS) {
2840 return replmd_replicated_request_error(ar, ret);
2843 replmd_ldb_message_sort(msg, ar->schema);
2845 /* we want to replace the old values */
2846 for (i=0; i < msg->num_elements; i++) {
2847 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2851 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2852 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2856 ret = ldb_build_mod_req(&change_req,
2864 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2866 return ldb_next_request(ar->module, change_req);
2869 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2870 struct ldb_reply *ares)
2872 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2873 struct replmd_replicated_request);
2877 return ldb_module_done(ar->req, NULL, NULL,
2878 LDB_ERR_OPERATIONS_ERROR);
2880 if (ares->error != LDB_SUCCESS &&
2881 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2882 return ldb_module_done(ar->req, ares->controls,
2883 ares->response, ares->error);
2886 switch (ares->type) {
2887 case LDB_REPLY_ENTRY:
2888 ar->search_msg = talloc_steal(ar, ares->message);
2891 case LDB_REPLY_REFERRAL:
2892 /* we ignore referrals */
2895 case LDB_REPLY_DONE:
2896 if (ar->search_msg != NULL) {
2897 ret = replmd_replicated_apply_merge(ar);
2899 ret = replmd_replicated_apply_add(ar);
2901 if (ret != LDB_SUCCESS) {
2902 return ldb_module_done(ar->req, NULL, NULL, ret);
2910 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2912 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2914 struct ldb_context *ldb;
2918 struct ldb_request *search_req;
2919 struct ldb_search_options_control *options;
2921 if (ar->index_current >= ar->objs->num_objects) {
2922 /* done with it, go to next stage */
2923 return replmd_replicated_uptodate_vector(ar);
2926 ldb = ldb_module_get_ctx(ar->module);
2927 ar->search_msg = NULL;
2929 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2930 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2932 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2933 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2934 talloc_free(tmp_str);
2936 ret = ldb_build_search_req(&search_req,
2945 replmd_replicated_apply_search_callback,
2948 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2949 if (ret != LDB_SUCCESS) {
2953 /* we need to cope with cross-partition links, so search for
2954 the GUID over all partitions */
2955 options = talloc(search_req, struct ldb_search_options_control);
2956 if (options == NULL) {
2957 DEBUG(0, (__location__ ": out of memory\n"));
2958 return LDB_ERR_OPERATIONS_ERROR;
2960 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2962 ret = ldb_request_add_control(search_req,
2963 LDB_CONTROL_SEARCH_OPTIONS_OID,
2965 if (ret != LDB_SUCCESS) {
2969 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2971 return ldb_next_request(ar->module, search_req);
2974 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2975 struct ldb_reply *ares)
2977 struct ldb_context *ldb;
2978 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2979 struct replmd_replicated_request);
2980 ldb = ldb_module_get_ctx(ar->module);
2983 return ldb_module_done(ar->req, NULL, NULL,
2984 LDB_ERR_OPERATIONS_ERROR);
2986 if (ares->error != LDB_SUCCESS) {
2987 return ldb_module_done(ar->req, ares->controls,
2988 ares->response, ares->error);
2991 if (ares->type != LDB_REPLY_DONE) {
2992 ldb_set_errstring(ldb, "Invalid reply type\n!");
2993 return ldb_module_done(ar->req, NULL, NULL,
2994 LDB_ERR_OPERATIONS_ERROR);
2999 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3002 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3004 struct ldb_context *ldb;
3005 struct ldb_request *change_req;
3006 enum ndr_err_code ndr_err;
3007 struct ldb_message *msg;
3008 struct replUpToDateVectorBlob ouv;
3009 const struct ldb_val *ouv_value;
3010 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3011 struct replUpToDateVectorBlob nuv;
3012 struct ldb_val nuv_value;
3013 struct ldb_message_element *nuv_el = NULL;
3014 const struct GUID *our_invocation_id;
3015 struct ldb_message_element *orf_el = NULL;
3016 struct repsFromToBlob nrf;
3017 struct ldb_val *nrf_value = NULL;
3018 struct ldb_message_element *nrf_el = NULL;
3021 time_t t = time(NULL);
3025 ldb = ldb_module_get_ctx(ar->module);
3026 ruv = ar->objs->uptodateness_vector;
3032 unix_to_nt_time(&now, t);
3035 * first create the new replUpToDateVector
3037 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
3039 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
3040 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
3041 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3042 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3043 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3044 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3047 if (ouv.version != 2) {
3048 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3053 * the new uptodateness vector will at least
3054 * contain 1 entry, one for the source_dsa
3056 * plus optional values from our old vector and the one from the source_dsa
3058 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
3059 if (ruv) nuv.ctr.ctr2.count += ruv->count;
3060 nuv.ctr.ctr2.cursors = talloc_array(ar,
3061 struct drsuapi_DsReplicaCursor2,
3062 nuv.ctr.ctr2.count);
3063 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3065 /* first copy the old vector */
3066 for (i=0; i < ouv.ctr.ctr2.count; i++) {
3067 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
3071 /* get our invocation_id if we have one already attached to the ldb */
3072 our_invocation_id = samdb_ntds_invocation_id(ldb);
3074 /* merge in the source_dsa vector is available */
3075 for (i=0; (ruv && i < ruv->count); i++) {
3078 if (our_invocation_id &&
3079 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3080 our_invocation_id)) {
3084 for (j=0; j < ni; j++) {
3085 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3086 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3093 * we update only the highest_usn and not the latest_sync_success time,
3094 * because the last success stands for direct replication
3096 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3097 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3102 if (found) continue;
3104 /* if it's not there yet, add it */
3105 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3110 * merge in the current highwatermark for the source_dsa
3113 for (j=0; j < ni; j++) {
3114 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
3115 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3122 * here we update the highest_usn and last_sync_success time
3123 * because we're directly replicating from the source_dsa
3125 * and use the tmp_highest_usn because this is what we have just applied
3128 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3129 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
3134 * here we update the highest_usn and last_sync_success time
3135 * because we're directly replicating from the source_dsa
3137 * and use the tmp_highest_usn because this is what we have just applied
3140 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
3141 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3142 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
3147 * finally correct the size of the cursors array
3149 nuv.ctr.ctr2.count = ni;
3154 qsort(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count,
3155 sizeof(struct drsuapi_DsReplicaCursor2),
3156 (comparison_fn_t)drsuapi_DsReplicaCursor2_compare);
3159 * create the change ldb_message
3161 msg = ldb_msg_new(ar);
3162 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3163 msg->dn = ar->search_msg->dn;
3165 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
3166 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3168 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3169 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3170 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3171 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3173 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3174 if (ret != LDB_SUCCESS) {
3175 return replmd_replicated_request_error(ar, ret);
3177 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3180 * now create the new repsFrom value from the given repsFromTo1 structure
3184 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3185 /* and fix some values... */
3186 nrf.ctr.ctr1.consecutive_sync_failures = 0;
3187 nrf.ctr.ctr1.last_success = now;
3188 nrf.ctr.ctr1.last_attempt = now;
3189 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
3190 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3193 * first see if we already have a repsFrom value for the current source dsa
3194 * if so we'll later replace this value
3196 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3198 for (i=0; i < orf_el->num_values; i++) {
3199 struct repsFromToBlob *trf;
3201 trf = talloc(ar, struct repsFromToBlob);
3202 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3204 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
3205 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3206 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3207 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3208 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3211 if (trf->version != 1) {
3212 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3216 * we compare the source dsa objectGUID not the invocation_id
3217 * because we want only one repsFrom value per source dsa
3218 * and when the invocation_id of the source dsa has changed we don't need
3219 * the old repsFrom with the old invocation_id
3221 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3222 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3228 nrf_value = &orf_el->values[i];
3233 * copy over all old values to the new ldb_message
3235 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3236 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3241 * if we haven't found an old repsFrom value for the current source dsa
3242 * we'll add a new value
3245 struct ldb_val zero_value;
3246 ZERO_STRUCT(zero_value);
3247 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3248 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3250 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3253 /* we now fill the value which is already attached to ldb_message */
3254 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3255 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3257 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3258 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3259 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3260 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3264 * the ldb_message_element for the attribute, has all the old values and the new one
3265 * so we'll replace the whole attribute with all values
3267 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3270 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3271 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3275 /* prepare the ldb_modify() request */
3276 ret = ldb_build_mod_req(&change_req,
3282 replmd_replicated_uptodate_modify_callback,
3284 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3286 return ldb_next_request(ar->module, change_req);
3289 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3290 struct ldb_reply *ares)
3292 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3293 struct replmd_replicated_request);
3297 return ldb_module_done(ar->req, NULL, NULL,
3298 LDB_ERR_OPERATIONS_ERROR);
3300 if (ares->error != LDB_SUCCESS &&
3301 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3302 return ldb_module_done(ar->req, ares->controls,
3303 ares->response, ares->error);
3306 switch (ares->type) {
3307 case LDB_REPLY_ENTRY:
3308 ar->search_msg = talloc_steal(ar, ares->message);
3311 case LDB_REPLY_REFERRAL:
3312 /* we ignore referrals */
3315 case LDB_REPLY_DONE:
3316 if (ar->search_msg == NULL) {
3317 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3319 ret = replmd_replicated_uptodate_modify(ar);
3321 if (ret != LDB_SUCCESS) {
3322 return ldb_module_done(ar->req, NULL, NULL, ret);
3331 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3333 struct ldb_context *ldb;
3335 static const char *attrs[] = {
3336 "replUpToDateVector",
3340 struct ldb_request *search_req;
3342 ldb = ldb_module_get_ctx(ar->module);
3343 ar->search_msg = NULL;
3345 ret = ldb_build_search_req(&search_req,
3348 ar->objs->partition_dn,
3354 replmd_replicated_uptodate_search_callback,
3356 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3358 return ldb_next_request(ar->module, search_req);
3363 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3365 struct ldb_context *ldb;
3366 struct dsdb_extended_replicated_objects *objs;
3367 struct replmd_replicated_request *ar;
3368 struct ldb_control **ctrls;
3370 struct replmd_private *replmd_private =
3371 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3373 ldb = ldb_module_get_ctx(module);
3375 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3377 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3379 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3380 return LDB_ERR_PROTOCOL_ERROR;
3383 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3384 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3385 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3386 return LDB_ERR_PROTOCOL_ERROR;
3389 ar = replmd_ctx_init(module, req);
3391 return LDB_ERR_OPERATIONS_ERROR;
3393 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3394 ar->apply_mode = true;
3396 ar->schema = dsdb_get_schema(ldb);
3398 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3400 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3401 return LDB_ERR_CONSTRAINT_VIOLATION;
3404 ctrls = req->controls;
3406 if (req->controls) {
3407 req->controls = talloc_memdup(ar, req->controls,
3408 talloc_get_size(req->controls));
3409 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3412 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3413 if (ret != LDB_SUCCESS) {
3417 ar->controls = req->controls;
3418 req->controls = ctrls;
3420 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3422 /* save away the linked attributes for the end of the
3424 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3425 struct la_entry *la_entry;
3427 if (replmd_private->la_ctx == NULL) {
3428 replmd_private->la_ctx = talloc_new(replmd_private);
3430 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3431 if (la_entry == NULL) {
3433 return LDB_ERR_OPERATIONS_ERROR;
3435 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3436 if (la_entry->la == NULL) {
3437 talloc_free(la_entry);
3439 return LDB_ERR_OPERATIONS_ERROR;
3441 *la_entry->la = ar->objs->linked_attributes[i];
3443 /* we need to steal the non-scalars so they stay
3444 around until the end of the transaction */
3445 talloc_steal(la_entry->la, la_entry->la->identifier);
3446 talloc_steal(la_entry->la, la_entry->la->value.blob);
3448 DLIST_ADD(replmd_private->la_list, la_entry);
3451 return replmd_replicated_apply_next(ar);
3455 process one linked attribute structure
3457 static int replmd_process_linked_attribute(struct ldb_module *module,
3458 struct la_entry *la_entry)
3460 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3461 struct ldb_context *ldb = ldb_module_get_ctx(module);
3462 struct dsdb_schema *schema = dsdb_get_schema(ldb);
3463 struct ldb_message *msg;
3464 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3466 const struct dsdb_attribute *attr;
3467 struct dsdb_dn *dsdb_dn;
3468 uint64_t seq_num = 0;
3469 struct ldb_message_element *old_el;
3471 time_t t = time(NULL);
3472 struct ldb_result *res;
3473 const char *attrs[2];
3474 struct parsed_dn *pdn_list, *pdn;
3475 struct GUID guid = GUID_zero();
3477 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3478 const struct GUID *our_invocation_id;
3481 linked_attributes[0]:
3482 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3484 identifier: struct drsuapi_DsReplicaObjectIdentifier
3485 __ndr_size : 0x0000003a (58)
3486 __ndr_size_sid : 0x00000000 (0)
3487 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3489 __ndr_size_dn : 0x00000000 (0)
3491 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3492 value: struct drsuapi_DsAttributeValue
3493 __ndr_size : 0x0000007e (126)
3495 blob : DATA_BLOB length=126
3496 flags : 0x00000001 (1)
3497 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3498 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3499 meta_data: struct drsuapi_DsReplicaMetaData
3500 version : 0x00000015 (21)
3501 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3502 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3503 originating_usn : 0x000000000001e19c (123292)
3505 (for cases where the link is to a normal DN)
3506 &target: struct drsuapi_DsReplicaObjectIdentifier3
3507 __ndr_size : 0x0000007e (126)
3508 __ndr_size_sid : 0x0000001c (28)
3509 guid : 7639e594-db75-4086-b0d4-67890ae46031
3510 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3511 __ndr_size_dn : 0x00000022 (34)
3512 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3515 /* find the attribute being modified */
3516 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3518 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3519 talloc_free(tmp_ctx);
3520 return LDB_ERR_OPERATIONS_ERROR;
3523 attrs[0] = attr->lDAPDisplayName;
3526 /* get the existing message from the db for the object with
3527 this GUID, returning attribute being modified. We will then
3528 use this msg as the basis for a modify call */
3529 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3530 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3531 DSDB_SEARCH_SHOW_DELETED |
3532 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3533 DSDB_SEARCH_REVEAL_INTERNALS,
3534 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3535 if (ret != LDB_SUCCESS) {
3536 talloc_free(tmp_ctx);
3539 if (res->count != 1) {
3540 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3541 GUID_string(tmp_ctx, &la->identifier->guid));
3542 talloc_free(tmp_ctx);
3543 return LDB_ERR_NO_SUCH_OBJECT;
3547 if (msg->num_elements == 0) {
3548 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3549 if (ret != LDB_SUCCESS) {
3550 ldb_module_oom(module);
3551 talloc_free(tmp_ctx);
3552 return LDB_ERR_OPERATIONS_ERROR;
3555 old_el = &msg->elements[0];
3556 old_el->flags = LDB_FLAG_MOD_REPLACE;
3559 /* parse the existing links */
3560 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3561 if (ret != LDB_SUCCESS) {
3562 talloc_free(tmp_ctx);
3566 /* get our invocationId */
3567 our_invocation_id = samdb_ntds_invocation_id(ldb);
3568 if (!our_invocation_id) {
3569 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
3570 talloc_free(tmp_ctx);
3571 return LDB_ERR_OPERATIONS_ERROR;
3574 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, our_invocation_id);
3575 if (ret != LDB_SUCCESS) {
3576 talloc_free(tmp_ctx);
3580 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
3581 if (!W_ERROR_IS_OK(status)) {
3582 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
3583 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
3584 return LDB_ERR_OPERATIONS_ERROR;
3587 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3588 if (!NT_STATUS_IS_OK(ntstatus) && active) {
3589 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
3591 ldb_dn_get_linearized(dsdb_dn->dn),
3592 ldb_dn_get_linearized(msg->dn));
3593 return LDB_ERR_OPERATIONS_ERROR;
3596 /* re-resolve the DN by GUID, as the DRS server may give us an
3598 ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn);
3599 if (ret != LDB_SUCCESS) {
3600 ldb_asprintf_errstring(ldb, __location__ ": Failed to re-resolve GUID %s",
3601 GUID_string(tmp_ctx, &guid));
3602 talloc_free(tmp_ctx);
3606 /* see if this link already exists */
3607 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
3609 /* see if this update is newer than what we have already */
3610 struct GUID invocation_id = GUID_zero();
3611 uint32_t version = 0;
3612 NTTIME change_time = 0;
3613 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
3615 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3616 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3617 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3619 if (!replmd_update_is_newer(&invocation_id,
3620 &la->meta_data.originating_invocation_id,
3622 la->meta_data.version,
3624 la->meta_data.originating_change_time)) {
3625 DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3626 old_el->name, ldb_dn_get_linearized(msg->dn),
3627 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3628 talloc_free(tmp_ctx);
3632 /* get a seq_num for this change */
3633 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3634 if (ret != LDB_SUCCESS) {
3635 talloc_free(tmp_ctx);
3639 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
3640 /* remove the existing backlink */
3641 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3642 if (ret != LDB_SUCCESS) {
3643 talloc_free(tmp_ctx);
3648 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3649 &la->meta_data.originating_invocation_id,
3650 la->meta_data.originating_usn, seq_num,
3651 la->meta_data.originating_change_time,
3652 la->meta_data.version,
3654 if (ret != LDB_SUCCESS) {
3655 talloc_free(tmp_ctx);
3660 /* add the new backlink */
3661 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3662 if (ret != LDB_SUCCESS) {
3663 talloc_free(tmp_ctx);
3668 /* get a seq_num for this change */
3669 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3670 if (ret != LDB_SUCCESS) {
3671 talloc_free(tmp_ctx);
3675 old_el->values = talloc_realloc(msg->elements, old_el->values,
3676 struct ldb_val, old_el->num_values+1);
3677 if (!old_el->values) {
3678 ldb_module_oom(module);
3679 return LDB_ERR_OPERATIONS_ERROR;
3681 old_el->num_values++;
3683 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3684 &la->meta_data.originating_invocation_id,
3685 la->meta_data.originating_usn, seq_num,
3686 la->meta_data.originating_change_time,
3687 la->meta_data.version,
3688 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3689 if (ret != LDB_SUCCESS) {
3690 talloc_free(tmp_ctx);
3695 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3697 if (ret != LDB_SUCCESS) {
3698 talloc_free(tmp_ctx);
3704 /* we only change whenChanged and uSNChanged if the seq_num
3706 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3707 talloc_free(tmp_ctx);
3708 return LDB_ERR_OPERATIONS_ERROR;
3711 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3712 talloc_free(tmp_ctx);
3713 return LDB_ERR_OPERATIONS_ERROR;
3716 ret = dsdb_check_single_valued_link(attr, old_el);
3717 if (ret != LDB_SUCCESS) {
3718 talloc_free(tmp_ctx);
3722 ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
3723 if (ret != LDB_SUCCESS) {
3724 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
3726 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3727 talloc_free(tmp_ctx);
3731 talloc_free(tmp_ctx);
3736 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3738 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3739 return replmd_extended_replicated_objects(module, req);
3742 return ldb_next_request(module, req);
3747 we hook into the transaction operations to allow us to
3748 perform the linked attribute updates at the end of the whole
3749 transaction. This allows a forward linked attribute to be created
3750 before the object is created. During a vampire, w2k8 sends us linked
3751 attributes before the objects they are part of.
3753 static int replmd_start_transaction(struct ldb_module *module)
3755 /* create our private structure for this transaction */
3756 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3757 struct replmd_private);
3758 replmd_txn_cleanup(replmd_private);
3760 /* free any leftover mod_usn records from cancelled
3762 while (replmd_private->ncs) {
3763 struct nc_entry *e = replmd_private->ncs;
3764 DLIST_REMOVE(replmd_private->ncs, e);
3768 return ldb_next_start_trans(module);
3772 on prepare commit we loop over our queued la_context structures and
3775 static int replmd_prepare_commit(struct ldb_module *module)
3777 struct replmd_private *replmd_private =
3778 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3779 struct la_entry *la, *prev;
3780 struct la_backlink *bl;
3783 /* walk the list backwards, to do the first entry first, as we
3784 * added the entries with DLIST_ADD() which puts them at the
3785 * start of the list */
3786 DLIST_TAIL(replmd_private->la_list,la);
3787 for (; la; la=prev) {
3788 prev = DLIST_PREV(la);
3789 DLIST_REMOVE(replmd_private->la_list, la);
3790 ret = replmd_process_linked_attribute(module, la);
3791 if (ret != LDB_SUCCESS) {
3792 replmd_txn_cleanup(replmd_private);
3797 /* process our backlink list, creating and deleting backlinks
3799 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3800 ret = replmd_process_backlink(module, bl);
3801 if (ret != LDB_SUCCESS) {
3802 replmd_txn_cleanup(replmd_private);
3807 replmd_txn_cleanup(replmd_private);
3809 /* possibly change @REPLCHANGED */
3810 ret = replmd_notify_store(module);
3811 if (ret != LDB_SUCCESS) {
3815 return ldb_next_prepare_commit(module);
3818 static int replmd_del_transaction(struct ldb_module *module)
3820 struct replmd_private *replmd_private =
3821 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3822 replmd_txn_cleanup(replmd_private);
3824 return ldb_next_del_trans(module);
3828 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3829 .name = "repl_meta_data",
3830 .init_context = replmd_init,
3832 .modify = replmd_modify,
3833 .rename = replmd_rename,
3834 .del = replmd_delete,
3835 .extended = replmd_extended,
3836 .start_transaction = replmd_start_transaction,
3837 .prepare_commit = replmd_prepare_commit,
3838 .del_transaction = replmd_del_transaction,