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