4 Copyright (C) Simo Sorce 2004-2008
5 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6 Copyright (C) Andrew Tridgell 2005
7 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 * Component: ldb repl_meta_data module
28 * Description: - add a unique objectGUID onto every new record,
29 * - handle whenCreated, whenChanged timestamps
30 * - handle uSNCreated, uSNChanged numbers
31 * - handle replPropertyMetaData attribute
34 * Author: Stefan Metzmacher
38 #include "ldb_module.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "dsdb/common/proto.h"
41 #include "../libds/common/flags.h"
42 #include "librpc/gen_ndr/ndr_misc.h"
43 #include "librpc/gen_ndr/ndr_drsuapi.h"
44 #include "librpc/gen_ndr/ndr_drsblobs.h"
45 #include "param/param.h"
46 #include "libcli/security/dom_sid.h"
47 #include "lib/util/dlinklist.h"
48 #include "dsdb/samdb/ldb_modules/util.h"
49 #include "lib/util/binsearch.h"
50 #include "libcli/security/security.h"
51 #include "lib/util/tsort.h"
53 #define W2K3_LINKED_ATTRIBUTES 1
55 struct replmd_private {
57 struct la_entry *la_list;
59 struct la_backlink *la_backlinks;
61 struct nc_entry *prev, *next;
64 uint64_t mod_usn_urgent;
69 struct la_entry *next, *prev;
70 struct drsuapi_DsReplicaLinkedAttribute *la;
73 struct replmd_replicated_request {
74 struct ldb_module *module;
75 struct ldb_request *req;
77 const struct dsdb_schema *schema;
79 /* the controls we pass down */
80 struct ldb_control **controls;
82 /* details for the mode where we apply a bunch of inbound replication meessages */
84 uint32_t index_current;
85 struct dsdb_extended_replicated_objects *objs;
87 struct ldb_message *search_msg;
93 enum urgent_situation {
94 REPL_URGENT_ON_CREATE = 1,
95 REPL_URGENT_ON_UPDATE = 2,
96 REPL_URGENT_ON_DELETE = 4
100 static const struct {
101 const char *update_name;
102 enum urgent_situation repl_situation;
103 } urgent_objects[] = {
104 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
105 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
106 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
107 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
108 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
109 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
113 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
114 static const char *urgent_attrs[] = {
117 "userAccountControl",
122 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
123 enum urgent_situation situation)
126 for (i=0; urgent_objects[i].update_name; i++) {
128 if ((situation & urgent_objects[i].repl_situation) == 0) {
132 for (j=0; j<objectclass_el->num_values; j++) {
133 const struct ldb_val *v = &objectclass_el->values[j];
134 if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
142 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
144 if (ldb_attr_in_list(urgent_attrs, el->name)) {
151 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
154 initialise the module
155 allocate the private structure and build the list
156 of partition DNs for use by replmd_notify()
158 static int replmd_init(struct ldb_module *module)
160 struct replmd_private *replmd_private;
161 struct ldb_context *ldb = ldb_module_get_ctx(module);
163 replmd_private = talloc_zero(module, struct replmd_private);
164 if (replmd_private == NULL) {
166 return LDB_ERR_OPERATIONS_ERROR;
168 ldb_module_set_private(module, replmd_private);
170 return ldb_next_init(module);
174 cleanup our per-transaction contexts
176 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
178 talloc_free(replmd_private->la_ctx);
179 replmd_private->la_list = NULL;
180 replmd_private->la_ctx = NULL;
182 talloc_free(replmd_private->bl_ctx);
183 replmd_private->la_backlinks = NULL;
184 replmd_private->bl_ctx = NULL;
189 struct la_backlink *next, *prev;
190 const char *attr_name;
191 struct GUID forward_guid, target_guid;
196 process a backlinks we accumulated during a transaction, adding and
197 deleting the backlinks from the target objects
199 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl)
201 struct ldb_dn *target_dn, *source_dn;
203 struct ldb_context *ldb = ldb_module_get_ctx(module);
204 struct ldb_message *msg;
205 TALLOC_CTX *tmp_ctx = talloc_new(bl);
211 - construct ldb_message
212 - either an add or a delete
214 ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn);
215 if (ret != LDB_SUCCESS) {
216 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
217 GUID_string(bl, &bl->target_guid)));
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 /* Ensure the schema does not go away before the bl->attr_name is used */
325 if (!talloc_reference(bl, schema)) {
327 ldb_module_oom(module);
328 return LDB_ERR_OPERATIONS_ERROR;
331 bl->attr_name = target_attr->lDAPDisplayName;
332 bl->forward_guid = *forward_guid;
333 bl->target_guid = *target_guid;
336 /* the caller may ask for this backlink to be processed
339 int ret = replmd_process_backlink(module, bl);
344 DLIST_ADD(replmd_private->la_backlinks, bl);
351 * Callback for most write operations in this module:
353 * notify the repl task that a object has changed. The notifies are
354 * gathered up in the replmd_private structure then written to the
355 * @REPLCHANGED object in each partition during the prepare_commit
357 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
360 struct replmd_replicated_request *ac =
361 talloc_get_type_abort(req->context, struct replmd_replicated_request);
362 struct replmd_private *replmd_private =
363 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
364 struct nc_entry *modified_partition;
365 struct ldb_control *partition_ctrl;
366 const struct dsdb_control_current_partition *partition;
368 struct ldb_control **controls;
370 partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
372 /* Remove the 'partition' control from what we pass up the chain */
373 controls = controls_except_specified(ares->controls, ares, partition_ctrl);
375 if (ares->error != LDB_SUCCESS) {
376 return ldb_module_done(ac->req, controls,
377 ares->response, ares->error);
380 if (ares->type != LDB_REPLY_DONE) {
381 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
382 return ldb_module_done(ac->req, NULL,
383 NULL, LDB_ERR_OPERATIONS_ERROR);
386 if (!partition_ctrl) {
387 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
388 return ldb_module_done(ac->req, NULL,
389 NULL, LDB_ERR_OPERATIONS_ERROR);
392 partition = talloc_get_type_abort(partition_ctrl->data,
393 struct dsdb_control_current_partition);
395 if (ac->seq_num > 0) {
396 for (modified_partition = replmd_private->ncs; modified_partition;
397 modified_partition = modified_partition->next) {
398 if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
403 if (modified_partition == NULL) {
404 modified_partition = talloc_zero(replmd_private, struct nc_entry);
405 if (!modified_partition) {
406 ldb_oom(ldb_module_get_ctx(ac->module));
407 return ldb_module_done(ac->req, NULL,
408 NULL, LDB_ERR_OPERATIONS_ERROR);
410 modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
411 if (!modified_partition->dn) {
412 ldb_oom(ldb_module_get_ctx(ac->module));
413 return ldb_module_done(ac->req, NULL,
414 NULL, LDB_ERR_OPERATIONS_ERROR);
416 DLIST_ADD(replmd_private->ncs, modified_partition);
419 if (ac->seq_num > modified_partition->mod_usn) {
420 modified_partition->mod_usn = ac->seq_num;
422 modified_partition->mod_usn_urgent = ac->seq_num;
427 if (ac->apply_mode) {
431 ret = replmd_replicated_apply_next(ac);
432 if (ret != LDB_SUCCESS) {
433 return ldb_module_done(ac->req, NULL, NULL, ret);
437 /* free the partition control container here, for the
438 * common path. Other cases will have it cleaned up
439 * eventually with the ares */
440 talloc_free(partition_ctrl);
441 return ldb_module_done(ac->req,
442 controls_except_specified(controls, ares, partition_ctrl),
443 ares->response, LDB_SUCCESS);
449 * update a @REPLCHANGED record in each partition if there have been
450 * any writes of replicated data in the partition
452 static int replmd_notify_store(struct ldb_module *module)
454 struct replmd_private *replmd_private =
455 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
457 while (replmd_private->ncs) {
459 struct nc_entry *modified_partition = replmd_private->ncs;
461 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
462 modified_partition->mod_usn,
463 modified_partition->mod_usn_urgent);
464 if (ret != LDB_SUCCESS) {
465 DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
466 ldb_dn_get_linearized(modified_partition->dn)));
469 DLIST_REMOVE(replmd_private->ncs, modified_partition);
470 talloc_free(modified_partition);
478 created a replmd_replicated_request context
480 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
481 struct ldb_request *req)
483 struct ldb_context *ldb;
484 struct replmd_replicated_request *ac;
486 ldb = ldb_module_get_ctx(module);
488 ac = talloc_zero(req, struct replmd_replicated_request);
497 ac->schema = dsdb_get_schema(ldb, ac);
499 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
500 "replmd_modify: no dsdb_schema loaded");
501 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
509 add a time element to a record
511 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
513 struct ldb_message_element *el;
516 if (ldb_msg_find_element(msg, attr) != NULL) {
520 s = ldb_timestring(msg, t);
522 return LDB_ERR_OPERATIONS_ERROR;
525 if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
526 return LDB_ERR_OPERATIONS_ERROR;
529 el = ldb_msg_find_element(msg, attr);
530 /* always set as replace. This works because on add ops, the flag
532 el->flags = LDB_FLAG_MOD_REPLACE;
538 add a uint64_t element to a record
540 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
542 struct ldb_message_element *el;
544 if (ldb_msg_find_element(msg, attr) != NULL) {
548 if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
549 return LDB_ERR_OPERATIONS_ERROR;
552 el = ldb_msg_find_element(msg, attr);
553 /* always set as replace. This works because on add ops, the flag
555 el->flags = LDB_FLAG_MOD_REPLACE;
560 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
561 const struct replPropertyMetaData1 *m2,
562 const uint32_t *rdn_attid)
564 if (m1->attid == m2->attid) {
569 * the rdn attribute should be at the end!
570 * so we need to return a value greater than zero
571 * which means m1 is greater than m2
573 if (m1->attid == *rdn_attid) {
578 * the rdn attribute should be at the end!
579 * so we need to return a value less than zero
580 * which means m2 is greater than m1
582 if (m2->attid == *rdn_attid) {
586 return m1->attid > m2->attid ? 1 : -1;
589 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
590 const struct dsdb_schema *schema,
593 const char *rdn_name;
594 const struct dsdb_attribute *rdn_sa;
596 rdn_name = ldb_dn_get_rdn_name(dn);
598 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
599 return LDB_ERR_OPERATIONS_ERROR;
602 rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
603 if (rdn_sa == NULL) {
604 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
605 return LDB_ERR_OPERATIONS_ERROR;
608 DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
609 rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
611 LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
616 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
617 const struct ldb_message_element *e2,
618 const struct dsdb_schema *schema)
620 const struct dsdb_attribute *a1;
621 const struct dsdb_attribute *a2;
624 * TODO: make this faster by caching the dsdb_attribute pointer
625 * on the ldb_messag_element
628 a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
629 a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
632 * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
636 return strcasecmp(e1->name, e2->name);
638 if (a1->attributeID_id == a2->attributeID_id) {
641 return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
644 static void replmd_ldb_message_sort(struct ldb_message *msg,
645 const struct dsdb_schema *schema)
647 LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
650 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
651 const struct GUID *invocation_id, uint64_t seq_num,
652 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
656 fix up linked attributes in replmd_add.
657 This involves setting up the right meta-data in extended DN
658 components, and creating backlinks to the object
660 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
661 uint64_t seq_num, const struct GUID *invocationId, time_t t,
662 struct GUID *guid, const struct dsdb_attribute *sa)
665 TALLOC_CTX *tmp_ctx = talloc_new(el->values);
666 struct ldb_context *ldb = ldb_module_get_ctx(module);
668 /* We will take a reference to the schema in replmd_add_backlink */
669 const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
672 unix_to_nt_time(&now, t);
674 for (i=0; i<el->num_values; i++) {
675 struct ldb_val *v = &el->values[i];
676 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
677 struct GUID target_guid;
681 /* note that the DN already has the extended
682 components from the extended_dn_store module */
683 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
684 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
685 ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid);
686 if (ret != LDB_SUCCESS) {
687 talloc_free(tmp_ctx);
690 ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
691 if (ret != LDB_SUCCESS) {
692 talloc_free(tmp_ctx);
697 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
698 seq_num, seq_num, now, 0, false);
699 if (ret != LDB_SUCCESS) {
700 talloc_free(tmp_ctx);
704 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
705 if (ret != LDB_SUCCESS) {
706 talloc_free(tmp_ctx);
711 talloc_free(tmp_ctx);
717 intercept add requests
719 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
721 struct ldb_context *ldb;
722 struct ldb_control *control;
723 struct replmd_replicated_request *ac;
724 enum ndr_err_code ndr_err;
725 struct ldb_request *down_req;
726 struct ldb_message *msg;
727 const DATA_BLOB *guid_blob;
729 struct replPropertyMetaDataBlob nmd;
730 struct ldb_val nmd_value;
731 const struct GUID *our_invocation_id;
732 time_t t = time(NULL);
738 bool allow_add_guid = false;
739 bool remove_current_guid = false;
740 bool is_urgent = false;
741 struct ldb_message_element *objectclass_el;
743 /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
744 control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
746 allow_add_guid = true;
749 /* do not manipulate our control entries */
750 if (ldb_dn_is_special(req->op.add.message->dn)) {
751 return ldb_next_request(module, req);
754 ldb = ldb_module_get_ctx(module);
756 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
758 ac = replmd_ctx_init(module, req);
760 return LDB_ERR_OPERATIONS_ERROR;
763 guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
764 if ( guid_blob != NULL ) {
765 if( !allow_add_guid ) {
766 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
767 "replmd_add: it's not allowed to add an object with objectGUID\n");
769 return LDB_ERR_UNWILLING_TO_PERFORM;
771 NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
772 if ( !NT_STATUS_IS_OK(status)) {
773 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
774 "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
776 return LDB_ERR_UNWILLING_TO_PERFORM;
778 /* we remove this attribute as it can be a string and will not be treated
779 correctly and then we will readd it latter on in the good format*/
780 remove_current_guid = true;
784 guid = GUID_random();
787 /* Get a sequence number from the backend */
788 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
789 if (ret != LDB_SUCCESS) {
794 /* get our invocationId */
795 our_invocation_id = samdb_ntds_invocation_id(ldb);
796 if (!our_invocation_id) {
797 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
798 "replmd_add: unable to find invocationId\n");
800 return LDB_ERR_OPERATIONS_ERROR;
803 /* we have to copy the message as the caller might have it as a const */
804 msg = ldb_msg_copy_shallow(ac, req->op.add.message);
808 return LDB_ERR_OPERATIONS_ERROR;
811 /* generated times */
812 unix_to_nt_time(&now, t);
813 time_str = ldb_timestring(msg, t);
817 return LDB_ERR_OPERATIONS_ERROR;
819 if (remove_current_guid) {
820 ldb_msg_remove_attr(msg,"objectGUID");
824 * remove autogenerated attributes
826 ldb_msg_remove_attr(msg, "whenCreated");
827 ldb_msg_remove_attr(msg, "whenChanged");
828 ldb_msg_remove_attr(msg, "uSNCreated");
829 ldb_msg_remove_attr(msg, "uSNChanged");
830 ldb_msg_remove_attr(msg, "replPropertyMetaData");
833 * readd replicated attributes
835 ret = ldb_msg_add_string(msg, "whenCreated", time_str);
836 if (ret != LDB_SUCCESS) {
842 /* build the replication meta_data */
845 nmd.ctr.ctr1.count = msg->num_elements;
846 nmd.ctr.ctr1.array = talloc_array(msg,
847 struct replPropertyMetaData1,
849 if (!nmd.ctr.ctr1.array) {
852 return LDB_ERR_OPERATIONS_ERROR;
855 for (i=0; i < msg->num_elements; i++) {
856 struct ldb_message_element *e = &msg->elements[i];
857 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
858 const struct dsdb_attribute *sa;
860 if (e->name[0] == '@') continue;
862 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
864 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
865 "replmd_add: attribute '%s' not defined in schema\n",
868 return LDB_ERR_NO_SUCH_ATTRIBUTE;
871 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
872 /* if the attribute is not replicated (0x00000001)
873 * or constructed (0x00000004) it has no metadata
878 #if W2K3_LINKED_ATTRIBUTES
879 if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
880 ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa);
881 if (ret != LDB_SUCCESS) {
885 /* linked attributes are not stored in
886 replPropertyMetaData in FL above w2k */
891 m->attid = sa->attributeID_id;
893 m->originating_change_time = now;
894 m->originating_invocation_id = *our_invocation_id;
895 m->originating_usn = ac->seq_num;
896 m->local_usn = ac->seq_num;
900 /* fix meta data count */
901 nmd.ctr.ctr1.count = ni;
904 * sort meta data array, and move the rdn attribute entry to the end
906 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
907 if (ret != LDB_SUCCESS) {
912 /* generated NDR encoded values */
913 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
915 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
916 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
919 return LDB_ERR_OPERATIONS_ERROR;
923 * add the autogenerated values
925 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
926 if (ret != LDB_SUCCESS) {
931 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
932 if (ret != LDB_SUCCESS) {
937 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
938 if (ret != LDB_SUCCESS) {
943 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
944 if (ret != LDB_SUCCESS) {
949 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
950 if (ret != LDB_SUCCESS) {
957 * sort the attributes by attid before storing the object
959 replmd_ldb_message_sort(msg, ac->schema);
961 objectclass_el = ldb_msg_find_element(msg, "objectClass");
962 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
963 REPL_URGENT_ON_CREATE);
965 ac->is_urgent = is_urgent;
966 ret = ldb_build_add_req(&down_req, ldb, ac,
969 ac, replmd_op_callback,
972 if (ret != LDB_SUCCESS) {
977 /* mark the control done */
979 control->critical = 0;
982 /* go on with the call chain */
983 return ldb_next_request(module, down_req);
988 * update the replPropertyMetaData for one element
990 static int replmd_update_rpmd_element(struct ldb_context *ldb,
991 struct ldb_message *msg,
992 struct ldb_message_element *el,
993 struct ldb_message_element *old_el,
994 struct replPropertyMetaDataBlob *omd,
995 const struct dsdb_schema *schema,
997 const struct GUID *our_invocation_id,
1001 const struct dsdb_attribute *a;
1002 struct replPropertyMetaData1 *md1;
1004 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1006 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1008 return LDB_ERR_OPERATIONS_ERROR;
1011 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1015 /* if the attribute's value haven't changed then return LDB_SUCCESS */
1016 if (old_el != NULL && ldb_msg_element_compare(el, old_el) == 0) {
1020 for (i=0; i<omd->ctr.ctr1.count; i++) {
1021 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1024 #if W2K3_LINKED_ATTRIBUTES
1025 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1026 /* linked attributes are not stored in
1027 replPropertyMetaData in FL above w2k, but we do
1028 raise the seqnum for the object */
1029 if (*seq_num == 0 &&
1030 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1031 return LDB_ERR_OPERATIONS_ERROR;
1037 if (i == omd->ctr.ctr1.count) {
1038 /* we need to add a new one */
1039 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1040 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1041 if (omd->ctr.ctr1.array == NULL) {
1043 return LDB_ERR_OPERATIONS_ERROR;
1045 omd->ctr.ctr1.count++;
1046 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1049 /* Get a new sequence number from the backend. We only do this
1050 * if we have a change that requires a new
1051 * replPropertyMetaData element
1053 if (*seq_num == 0) {
1054 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1055 if (ret != LDB_SUCCESS) {
1056 return LDB_ERR_OPERATIONS_ERROR;
1060 md1 = &omd->ctr.ctr1.array[i];
1062 md1->attid = a->attributeID_id;
1063 md1->originating_change_time = now;
1064 md1->originating_invocation_id = *our_invocation_id;
1065 md1->originating_usn = *seq_num;
1066 md1->local_usn = *seq_num;
1072 * update the replPropertyMetaData object each time we modify an
1073 * object. This is needed for DRS replication, as the merge on the
1074 * client is based on this object
1076 static int replmd_update_rpmd(struct ldb_module *module,
1077 const struct dsdb_schema *schema,
1078 struct ldb_request *req,
1079 struct ldb_message *msg, uint64_t *seq_num,
1083 const struct ldb_val *omd_value;
1084 enum ndr_err_code ndr_err;
1085 struct replPropertyMetaDataBlob omd;
1088 const struct GUID *our_invocation_id;
1090 const char *attrs[] = { "replPropertyMetaData", "*", NULL };
1091 struct ldb_result *res;
1092 struct ldb_context *ldb;
1093 struct ldb_message_element *objectclass_el;
1094 enum urgent_situation situation;
1097 ldb = ldb_module_get_ctx(module);
1099 our_invocation_id = samdb_ntds_invocation_id(ldb);
1100 if (!our_invocation_id) {
1101 /* this happens during an initial vampire while
1102 updating the schema */
1103 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1107 unix_to_nt_time(&now, t);
1109 /* search for the existing replPropertyMetaDataBlob. We need
1110 * to use REVEAL and ask for DNs in storage format to support
1111 * the check for values being the same in
1112 * replmd_update_rpmd_element()
1114 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1115 DSDB_SEARCH_SHOW_DELETED |
1116 DSDB_SEARCH_SHOW_EXTENDED_DN |
1117 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1118 DSDB_SEARCH_REVEAL_INTERNALS);
1119 if (ret != LDB_SUCCESS || res->count != 1) {
1120 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1121 ldb_dn_get_linearized(msg->dn)));
1122 return LDB_ERR_OPERATIONS_ERROR;
1125 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1126 * otherwise we consider we are updating */
1127 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1128 situation = REPL_URGENT_ON_DELETE;
1130 situation = REPL_URGENT_ON_UPDATE;
1133 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1134 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1139 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1141 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1142 ldb_dn_get_linearized(msg->dn)));
1143 return LDB_ERR_OPERATIONS_ERROR;
1146 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1147 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1148 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1149 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1150 ldb_dn_get_linearized(msg->dn)));
1151 return LDB_ERR_OPERATIONS_ERROR;
1154 if (omd.version != 1) {
1155 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1156 omd.version, ldb_dn_get_linearized(msg->dn)));
1157 return LDB_ERR_OPERATIONS_ERROR;
1160 /*we have elements that will be modified*/
1161 if (msg->num_elements > 0) {
1162 /*if we are RODC and this is a DRSR update then its ok*/
1163 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1164 ret = samdb_rodc(ldb, &rodc);
1165 if (ret != LDB_SUCCESS) {
1166 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1168 ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n");
1169 return LDB_ERR_REFERRAL;
1174 for (i=0; i<msg->num_elements; i++) {
1175 struct ldb_message_element *old_el;
1176 old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1177 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1178 our_invocation_id, now);
1179 if (ret != LDB_SUCCESS) {
1183 if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1184 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1190 * replmd_update_rpmd_element has done an update if the
1193 if (*seq_num != 0) {
1194 struct ldb_val *md_value;
1195 struct ldb_message_element *el;
1197 md_value = talloc(msg, struct ldb_val);
1198 if (md_value == NULL) {
1200 return LDB_ERR_OPERATIONS_ERROR;
1203 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1204 if (ret != LDB_SUCCESS) {
1208 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1209 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1210 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1211 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1212 ldb_dn_get_linearized(msg->dn)));
1213 return LDB_ERR_OPERATIONS_ERROR;
1216 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1217 if (ret != LDB_SUCCESS) {
1218 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1219 ldb_dn_get_linearized(msg->dn)));
1224 el->values = md_value;
1231 struct dsdb_dn *dsdb_dn;
1236 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1238 return GUID_compare(pdn1->guid, pdn2->guid);
1241 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid, struct ldb_dn *dn)
1243 struct parsed_dn *ret;
1244 if (dn && GUID_all_zero(guid)) {
1245 /* when updating a link using DRS, we sometimes get a
1246 NULL GUID. We then need to try and match by DN */
1248 for (i=0; i<count; i++) {
1249 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1250 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1256 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1261 get a series of message element values as an array of DNs and GUIDs
1262 the result is sorted by GUID
1264 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1265 struct ldb_message_element *el, struct parsed_dn **pdn,
1266 const char *ldap_oid)
1269 struct ldb_context *ldb = ldb_module_get_ctx(module);
1276 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1278 ldb_module_oom(module);
1279 return LDB_ERR_OPERATIONS_ERROR;
1282 for (i=0; i<el->num_values; i++) {
1283 struct ldb_val *v = &el->values[i];
1286 struct parsed_dn *p;
1290 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1291 if (p->dsdb_dn == NULL) {
1292 return LDB_ERR_INVALID_DN_SYNTAX;
1295 dn = p->dsdb_dn->dn;
1297 p->guid = talloc(*pdn, struct GUID);
1298 if (p->guid == NULL) {
1299 ldb_module_oom(module);
1300 return LDB_ERR_OPERATIONS_ERROR;
1303 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1304 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1305 /* we got a DN without a GUID - go find the GUID */
1306 int ret = dsdb_module_guid_by_dn(module, dn, p->guid);
1307 if (ret != LDB_SUCCESS) {
1308 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1309 ldb_dn_get_linearized(dn));
1312 ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1313 if (ret != LDB_SUCCESS) {
1316 } else if (!NT_STATUS_IS_OK(status)) {
1317 return LDB_ERR_OPERATIONS_ERROR;
1320 /* keep a pointer to the original ldb_val */
1324 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1330 build a new extended DN, including all meta data fields
1332 RMD_FLAGS = DSDB_RMD_FLAG_* bits
1333 RMD_ADDTIME = originating_add_time
1334 RMD_INVOCID = originating_invocation_id
1335 RMD_CHANGETIME = originating_change_time
1336 RMD_ORIGINATING_USN = originating_usn
1337 RMD_LOCAL_USN = local_usn
1338 RMD_VERSION = version
1340 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1341 const struct GUID *invocation_id, uint64_t seq_num,
1342 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1344 struct ldb_dn *dn = dsdb_dn->dn;
1345 const char *tstring, *usn_string, *flags_string;
1346 struct ldb_val tval;
1348 struct ldb_val usnv, local_usnv;
1349 struct ldb_val vers, flagsv;
1352 const char *dnstring;
1354 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1356 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1358 return LDB_ERR_OPERATIONS_ERROR;
1360 tval = data_blob_string_const(tstring);
1362 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1364 return LDB_ERR_OPERATIONS_ERROR;
1366 usnv = data_blob_string_const(usn_string);
1368 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1370 return LDB_ERR_OPERATIONS_ERROR;
1372 local_usnv = data_blob_string_const(usn_string);
1374 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1376 return LDB_ERR_OPERATIONS_ERROR;
1378 vers = data_blob_string_const(vstring);
1380 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1381 if (!NT_STATUS_IS_OK(status)) {
1382 return LDB_ERR_OPERATIONS_ERROR;
1385 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1386 if (!flags_string) {
1387 return LDB_ERR_OPERATIONS_ERROR;
1389 flagsv = data_blob_string_const(flags_string);
1391 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1392 if (ret != LDB_SUCCESS) return ret;
1393 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1394 if (ret != LDB_SUCCESS) return ret;
1395 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1396 if (ret != LDB_SUCCESS) return ret;
1397 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1398 if (ret != LDB_SUCCESS) return ret;
1399 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1400 if (ret != LDB_SUCCESS) return ret;
1401 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1402 if (ret != LDB_SUCCESS) return ret;
1403 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1404 if (ret != LDB_SUCCESS) return ret;
1406 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1407 if (dnstring == NULL) {
1408 return LDB_ERR_OPERATIONS_ERROR;
1410 *v = data_blob_string_const(dnstring);
1415 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1416 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1417 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1418 uint32_t version, bool deleted);
1421 check if any links need upgrading from w2k format
1423 The parent_ctx is the ldb_message_element which contains the values array that dns[i].v points at, and which should be used for allocating any new value.
1425 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1428 for (i=0; i<count; i++) {
1433 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1434 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1438 /* it's an old one that needs upgrading */
1439 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1441 if (ret != LDB_SUCCESS) {
1449 update an extended DN, including all meta data fields
1451 see replmd_build_la_val for value names
1453 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1454 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1455 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1456 uint32_t version, bool deleted)
1458 struct ldb_dn *dn = dsdb_dn->dn;
1459 const char *tstring, *usn_string, *flags_string;
1460 struct ldb_val tval;
1462 struct ldb_val usnv, local_usnv;
1463 struct ldb_val vers, flagsv;
1464 const struct ldb_val *old_addtime;
1465 uint32_t old_version;
1468 const char *dnstring;
1470 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1472 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1474 return LDB_ERR_OPERATIONS_ERROR;
1476 tval = data_blob_string_const(tstring);
1478 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1480 return LDB_ERR_OPERATIONS_ERROR;
1482 usnv = data_blob_string_const(usn_string);
1484 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1486 return LDB_ERR_OPERATIONS_ERROR;
1488 local_usnv = data_blob_string_const(usn_string);
1490 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1491 if (!NT_STATUS_IS_OK(status)) {
1492 return LDB_ERR_OPERATIONS_ERROR;
1495 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1496 if (!flags_string) {
1497 return LDB_ERR_OPERATIONS_ERROR;
1499 flagsv = data_blob_string_const(flags_string);
1501 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1502 if (ret != LDB_SUCCESS) return ret;
1504 /* get the ADDTIME from the original */
1505 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1506 if (old_addtime == NULL) {
1507 old_addtime = &tval;
1509 if (dsdb_dn != old_dsdb_dn) {
1510 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1511 if (ret != LDB_SUCCESS) return ret;
1514 /* use our invocation id */
1515 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1516 if (ret != LDB_SUCCESS) return ret;
1518 /* changetime is the current time */
1519 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1520 if (ret != LDB_SUCCESS) return ret;
1522 /* update the USN */
1523 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1524 if (ret != LDB_SUCCESS) return ret;
1526 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1527 if (ret != LDB_SUCCESS) return ret;
1529 /* increase the version by 1 */
1530 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1531 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1532 version = old_version+1;
1534 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1535 vers = data_blob_string_const(vstring);
1536 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1537 if (ret != LDB_SUCCESS) return ret;
1539 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1540 if (dnstring == NULL) {
1541 return LDB_ERR_OPERATIONS_ERROR;
1543 *v = data_blob_string_const(dnstring);
1549 handle adding a linked attribute
1551 static int replmd_modify_la_add(struct ldb_module *module,
1552 const struct dsdb_schema *schema,
1553 struct ldb_message *msg,
1554 struct ldb_message_element *el,
1555 struct ldb_message_element *old_el,
1556 const struct dsdb_attribute *schema_attr,
1559 struct GUID *msg_guid)
1562 struct parsed_dn *dns, *old_dns;
1563 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1565 struct ldb_val *new_values = NULL;
1566 unsigned int num_new_values = 0;
1567 unsigned old_num_values = old_el?old_el->num_values:0;
1568 const struct GUID *invocation_id;
1569 struct ldb_context *ldb = ldb_module_get_ctx(module);
1572 unix_to_nt_time(&now, t);
1574 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1575 if (ret != LDB_SUCCESS) {
1576 talloc_free(tmp_ctx);
1580 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1581 if (ret != LDB_SUCCESS) {
1582 talloc_free(tmp_ctx);
1586 invocation_id = samdb_ntds_invocation_id(ldb);
1587 if (!invocation_id) {
1588 talloc_free(tmp_ctx);
1589 return LDB_ERR_OPERATIONS_ERROR;
1592 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1593 if (ret != LDB_SUCCESS) {
1594 talloc_free(tmp_ctx);
1598 /* for each new value, see if it exists already with the same GUID */
1599 for (i=0; i<el->num_values; i++) {
1600 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1602 /* this is a new linked attribute value */
1603 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1604 if (new_values == NULL) {
1605 ldb_module_oom(module);
1606 talloc_free(tmp_ctx);
1607 return LDB_ERR_OPERATIONS_ERROR;
1609 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1610 invocation_id, seq_num, seq_num, now, 0, false);
1611 if (ret != LDB_SUCCESS) {
1612 talloc_free(tmp_ctx);
1617 /* this is only allowed if the GUID was
1618 previously deleted. */
1619 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1621 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1622 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1623 el->name, GUID_string(tmp_ctx, p->guid));
1624 talloc_free(tmp_ctx);
1625 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1627 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1628 invocation_id, seq_num, seq_num, now, 0, false);
1629 if (ret != LDB_SUCCESS) {
1630 talloc_free(tmp_ctx);
1635 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1636 if (ret != LDB_SUCCESS) {
1637 talloc_free(tmp_ctx);
1642 /* add the new ones on to the end of the old values, constructing a new el->values */
1643 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1645 old_num_values+num_new_values);
1646 if (el->values == NULL) {
1647 ldb_module_oom(module);
1648 return LDB_ERR_OPERATIONS_ERROR;
1651 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1652 el->num_values = old_num_values + num_new_values;
1654 talloc_steal(msg->elements, el->values);
1655 talloc_steal(el->values, new_values);
1657 talloc_free(tmp_ctx);
1659 /* we now tell the backend to replace all existing values
1660 with the one we have constructed */
1661 el->flags = LDB_FLAG_MOD_REPLACE;
1668 handle deleting all active linked attributes
1670 static int replmd_modify_la_delete(struct ldb_module *module,
1671 const struct dsdb_schema *schema,
1672 struct ldb_message *msg,
1673 struct ldb_message_element *el,
1674 struct ldb_message_element *old_el,
1675 const struct dsdb_attribute *schema_attr,
1678 struct GUID *msg_guid)
1681 struct parsed_dn *dns, *old_dns;
1682 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1684 const struct GUID *invocation_id;
1685 struct ldb_context *ldb = ldb_module_get_ctx(module);
1688 unix_to_nt_time(&now, t);
1690 /* check if there is nothing to delete */
1691 if ((!old_el || old_el->num_values == 0) &&
1692 el->num_values == 0) {
1696 if (!old_el || old_el->num_values == 0) {
1697 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1700 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1701 if (ret != LDB_SUCCESS) {
1702 talloc_free(tmp_ctx);
1706 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1707 if (ret != LDB_SUCCESS) {
1708 talloc_free(tmp_ctx);
1712 invocation_id = samdb_ntds_invocation_id(ldb);
1713 if (!invocation_id) {
1714 return LDB_ERR_OPERATIONS_ERROR;
1717 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1718 if (ret != LDB_SUCCESS) {
1719 talloc_free(tmp_ctx);
1725 /* see if we are being asked to delete any links that
1726 don't exist or are already deleted */
1727 for (i=0; i<el->num_values; i++) {
1728 struct parsed_dn *p = &dns[i];
1729 struct parsed_dn *p2;
1732 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1734 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1735 el->name, GUID_string(tmp_ctx, p->guid));
1736 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1738 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1739 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1740 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1741 el->name, GUID_string(tmp_ctx, p->guid));
1742 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1746 /* for each new value, see if it exists already with the same GUID
1747 if it is not already deleted and matches the delete list then delete it
1749 for (i=0; i<old_el->num_values; i++) {
1750 struct parsed_dn *p = &old_dns[i];
1753 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1757 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1758 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1760 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1761 invocation_id, seq_num, seq_num, now, 0, true);
1762 if (ret != LDB_SUCCESS) {
1763 talloc_free(tmp_ctx);
1767 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1768 if (ret != LDB_SUCCESS) {
1769 talloc_free(tmp_ctx);
1774 el->values = talloc_steal(msg->elements, old_el->values);
1775 el->num_values = old_el->num_values;
1777 talloc_free(tmp_ctx);
1779 /* we now tell the backend to replace all existing values
1780 with the one we have constructed */
1781 el->flags = LDB_FLAG_MOD_REPLACE;
1787 handle replacing a linked attribute
1789 static int replmd_modify_la_replace(struct ldb_module *module,
1790 const struct dsdb_schema *schema,
1791 struct ldb_message *msg,
1792 struct ldb_message_element *el,
1793 struct ldb_message_element *old_el,
1794 const struct dsdb_attribute *schema_attr,
1797 struct GUID *msg_guid)
1800 struct parsed_dn *dns, *old_dns;
1801 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1803 const struct GUID *invocation_id;
1804 struct ldb_context *ldb = ldb_module_get_ctx(module);
1805 struct ldb_val *new_values = NULL;
1806 unsigned int num_new_values = 0;
1807 unsigned int old_num_values = old_el?old_el->num_values:0;
1810 unix_to_nt_time(&now, t);
1812 /* check if there is nothing to replace */
1813 if ((!old_el || old_el->num_values == 0) &&
1814 el->num_values == 0) {
1818 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1819 if (ret != LDB_SUCCESS) {
1820 talloc_free(tmp_ctx);
1824 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1825 if (ret != LDB_SUCCESS) {
1826 talloc_free(tmp_ctx);
1830 invocation_id = samdb_ntds_invocation_id(ldb);
1831 if (!invocation_id) {
1832 return LDB_ERR_OPERATIONS_ERROR;
1835 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1836 if (ret != LDB_SUCCESS) {
1837 talloc_free(tmp_ctx);
1841 /* mark all the old ones as deleted */
1842 for (i=0; i<old_num_values; i++) {
1843 struct parsed_dn *old_p = &old_dns[i];
1844 struct parsed_dn *p;
1845 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1847 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1849 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1850 if (ret != LDB_SUCCESS) {
1851 talloc_free(tmp_ctx);
1855 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1857 /* we don't delete it if we are re-adding it */
1861 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1862 invocation_id, seq_num, seq_num, now, 0, true);
1863 if (ret != LDB_SUCCESS) {
1864 talloc_free(tmp_ctx);
1869 /* for each new value, either update its meta-data, or add it
1872 for (i=0; i<el->num_values; i++) {
1873 struct parsed_dn *p = &dns[i], *old_p;
1876 (old_p = parsed_dn_find(old_dns,
1877 old_num_values, p->guid, NULL)) != NULL) {
1878 /* update in place */
1879 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1880 old_p->dsdb_dn, invocation_id,
1881 seq_num, seq_num, now, 0, false);
1882 if (ret != LDB_SUCCESS) {
1883 talloc_free(tmp_ctx);
1888 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1890 if (new_values == NULL) {
1891 ldb_module_oom(module);
1892 talloc_free(tmp_ctx);
1893 return LDB_ERR_OPERATIONS_ERROR;
1895 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1896 invocation_id, seq_num, seq_num, now, 0, false);
1897 if (ret != LDB_SUCCESS) {
1898 talloc_free(tmp_ctx);
1904 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1905 if (ret != LDB_SUCCESS) {
1906 talloc_free(tmp_ctx);
1911 /* add the new values to the end of old_el */
1912 if (num_new_values != 0) {
1913 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1914 struct ldb_val, old_num_values+num_new_values);
1915 if (el->values == NULL) {
1916 ldb_module_oom(module);
1917 return LDB_ERR_OPERATIONS_ERROR;
1919 memcpy(&el->values[old_num_values], &new_values[0],
1920 sizeof(struct ldb_val)*num_new_values);
1921 el->num_values = old_num_values + num_new_values;
1922 talloc_steal(msg->elements, new_values);
1924 el->values = old_el->values;
1925 el->num_values = old_el->num_values;
1926 talloc_steal(msg->elements, el->values);
1929 talloc_free(tmp_ctx);
1931 /* we now tell the backend to replace all existing values
1932 with the one we have constructed */
1933 el->flags = LDB_FLAG_MOD_REPLACE;
1940 handle linked attributes in modify requests
1942 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1943 struct ldb_message *msg,
1944 uint64_t seq_num, time_t t)
1946 struct ldb_result *res;
1949 struct ldb_context *ldb = ldb_module_get_ctx(module);
1950 struct ldb_message *old_msg;
1952 const struct dsdb_schema *schema;
1953 struct GUID old_guid;
1956 /* there the replmd_update_rpmd code has already
1957 * checked and saw that there are no linked
1962 #if !W2K3_LINKED_ATTRIBUTES
1966 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1967 /* don't do anything special for linked attributes */
1971 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1972 DSDB_SEARCH_SHOW_DELETED |
1973 DSDB_SEARCH_REVEAL_INTERNALS |
1974 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1975 if (ret != LDB_SUCCESS) {
1978 schema = dsdb_get_schema(ldb, res);
1980 return LDB_ERR_OPERATIONS_ERROR;
1983 old_msg = res->msgs[0];
1985 old_guid = samdb_result_guid(old_msg, "objectGUID");
1987 for (i=0; i<msg->num_elements; i++) {
1988 struct ldb_message_element *el = &msg->elements[i];
1989 struct ldb_message_element *old_el, *new_el;
1990 const struct dsdb_attribute *schema_attr
1991 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1993 ldb_asprintf_errstring(ldb,
1994 "attribute %s is not a valid attribute in schema", el->name);
1995 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1997 if (schema_attr->linkID == 0) {
2000 if ((schema_attr->linkID & 1) == 1) {
2001 /* Odd is for the target. Illegal to modify */
2002 ldb_asprintf_errstring(ldb,
2003 "attribute %s must not be modified directly, it is a linked attribute", el->name);
2004 return LDB_ERR_UNWILLING_TO_PERFORM;
2006 old_el = ldb_msg_find_element(old_msg, el->name);
2007 switch (el->flags & LDB_FLAG_MOD_MASK) {
2008 case LDB_FLAG_MOD_REPLACE:
2009 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
2011 case LDB_FLAG_MOD_DELETE:
2012 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
2014 case LDB_FLAG_MOD_ADD:
2015 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
2018 ldb_asprintf_errstring(ldb,
2019 "invalid flags 0x%x for %s linked attribute",
2020 el->flags, el->name);
2021 return LDB_ERR_UNWILLING_TO_PERFORM;
2023 if (ret != LDB_SUCCESS) {
2027 ldb_msg_remove_attr(old_msg, el->name);
2029 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2030 new_el->num_values = el->num_values;
2031 new_el->values = talloc_steal(msg->elements, el->values);
2033 /* TODO: this relises a bit too heavily on the exact
2034 behaviour of ldb_msg_find_element and
2035 ldb_msg_remove_element */
2036 old_el = ldb_msg_find_element(msg, el->name);
2038 ldb_msg_remove_element(msg, old_el);
2049 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2051 struct ldb_context *ldb;
2052 struct replmd_replicated_request *ac;
2053 struct ldb_request *down_req;
2054 struct ldb_message *msg;
2055 time_t t = time(NULL);
2057 bool is_urgent = false;
2058 struct loadparm_context *lp_ctx;
2061 /* do not manipulate our control entries */
2062 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2063 return ldb_next_request(module, req);
2066 ldb = ldb_module_get_ctx(module);
2067 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2068 struct loadparm_context);
2070 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2072 ac = replmd_ctx_init(module, req);
2074 return LDB_ERR_OPERATIONS_ERROR;
2077 /* we have to copy the message as the caller might have it as a const */
2078 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2082 return LDB_ERR_OPERATIONS_ERROR;
2085 ldb_msg_remove_attr(msg, "whenChanged");
2086 ldb_msg_remove_attr(msg, "uSNChanged");
2088 ret = replmd_update_rpmd(module, ac->schema, req, msg, &ac->seq_num, t, &is_urgent);
2089 if (ret == LDB_ERR_REFERRAL) {
2092 referral = talloc_asprintf(req,
2094 lp_dnsdomain(lp_ctx),
2095 ldb_dn_get_linearized(msg->dn));
2096 ret = ldb_module_send_referral(req, referral);
2097 return ldb_module_done(req, NULL, NULL, ret);
2100 if (ret != LDB_SUCCESS) {
2105 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
2106 if (ret != LDB_SUCCESS) {
2112 * - replace the old object with the newly constructed one
2115 ac->is_urgent = is_urgent;
2117 ret = ldb_build_mod_req(&down_req, ldb, ac,
2120 ac, replmd_op_callback,
2122 if (ret != LDB_SUCCESS) {
2126 talloc_steal(down_req, msg);
2128 /* we only change whenChanged and uSNChanged if the seq_num
2130 if (ac->seq_num != 0) {
2131 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2136 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2142 /* go on with the call chain */
2143 return ldb_next_request(module, down_req);
2146 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2149 handle a rename request
2151 On a rename we need to do an extra ldb_modify which sets the
2152 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2154 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2156 struct ldb_context *ldb;
2157 struct replmd_replicated_request *ac;
2159 struct ldb_request *down_req;
2161 /* do not manipulate our control entries */
2162 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2163 return ldb_next_request(module, req);
2166 ldb = ldb_module_get_ctx(module);
2168 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2170 ac = replmd_ctx_init(module, req);
2172 return LDB_ERR_OPERATIONS_ERROR;
2174 ret = ldb_build_rename_req(&down_req, ldb, ac,
2175 ac->req->op.rename.olddn,
2176 ac->req->op.rename.newdn,
2178 ac, replmd_rename_callback,
2181 if (ret != LDB_SUCCESS) {
2186 /* go on with the call chain */
2187 return ldb_next_request(module, down_req);
2190 /* After the rename is compleated, update the whenchanged etc */
2191 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2193 struct ldb_context *ldb;
2194 struct replmd_replicated_request *ac;
2195 struct ldb_request *down_req;
2196 struct ldb_message *msg;
2197 time_t t = time(NULL);
2200 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2201 ldb = ldb_module_get_ctx(ac->module);
2203 if (ares->error != LDB_SUCCESS) {
2204 return ldb_module_done(ac->req, ares->controls,
2205 ares->response, ares->error);
2208 if (ares->type != LDB_REPLY_DONE) {
2209 ldb_set_errstring(ldb,
2210 "invalid ldb_reply_type in callback");
2212 return ldb_module_done(ac->req, NULL, NULL,
2213 LDB_ERR_OPERATIONS_ERROR);
2216 /* Get a sequence number from the backend */
2217 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2218 if (ret != LDB_SUCCESS) {
2223 * - replace the old object with the newly constructed one
2226 msg = ldb_msg_new(ac);
2229 return LDB_ERR_OPERATIONS_ERROR;
2232 msg->dn = ac->req->op.rename.newdn;
2234 ret = ldb_build_mod_req(&down_req, ldb, ac,
2237 ac, replmd_op_callback,
2240 if (ret != LDB_SUCCESS) {
2244 talloc_steal(down_req, msg);
2246 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2251 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2256 /* go on with the call chain - do the modify after the rename */
2257 return ldb_next_request(ac->module, down_req);
2261 remove links from objects that point at this object when an object
2264 static int replmd_delete_remove_link(struct ldb_module *module,
2265 const struct dsdb_schema *schema,
2267 struct ldb_message_element *el,
2268 const struct dsdb_attribute *sa)
2271 TALLOC_CTX *tmp_ctx = talloc_new(module);
2272 struct ldb_context *ldb = ldb_module_get_ctx(module);
2274 for (i=0; i<el->num_values; i++) {
2275 struct dsdb_dn *dsdb_dn;
2279 struct ldb_message *msg;
2280 const struct dsdb_attribute *target_attr;
2281 struct ldb_message_element *el2;
2282 struct ldb_val dn_val;
2284 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2288 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2290 talloc_free(tmp_ctx);
2291 return LDB_ERR_OPERATIONS_ERROR;
2294 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2295 if (!NT_STATUS_IS_OK(status)) {
2296 talloc_free(tmp_ctx);
2297 return LDB_ERR_OPERATIONS_ERROR;
2300 /* remove the link */
2301 msg = ldb_msg_new(tmp_ctx);
2303 ldb_module_oom(module);
2304 talloc_free(tmp_ctx);
2305 return LDB_ERR_OPERATIONS_ERROR;
2309 msg->dn = dsdb_dn->dn;
2311 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2312 if (target_attr == NULL) {
2316 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2317 if (ret != LDB_SUCCESS) {
2318 ldb_module_oom(module);
2319 talloc_free(tmp_ctx);
2320 return LDB_ERR_OPERATIONS_ERROR;
2322 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2323 el2->values = &dn_val;
2324 el2->num_values = 1;
2326 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2327 if (ret != LDB_SUCCESS) {
2328 talloc_free(tmp_ctx);
2332 talloc_free(tmp_ctx);
2338 handle update of replication meta data for deletion of objects
2340 This also handles the mapping of delete to a rename operation
2341 to allow deletes to be replicated.
2343 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2345 int ret = LDB_ERR_OTHER;
2347 struct ldb_dn *old_dn, *new_dn;
2348 const char *rdn_name;
2349 const struct ldb_val *rdn_value, *new_rdn_value;
2351 struct ldb_context *ldb = ldb_module_get_ctx(module);
2352 const struct dsdb_schema *schema;
2353 struct ldb_message *msg, *old_msg;
2354 struct ldb_message_element *el;
2355 TALLOC_CTX *tmp_ctx;
2356 struct ldb_result *res, *parent_res;
2357 const char *preserved_attrs[] = {
2358 /* yes, this really is a hard coded list. See MS-ADTS
2359 section 3.1.1.5.5.1.1 */
2360 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2361 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2362 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2363 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2364 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2365 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2366 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2367 "whenChanged", NULL};
2368 unsigned int i, el_count = 0;
2369 enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2370 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2371 enum deletion_state deletion_state, next_deletion_state;
2374 if (ldb_dn_is_special(req->op.del.dn)) {
2375 return ldb_next_request(module, req);
2378 tmp_ctx = talloc_new(ldb);
2381 return LDB_ERR_OPERATIONS_ERROR;
2384 schema = dsdb_get_schema(ldb, tmp_ctx);
2386 return LDB_ERR_OPERATIONS_ERROR;
2389 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2391 /* we need the complete msg off disk, so we can work out which
2392 attributes need to be removed */
2393 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2394 DSDB_SEARCH_SHOW_DELETED |
2395 DSDB_SEARCH_REVEAL_INTERNALS |
2396 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2397 if (ret != LDB_SUCCESS) {
2398 talloc_free(tmp_ctx);
2401 old_msg = res->msgs[0];
2404 ret = dsdb_recyclebin_enabled(module, &enabled);
2405 if (ret != LDB_SUCCESS) {
2406 talloc_free(tmp_ctx);
2410 if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2412 deletion_state = OBJECT_TOMBSTONE;
2413 next_deletion_state = OBJECT_REMOVED;
2414 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2415 deletion_state = OBJECT_RECYCLED;
2416 next_deletion_state = OBJECT_REMOVED;
2418 deletion_state = OBJECT_DELETED;
2419 next_deletion_state = OBJECT_RECYCLED;
2422 deletion_state = OBJECT_NOT_DELETED;
2424 next_deletion_state = OBJECT_DELETED;
2426 next_deletion_state = OBJECT_TOMBSTONE;
2430 if (next_deletion_state == OBJECT_REMOVED) {
2431 struct auth_session_info *session_info =
2432 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2433 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2434 ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2435 ldb_dn_get_linearized(old_msg->dn));
2436 return LDB_ERR_UNWILLING_TO_PERFORM;
2439 /* it is already deleted - really remove it this time */
2440 talloc_free(tmp_ctx);
2441 return ldb_next_request(module, req);
2444 rdn_name = ldb_dn_get_rdn_name(old_dn);
2445 rdn_value = ldb_dn_get_rdn_val(old_dn);
2447 msg = ldb_msg_new(tmp_ctx);
2449 ldb_module_oom(module);
2450 talloc_free(tmp_ctx);
2451 return LDB_ERR_OPERATIONS_ERROR;
2456 if (deletion_state == OBJECT_NOT_DELETED){
2457 /* work out where we will be renaming this object to */
2458 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2459 if (ret != LDB_SUCCESS) {
2460 /* this is probably an attempted delete on a partition
2461 * that doesn't allow delete operations, such as the
2462 * schema partition */
2463 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2464 ldb_dn_get_linearized(old_dn));
2465 talloc_free(tmp_ctx);
2466 return LDB_ERR_UNWILLING_TO_PERFORM;
2469 /* get the objects GUID from the search we just did */
2470 guid = samdb_result_guid(old_msg, "objectGUID");
2472 /* Add a formatted child */
2473 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2476 GUID_string(tmp_ctx, &guid));
2478 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2479 ldb_dn_get_linearized(new_dn)));
2480 talloc_free(tmp_ctx);
2481 return LDB_ERR_OPERATIONS_ERROR;
2484 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2485 if (ret != LDB_SUCCESS) {
2486 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2487 ldb_module_oom(module);
2488 talloc_free(tmp_ctx);
2491 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2495 now we need to modify the object in the following ways:
2497 - add isDeleted=TRUE
2498 - update rDN and name, with new rDN
2499 - remove linked attributes
2500 - remove objectCategory and sAMAccountType
2501 - remove attribs not on the preserved list
2502 - preserved if in above list, or is rDN
2503 - remove all linked attribs from this object
2504 - remove all links from other objects to this object
2505 - add lastKnownParent
2506 - update replPropertyMetaData?
2508 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2511 /* we need the storage form of the parent GUID */
2512 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2513 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2514 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2515 DSDB_SEARCH_REVEAL_INTERNALS|
2516 DSDB_SEARCH_SHOW_DELETED);
2517 if (ret != LDB_SUCCESS) {
2518 talloc_free(tmp_ctx);
2522 if (deletion_state == OBJECT_NOT_DELETED){
2523 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2524 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2525 if (ret != LDB_SUCCESS) {
2526 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2527 ldb_module_oom(module);
2528 talloc_free(tmp_ctx);
2531 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2534 switch (next_deletion_state){
2536 case OBJECT_DELETED:
2538 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2539 if (ret != LDB_SUCCESS) {
2540 DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2541 ldb_module_oom(module);
2542 talloc_free(tmp_ctx);
2545 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2547 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_DELETE, NULL);
2548 if (ret != LDB_SUCCESS) {
2549 talloc_free(tmp_ctx);
2550 ldb_module_oom(module);
2554 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_DELETE, NULL);
2555 if (ret != LDB_SUCCESS) {
2556 talloc_free(tmp_ctx);
2557 ldb_module_oom(module);
2563 case OBJECT_RECYCLED:
2564 case OBJECT_TOMBSTONE:
2566 /* we also mark it as recycled, meaning this object can't be
2567 recovered (we are stripping its attributes) */
2568 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2569 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2570 if (ret != LDB_SUCCESS) {
2571 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2572 ldb_module_oom(module);
2573 talloc_free(tmp_ctx);
2576 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2579 /* work out which of the old attributes we will be removing */
2580 for (i=0; i<old_msg->num_elements; i++) {
2581 const struct dsdb_attribute *sa;
2582 el = &old_msg->elements[i];
2583 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2585 talloc_free(tmp_ctx);
2586 return LDB_ERR_OPERATIONS_ERROR;
2588 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2589 /* don't remove the rDN */
2592 if (sa->linkID && sa->linkID & 1) {
2593 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2594 if (ret != LDB_SUCCESS) {
2595 talloc_free(tmp_ctx);
2596 return LDB_ERR_OPERATIONS_ERROR;
2600 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2603 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2604 if (ret != LDB_SUCCESS) {
2605 talloc_free(tmp_ctx);
2606 ldb_module_oom(module);
2616 if (deletion_state == OBJECT_NOT_DELETED) {
2617 /* work out what the new rdn value is, for updating the
2618 rDN and name fields */
2619 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2621 ret = ldb_msg_add_value(msg, strlower_talloc(tmp_ctx, rdn_name), new_rdn_value, &el);
2622 if (ret != LDB_SUCCESS) {
2623 talloc_free(tmp_ctx);
2626 el->flags = LDB_FLAG_MOD_REPLACE;
2628 el = ldb_msg_find_element(old_msg, "name");
2630 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2631 if (ret != LDB_SUCCESS) {
2632 talloc_free(tmp_ctx);
2635 el->flags = LDB_FLAG_MOD_REPLACE;
2639 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2640 if (ret != LDB_SUCCESS) {
2641 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2642 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2643 talloc_free(tmp_ctx);
2647 if (deletion_state == OBJECT_NOT_DELETED) {
2648 /* now rename onto the new DN */
2649 ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2650 if (ret != LDB_SUCCESS){
2651 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2652 ldb_dn_get_linearized(old_dn),
2653 ldb_dn_get_linearized(new_dn),
2654 ldb_errstring(ldb)));
2655 talloc_free(tmp_ctx);
2660 talloc_free(tmp_ctx);
2662 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2667 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2672 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2674 int ret = LDB_ERR_OTHER;
2675 /* TODO: do some error mapping */
2679 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2681 struct ldb_context *ldb;
2682 struct ldb_request *change_req;
2683 enum ndr_err_code ndr_err;
2684 struct ldb_message *msg;
2685 struct replPropertyMetaDataBlob *md;
2686 struct ldb_val md_value;
2691 * TODO: check if the parent object exist
2695 * TODO: handle the conflict case where an object with the
2699 ldb = ldb_module_get_ctx(ar->module);
2700 msg = ar->objs->objects[ar->index_current].msg;
2701 md = ar->objs->objects[ar->index_current].meta_data;
2703 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2704 if (ret != LDB_SUCCESS) {
2705 return replmd_replicated_request_error(ar, ret);
2708 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2709 if (ret != LDB_SUCCESS) {
2710 return replmd_replicated_request_error(ar, ret);
2713 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2714 if (ret != LDB_SUCCESS) {
2715 return replmd_replicated_request_error(ar, ret);
2718 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2719 if (ret != LDB_SUCCESS) {
2720 return replmd_replicated_request_error(ar, ret);
2723 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2724 if (ret != LDB_SUCCESS) {
2725 return replmd_replicated_request_error(ar, ret);
2728 /* remove any message elements that have zero values */
2729 for (i=0; i<msg->num_elements; i++) {
2730 struct ldb_message_element *el = &msg->elements[i];
2732 if (el->num_values == 0) {
2733 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2735 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2736 msg->num_elements--;
2743 * the meta data array is already sorted by the caller
2745 for (i=0; i < md->ctr.ctr1.count; i++) {
2746 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2748 ndr_err = ndr_push_struct_blob(&md_value, msg, md,
2749 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2750 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2751 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2752 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2754 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2755 if (ret != LDB_SUCCESS) {
2756 return replmd_replicated_request_error(ar, ret);
2759 replmd_ldb_message_sort(msg, ar->schema);
2762 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2763 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2767 ret = ldb_build_add_req(&change_req,
2775 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2777 return ldb_next_request(ar->module, change_req);
2781 return true if an update is newer than an existing entry
2782 see section 5.11 of MS-ADTS
2784 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2785 const struct GUID *update_invocation_id,
2786 uint32_t current_version,
2787 uint32_t update_version,
2788 NTTIME current_change_time,
2789 NTTIME update_change_time)
2791 if (update_version != current_version) {
2792 return update_version > current_version;
2794 if (update_change_time > current_change_time) {
2797 if (update_change_time == current_change_time) {
2798 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2803 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2804 struct replPropertyMetaData1 *new_m)
2806 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2807 &new_m->originating_invocation_id,
2810 cur_m->originating_change_time,
2811 new_m->originating_change_time);
2814 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2816 struct ldb_context *ldb;
2817 struct ldb_request *change_req;
2818 enum ndr_err_code ndr_err;
2819 struct ldb_message *msg;
2820 struct replPropertyMetaDataBlob *rmd;
2821 struct replPropertyMetaDataBlob omd;
2822 const struct ldb_val *omd_value;
2823 struct replPropertyMetaDataBlob nmd;
2824 struct ldb_val nmd_value;
2827 unsigned int removed_attrs = 0;
2830 ldb = ldb_module_get_ctx(ar->module);
2831 msg = ar->objs->objects[ar->index_current].msg;
2832 rmd = ar->objs->objects[ar->index_current].meta_data;
2837 * TODO: check repl data is correct after a rename
2839 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2840 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2841 ldb_dn_get_linearized(ar->search_msg->dn),
2842 ldb_dn_get_linearized(msg->dn));
2843 if (dsdb_module_rename(ar->module,
2844 ar->search_msg->dn, msg->dn,
2845 DSDB_FLAG_OWN_MODULE) != LDB_SUCCESS) {
2846 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2847 ldb_dn_get_linearized(ar->search_msg->dn),
2848 ldb_dn_get_linearized(msg->dn),
2849 ldb_errstring(ldb));
2850 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2854 /* find existing meta data */
2855 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2857 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
2858 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2859 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2860 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2861 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2864 if (omd.version != 1) {
2865 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2871 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2872 nmd.ctr.ctr1.array = talloc_array(ar,
2873 struct replPropertyMetaData1,
2874 nmd.ctr.ctr1.count);
2875 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2877 /* first copy the old meta data */
2878 for (i=0; i < omd.ctr.ctr1.count; i++) {
2879 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2883 /* now merge in the new meta data */
2884 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2887 for (j=0; j < ni; j++) {
2890 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2894 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2895 &rmd->ctr.ctr1.array[i]);
2897 /* replace the entry */
2898 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2903 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType) {
2904 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
2905 msg->elements[i-removed_attrs].name,
2906 ldb_dn_get_linearized(msg->dn),
2907 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2910 /* we don't want to apply this change so remove the attribute */
2911 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2918 if (found) continue;
2920 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2925 * finally correct the size of the meta_data array
2927 nmd.ctr.ctr1.count = ni;
2930 * the rdn attribute (the alias for the name attribute),
2931 * 'cn' for most objects is the last entry in the meta data array
2934 * sort the new meta data array
2936 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2937 if (ret != LDB_SUCCESS) {
2942 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2944 if (msg->num_elements == 0) {
2945 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2948 ar->index_current++;
2949 return replmd_replicated_apply_next(ar);
2952 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2953 ar->index_current, msg->num_elements);
2955 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2956 if (ret != LDB_SUCCESS) {
2957 return replmd_replicated_request_error(ar, ret);
2960 for (i=0; i<ni; i++) {
2961 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2964 /* create the meta data value */
2965 ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
2966 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2967 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2968 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2969 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2973 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2974 * and replPopertyMetaData attributes
2976 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2977 if (ret != LDB_SUCCESS) {
2978 return replmd_replicated_request_error(ar, ret);
2980 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2981 if (ret != LDB_SUCCESS) {
2982 return replmd_replicated_request_error(ar, ret);
2984 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2985 if (ret != LDB_SUCCESS) {
2986 return replmd_replicated_request_error(ar, ret);
2989 replmd_ldb_message_sort(msg, ar->schema);
2991 /* we want to replace the old values */
2992 for (i=0; i < msg->num_elements; i++) {
2993 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2997 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2998 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
3002 ret = ldb_build_mod_req(&change_req,
3010 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3012 return ldb_next_request(ar->module, change_req);
3015 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
3016 struct ldb_reply *ares)
3018 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3019 struct replmd_replicated_request);
3023 return ldb_module_done(ar->req, NULL, NULL,
3024 LDB_ERR_OPERATIONS_ERROR);
3026 if (ares->error != LDB_SUCCESS &&
3027 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3028 return ldb_module_done(ar->req, ares->controls,
3029 ares->response, ares->error);
3032 switch (ares->type) {
3033 case LDB_REPLY_ENTRY:
3034 ar->search_msg = talloc_steal(ar, ares->message);
3037 case LDB_REPLY_REFERRAL:
3038 /* we ignore referrals */
3041 case LDB_REPLY_DONE:
3042 if (ar->search_msg != NULL) {
3043 ret = replmd_replicated_apply_merge(ar);
3045 ret = replmd_replicated_apply_add(ar);
3047 if (ret != LDB_SUCCESS) {
3048 return ldb_module_done(ar->req, NULL, NULL, ret);
3056 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3058 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3060 struct ldb_context *ldb;
3064 struct ldb_request *search_req;
3065 struct ldb_search_options_control *options;
3067 if (ar->index_current >= ar->objs->num_objects) {
3068 /* done with it, go to next stage */
3069 return replmd_replicated_uptodate_vector(ar);
3072 ldb = ldb_module_get_ctx(ar->module);
3073 ar->search_msg = NULL;
3075 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3076 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3078 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3079 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3080 talloc_free(tmp_str);
3082 ret = ldb_build_search_req(&search_req,
3091 replmd_replicated_apply_search_callback,
3094 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3095 if (ret != LDB_SUCCESS) {
3099 /* we need to cope with cross-partition links, so search for
3100 the GUID over all partitions */
3101 options = talloc(search_req, struct ldb_search_options_control);
3102 if (options == NULL) {
3103 DEBUG(0, (__location__ ": out of memory\n"));
3104 return LDB_ERR_OPERATIONS_ERROR;
3106 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3108 ret = ldb_request_add_control(search_req,
3109 LDB_CONTROL_SEARCH_OPTIONS_OID,
3111 if (ret != LDB_SUCCESS) {
3115 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3117 return ldb_next_request(ar->module, search_req);
3120 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
3121 struct ldb_reply *ares)
3123 struct ldb_context *ldb;
3124 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3125 struct replmd_replicated_request);
3126 ldb = ldb_module_get_ctx(ar->module);
3129 return ldb_module_done(ar->req, NULL, NULL,
3130 LDB_ERR_OPERATIONS_ERROR);
3132 if (ares->error != LDB_SUCCESS) {
3133 return ldb_module_done(ar->req, ares->controls,
3134 ares->response, ares->error);
3137 if (ares->type != LDB_REPLY_DONE) {
3138 ldb_set_errstring(ldb, "Invalid reply type\n!");
3139 return ldb_module_done(ar->req, NULL, NULL,
3140 LDB_ERR_OPERATIONS_ERROR);
3145 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3148 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3150 struct ldb_context *ldb;
3151 struct ldb_request *change_req;
3152 enum ndr_err_code ndr_err;
3153 struct ldb_message *msg;
3154 struct replUpToDateVectorBlob ouv;
3155 const struct ldb_val *ouv_value;
3156 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3157 struct replUpToDateVectorBlob nuv;
3158 struct ldb_val nuv_value;
3159 struct ldb_message_element *nuv_el = NULL;
3160 const struct GUID *our_invocation_id;
3161 struct ldb_message_element *orf_el = NULL;
3162 struct repsFromToBlob nrf;
3163 struct ldb_val *nrf_value = NULL;
3164 struct ldb_message_element *nrf_el = NULL;
3168 time_t t = time(NULL);
3172 ldb = ldb_module_get_ctx(ar->module);
3173 ruv = ar->objs->uptodateness_vector;
3179 unix_to_nt_time(&now, t);
3182 * first create the new replUpToDateVector
3184 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
3186 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
3187 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3188 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3189 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3190 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3193 if (ouv.version != 2) {
3194 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3199 * the new uptodateness vector will at least
3200 * contain 1 entry, one for the source_dsa
3202 * plus optional values from our old vector and the one from the source_dsa
3204 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
3205 if (ruv) nuv.ctr.ctr2.count += ruv->count;
3206 nuv.ctr.ctr2.cursors = talloc_array(ar,
3207 struct drsuapi_DsReplicaCursor2,
3208 nuv.ctr.ctr2.count);
3209 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3211 /* first copy the old vector */
3212 for (i=0; i < ouv.ctr.ctr2.count; i++) {
3213 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
3217 /* get our invocation_id if we have one already attached to the ldb */
3218 our_invocation_id = samdb_ntds_invocation_id(ldb);
3220 /* merge in the source_dsa vector is available */
3221 for (i=0; (ruv && i < ruv->count); i++) {
3224 if (our_invocation_id &&
3225 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3226 our_invocation_id)) {
3230 for (j=0; j < ni; j++) {
3231 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3232 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3239 * we update only the highest_usn and not the latest_sync_success time,
3240 * because the last success stands for direct replication
3242 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3243 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3248 if (found) continue;
3250 /* if it's not there yet, add it */
3251 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3256 * merge in the current highwatermark for the source_dsa
3259 for (j=0; j < ni; j++) {
3260 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
3261 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3268 * here we update the highest_usn and last_sync_success time
3269 * because we're directly replicating from the source_dsa
3271 * and use the tmp_highest_usn because this is what we have just applied
3274 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3275 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
3280 * here we update the highest_usn and last_sync_success time
3281 * because we're directly replicating from the source_dsa
3283 * and use the tmp_highest_usn because this is what we have just applied
3286 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
3287 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3288 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
3293 * finally correct the size of the cursors array
3295 nuv.ctr.ctr2.count = ni;
3300 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
3303 * create the change ldb_message
3305 msg = ldb_msg_new(ar);
3306 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3307 msg->dn = ar->search_msg->dn;
3309 ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
3310 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3311 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3312 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3313 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3315 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3316 if (ret != LDB_SUCCESS) {
3317 return replmd_replicated_request_error(ar, ret);
3319 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3322 * now create the new repsFrom value from the given repsFromTo1 structure
3326 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3327 /* and fix some values... */
3328 nrf.ctr.ctr1.consecutive_sync_failures = 0;
3329 nrf.ctr.ctr1.last_success = now;
3330 nrf.ctr.ctr1.last_attempt = now;
3331 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
3332 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3335 * first see if we already have a repsFrom value for the current source dsa
3336 * if so we'll later replace this value
3338 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3340 for (i=0; i < orf_el->num_values; i++) {
3341 struct repsFromToBlob *trf;
3343 trf = talloc(ar, struct repsFromToBlob);
3344 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3346 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
3347 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3348 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3349 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3350 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3353 if (trf->version != 1) {
3354 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3358 * we compare the source dsa objectGUID not the invocation_id
3359 * because we want only one repsFrom value per source dsa
3360 * and when the invocation_id of the source dsa has changed we don't need
3361 * the old repsFrom with the old invocation_id
3363 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3364 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3370 nrf_value = &orf_el->values[i];
3375 * copy over all old values to the new ldb_message
3377 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3378 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3383 * if we haven't found an old repsFrom value for the current source dsa
3384 * we'll add a new value
3387 struct ldb_val zero_value;
3388 ZERO_STRUCT(zero_value);
3389 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3390 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3392 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3395 /* we now fill the value which is already attached to ldb_message */
3396 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3398 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3399 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3400 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3401 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3405 * the ldb_message_element for the attribute, has all the old values and the new one
3406 * so we'll replace the whole attribute with all values
3408 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3411 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3412 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3416 /* prepare the ldb_modify() request */
3417 ret = ldb_build_mod_req(&change_req,
3423 replmd_replicated_uptodate_modify_callback,
3425 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3427 return ldb_next_request(ar->module, change_req);
3430 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3431 struct ldb_reply *ares)
3433 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3434 struct replmd_replicated_request);
3438 return ldb_module_done(ar->req, NULL, NULL,
3439 LDB_ERR_OPERATIONS_ERROR);
3441 if (ares->error != LDB_SUCCESS &&
3442 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3443 return ldb_module_done(ar->req, ares->controls,
3444 ares->response, ares->error);
3447 switch (ares->type) {
3448 case LDB_REPLY_ENTRY:
3449 ar->search_msg = talloc_steal(ar, ares->message);
3452 case LDB_REPLY_REFERRAL:
3453 /* we ignore referrals */
3456 case LDB_REPLY_DONE:
3457 if (ar->search_msg == NULL) {
3458 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3460 ret = replmd_replicated_uptodate_modify(ar);
3462 if (ret != LDB_SUCCESS) {
3463 return ldb_module_done(ar->req, NULL, NULL, ret);
3472 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3474 struct ldb_context *ldb;
3476 static const char *attrs[] = {
3477 "replUpToDateVector",
3481 struct ldb_request *search_req;
3483 ldb = ldb_module_get_ctx(ar->module);
3484 ar->search_msg = NULL;
3486 ret = ldb_build_search_req(&search_req,
3489 ar->objs->partition_dn,
3495 replmd_replicated_uptodate_search_callback,
3497 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3499 return ldb_next_request(ar->module, search_req);
3504 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3506 struct ldb_context *ldb;
3507 struct dsdb_extended_replicated_objects *objs;
3508 struct replmd_replicated_request *ar;
3509 struct ldb_control **ctrls;
3512 struct replmd_private *replmd_private =
3513 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3515 ldb = ldb_module_get_ctx(module);
3517 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3519 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3521 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3522 return LDB_ERR_PROTOCOL_ERROR;
3525 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3526 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3527 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3528 return LDB_ERR_PROTOCOL_ERROR;
3531 ar = replmd_ctx_init(module, req);
3533 return LDB_ERR_OPERATIONS_ERROR;
3535 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3536 ar->apply_mode = true;
3538 ar->schema = dsdb_get_schema(ldb, ar);
3540 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3542 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3543 return LDB_ERR_CONSTRAINT_VIOLATION;
3546 ctrls = req->controls;
3548 if (req->controls) {
3549 req->controls = talloc_memdup(ar, req->controls,
3550 talloc_get_size(req->controls));
3551 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3554 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3555 if (ret != LDB_SUCCESS) {
3559 ar->controls = req->controls;
3560 req->controls = ctrls;
3562 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3564 /* save away the linked attributes for the end of the
3566 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3567 struct la_entry *la_entry;
3569 if (replmd_private->la_ctx == NULL) {
3570 replmd_private->la_ctx = talloc_new(replmd_private);
3572 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3573 if (la_entry == NULL) {
3575 return LDB_ERR_OPERATIONS_ERROR;
3577 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3578 if (la_entry->la == NULL) {
3579 talloc_free(la_entry);
3581 return LDB_ERR_OPERATIONS_ERROR;
3583 *la_entry->la = ar->objs->linked_attributes[i];
3585 /* we need to steal the non-scalars so they stay
3586 around until the end of the transaction */
3587 talloc_steal(la_entry->la, la_entry->la->identifier);
3588 talloc_steal(la_entry->la, la_entry->la->value.blob);
3590 DLIST_ADD(replmd_private->la_list, la_entry);
3593 return replmd_replicated_apply_next(ar);
3597 process one linked attribute structure
3599 static int replmd_process_linked_attribute(struct ldb_module *module,
3600 struct la_entry *la_entry)
3602 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3603 struct ldb_context *ldb = ldb_module_get_ctx(module);
3604 struct ldb_message *msg;
3605 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3606 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
3608 const struct dsdb_attribute *attr;
3609 struct dsdb_dn *dsdb_dn;
3610 uint64_t seq_num = 0;
3611 struct ldb_message_element *old_el;
3613 time_t t = time(NULL);
3614 struct ldb_result *res;
3615 const char *attrs[2];
3616 struct parsed_dn *pdn_list, *pdn;
3617 struct GUID guid = GUID_zero();
3619 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3620 const struct GUID *our_invocation_id;
3623 linked_attributes[0]:
3624 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3626 identifier: struct drsuapi_DsReplicaObjectIdentifier
3627 __ndr_size : 0x0000003a (58)
3628 __ndr_size_sid : 0x00000000 (0)
3629 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3631 __ndr_size_dn : 0x00000000 (0)
3633 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3634 value: struct drsuapi_DsAttributeValue
3635 __ndr_size : 0x0000007e (126)
3637 blob : DATA_BLOB length=126
3638 flags : 0x00000001 (1)
3639 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3640 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3641 meta_data: struct drsuapi_DsReplicaMetaData
3642 version : 0x00000015 (21)
3643 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3644 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3645 originating_usn : 0x000000000001e19c (123292)
3647 (for cases where the link is to a normal DN)
3648 &target: struct drsuapi_DsReplicaObjectIdentifier3
3649 __ndr_size : 0x0000007e (126)
3650 __ndr_size_sid : 0x0000001c (28)
3651 guid : 7639e594-db75-4086-b0d4-67890ae46031
3652 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3653 __ndr_size_dn : 0x00000022 (34)
3654 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3657 /* find the attribute being modified */
3658 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3660 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3661 talloc_free(tmp_ctx);
3662 return LDB_ERR_OPERATIONS_ERROR;
3665 attrs[0] = attr->lDAPDisplayName;
3668 /* get the existing message from the db for the object with
3669 this GUID, returning attribute being modified. We will then
3670 use this msg as the basis for a modify call */
3671 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3672 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3673 DSDB_SEARCH_SHOW_DELETED |
3674 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3675 DSDB_SEARCH_REVEAL_INTERNALS,
3676 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3677 if (ret != LDB_SUCCESS) {
3678 talloc_free(tmp_ctx);
3681 if (res->count != 1) {
3682 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3683 GUID_string(tmp_ctx, &la->identifier->guid));
3684 talloc_free(tmp_ctx);
3685 return LDB_ERR_NO_SUCH_OBJECT;
3689 if (msg->num_elements == 0) {
3690 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3691 if (ret != LDB_SUCCESS) {
3692 ldb_module_oom(module);
3693 talloc_free(tmp_ctx);
3694 return LDB_ERR_OPERATIONS_ERROR;
3697 old_el = &msg->elements[0];
3698 old_el->flags = LDB_FLAG_MOD_REPLACE;
3701 /* parse the existing links */
3702 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3703 if (ret != LDB_SUCCESS) {
3704 talloc_free(tmp_ctx);
3708 /* get our invocationId */
3709 our_invocation_id = samdb_ntds_invocation_id(ldb);
3710 if (!our_invocation_id) {
3711 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
3712 talloc_free(tmp_ctx);
3713 return LDB_ERR_OPERATIONS_ERROR;
3716 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
3717 if (ret != LDB_SUCCESS) {
3718 talloc_free(tmp_ctx);
3722 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
3723 if (!W_ERROR_IS_OK(status)) {
3724 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
3725 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
3726 return LDB_ERR_OPERATIONS_ERROR;
3729 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3730 if (!NT_STATUS_IS_OK(ntstatus) && active) {
3731 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
3733 ldb_dn_get_linearized(dsdb_dn->dn),
3734 ldb_dn_get_linearized(msg->dn));
3735 return LDB_ERR_OPERATIONS_ERROR;
3738 /* re-resolve the DN by GUID, as the DRS server may give us an
3740 ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn);
3741 if (ret != LDB_SUCCESS) {
3742 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s",
3743 GUID_string(tmp_ctx, &guid),
3744 ldb_dn_get_linearized(dsdb_dn->dn)));
3747 /* see if this link already exists */
3748 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
3750 /* see if this update is newer than what we have already */
3751 struct GUID invocation_id = GUID_zero();
3752 uint32_t version = 0;
3753 NTTIME change_time = 0;
3754 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
3756 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3757 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3758 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3760 if (!replmd_update_is_newer(&invocation_id,
3761 &la->meta_data.originating_invocation_id,
3763 la->meta_data.version,
3765 la->meta_data.originating_change_time)) {
3766 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3767 old_el->name, ldb_dn_get_linearized(msg->dn),
3768 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3769 talloc_free(tmp_ctx);
3773 /* get a seq_num for this change */
3774 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3775 if (ret != LDB_SUCCESS) {
3776 talloc_free(tmp_ctx);
3780 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
3781 /* remove the existing backlink */
3782 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3783 if (ret != LDB_SUCCESS) {
3784 talloc_free(tmp_ctx);
3789 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3790 &la->meta_data.originating_invocation_id,
3791 la->meta_data.originating_usn, seq_num,
3792 la->meta_data.originating_change_time,
3793 la->meta_data.version,
3795 if (ret != LDB_SUCCESS) {
3796 talloc_free(tmp_ctx);
3801 /* add the new backlink */
3802 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3803 if (ret != LDB_SUCCESS) {
3804 talloc_free(tmp_ctx);
3809 /* get a seq_num for this change */
3810 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3811 if (ret != LDB_SUCCESS) {
3812 talloc_free(tmp_ctx);
3816 old_el->values = talloc_realloc(msg->elements, old_el->values,
3817 struct ldb_val, old_el->num_values+1);
3818 if (!old_el->values) {
3819 ldb_module_oom(module);
3820 return LDB_ERR_OPERATIONS_ERROR;
3822 old_el->num_values++;
3824 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3825 &la->meta_data.originating_invocation_id,
3826 la->meta_data.originating_usn, seq_num,
3827 la->meta_data.originating_change_time,
3828 la->meta_data.version,
3829 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3830 if (ret != LDB_SUCCESS) {
3831 talloc_free(tmp_ctx);
3836 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3838 if (ret != LDB_SUCCESS) {
3839 talloc_free(tmp_ctx);
3845 /* we only change whenChanged and uSNChanged if the seq_num
3847 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3848 talloc_free(tmp_ctx);
3849 return LDB_ERR_OPERATIONS_ERROR;
3852 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3853 talloc_free(tmp_ctx);
3854 return LDB_ERR_OPERATIONS_ERROR;
3857 ret = dsdb_check_single_valued_link(attr, old_el);
3858 if (ret != LDB_SUCCESS) {
3859 talloc_free(tmp_ctx);
3863 ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
3864 if (ret != LDB_SUCCESS) {
3865 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
3867 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3868 talloc_free(tmp_ctx);
3872 talloc_free(tmp_ctx);
3877 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3879 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3880 return replmd_extended_replicated_objects(module, req);
3883 return ldb_next_request(module, req);
3888 we hook into the transaction operations to allow us to
3889 perform the linked attribute updates at the end of the whole
3890 transaction. This allows a forward linked attribute to be created
3891 before the object is created. During a vampire, w2k8 sends us linked
3892 attributes before the objects they are part of.
3894 static int replmd_start_transaction(struct ldb_module *module)
3896 /* create our private structure for this transaction */
3897 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3898 struct replmd_private);
3899 replmd_txn_cleanup(replmd_private);
3901 /* free any leftover mod_usn records from cancelled
3903 while (replmd_private->ncs) {
3904 struct nc_entry *e = replmd_private->ncs;
3905 DLIST_REMOVE(replmd_private->ncs, e);
3909 return ldb_next_start_trans(module);
3913 on prepare commit we loop over our queued la_context structures and
3916 static int replmd_prepare_commit(struct ldb_module *module)
3918 struct replmd_private *replmd_private =
3919 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3920 struct la_entry *la, *prev;
3921 struct la_backlink *bl;
3924 /* walk the list backwards, to do the first entry first, as we
3925 * added the entries with DLIST_ADD() which puts them at the
3926 * start of the list */
3927 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
3928 prev = DLIST_PREV(la);
3929 DLIST_REMOVE(replmd_private->la_list, la);
3930 ret = replmd_process_linked_attribute(module, la);
3931 if (ret != LDB_SUCCESS) {
3932 replmd_txn_cleanup(replmd_private);
3937 /* process our backlink list, creating and deleting backlinks
3939 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3940 ret = replmd_process_backlink(module, bl);
3941 if (ret != LDB_SUCCESS) {
3942 replmd_txn_cleanup(replmd_private);
3947 replmd_txn_cleanup(replmd_private);
3949 /* possibly change @REPLCHANGED */
3950 ret = replmd_notify_store(module);
3951 if (ret != LDB_SUCCESS) {
3955 return ldb_next_prepare_commit(module);
3958 static int replmd_del_transaction(struct ldb_module *module)
3960 struct replmd_private *replmd_private =
3961 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3962 replmd_txn_cleanup(replmd_private);
3964 return ldb_next_del_trans(module);
3968 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3969 .name = "repl_meta_data",
3970 .init_context = replmd_init,
3972 .modify = replmd_modify,
3973 .rename = replmd_rename,
3974 .del = replmd_delete,
3975 .extended = replmd_extended,
3976 .start_transaction = replmd_start_transaction,
3977 .prepare_commit = replmd_prepare_commit,
3978 .del_transaction = replmd_del_transaction,