s4:dsdb/repl_meta_data: call dsdb_module_schedule_sd_propagation() for replicated...
[sfrench/samba-autobuild/.git] / source4 / dsdb / samdb / ldb_modules / repl_meta_data.c
1 /*
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8    Copyright (C) Matthieu Patou <mat@samba.org> 2010
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb repl_meta_data module
28  *
29  *  Description: - add a unique objectGUID onto every new record,
30  *               - handle whenCreated, whenChanged timestamps
31  *               - handle uSNCreated, uSNChanged numbers
32  *               - handle replPropertyMetaData attribute
33  *
34  *  Author: Simo Sorce
35  *  Author: Stefan Metzmacher
36  */
37
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "../libds/common/flags.h"
43 #include "librpc/gen_ndr/ndr_misc.h"
44 #include "librpc/gen_ndr/ndr_drsuapi.h"
45 #include "librpc/gen_ndr/ndr_drsblobs.h"
46 #include "param/param.h"
47 #include "libcli/security/security.h"
48 #include "lib/util/dlinklist.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
50 #include "lib/util/binsearch.h"
51 #include "lib/util/tsort.h"
52
53 /*
54  * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
55  * Deleted Objects Container
56  */
57 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
58
59 struct replmd_private {
60         TALLOC_CTX *la_ctx;
61         struct la_entry *la_list;
62         TALLOC_CTX *bl_ctx;
63         struct la_backlink *la_backlinks;
64         struct nc_entry {
65                 struct nc_entry *prev, *next;
66                 struct ldb_dn *dn;
67                 uint64_t mod_usn;
68                 uint64_t mod_usn_urgent;
69         } *ncs;
70 };
71
72 struct la_entry {
73         struct la_entry *next, *prev;
74         struct drsuapi_DsReplicaLinkedAttribute *la;
75 };
76
77 struct replmd_replicated_request {
78         struct ldb_module *module;
79         struct ldb_request *req;
80
81         const struct dsdb_schema *schema;
82
83         /* the controls we pass down */
84         struct ldb_control **controls;
85
86         /* details for the mode where we apply a bunch of inbound replication meessages */
87         bool apply_mode;
88         uint32_t index_current;
89         struct dsdb_extended_replicated_objects *objs;
90
91         struct ldb_message *search_msg;
92
93         uint64_t seq_num;
94         bool is_urgent;
95 };
96
97 enum urgent_situation {
98         REPL_URGENT_ON_CREATE = 1,
99         REPL_URGENT_ON_UPDATE = 2,
100         REPL_URGENT_ON_DELETE = 4
101 };
102
103
104 static const struct {
105         const char *update_name;
106         enum urgent_situation repl_situation;
107 } urgent_objects[] = {
108                 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
109                 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
110                 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
111                 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
112                 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
113                 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
114                 {NULL, 0}
115 };
116
117 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
118 static const char *urgent_attrs[] = {
119                 "lockoutTime",
120                 "pwdLastSet",
121                 "userAccountControl",
122                 NULL
123 };
124
125
126 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
127                                         enum urgent_situation situation)
128 {
129         unsigned int i, j;
130         for (i=0; urgent_objects[i].update_name; i++) {
131
132                 if ((situation & urgent_objects[i].repl_situation) == 0) {
133                         continue;
134                 }
135
136                 for (j=0; j<objectclass_el->num_values; j++) {
137                         const struct ldb_val *v = &objectclass_el->values[j];
138                         if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
139                                 return true;
140                         }
141                 }
142         }
143         return false;
144 }
145
146 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
147 {
148         if (ldb_attr_in_list(urgent_attrs, el->name)) {
149                 return true;
150         }
151         return false;
152 }
153
154
155 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
156
157 /*
158   initialise the module
159   allocate the private structure and build the list
160   of partition DNs for use by replmd_notify()
161  */
162 static int replmd_init(struct ldb_module *module)
163 {
164         struct replmd_private *replmd_private;
165         struct ldb_context *ldb = ldb_module_get_ctx(module);
166
167         replmd_private = talloc_zero(module, struct replmd_private);
168         if (replmd_private == NULL) {
169                 ldb_oom(ldb);
170                 return LDB_ERR_OPERATIONS_ERROR;
171         }
172         ldb_module_set_private(module, replmd_private);
173
174         return ldb_next_init(module);
175 }
176
177 /*
178   cleanup our per-transaction contexts
179  */
180 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
181 {
182         talloc_free(replmd_private->la_ctx);
183         replmd_private->la_list = NULL;
184         replmd_private->la_ctx = NULL;
185
186         talloc_free(replmd_private->bl_ctx);
187         replmd_private->la_backlinks = NULL;
188         replmd_private->bl_ctx = NULL;
189 }
190
191
192 struct la_backlink {
193         struct la_backlink *next, *prev;
194         const char *attr_name;
195         struct GUID forward_guid, target_guid;
196         bool active;
197 };
198
199 /*
200   process a backlinks we accumulated during a transaction, adding and
201   deleting the backlinks from the target objects
202  */
203 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
204 {
205         struct ldb_dn *target_dn, *source_dn;
206         int ret;
207         struct ldb_context *ldb = ldb_module_get_ctx(module);
208         struct ldb_message *msg;
209         TALLOC_CTX *tmp_ctx = talloc_new(bl);
210         char *dn_string;
211
212         /*
213           - find DN of target
214           - find DN of source
215           - construct ldb_message
216               - either an add or a delete
217          */
218         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
219         if (ret != LDB_SUCCESS) {
220                 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
221                          GUID_string(bl, &bl->target_guid)));
222                 return LDB_SUCCESS;
223         }
224
225         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
226         if (ret != LDB_SUCCESS) {
227                 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
228                                        GUID_string(bl, &bl->forward_guid));
229                 talloc_free(tmp_ctx);
230                 return ret;
231         }
232
233         msg = ldb_msg_new(tmp_ctx);
234         if (msg == NULL) {
235                 ldb_module_oom(module);
236                 talloc_free(tmp_ctx);
237                 return LDB_ERR_OPERATIONS_ERROR;
238         }
239
240         /* construct a ldb_message for adding/deleting the backlink */
241         msg->dn = target_dn;
242         dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
243         if (!dn_string) {
244                 ldb_module_oom(module);
245                 talloc_free(tmp_ctx);
246                 return LDB_ERR_OPERATIONS_ERROR;
247         }
248         ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
249         if (ret != LDB_SUCCESS) {
250                 talloc_free(tmp_ctx);
251                 return ret;
252         }
253         msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
254
255         /* a backlink should never be single valued. Unfortunately the
256            exchange schema has a attribute
257            msExchBridgeheadedLocalConnectorsDNBL which is single
258            valued and a backlink. We need to cope with that by
259            ignoring the single value flag */
260         msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
261
262         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
263         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
264                 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
265                    cope with possible corruption where the backlink has
266                    already been removed */
267                 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
268                          ldb_dn_get_linearized(target_dn),
269                          ldb_dn_get_linearized(source_dn),
270                          ldb_errstring(ldb)));
271                 ret = LDB_SUCCESS;
272         } else if (ret != LDB_SUCCESS) {
273                 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
274                                        bl->active?"add":"remove",
275                                        ldb_dn_get_linearized(source_dn),
276                                        ldb_dn_get_linearized(target_dn),
277                                        ldb_errstring(ldb));
278                 talloc_free(tmp_ctx);
279                 return ret;
280         }
281         talloc_free(tmp_ctx);
282         return ret;
283 }
284
285 /*
286   add a backlink to the list of backlinks to add/delete in the prepare
287   commit
288  */
289 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
290                                struct GUID *forward_guid, struct GUID *target_guid,
291                                bool active, const struct dsdb_attribute *schema_attr, bool immediate)
292 {
293         const struct dsdb_attribute *target_attr;
294         struct la_backlink *bl;
295         struct replmd_private *replmd_private =
296                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
297
298         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
299         if (!target_attr) {
300                 /*
301                  * windows 2003 has a broken schema where the
302                  * definition of msDS-IsDomainFor is missing (which is
303                  * supposed to be the backlink of the
304                  * msDS-HasDomainNCs attribute
305                  */
306                 return LDB_SUCCESS;
307         }
308
309         /* see if its already in the list */
310         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
311                 if (GUID_equal(forward_guid, &bl->forward_guid) &&
312                     GUID_equal(target_guid, &bl->target_guid) &&
313                     (target_attr->lDAPDisplayName == bl->attr_name ||
314                      strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
315                         break;
316                 }
317         }
318
319         if (bl) {
320                 /* we found an existing one */
321                 if (bl->active == active) {
322                         return LDB_SUCCESS;
323                 }
324                 DLIST_REMOVE(replmd_private->la_backlinks, bl);
325                 talloc_free(bl);
326                 return LDB_SUCCESS;
327         }
328
329         if (replmd_private->bl_ctx == NULL) {
330                 replmd_private->bl_ctx = talloc_new(replmd_private);
331                 if (replmd_private->bl_ctx == NULL) {
332                         ldb_module_oom(module);
333                         return LDB_ERR_OPERATIONS_ERROR;
334                 }
335         }
336
337         /* its a new one */
338         bl = talloc(replmd_private->bl_ctx, struct la_backlink);
339         if (bl == NULL) {
340                 ldb_module_oom(module);
341                 return LDB_ERR_OPERATIONS_ERROR;
342         }
343
344         /* Ensure the schema does not go away before the bl->attr_name is used */
345         if (!talloc_reference(bl, schema)) {
346                 talloc_free(bl);
347                 ldb_module_oom(module);
348                 return LDB_ERR_OPERATIONS_ERROR;
349         }
350
351         bl->attr_name = target_attr->lDAPDisplayName;
352         bl->forward_guid = *forward_guid;
353         bl->target_guid = *target_guid;
354         bl->active = active;
355
356         /* the caller may ask for this backlink to be processed
357            immediately */
358         if (immediate) {
359                 int ret = replmd_process_backlink(module, bl, NULL);
360                 talloc_free(bl);
361                 return ret;
362         }
363
364         DLIST_ADD(replmd_private->la_backlinks, bl);
365
366         return LDB_SUCCESS;
367 }
368
369
370 /*
371  * Callback for most write operations in this module:
372  *
373  * notify the repl task that a object has changed. The notifies are
374  * gathered up in the replmd_private structure then written to the
375  * @REPLCHANGED object in each partition during the prepare_commit
376  */
377 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
378 {
379         int ret;
380         struct replmd_replicated_request *ac =
381                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
382         struct replmd_private *replmd_private =
383                 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
384         struct nc_entry *modified_partition;
385         struct ldb_control *partition_ctrl;
386         const struct dsdb_control_current_partition *partition;
387
388         struct ldb_control **controls;
389
390         partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
391
392         controls = ares->controls;
393         if (ldb_request_get_control(ac->req,
394                                     DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
395                 /*
396                  * Remove the current partition control from what we pass up
397                  * the chain if it hasn't been requested manually.
398                  */
399                 controls = ldb_controls_except_specified(ares->controls, ares,
400                                                          partition_ctrl);
401         }
402
403         if (ares->error != LDB_SUCCESS) {
404                 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
405                 return ldb_module_done(ac->req, controls,
406                                         ares->response, ares->error);
407         }
408
409         if (ares->type != LDB_REPLY_DONE) {
410                 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
411                 return ldb_module_done(ac->req, NULL,
412                                        NULL, LDB_ERR_OPERATIONS_ERROR);
413         }
414
415         if (!partition_ctrl) {
416                 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
417                 return ldb_module_done(ac->req, NULL,
418                                        NULL, LDB_ERR_OPERATIONS_ERROR);
419         }
420
421         partition = talloc_get_type_abort(partition_ctrl->data,
422                                     struct dsdb_control_current_partition);
423
424         if (ac->seq_num > 0) {
425                 for (modified_partition = replmd_private->ncs; modified_partition;
426                      modified_partition = modified_partition->next) {
427                         if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
428                                 break;
429                         }
430                 }
431
432                 if (modified_partition == NULL) {
433                         modified_partition = talloc_zero(replmd_private, struct nc_entry);
434                         if (!modified_partition) {
435                                 ldb_oom(ldb_module_get_ctx(ac->module));
436                                 return ldb_module_done(ac->req, NULL,
437                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
438                         }
439                         modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
440                         if (!modified_partition->dn) {
441                                 ldb_oom(ldb_module_get_ctx(ac->module));
442                                 return ldb_module_done(ac->req, NULL,
443                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
444                         }
445                         DLIST_ADD(replmd_private->ncs, modified_partition);
446                 }
447
448                 if (ac->seq_num > modified_partition->mod_usn) {
449                         modified_partition->mod_usn = ac->seq_num;
450                         if (ac->is_urgent) {
451                                 modified_partition->mod_usn_urgent = ac->seq_num;
452                         }
453                 }
454         }
455
456         if (ac->apply_mode) {
457                 talloc_free(ares);
458                 ac->index_current++;
459
460                 ret = replmd_replicated_apply_next(ac);
461                 if (ret != LDB_SUCCESS) {
462                         return ldb_module_done(ac->req, NULL, NULL, ret);
463                 }
464                 return ret;
465         } else {
466                 /* free the partition control container here, for the
467                  * common path.  Other cases will have it cleaned up
468                  * eventually with the ares */
469                 talloc_free(partition_ctrl);
470                 return ldb_module_done(ac->req, controls,
471                                        ares->response, LDB_SUCCESS);
472         }
473 }
474
475
476 /*
477  * update a @REPLCHANGED record in each partition if there have been
478  * any writes of replicated data in the partition
479  */
480 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
481 {
482         struct replmd_private *replmd_private =
483                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
484
485         while (replmd_private->ncs) {
486                 int ret;
487                 struct nc_entry *modified_partition = replmd_private->ncs;
488
489                 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
490                                                      modified_partition->mod_usn,
491                                                      modified_partition->mod_usn_urgent, parent);
492                 if (ret != LDB_SUCCESS) {
493                         DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
494                                  ldb_dn_get_linearized(modified_partition->dn)));
495                         return ret;
496                 }
497                 DLIST_REMOVE(replmd_private->ncs, modified_partition);
498                 talloc_free(modified_partition);
499         }
500
501         return LDB_SUCCESS;
502 }
503
504
505 /*
506   created a replmd_replicated_request context
507  */
508 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
509                                                          struct ldb_request *req)
510 {
511         struct ldb_context *ldb;
512         struct replmd_replicated_request *ac;
513
514         ldb = ldb_module_get_ctx(module);
515
516         ac = talloc_zero(req, struct replmd_replicated_request);
517         if (ac == NULL) {
518                 ldb_oom(ldb);
519                 return NULL;
520         }
521
522         ac->module = module;
523         ac->req = req;
524
525         ac->schema = dsdb_get_schema(ldb, ac);
526         if (!ac->schema) {
527                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
528                               "replmd_modify: no dsdb_schema loaded");
529                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
530                 return NULL;
531         }
532
533         return ac;
534 }
535
536 /*
537   add a time element to a record
538 */
539 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
540 {
541         struct ldb_message_element *el;
542         char *s;
543         int ret;
544
545         if (ldb_msg_find_element(msg, attr) != NULL) {
546                 return LDB_SUCCESS;
547         }
548
549         s = ldb_timestring(msg, t);
550         if (s == NULL) {
551                 return LDB_ERR_OPERATIONS_ERROR;
552         }
553
554         ret = ldb_msg_add_string(msg, attr, s);
555         if (ret != LDB_SUCCESS) {
556                 return ret;
557         }
558
559         el = ldb_msg_find_element(msg, attr);
560         /* always set as replace. This works because on add ops, the flag
561            is ignored */
562         el->flags = LDB_FLAG_MOD_REPLACE;
563
564         return LDB_SUCCESS;
565 }
566
567 /*
568   add a uint64_t element to a record
569 */
570 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
571                               const char *attr, uint64_t v)
572 {
573         struct ldb_message_element *el;
574         int ret;
575
576         if (ldb_msg_find_element(msg, attr) != NULL) {
577                 return LDB_SUCCESS;
578         }
579
580         ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
581         if (ret != LDB_SUCCESS) {
582                 return ret;
583         }
584
585         el = ldb_msg_find_element(msg, attr);
586         /* always set as replace. This works because on add ops, the flag
587            is ignored */
588         el->flags = LDB_FLAG_MOD_REPLACE;
589
590         return LDB_SUCCESS;
591 }
592
593 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
594                                                    const struct replPropertyMetaData1 *m2,
595                                                    const uint32_t *rdn_attid)
596 {
597         if (m1->attid == m2->attid) {
598                 return 0;
599         }
600
601         /*
602          * the rdn attribute should be at the end!
603          * so we need to return a value greater than zero
604          * which means m1 is greater than m2
605          */
606         if (m1->attid == *rdn_attid) {
607                 return 1;
608         }
609
610         /*
611          * the rdn attribute should be at the end!
612          * so we need to return a value less than zero
613          * which means m2 is greater than m1
614          */
615         if (m2->attid == *rdn_attid) {
616                 return -1;
617         }
618
619         return m1->attid > m2->attid ? 1 : -1;
620 }
621
622 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
623                                                 const struct dsdb_schema *schema,
624                                                 struct ldb_dn *dn)
625 {
626         const char *rdn_name;
627         const struct dsdb_attribute *rdn_sa;
628
629         rdn_name = ldb_dn_get_rdn_name(dn);
630         if (!rdn_name) {
631                 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
632                 return LDB_ERR_OPERATIONS_ERROR;
633         }
634
635         rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
636         if (rdn_sa == NULL) {
637                 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
638                 return LDB_ERR_OPERATIONS_ERROR;
639         }
640
641         DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
642                  rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
643
644         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
645
646         return LDB_SUCCESS;
647 }
648
649 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
650                                                  const struct ldb_message_element *e2,
651                                                  const struct dsdb_schema *schema)
652 {
653         const struct dsdb_attribute *a1;
654         const struct dsdb_attribute *a2;
655
656         /*
657          * TODO: make this faster by caching the dsdb_attribute pointer
658          *       on the ldb_messag_element
659          */
660
661         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
662         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
663
664         if (a1->attributeID_id == a2->attributeID_id) {
665                 return 0;
666         }
667         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
668 }
669
670 static void replmd_ldb_message_sort(struct ldb_message *msg,
671                                     const struct dsdb_schema *schema)
672 {
673         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
674 }
675
676 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
677                                const struct GUID *invocation_id, uint64_t seq_num,
678                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
679
680
681 /*
682   fix up linked attributes in replmd_add.
683   This involves setting up the right meta-data in extended DN
684   components, and creating backlinks to the object
685  */
686 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
687                              uint64_t seq_num, const struct GUID *invocationId, time_t t,
688                              struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
689 {
690         unsigned int i;
691         TALLOC_CTX *tmp_ctx = talloc_new(el->values);
692         struct ldb_context *ldb = ldb_module_get_ctx(module);
693
694         /* We will take a reference to the schema in replmd_add_backlink */
695         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
696         NTTIME now;
697
698         unix_to_nt_time(&now, t);
699
700         for (i=0; i<el->num_values; i++) {
701                 struct ldb_val *v = &el->values[i];
702                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
703                 struct GUID target_guid;
704                 NTSTATUS status;
705                 int ret;
706
707                 /* note that the DN already has the extended
708                    components from the extended_dn_store module */
709                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
710                 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
711                         ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
712                         if (ret != LDB_SUCCESS) {
713                                 talloc_free(tmp_ctx);
714                                 return ret;
715                         }
716                         ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
717                         if (ret != LDB_SUCCESS) {
718                                 talloc_free(tmp_ctx);
719                                 return ret;
720                         }
721                 }
722
723                 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
724                                           seq_num, seq_num, now, 0, false);
725                 if (ret != LDB_SUCCESS) {
726                         talloc_free(tmp_ctx);
727                         return ret;
728                 }
729
730                 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
731                 if (ret != LDB_SUCCESS) {
732                         talloc_free(tmp_ctx);
733                         return ret;
734                 }
735         }
736
737         talloc_free(tmp_ctx);
738         return LDB_SUCCESS;
739 }
740
741
742 /*
743   intercept add requests
744  */
745 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
746 {
747         struct samldb_msds_intid_persistant *msds_intid_struct;
748         struct ldb_context *ldb;
749         struct ldb_control *control;
750         struct replmd_replicated_request *ac;
751         enum ndr_err_code ndr_err;
752         struct ldb_request *down_req;
753         struct ldb_message *msg;
754         const DATA_BLOB *guid_blob;
755         struct GUID guid;
756         struct replPropertyMetaDataBlob nmd;
757         struct ldb_val nmd_value;
758         const struct GUID *our_invocation_id;
759         time_t t = time(NULL);
760         NTTIME now;
761         char *time_str;
762         int ret;
763         unsigned int i;
764         unsigned int functional_level;
765         uint32_t ni=0;
766         bool allow_add_guid = false;
767         bool remove_current_guid = false;
768         bool is_urgent = false;
769         struct ldb_message_element *objectclass_el;
770
771         /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
772         control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
773         if (control) {
774                 allow_add_guid = true;
775         }
776
777         /* do not manipulate our control entries */
778         if (ldb_dn_is_special(req->op.add.message->dn)) {
779                 return ldb_next_request(module, req);
780         }
781
782         ldb = ldb_module_get_ctx(module);
783
784         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
785
786         guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
787         if (guid_blob != NULL) {
788                 if (!allow_add_guid) {
789                         ldb_set_errstring(ldb,
790                                           "replmd_add: it's not allowed to add an object with objectGUID!");
791                         return LDB_ERR_UNWILLING_TO_PERFORM;
792                 } else {
793                         NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
794                         if (!NT_STATUS_IS_OK(status)) {
795                                 ldb_set_errstring(ldb,
796                                                   "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
797                                 return LDB_ERR_UNWILLING_TO_PERFORM;
798                         }
799                         /* we remove this attribute as it can be a string and
800                          * will not be treated correctly and then we will re-add
801                          * it later on in the good format */
802                         remove_current_guid = true;
803                 }
804         } else {
805                 /* a new GUID */
806                 guid = GUID_random();
807         }
808
809         ac = replmd_ctx_init(module, req);
810         if (ac == NULL) {
811                 return ldb_module_oom(module);
812         }
813
814         functional_level = dsdb_functional_level(ldb);
815
816         /* Get a sequence number from the backend */
817         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
818         if (ret != LDB_SUCCESS) {
819                 talloc_free(ac);
820                 return ret;
821         }
822
823         /* get our invocationId */
824         our_invocation_id = samdb_ntds_invocation_id(ldb);
825         if (!our_invocation_id) {
826                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
827                               "replmd_add: unable to find invocationId\n");
828                 talloc_free(ac);
829                 return LDB_ERR_OPERATIONS_ERROR;
830         }
831
832         /* we have to copy the message as the caller might have it as a const */
833         msg = ldb_msg_copy_shallow(ac, req->op.add.message);
834         if (msg == NULL) {
835                 ldb_oom(ldb);
836                 talloc_free(ac);
837                 return LDB_ERR_OPERATIONS_ERROR;
838         }
839
840         /* generated times */
841         unix_to_nt_time(&now, t);
842         time_str = ldb_timestring(msg, t);
843         if (!time_str) {
844                 ldb_oom(ldb);
845                 talloc_free(ac);
846                 return LDB_ERR_OPERATIONS_ERROR;
847         }
848         if (remove_current_guid) {
849                 ldb_msg_remove_attr(msg,"objectGUID");
850         }
851
852         /*
853          * remove autogenerated attributes
854          */
855         ldb_msg_remove_attr(msg, "whenCreated");
856         ldb_msg_remove_attr(msg, "whenChanged");
857         ldb_msg_remove_attr(msg, "uSNCreated");
858         ldb_msg_remove_attr(msg, "uSNChanged");
859         ldb_msg_remove_attr(msg, "replPropertyMetaData");
860
861         /*
862          * readd replicated attributes
863          */
864         ret = ldb_msg_add_string(msg, "whenCreated", time_str);
865         if (ret != LDB_SUCCESS) {
866                 ldb_oom(ldb);
867                 talloc_free(ac);
868                 return ret;
869         }
870
871         /* build the replication meta_data */
872         ZERO_STRUCT(nmd);
873         nmd.version             = 1;
874         nmd.ctr.ctr1.count      = msg->num_elements;
875         nmd.ctr.ctr1.array      = talloc_array(msg,
876                                                struct replPropertyMetaData1,
877                                                nmd.ctr.ctr1.count);
878         if (!nmd.ctr.ctr1.array) {
879                 ldb_oom(ldb);
880                 talloc_free(ac);
881                 return LDB_ERR_OPERATIONS_ERROR;
882         }
883
884         for (i=0; i < msg->num_elements; i++) {
885                 struct ldb_message_element *e = &msg->elements[i];
886                 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
887                 const struct dsdb_attribute *sa;
888
889                 if (e->name[0] == '@') continue;
890
891                 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
892                 if (!sa) {
893                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
894                                       "replmd_add: attribute '%s' not defined in schema\n",
895                                       e->name);
896                         talloc_free(ac);
897                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
898                 }
899
900                 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
901                         /* if the attribute is not replicated (0x00000001)
902                          * or constructed (0x00000004) it has no metadata
903                          */
904                         continue;
905                 }
906
907                 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
908                         ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa, req);
909                         if (ret != LDB_SUCCESS) {
910                                 talloc_free(ac);
911                                 return ret;
912                         }
913                         /* linked attributes are not stored in
914                            replPropertyMetaData in FL above w2k */
915                         continue;
916                 }
917
918                 m->attid                        = sa->attributeID_id;
919                 m->version                      = 1;
920                 if (m->attid == 0x20030) {
921                         const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
922                         const char* rdn;
923
924                         if (rdn_val == NULL) {
925                                 ldb_oom(ldb);
926                                 talloc_free(ac);
927                                 return LDB_ERR_OPERATIONS_ERROR;
928                         }
929
930                         rdn = (const char*)rdn_val->data;
931                         if (strcmp(rdn, "Deleted Objects") == 0) {
932                                 /*
933                                  * Set the originating_change_time to 29/12/9999 at 23:59:59
934                                  * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
935                                  */
936                                 m->originating_change_time      = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
937                         } else {
938                                 m->originating_change_time      = now;
939                         }
940                 } else {
941                         m->originating_change_time      = now;
942                 }
943                 m->originating_invocation_id    = *our_invocation_id;
944                 m->originating_usn              = ac->seq_num;
945                 m->local_usn                    = ac->seq_num;
946                 ni++;
947         }
948
949         /* fix meta data count */
950         nmd.ctr.ctr1.count = ni;
951
952         /*
953          * sort meta data array, and move the rdn attribute entry to the end
954          */
955         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
956         if (ret != LDB_SUCCESS) {
957                 talloc_free(ac);
958                 return ret;
959         }
960
961         /* generated NDR encoded values */
962         ndr_err = ndr_push_struct_blob(&nmd_value, msg,
963                                        &nmd,
964                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
965         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
966                 ldb_oom(ldb);
967                 talloc_free(ac);
968                 return LDB_ERR_OPERATIONS_ERROR;
969         }
970
971         /*
972          * add the autogenerated values
973          */
974         ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
975         if (ret != LDB_SUCCESS) {
976                 ldb_oom(ldb);
977                 talloc_free(ac);
978                 return ret;
979         }
980         ret = ldb_msg_add_string(msg, "whenChanged", time_str);
981         if (ret != LDB_SUCCESS) {
982                 ldb_oom(ldb);
983                 talloc_free(ac);
984                 return ret;
985         }
986         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
987         if (ret != LDB_SUCCESS) {
988                 ldb_oom(ldb);
989                 talloc_free(ac);
990                 return ret;
991         }
992         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
993         if (ret != LDB_SUCCESS) {
994                 ldb_oom(ldb);
995                 talloc_free(ac);
996                 return ret;
997         }
998         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
999         if (ret != LDB_SUCCESS) {
1000                 ldb_oom(ldb);
1001                 talloc_free(ac);
1002                 return ret;
1003         }
1004
1005         /*
1006          * sort the attributes by attid before storing the object
1007          */
1008         replmd_ldb_message_sort(msg, ac->schema);
1009
1010         objectclass_el = ldb_msg_find_element(msg, "objectClass");
1011         is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1012                                                         REPL_URGENT_ON_CREATE);
1013
1014         ac->is_urgent = is_urgent;
1015         ret = ldb_build_add_req(&down_req, ldb, ac,
1016                                 msg,
1017                                 req->controls,
1018                                 ac, replmd_op_callback,
1019                                 req);
1020
1021         LDB_REQ_SET_LOCATION(down_req);
1022         if (ret != LDB_SUCCESS) {
1023                 talloc_free(ac);
1024                 return ret;
1025         }
1026
1027         /* current partition control is needed by "replmd_op_callback" */
1028         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1029                 ret = ldb_request_add_control(down_req,
1030                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
1031                                               false, NULL);
1032                 if (ret != LDB_SUCCESS) {
1033                         talloc_free(ac);
1034                         return ret;
1035                 }
1036         }
1037
1038         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1039                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1040                 if (ret != LDB_SUCCESS) {
1041                         talloc_free(ac);
1042                         return ret;
1043                 }
1044         }
1045
1046         /* mark the control done */
1047         if (control) {
1048                 control->critical = 0;
1049         }
1050         if (ldb_dn_compare_base(ac->schema->base_dn, req->op.add.message->dn) != 0) {
1051
1052                 /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */
1053                 msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
1054                 if (msds_intid_struct) {
1055                         msds_intid_struct->usn = ac->seq_num;
1056                 }
1057         }
1058         /* go on with the call chain */
1059         return ldb_next_request(module, down_req);
1060 }
1061
1062
1063 /*
1064  * update the replPropertyMetaData for one element
1065  */
1066 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1067                                       struct ldb_message *msg,
1068                                       struct ldb_message_element *el,
1069                                       struct ldb_message_element *old_el,
1070                                       struct replPropertyMetaDataBlob *omd,
1071                                       const struct dsdb_schema *schema,
1072                                       uint64_t *seq_num,
1073                                       const struct GUID *our_invocation_id,
1074                                       NTTIME now,
1075                                       struct ldb_request *req)
1076 {
1077         uint32_t i;
1078         const struct dsdb_attribute *a;
1079         struct replPropertyMetaData1 *md1;
1080
1081         a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1082         if (a == NULL) {
1083                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1084                         /* allow this to make it possible for dbcheck
1085                            to remove bad attributes */
1086                         return LDB_SUCCESS;
1087                 }
1088
1089                 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1090                          el->name));
1091                 return LDB_ERR_OPERATIONS_ERROR;
1092         }
1093
1094         if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1095                 return LDB_SUCCESS;
1096         }
1097
1098         /* if the attribute's value haven't changed then return LDB_SUCCESS
1099          * Unless we have the provision control or if the attribute is
1100          * interSiteTopologyGenerator as this page explain: http://support.microsoft.com/kb/224815
1101          * this attribute is periodicaly written by the DC responsible for the intersite generation
1102          * in a given site
1103          */
1104         if (old_el != NULL && ldb_msg_element_compare(el, old_el) == 0) {
1105                 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1106                     !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1107                         /*
1108                          * allow this to make it possible for dbcheck
1109                          * to rebuild broken metadata
1110                          */
1111                         return LDB_SUCCESS;
1112                 }
1113         }
1114
1115         for (i=0; i<omd->ctr.ctr1.count; i++) {
1116                 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1117         }
1118
1119         if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1120                 /* linked attributes are not stored in
1121                    replPropertyMetaData in FL above w2k, but we do
1122                    raise the seqnum for the object  */
1123                 if (*seq_num == 0 &&
1124                     ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1125                         return LDB_ERR_OPERATIONS_ERROR;
1126                 }
1127                 return LDB_SUCCESS;
1128         }
1129
1130         if (i == omd->ctr.ctr1.count) {
1131                 /* we need to add a new one */
1132                 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1133                                                      struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1134                 if (omd->ctr.ctr1.array == NULL) {
1135                         ldb_oom(ldb);
1136                         return LDB_ERR_OPERATIONS_ERROR;
1137                 }
1138                 omd->ctr.ctr1.count++;
1139                 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1140         }
1141
1142         /* Get a new sequence number from the backend. We only do this
1143          * if we have a change that requires a new
1144          * replPropertyMetaData element
1145          */
1146         if (*seq_num == 0) {
1147                 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1148                 if (ret != LDB_SUCCESS) {
1149                         return LDB_ERR_OPERATIONS_ERROR;
1150                 }
1151         }
1152
1153         md1 = &omd->ctr.ctr1.array[i];
1154         md1->version++;
1155         md1->attid                     = a->attributeID_id;
1156         if (md1->attid == 0x20030) {
1157                 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1158                 const char* rdn;
1159
1160                 if (rdn_val == NULL) {
1161                         ldb_oom(ldb);
1162                         return LDB_ERR_OPERATIONS_ERROR;
1163                 }
1164
1165                 rdn = (const char*)rdn_val->data;
1166                 if (strcmp(rdn, "Deleted Objects") == 0) {
1167                         /*
1168                          * Set the originating_change_time to 29/12/9999 at 23:59:59
1169                          * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1170                          */
1171                         md1->originating_change_time    = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1172                 } else {
1173                         md1->originating_change_time    = now;
1174                 }
1175         } else {
1176                 md1->originating_change_time    = now;
1177         }
1178         md1->originating_invocation_id = *our_invocation_id;
1179         md1->originating_usn           = *seq_num;
1180         md1->local_usn                 = *seq_num;
1181
1182         return LDB_SUCCESS;
1183 }
1184
1185 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1186 {
1187         uint32_t count = omd.ctr.ctr1.count;
1188         uint64_t max = 0;
1189         uint32_t i;
1190         for (i=0; i < count; i++) {
1191                 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1192                 if (max < m.local_usn) {
1193                         max = m.local_usn;
1194                 }
1195         }
1196         return max;
1197 }
1198
1199 /*
1200  * update the replPropertyMetaData object each time we modify an
1201  * object. This is needed for DRS replication, as the merge on the
1202  * client is based on this object
1203  */
1204 static int replmd_update_rpmd(struct ldb_module *module,
1205                               const struct dsdb_schema *schema,
1206                               struct ldb_request *req,
1207                               const char * const *rename_attrs,
1208                               struct ldb_message *msg, uint64_t *seq_num,
1209                               time_t t,
1210                               bool *is_urgent, bool *rodc)
1211 {
1212         const struct ldb_val *omd_value;
1213         enum ndr_err_code ndr_err;
1214         struct replPropertyMetaDataBlob omd;
1215         unsigned int i;
1216         NTTIME now;
1217         const struct GUID *our_invocation_id;
1218         int ret;
1219         const char * const *attrs = NULL;
1220         const char * const attrs1[] = { "replPropertyMetaData", "*", NULL };
1221         const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1222         struct ldb_result *res;
1223         struct ldb_context *ldb;
1224         struct ldb_message_element *objectclass_el;
1225         enum urgent_situation situation;
1226         bool rmd_is_provided;
1227
1228         if (rename_attrs) {
1229                 attrs = rename_attrs;
1230         } else {
1231                 attrs = attrs1;
1232         }
1233
1234         ldb = ldb_module_get_ctx(module);
1235
1236         our_invocation_id = samdb_ntds_invocation_id(ldb);
1237         if (!our_invocation_id) {
1238                 /* this happens during an initial vampire while
1239                    updating the schema */
1240                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1241                 return LDB_SUCCESS;
1242         }
1243
1244         unix_to_nt_time(&now, t);
1245
1246         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1247                 rmd_is_provided = true;
1248         } else {
1249                 rmd_is_provided = false;
1250         }
1251
1252         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1253          * otherwise we consider we are updating */
1254         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1255                 situation = REPL_URGENT_ON_DELETE;
1256         } else if (rename_attrs) {
1257                 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1258         } else {
1259                 situation = REPL_URGENT_ON_UPDATE;
1260         }
1261
1262         if (rmd_is_provided) {
1263                 /* In this case the change_replmetadata control was supplied */
1264                 /* We check that it's the only attribute that is provided
1265                  * (it's a rare case so it's better to keep the code simplier)
1266                  * We also check that the highest local_usn is bigger than
1267                  * uSNChanged. */
1268                 uint64_t db_seq;
1269                 if( msg->num_elements != 1 ||
1270                         strncmp(msg->elements[0].name,
1271                                 "replPropertyMetaData", 20) ) {
1272                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1273                                 "a specified replPropertyMetaData attribute or with others\n"));
1274                         return LDB_ERR_OPERATIONS_ERROR;
1275                 }
1276                 if (situation != REPL_URGENT_ON_UPDATE) {
1277                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1278                         return LDB_ERR_OPERATIONS_ERROR;
1279                 }
1280                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1281                 if (!omd_value) {
1282                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1283                                  ldb_dn_get_linearized(msg->dn)));
1284                         return LDB_ERR_OPERATIONS_ERROR;
1285                 }
1286                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1287                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1288                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1289                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1290                                  ldb_dn_get_linearized(msg->dn)));
1291                         return LDB_ERR_OPERATIONS_ERROR;
1292                 }
1293                 *seq_num = find_max_local_usn(omd);
1294
1295                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1296                                             DSDB_FLAG_NEXT_MODULE |
1297                                             DSDB_SEARCH_SHOW_RECYCLED |
1298                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1299                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1300                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1301
1302                 if (ret != LDB_SUCCESS) {
1303                         return ret;
1304                 }
1305
1306                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1307                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1308                                                                 situation)) {
1309                         *is_urgent = true;
1310                 }
1311
1312                 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1313                 if (*seq_num <= db_seq) {
1314                         DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\
1315                                               " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n",
1316                                  (long long)*seq_num, (long long)db_seq));
1317                         return LDB_ERR_OPERATIONS_ERROR;
1318                 }
1319
1320         } else {
1321                 /* search for the existing replPropertyMetaDataBlob. We need
1322                  * to use REVEAL and ask for DNs in storage format to support
1323                  * the check for values being the same in
1324                  * replmd_update_rpmd_element()
1325                  */
1326                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1327                                             DSDB_FLAG_NEXT_MODULE |
1328                                             DSDB_SEARCH_SHOW_RECYCLED |
1329                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1330                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1331                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1332                 if (ret != LDB_SUCCESS) {
1333                         return ret;
1334                 }
1335
1336                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1337                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1338                                                                 situation)) {
1339                         *is_urgent = true;
1340                 }
1341
1342                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1343                 if (!omd_value) {
1344                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1345                                  ldb_dn_get_linearized(msg->dn)));
1346                         return LDB_ERR_OPERATIONS_ERROR;
1347                 }
1348
1349                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1350                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1351                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1352                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1353                                  ldb_dn_get_linearized(msg->dn)));
1354                         return LDB_ERR_OPERATIONS_ERROR;
1355                 }
1356
1357                 if (omd.version != 1) {
1358                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1359                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1360                         return LDB_ERR_OPERATIONS_ERROR;
1361                 }
1362
1363                 for (i=0; i<msg->num_elements; i++) {
1364                         struct ldb_message_element *old_el;
1365                         old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1366                         ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1367                                                          our_invocation_id, now, req);
1368                         if (ret != LDB_SUCCESS) {
1369                                 return ret;
1370                         }
1371
1372                         if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1373                                 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1374                         }
1375
1376                 }
1377         }
1378         /*
1379          * replmd_update_rpmd_element has done an update if the
1380          * seq_num is set
1381          */
1382         if (*seq_num != 0) {
1383                 struct ldb_val *md_value;
1384                 struct ldb_message_element *el;
1385
1386                 /*if we are RODC and this is a DRSR update then its ok*/
1387                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1388                     && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1389                         unsigned instanceType;
1390
1391                         ret = samdb_rodc(ldb, rodc);
1392                         if (ret != LDB_SUCCESS) {
1393                                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1394                         } else if (*rodc) {
1395                                 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1396                                 return LDB_ERR_REFERRAL;
1397                         }
1398
1399                         instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1400                         if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1401                                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1402                                                  "cannot change replicated attribute on partial replica");
1403                         }
1404                 }
1405
1406                 md_value = talloc(msg, struct ldb_val);
1407                 if (md_value == NULL) {
1408                         ldb_oom(ldb);
1409                         return LDB_ERR_OPERATIONS_ERROR;
1410                 }
1411
1412                 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1413                 if (ret != LDB_SUCCESS) {
1414                         return ret;
1415                 }
1416
1417                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1418                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1419                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1420                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1421                                  ldb_dn_get_linearized(msg->dn)));
1422                         return LDB_ERR_OPERATIONS_ERROR;
1423                 }
1424
1425                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1426                 if (ret != LDB_SUCCESS) {
1427                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1428                                  ldb_dn_get_linearized(msg->dn)));
1429                         return ret;
1430                 }
1431
1432                 el->num_values = 1;
1433                 el->values = md_value;
1434         }
1435
1436         return LDB_SUCCESS;
1437 }
1438
1439 struct parsed_dn {
1440         struct dsdb_dn *dsdb_dn;
1441         struct GUID *guid;
1442         struct ldb_val *v;
1443 };
1444
1445 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1446 {
1447         return GUID_compare(pdn1->guid, pdn2->guid);
1448 }
1449
1450 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1451                                         unsigned int count, struct GUID *guid,
1452                                         struct ldb_dn *dn)
1453 {
1454         struct parsed_dn *ret;
1455         unsigned int i;
1456         if (dn && GUID_all_zero(guid)) {
1457                 /* when updating a link using DRS, we sometimes get a
1458                    NULL GUID. We then need to try and match by DN */
1459                 for (i=0; i<count; i++) {
1460                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1461                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1462                                 return &pdn[i];
1463                         }
1464                 }
1465                 return NULL;
1466         }
1467         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1468         return ret;
1469 }
1470
1471 /*
1472   get a series of message element values as an array of DNs and GUIDs
1473   the result is sorted by GUID
1474  */
1475 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1476                           struct ldb_message_element *el, struct parsed_dn **pdn,
1477                           const char *ldap_oid, struct ldb_request *parent)
1478 {
1479         unsigned int i;
1480         struct ldb_context *ldb = ldb_module_get_ctx(module);
1481
1482         if (el == NULL) {
1483                 *pdn = NULL;
1484                 return LDB_SUCCESS;
1485         }
1486
1487         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1488         if (!*pdn) {
1489                 ldb_module_oom(module);
1490                 return LDB_ERR_OPERATIONS_ERROR;
1491         }
1492
1493         for (i=0; i<el->num_values; i++) {
1494                 struct ldb_val *v = &el->values[i];
1495                 NTSTATUS status;
1496                 struct ldb_dn *dn;
1497                 struct parsed_dn *p;
1498
1499                 p = &(*pdn)[i];
1500
1501                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1502                 if (p->dsdb_dn == NULL) {
1503                         return LDB_ERR_INVALID_DN_SYNTAX;
1504                 }
1505
1506                 dn = p->dsdb_dn->dn;
1507
1508                 p->guid = talloc(*pdn, struct GUID);
1509                 if (p->guid == NULL) {
1510                         ldb_module_oom(module);
1511                         return LDB_ERR_OPERATIONS_ERROR;
1512                 }
1513
1514                 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1515                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1516                         /* we got a DN without a GUID - go find the GUID */
1517                         int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1518                         if (ret != LDB_SUCCESS) {
1519                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1520                                                        ldb_dn_get_linearized(dn));
1521                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1522                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1523                                     ldb_attr_cmp(el->name, "member") == 0) {
1524                                         return LDB_ERR_UNWILLING_TO_PERFORM;
1525                                 }
1526                                 return ret;
1527                         }
1528                         ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1529                         if (ret != LDB_SUCCESS) {
1530                                 return ret;
1531                         }
1532                 } else if (!NT_STATUS_IS_OK(status)) {
1533                         return LDB_ERR_OPERATIONS_ERROR;
1534                 }
1535
1536                 /* keep a pointer to the original ldb_val */
1537                 p->v = v;
1538         }
1539
1540         TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1541
1542         return LDB_SUCCESS;
1543 }
1544
1545 /*
1546   build a new extended DN, including all meta data fields
1547
1548   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1549   RMD_ADDTIME         = originating_add_time
1550   RMD_INVOCID         = originating_invocation_id
1551   RMD_CHANGETIME      = originating_change_time
1552   RMD_ORIGINATING_USN = originating_usn
1553   RMD_LOCAL_USN       = local_usn
1554   RMD_VERSION         = version
1555  */
1556 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1557                                const struct GUID *invocation_id, uint64_t seq_num,
1558                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1559 {
1560         struct ldb_dn *dn = dsdb_dn->dn;
1561         const char *tstring, *usn_string, *flags_string;
1562         struct ldb_val tval;
1563         struct ldb_val iid;
1564         struct ldb_val usnv, local_usnv;
1565         struct ldb_val vers, flagsv;
1566         NTSTATUS status;
1567         int ret;
1568         const char *dnstring;
1569         char *vstring;
1570         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1571
1572         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1573         if (!tstring) {
1574                 return LDB_ERR_OPERATIONS_ERROR;
1575         }
1576         tval = data_blob_string_const(tstring);
1577
1578         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1579         if (!usn_string) {
1580                 return LDB_ERR_OPERATIONS_ERROR;
1581         }
1582         usnv = data_blob_string_const(usn_string);
1583
1584         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1585         if (!usn_string) {
1586                 return LDB_ERR_OPERATIONS_ERROR;
1587         }
1588         local_usnv = data_blob_string_const(usn_string);
1589
1590         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1591         if (!vstring) {
1592                 return LDB_ERR_OPERATIONS_ERROR;
1593         }
1594         vers = data_blob_string_const(vstring);
1595
1596         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1597         if (!NT_STATUS_IS_OK(status)) {
1598                 return LDB_ERR_OPERATIONS_ERROR;
1599         }
1600
1601         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1602         if (!flags_string) {
1603                 return LDB_ERR_OPERATIONS_ERROR;
1604         }
1605         flagsv = data_blob_string_const(flags_string);
1606
1607         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1608         if (ret != LDB_SUCCESS) return ret;
1609         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1610         if (ret != LDB_SUCCESS) return ret;
1611         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1612         if (ret != LDB_SUCCESS) return ret;
1613         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1614         if (ret != LDB_SUCCESS) return ret;
1615         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1616         if (ret != LDB_SUCCESS) return ret;
1617         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1618         if (ret != LDB_SUCCESS) return ret;
1619         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1620         if (ret != LDB_SUCCESS) return ret;
1621
1622         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1623         if (dnstring == NULL) {
1624                 return LDB_ERR_OPERATIONS_ERROR;
1625         }
1626         *v = data_blob_string_const(dnstring);
1627
1628         return LDB_SUCCESS;
1629 }
1630
1631 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1632                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1633                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1634                                 uint32_t version, bool deleted);
1635
1636 /*
1637   check if any links need upgrading from w2k format
1638
1639   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.
1640  */
1641 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1642 {
1643         uint32_t i;
1644         for (i=0; i<count; i++) {
1645                 NTSTATUS status;
1646                 uint32_t version;
1647                 int ret;
1648
1649                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1650                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1651                         continue;
1652                 }
1653
1654                 /* it's an old one that needs upgrading */
1655                 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1656                                            1, 1, 0, 0, false);
1657                 if (ret != LDB_SUCCESS) {
1658                         return ret;
1659                 }
1660         }
1661         return LDB_SUCCESS;
1662 }
1663
1664 /*
1665   update an extended DN, including all meta data fields
1666
1667   see replmd_build_la_val for value names
1668  */
1669 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1670                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1671                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1672                                 uint32_t version, bool deleted)
1673 {
1674         struct ldb_dn *dn = dsdb_dn->dn;
1675         const char *tstring, *usn_string, *flags_string;
1676         struct ldb_val tval;
1677         struct ldb_val iid;
1678         struct ldb_val usnv, local_usnv;
1679         struct ldb_val vers, flagsv;
1680         const struct ldb_val *old_addtime;
1681         uint32_t old_version;
1682         NTSTATUS status;
1683         int ret;
1684         const char *dnstring;
1685         char *vstring;
1686         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1687
1688         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1689         if (!tstring) {
1690                 return LDB_ERR_OPERATIONS_ERROR;
1691         }
1692         tval = data_blob_string_const(tstring);
1693
1694         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1695         if (!usn_string) {
1696                 return LDB_ERR_OPERATIONS_ERROR;
1697         }
1698         usnv = data_blob_string_const(usn_string);
1699
1700         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1701         if (!usn_string) {
1702                 return LDB_ERR_OPERATIONS_ERROR;
1703         }
1704         local_usnv = data_blob_string_const(usn_string);
1705
1706         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1707         if (!NT_STATUS_IS_OK(status)) {
1708                 return LDB_ERR_OPERATIONS_ERROR;
1709         }
1710
1711         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1712         if (!flags_string) {
1713                 return LDB_ERR_OPERATIONS_ERROR;
1714         }
1715         flagsv = data_blob_string_const(flags_string);
1716
1717         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1718         if (ret != LDB_SUCCESS) return ret;
1719
1720         /* get the ADDTIME from the original */
1721         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1722         if (old_addtime == NULL) {
1723                 old_addtime = &tval;
1724         }
1725         if (dsdb_dn != old_dsdb_dn ||
1726             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1727                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1728                 if (ret != LDB_SUCCESS) return ret;
1729         }
1730
1731         /* use our invocation id */
1732         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1733         if (ret != LDB_SUCCESS) return ret;
1734
1735         /* changetime is the current time */
1736         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1737         if (ret != LDB_SUCCESS) return ret;
1738
1739         /* update the USN */
1740         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1741         if (ret != LDB_SUCCESS) return ret;
1742
1743         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1744         if (ret != LDB_SUCCESS) return ret;
1745
1746         /* increase the version by 1 */
1747         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1748         if (NT_STATUS_IS_OK(status) && old_version >= version) {
1749                 version = old_version+1;
1750         }
1751         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1752         vers = data_blob_string_const(vstring);
1753         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1754         if (ret != LDB_SUCCESS) return ret;
1755
1756         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1757         if (dnstring == NULL) {
1758                 return LDB_ERR_OPERATIONS_ERROR;
1759         }
1760         *v = data_blob_string_const(dnstring);
1761
1762         return LDB_SUCCESS;
1763 }
1764
1765 /*
1766   handle adding a linked attribute
1767  */
1768 static int replmd_modify_la_add(struct ldb_module *module,
1769                                 const struct dsdb_schema *schema,
1770                                 struct ldb_message *msg,
1771                                 struct ldb_message_element *el,
1772                                 struct ldb_message_element *old_el,
1773                                 const struct dsdb_attribute *schema_attr,
1774                                 uint64_t seq_num,
1775                                 time_t t,
1776                                 struct GUID *msg_guid,
1777                                 struct ldb_request *parent)
1778 {
1779         unsigned int i;
1780         struct parsed_dn *dns, *old_dns;
1781         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1782         int ret;
1783         struct ldb_val *new_values = NULL;
1784         unsigned int num_new_values = 0;
1785         unsigned old_num_values = old_el?old_el->num_values:0;
1786         const struct GUID *invocation_id;
1787         struct ldb_context *ldb = ldb_module_get_ctx(module);
1788         NTTIME now;
1789
1790         unix_to_nt_time(&now, t);
1791
1792         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1793         if (ret != LDB_SUCCESS) {
1794                 talloc_free(tmp_ctx);
1795                 return ret;
1796         }
1797
1798         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1799         if (ret != LDB_SUCCESS) {
1800                 talloc_free(tmp_ctx);
1801                 return ret;
1802         }
1803
1804         invocation_id = samdb_ntds_invocation_id(ldb);
1805         if (!invocation_id) {
1806                 talloc_free(tmp_ctx);
1807                 return LDB_ERR_OPERATIONS_ERROR;
1808         }
1809
1810         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1811         if (ret != LDB_SUCCESS) {
1812                 talloc_free(tmp_ctx);
1813                 return ret;
1814         }
1815
1816         /* for each new value, see if it exists already with the same GUID */
1817         for (i=0; i<el->num_values; i++) {
1818                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1819                 if (p == NULL) {
1820                         /* this is a new linked attribute value */
1821                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1822                         if (new_values == NULL) {
1823                                 ldb_module_oom(module);
1824                                 talloc_free(tmp_ctx);
1825                                 return LDB_ERR_OPERATIONS_ERROR;
1826                         }
1827                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1828                                                   invocation_id, seq_num, seq_num, now, 0, false);
1829                         if (ret != LDB_SUCCESS) {
1830                                 talloc_free(tmp_ctx);
1831                                 return ret;
1832                         }
1833                         num_new_values++;
1834                 } else {
1835                         /* this is only allowed if the GUID was
1836                            previously deleted. */
1837                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1838
1839                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1840                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1841                                                        el->name, GUID_string(tmp_ctx, p->guid));
1842                                 talloc_free(tmp_ctx);
1843                                 /* error codes for 'member' need to be
1844                                    special cased */
1845                                 if (ldb_attr_cmp(el->name, "member") == 0) {
1846                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
1847                                 } else {
1848                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1849                                 }
1850                         }
1851                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1852                                                    invocation_id, seq_num, seq_num, now, 0, false);
1853                         if (ret != LDB_SUCCESS) {
1854                                 talloc_free(tmp_ctx);
1855                                 return ret;
1856                         }
1857                 }
1858
1859                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1860                 if (ret != LDB_SUCCESS) {
1861                         talloc_free(tmp_ctx);
1862                         return ret;
1863                 }
1864         }
1865
1866         /* add the new ones on to the end of the old values, constructing a new el->values */
1867         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1868                                     struct ldb_val,
1869                                     old_num_values+num_new_values);
1870         if (el->values == NULL) {
1871                 ldb_module_oom(module);
1872                 return LDB_ERR_OPERATIONS_ERROR;
1873         }
1874
1875         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1876         el->num_values = old_num_values + num_new_values;
1877
1878         talloc_steal(msg->elements, el->values);
1879         talloc_steal(el->values, new_values);
1880
1881         talloc_free(tmp_ctx);
1882
1883         /* we now tell the backend to replace all existing values
1884            with the one we have constructed */
1885         el->flags = LDB_FLAG_MOD_REPLACE;
1886
1887         return LDB_SUCCESS;
1888 }
1889
1890
1891 /*
1892   handle deleting all active linked attributes
1893  */
1894 static int replmd_modify_la_delete(struct ldb_module *module,
1895                                    const struct dsdb_schema *schema,
1896                                    struct ldb_message *msg,
1897                                    struct ldb_message_element *el,
1898                                    struct ldb_message_element *old_el,
1899                                    const struct dsdb_attribute *schema_attr,
1900                                    uint64_t seq_num,
1901                                    time_t t,
1902                                    struct GUID *msg_guid,
1903                                    struct ldb_request *parent)
1904 {
1905         unsigned int i;
1906         struct parsed_dn *dns, *old_dns;
1907         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1908         int ret;
1909         const struct GUID *invocation_id;
1910         struct ldb_context *ldb = ldb_module_get_ctx(module);
1911         NTTIME now;
1912
1913         unix_to_nt_time(&now, t);
1914
1915         /* check if there is nothing to delete */
1916         if ((!old_el || old_el->num_values == 0) &&
1917             el->num_values == 0) {
1918                 return LDB_SUCCESS;
1919         }
1920
1921         if (!old_el || old_el->num_values == 0) {
1922                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1923         }
1924
1925         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1926         if (ret != LDB_SUCCESS) {
1927                 talloc_free(tmp_ctx);
1928                 return ret;
1929         }
1930
1931         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1932         if (ret != LDB_SUCCESS) {
1933                 talloc_free(tmp_ctx);
1934                 return ret;
1935         }
1936
1937         invocation_id = samdb_ntds_invocation_id(ldb);
1938         if (!invocation_id) {
1939                 return LDB_ERR_OPERATIONS_ERROR;
1940         }
1941
1942         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1943         if (ret != LDB_SUCCESS) {
1944                 talloc_free(tmp_ctx);
1945                 return ret;
1946         }
1947
1948         el->values = NULL;
1949
1950         /* see if we are being asked to delete any links that
1951            don't exist or are already deleted */
1952         for (i=0; i<el->num_values; i++) {
1953                 struct parsed_dn *p = &dns[i];
1954                 struct parsed_dn *p2;
1955                 uint32_t rmd_flags;
1956
1957                 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1958                 if (!p2) {
1959                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1960                                                el->name, GUID_string(tmp_ctx, p->guid));
1961                         if (ldb_attr_cmp(el->name, "member") == 0) {
1962                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1963                         } else {
1964                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1965                         }
1966                 }
1967                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1968                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1969                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1970                                                el->name, GUID_string(tmp_ctx, p->guid));
1971                         if (ldb_attr_cmp(el->name, "member") == 0) {
1972                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1973                         } else {
1974                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1975                         }
1976                 }
1977         }
1978
1979         /* for each new value, see if it exists already with the same GUID
1980            if it is not already deleted and matches the delete list then delete it
1981         */
1982         for (i=0; i<old_el->num_values; i++) {
1983                 struct parsed_dn *p = &old_dns[i];
1984                 uint32_t rmd_flags;
1985
1986                 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1987                         continue;
1988                 }
1989
1990                 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1991                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1992
1993                 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1994                                            invocation_id, seq_num, seq_num, now, 0, true);
1995                 if (ret != LDB_SUCCESS) {
1996                         talloc_free(tmp_ctx);
1997                         return ret;
1998                 }
1999
2000                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
2001                 if (ret != LDB_SUCCESS) {
2002                         talloc_free(tmp_ctx);
2003                         return ret;
2004                 }
2005         }
2006
2007         el->values = talloc_steal(msg->elements, old_el->values);
2008         el->num_values = old_el->num_values;
2009
2010         talloc_free(tmp_ctx);
2011
2012         /* we now tell the backend to replace all existing values
2013            with the one we have constructed */
2014         el->flags = LDB_FLAG_MOD_REPLACE;
2015
2016         return LDB_SUCCESS;
2017 }
2018
2019 /*
2020   handle replacing a linked attribute
2021  */
2022 static int replmd_modify_la_replace(struct ldb_module *module,
2023                                     const struct dsdb_schema *schema,
2024                                     struct ldb_message *msg,
2025                                     struct ldb_message_element *el,
2026                                     struct ldb_message_element *old_el,
2027                                     const struct dsdb_attribute *schema_attr,
2028                                     uint64_t seq_num,
2029                                     time_t t,
2030                                     struct GUID *msg_guid,
2031                                     struct ldb_request *parent)
2032 {
2033         unsigned int i;
2034         struct parsed_dn *dns, *old_dns;
2035         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2036         int ret;
2037         const struct GUID *invocation_id;
2038         struct ldb_context *ldb = ldb_module_get_ctx(module);
2039         struct ldb_val *new_values = NULL;
2040         unsigned int num_new_values = 0;
2041         unsigned int old_num_values = old_el?old_el->num_values:0;
2042         NTTIME now;
2043
2044         unix_to_nt_time(&now, t);
2045
2046         /* check if there is nothing to replace */
2047         if ((!old_el || old_el->num_values == 0) &&
2048             el->num_values == 0) {
2049                 return LDB_SUCCESS;
2050         }
2051
2052         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2053         if (ret != LDB_SUCCESS) {
2054                 talloc_free(tmp_ctx);
2055                 return ret;
2056         }
2057
2058         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2059         if (ret != LDB_SUCCESS) {
2060                 talloc_free(tmp_ctx);
2061                 return ret;
2062         }
2063
2064         invocation_id = samdb_ntds_invocation_id(ldb);
2065         if (!invocation_id) {
2066                 return LDB_ERR_OPERATIONS_ERROR;
2067         }
2068
2069         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2070         if (ret != LDB_SUCCESS) {
2071                 talloc_free(tmp_ctx);
2072                 return ret;
2073         }
2074
2075         /* mark all the old ones as deleted */
2076         for (i=0; i<old_num_values; i++) {
2077                 struct parsed_dn *old_p = &old_dns[i];
2078                 struct parsed_dn *p;
2079                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2080
2081                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2082
2083                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
2084                 if (ret != LDB_SUCCESS) {
2085                         talloc_free(tmp_ctx);
2086                         return ret;
2087                 }
2088
2089                 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
2090                 if (p) {
2091                         /* we don't delete it if we are re-adding it */
2092                         continue;
2093                 }
2094
2095                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2096                                            invocation_id, seq_num, seq_num, now, 0, true);
2097                 if (ret != LDB_SUCCESS) {
2098                         talloc_free(tmp_ctx);
2099                         return ret;
2100                 }
2101         }
2102
2103         /* for each new value, either update its meta-data, or add it
2104          * to old_el
2105         */
2106         for (i=0; i<el->num_values; i++) {
2107                 struct parsed_dn *p = &dns[i], *old_p;
2108
2109                 if (old_dns &&
2110                     (old_p = parsed_dn_find(old_dns,
2111                                             old_num_values, p->guid, NULL)) != NULL) {
2112                         /* update in place */
2113                         ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2114                                                    old_p->dsdb_dn, invocation_id,
2115                                                    seq_num, seq_num, now, 0, false);
2116                         if (ret != LDB_SUCCESS) {
2117                                 talloc_free(tmp_ctx);
2118                                 return ret;
2119                         }
2120                 } else {
2121                         /* add a new one */
2122                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2123                                                     num_new_values+1);
2124                         if (new_values == NULL) {
2125                                 ldb_module_oom(module);
2126                                 talloc_free(tmp_ctx);
2127                                 return LDB_ERR_OPERATIONS_ERROR;
2128                         }
2129                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2130                                                   invocation_id, seq_num, seq_num, now, 0, false);
2131                         if (ret != LDB_SUCCESS) {
2132                                 talloc_free(tmp_ctx);
2133                                 return ret;
2134                         }
2135                         num_new_values++;
2136                 }
2137
2138                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2139                 if (ret != LDB_SUCCESS) {
2140                         talloc_free(tmp_ctx);
2141                         return ret;
2142                 }
2143         }
2144
2145         /* add the new values to the end of old_el */
2146         if (num_new_values != 0) {
2147                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2148                                             struct ldb_val, old_num_values+num_new_values);
2149                 if (el->values == NULL) {
2150                         ldb_module_oom(module);
2151                         return LDB_ERR_OPERATIONS_ERROR;
2152                 }
2153                 memcpy(&el->values[old_num_values], &new_values[0],
2154                        sizeof(struct ldb_val)*num_new_values);
2155                 el->num_values = old_num_values + num_new_values;
2156                 talloc_steal(msg->elements, new_values);
2157         } else {
2158                 el->values = old_el->values;
2159                 el->num_values = old_el->num_values;
2160                 talloc_steal(msg->elements, el->values);
2161         }
2162
2163         talloc_free(tmp_ctx);
2164
2165         /* we now tell the backend to replace all existing values
2166            with the one we have constructed */
2167         el->flags = LDB_FLAG_MOD_REPLACE;
2168
2169         return LDB_SUCCESS;
2170 }
2171
2172
2173 /*
2174   handle linked attributes in modify requests
2175  */
2176 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2177                                                struct ldb_message *msg,
2178                                                uint64_t seq_num, time_t t,
2179                                                struct ldb_request *parent)
2180 {
2181         struct ldb_result *res;
2182         unsigned int i;
2183         int ret;
2184         struct ldb_context *ldb = ldb_module_get_ctx(module);
2185         struct ldb_message *old_msg;
2186
2187         const struct dsdb_schema *schema;
2188         struct GUID old_guid;
2189
2190         if (seq_num == 0) {
2191                 /* there the replmd_update_rpmd code has already
2192                  * checked and saw that there are no linked
2193                  * attributes */
2194                 return LDB_SUCCESS;
2195         }
2196
2197         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2198                 /* don't do anything special for linked attributes */
2199                 return LDB_SUCCESS;
2200         }
2201
2202         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2203                                     DSDB_FLAG_NEXT_MODULE |
2204                                     DSDB_SEARCH_SHOW_RECYCLED |
2205                                     DSDB_SEARCH_REVEAL_INTERNALS |
2206                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2207                                     parent);
2208         if (ret != LDB_SUCCESS) {
2209                 return ret;
2210         }
2211         schema = dsdb_get_schema(ldb, res);
2212         if (!schema) {
2213                 return LDB_ERR_OPERATIONS_ERROR;
2214         }
2215
2216         old_msg = res->msgs[0];
2217
2218         old_guid = samdb_result_guid(old_msg, "objectGUID");
2219
2220         for (i=0; i<msg->num_elements; i++) {
2221                 struct ldb_message_element *el = &msg->elements[i];
2222                 struct ldb_message_element *old_el, *new_el;
2223                 const struct dsdb_attribute *schema_attr
2224                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2225                 if (!schema_attr) {
2226                         ldb_asprintf_errstring(ldb,
2227                                                "%s: attribute %s is not a valid attribute in schema",
2228                                                __FUNCTION__, el->name);
2229                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2230                 }
2231                 if (schema_attr->linkID == 0) {
2232                         continue;
2233                 }
2234                 if ((schema_attr->linkID & 1) == 1) {
2235                         if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2236                                 continue;
2237                         }
2238                         /* Odd is for the target.  Illegal to modify */
2239                         ldb_asprintf_errstring(ldb,
2240                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2241                         return LDB_ERR_UNWILLING_TO_PERFORM;
2242                 }
2243                 old_el = ldb_msg_find_element(old_msg, el->name);
2244                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2245                 case LDB_FLAG_MOD_REPLACE:
2246                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2247                         break;
2248                 case LDB_FLAG_MOD_DELETE:
2249                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2250                         break;
2251                 case LDB_FLAG_MOD_ADD:
2252                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2253                         break;
2254                 default:
2255                         ldb_asprintf_errstring(ldb,
2256                                                "invalid flags 0x%x for %s linked attribute",
2257                                                el->flags, el->name);
2258                         return LDB_ERR_UNWILLING_TO_PERFORM;
2259                 }
2260                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2261                         ldb_asprintf_errstring(ldb,
2262                                                "Attribute %s is single valued but more than one value has been supplied",
2263                                                el->name);
2264                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2265                 } else {
2266                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2267                 }
2268
2269
2270
2271                 if (ret != LDB_SUCCESS) {
2272                         return ret;
2273                 }
2274                 if (old_el) {
2275                         ldb_msg_remove_attr(old_msg, el->name);
2276                 }
2277                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2278                 new_el->num_values = el->num_values;
2279                 new_el->values = talloc_steal(msg->elements, el->values);
2280
2281                 /* TODO: this relises a bit too heavily on the exact
2282                    behaviour of ldb_msg_find_element and
2283                    ldb_msg_remove_element */
2284                 old_el = ldb_msg_find_element(msg, el->name);
2285                 if (old_el != el) {
2286                         ldb_msg_remove_element(msg, old_el);
2287                         i--;
2288                 }
2289         }
2290
2291         talloc_free(res);
2292         return ret;
2293 }
2294
2295
2296
2297 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2298 {
2299         struct samldb_msds_intid_persistant *msds_intid_struct;
2300         struct ldb_context *ldb;
2301         struct replmd_replicated_request *ac;
2302         struct ldb_request *down_req;
2303         struct ldb_message *msg;
2304         time_t t = time(NULL);
2305         int ret;
2306         bool is_urgent = false, rodc = false;
2307         unsigned int functional_level;
2308         const DATA_BLOB *guid_blob;
2309         struct ldb_control *sd_propagation_control;
2310
2311         /* do not manipulate our control entries */
2312         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2313                 return ldb_next_request(module, req);
2314         }
2315
2316         sd_propagation_control = ldb_request_get_control(req,
2317                                         DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
2318         if (sd_propagation_control != NULL) {
2319                 if (req->op.mod.message->num_elements != 1) {
2320                         return ldb_module_operr(module);
2321                 }
2322                 ret = strcmp(req->op.mod.message->elements[0].name,
2323                              "nTSecurityDescriptor");
2324                 if (ret != 0) {
2325                         return ldb_module_operr(module);
2326                 }
2327
2328                 return ldb_next_request(module, req);
2329         }
2330
2331         ldb = ldb_module_get_ctx(module);
2332
2333         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2334
2335         guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2336         if ( guid_blob != NULL ) {
2337                 ldb_set_errstring(ldb,
2338                                   "replmd_modify: it's not allowed to change the objectGUID!");
2339                 return LDB_ERR_CONSTRAINT_VIOLATION;
2340         }
2341
2342         ac = replmd_ctx_init(module, req);
2343         if (ac == NULL) {
2344                 return ldb_module_oom(module);
2345         }
2346
2347         functional_level = dsdb_functional_level(ldb);
2348
2349         /* we have to copy the message as the caller might have it as a const */
2350         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2351         if (msg == NULL) {
2352                 ldb_oom(ldb);
2353                 talloc_free(ac);
2354                 return LDB_ERR_OPERATIONS_ERROR;
2355         }
2356
2357         ldb_msg_remove_attr(msg, "whenChanged");
2358         ldb_msg_remove_attr(msg, "uSNChanged");
2359
2360         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2361                                  msg, &ac->seq_num, t, &is_urgent, &rodc);
2362         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2363                 struct loadparm_context *lp_ctx;
2364                 char *referral;
2365
2366                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2367                                          struct loadparm_context);
2368
2369                 referral = talloc_asprintf(req,
2370                                            "ldap://%s/%s",
2371                                            lpcfg_dnsdomain(lp_ctx),
2372                                            ldb_dn_get_linearized(msg->dn));
2373                 ret = ldb_module_send_referral(req, referral);
2374                 talloc_free(ac);
2375                 return ret;
2376         }
2377
2378         if (ret != LDB_SUCCESS) {
2379                 talloc_free(ac);
2380                 return ret;
2381         }
2382
2383         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2384         if (ret != LDB_SUCCESS) {
2385                 talloc_free(ac);
2386                 return ret;
2387         }
2388
2389         /* TODO:
2390          * - replace the old object with the newly constructed one
2391          */
2392
2393         ac->is_urgent = is_urgent;
2394
2395         ret = ldb_build_mod_req(&down_req, ldb, ac,
2396                                 msg,
2397                                 req->controls,
2398                                 ac, replmd_op_callback,
2399                                 req);
2400         LDB_REQ_SET_LOCATION(down_req);
2401         if (ret != LDB_SUCCESS) {
2402                 talloc_free(ac);
2403                 return ret;
2404         }
2405
2406         /* current partition control is needed by "replmd_op_callback" */
2407         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2408                 ret = ldb_request_add_control(down_req,
2409                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2410                                               false, NULL);
2411                 if (ret != LDB_SUCCESS) {
2412                         talloc_free(ac);
2413                         return ret;
2414                 }
2415         }
2416
2417         /* If we are in functional level 2000, then
2418          * replmd_modify_handle_linked_attribs will have done
2419          * nothing */
2420         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2421                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2422                 if (ret != LDB_SUCCESS) {
2423                         talloc_free(ac);
2424                         return ret;
2425                 }
2426         }
2427
2428         talloc_steal(down_req, msg);
2429
2430         /* we only change whenChanged and uSNChanged if the seq_num
2431            has changed */
2432         if (ac->seq_num != 0) {
2433                 ret = add_time_element(msg, "whenChanged", t);
2434                 if (ret != LDB_SUCCESS) {
2435                         talloc_free(ac);
2436                         ldb_operr(ldb);
2437                         return ret;
2438                 }
2439
2440                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2441                 if (ret != LDB_SUCCESS) {
2442                         talloc_free(ac);
2443                         ldb_operr(ldb);
2444                         return ret;
2445                 }
2446         }
2447
2448         if (!ldb_dn_compare_base(ac->schema->base_dn, msg->dn)) {
2449                 /* Update the usn in the SAMLDB_MSDS_INTID_OPAQUE opaque */
2450                 msds_intid_struct = (struct samldb_msds_intid_persistant *) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
2451                 if (msds_intid_struct) {
2452                         msds_intid_struct->usn = ac->seq_num;
2453                 }
2454         }
2455
2456         /* go on with the call chain */
2457         return ldb_next_request(module, down_req);
2458 }
2459
2460 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2461
2462 /*
2463   handle a rename request
2464
2465   On a rename we need to do an extra ldb_modify which sets the
2466   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2467  */
2468 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2469 {
2470         struct ldb_context *ldb;
2471         struct replmd_replicated_request *ac;
2472         int ret;
2473         struct ldb_request *down_req;
2474
2475         /* do not manipulate our control entries */
2476         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2477                 return ldb_next_request(module, req);
2478         }
2479
2480         ldb = ldb_module_get_ctx(module);
2481
2482         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2483
2484         ac = replmd_ctx_init(module, req);
2485         if (ac == NULL) {
2486                 return ldb_module_oom(module);
2487         }
2488
2489         ret = ldb_build_rename_req(&down_req, ldb, ac,
2490                                    ac->req->op.rename.olddn,
2491                                    ac->req->op.rename.newdn,
2492                                    ac->req->controls,
2493                                    ac, replmd_rename_callback,
2494                                    ac->req);
2495         LDB_REQ_SET_LOCATION(down_req);
2496         if (ret != LDB_SUCCESS) {
2497                 talloc_free(ac);
2498                 return ret;
2499         }
2500
2501         /* go on with the call chain */
2502         return ldb_next_request(module, down_req);
2503 }
2504
2505 /* After the rename is compleated, update the whenchanged etc */
2506 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2507 {
2508         struct ldb_context *ldb;
2509         struct replmd_replicated_request *ac;
2510         struct ldb_request *down_req;
2511         struct ldb_message *msg;
2512         const struct dsdb_attribute *rdn_attr;
2513         const char *rdn_name;
2514         const struct ldb_val *rdn_val;
2515         const char *attrs[5] = { NULL, };
2516         time_t t = time(NULL);
2517         int ret;
2518         bool is_urgent = false, rodc = false;
2519
2520         ac = talloc_get_type(req->context, struct replmd_replicated_request);
2521         ldb = ldb_module_get_ctx(ac->module);
2522
2523         if (ares->error != LDB_SUCCESS) {
2524                 return ldb_module_done(ac->req, ares->controls,
2525                                         ares->response, ares->error);
2526         }
2527
2528         if (ares->type != LDB_REPLY_DONE) {
2529                 ldb_set_errstring(ldb,
2530                                   "invalid ldb_reply_type in callback");
2531                 talloc_free(ares);
2532                 return ldb_module_done(ac->req, NULL, NULL,
2533                                         LDB_ERR_OPERATIONS_ERROR);
2534         }
2535
2536         /* TODO:
2537          * - replace the old object with the newly constructed one
2538          */
2539
2540         msg = ldb_msg_new(ac);
2541         if (msg == NULL) {
2542                 ldb_oom(ldb);
2543                 return LDB_ERR_OPERATIONS_ERROR;
2544         }
2545
2546         msg->dn = ac->req->op.rename.newdn;
2547
2548         rdn_name = ldb_dn_get_rdn_name(msg->dn);
2549         if (rdn_name == NULL) {
2550                 talloc_free(ares);
2551                 return ldb_module_done(ac->req, NULL, NULL,
2552                                        ldb_operr(ldb));
2553         }
2554
2555         /* normalize the rdn attribute name */
2556         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2557         if (rdn_attr == NULL) {
2558                 talloc_free(ares);
2559                 return ldb_module_done(ac->req, NULL, NULL,
2560                                        ldb_operr(ldb));
2561         }
2562         rdn_name = rdn_attr->lDAPDisplayName;
2563
2564         rdn_val = ldb_dn_get_rdn_val(msg->dn);
2565         if (rdn_val == NULL) {
2566                 talloc_free(ares);
2567                 return ldb_module_done(ac->req, NULL, NULL,
2568                                        ldb_operr(ldb));
2569         }
2570
2571         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2572                 talloc_free(ares);
2573                 return ldb_module_done(ac->req, NULL, NULL,
2574                                        ldb_oom(ldb));
2575         }
2576         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2577                 talloc_free(ares);
2578                 return ldb_module_done(ac->req, NULL, NULL,
2579                                        ldb_oom(ldb));
2580         }
2581         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2582                 talloc_free(ares);
2583                 return ldb_module_done(ac->req, NULL, NULL,
2584                                        ldb_oom(ldb));
2585         }
2586         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2587                 talloc_free(ares);
2588                 return ldb_module_done(ac->req, NULL, NULL,
2589                                        ldb_oom(ldb));
2590         }
2591
2592         /*
2593          * here we let replmd_update_rpmd() only search for
2594          * the existing "replPropertyMetaData" and rdn_name attributes.
2595          *
2596          * We do not want the existing "name" attribute as
2597          * the "name" attribute needs to get the version
2598          * updated on rename even if the rdn value hasn't changed.
2599          *
2600          * This is the diff of the meta data, for a moved user
2601          * on a w2k8r2 server:
2602          *
2603          * # record 1
2604          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2605          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2606          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
2607          *         version                  : 0x00000001 (1)
2608          *         reserved                 : 0x00000000 (0)
2609          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
2610          *                      local_usn                : 0x00000000000037a5 (14245)
2611          *                 array: struct replPropertyMetaData1
2612          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
2613          * -                    version                  : 0x00000001 (1)
2614          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
2615          * +                    version                  : 0x00000002 (2)
2616          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
2617          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2618          * -                    originating_usn          : 0x00000000000037a5 (14245)
2619          * -                    local_usn                : 0x00000000000037a5 (14245)
2620          * +                    originating_usn          : 0x0000000000003834 (14388)
2621          * +                    local_usn                : 0x0000000000003834 (14388)
2622          *                 array: struct replPropertyMetaData1
2623          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
2624          *                      version                  : 0x00000004 (4)
2625          */
2626         attrs[0] = "replPropertyMetaData";
2627         attrs[1] = "objectClass";
2628         attrs[2] = "instanceType";
2629         attrs[3] = rdn_name;
2630         attrs[4] = NULL;
2631
2632         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2633                                  msg, &ac->seq_num, t, &is_urgent, &rodc);
2634         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2635                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2636                 struct loadparm_context *lp_ctx;
2637                 char *referral;
2638
2639                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2640                                          struct loadparm_context);
2641
2642                 referral = talloc_asprintf(req,
2643                                            "ldap://%s/%s",
2644                                            lpcfg_dnsdomain(lp_ctx),
2645                                            ldb_dn_get_linearized(olddn));
2646                 ret = ldb_module_send_referral(req, referral);
2647                 talloc_free(ares);
2648                 return ldb_module_done(req, NULL, NULL, ret);
2649         }
2650
2651         if (ret != LDB_SUCCESS) {
2652                 talloc_free(ares);
2653                 return ldb_module_done(ac->req, NULL, NULL, ret);
2654         }
2655
2656         if (ac->seq_num == 0) {
2657                 talloc_free(ares);
2658                 return ldb_module_done(ac->req, NULL, NULL,
2659                                        ldb_error(ldb, ret,
2660                                         "internal error seq_num == 0"));
2661         }
2662         ac->is_urgent = is_urgent;
2663
2664         ret = ldb_build_mod_req(&down_req, ldb, ac,
2665                                 msg,
2666                                 req->controls,
2667                                 ac, replmd_op_callback,
2668                                 req);
2669         LDB_REQ_SET_LOCATION(down_req);
2670         if (ret != LDB_SUCCESS) {
2671                 talloc_free(ac);
2672                 return ret;
2673         }
2674
2675         /* current partition control is needed by "replmd_op_callback" */
2676         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2677                 ret = ldb_request_add_control(down_req,
2678                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2679                                               false, NULL);
2680                 if (ret != LDB_SUCCESS) {
2681                         talloc_free(ac);
2682                         return ret;
2683                 }
2684         }
2685
2686         talloc_steal(down_req, msg);
2687
2688         ret = add_time_element(msg, "whenChanged", t);
2689         if (ret != LDB_SUCCESS) {
2690                 talloc_free(ac);
2691                 ldb_operr(ldb);
2692                 return ret;
2693         }
2694
2695         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2696         if (ret != LDB_SUCCESS) {
2697                 talloc_free(ac);
2698                 ldb_operr(ldb);
2699                 return ret;
2700         }
2701
2702         /* go on with the call chain - do the modify after the rename */
2703         return ldb_next_request(ac->module, down_req);
2704 }
2705
2706 /*
2707    remove links from objects that point at this object when an object
2708    is deleted
2709  */
2710 static int replmd_delete_remove_link(struct ldb_module *module,
2711                                      const struct dsdb_schema *schema,
2712                                      struct ldb_dn *dn,
2713                                      struct ldb_message_element *el,
2714                                      const struct dsdb_attribute *sa,
2715                                      struct ldb_request *parent)
2716 {
2717         unsigned int i;
2718         TALLOC_CTX *tmp_ctx = talloc_new(module);
2719         struct ldb_context *ldb = ldb_module_get_ctx(module);
2720
2721         for (i=0; i<el->num_values; i++) {
2722                 struct dsdb_dn *dsdb_dn;
2723                 NTSTATUS status;
2724                 int ret;
2725                 struct GUID guid2;
2726                 struct ldb_message *msg;
2727                 const struct dsdb_attribute *target_attr;
2728                 struct ldb_message_element *el2;
2729                 struct ldb_val dn_val;
2730
2731                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2732                         continue;
2733                 }
2734
2735                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2736                 if (!dsdb_dn) {
2737                         talloc_free(tmp_ctx);
2738                         return LDB_ERR_OPERATIONS_ERROR;
2739                 }
2740
2741                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2742                 if (!NT_STATUS_IS_OK(status)) {
2743                         talloc_free(tmp_ctx);
2744                         return LDB_ERR_OPERATIONS_ERROR;
2745                 }
2746
2747                 /* remove the link */
2748                 msg = ldb_msg_new(tmp_ctx);
2749                 if (!msg) {
2750                         ldb_module_oom(module);
2751                         talloc_free(tmp_ctx);
2752                         return LDB_ERR_OPERATIONS_ERROR;
2753                 }
2754
2755
2756                 msg->dn = dsdb_dn->dn;
2757
2758                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2759                 if (target_attr == NULL) {
2760                         continue;
2761                 }
2762
2763                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2764                 if (ret != LDB_SUCCESS) {
2765                         ldb_module_oom(module);
2766                         talloc_free(tmp_ctx);
2767                         return LDB_ERR_OPERATIONS_ERROR;
2768                 }
2769                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2770                 el2->values = &dn_val;
2771                 el2->num_values = 1;
2772
2773                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2774                 if (ret != LDB_SUCCESS) {
2775                         talloc_free(tmp_ctx);
2776                         return ret;
2777                 }
2778         }
2779         talloc_free(tmp_ctx);
2780         return LDB_SUCCESS;
2781 }
2782
2783
2784 /*
2785   handle update of replication meta data for deletion of objects
2786
2787   This also handles the mapping of delete to a rename operation
2788   to allow deletes to be replicated.
2789  */
2790 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2791 {
2792         int ret = LDB_ERR_OTHER;
2793         bool retb, disallow_move_on_delete;
2794         struct ldb_dn *old_dn, *new_dn;
2795         const char *rdn_name;
2796         const struct ldb_val *rdn_value, *new_rdn_value;
2797         struct GUID guid;
2798         struct ldb_context *ldb = ldb_module_get_ctx(module);
2799         const struct dsdb_schema *schema;
2800         struct ldb_message *msg, *old_msg;
2801         struct ldb_message_element *el;
2802         TALLOC_CTX *tmp_ctx;
2803         struct ldb_result *res, *parent_res;
2804         const char *preserved_attrs[] = {
2805                 /* yes, this really is a hard coded list. See MS-ADTS
2806                    section 3.1.1.5.5.1.1 */
2807                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2808                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2809                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2810                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2811                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2812                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2813                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2814                 "whenChanged", NULL};
2815         unsigned int i, el_count = 0;
2816         enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2817                                                 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2818         enum deletion_state deletion_state, next_deletion_state;
2819         bool enabled;
2820
2821         if (ldb_dn_is_special(req->op.del.dn)) {
2822                 return ldb_next_request(module, req);
2823         }
2824
2825         tmp_ctx = talloc_new(ldb);
2826         if (!tmp_ctx) {
2827                 ldb_oom(ldb);
2828                 return LDB_ERR_OPERATIONS_ERROR;
2829         }
2830
2831         schema = dsdb_get_schema(ldb, tmp_ctx);
2832         if (!schema) {
2833                 return LDB_ERR_OPERATIONS_ERROR;
2834         }
2835
2836         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2837
2838         /* we need the complete msg off disk, so we can work out which
2839            attributes need to be removed */
2840         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2841                                     DSDB_FLAG_NEXT_MODULE |
2842                                     DSDB_SEARCH_SHOW_RECYCLED |
2843                                     DSDB_SEARCH_REVEAL_INTERNALS |
2844                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2845         if (ret != LDB_SUCCESS) {
2846                 talloc_free(tmp_ctx);
2847                 return ret;
2848         }
2849         old_msg = res->msgs[0];
2850
2851
2852         ret = dsdb_recyclebin_enabled(module, &enabled);
2853         if (ret != LDB_SUCCESS) {
2854                 talloc_free(tmp_ctx);
2855                 return ret;
2856         }
2857
2858         if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2859                 if (!enabled) {
2860                         deletion_state = OBJECT_TOMBSTONE;
2861                         next_deletion_state = OBJECT_REMOVED;
2862                 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2863                         deletion_state = OBJECT_RECYCLED;
2864                         next_deletion_state = OBJECT_REMOVED;
2865                 } else {
2866                         deletion_state = OBJECT_DELETED;
2867                         next_deletion_state = OBJECT_RECYCLED;
2868                 }
2869         } else {
2870                 deletion_state = OBJECT_NOT_DELETED;
2871                 if (enabled) {
2872                         next_deletion_state = OBJECT_DELETED;
2873                 } else {
2874                         next_deletion_state = OBJECT_TOMBSTONE;
2875                 }
2876         }
2877
2878         if (next_deletion_state == OBJECT_REMOVED) {
2879                 struct auth_session_info *session_info =
2880                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2881                 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2882                         ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2883                                         ldb_dn_get_linearized(old_msg->dn));
2884                         return LDB_ERR_UNWILLING_TO_PERFORM;
2885                 }
2886
2887                 /* it is already deleted - really remove it this time */
2888                 talloc_free(tmp_ctx);
2889                 return ldb_next_request(module, req);
2890         }
2891
2892         rdn_name = ldb_dn_get_rdn_name(old_dn);
2893         rdn_value = ldb_dn_get_rdn_val(old_dn);
2894         if ((rdn_name == NULL) || (rdn_value == NULL)) {
2895                 talloc_free(tmp_ctx);
2896                 return ldb_operr(ldb);
2897         }
2898
2899         msg = ldb_msg_new(tmp_ctx);
2900         if (msg == NULL) {
2901                 ldb_module_oom(module);
2902                 talloc_free(tmp_ctx);
2903                 return LDB_ERR_OPERATIONS_ERROR;
2904         }
2905
2906         msg->dn = old_dn;
2907
2908         if (deletion_state == OBJECT_NOT_DELETED){
2909                 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2910                 disallow_move_on_delete =
2911                         (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2912                                 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2913
2914                 /* work out where we will be renaming this object to */
2915                 if (!disallow_move_on_delete) {
2916                         ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2917                                                           &new_dn);
2918                         if (ret != LDB_SUCCESS) {
2919                                 /* this is probably an attempted delete on a partition
2920                                  * that doesn't allow delete operations, such as the
2921                                  * schema partition */
2922                                 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2923                                                            ldb_dn_get_linearized(old_dn));
2924                                 talloc_free(tmp_ctx);
2925                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2926                         }
2927                 } else {
2928                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2929                         if (new_dn == NULL) {
2930                                 ldb_module_oom(module);
2931                                 talloc_free(tmp_ctx);
2932                                 return LDB_ERR_OPERATIONS_ERROR;
2933                         }
2934                 }
2935
2936                 /* get the objects GUID from the search we just did */
2937                 guid = samdb_result_guid(old_msg, "objectGUID");
2938
2939                 /* Add a formatted child */
2940                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2941                                                 rdn_name,
2942                                                 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2943                                                 GUID_string(tmp_ctx, &guid));
2944                 if (!retb) {
2945                         DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2946                                         ldb_dn_get_linearized(new_dn)));
2947                         talloc_free(tmp_ctx);
2948                         return LDB_ERR_OPERATIONS_ERROR;
2949                 }
2950
2951                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2952                 if (ret != LDB_SUCCESS) {
2953                         DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2954                         ldb_module_oom(module);
2955                         talloc_free(tmp_ctx);
2956                         return ret;
2957                 }
2958                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2959         }
2960
2961         /*
2962           now we need to modify the object in the following ways:
2963
2964           - add isDeleted=TRUE
2965           - update rDN and name, with new rDN
2966           - remove linked attributes
2967           - remove objectCategory and sAMAccountType
2968           - remove attribs not on the preserved list
2969              - preserved if in above list, or is rDN
2970           - remove all linked attribs from this object
2971           - remove all links from other objects to this object
2972           - add lastKnownParent
2973           - update replPropertyMetaData?
2974
2975           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2976          */
2977
2978         /* we need the storage form of the parent GUID */
2979         ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2980                                     ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2981                                     DSDB_FLAG_NEXT_MODULE |
2982                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2983                                     DSDB_SEARCH_REVEAL_INTERNALS|
2984                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2985         if (ret != LDB_SUCCESS) {
2986                 talloc_free(tmp_ctx);
2987                 return ret;
2988         }
2989
2990         if (deletion_state == OBJECT_NOT_DELETED){
2991                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2992                                                    ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2993                 if (ret != LDB_SUCCESS) {
2994                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2995                         ldb_module_oom(module);
2996                         talloc_free(tmp_ctx);
2997                         return ret;
2998                 }
2999                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3000         }
3001
3002         switch (next_deletion_state){
3003
3004         case OBJECT_DELETED:
3005
3006                 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3007                 if (ret != LDB_SUCCESS) {
3008                         DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
3009                         ldb_module_oom(module);
3010                         talloc_free(tmp_ctx);
3011                         return ret;
3012                 }
3013                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3014
3015                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
3016                 if (ret != LDB_SUCCESS) {
3017                         talloc_free(tmp_ctx);
3018                         ldb_module_oom(module);
3019                         return ret;
3020                 }
3021
3022                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
3023                 if (ret != LDB_SUCCESS) {
3024                         talloc_free(tmp_ctx);
3025                         ldb_module_oom(module);
3026                         return ret;
3027                 }
3028
3029                 break;
3030
3031         case OBJECT_RECYCLED:
3032         case OBJECT_TOMBSTONE:
3033
3034                 /*
3035                  * we also mark it as recycled, meaning this object can't be
3036                  * recovered (we are stripping its attributes).
3037                  * This is done only if we have this schema object of course ...
3038                  * This behavior is identical to the one of Windows 2008R2 which
3039                  * always set the isRecycled attribute, even if the recycle-bin is
3040                  * not activated and what ever the forest level is.
3041                  */
3042                 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3043                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3044                         if (ret != LDB_SUCCESS) {
3045                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3046                                 ldb_module_oom(module);
3047                                 talloc_free(tmp_ctx);
3048                                 return ret;
3049                         }
3050                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3051                 }
3052
3053                 /* work out which of the old attributes we will be removing */
3054                 for (i=0; i<old_msg->num_elements; i++) {
3055                         const struct dsdb_attribute *sa;
3056                         el = &old_msg->elements[i];
3057                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3058                         if (!sa) {
3059                                 talloc_free(tmp_ctx);
3060                                 return LDB_ERR_OPERATIONS_ERROR;
3061                         }
3062                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3063                                 /* don't remove the rDN */
3064                                 continue;
3065                         }
3066                         if (sa->linkID && (sa->linkID & 1)) {
3067                                 /*
3068                                   we have a backlink in this object
3069                                   that needs to be removed. We're not
3070                                   allowed to remove it directly
3071                                   however, so we instead setup a
3072                                   modify to delete the corresponding
3073                                   forward link
3074                                  */
3075                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3076                                 if (ret != LDB_SUCCESS) {
3077                                         talloc_free(tmp_ctx);
3078                                         return LDB_ERR_OPERATIONS_ERROR;
3079                                 }
3080                                 /* now we continue, which means we
3081                                    won't remove this backlink
3082                                    directly
3083                                 */
3084                                 continue;
3085                         }
3086                         if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
3087                                 continue;
3088                         }
3089                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3090                         if (ret != LDB_SUCCESS) {
3091                                 talloc_free(tmp_ctx);
3092                                 ldb_module_oom(module);
3093                                 return ret;
3094                         }
3095                 }
3096                 break;
3097
3098         default:
3099                 break;
3100         }
3101
3102         if (deletion_state == OBJECT_NOT_DELETED) {
3103                 const struct dsdb_attribute *sa;
3104
3105                 /* work out what the new rdn value is, for updating the
3106                    rDN and name fields */
3107                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3108                 if (new_rdn_value == NULL) {
3109                         talloc_free(tmp_ctx);
3110                         return ldb_operr(ldb);
3111                 }
3112
3113                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3114                 if (!sa) {
3115                         talloc_free(tmp_ctx);
3116                         return LDB_ERR_OPERATIONS_ERROR;
3117                 }
3118
3119                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3120                                         &el);
3121                 if (ret != LDB_SUCCESS) {
3122                         talloc_free(tmp_ctx);
3123                         return ret;
3124                 }
3125                 el->flags = LDB_FLAG_MOD_REPLACE;
3126
3127                 el = ldb_msg_find_element(old_msg, "name");
3128                 if (el) {
3129                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3130                         if (ret != LDB_SUCCESS) {
3131                                 talloc_free(tmp_ctx);
3132                                 return ret;
3133                         }
3134                         el->flags = LDB_FLAG_MOD_REPLACE;
3135                 }
3136         }
3137
3138         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3139         if (ret != LDB_SUCCESS) {
3140                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3141                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3142                 talloc_free(tmp_ctx);
3143                 return ret;
3144         }
3145
3146         if (deletion_state == OBJECT_NOT_DELETED) {
3147                 /* now rename onto the new DN */
3148                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3149                 if (ret != LDB_SUCCESS){
3150                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3151                                  ldb_dn_get_linearized(old_dn),
3152                                  ldb_dn_get_linearized(new_dn),
3153                                  ldb_errstring(ldb)));
3154                         talloc_free(tmp_ctx);
3155                         return ret;
3156                 }
3157         }
3158
3159         talloc_free(tmp_ctx);
3160
3161         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3162 }
3163
3164
3165
3166 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3167 {
3168         return ret;
3169 }
3170
3171 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3172 {
3173         int ret = LDB_ERR_OTHER;
3174         /* TODO: do some error mapping */
3175         return ret;
3176 }
3177
3178
3179 static struct replPropertyMetaData1 *
3180 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3181                                         enum drsuapi_DsAttributeId attid)
3182 {
3183         uint32_t i;
3184         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3185
3186         for (i = 0; i < rpmd_ctr->count; i++) {
3187                 if (rpmd_ctr->array[i].attid == attid) {
3188                         return &rpmd_ctr->array[i];
3189                 }
3190         }
3191         return NULL;
3192 }
3193
3194
3195 /*
3196    return true if an update is newer than an existing entry
3197    see section 5.11 of MS-ADTS
3198 */
3199 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3200                                    const struct GUID *update_invocation_id,
3201                                    uint32_t current_version,
3202                                    uint32_t update_version,
3203                                    NTTIME current_change_time,
3204                                    NTTIME update_change_time)
3205 {
3206         if (update_version != current_version) {
3207                 return update_version > current_version;
3208         }
3209         if (update_change_time != current_change_time) {
3210                 return update_change_time > current_change_time;
3211         }
3212         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3213 }
3214
3215 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3216                                                   struct replPropertyMetaData1 *new_m)
3217 {
3218         return replmd_update_is_newer(&cur_m->originating_invocation_id,
3219                                       &new_m->originating_invocation_id,
3220                                       cur_m->version,
3221                                       new_m->version,
3222                                       cur_m->originating_change_time,
3223                                       new_m->originating_change_time);
3224 }
3225
3226
3227 /*
3228   form a conflict DN
3229  */
3230 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3231 {
3232         const struct ldb_val *rdn_val;
3233         const char *rdn_name;
3234         struct ldb_dn *new_dn;
3235
3236         rdn_val = ldb_dn_get_rdn_val(dn);
3237         rdn_name = ldb_dn_get_rdn_name(dn);
3238         if (!rdn_val || !rdn_name) {
3239                 return NULL;
3240         }
3241
3242         new_dn = ldb_dn_copy(mem_ctx, dn);
3243         if (!new_dn) {
3244                 return NULL;
3245         }
3246
3247         if (!ldb_dn_remove_child_components(new_dn, 1)) {
3248                 return NULL;
3249         }
3250
3251         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3252                                   rdn_name,
3253                                   ldb_dn_escape_value(new_dn, *rdn_val),
3254                                   GUID_string(new_dn, guid))) {
3255                 return NULL;
3256         }
3257
3258         return new_dn;
3259 }
3260
3261
3262 /*
3263   perform a modify operation which sets the rDN and name attributes to
3264   their current values. This has the effect of changing these
3265   attributes to have been last updated by the current DC. This is
3266   needed to ensure that renames performed as part of conflict
3267   resolution are propogated to other DCs
3268  */
3269 static int replmd_name_modify(struct replmd_replicated_request *ar,
3270                               struct ldb_request *req, struct ldb_dn *dn)
3271 {
3272         struct ldb_message *msg;
3273         const char *rdn_name;
3274         const struct ldb_val *rdn_val;
3275         const struct dsdb_attribute *rdn_attr;
3276         int ret;
3277
3278         msg = ldb_msg_new(req);
3279         if (msg == NULL) {
3280                 goto failed;
3281         }
3282         msg->dn = dn;
3283
3284         rdn_name = ldb_dn_get_rdn_name(dn);
3285         if (rdn_name == NULL) {
3286                 goto failed;
3287         }
3288
3289         /* normalize the rdn attribute name */
3290         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3291         if (rdn_attr == NULL) {
3292                 goto failed;
3293         }
3294         rdn_name = rdn_attr->lDAPDisplayName;
3295
3296         rdn_val = ldb_dn_get_rdn_val(dn);
3297         if (rdn_val == NULL) {
3298                 goto failed;
3299         }
3300
3301         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3302                 goto failed;
3303         }
3304         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3305                 goto failed;
3306         }
3307         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3308                 goto failed;
3309         }
3310         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3311                 goto failed;
3312         }
3313
3314         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3315         if (ret != LDB_SUCCESS) {
3316                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3317                          ldb_dn_get_linearized(dn),
3318                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3319                 return ret;
3320         }
3321
3322         talloc_free(msg);
3323
3324         return LDB_SUCCESS;
3325
3326 failed:
3327         talloc_free(msg);
3328         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3329                  ldb_dn_get_linearized(dn)));
3330         return LDB_ERR_OPERATIONS_ERROR;
3331 }
3332
3333
3334 /*
3335   callback for conflict DN handling where we have renamed the incoming
3336   record. After renaming it, we need to ensure the change of name and
3337   rDN for the incoming record is seen as an originating update by this DC.
3338
3339   This also handles updating lastKnownParent for entries sent to lostAndFound
3340  */
3341 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3342 {
3343         struct replmd_replicated_request *ar =
3344                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3345         struct ldb_dn *conflict_dn;
3346         int ret;
3347
3348         if (ares->error != LDB_SUCCESS) {
3349                 /* call the normal callback for everything except success */
3350                 return replmd_op_callback(req, ares);
3351         }
3352
3353         switch (req->operation) {
3354         case LDB_ADD:
3355                 conflict_dn = req->op.add.message->dn;
3356                 break;
3357         case LDB_MODIFY:
3358                 conflict_dn = req->op.mod.message->dn;
3359                 break;
3360         default:
3361                 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
3362         }
3363
3364         /* perform a modify of the rDN and name of the record */
3365         ret = replmd_name_modify(ar, req, conflict_dn);
3366         if (ret != LDB_SUCCESS) {
3367                 ares->error = ret;
3368                 return replmd_op_callback(req, ares);
3369         }
3370
3371         if (ar->objs->objects[ar->index_current].last_known_parent) {
3372                 struct ldb_message *msg = ldb_msg_new(req);
3373                 if (msg == NULL) {
3374                         ldb_module_oom(ar->module);
3375                         return LDB_ERR_OPERATIONS_ERROR;
3376                 }
3377
3378                 msg->dn = req->op.add.message->dn;
3379
3380                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3381                                                ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
3382                 if (ret != LDB_SUCCESS) {
3383                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
3384                         ldb_module_oom(ar->module);
3385                         return ret;
3386                 }
3387                 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
3388
3389                 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3390                 if (ret != LDB_SUCCESS) {
3391                         DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
3392                                  ldb_dn_get_linearized(msg->dn),
3393                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3394                         return ret;
3395                 }
3396                 TALLOC_FREE(msg);
3397         }
3398
3399         return replmd_op_callback(req, ares);
3400 }
3401
3402 /*
3403   callback for replmd_replicated_apply_add() and replmd_replicated_handle_rename()
3404   This copes with the creation of conflict records in the case where
3405   the DN exists, but with a different objectGUID
3406  */
3407 static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct ldb_reply *ares, int (*callback)(struct ldb_request *req, struct ldb_reply *ares))
3408 {
3409         struct ldb_dn *conflict_dn;
3410         struct replmd_replicated_request *ar =
3411                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3412         struct ldb_result *res;
3413         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3414         int ret;
3415         const struct ldb_val *omd_value;
3416         struct replPropertyMetaDataBlob omd, *rmd;
3417         enum ndr_err_code ndr_err;
3418         bool rename_incoming_record, rodc;
3419         struct replPropertyMetaData1 *rmd_name, *omd_name;
3420         struct ldb_message *msg;
3421
3422         req->callback = callback;
3423
3424         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3425                 /* call the normal callback for everything except
3426                    conflicts */
3427                 return ldb_module_done(req, ares->controls, ares->response, ares->error);
3428         }
3429
3430         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
3431         if (ret != LDB_SUCCESS) {
3432                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to determine if we are an RODC when attempting to form conflict DN: %s", ldb_errstring(ldb_module_get_ctx(ar->module)));
3433                 return ldb_module_done(req, ares->controls, ares->response, LDB_ERR_OPERATIONS_ERROR);
3434         }
3435         /*
3436          * we have a conflict, and need to decide if we will keep the
3437          * new record or the old record
3438          */
3439
3440         msg = ar->objs->objects[ar->index_current].msg;
3441
3442         switch (req->operation) {
3443         case LDB_ADD:
3444                 conflict_dn = msg->dn;
3445                 break;
3446         case LDB_RENAME:
3447                 conflict_dn = req->op.rename.newdn;
3448                 break;
3449         default:
3450                 return ldb_module_done(req, ares->controls, ares->response, ldb_module_operr(ar->module));
3451         }
3452
3453         if (rodc) {
3454                 /*
3455                  * We are on an RODC, or were a GC for this
3456                  * partition, so we have to fail this until
3457                  * someone who owns the partition sorts it
3458                  * out 
3459                  */
3460                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), 
3461                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
3462                                        " - We must fail the operation until a master for this partition resolves the conflict",
3463                                        ldb_dn_get_linearized(conflict_dn));
3464                 goto failed;
3465         }
3466
3467         /*
3468          * first we need the replPropertyMetaData attribute from the
3469          * old record
3470          */
3471         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3472                                     attrs,
3473                                     DSDB_FLAG_NEXT_MODULE |
3474                                     DSDB_SEARCH_SHOW_DELETED |
3475                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3476         if (ret != LDB_SUCCESS) {
3477                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3478                          ldb_dn_get_linearized(conflict_dn)));
3479                 goto failed;
3480         }
3481
3482         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3483         if (omd_value == NULL) {
3484                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3485                          ldb_dn_get_linearized(conflict_dn)));
3486                 goto failed;
3487         }
3488
3489         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3490                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3491         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3492                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3493                          ldb_dn_get_linearized(conflict_dn)));
3494                 goto failed;
3495         }
3496
3497         rmd = ar->objs->objects[ar->index_current].meta_data;
3498
3499         /* we decide which is newer based on the RPMD on the name
3500            attribute.  See [MS-DRSR] ResolveNameConflict */
3501         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3502         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3503         if (!rmd_name || !omd_name) {
3504                 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3505                          ldb_dn_get_linearized(conflict_dn)));
3506                 goto failed;
3507         }
3508
3509         rename_incoming_record = !(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) &&
3510                 !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3511
3512         if (rename_incoming_record) {
3513                 struct GUID guid;
3514                 struct ldb_dn *new_dn;
3515                 struct ldb_message *new_msg;
3516
3517                 /*
3518                  * We want to run the original callback here, which
3519                  * will return LDB_ERR_ENTRY_ALREADY_EXISTS to the
3520                  * caller, which will in turn know to rename the
3521                  * incoming record.  The error string is set in case
3522                  * this isn't handled properly at some point in the
3523                  * future.
3524                  */
3525                 if (req->operation == LDB_RENAME) {
3526                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
3527                                                "Unable to handle incoming renames where this would "
3528                                                "create a conflict. Incoming record is %s (caller to handle)\n",
3529                                                ldb_dn_get_extended_linearized(req, conflict_dn, 1));
3530
3531                         goto failed;
3532                 }
3533
3534                 guid = samdb_result_guid(msg, "objectGUID");
3535                 if (GUID_all_zero(&guid)) {
3536                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3537                                  ldb_dn_get_linearized(conflict_dn)));
3538                         goto failed;
3539                 }
3540                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3541                 if (new_dn == NULL) {
3542                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3543                                  ldb_dn_get_linearized(conflict_dn)));
3544                         goto failed;
3545                 }
3546
3547                 DEBUG(1,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3548                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3549
3550                 /* re-submit the request, but with a different
3551                    callback, so we don't loop forever. */
3552                 new_msg = ldb_msg_copy_shallow(req, msg);
3553                 if (!new_msg) {
3554                         goto failed;
3555                         DEBUG(0,(__location__ ": Failed to copy conflict DN message for %s\n",
3556                                  ldb_dn_get_linearized(conflict_dn)));
3557                 }
3558                 new_msg->dn = new_dn;
3559                 req->op.add.message = new_msg;
3560                 req->callback = replmd_op_name_modify_callback;
3561
3562                 return ldb_next_request(ar->module, req);
3563         } else {
3564                 /* we are renaming the existing record */
3565                 struct GUID guid;
3566                 struct ldb_dn *new_dn;
3567
3568                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3569                 if (GUID_all_zero(&guid)) {
3570                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3571                                  ldb_dn_get_linearized(conflict_dn)));
3572                         goto failed;
3573                 }
3574
3575                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3576                 if (new_dn == NULL) {
3577                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3578                                  ldb_dn_get_linearized(conflict_dn)));
3579                         goto failed;
3580                 }
3581
3582                 DEBUG(1,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
3583                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3584
3585                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3586                                          DSDB_FLAG_OWN_MODULE, req);
3587                 if (ret != LDB_SUCCESS) {
3588                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3589                                  ldb_dn_get_linearized(conflict_dn),
3590                                  ldb_dn_get_linearized(new_dn),
3591                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3592                         goto failed;
3593                 }
3594
3595                 /*
3596                  * now we need to ensure that the rename is seen as an
3597                  * originating update. We do that with a modify.
3598                  */
3599                 ret = replmd_name_modify(ar, req, new_dn);
3600                 if (ret != LDB_SUCCESS) {
3601                         goto failed;
3602                 }
3603
3604                 return ldb_next_request(ar->module, req);
3605         }
3606
3607 failed:
3608         /* on failure do the original callback. This means replication
3609          * will stop with an error, but there is not much else we can
3610          * do
3611          */
3612         return ldb_module_done(req, ares->controls, ares->response, ares->error);
3613 }
3614
3615 /*
3616   callback for replmd_replicated_apply_add()
3617   This copes with the creation of conflict records in the case where
3618   the DN exists, but with a different objectGUID
3619  */
3620 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3621 {
3622         struct replmd_replicated_request *ar =
3623                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3624
3625         if (ar->objs->objects[ar->index_current].last_known_parent) {
3626                 /* This is like a conflict DN, where we put the object in LostAndFound
3627                    see MS-DRSR 4.1.10.6.10 FindBestParentObject */
3628                 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
3629         }
3630
3631         return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
3632 }
3633
3634 /*
3635   callback for replmd_replicated_handle_rename()
3636   This copes with the creation of conflict records in the case where
3637   the DN exists, but with a different objectGUID
3638  */
3639 static int replmd_op_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3640 {
3641         return replmd_op_possible_conflict_callback(req, ares, ldb_modify_default_callback);
3642 }
3643
3644 /*
3645   this is called when a new object comes in over DRS
3646  */
3647 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3648 {
3649         struct ldb_context *ldb;
3650         struct ldb_request *change_req;
3651         enum ndr_err_code ndr_err;
3652         struct ldb_message *msg;
3653         struct replPropertyMetaDataBlob *md;
3654         struct ldb_val md_value;
3655         unsigned int i;
3656         int ret;
3657         bool remote_isDeleted = false;
3658
3659         /*
3660          * TODO: check if the parent object exist
3661          */
3662
3663         /*
3664          * TODO: handle the conflict case where an object with the
3665          *       same name exist
3666          */
3667
3668         ldb = ldb_module_get_ctx(ar->module);
3669         msg = ar->objs->objects[ar->index_current].msg;
3670         md = ar->objs->objects[ar->index_current].meta_data;
3671
3672         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3673         if (ret != LDB_SUCCESS) {
3674                 return replmd_replicated_request_error(ar, ret);
3675         }
3676
3677         ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
3678         if (ret != LDB_SUCCESS) {
3679                 return replmd_replicated_request_error(ar, ret);
3680         }
3681
3682         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3683         if (ret != LDB_SUCCESS) {
3684                 return replmd_replicated_request_error(ar, ret);
3685         }
3686
3687         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
3688         if (ret != LDB_SUCCESS) {
3689                 return replmd_replicated_request_error(ar, ret);
3690         }
3691
3692         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3693         if (ret != LDB_SUCCESS) {
3694                 return replmd_replicated_request_error(ar, ret);
3695         }
3696
3697         /* remove any message elements that have zero values */
3698         for (i=0; i<msg->num_elements; i++) {
3699                 struct ldb_message_element *el = &msg->elements[i];
3700
3701                 if (el->num_values == 0) {
3702                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
3703                                  el->name));
3704                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
3705                         msg->num_elements--;
3706                         i--;
3707                         continue;
3708                 }
3709         }
3710
3711         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
3712                                                      "isDeleted", false);
3713
3714         /*
3715          * the meta data array is already sorted by the caller
3716          */
3717         for (i=0; i < md->ctr.ctr1.count; i++) {
3718                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3719         }
3720         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3721                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3722         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3723                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3724                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3725         }
3726         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3727         if (ret != LDB_SUCCESS) {
3728                 return replmd_replicated_request_error(ar, ret);
3729         }
3730
3731         replmd_ldb_message_sort(msg, ar->schema);
3732
3733         if (!remote_isDeleted) {
3734                 ret = dsdb_module_schedule_sd_propagation(ar->module,
3735                                                           ar->objs->partition_dn,
3736                                                           msg->dn, true);
3737                 if (ret != LDB_SUCCESS) {
3738                         return replmd_replicated_request_error(ar, ret);
3739                 }
3740         }
3741
3742         if (DEBUGLVL(4)) {
3743                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3744                 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3745                 talloc_free(s);
3746         }
3747
3748         ret = ldb_build_add_req(&change_req,
3749                                 ldb,
3750                                 ar,
3751                                 msg,
3752                                 ar->controls,
3753                                 ar,
3754                                 replmd_op_add_callback,
3755                                 ar->req);
3756         LDB_REQ_SET_LOCATION(change_req);
3757         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3758
3759         /* current partition control needed by "repmd_op_callback" */
3760         ret = ldb_request_add_control(change_req,
3761                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3762                                       false, NULL);
3763         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3764
3765         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
3766                 /* this tells the partition module to make it a
3767                    partial replica if creating an NC */
3768                 ret = ldb_request_add_control(change_req,
3769                                               DSDB_CONTROL_PARTIAL_REPLICA,
3770                                               false, NULL);
3771                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3772         }
3773
3774         return ldb_next_request(ar->module, change_req);
3775 }
3776
3777 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
3778                                                               struct ldb_reply *ares)
3779 {
3780         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3781                                                struct replmd_replicated_request);
3782         int ret;
3783
3784         if (!ares) {
3785                 return ldb_module_done(ar->req, NULL, NULL,
3786                                         LDB_ERR_OPERATIONS_ERROR);
3787         }
3788         if (ares->error != LDB_SUCCESS &&
3789             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3790                 return ldb_module_done(ar->req, ares->controls,
3791                                         ares->response, ares->error);
3792         }
3793
3794         switch (ares->type) {
3795         case LDB_REPLY_ENTRY:
3796         {
3797                 struct ldb_message *parent_msg = ares->message;
3798                 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
3799                 struct ldb_dn *parent_dn;
3800                 int comp_num;
3801
3802                 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
3803                     && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
3804                         /* Per MS-DRSR 4.1.10.6.10
3805                          * FindBestParentObject we need to move this
3806                          * new object under a deleted object to
3807                          * lost-and-found */
3808                         struct ldb_dn *nc_root;
3809
3810                         ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
3811                         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
3812                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
3813                                                        "No suitable NC root found for %s.  "
3814                                                        "We need to move this object because parent object %s "
3815                                                        "is deleted, but this object is not.",
3816                                                        ldb_dn_get_linearized(msg->dn),
3817                                                        ldb_dn_get_linearized(parent_msg->dn));
3818                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
3819                         } else if (ret != LDB_SUCCESS) {
3820                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
3821                                                        "Unable to find NC root for %s: %s. "
3822                                                        "We need to move this object because parent object %s "
3823                                                        "is deleted, but this object is not.",
3824                                                        ldb_dn_get_linearized(msg->dn),
3825                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
3826                                                        ldb_dn_get_linearized(parent_msg->dn));
3827                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
3828                         }
3829                         
3830                         ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
3831                                                 nc_root,
3832                                                 DS_GUID_LOSTANDFOUND_CONTAINER,
3833                                                 &parent_dn);
3834                         if (ret != LDB_SUCCESS) {
3835                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
3836                                                        "Unable to find LostAndFound Container for %s "
3837                                                        "in partition %s: %s. "
3838                                                        "We need to move this object because parent object %s "
3839                                                        "is deleted, but this object is not.",
3840                                                        ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
3841                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
3842                                                        ldb_dn_get_linearized(parent_msg->dn));
3843                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
3844                         }
3845                         ar->objs->objects[ar->index_current].last_known_parent
3846                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
3847                 } else {
3848                         parent_dn = parent_msg->dn;
3849                 }
3850
3851                 comp_num = ldb_dn_get_comp_num(msg->dn);
3852                 if (comp_num > 1) {
3853                         if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
3854                                 talloc_free(ares);
3855                                 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
3856                         }
3857                 }
3858                 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
3859                         talloc_free(ares);
3860                         return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
3861                 }
3862                 break;
3863         }
3864         case LDB_REPLY_REFERRAL:
3865                 /* we ignore referrals */
3866                 break;
3867
3868         case LDB_REPLY_DONE:
3869                 ret = replmd_replicated_apply_add(ar);
3870                 if (ret != LDB_SUCCESS) {
3871                         return ldb_module_done(ar->req, NULL, NULL, ret);
3872                 }
3873         }
3874
3875         talloc_free(ares);
3876         return LDB_SUCCESS;
3877 }
3878
3879 /*
3880  * Look for the parent object, so we put the new object in the right place
3881  */
3882
3883 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
3884 {
3885         struct ldb_context *ldb;
3886         int ret;
3887         char *tmp_str;
3888         char *filter;
3889         struct ldb_request *search_req;
3890         static const char *attrs[] = {"isDeleted", NULL};
3891
3892         ldb = ldb_module_get_ctx(ar->module);
3893
3894         if (!ar->objs->objects[ar->index_current].parent_guid_value.data) {
3895                 return replmd_replicated_apply_add(ar);
3896         }
3897
3898         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].parent_guid_value);
3899         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3900
3901         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3902         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3903         talloc_free(tmp_str);
3904
3905         ret = ldb_build_search_req(&search_req,
3906                                    ldb,
3907                                    ar,
3908                                    ar->objs->partition_dn,
3909                                    LDB_SCOPE_SUBTREE,
3910                                    filter,
3911                                    attrs,
3912                                    NULL,
3913                                    ar,
3914                                    replmd_replicated_apply_search_for_parent_callback,
3915                                    ar->req);
3916         LDB_REQ_SET_LOCATION(search_req);
3917
3918         ret = dsdb_request_add_controls(search_req, 
3919                                         DSDB_SEARCH_SHOW_RECYCLED|
3920                                         DSDB_SEARCH_SHOW_DELETED|
3921                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
3922         if (ret != LDB_SUCCESS) {
3923                 return ret;
3924         }
3925
3926         return ldb_next_request(ar->module, search_req);
3927 }
3928
3929 /*
3930   handle renames that come in over DRS replication
3931  */
3932 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
3933                                            struct ldb_message *msg,
3934                                            struct replPropertyMetaDataBlob *rmd,
3935                                            struct replPropertyMetaDataBlob *omd,
3936                                            struct ldb_request *parent,
3937                                            bool *renamed)
3938 {
3939         struct replPropertyMetaData1 *md_remote;
3940         struct replPropertyMetaData1 *md_local;
3941
3942         *renamed = true;
3943
3944         if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3945                 /* no rename */
3946                 return LDB_SUCCESS;
3947         }
3948
3949         /* now we need to check for double renames. We could have a
3950          * local rename pending which our replication partner hasn't
3951          * received yet. We choose which one wins by looking at the
3952          * attribute stamps on the two objects, the newer one wins
3953          */
3954         md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3955         md_local  = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3956         /* if there is no name attribute then we have to assume the
3957            object we've received is in fact newer */
3958         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING ||
3959             !md_remote || !md_local ||
3960             replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3961                 struct ldb_request *req;
3962                 int ret;
3963                 TALLOC_CTX *tmp_ctx = talloc_new(msg);
3964                 struct ldb_result *res;
3965
3966                 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3967                          ldb_dn_get_linearized(ar->search_msg->dn),
3968                          ldb_dn_get_linearized(msg->dn)));
3969
3970
3971                 res = talloc_zero(tmp_ctx, struct ldb_result);
3972                 if (!res) {
3973                         talloc_free(tmp_ctx);
3974                         return ldb_oom(ldb_module_get_ctx(ar->module));
3975                 }
3976
3977                 /* pass rename to the next module
3978                  * so it doesn't appear as an originating update */
3979                 ret = ldb_build_rename_req(&req, ldb_module_get_ctx(ar->module), tmp_ctx,
3980                                            ar->search_msg->dn, msg->dn,
3981                                            NULL,
3982                                            ar,
3983                                            replmd_op_rename_callback,
3984                                            parent);
3985                 LDB_REQ_SET_LOCATION(req);
3986                 if (ret != LDB_SUCCESS) {
3987                         talloc_free(tmp_ctx);
3988                         return ret;
3989                 }
3990
3991                 ret = dsdb_request_add_controls(req, DSDB_MODIFY_RELAX);
3992                 if (ret != LDB_SUCCESS) {
3993                         talloc_free(tmp_ctx);
3994                         return ret;
3995                 }
3996
3997                 ret = ldb_next_request(ar->module, req);
3998
3999                 if (ret == LDB_SUCCESS) {
4000                         ret = ldb_wait(req->handle, LDB_WAIT_ALL);
4001                 }
4002
4003                 talloc_free(tmp_ctx);
4004                 return ret;
4005         }
4006
4007         /* we're going to keep our old object */
4008         DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
4009                  ldb_dn_get_linearized(ar->search_msg->dn),
4010                  ldb_dn_get_linearized(msg->dn)));
4011         return LDB_SUCCESS;
4012 }
4013
4014
4015 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
4016 {
4017         struct ldb_context *ldb;
4018         struct ldb_request *change_req;
4019         enum ndr_err_code ndr_err;
4020         struct ldb_message *msg;
4021         struct replPropertyMetaDataBlob *rmd;
4022         struct replPropertyMetaDataBlob omd;
4023         const struct ldb_val *omd_value;
4024         struct replPropertyMetaDataBlob nmd;
4025         struct ldb_val nmd_value;
4026         unsigned int i;
4027         uint32_t j,ni=0;
4028         unsigned int removed_attrs = 0;
4029         int ret;
4030         int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
4031         bool isDeleted = false;
4032         bool local_isDeleted = false;
4033         bool remote_isDeleted = false;
4034         bool take_remote_isDeleted = false;
4035         bool sd_updated = false;
4036         bool renamed = false;
4037
4038         ldb = ldb_module_get_ctx(ar->module);
4039         msg = ar->objs->objects[ar->index_current].msg;
4040
4041         rmd = ar->objs->objects[ar->index_current].meta_data;
4042         ZERO_STRUCT(omd);
4043         omd.version = 1;
4044
4045         /* find existing meta data */
4046         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
4047         if (omd_value) {
4048                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
4049                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4050                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4051                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4052                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4053                 }
4054
4055                 if (omd.version != 1) {
4056                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4057                 }
4058         }
4059
4060         local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
4061                                                     "isDeleted", false);
4062         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4063                                                      "isDeleted", false);
4064
4065         /* handle renames that come in over DRS */
4066         ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd,
4067                                               ar->req, &renamed);
4068
4069         /*
4070          * This particular error code means that we already tried the
4071          * conflict algrorithm, and the existing record name was newer, so we
4072          * need to rename the incoming record
4073          */
4074         if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
4075                 struct GUID guid;
4076                 NTSTATUS status;
4077                 struct ldb_dn *new_dn;
4078                 status = GUID_from_ndr_blob(&ar->objs->objects[ar->index_current].guid_value, &guid);
4079                 /* This really, really can't fail */
4080                 SMB_ASSERT(NT_STATUS_IS_OK(status));
4081
4082                 new_dn = replmd_conflict_dn(msg, msg->dn, &guid);
4083                 if (new_dn == NULL) {
4084                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4085                                                                   "Failed to form conflict DN for %s\n",
4086                                                                   ldb_dn_get_linearized(msg->dn));
4087
4088                         return replmd_replicated_request_werror(ar, WERR_NOMEM);
4089                 }
4090
4091                 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
4092                                          DSDB_FLAG_NEXT_MODULE, ar->req);
4093                 if (ret != LDB_SUCCESS) {
4094                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4095                                                "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
4096                                                ldb_dn_get_linearized(msg->dn),
4097                                                ldb_dn_get_linearized(ar->search_msg->dn),
4098                                                ldb_dn_get_linearized(new_dn),
4099                                                ldb_errstring(ldb_module_get_ctx(ar->module)));
4100                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4101                 }
4102
4103                 /* Set the callback to one that will fix up the name to be a conflict DN */
4104                 callback = replmd_op_name_modify_callback;
4105                 msg->dn = new_dn;
4106                 renamed = true;
4107         } else if (ret != LDB_SUCCESS) {
4108                 ldb_debug(ldb, LDB_DEBUG_FATAL,
4109                           "replmd_replicated_request rename %s => %s failed - %s\n",
4110                           ldb_dn_get_linearized(ar->search_msg->dn),
4111                           ldb_dn_get_linearized(msg->dn),
4112                           ldb_errstring(ldb));
4113                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4114         }
4115
4116         ZERO_STRUCT(nmd);
4117         nmd.version = 1;
4118         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
4119         nmd.ctr.ctr1.array = talloc_array(ar,
4120                                           struct replPropertyMetaData1,
4121                                           nmd.ctr.ctr1.count);
4122         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4123
4124         /* first copy the old meta data */
4125         for (i=0; i < omd.ctr.ctr1.count; i++) {
4126                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
4127                 ni++;
4128         }
4129
4130         ar->seq_num = 0;
4131         /* now merge in the new meta data */
4132         for (i=0; i < rmd->ctr.ctr1.count; i++) {
4133                 bool found = false;
4134
4135                 for (j=0; j < ni; j++) {
4136                         bool cmp;
4137
4138                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
4139                                 continue;
4140                         }
4141
4142                         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4143                                 /* if we compare equal then do an
4144                                    update. This is used when a client
4145                                    asks for a FULL_SYNC, and can be
4146                                    used to recover a corrupt
4147                                    replica */
4148                                 cmp = !replmd_replPropertyMetaData1_is_newer(&rmd->ctr.ctr1.array[i],
4149                                                                              &nmd.ctr.ctr1.array[j]);
4150                         } else {
4151                                 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
4152                                                                             &rmd->ctr.ctr1.array[i]);
4153                         }
4154                         if (cmp) {
4155                                 /* replace the entry */
4156                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
4157                                 if (ar->seq_num == 0) {
4158                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4159                                         if (ret != LDB_SUCCESS) {
4160                                                 return replmd_replicated_request_error(ar, ret);
4161                                         }
4162                                 }
4163                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
4164                                 switch (nmd.ctr.ctr1.array[j].attid) {
4165                                 case DRSUAPI_ATTID_ntSecurityDescriptor:
4166                                         sd_updated = true;
4167                                         break;
4168                                 case DRSUAPI_ATTID_isDeleted:
4169                                         take_remote_isDeleted = true;
4170                                         break;
4171                                 default:
4172                                         break;
4173                                 }
4174                                 found = true;
4175                                 break;
4176                         }
4177
4178                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
4179                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
4180                                          msg->elements[i-removed_attrs].name,
4181                                          ldb_dn_get_linearized(msg->dn),
4182                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
4183                         }
4184
4185                         /* we don't want to apply this change so remove the attribute */
4186                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
4187                         removed_attrs++;
4188
4189                         found = true;
4190                         break;
4191                 }
4192
4193                 if (found) continue;
4194
4195                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
4196                 if (ar->seq_num == 0) {
4197                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4198                         if (ret != LDB_SUCCESS) {
4199                                 return replmd_replicated_request_error(ar, ret);
4200                         }
4201                 }
4202                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
4203                 switch (nmd.ctr.ctr1.array[ni].attid) {
4204                 case DRSUAPI_ATTID_ntSecurityDescriptor:
4205                         sd_updated = true;
4206                         break;
4207                 case DRSUAPI_ATTID_isDeleted:
4208                         take_remote_isDeleted = true;
4209                         break;
4210                 default:
4211                         break;
4212                 }
4213                 ni++;
4214         }
4215
4216         /*
4217          * finally correct the size of the meta_data array
4218          */
4219         nmd.ctr.ctr1.count = ni;
4220
4221         /*
4222          * the rdn attribute (the alias for the name attribute),
4223          * 'cn' for most objects is the last entry in the meta data array
4224          * we have stored
4225          *
4226          * sort the new meta data array
4227          */
4228         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
4229         if (ret != LDB_SUCCESS) {
4230                 return ret;
4231         }
4232
4233         /*
4234          * check if some replicated attributes left, otherwise skip the ldb_modify() call
4235          */
4236         if (msg->num_elements == 0) {
4237                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
4238                           ar->index_current);
4239
4240                 ar->index_current++;
4241                 return replmd_replicated_apply_next(ar);
4242         }
4243
4244         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
4245                   ar->index_current, msg->num_elements);
4246
4247         if (take_remote_isDeleted) {
4248                 isDeleted = remote_isDeleted;
4249         } else {
4250                 isDeleted = local_isDeleted;
4251         }
4252
4253         if (renamed) {
4254                 sd_updated = true;
4255         }
4256
4257         if (sd_updated && !isDeleted) {
4258                 ret = dsdb_module_schedule_sd_propagation(ar->module,
4259                                                           ar->objs->partition_dn,
4260                                                           msg->dn, true);
4261                 if (ret != LDB_SUCCESS) {
4262                         return ldb_operr(ldb);
4263                 }
4264         }
4265
4266         /* create the meta data value */
4267         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
4268                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4269         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4270                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4271                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4272         }
4273
4274         /*
4275          * when we know that we'll modify the record, add the whenChanged, uSNChanged
4276          * and replPopertyMetaData attributes
4277          */
4278         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4279         if (ret != LDB_SUCCESS) {
4280                 return replmd_replicated_request_error(ar, ret);
4281         }
4282         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4283         if (ret != LDB_SUCCESS) {
4284                 return replmd_replicated_request_error(ar, ret);
4285         }
4286         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
4287         if (ret != LDB_SUCCESS) {
4288                 return replmd_replicated_request_error(ar, ret);
4289         }
4290
4291         replmd_ldb_message_sort(msg, ar->schema);
4292
4293         /* we want to replace the old values */
4294         for (i=0; i < msg->num_elements; i++) {
4295                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4296         }
4297
4298         if (DEBUGLVL(4)) {
4299                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4300                 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
4301                 talloc_free(s);
4302         }
4303
4304         ret = ldb_build_mod_req(&change_req,
4305                                 ldb,
4306                                 ar,
4307                                 msg,
4308                                 ar->controls,
4309                                 ar,
4310                                 callback,
4311                                 ar->req);
4312         LDB_REQ_SET_LOCATION(change_req);
4313         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4314
4315         /* current partition control needed by "repmd_op_callback" */
4316         ret = ldb_request_add_control(change_req,
4317                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4318                                       false, NULL);
4319         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4320
4321         return ldb_next_request(ar->module, change_req);
4322 }
4323
4324 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
4325                                                    struct ldb_reply *ares)
4326 {
4327         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4328                                                struct replmd_replicated_request);
4329         int ret;
4330
4331         if (!ares) {
4332                 return ldb_module_done(ar->req, NULL, NULL,
4333                                         LDB_ERR_OPERATIONS_ERROR);
4334         }
4335         if (ares->error != LDB_SUCCESS &&
4336             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4337                 return ldb_module_done(ar->req, ares->controls,
4338                                         ares->response, ares->error);
4339         }
4340
4341         switch (ares->type) {
4342         case LDB_REPLY_ENTRY:
4343                 ar->search_msg = talloc_steal(ar, ares->message);
4344                 break;
4345
4346         case LDB_REPLY_REFERRAL:
4347                 /* we ignore referrals */
4348                 break;
4349
4350         case LDB_REPLY_DONE:
4351                 ar->objs->objects[ar->index_current].last_known_parent = NULL;
4352
4353                 if (ar->search_msg != NULL) {
4354                         ret = replmd_replicated_apply_merge(ar);
4355                 } else {
4356                         ret = replmd_replicated_apply_search_for_parent(ar);
4357                 }
4358                 if (ret != LDB_SUCCESS) {
4359                         return ldb_module_done(ar->req, NULL, NULL, ret);
4360                 }
4361         }
4362
4363         talloc_free(ares);
4364         return LDB_SUCCESS;
4365 }
4366
4367 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
4368
4369 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
4370 {
4371         struct ldb_context *ldb;
4372         int ret;
4373         char *tmp_str;
4374         char *filter;
4375         struct ldb_request *search_req;
4376         struct ldb_search_options_control *options;
4377
4378         if (ar->index_current >= ar->objs->num_objects) {
4379                 /* done with it, go to next stage */
4380                 return replmd_replicated_uptodate_vector(ar);
4381         }
4382
4383         ldb = ldb_module_get_ctx(ar->module);
4384         ar->search_msg = NULL;
4385
4386         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
4387         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4388
4389         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4390         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4391         talloc_free(tmp_str);
4392
4393         ret = ldb_build_search_req(&search_req,
4394                                    ldb,
4395                                    ar,
4396                                    NULL,
4397                                    LDB_SCOPE_SUBTREE,
4398                                    filter,
4399                                    NULL,
4400                                    NULL,
4401                                    ar,
4402                                    replmd_replicated_apply_search_callback,
4403                                    ar->req);
4404         LDB_REQ_SET_LOCATION(search_req);
4405
4406         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
4407                                       true, NULL);
4408         if (ret != LDB_SUCCESS) {
4409                 return ret;
4410         }
4411
4412         /* we need to cope with cross-partition links, so search for
4413            the GUID over all partitions */
4414         options = talloc(search_req, struct ldb_search_options_control);
4415         if (options == NULL) {
4416                 DEBUG(0, (__location__ ": out of memory\n"));
4417                 return LDB_ERR_OPERATIONS_ERROR;
4418         }
4419         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
4420
4421         ret = ldb_request_add_control(search_req,
4422                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
4423                                       true, options);
4424         if (ret != LDB_SUCCESS) {
4425                 return ret;
4426         }
4427
4428         return ldb_next_request(ar->module, search_req);
4429 }
4430
4431 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
4432                                                       struct ldb_reply *ares)
4433 {
4434         struct ldb_context *ldb;
4435         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4436                                                struct replmd_replicated_request);
4437         ldb = ldb_module_get_ctx(ar->module);
4438
4439         if (!ares) {
4440                 return ldb_module_done(ar->req, NULL, NULL,
4441                                         LDB_ERR_OPERATIONS_ERROR);
4442         }
4443         if (ares->error != LDB_SUCCESS) {
4444                 return ldb_module_done(ar->req, ares->controls,
4445                                         ares->response, ares->error);
4446         }
4447
4448         if (ares->type != LDB_REPLY_DONE) {
4449                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
4450                 return ldb_module_done(ar->req, NULL, NULL,
4451                                         LDB_ERR_OPERATIONS_ERROR);
4452         }
4453
4454         talloc_free(ares);
4455
4456         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4457 }
4458
4459 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
4460 {
4461         struct ldb_context *ldb;
4462         struct ldb_request *change_req;
4463         enum ndr_err_code ndr_err;
4464         struct ldb_message *msg;
4465         struct replUpToDateVectorBlob ouv;
4466         const struct ldb_val *ouv_value;
4467         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
4468         struct replUpToDateVectorBlob nuv;
4469         struct ldb_val nuv_value;
4470         struct ldb_message_element *nuv_el = NULL;
4471         const struct GUID *our_invocation_id;
4472         struct ldb_message_element *orf_el = NULL;
4473         struct repsFromToBlob nrf;
4474         struct ldb_val *nrf_value = NULL;
4475         struct ldb_message_element *nrf_el = NULL;
4476         unsigned int i;
4477         uint32_t j,ni=0;
4478         bool found = false;
4479         time_t t = time(NULL);
4480         NTTIME now;
4481         int ret;
4482         uint32_t instanceType;
4483
4484         ldb = ldb_module_get_ctx(ar->module);
4485         ruv = ar->objs->uptodateness_vector;
4486         ZERO_STRUCT(ouv);
4487         ouv.version = 2;
4488         ZERO_STRUCT(nuv);
4489         nuv.version = 2;
4490
4491         unix_to_nt_time(&now, t);
4492
4493         if (ar->search_msg == NULL) {
4494                 /* this happens for a REPL_OBJ call where we are
4495                    creating the target object by replicating it. The
4496                    subdomain join code does this for the partition DN
4497                 */
4498                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
4499                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4500         }
4501
4502         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
4503         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
4504                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
4505                          ldb_dn_get_linearized(ar->search_msg->dn)));
4506                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4507         }
4508
4509         /*
4510          * first create the new replUpToDateVector
4511          */
4512         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
4513         if (ouv_value) {
4514                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
4515                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4516                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4517                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4518                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4519                 }
4520
4521                 if (ouv.version != 2) {
4522                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4523                 }
4524         }
4525
4526         /*
4527          * the new uptodateness vector will at least
4528          * contain 1 entry, one for the source_dsa
4529          *
4530          * plus optional values from our old vector and the one from the source_dsa
4531          */
4532         nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
4533         if (ruv) nuv.ctr.ctr2.count += ruv->count;
4534         nuv.ctr.ctr2.cursors = talloc_array(ar,
4535                                             struct drsuapi_DsReplicaCursor2,
4536                                             nuv.ctr.ctr2.count);
4537         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4538
4539         /* first copy the old vector */
4540         for (i=0; i < ouv.ctr.ctr2.count; i++) {
4541                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
4542                 ni++;
4543         }
4544
4545         /* get our invocation_id if we have one already attached to the ldb */
4546         our_invocation_id = samdb_ntds_invocation_id(ldb);
4547
4548         /* merge in the source_dsa vector is available */
4549         for (i=0; (ruv && i < ruv->count); i++) {
4550                 found = false;
4551
4552                 if (our_invocation_id &&
4553                     GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4554                                our_invocation_id)) {
4555                         continue;
4556                 }
4557
4558                 for (j=0; j < ni; j++) {
4559                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4560                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4561                                 continue;
4562                         }
4563
4564                         found = true;
4565
4566                         /*
4567                          * we update only the highest_usn and not the latest_sync_success time,
4568                          * because the last success stands for direct replication
4569                          */
4570                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
4571                                 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
4572                         }
4573                         break;
4574                 }
4575
4576                 if (found) continue;
4577
4578                 /* if it's not there yet, add it */
4579                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
4580                 ni++;
4581         }
4582
4583         /*
4584          * merge in the current highwatermark for the source_dsa
4585          */
4586         found = false;
4587         for (j=0; j < ni; j++) {
4588                 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
4589                                 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4590                         continue;
4591                 }
4592
4593                 found = true;
4594
4595                 /*
4596                  * here we update the highest_usn and last_sync_success time
4597                  * because we're directly replicating from the source_dsa
4598                  *
4599                  * and use the tmp_highest_usn because this is what we have just applied
4600                  * to our ldb
4601                  */
4602                 nuv.ctr.ctr2.cursors[j].highest_usn             = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4603                 nuv.ctr.ctr2.cursors[j].last_sync_success       = now;
4604                 break;
4605         }
4606         if (!found) {
4607                 /*
4608                  * here we update the highest_usn and last_sync_success time
4609                  * because we're directly replicating from the source_dsa
4610                  *
4611                  * and use the tmp_highest_usn because this is what we have just applied
4612                  * to our ldb
4613                  */
4614                 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
4615                 nuv.ctr.ctr2.cursors[ni].highest_usn            = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4616                 nuv.ctr.ctr2.cursors[ni].last_sync_success      = now;
4617                 ni++;
4618         }
4619
4620         /*
4621          * finally correct the size of the cursors array
4622          */
4623         nuv.ctr.ctr2.count = ni;
4624
4625         /*
4626          * sort the cursors
4627          */
4628         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
4629
4630         /*
4631          * create the change ldb_message
4632          */
4633         msg = ldb_msg_new(ar);
4634         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4635         msg->dn = ar->search_msg->dn;
4636
4637         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
4638                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
4639         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4640                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4641                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4642         }
4643         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
4644         if (ret != LDB_SUCCESS) {
4645                 return replmd_replicated_request_error(ar, ret);
4646         }
4647         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
4648
4649         /*
4650          * now create the new repsFrom value from the given repsFromTo1 structure
4651          */
4652         ZERO_STRUCT(nrf);
4653         nrf.version                                     = 1;
4654         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
4655         nrf.ctr.ctr1.highwatermark.highest_usn          = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
4656
4657         /*
4658          * first see if we already have a repsFrom value for the current source dsa
4659          * if so we'll later replace this value
4660          */
4661         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
4662         if (orf_el) {
4663                 for (i=0; i < orf_el->num_values; i++) {
4664                         struct repsFromToBlob *trf;
4665
4666                         trf = talloc(ar, struct repsFromToBlob);
4667                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4668
4669                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
4670                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
4671                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4672                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4673                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4674                         }
4675
4676                         if (trf->version != 1) {
4677                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4678                         }
4679
4680                         /*
4681                          * we compare the source dsa objectGUID not the invocation_id
4682                          * because we want only one repsFrom value per source dsa
4683                          * and when the invocation_id of the source dsa has changed we don't need
4684                          * the old repsFrom with the old invocation_id
4685                          */
4686                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
4687                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
4688                                 talloc_free(trf);
4689                                 continue;
4690                         }
4691
4692                         talloc_free(trf);
4693                         nrf_value = &orf_el->values[i];
4694                         break;
4695                 }
4696
4697                 /*
4698                  * copy over all old values to the new ldb_message
4699                  */
4700                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
4701                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4702                 *nrf_el = *orf_el;
4703         }
4704
4705         /*
4706          * if we haven't found an old repsFrom value for the current source dsa
4707          * we'll add a new value
4708          */
4709         if (!nrf_value) {
4710                 struct ldb_val zero_value;
4711                 ZERO_STRUCT(zero_value);
4712                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
4713                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4714
4715                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
4716         }
4717
4718         /* we now fill the value which is already attached to ldb_message */
4719         ndr_err = ndr_push_struct_blob(nrf_value, msg,
4720                                        &nrf,
4721                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
4722         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4723                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4724                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4725         }
4726
4727         /*
4728          * the ldb_message_element for the attribute, has all the old values and the new one
4729          * so we'll replace the whole attribute with all values
4730          */
4731         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
4732
4733         if (CHECK_DEBUGLVL(4)) {
4734                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4735                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
4736                 talloc_free(s);
4737         }
4738
4739         /* prepare the ldb_modify() request */
4740         ret = ldb_build_mod_req(&change_req,
4741                                 ldb,
4742                                 ar,
4743                                 msg,
4744                                 ar->controls,
4745                                 ar,
4746                                 replmd_replicated_uptodate_modify_callback,
4747                                 ar->req);
4748         LDB_REQ_SET_LOCATION(change_req);
4749         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4750
4751         return ldb_next_request(ar->module, change_req);
4752 }
4753
4754 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
4755                                                       struct ldb_reply *ares)
4756 {
4757         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4758                                                struct replmd_replicated_request);
4759         int ret;
4760
4761         if (!ares) {
4762                 return ldb_module_done(ar->req, NULL, NULL,
4763                                         LDB_ERR_OPERATIONS_ERROR);
4764         }
4765         if (ares->error != LDB_SUCCESS &&
4766             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4767                 return ldb_module_done(ar->req, ares->controls,
4768                                         ares->response, ares->error);
4769         }
4770
4771         switch (ares->type) {
4772         case LDB_REPLY_ENTRY:
4773                 ar->search_msg = talloc_steal(ar, ares->message);
4774                 break;
4775
4776         case LDB_REPLY_REFERRAL:
4777                 /* we ignore referrals */
4778                 break;
4779
4780         case LDB_REPLY_DONE:
4781                 ret = replmd_replicated_uptodate_modify(ar);
4782                 if (ret != LDB_SUCCESS) {
4783                         return ldb_module_done(ar->req, NULL, NULL, ret);
4784                 }
4785         }
4786
4787         talloc_free(ares);
4788         return LDB_SUCCESS;
4789 }
4790
4791
4792 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
4793 {
4794         struct ldb_context *ldb;
4795         int ret;
4796         static const char *attrs[] = {
4797                 "replUpToDateVector",
4798                 "repsFrom",
4799                 "instanceType",
4800                 NULL
4801         };
4802         struct ldb_request *search_req;
4803
4804         ldb = ldb_module_get_ctx(ar->module);
4805         ar->search_msg = NULL;
4806
4807         ret = ldb_build_search_req(&search_req,
4808                                    ldb,
4809                                    ar,
4810                                    ar->objs->partition_dn,
4811                                    LDB_SCOPE_BASE,
4812                                    "(objectClass=*)",
4813                                    attrs,
4814                                    NULL,
4815                                    ar,
4816                                    replmd_replicated_uptodate_search_callback,
4817                                    ar->req);
4818         LDB_REQ_SET_LOCATION(search_req);
4819         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4820
4821         return ldb_next_request(ar->module, search_req);
4822 }
4823
4824
4825
4826 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
4827 {
4828         struct ldb_context *ldb;
4829         struct dsdb_extended_replicated_objects *objs;
4830         struct replmd_replicated_request *ar;
4831         struct ldb_control **ctrls;
4832         int ret;
4833         uint32_t i;
4834         struct replmd_private *replmd_private =
4835                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4836         struct dsdb_control_replicated_update *rep_update;
4837
4838         ldb = ldb_module_get_ctx(module);
4839
4840         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
4841
4842         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
4843         if (!objs) {
4844                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
4845                 return LDB_ERR_PROTOCOL_ERROR;
4846         }
4847
4848         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
4849                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
4850                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
4851                 return LDB_ERR_PROTOCOL_ERROR;
4852         }
4853
4854         ar = replmd_ctx_init(module, req);
4855         if (!ar)
4856                 return LDB_ERR_OPERATIONS_ERROR;
4857
4858         /* Set the flags to have the replmd_op_callback run over the full set of objects */
4859         ar->apply_mode = true;
4860         ar->objs = objs;
4861         ar->schema = dsdb_get_schema(ldb, ar);
4862         if (!ar->schema) {
4863                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
4864                 talloc_free(ar);
4865                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4866                 return LDB_ERR_CONSTRAINT_VIOLATION;
4867         }
4868
4869         ctrls = req->controls;
4870
4871         if (req->controls) {
4872                 req->controls = talloc_memdup(ar, req->controls,
4873                                               talloc_get_size(req->controls));
4874                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4875         }
4876
4877         /* This allows layers further down to know if a change came in
4878            over replication and what the replication flags were */
4879         rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
4880         if (rep_update == NULL) {
4881                 return ldb_module_oom(module);
4882         }
4883         rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
4884
4885         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
4886         if (ret != LDB_SUCCESS) {
4887                 return ret;
4888         }
4889
4890         /* If this change contained linked attributes in the body
4891          * (rather than in the links section) we need to update
4892          * backlinks in linked_attributes */
4893         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
4894         if (ret != LDB_SUCCESS) {
4895                 return ret;
4896         }
4897
4898         ar->controls = req->controls;
4899         req->controls = ctrls;
4900
4901         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
4902
4903         /* save away the linked attributes for the end of the
4904            transaction */
4905         for (i=0; i<ar->objs->linked_attributes_count; i++) {
4906                 struct la_entry *la_entry;
4907
4908                 if (replmd_private->la_ctx == NULL) {
4909                         replmd_private->la_ctx = talloc_new(replmd_private);
4910                 }
4911                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
4912                 if (la_entry == NULL) {
4913                         ldb_oom(ldb);
4914                         return LDB_ERR_OPERATIONS_ERROR;
4915                 }
4916                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
4917                 if (la_entry->la == NULL) {
4918                         talloc_free(la_entry);
4919                         ldb_oom(ldb);
4920                         return LDB_ERR_OPERATIONS_ERROR;
4921                 }
4922                 *la_entry->la = ar->objs->linked_attributes[i];
4923
4924                 /* we need to steal the non-scalars so they stay
4925                    around until the end of the transaction */
4926                 talloc_steal(la_entry->la, la_entry->la->identifier);
4927                 talloc_steal(la_entry->la, la_entry->la->value.blob);
4928
4929                 DLIST_ADD(replmd_private->la_list, la_entry);
4930         }
4931
4932         return replmd_replicated_apply_next(ar);
4933 }
4934
4935 /*
4936   process one linked attribute structure
4937  */
4938 static int replmd_process_linked_attribute(struct ldb_module *module,
4939                                            struct la_entry *la_entry,
4940                                            struct ldb_request *parent)
4941 {
4942         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
4943         struct ldb_context *ldb = ldb_module_get_ctx(module);
4944         struct ldb_message *msg;
4945         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
4946         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
4947         int ret;
4948         const struct dsdb_attribute *attr;
4949         struct dsdb_dn *dsdb_dn;
4950         uint64_t seq_num = 0;
4951         struct ldb_message_element *old_el;
4952         WERROR status;
4953         time_t t = time(NULL);
4954         struct ldb_result *res;
4955         const char *attrs[2];
4956         struct parsed_dn *pdn_list, *pdn;
4957         struct GUID guid = GUID_zero();
4958         NTSTATUS ntstatus;
4959         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
4960         const struct GUID *our_invocation_id;
4961
4962 /*
4963 linked_attributes[0]:
4964      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
4965         identifier               : *
4966             identifier: struct drsuapi_DsReplicaObjectIdentifier
4967                 __ndr_size               : 0x0000003a (58)
4968                 __ndr_size_sid           : 0x00000000 (0)
4969                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
4970                 sid                      : S-0-0
4971                 __ndr_size_dn            : 0x00000000 (0)
4972                 dn                       : ''
4973         attid                    : DRSUAPI_ATTID_member (0x1F)
4974         value: struct drsuapi_DsAttributeValue
4975             __ndr_size               : 0x0000007e (126)
4976             blob                     : *
4977                 blob                     : DATA_BLOB length=126
4978         flags                    : 0x00000001 (1)
4979                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
4980         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
4981         meta_data: struct drsuapi_DsReplicaMetaData
4982             version                  : 0x00000015 (21)
4983             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
4984             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
4985             originating_usn          : 0x000000000001e19c (123292)
4986
4987 (for cases where the link is to a normal DN)
4988      &target: struct drsuapi_DsReplicaObjectIdentifier3
4989         __ndr_size               : 0x0000007e (126)
4990         __ndr_size_sid           : 0x0000001c (28)
4991         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
4992         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
4993         __ndr_size_dn            : 0x00000022 (34)
4994         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
4995  */
4996
4997         /* find the attribute being modified */
4998         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
4999         if (attr == NULL) {
5000                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
5001                 talloc_free(tmp_ctx);
5002                 return LDB_ERR_OPERATIONS_ERROR;
5003         }
5004
5005         attrs[0] = attr->lDAPDisplayName;
5006         attrs[1] = NULL;
5007
5008         /* get the existing message from the db for the object with
5009            this GUID, returning attribute being modified. We will then
5010            use this msg as the basis for a modify call */
5011         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
5012                                  DSDB_FLAG_NEXT_MODULE |
5013                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5014                                  DSDB_SEARCH_SHOW_RECYCLED |
5015                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
5016                                  DSDB_SEARCH_REVEAL_INTERNALS,
5017                                  parent,
5018                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
5019         if (ret != LDB_SUCCESS) {
5020                 talloc_free(tmp_ctx);
5021                 return ret;
5022         }
5023         if (res->count != 1) {
5024                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
5025                                        GUID_string(tmp_ctx, &la->identifier->guid));
5026                 talloc_free(tmp_ctx);
5027                 return LDB_ERR_NO_SUCH_OBJECT;
5028         }
5029         msg = res->msgs[0];
5030
5031         if (msg->num_elements == 0) {
5032                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
5033                 if (ret != LDB_SUCCESS) {
5034                         ldb_module_oom(module);
5035                         talloc_free(tmp_ctx);
5036                         return LDB_ERR_OPERATIONS_ERROR;
5037                 }
5038         } else {
5039                 old_el = &msg->elements[0];
5040                 old_el->flags = LDB_FLAG_MOD_REPLACE;
5041         }
5042
5043         /* parse the existing links */
5044         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
5045         if (ret != LDB_SUCCESS) {
5046                 talloc_free(tmp_ctx);
5047                 return ret;
5048         }
5049
5050         /* get our invocationId */
5051         our_invocation_id = samdb_ntds_invocation_id(ldb);
5052         if (!our_invocation_id) {
5053                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
5054                 talloc_free(tmp_ctx);
5055                 return LDB_ERR_OPERATIONS_ERROR;
5056         }
5057
5058         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
5059         if (ret != LDB_SUCCESS) {
5060                 talloc_free(tmp_ctx);
5061                 return ret;
5062         }
5063
5064         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
5065         if (!W_ERROR_IS_OK(status)) {
5066                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
5067                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
5068                 return LDB_ERR_OPERATIONS_ERROR;
5069         }
5070
5071         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
5072         if (!NT_STATUS_IS_OK(ntstatus) && active) {
5073                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
5074                                        old_el->name,
5075                                        ldb_dn_get_linearized(dsdb_dn->dn),
5076                                        ldb_dn_get_linearized(msg->dn));
5077                 return LDB_ERR_OPERATIONS_ERROR;
5078         }
5079
5080         /* re-resolve the DN by GUID, as the DRS server may give us an
5081            old DN value */
5082         ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
5083         if (ret != LDB_SUCCESS) {
5084                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
5085                          GUID_string(tmp_ctx, &guid),
5086                          ldb_dn_get_linearized(dsdb_dn->dn)));
5087         }
5088
5089         /* see if this link already exists */
5090         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
5091         if (pdn != NULL) {
5092                 /* see if this update is newer than what we have already */
5093                 struct GUID invocation_id = GUID_zero();
5094                 uint32_t version = 0;
5095                 uint32_t originating_usn = 0;
5096                 NTTIME change_time = 0;
5097                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
5098
5099                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
5100                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
5101                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
5102                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
5103
5104                 if (!replmd_update_is_newer(&invocation_id,
5105                                             &la->meta_data.originating_invocation_id,
5106                                             version,
5107                                             la->meta_data.version,
5108                                             change_time,
5109                                             la->meta_data.originating_change_time)) {
5110                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
5111                                  old_el->name, ldb_dn_get_linearized(msg->dn),
5112                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
5113                         talloc_free(tmp_ctx);
5114                         return LDB_SUCCESS;
5115                 }
5116
5117                 /* get a seq_num for this change */
5118                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
5119                 if (ret != LDB_SUCCESS) {
5120                         talloc_free(tmp_ctx);
5121                         return ret;
5122                 }
5123
5124                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
5125                         /* remove the existing backlink */
5126                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
5127                         if (ret != LDB_SUCCESS) {
5128                                 talloc_free(tmp_ctx);
5129                                 return ret;
5130                         }
5131                 }
5132
5133                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
5134                                            &la->meta_data.originating_invocation_id,
5135                                            la->meta_data.originating_usn, seq_num,
5136                                            la->meta_data.originating_change_time,
5137                                            la->meta_data.version,
5138                                            !active);
5139                 if (ret != LDB_SUCCESS) {
5140                         talloc_free(tmp_ctx);
5141                         return ret;
5142                 }
5143
5144                 if (active) {
5145                         /* add the new backlink */
5146                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
5147                         if (ret != LDB_SUCCESS) {
5148                                 talloc_free(tmp_ctx);
5149                                 return ret;
5150                         }
5151                 }
5152         } else {
5153                 /* get a seq_num for this change */
5154                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
5155                 if (ret != LDB_SUCCESS) {
5156                         talloc_free(tmp_ctx);
5157                         return ret;
5158                 }
5159
5160                 old_el->values = talloc_realloc(msg->elements, old_el->values,
5161                                                 struct ldb_val, old_el->num_values+1);
5162                 if (!old_el->values) {
5163                         ldb_module_oom(module);
5164                         return LDB_ERR_OPERATIONS_ERROR;
5165                 }
5166                 old_el->num_values++;
5167
5168                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
5169                                           &la->meta_data.originating_invocation_id,
5170                                           la->meta_data.originating_usn, seq_num,
5171                                           la->meta_data.originating_change_time,
5172                                           la->meta_data.version,
5173                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
5174                 if (ret != LDB_SUCCESS) {
5175                         talloc_free(tmp_ctx);
5176                         return ret;
5177                 }
5178
5179                 if (active) {
5180                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
5181                                                   true, attr, false);
5182                         if (ret != LDB_SUCCESS) {
5183                                 talloc_free(tmp_ctx);
5184                                 return ret;
5185                         }
5186                 }
5187         }
5188
5189         /* we only change whenChanged and uSNChanged if the seq_num
5190            has changed */
5191         ret = add_time_element(msg, "whenChanged", t);
5192         if (ret != LDB_SUCCESS) {
5193                 talloc_free(tmp_ctx);
5194                 ldb_operr(ldb);
5195                 return ret;
5196         }
5197
5198         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
5199         if (ret != LDB_SUCCESS) {
5200                 talloc_free(tmp_ctx);
5201                 ldb_operr(ldb);
5202                 return ret;
5203         }
5204
5205         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
5206         if (old_el == NULL) {
5207                 talloc_free(tmp_ctx);
5208                 return ldb_operr(ldb);
5209         }
5210
5211         ret = dsdb_check_single_valued_link(attr, old_el);
5212         if (ret != LDB_SUCCESS) {
5213                 talloc_free(tmp_ctx);
5214                 return ret;
5215         }
5216
5217         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
5218
5219         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
5220         if (ret != LDB_SUCCESS) {
5221                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
5222                           ldb_errstring(ldb),
5223                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
5224                 talloc_free(tmp_ctx);
5225                 return ret;
5226         }
5227
5228         talloc_free(tmp_ctx);
5229
5230         return ret;
5231 }
5232
5233 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
5234 {
5235         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
5236                 return replmd_extended_replicated_objects(module, req);
5237         }
5238
5239         return ldb_next_request(module, req);
5240 }
5241
5242
5243 /*
5244   we hook into the transaction operations to allow us to
5245   perform the linked attribute updates at the end of the whole
5246   transaction. This allows a forward linked attribute to be created
5247   before the object is created. During a vampire, w2k8 sends us linked
5248   attributes before the objects they are part of.
5249  */
5250 static int replmd_start_transaction(struct ldb_module *module)
5251 {
5252         /* create our private structure for this transaction */
5253         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
5254                                                                 struct replmd_private);
5255         replmd_txn_cleanup(replmd_private);
5256
5257         /* free any leftover mod_usn records from cancelled
5258            transactions */
5259         while (replmd_private->ncs) {
5260                 struct nc_entry *e = replmd_private->ncs;
5261                 DLIST_REMOVE(replmd_private->ncs, e);
5262                 talloc_free(e);
5263         }
5264
5265         return ldb_next_start_trans(module);
5266 }
5267
5268 /*
5269   on prepare commit we loop over our queued la_context structures and
5270   apply each of them
5271  */
5272 static int replmd_prepare_commit(struct ldb_module *module)
5273 {
5274         struct replmd_private *replmd_private =
5275                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5276         struct la_entry *la, *prev;
5277         struct la_backlink *bl;
5278         int ret;
5279
5280         /* walk the list backwards, to do the first entry first, as we
5281          * added the entries with DLIST_ADD() which puts them at the
5282          * start of the list */
5283         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
5284                 prev = DLIST_PREV(la);
5285                 DLIST_REMOVE(replmd_private->la_list, la);
5286                 ret = replmd_process_linked_attribute(module, la, NULL);
5287                 if (ret != LDB_SUCCESS) {
5288                         replmd_txn_cleanup(replmd_private);
5289                         return ret;
5290                 }
5291         }
5292
5293         /* process our backlink list, creating and deleting backlinks
5294            as necessary */
5295         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
5296                 ret = replmd_process_backlink(module, bl, NULL);
5297                 if (ret != LDB_SUCCESS) {
5298                         replmd_txn_cleanup(replmd_private);
5299                         return ret;
5300                 }
5301         }
5302
5303         replmd_txn_cleanup(replmd_private);
5304
5305         /* possibly change @REPLCHANGED */
5306         ret = replmd_notify_store(module, NULL);
5307         if (ret != LDB_SUCCESS) {
5308                 return ret;
5309         }
5310
5311         return ldb_next_prepare_commit(module);
5312 }
5313
5314 static int replmd_del_transaction(struct ldb_module *module)
5315 {
5316         struct replmd_private *replmd_private =
5317                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5318         replmd_txn_cleanup(replmd_private);
5319
5320         return ldb_next_del_trans(module);
5321 }
5322
5323
5324 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
5325         .name          = "repl_meta_data",
5326         .init_context      = replmd_init,
5327         .add               = replmd_add,
5328         .modify            = replmd_modify,
5329         .rename            = replmd_rename,
5330         .del               = replmd_delete,
5331         .extended          = replmd_extended,
5332         .start_transaction = replmd_start_transaction,
5333         .prepare_commit    = replmd_prepare_commit,
5334         .del_transaction   = replmd_del_transaction,
5335 };
5336
5337 int ldb_repl_meta_data_module_init(const char *version)
5338 {
5339         LDB_MODULE_CHECK_VERSION(version);
5340         return ldb_register_module(&ldb_repl_meta_data_module_ops);
5341 }