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