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,
914 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
916 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
917 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
920 return LDB_ERR_OPERATIONS_ERROR;
924 * add the autogenerated values
926 ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
927 if (ret != LDB_SUCCESS) {
932 ret = ldb_msg_add_string(msg, "whenChanged", time_str);
933 if (ret != LDB_SUCCESS) {
938 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
939 if (ret != LDB_SUCCESS) {
944 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
945 if (ret != LDB_SUCCESS) {
950 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
951 if (ret != LDB_SUCCESS) {
958 * sort the attributes by attid before storing the object
960 replmd_ldb_message_sort(msg, ac->schema);
962 objectclass_el = ldb_msg_find_element(msg, "objectClass");
963 is_urgent = replmd_check_urgent_objectclass(objectclass_el,
964 REPL_URGENT_ON_CREATE);
966 ac->is_urgent = is_urgent;
967 ret = ldb_build_add_req(&down_req, ldb, ac,
970 ac, replmd_op_callback,
973 if (ret != LDB_SUCCESS) {
978 /* mark the control done */
980 control->critical = 0;
983 /* go on with the call chain */
984 return ldb_next_request(module, down_req);
989 * update the replPropertyMetaData for one element
991 static int replmd_update_rpmd_element(struct ldb_context *ldb,
992 struct ldb_message *msg,
993 struct ldb_message_element *el,
994 struct ldb_message_element *old_el,
995 struct replPropertyMetaDataBlob *omd,
996 const struct dsdb_schema *schema,
998 const struct GUID *our_invocation_id,
1002 const struct dsdb_attribute *a;
1003 struct replPropertyMetaData1 *md1;
1005 a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1007 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1009 return LDB_ERR_OPERATIONS_ERROR;
1012 if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1016 /* if the attribute's value haven't changed then return LDB_SUCCESS */
1017 if (old_el != NULL && ldb_msg_element_compare(el, old_el) == 0) {
1021 for (i=0; i<omd->ctr.ctr1.count; i++) {
1022 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1025 #if W2K3_LINKED_ATTRIBUTES
1026 if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1027 /* linked attributes are not stored in
1028 replPropertyMetaData in FL above w2k, but we do
1029 raise the seqnum for the object */
1030 if (*seq_num == 0 &&
1031 ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1032 return LDB_ERR_OPERATIONS_ERROR;
1038 if (i == omd->ctr.ctr1.count) {
1039 /* we need to add a new one */
1040 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1041 struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1042 if (omd->ctr.ctr1.array == NULL) {
1044 return LDB_ERR_OPERATIONS_ERROR;
1046 omd->ctr.ctr1.count++;
1047 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1050 /* Get a new sequence number from the backend. We only do this
1051 * if we have a change that requires a new
1052 * replPropertyMetaData element
1054 if (*seq_num == 0) {
1055 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1056 if (ret != LDB_SUCCESS) {
1057 return LDB_ERR_OPERATIONS_ERROR;
1061 md1 = &omd->ctr.ctr1.array[i];
1063 md1->attid = a->attributeID_id;
1064 md1->originating_change_time = now;
1065 md1->originating_invocation_id = *our_invocation_id;
1066 md1->originating_usn = *seq_num;
1067 md1->local_usn = *seq_num;
1073 * update the replPropertyMetaData object each time we modify an
1074 * object. This is needed for DRS replication, as the merge on the
1075 * client is based on this object
1077 static int replmd_update_rpmd(struct ldb_module *module,
1078 const struct dsdb_schema *schema,
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;
1096 ldb = ldb_module_get_ctx(module);
1098 our_invocation_id = samdb_ntds_invocation_id(ldb);
1099 if (!our_invocation_id) {
1100 /* this happens during an initial vampire while
1101 updating the schema */
1102 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1106 unix_to_nt_time(&now, t);
1108 /* search for the existing replPropertyMetaDataBlob. We need
1109 * to use REVEAL and ask for DNs in storage format to support
1110 * the check for values being the same in
1111 * replmd_update_rpmd_element()
1113 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1114 DSDB_SEARCH_SHOW_DELETED |
1115 DSDB_SEARCH_SHOW_EXTENDED_DN |
1116 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1117 DSDB_SEARCH_REVEAL_INTERNALS);
1118 if (ret != LDB_SUCCESS || res->count != 1) {
1119 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1120 ldb_dn_get_linearized(msg->dn)));
1121 return LDB_ERR_OPERATIONS_ERROR;
1124 /* if isDeleted is present and is TRUE, then we consider we are deleting,
1125 * otherwise we consider we are updating */
1126 if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1127 situation = REPL_URGENT_ON_DELETE;
1129 situation = REPL_URGENT_ON_UPDATE;
1132 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1133 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1138 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1140 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1141 ldb_dn_get_linearized(msg->dn)));
1142 return LDB_ERR_OPERATIONS_ERROR;
1145 ndr_err = ndr_pull_struct_blob(omd_value, msg,
1146 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &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 for (i=0; i<msg->num_elements; i++) {
1161 struct ldb_message_element *old_el;
1162 old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1163 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1164 our_invocation_id, now);
1165 if (ret != LDB_SUCCESS) {
1169 if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1170 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1176 * replmd_update_rpmd_element has done an update if the
1179 if (*seq_num != 0) {
1180 struct ldb_val *md_value;
1181 struct ldb_message_element *el;
1183 md_value = talloc(msg, struct ldb_val);
1184 if (md_value == NULL) {
1186 return LDB_ERR_OPERATIONS_ERROR;
1189 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1190 if (ret != LDB_SUCCESS) {
1194 ndr_err = ndr_push_struct_blob(md_value, msg,
1195 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1197 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1198 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1199 DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1200 ldb_dn_get_linearized(msg->dn)));
1201 return LDB_ERR_OPERATIONS_ERROR;
1204 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1205 if (ret != LDB_SUCCESS) {
1206 DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1207 ldb_dn_get_linearized(msg->dn)));
1212 el->values = md_value;
1219 struct dsdb_dn *dsdb_dn;
1224 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1226 return GUID_compare(pdn1->guid, pdn2->guid);
1229 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid, struct ldb_dn *dn)
1231 struct parsed_dn *ret;
1232 if (dn && GUID_all_zero(guid)) {
1233 /* when updating a link using DRS, we sometimes get a
1234 NULL GUID. We then need to try and match by DN */
1236 for (i=0; i<count; i++) {
1237 if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1238 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1244 BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1249 get a series of message element values as an array of DNs and GUIDs
1250 the result is sorted by GUID
1252 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1253 struct ldb_message_element *el, struct parsed_dn **pdn,
1254 const char *ldap_oid)
1257 struct ldb_context *ldb = ldb_module_get_ctx(module);
1264 (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1266 ldb_module_oom(module);
1267 return LDB_ERR_OPERATIONS_ERROR;
1270 for (i=0; i<el->num_values; i++) {
1271 struct ldb_val *v = &el->values[i];
1274 struct parsed_dn *p;
1278 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1279 if (p->dsdb_dn == NULL) {
1280 return LDB_ERR_INVALID_DN_SYNTAX;
1283 dn = p->dsdb_dn->dn;
1285 p->guid = talloc(*pdn, struct GUID);
1286 if (p->guid == NULL) {
1287 ldb_module_oom(module);
1288 return LDB_ERR_OPERATIONS_ERROR;
1291 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1292 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1293 /* we got a DN without a GUID - go find the GUID */
1294 int ret = dsdb_module_guid_by_dn(module, dn, p->guid);
1295 if (ret != LDB_SUCCESS) {
1296 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1297 ldb_dn_get_linearized(dn));
1300 ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1301 if (ret != LDB_SUCCESS) {
1304 } else if (!NT_STATUS_IS_OK(status)) {
1305 return LDB_ERR_OPERATIONS_ERROR;
1308 /* keep a pointer to the original ldb_val */
1312 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1318 build a new extended DN, including all meta data fields
1320 RMD_FLAGS = DSDB_RMD_FLAG_* bits
1321 RMD_ADDTIME = originating_add_time
1322 RMD_INVOCID = originating_invocation_id
1323 RMD_CHANGETIME = originating_change_time
1324 RMD_ORIGINATING_USN = originating_usn
1325 RMD_LOCAL_USN = local_usn
1326 RMD_VERSION = version
1328 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1329 const struct GUID *invocation_id, uint64_t seq_num,
1330 uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1332 struct ldb_dn *dn = dsdb_dn->dn;
1333 const char *tstring, *usn_string, *flags_string;
1334 struct ldb_val tval;
1336 struct ldb_val usnv, local_usnv;
1337 struct ldb_val vers, flagsv;
1340 const char *dnstring;
1342 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1344 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1346 return LDB_ERR_OPERATIONS_ERROR;
1348 tval = data_blob_string_const(tstring);
1350 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1352 return LDB_ERR_OPERATIONS_ERROR;
1354 usnv = data_blob_string_const(usn_string);
1356 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1358 return LDB_ERR_OPERATIONS_ERROR;
1360 local_usnv = data_blob_string_const(usn_string);
1362 vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1364 return LDB_ERR_OPERATIONS_ERROR;
1366 vers = data_blob_string_const(vstring);
1368 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1369 if (!NT_STATUS_IS_OK(status)) {
1370 return LDB_ERR_OPERATIONS_ERROR;
1373 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1374 if (!flags_string) {
1375 return LDB_ERR_OPERATIONS_ERROR;
1377 flagsv = data_blob_string_const(flags_string);
1379 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1380 if (ret != LDB_SUCCESS) return ret;
1381 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1382 if (ret != LDB_SUCCESS) return ret;
1383 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1384 if (ret != LDB_SUCCESS) return ret;
1385 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1386 if (ret != LDB_SUCCESS) return ret;
1387 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1388 if (ret != LDB_SUCCESS) return ret;
1389 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1390 if (ret != LDB_SUCCESS) return ret;
1391 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1392 if (ret != LDB_SUCCESS) return ret;
1394 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1395 if (dnstring == NULL) {
1396 return LDB_ERR_OPERATIONS_ERROR;
1398 *v = data_blob_string_const(dnstring);
1403 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1404 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1405 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1406 uint32_t version, bool deleted);
1409 check if any links need upgrading from w2k format
1411 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.
1413 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1416 for (i=0; i<count; i++) {
1421 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1422 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1426 /* it's an old one that needs upgrading */
1427 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1429 if (ret != LDB_SUCCESS) {
1437 update an extended DN, including all meta data fields
1439 see replmd_build_la_val for value names
1441 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1442 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1443 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1444 uint32_t version, bool deleted)
1446 struct ldb_dn *dn = dsdb_dn->dn;
1447 const char *tstring, *usn_string, *flags_string;
1448 struct ldb_val tval;
1450 struct ldb_val usnv, local_usnv;
1451 struct ldb_val vers, flagsv;
1452 const struct ldb_val *old_addtime;
1453 uint32_t old_version;
1456 const char *dnstring;
1458 uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1460 tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1462 return LDB_ERR_OPERATIONS_ERROR;
1464 tval = data_blob_string_const(tstring);
1466 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1468 return LDB_ERR_OPERATIONS_ERROR;
1470 usnv = data_blob_string_const(usn_string);
1472 usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1474 return LDB_ERR_OPERATIONS_ERROR;
1476 local_usnv = data_blob_string_const(usn_string);
1478 status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1479 if (!NT_STATUS_IS_OK(status)) {
1480 return LDB_ERR_OPERATIONS_ERROR;
1483 flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1484 if (!flags_string) {
1485 return LDB_ERR_OPERATIONS_ERROR;
1487 flagsv = data_blob_string_const(flags_string);
1489 ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1490 if (ret != LDB_SUCCESS) return ret;
1492 /* get the ADDTIME from the original */
1493 old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1494 if (old_addtime == NULL) {
1495 old_addtime = &tval;
1497 if (dsdb_dn != old_dsdb_dn) {
1498 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1499 if (ret != LDB_SUCCESS) return ret;
1502 /* use our invocation id */
1503 ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1504 if (ret != LDB_SUCCESS) return ret;
1506 /* changetime is the current time */
1507 ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1508 if (ret != LDB_SUCCESS) return ret;
1510 /* update the USN */
1511 ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1512 if (ret != LDB_SUCCESS) return ret;
1514 ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1515 if (ret != LDB_SUCCESS) return ret;
1517 /* increase the version by 1 */
1518 status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1519 if (NT_STATUS_IS_OK(status) && old_version >= version) {
1520 version = old_version+1;
1522 vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1523 vers = data_blob_string_const(vstring);
1524 ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1525 if (ret != LDB_SUCCESS) return ret;
1527 dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1528 if (dnstring == NULL) {
1529 return LDB_ERR_OPERATIONS_ERROR;
1531 *v = data_blob_string_const(dnstring);
1537 handle adding a linked attribute
1539 static int replmd_modify_la_add(struct ldb_module *module,
1540 const struct dsdb_schema *schema,
1541 struct ldb_message *msg,
1542 struct ldb_message_element *el,
1543 struct ldb_message_element *old_el,
1544 const struct dsdb_attribute *schema_attr,
1547 struct GUID *msg_guid)
1550 struct parsed_dn *dns, *old_dns;
1551 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1553 struct ldb_val *new_values = NULL;
1554 unsigned int num_new_values = 0;
1555 unsigned old_num_values = old_el?old_el->num_values:0;
1556 const struct GUID *invocation_id;
1557 struct ldb_context *ldb = ldb_module_get_ctx(module);
1560 unix_to_nt_time(&now, t);
1562 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1563 if (ret != LDB_SUCCESS) {
1564 talloc_free(tmp_ctx);
1568 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1569 if (ret != LDB_SUCCESS) {
1570 talloc_free(tmp_ctx);
1574 invocation_id = samdb_ntds_invocation_id(ldb);
1575 if (!invocation_id) {
1576 talloc_free(tmp_ctx);
1577 return LDB_ERR_OPERATIONS_ERROR;
1580 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1581 if (ret != LDB_SUCCESS) {
1582 talloc_free(tmp_ctx);
1586 /* for each new value, see if it exists already with the same GUID */
1587 for (i=0; i<el->num_values; i++) {
1588 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1590 /* this is a new linked attribute value */
1591 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1592 if (new_values == NULL) {
1593 ldb_module_oom(module);
1594 talloc_free(tmp_ctx);
1595 return LDB_ERR_OPERATIONS_ERROR;
1597 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1598 invocation_id, seq_num, seq_num, now, 0, false);
1599 if (ret != LDB_SUCCESS) {
1600 talloc_free(tmp_ctx);
1605 /* this is only allowed if the GUID was
1606 previously deleted. */
1607 uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1609 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1610 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1611 el->name, GUID_string(tmp_ctx, p->guid));
1612 talloc_free(tmp_ctx);
1613 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1615 ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1616 invocation_id, seq_num, seq_num, now, 0, false);
1617 if (ret != LDB_SUCCESS) {
1618 talloc_free(tmp_ctx);
1623 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1624 if (ret != LDB_SUCCESS) {
1625 talloc_free(tmp_ctx);
1630 /* add the new ones on to the end of the old values, constructing a new el->values */
1631 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1633 old_num_values+num_new_values);
1634 if (el->values == NULL) {
1635 ldb_module_oom(module);
1636 return LDB_ERR_OPERATIONS_ERROR;
1639 memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1640 el->num_values = old_num_values + num_new_values;
1642 talloc_steal(msg->elements, el->values);
1643 talloc_steal(el->values, new_values);
1645 talloc_free(tmp_ctx);
1647 /* we now tell the backend to replace all existing values
1648 with the one we have constructed */
1649 el->flags = LDB_FLAG_MOD_REPLACE;
1656 handle deleting all active linked attributes
1658 static int replmd_modify_la_delete(struct ldb_module *module,
1659 const struct dsdb_schema *schema,
1660 struct ldb_message *msg,
1661 struct ldb_message_element *el,
1662 struct ldb_message_element *old_el,
1663 const struct dsdb_attribute *schema_attr,
1666 struct GUID *msg_guid)
1669 struct parsed_dn *dns, *old_dns;
1670 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1672 const struct GUID *invocation_id;
1673 struct ldb_context *ldb = ldb_module_get_ctx(module);
1676 unix_to_nt_time(&now, t);
1678 /* check if there is nothing to delete */
1679 if ((!old_el || old_el->num_values == 0) &&
1680 el->num_values == 0) {
1684 if (!old_el || old_el->num_values == 0) {
1685 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1688 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1689 if (ret != LDB_SUCCESS) {
1690 talloc_free(tmp_ctx);
1694 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1695 if (ret != LDB_SUCCESS) {
1696 talloc_free(tmp_ctx);
1700 invocation_id = samdb_ntds_invocation_id(ldb);
1701 if (!invocation_id) {
1702 return LDB_ERR_OPERATIONS_ERROR;
1705 ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1706 if (ret != LDB_SUCCESS) {
1707 talloc_free(tmp_ctx);
1713 /* see if we are being asked to delete any links that
1714 don't exist or are already deleted */
1715 for (i=0; i<el->num_values; i++) {
1716 struct parsed_dn *p = &dns[i];
1717 struct parsed_dn *p2;
1720 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1722 ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1723 el->name, GUID_string(tmp_ctx, p->guid));
1724 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1726 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1727 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1728 ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1729 el->name, GUID_string(tmp_ctx, p->guid));
1730 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1734 /* for each new value, see if it exists already with the same GUID
1735 if it is not already deleted and matches the delete list then delete it
1737 for (i=0; i<old_el->num_values; i++) {
1738 struct parsed_dn *p = &old_dns[i];
1741 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1745 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1746 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1748 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1749 invocation_id, seq_num, seq_num, now, 0, true);
1750 if (ret != LDB_SUCCESS) {
1751 talloc_free(tmp_ctx);
1755 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1756 if (ret != LDB_SUCCESS) {
1757 talloc_free(tmp_ctx);
1762 el->values = talloc_steal(msg->elements, old_el->values);
1763 el->num_values = old_el->num_values;
1765 talloc_free(tmp_ctx);
1767 /* we now tell the backend to replace all existing values
1768 with the one we have constructed */
1769 el->flags = LDB_FLAG_MOD_REPLACE;
1775 handle replacing a linked attribute
1777 static int replmd_modify_la_replace(struct ldb_module *module,
1778 const struct dsdb_schema *schema,
1779 struct ldb_message *msg,
1780 struct ldb_message_element *el,
1781 struct ldb_message_element *old_el,
1782 const struct dsdb_attribute *schema_attr,
1785 struct GUID *msg_guid)
1788 struct parsed_dn *dns, *old_dns;
1789 TALLOC_CTX *tmp_ctx = talloc_new(msg);
1791 const struct GUID *invocation_id;
1792 struct ldb_context *ldb = ldb_module_get_ctx(module);
1793 struct ldb_val *new_values = NULL;
1794 unsigned int num_new_values = 0;
1795 unsigned int old_num_values = old_el?old_el->num_values:0;
1798 unix_to_nt_time(&now, t);
1800 /* check if there is nothing to replace */
1801 if ((!old_el || old_el->num_values == 0) &&
1802 el->num_values == 0) {
1806 ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1807 if (ret != LDB_SUCCESS) {
1808 talloc_free(tmp_ctx);
1812 ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1813 if (ret != LDB_SUCCESS) {
1814 talloc_free(tmp_ctx);
1818 invocation_id = samdb_ntds_invocation_id(ldb);
1819 if (!invocation_id) {
1820 return LDB_ERR_OPERATIONS_ERROR;
1823 ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1824 if (ret != LDB_SUCCESS) {
1825 talloc_free(tmp_ctx);
1829 /* mark all the old ones as deleted */
1830 for (i=0; i<old_num_values; i++) {
1831 struct parsed_dn *old_p = &old_dns[i];
1832 struct parsed_dn *p;
1833 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1835 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1837 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1838 if (ret != LDB_SUCCESS) {
1839 talloc_free(tmp_ctx);
1843 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1845 /* we don't delete it if we are re-adding it */
1849 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1850 invocation_id, seq_num, seq_num, now, 0, true);
1851 if (ret != LDB_SUCCESS) {
1852 talloc_free(tmp_ctx);
1857 /* for each new value, either update its meta-data, or add it
1860 for (i=0; i<el->num_values; i++) {
1861 struct parsed_dn *p = &dns[i], *old_p;
1864 (old_p = parsed_dn_find(old_dns,
1865 old_num_values, p->guid, NULL)) != NULL) {
1866 /* update in place */
1867 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1868 old_p->dsdb_dn, invocation_id,
1869 seq_num, seq_num, now, 0, false);
1870 if (ret != LDB_SUCCESS) {
1871 talloc_free(tmp_ctx);
1876 new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1878 if (new_values == NULL) {
1879 ldb_module_oom(module);
1880 talloc_free(tmp_ctx);
1881 return LDB_ERR_OPERATIONS_ERROR;
1883 ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1884 invocation_id, seq_num, seq_num, now, 0, false);
1885 if (ret != LDB_SUCCESS) {
1886 talloc_free(tmp_ctx);
1892 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1893 if (ret != LDB_SUCCESS) {
1894 talloc_free(tmp_ctx);
1899 /* add the new values to the end of old_el */
1900 if (num_new_values != 0) {
1901 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1902 struct ldb_val, old_num_values+num_new_values);
1903 if (el->values == NULL) {
1904 ldb_module_oom(module);
1905 return LDB_ERR_OPERATIONS_ERROR;
1907 memcpy(&el->values[old_num_values], &new_values[0],
1908 sizeof(struct ldb_val)*num_new_values);
1909 el->num_values = old_num_values + num_new_values;
1910 talloc_steal(msg->elements, new_values);
1912 el->values = old_el->values;
1913 el->num_values = old_el->num_values;
1914 talloc_steal(msg->elements, el->values);
1917 talloc_free(tmp_ctx);
1919 /* we now tell the backend to replace all existing values
1920 with the one we have constructed */
1921 el->flags = LDB_FLAG_MOD_REPLACE;
1928 handle linked attributes in modify requests
1930 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1931 struct ldb_message *msg,
1932 uint64_t seq_num, time_t t)
1934 struct ldb_result *res;
1937 struct ldb_context *ldb = ldb_module_get_ctx(module);
1938 struct ldb_message *old_msg;
1940 const struct dsdb_schema *schema;
1941 struct GUID old_guid;
1944 /* there the replmd_update_rpmd code has already
1945 * checked and saw that there are no linked
1950 #if !W2K3_LINKED_ATTRIBUTES
1954 if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1955 /* don't do anything special for linked attributes */
1959 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1960 DSDB_SEARCH_SHOW_DELETED |
1961 DSDB_SEARCH_REVEAL_INTERNALS |
1962 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1963 if (ret != LDB_SUCCESS) {
1966 schema = dsdb_get_schema(ldb, res);
1968 return LDB_ERR_OPERATIONS_ERROR;
1971 old_msg = res->msgs[0];
1973 old_guid = samdb_result_guid(old_msg, "objectGUID");
1975 for (i=0; i<msg->num_elements; i++) {
1976 struct ldb_message_element *el = &msg->elements[i];
1977 struct ldb_message_element *old_el, *new_el;
1978 const struct dsdb_attribute *schema_attr
1979 = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1981 ldb_asprintf_errstring(ldb,
1982 "attribute %s is not a valid attribute in schema", el->name);
1983 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1985 if (schema_attr->linkID == 0) {
1988 if ((schema_attr->linkID & 1) == 1) {
1989 /* Odd is for the target. Illegal to modify */
1990 ldb_asprintf_errstring(ldb,
1991 "attribute %s must not be modified directly, it is a linked attribute", el->name);
1992 return LDB_ERR_UNWILLING_TO_PERFORM;
1994 old_el = ldb_msg_find_element(old_msg, el->name);
1995 switch (el->flags & LDB_FLAG_MOD_MASK) {
1996 case LDB_FLAG_MOD_REPLACE:
1997 ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1999 case LDB_FLAG_MOD_DELETE:
2000 ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
2002 case LDB_FLAG_MOD_ADD:
2003 ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
2006 ldb_asprintf_errstring(ldb,
2007 "invalid flags 0x%x for %s linked attribute",
2008 el->flags, el->name);
2009 return LDB_ERR_UNWILLING_TO_PERFORM;
2011 if (ret != LDB_SUCCESS) {
2015 ldb_msg_remove_attr(old_msg, el->name);
2017 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2018 new_el->num_values = el->num_values;
2019 new_el->values = talloc_steal(msg->elements, el->values);
2021 /* TODO: this relises a bit too heavily on the exact
2022 behaviour of ldb_msg_find_element and
2023 ldb_msg_remove_element */
2024 old_el = ldb_msg_find_element(msg, el->name);
2026 ldb_msg_remove_element(msg, old_el);
2037 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2039 struct ldb_context *ldb;
2040 struct replmd_replicated_request *ac;
2041 struct ldb_request *down_req;
2042 struct ldb_message *msg;
2043 time_t t = time(NULL);
2045 bool is_urgent = false;
2047 /* do not manipulate our control entries */
2048 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2049 return ldb_next_request(module, req);
2052 ldb = ldb_module_get_ctx(module);
2054 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2056 ac = replmd_ctx_init(module, req);
2058 return LDB_ERR_OPERATIONS_ERROR;
2061 /* we have to copy the message as the caller might have it as a const */
2062 msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2066 return LDB_ERR_OPERATIONS_ERROR;
2069 ldb_msg_remove_attr(msg, "whenChanged");
2070 ldb_msg_remove_attr(msg, "uSNChanged");
2072 ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t, &is_urgent);
2073 if (ret != LDB_SUCCESS) {
2078 ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
2079 if (ret != LDB_SUCCESS) {
2085 * - replace the old object with the newly constructed one
2088 ac->is_urgent = is_urgent;
2090 ret = ldb_build_mod_req(&down_req, ldb, ac,
2093 ac, replmd_op_callback,
2095 if (ret != LDB_SUCCESS) {
2099 talloc_steal(down_req, msg);
2101 /* we only change whenChanged and uSNChanged if the seq_num
2103 if (ac->seq_num != 0) {
2104 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2109 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2115 /* go on with the call chain */
2116 return ldb_next_request(module, down_req);
2119 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2122 handle a rename request
2124 On a rename we need to do an extra ldb_modify which sets the
2125 whenChanged and uSNChanged attributes. We do this in a callback after the success.
2127 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2129 struct ldb_context *ldb;
2130 struct replmd_replicated_request *ac;
2132 struct ldb_request *down_req;
2134 /* do not manipulate our control entries */
2135 if (ldb_dn_is_special(req->op.mod.message->dn)) {
2136 return ldb_next_request(module, req);
2139 ldb = ldb_module_get_ctx(module);
2141 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2143 ac = replmd_ctx_init(module, req);
2145 return LDB_ERR_OPERATIONS_ERROR;
2147 ret = ldb_build_rename_req(&down_req, ldb, ac,
2148 ac->req->op.rename.olddn,
2149 ac->req->op.rename.newdn,
2151 ac, replmd_rename_callback,
2154 if (ret != LDB_SUCCESS) {
2159 /* go on with the call chain */
2160 return ldb_next_request(module, down_req);
2163 /* After the rename is compleated, update the whenchanged etc */
2164 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2166 struct ldb_context *ldb;
2167 struct replmd_replicated_request *ac;
2168 struct ldb_request *down_req;
2169 struct ldb_message *msg;
2170 time_t t = time(NULL);
2173 ac = talloc_get_type(req->context, struct replmd_replicated_request);
2174 ldb = ldb_module_get_ctx(ac->module);
2176 if (ares->error != LDB_SUCCESS) {
2177 return ldb_module_done(ac->req, ares->controls,
2178 ares->response, ares->error);
2181 if (ares->type != LDB_REPLY_DONE) {
2182 ldb_set_errstring(ldb,
2183 "invalid ldb_reply_type in callback");
2185 return ldb_module_done(ac->req, NULL, NULL,
2186 LDB_ERR_OPERATIONS_ERROR);
2189 /* Get a sequence number from the backend */
2190 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2191 if (ret != LDB_SUCCESS) {
2196 * - replace the old object with the newly constructed one
2199 msg = ldb_msg_new(ac);
2202 return LDB_ERR_OPERATIONS_ERROR;
2205 msg->dn = ac->req->op.rename.newdn;
2207 ret = ldb_build_mod_req(&down_req, ldb, ac,
2210 ac, replmd_op_callback,
2213 if (ret != LDB_SUCCESS) {
2217 talloc_steal(down_req, msg);
2219 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2224 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2229 /* go on with the call chain - do the modify after the rename */
2230 return ldb_next_request(ac->module, down_req);
2234 remove links from objects that point at this object when an object
2237 static int replmd_delete_remove_link(struct ldb_module *module,
2238 const struct dsdb_schema *schema,
2240 struct ldb_message_element *el,
2241 const struct dsdb_attribute *sa)
2244 TALLOC_CTX *tmp_ctx = talloc_new(module);
2245 struct ldb_context *ldb = ldb_module_get_ctx(module);
2247 for (i=0; i<el->num_values; i++) {
2248 struct dsdb_dn *dsdb_dn;
2252 struct ldb_message *msg;
2253 const struct dsdb_attribute *target_attr;
2254 struct ldb_message_element *el2;
2255 struct ldb_val dn_val;
2257 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2261 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2263 talloc_free(tmp_ctx);
2264 return LDB_ERR_OPERATIONS_ERROR;
2267 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2268 if (!NT_STATUS_IS_OK(status)) {
2269 talloc_free(tmp_ctx);
2270 return LDB_ERR_OPERATIONS_ERROR;
2273 /* remove the link */
2274 msg = ldb_msg_new(tmp_ctx);
2276 ldb_module_oom(module);
2277 talloc_free(tmp_ctx);
2278 return LDB_ERR_OPERATIONS_ERROR;
2282 msg->dn = dsdb_dn->dn;
2284 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2285 if (target_attr == NULL) {
2289 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2290 if (ret != LDB_SUCCESS) {
2291 ldb_module_oom(module);
2292 talloc_free(tmp_ctx);
2293 return LDB_ERR_OPERATIONS_ERROR;
2295 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2296 el2->values = &dn_val;
2297 el2->num_values = 1;
2299 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2300 if (ret != LDB_SUCCESS) {
2301 talloc_free(tmp_ctx);
2305 talloc_free(tmp_ctx);
2311 handle update of replication meta data for deletion of objects
2313 This also handles the mapping of delete to a rename operation
2314 to allow deletes to be replicated.
2316 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2318 int ret = LDB_ERR_OTHER;
2320 struct ldb_dn *old_dn, *new_dn;
2321 const char *rdn_name;
2322 const struct ldb_val *rdn_value, *new_rdn_value;
2324 struct ldb_context *ldb = ldb_module_get_ctx(module);
2325 const struct dsdb_schema *schema;
2326 struct ldb_message *msg, *old_msg;
2327 struct ldb_message_element *el;
2328 TALLOC_CTX *tmp_ctx;
2329 struct ldb_result *res, *parent_res;
2330 const char *preserved_attrs[] = {
2331 /* yes, this really is a hard coded list. See MS-ADTS
2332 section 3.1.1.5.5.1.1 */
2333 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2334 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2335 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2336 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2337 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2338 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2339 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2340 "whenChanged", NULL};
2341 unsigned int i, el_count = 0;
2342 enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2343 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2344 enum deletion_state deletion_state, next_deletion_state;
2347 if (ldb_dn_is_special(req->op.del.dn)) {
2348 return ldb_next_request(module, req);
2351 tmp_ctx = talloc_new(ldb);
2354 return LDB_ERR_OPERATIONS_ERROR;
2357 schema = dsdb_get_schema(ldb, tmp_ctx);
2359 return LDB_ERR_OPERATIONS_ERROR;
2362 old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2364 /* we need the complete msg off disk, so we can work out which
2365 attributes need to be removed */
2366 ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2367 DSDB_SEARCH_SHOW_DELETED |
2368 DSDB_SEARCH_REVEAL_INTERNALS |
2369 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2370 if (ret != LDB_SUCCESS) {
2371 talloc_free(tmp_ctx);
2374 old_msg = res->msgs[0];
2377 ret = dsdb_recyclebin_enabled(module, &enabled);
2378 if (ret != LDB_SUCCESS) {
2379 talloc_free(tmp_ctx);
2383 if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2385 deletion_state = OBJECT_TOMBSTONE;
2386 next_deletion_state = OBJECT_REMOVED;
2387 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2388 deletion_state = OBJECT_RECYCLED;
2389 next_deletion_state = OBJECT_REMOVED;
2391 deletion_state = OBJECT_DELETED;
2392 next_deletion_state = OBJECT_RECYCLED;
2395 deletion_state = OBJECT_NOT_DELETED;
2397 next_deletion_state = OBJECT_DELETED;
2399 next_deletion_state = OBJECT_TOMBSTONE;
2403 if (next_deletion_state == OBJECT_REMOVED) {
2404 struct auth_session_info *session_info =
2405 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2406 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2407 ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2408 ldb_dn_get_linearized(old_msg->dn));
2409 return LDB_ERR_UNWILLING_TO_PERFORM;
2412 /* it is already deleted - really remove it this time */
2413 talloc_free(tmp_ctx);
2414 return ldb_next_request(module, req);
2417 rdn_name = ldb_dn_get_rdn_name(old_dn);
2418 rdn_value = ldb_dn_get_rdn_val(old_dn);
2420 msg = ldb_msg_new(tmp_ctx);
2422 ldb_module_oom(module);
2423 talloc_free(tmp_ctx);
2424 return LDB_ERR_OPERATIONS_ERROR;
2429 if (deletion_state == OBJECT_NOT_DELETED){
2430 /* work out where we will be renaming this object to */
2431 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2432 if (ret != LDB_SUCCESS) {
2433 /* this is probably an attempted delete on a partition
2434 * that doesn't allow delete operations, such as the
2435 * schema partition */
2436 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2437 ldb_dn_get_linearized(old_dn));
2438 talloc_free(tmp_ctx);
2439 return LDB_ERR_UNWILLING_TO_PERFORM;
2442 /* get the objects GUID from the search we just did */
2443 guid = samdb_result_guid(old_msg, "objectGUID");
2445 /* Add a formatted child */
2446 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2449 GUID_string(tmp_ctx, &guid));
2451 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2452 ldb_dn_get_linearized(new_dn)));
2453 talloc_free(tmp_ctx);
2454 return LDB_ERR_OPERATIONS_ERROR;
2457 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2458 if (ret != LDB_SUCCESS) {
2459 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2460 ldb_module_oom(module);
2461 talloc_free(tmp_ctx);
2464 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2468 now we need to modify the object in the following ways:
2470 - add isDeleted=TRUE
2471 - update rDN and name, with new rDN
2472 - remove linked attributes
2473 - remove objectCategory and sAMAccountType
2474 - remove attribs not on the preserved list
2475 - preserved if in above list, or is rDN
2476 - remove all linked attribs from this object
2477 - remove all links from other objects to this object
2478 - add lastKnownParent
2479 - update replPropertyMetaData?
2481 see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2484 /* we need the storage form of the parent GUID */
2485 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2486 ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2487 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2488 DSDB_SEARCH_REVEAL_INTERNALS|
2489 DSDB_SEARCH_SHOW_DELETED);
2490 if (ret != LDB_SUCCESS) {
2491 talloc_free(tmp_ctx);
2495 if (deletion_state == OBJECT_NOT_DELETED){
2496 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2497 ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2498 if (ret != LDB_SUCCESS) {
2499 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2500 ldb_module_oom(module);
2501 talloc_free(tmp_ctx);
2504 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2507 switch (next_deletion_state){
2509 case OBJECT_DELETED:
2511 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2512 if (ret != LDB_SUCCESS) {
2513 DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2514 ldb_module_oom(module);
2515 talloc_free(tmp_ctx);
2518 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2520 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_DELETE, NULL);
2521 if (ret != LDB_SUCCESS) {
2522 talloc_free(tmp_ctx);
2523 ldb_module_oom(module);
2527 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_DELETE, NULL);
2528 if (ret != LDB_SUCCESS) {
2529 talloc_free(tmp_ctx);
2530 ldb_module_oom(module);
2536 case OBJECT_RECYCLED:
2537 case OBJECT_TOMBSTONE:
2539 /* we also mark it as recycled, meaning this object can't be
2540 recovered (we are stripping its attributes) */
2541 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2542 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2543 if (ret != LDB_SUCCESS) {
2544 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2545 ldb_module_oom(module);
2546 talloc_free(tmp_ctx);
2549 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2552 /* work out which of the old attributes we will be removing */
2553 for (i=0; i<old_msg->num_elements; i++) {
2554 const struct dsdb_attribute *sa;
2555 el = &old_msg->elements[i];
2556 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2558 talloc_free(tmp_ctx);
2559 return LDB_ERR_OPERATIONS_ERROR;
2561 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2562 /* don't remove the rDN */
2565 if (sa->linkID && sa->linkID & 1) {
2566 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2567 if (ret != LDB_SUCCESS) {
2568 talloc_free(tmp_ctx);
2569 return LDB_ERR_OPERATIONS_ERROR;
2573 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2576 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2577 if (ret != LDB_SUCCESS) {
2578 talloc_free(tmp_ctx);
2579 ldb_module_oom(module);
2589 if (deletion_state == OBJECT_NOT_DELETED) {
2590 /* work out what the new rdn value is, for updating the
2591 rDN and name fields */
2592 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2594 ret = ldb_msg_add_value(msg, strlower_talloc(tmp_ctx, rdn_name), new_rdn_value, &el);
2595 if (ret != LDB_SUCCESS) {
2596 talloc_free(tmp_ctx);
2599 el->flags = LDB_FLAG_MOD_REPLACE;
2601 el = ldb_msg_find_element(old_msg, "name");
2603 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2604 if (ret != LDB_SUCCESS) {
2605 talloc_free(tmp_ctx);
2608 el->flags = LDB_FLAG_MOD_REPLACE;
2612 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2613 if (ret != LDB_SUCCESS) {
2614 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2615 ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2616 talloc_free(tmp_ctx);
2620 if (deletion_state == OBJECT_NOT_DELETED) {
2621 /* now rename onto the new DN */
2622 ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2623 if (ret != LDB_SUCCESS){
2624 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2625 ldb_dn_get_linearized(old_dn),
2626 ldb_dn_get_linearized(new_dn),
2627 ldb_errstring(ldb)));
2628 talloc_free(tmp_ctx);
2633 talloc_free(tmp_ctx);
2635 return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2640 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2645 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2647 int ret = LDB_ERR_OTHER;
2648 /* TODO: do some error mapping */
2652 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2654 struct ldb_context *ldb;
2655 struct ldb_request *change_req;
2656 enum ndr_err_code ndr_err;
2657 struct ldb_message *msg;
2658 struct replPropertyMetaDataBlob *md;
2659 struct ldb_val md_value;
2664 * TODO: check if the parent object exist
2668 * TODO: handle the conflict case where an object with the
2672 ldb = ldb_module_get_ctx(ar->module);
2673 msg = ar->objs->objects[ar->index_current].msg;
2674 md = ar->objs->objects[ar->index_current].meta_data;
2676 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2677 if (ret != LDB_SUCCESS) {
2678 return replmd_replicated_request_error(ar, ret);
2681 ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2682 if (ret != LDB_SUCCESS) {
2683 return replmd_replicated_request_error(ar, ret);
2686 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2687 if (ret != LDB_SUCCESS) {
2688 return replmd_replicated_request_error(ar, ret);
2691 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2692 if (ret != LDB_SUCCESS) {
2693 return replmd_replicated_request_error(ar, ret);
2696 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2697 if (ret != LDB_SUCCESS) {
2698 return replmd_replicated_request_error(ar, ret);
2701 /* remove any message elements that have zero values */
2702 for (i=0; i<msg->num_elements; i++) {
2703 struct ldb_message_element *el = &msg->elements[i];
2705 if (el->num_values == 0) {
2706 DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2708 memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2709 msg->num_elements--;
2716 * the meta data array is already sorted by the caller
2718 for (i=0; i < md->ctr.ctr1.count; i++) {
2719 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2721 ndr_err = ndr_push_struct_blob(&md_value, msg,
2722 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2724 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2725 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2726 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2727 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2729 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2730 if (ret != LDB_SUCCESS) {
2731 return replmd_replicated_request_error(ar, ret);
2734 replmd_ldb_message_sort(msg, ar->schema);
2737 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2738 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2742 ret = ldb_build_add_req(&change_req,
2750 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2752 return ldb_next_request(ar->module, change_req);
2756 return true if an update is newer than an existing entry
2757 see section 5.11 of MS-ADTS
2759 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2760 const struct GUID *update_invocation_id,
2761 uint32_t current_version,
2762 uint32_t update_version,
2763 NTTIME current_change_time,
2764 NTTIME update_change_time)
2766 if (update_version != current_version) {
2767 return update_version > current_version;
2769 if (update_change_time > current_change_time) {
2772 if (update_change_time == current_change_time) {
2773 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2778 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2779 struct replPropertyMetaData1 *new_m)
2781 return replmd_update_is_newer(&cur_m->originating_invocation_id,
2782 &new_m->originating_invocation_id,
2785 cur_m->originating_change_time,
2786 new_m->originating_change_time);
2789 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2791 struct ldb_context *ldb;
2792 struct ldb_request *change_req;
2793 enum ndr_err_code ndr_err;
2794 struct ldb_message *msg;
2795 struct replPropertyMetaDataBlob *rmd;
2796 struct replPropertyMetaDataBlob omd;
2797 const struct ldb_val *omd_value;
2798 struct replPropertyMetaDataBlob nmd;
2799 struct ldb_val nmd_value;
2802 unsigned int removed_attrs = 0;
2805 ldb = ldb_module_get_ctx(ar->module);
2806 msg = ar->objs->objects[ar->index_current].msg;
2807 rmd = ar->objs->objects[ar->index_current].meta_data;
2812 * TODO: check repl data is correct after a rename
2814 if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2815 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2816 ldb_dn_get_linearized(ar->search_msg->dn),
2817 ldb_dn_get_linearized(msg->dn));
2818 if (dsdb_module_rename(ar->module,
2819 ar->search_msg->dn, msg->dn,
2820 DSDB_FLAG_OWN_MODULE) != LDB_SUCCESS) {
2821 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2822 ldb_dn_get_linearized(ar->search_msg->dn),
2823 ldb_dn_get_linearized(msg->dn),
2824 ldb_errstring(ldb));
2825 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2829 /* find existing meta data */
2830 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2832 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2833 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2834 (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2835 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2836 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2837 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2840 if (omd.version != 1) {
2841 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2847 nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2848 nmd.ctr.ctr1.array = talloc_array(ar,
2849 struct replPropertyMetaData1,
2850 nmd.ctr.ctr1.count);
2851 if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2853 /* first copy the old meta data */
2854 for (i=0; i < omd.ctr.ctr1.count; i++) {
2855 nmd.ctr.ctr1.array[ni] = omd.ctr.ctr1.array[i];
2859 /* now merge in the new meta data */
2860 for (i=0; i < rmd->ctr.ctr1.count; i++) {
2863 for (j=0; j < ni; j++) {
2866 if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2870 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2871 &rmd->ctr.ctr1.array[i]);
2873 /* replace the entry */
2874 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2879 if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType) {
2880 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
2881 msg->elements[i-removed_attrs].name,
2882 ldb_dn_get_linearized(msg->dn),
2883 GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2886 /* we don't want to apply this change so remove the attribute */
2887 ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2894 if (found) continue;
2896 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2901 * finally correct the size of the meta_data array
2903 nmd.ctr.ctr1.count = ni;
2906 * the rdn attribute (the alias for the name attribute),
2907 * 'cn' for most objects is the last entry in the meta data array
2910 * sort the new meta data array
2912 ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2913 if (ret != LDB_SUCCESS) {
2918 * check if some replicated attributes left, otherwise skip the ldb_modify() call
2920 if (msg->num_elements == 0) {
2921 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2924 ar->index_current++;
2925 return replmd_replicated_apply_next(ar);
2928 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2929 ar->index_current, msg->num_elements);
2931 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2932 if (ret != LDB_SUCCESS) {
2933 return replmd_replicated_request_error(ar, ret);
2936 for (i=0; i<ni; i++) {
2937 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2940 /* create the meta data value */
2941 ndr_err = ndr_push_struct_blob(&nmd_value, msg,
2942 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2944 (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2945 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2946 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2947 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2951 * when we know that we'll modify the record, add the whenChanged, uSNChanged
2952 * and replPopertyMetaData attributes
2954 ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2955 if (ret != LDB_SUCCESS) {
2956 return replmd_replicated_request_error(ar, ret);
2958 ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2959 if (ret != LDB_SUCCESS) {
2960 return replmd_replicated_request_error(ar, ret);
2962 ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2963 if (ret != LDB_SUCCESS) {
2964 return replmd_replicated_request_error(ar, ret);
2967 replmd_ldb_message_sort(msg, ar->schema);
2969 /* we want to replace the old values */
2970 for (i=0; i < msg->num_elements; i++) {
2971 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2975 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2976 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2980 ret = ldb_build_mod_req(&change_req,
2988 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2990 return ldb_next_request(ar->module, change_req);
2993 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2994 struct ldb_reply *ares)
2996 struct replmd_replicated_request *ar = talloc_get_type(req->context,
2997 struct replmd_replicated_request);
3001 return ldb_module_done(ar->req, NULL, NULL,
3002 LDB_ERR_OPERATIONS_ERROR);
3004 if (ares->error != LDB_SUCCESS &&
3005 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3006 return ldb_module_done(ar->req, ares->controls,
3007 ares->response, ares->error);
3010 switch (ares->type) {
3011 case LDB_REPLY_ENTRY:
3012 ar->search_msg = talloc_steal(ar, ares->message);
3015 case LDB_REPLY_REFERRAL:
3016 /* we ignore referrals */
3019 case LDB_REPLY_DONE:
3020 if (ar->search_msg != NULL) {
3021 ret = replmd_replicated_apply_merge(ar);
3023 ret = replmd_replicated_apply_add(ar);
3025 if (ret != LDB_SUCCESS) {
3026 return ldb_module_done(ar->req, NULL, NULL, ret);
3034 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3036 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3038 struct ldb_context *ldb;
3042 struct ldb_request *search_req;
3043 struct ldb_search_options_control *options;
3045 if (ar->index_current >= ar->objs->num_objects) {
3046 /* done with it, go to next stage */
3047 return replmd_replicated_uptodate_vector(ar);
3050 ldb = ldb_module_get_ctx(ar->module);
3051 ar->search_msg = NULL;
3053 tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3054 if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3056 filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3057 if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3058 talloc_free(tmp_str);
3060 ret = ldb_build_search_req(&search_req,
3069 replmd_replicated_apply_search_callback,
3072 ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
3073 if (ret != LDB_SUCCESS) {
3077 /* we need to cope with cross-partition links, so search for
3078 the GUID over all partitions */
3079 options = talloc(search_req, struct ldb_search_options_control);
3080 if (options == NULL) {
3081 DEBUG(0, (__location__ ": out of memory\n"));
3082 return LDB_ERR_OPERATIONS_ERROR;
3084 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3086 ret = ldb_request_add_control(search_req,
3087 LDB_CONTROL_SEARCH_OPTIONS_OID,
3089 if (ret != LDB_SUCCESS) {
3093 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3095 return ldb_next_request(ar->module, search_req);
3098 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
3099 struct ldb_reply *ares)
3101 struct ldb_context *ldb;
3102 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3103 struct replmd_replicated_request);
3104 ldb = ldb_module_get_ctx(ar->module);
3107 return ldb_module_done(ar->req, NULL, NULL,
3108 LDB_ERR_OPERATIONS_ERROR);
3110 if (ares->error != LDB_SUCCESS) {
3111 return ldb_module_done(ar->req, ares->controls,
3112 ares->response, ares->error);
3115 if (ares->type != LDB_REPLY_DONE) {
3116 ldb_set_errstring(ldb, "Invalid reply type\n!");
3117 return ldb_module_done(ar->req, NULL, NULL,
3118 LDB_ERR_OPERATIONS_ERROR);
3123 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3126 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3128 struct ldb_context *ldb;
3129 struct ldb_request *change_req;
3130 enum ndr_err_code ndr_err;
3131 struct ldb_message *msg;
3132 struct replUpToDateVectorBlob ouv;
3133 const struct ldb_val *ouv_value;
3134 const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3135 struct replUpToDateVectorBlob nuv;
3136 struct ldb_val nuv_value;
3137 struct ldb_message_element *nuv_el = NULL;
3138 const struct GUID *our_invocation_id;
3139 struct ldb_message_element *orf_el = NULL;
3140 struct repsFromToBlob nrf;
3141 struct ldb_val *nrf_value = NULL;
3142 struct ldb_message_element *nrf_el = NULL;
3146 time_t t = time(NULL);
3150 ldb = ldb_module_get_ctx(ar->module);
3151 ruv = ar->objs->uptodateness_vector;
3157 unix_to_nt_time(&now, t);
3160 * first create the new replUpToDateVector
3162 ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
3164 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
3165 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
3166 (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3167 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3168 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3169 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3172 if (ouv.version != 2) {
3173 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3178 * the new uptodateness vector will at least
3179 * contain 1 entry, one for the source_dsa
3181 * plus optional values from our old vector and the one from the source_dsa
3183 nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
3184 if (ruv) nuv.ctr.ctr2.count += ruv->count;
3185 nuv.ctr.ctr2.cursors = talloc_array(ar,
3186 struct drsuapi_DsReplicaCursor2,
3187 nuv.ctr.ctr2.count);
3188 if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3190 /* first copy the old vector */
3191 for (i=0; i < ouv.ctr.ctr2.count; i++) {
3192 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
3196 /* get our invocation_id if we have one already attached to the ldb */
3197 our_invocation_id = samdb_ntds_invocation_id(ldb);
3199 /* merge in the source_dsa vector is available */
3200 for (i=0; (ruv && i < ruv->count); i++) {
3203 if (our_invocation_id &&
3204 GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3205 our_invocation_id)) {
3209 for (j=0; j < ni; j++) {
3210 if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3211 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3218 * we update only the highest_usn and not the latest_sync_success time,
3219 * because the last success stands for direct replication
3221 if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3222 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3227 if (found) continue;
3229 /* if it's not there yet, add it */
3230 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3235 * merge in the current highwatermark for the source_dsa
3238 for (j=0; j < ni; j++) {
3239 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
3240 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3247 * here we update the highest_usn and last_sync_success time
3248 * because we're directly replicating from the source_dsa
3250 * and use the tmp_highest_usn because this is what we have just applied
3253 nuv.ctr.ctr2.cursors[j].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3254 nuv.ctr.ctr2.cursors[j].last_sync_success = now;
3259 * here we update the highest_usn and last_sync_success time
3260 * because we're directly replicating from the source_dsa
3262 * and use the tmp_highest_usn because this is what we have just applied
3265 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
3266 nuv.ctr.ctr2.cursors[ni].highest_usn = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3267 nuv.ctr.ctr2.cursors[ni].last_sync_success = now;
3272 * finally correct the size of the cursors array
3274 nuv.ctr.ctr2.count = ni;
3279 TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
3282 * create the change ldb_message
3284 msg = ldb_msg_new(ar);
3285 if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3286 msg->dn = ar->search_msg->dn;
3288 ndr_err = ndr_push_struct_blob(&nuv_value, msg,
3289 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3291 (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3292 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3293 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3294 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3296 ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3297 if (ret != LDB_SUCCESS) {
3298 return replmd_replicated_request_error(ar, ret);
3300 nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3303 * now create the new repsFrom value from the given repsFromTo1 structure
3307 nrf.ctr.ctr1 = *ar->objs->source_dsa;
3308 /* and fix some values... */
3309 nrf.ctr.ctr1.consecutive_sync_failures = 0;
3310 nrf.ctr.ctr1.last_success = now;
3311 nrf.ctr.ctr1.last_attempt = now;
3312 nrf.ctr.ctr1.result_last_attempt = WERR_OK;
3313 nrf.ctr.ctr1.highwatermark.highest_usn = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3316 * first see if we already have a repsFrom value for the current source dsa
3317 * if so we'll later replace this value
3319 orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3321 for (i=0; i < orf_el->num_values; i++) {
3322 struct repsFromToBlob *trf;
3324 trf = talloc(ar, struct repsFromToBlob);
3325 if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3327 ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
3328 (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3329 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3330 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3331 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3334 if (trf->version != 1) {
3335 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3339 * we compare the source dsa objectGUID not the invocation_id
3340 * because we want only one repsFrom value per source dsa
3341 * and when the invocation_id of the source dsa has changed we don't need
3342 * the old repsFrom with the old invocation_id
3344 if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3345 &ar->objs->source_dsa->source_dsa_obj_guid)) {
3351 nrf_value = &orf_el->values[i];
3356 * copy over all old values to the new ldb_message
3358 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3359 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3364 * if we haven't found an old repsFrom value for the current source dsa
3365 * we'll add a new value
3368 struct ldb_val zero_value;
3369 ZERO_STRUCT(zero_value);
3370 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3371 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3373 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3376 /* we now fill the value which is already attached to ldb_message */
3377 ndr_err = ndr_push_struct_blob(nrf_value, msg,
3378 lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3380 (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3381 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3382 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3383 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3387 * the ldb_message_element for the attribute, has all the old values and the new one
3388 * so we'll replace the whole attribute with all values
3390 nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3393 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3394 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3398 /* prepare the ldb_modify() request */
3399 ret = ldb_build_mod_req(&change_req,
3405 replmd_replicated_uptodate_modify_callback,
3407 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3409 return ldb_next_request(ar->module, change_req);
3412 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3413 struct ldb_reply *ares)
3415 struct replmd_replicated_request *ar = talloc_get_type(req->context,
3416 struct replmd_replicated_request);
3420 return ldb_module_done(ar->req, NULL, NULL,
3421 LDB_ERR_OPERATIONS_ERROR);
3423 if (ares->error != LDB_SUCCESS &&
3424 ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3425 return ldb_module_done(ar->req, ares->controls,
3426 ares->response, ares->error);
3429 switch (ares->type) {
3430 case LDB_REPLY_ENTRY:
3431 ar->search_msg = talloc_steal(ar, ares->message);
3434 case LDB_REPLY_REFERRAL:
3435 /* we ignore referrals */
3438 case LDB_REPLY_DONE:
3439 if (ar->search_msg == NULL) {
3440 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3442 ret = replmd_replicated_uptodate_modify(ar);
3444 if (ret != LDB_SUCCESS) {
3445 return ldb_module_done(ar->req, NULL, NULL, ret);
3454 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3456 struct ldb_context *ldb;
3458 static const char *attrs[] = {
3459 "replUpToDateVector",
3463 struct ldb_request *search_req;
3465 ldb = ldb_module_get_ctx(ar->module);
3466 ar->search_msg = NULL;
3468 ret = ldb_build_search_req(&search_req,
3471 ar->objs->partition_dn,
3477 replmd_replicated_uptodate_search_callback,
3479 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3481 return ldb_next_request(ar->module, search_req);
3486 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3488 struct ldb_context *ldb;
3489 struct dsdb_extended_replicated_objects *objs;
3490 struct replmd_replicated_request *ar;
3491 struct ldb_control **ctrls;
3494 struct replmd_private *replmd_private =
3495 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3497 ldb = ldb_module_get_ctx(module);
3499 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3501 objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3503 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3504 return LDB_ERR_PROTOCOL_ERROR;
3507 if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3508 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3509 objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3510 return LDB_ERR_PROTOCOL_ERROR;
3513 ar = replmd_ctx_init(module, req);
3515 return LDB_ERR_OPERATIONS_ERROR;
3517 /* Set the flags to have the replmd_op_callback run over the full set of objects */
3518 ar->apply_mode = true;
3520 ar->schema = dsdb_get_schema(ldb, ar);
3522 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3524 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3525 return LDB_ERR_CONSTRAINT_VIOLATION;
3528 ctrls = req->controls;
3530 if (req->controls) {
3531 req->controls = talloc_memdup(ar, req->controls,
3532 talloc_get_size(req->controls));
3533 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3536 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3537 if (ret != LDB_SUCCESS) {
3541 ar->controls = req->controls;
3542 req->controls = ctrls;
3544 DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3546 /* save away the linked attributes for the end of the
3548 for (i=0; i<ar->objs->linked_attributes_count; i++) {
3549 struct la_entry *la_entry;
3551 if (replmd_private->la_ctx == NULL) {
3552 replmd_private->la_ctx = talloc_new(replmd_private);
3554 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3555 if (la_entry == NULL) {
3557 return LDB_ERR_OPERATIONS_ERROR;
3559 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3560 if (la_entry->la == NULL) {
3561 talloc_free(la_entry);
3563 return LDB_ERR_OPERATIONS_ERROR;
3565 *la_entry->la = ar->objs->linked_attributes[i];
3567 /* we need to steal the non-scalars so they stay
3568 around until the end of the transaction */
3569 talloc_steal(la_entry->la, la_entry->la->identifier);
3570 talloc_steal(la_entry->la, la_entry->la->value.blob);
3572 DLIST_ADD(replmd_private->la_list, la_entry);
3575 return replmd_replicated_apply_next(ar);
3579 process one linked attribute structure
3581 static int replmd_process_linked_attribute(struct ldb_module *module,
3582 struct la_entry *la_entry)
3584 struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3585 struct ldb_context *ldb = ldb_module_get_ctx(module);
3586 struct ldb_message *msg;
3587 TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3588 const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
3590 const struct dsdb_attribute *attr;
3591 struct dsdb_dn *dsdb_dn;
3592 uint64_t seq_num = 0;
3593 struct ldb_message_element *old_el;
3595 time_t t = time(NULL);
3596 struct ldb_result *res;
3597 const char *attrs[2];
3598 struct parsed_dn *pdn_list, *pdn;
3599 struct GUID guid = GUID_zero();
3601 bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3602 const struct GUID *our_invocation_id;
3605 linked_attributes[0]:
3606 &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
3608 identifier: struct drsuapi_DsReplicaObjectIdentifier
3609 __ndr_size : 0x0000003a (58)
3610 __ndr_size_sid : 0x00000000 (0)
3611 guid : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3613 __ndr_size_dn : 0x00000000 (0)
3615 attid : DRSUAPI_ATTRIBUTE_member (0x1F)
3616 value: struct drsuapi_DsAttributeValue
3617 __ndr_size : 0x0000007e (126)
3619 blob : DATA_BLOB length=126
3620 flags : 0x00000001 (1)
3621 1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
3622 originating_add_time : Wed Sep 2 22:20:01 2009 EST
3623 meta_data: struct drsuapi_DsReplicaMetaData
3624 version : 0x00000015 (21)
3625 originating_change_time : Wed Sep 2 23:39:07 2009 EST
3626 originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
3627 originating_usn : 0x000000000001e19c (123292)
3629 (for cases where the link is to a normal DN)
3630 &target: struct drsuapi_DsReplicaObjectIdentifier3
3631 __ndr_size : 0x0000007e (126)
3632 __ndr_size_sid : 0x0000001c (28)
3633 guid : 7639e594-db75-4086-b0d4-67890ae46031
3634 sid : S-1-5-21-2848215498-2472035911-1947525656-19924
3635 __ndr_size_dn : 0x00000022 (34)
3636 dn : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
3639 /* find the attribute being modified */
3640 attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3642 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3643 talloc_free(tmp_ctx);
3644 return LDB_ERR_OPERATIONS_ERROR;
3647 attrs[0] = attr->lDAPDisplayName;
3650 /* get the existing message from the db for the object with
3651 this GUID, returning attribute being modified. We will then
3652 use this msg as the basis for a modify call */
3653 ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3654 DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3655 DSDB_SEARCH_SHOW_DELETED |
3656 DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3657 DSDB_SEARCH_REVEAL_INTERNALS,
3658 "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3659 if (ret != LDB_SUCCESS) {
3660 talloc_free(tmp_ctx);
3663 if (res->count != 1) {
3664 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3665 GUID_string(tmp_ctx, &la->identifier->guid));
3666 talloc_free(tmp_ctx);
3667 return LDB_ERR_NO_SUCH_OBJECT;
3671 if (msg->num_elements == 0) {
3672 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3673 if (ret != LDB_SUCCESS) {
3674 ldb_module_oom(module);
3675 talloc_free(tmp_ctx);
3676 return LDB_ERR_OPERATIONS_ERROR;
3679 old_el = &msg->elements[0];
3680 old_el->flags = LDB_FLAG_MOD_REPLACE;
3683 /* parse the existing links */
3684 ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3685 if (ret != LDB_SUCCESS) {
3686 talloc_free(tmp_ctx);
3690 /* get our invocationId */
3691 our_invocation_id = samdb_ntds_invocation_id(ldb);
3692 if (!our_invocation_id) {
3693 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
3694 talloc_free(tmp_ctx);
3695 return LDB_ERR_OPERATIONS_ERROR;
3698 ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
3699 if (ret != LDB_SUCCESS) {
3700 talloc_free(tmp_ctx);
3704 status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
3705 if (!W_ERROR_IS_OK(status)) {
3706 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
3707 old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
3708 return LDB_ERR_OPERATIONS_ERROR;
3711 ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3712 if (!NT_STATUS_IS_OK(ntstatus) && active) {
3713 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
3715 ldb_dn_get_linearized(dsdb_dn->dn),
3716 ldb_dn_get_linearized(msg->dn));
3717 return LDB_ERR_OPERATIONS_ERROR;
3720 /* re-resolve the DN by GUID, as the DRS server may give us an
3722 ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn);
3723 if (ret != LDB_SUCCESS) {
3724 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s",
3725 GUID_string(tmp_ctx, &guid),
3726 ldb_dn_get_linearized(dsdb_dn->dn)));
3729 /* see if this link already exists */
3730 pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
3732 /* see if this update is newer than what we have already */
3733 struct GUID invocation_id = GUID_zero();
3734 uint32_t version = 0;
3735 NTTIME change_time = 0;
3736 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
3738 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3739 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3740 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3742 if (!replmd_update_is_newer(&invocation_id,
3743 &la->meta_data.originating_invocation_id,
3745 la->meta_data.version,
3747 la->meta_data.originating_change_time)) {
3748 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3749 old_el->name, ldb_dn_get_linearized(msg->dn),
3750 GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3751 talloc_free(tmp_ctx);
3755 /* get a seq_num for this change */
3756 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3757 if (ret != LDB_SUCCESS) {
3758 talloc_free(tmp_ctx);
3762 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
3763 /* remove the existing backlink */
3764 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3765 if (ret != LDB_SUCCESS) {
3766 talloc_free(tmp_ctx);
3771 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3772 &la->meta_data.originating_invocation_id,
3773 la->meta_data.originating_usn, seq_num,
3774 la->meta_data.originating_change_time,
3775 la->meta_data.version,
3777 if (ret != LDB_SUCCESS) {
3778 talloc_free(tmp_ctx);
3783 /* add the new backlink */
3784 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3785 if (ret != LDB_SUCCESS) {
3786 talloc_free(tmp_ctx);
3791 /* get a seq_num for this change */
3792 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3793 if (ret != LDB_SUCCESS) {
3794 talloc_free(tmp_ctx);
3798 old_el->values = talloc_realloc(msg->elements, old_el->values,
3799 struct ldb_val, old_el->num_values+1);
3800 if (!old_el->values) {
3801 ldb_module_oom(module);
3802 return LDB_ERR_OPERATIONS_ERROR;
3804 old_el->num_values++;
3806 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3807 &la->meta_data.originating_invocation_id,
3808 la->meta_data.originating_usn, seq_num,
3809 la->meta_data.originating_change_time,
3810 la->meta_data.version,
3811 (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3812 if (ret != LDB_SUCCESS) {
3813 talloc_free(tmp_ctx);
3818 ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3820 if (ret != LDB_SUCCESS) {
3821 talloc_free(tmp_ctx);
3827 /* we only change whenChanged and uSNChanged if the seq_num
3829 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3830 talloc_free(tmp_ctx);
3831 return LDB_ERR_OPERATIONS_ERROR;
3834 if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3835 talloc_free(tmp_ctx);
3836 return LDB_ERR_OPERATIONS_ERROR;
3839 ret = dsdb_check_single_valued_link(attr, old_el);
3840 if (ret != LDB_SUCCESS) {
3841 talloc_free(tmp_ctx);
3845 ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
3846 if (ret != LDB_SUCCESS) {
3847 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
3849 ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3850 talloc_free(tmp_ctx);
3854 talloc_free(tmp_ctx);
3859 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3861 if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3862 return replmd_extended_replicated_objects(module, req);
3865 return ldb_next_request(module, req);
3870 we hook into the transaction operations to allow us to
3871 perform the linked attribute updates at the end of the whole
3872 transaction. This allows a forward linked attribute to be created
3873 before the object is created. During a vampire, w2k8 sends us linked
3874 attributes before the objects they are part of.
3876 static int replmd_start_transaction(struct ldb_module *module)
3878 /* create our private structure for this transaction */
3879 struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3880 struct replmd_private);
3881 replmd_txn_cleanup(replmd_private);
3883 /* free any leftover mod_usn records from cancelled
3885 while (replmd_private->ncs) {
3886 struct nc_entry *e = replmd_private->ncs;
3887 DLIST_REMOVE(replmd_private->ncs, e);
3891 return ldb_next_start_trans(module);
3895 on prepare commit we loop over our queued la_context structures and
3898 static int replmd_prepare_commit(struct ldb_module *module)
3900 struct replmd_private *replmd_private =
3901 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3902 struct la_entry *la, *prev;
3903 struct la_backlink *bl;
3906 /* walk the list backwards, to do the first entry first, as we
3907 * added the entries with DLIST_ADD() which puts them at the
3908 * start of the list */
3909 for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
3910 prev = DLIST_PREV(la);
3911 DLIST_REMOVE(replmd_private->la_list, la);
3912 ret = replmd_process_linked_attribute(module, la);
3913 if (ret != LDB_SUCCESS) {
3914 replmd_txn_cleanup(replmd_private);
3919 /* process our backlink list, creating and deleting backlinks
3921 for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3922 ret = replmd_process_backlink(module, bl);
3923 if (ret != LDB_SUCCESS) {
3924 replmd_txn_cleanup(replmd_private);
3929 replmd_txn_cleanup(replmd_private);
3931 /* possibly change @REPLCHANGED */
3932 ret = replmd_notify_store(module);
3933 if (ret != LDB_SUCCESS) {
3937 return ldb_next_prepare_commit(module);
3940 static int replmd_del_transaction(struct ldb_module *module)
3942 struct replmd_private *replmd_private =
3943 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3944 replmd_txn_cleanup(replmd_private);
3946 return ldb_next_del_trans(module);
3950 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3951 .name = "repl_meta_data",
3952 .init_context = replmd_init,
3954 .modify = replmd_modify,
3955 .rename = replmd_rename,
3956 .del = replmd_delete,
3957 .extended = replmd_extended,
3958 .start_transaction = replmd_start_transaction,
3959 .prepare_commit = replmd_prepare_commit,
3960 .del_transaction = replmd_del_transaction,