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