a198afcb00dac53895fcf05fafa43bb4546a0e3e
[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                 ret = replmd_replPropertyMetaDataCtr1_sort(&md->ctr.ctr1,
3719                                                            ar->schema, msg->dn);
3720                 if (ret != LDB_SUCCESS) {
3721                         return ret;
3722                 }
3723         }
3724
3725         /*
3726          * the meta data array is already sorted by the caller
3727          */
3728         for (i=0; i < md->ctr.ctr1.count; i++) {
3729                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3730         }
3731         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3732                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3733         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3734                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3735                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3736         }
3737         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3738         if (ret != LDB_SUCCESS) {
3739                 return replmd_replicated_request_error(ar, ret);
3740         }
3741
3742         replmd_ldb_message_sort(msg, ar->schema);
3743
3744         if (DEBUGLVL(4)) {
3745                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3746                 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3747                 talloc_free(s);
3748         }
3749
3750         ret = ldb_build_add_req(&change_req,
3751                                 ldb,
3752                                 ar,
3753                                 msg,
3754                                 ar->controls,
3755                                 ar,
3756                                 replmd_op_add_callback,
3757                                 ar->req);
3758         LDB_REQ_SET_LOCATION(change_req);
3759         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3760
3761         /* current partition control needed by "repmd_op_callback" */
3762         ret = ldb_request_add_control(change_req,
3763                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3764                                       false, NULL);
3765         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3766
3767         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
3768                 /* this tells the partition module to make it a
3769                    partial replica if creating an NC */
3770                 ret = ldb_request_add_control(change_req,
3771                                               DSDB_CONTROL_PARTIAL_REPLICA,
3772                                               false, NULL);
3773                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3774         }
3775
3776         return ldb_next_request(ar->module, change_req);
3777 }
3778
3779 /*
3780   handle renames that come in over DRS replication
3781  */
3782 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
3783                                            struct ldb_message *msg,
3784                                            struct replPropertyMetaDataBlob *rmd,
3785                                            struct replPropertyMetaDataBlob *omd,
3786                                            struct ldb_request *parent)
3787 {
3788         struct replPropertyMetaData1 *md_remote;
3789         struct replPropertyMetaData1 *md_local;
3790
3791         if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3792                 /* no rename */
3793                 return LDB_SUCCESS;
3794         }
3795
3796         /* now we need to check for double renames. We could have a
3797          * local rename pending which our replication partner hasn't
3798          * received yet. We choose which one wins by looking at the
3799          * attribute stamps on the two objects, the newer one wins
3800          */
3801         md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3802         md_local  = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3803         /* if there is no name attribute then we have to assume the
3804            object we've received is in fact newer */
3805         if (!md_remote || !md_local ||
3806             replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3807                 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3808                          ldb_dn_get_linearized(ar->search_msg->dn),
3809                          ldb_dn_get_linearized(msg->dn)));
3810                 /* pass rename to the next module
3811                  * so it doesn't appear as an originating update */
3812                 return dsdb_module_rename(ar->module,
3813                                           ar->search_msg->dn, msg->dn,
3814                                           DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX, parent);
3815         }
3816
3817         /* we're going to keep our old object */
3818         DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
3819                  ldb_dn_get_linearized(ar->search_msg->dn),
3820                  ldb_dn_get_linearized(msg->dn)));
3821         return LDB_SUCCESS;
3822 }
3823
3824
3825 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
3826 {
3827         struct ldb_context *ldb;
3828         struct ldb_request *change_req;
3829         enum ndr_err_code ndr_err;
3830         struct ldb_message *msg;
3831         struct replPropertyMetaDataBlob *rmd;
3832         struct replPropertyMetaDataBlob omd;
3833         const struct ldb_val *omd_value;
3834         struct replPropertyMetaDataBlob nmd;
3835         struct ldb_val nmd_value;
3836         unsigned int i;
3837         uint32_t j,ni=0;
3838         unsigned int removed_attrs = 0;
3839         int ret;
3840         bool found_old_is_deleted = false;
3841         bool found_old_is_recycled = false;
3842         bool found_old_has_lastknownrdn = false;
3843         bool old_is_deleted = false;
3844         bool old_is_recycled = false;
3845         bool old_has_lastknownrdn = false;
3846         bool found_new_is_deleted = false;
3847         bool found_new_is_recycled = false;
3848         bool found_new_has_lastknownrdn = false;
3849         bool new_is_deleted = false;
3850         bool new_is_recycled = false;
3851         bool new_has_lastknownrdn = false;
3852
3853         ldb = ldb_module_get_ctx(ar->module);
3854         msg = ar->objs->objects[ar->index_current].msg;
3855         rmd = ar->objs->objects[ar->index_current].meta_data;
3856         ZERO_STRUCT(omd);
3857         omd.version = 1;
3858
3859         if (!ar->is_recycled_tested) {
3860                 ar->isDeleted = dsdb_attribute_by_lDAPDisplayName(ar->schema,
3861                                                                    "isDeleted");
3862                 ar->isRecycled = dsdb_attribute_by_lDAPDisplayName(ar->schema,
3863                                                                    "isRecycled");
3864                 ar->lastKnownRDN = dsdb_attribute_by_lDAPDisplayName(ar->schema,
3865                                                                    "msDS-lastKnownRDN");
3866                 ar->is_recycled_tested = true;
3867         }
3868
3869         /* find existing meta data */
3870         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
3871         if (omd_value) {
3872                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
3873                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3874                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3875                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3876                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3877                 }
3878
3879                 if (omd.version != 1) {
3880                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3881                 }
3882         }
3883
3884         /* handle renames that come in over DRS */
3885         ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
3886         if (ret != LDB_SUCCESS) {
3887                 ldb_debug(ldb, LDB_DEBUG_FATAL,
3888                           "replmd_replicated_request rename %s => %s failed - %s\n",
3889                           ldb_dn_get_linearized(ar->search_msg->dn),
3890                           ldb_dn_get_linearized(msg->dn),
3891                           ldb_errstring(ldb));
3892                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
3893         }
3894
3895         for (i=0; i < ar->search_msg->num_elements; i++) {
3896                 struct ldb_message_element *el = &ar->search_msg->elements[i];
3897
3898                 if (ar->isDeleted && strcmp(el->name, ar->isDeleted->lDAPDisplayName) == 0) {
3899                         struct ldb_val *v = NULL;
3900
3901                         if (el->num_values == 0) {
3902                                 continue;
3903                         }
3904
3905                         found_old_is_deleted = true;
3906
3907                         v = &el->values[0];
3908
3909                         if (strncmp((const char*)v->data, "TRUE", 4) == 0) {
3910                                 old_is_deleted = true;
3911                         }
3912                 }
3913
3914                 if (ar->isRecycled && strcmp(el->name, ar->isRecycled->lDAPDisplayName) == 0) {
3915                         struct ldb_val *v = NULL;
3916
3917                         if (el->num_values == 0) {
3918                                 continue;
3919                         }
3920
3921                         found_old_is_recycled = true;
3922
3923                         v = &el->values[0];
3924
3925                         if (strncmp((const char*)v->data, "TRUE", 4) == 0) {
3926                                 old_is_recycled = true;
3927                         }
3928                 }
3929
3930                 if (ar->lastKnownRDN && strcmp(el->name, ar->lastKnownRDN->lDAPDisplayName) == 0) {
3931                         struct ldb_val *v = NULL;
3932
3933                         if (el->num_values == 0) {
3934                                 continue;
3935                         }
3936
3937                         found_old_has_lastknownrdn = true;
3938
3939                         v = &el->values[0];
3940
3941                         if (strncmp((const char*)v->data, "TRUE", 4) == 0) {
3942                                 old_has_lastknownrdn = true;
3943                         }
3944                 }
3945         }
3946
3947         ZERO_STRUCT(nmd);
3948         nmd.version = 1;
3949         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
3950         nmd.ctr.ctr1.array = talloc_array(ar,
3951                                           struct replPropertyMetaData1,
3952                                           nmd.ctr.ctr1.count);
3953         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3954
3955         /* first copy the old meta data */
3956         for (i=0; i < omd.ctr.ctr1.count; i++) {
3957                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
3958                 ni++;
3959         }
3960
3961         ar->seq_num = 0;
3962         /* now merge in the new meta data */
3963         for (i=0; i < rmd->ctr.ctr1.count; i++) {
3964                 bool found = false;
3965
3966                 for (j=0; j < ni; j++) {
3967                         bool cmp;
3968
3969                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
3970                                 continue;
3971                         }
3972
3973                         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
3974                                 /* if we compare equal then do an
3975                                    update. This is used when a client
3976                                    asks for a FULL_SYNC, and can be
3977                                    used to recover a corrupt
3978                                    replica */
3979                                 cmp = !replmd_replPropertyMetaData1_is_newer(&rmd->ctr.ctr1.array[i],
3980                                                                              &nmd.ctr.ctr1.array[j]);
3981                         } else {
3982                                 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
3983                                                                             &rmd->ctr.ctr1.array[i]);
3984                         }
3985                         if (cmp) {
3986                                 /* replace the entry */
3987                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
3988                                 if (ar->seq_num == 0) {
3989                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3990                                         if (ret != LDB_SUCCESS) {
3991                                                 return replmd_replicated_request_error(ar, ret);
3992                                         }
3993                                 }
3994                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
3995                                 found = true;
3996                                 break;
3997                         }
3998
3999                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
4000                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
4001                                          msg->elements[i-removed_attrs].name,
4002                                          ldb_dn_get_linearized(msg->dn),
4003                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
4004                         }
4005
4006                         /* we don't want to apply this change so remove the attribute */
4007                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
4008                         removed_attrs++;
4009
4010                         found = true;
4011                         break;
4012                 }
4013
4014                 if (found) continue;
4015
4016                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
4017                 if (ar->seq_num == 0) {
4018                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4019                         if (ret != LDB_SUCCESS) {
4020                                 return replmd_replicated_request_error(ar, ret);
4021                         }
4022                 }
4023                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
4024                 ni++;
4025         }
4026
4027         /*
4028          * finally correct the size of the meta_data array
4029          */
4030         nmd.ctr.ctr1.count = ni;
4031
4032         for (i=0; i < msg->num_elements; i++) {
4033                 struct ldb_message_element *el = &msg->elements[i];
4034
4035                 if (ar->isDeleted && strcmp(el->name, ar->isDeleted->lDAPDisplayName) == 0) {
4036                         struct ldb_val *v = NULL;
4037
4038                         if (el->num_values == 0) {
4039                                 continue;
4040                         }
4041
4042                         found_new_is_deleted = true;
4043
4044                         v = &el->values[0];
4045
4046                         if (strncmp((const char*)v->data, "TRUE", 4) == 0) {
4047                                 new_is_deleted = true;
4048                         }
4049                 }
4050
4051                 if (ar->isRecycled && strcmp(el->name, ar->isRecycled->lDAPDisplayName) == 0) {
4052                         struct ldb_val *v = NULL;
4053
4054                         if (el->num_values == 0) {
4055                                 continue;
4056                         }
4057
4058                         found_new_is_recycled = true;
4059
4060                         v = &el->values[0];
4061
4062                         if (strncmp((const char*)v->data, "TRUE", 4) == 0) {
4063                                 new_is_recycled = true;
4064                         }
4065                 }
4066
4067                 if (ar->lastKnownRDN && strcmp(el->name, ar->lastKnownRDN->lDAPDisplayName) == 0) {
4068                         struct ldb_val *v = NULL;
4069
4070                         if (el->num_values == 0) {
4071                                 continue;
4072                         }
4073
4074                         found_new_has_lastknownrdn = true;
4075
4076                         v = &el->values[0];
4077
4078                         if (strncmp((const char*)v->data, "TRUE", 4) == 0) {
4079                                 new_has_lastknownrdn = true;
4080                         }
4081                 }
4082         }
4083
4084         is_deleted = false;
4085         if (found_old_is_deleted) {
4086                 is_deleted = old_is_deleted;
4087         }
4088         if (found_new_is_deleted) {
4089                 is_deleted = new_is_deleted;
4090         }
4091
4092         is_recycled = false;
4093         if (found_old_is_recycled) {
4094                 is_recycled = old_is_recycled;
4095         }
4096         if (found_new_is_recycled) {
4097                 is_recycled = new_is_recycled;
4098         }
4099
4100         has_lastknownrdn = false;
4101         if (found_old_has_lastknownrdn) {
4102                 has_lastknownrdn = old_has_lastknownrdn;
4103         }
4104         if (found_new_has_lastknownrdn) {
4105                 has_lastknownrdn = new_has_lastknownrdn;
4106         }
4107
4108         if (is_deleted && ar->isRecycled && !is_recycled && !has_lastknownrdn) {
4109                 /*
4110                  * The replicated attributes for the current object has the
4111                  * isDeleted attribute but not the isRecycled and no the
4112                  * lastKnownRDN.  It means that we knew the object before and
4113                  * now we are notified that is has been deleted but it's not a
4114                  * recycled one.  If we support the isRecycled attribute we had
4115                  * this attribute.
4116                  */
4117 //TODO does this have impact on whenChanged?
4118                 ret = replmd_add_isrecycled(ar, ldb, msg, &nmd);
4119                 if (ret != LDB_SUCCESS) {
4120                         return ret;
4121                 }
4122         }
4123
4124         /*
4125          * the rdn attribute (the alias for the name attribute),
4126          * 'cn' for most objects is the last entry in the meta data array
4127          * we have stored
4128          *
4129          * sort the new meta data array
4130          */
4131         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
4132         if (ret != LDB_SUCCESS) {
4133                 return ret;
4134         }
4135
4136         /*
4137          * check if some replicated attributes left, otherwise skip the ldb_modify() call
4138          */
4139         if (msg->num_elements == 0) {
4140                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
4141                           ar->index_current);
4142
4143                 ar->index_current++;
4144                 return replmd_replicated_apply_next(ar);
4145         }
4146
4147         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
4148                   ar->index_current, msg->num_elements);
4149
4150         /* create the meta data value */
4151         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
4152                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4153         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4154                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4155                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4156         }
4157
4158         /*
4159          * when we know that we'll modify the record, add the whenChanged, uSNChanged
4160          * and replPopertyMetaData attributes
4161          */
4162         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4163         if (ret != LDB_SUCCESS) {
4164                 return replmd_replicated_request_error(ar, ret);
4165         }
4166         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4167         if (ret != LDB_SUCCESS) {
4168                 return replmd_replicated_request_error(ar, ret);
4169         }
4170         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
4171         if (ret != LDB_SUCCESS) {
4172                 return replmd_replicated_request_error(ar, ret);
4173         }
4174
4175         replmd_ldb_message_sort(msg, ar->schema);
4176
4177         /* we want to replace the old values */
4178         for (i=0; i < msg->num_elements; i++) {
4179                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4180         }
4181
4182         if (DEBUGLVL(4)) {
4183                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4184                 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
4185                 talloc_free(s);
4186         }
4187
4188         ret = ldb_build_mod_req(&change_req,
4189                                 ldb,
4190                                 ar,
4191                                 msg,
4192                                 ar->controls,
4193                                 ar,
4194                                 replmd_op_callback,
4195                                 ar->req);
4196         LDB_REQ_SET_LOCATION(change_req);
4197         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4198
4199         /* current partition control needed by "repmd_op_callback" */
4200         ret = ldb_request_add_control(change_req,
4201                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4202                                       false, NULL);
4203         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4204
4205         return ldb_next_request(ar->module, change_req);
4206 }
4207
4208 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
4209                                                    struct ldb_reply *ares)
4210 {
4211         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4212                                                struct replmd_replicated_request);
4213         int ret;
4214
4215         if (!ares) {
4216                 return ldb_module_done(ar->req, NULL, NULL,
4217                                         LDB_ERR_OPERATIONS_ERROR);
4218         }
4219         if (ares->error != LDB_SUCCESS &&
4220             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4221                 return ldb_module_done(ar->req, ares->controls,
4222                                         ares->response, ares->error);
4223         }
4224
4225         switch (ares->type) {
4226         case LDB_REPLY_ENTRY:
4227                 ar->search_msg = talloc_steal(ar, ares->message);
4228                 break;
4229
4230         case LDB_REPLY_REFERRAL:
4231                 /* we ignore referrals */
4232                 break;
4233
4234         case LDB_REPLY_DONE:
4235                 if (ar->search_msg != NULL) {
4236                         ret = replmd_replicated_apply_merge(ar);
4237                 } else {
4238                         ret = replmd_replicated_apply_add(ar);
4239                 }
4240                 if (ret != LDB_SUCCESS) {
4241                         return ldb_module_done(ar->req, NULL, NULL, ret);
4242                 }
4243         }
4244
4245         talloc_free(ares);
4246         return LDB_SUCCESS;
4247 }
4248
4249 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
4250
4251 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
4252 {
4253         struct ldb_context *ldb;
4254         int ret;
4255         char *tmp_str;
4256         char *filter;
4257         struct ldb_request *search_req;
4258         struct ldb_search_options_control *options;
4259
4260         if (ar->index_current >= ar->objs->num_objects) {
4261                 /* done with it, go to next stage */
4262                 return replmd_replicated_uptodate_vector(ar);
4263         }
4264
4265         ldb = ldb_module_get_ctx(ar->module);
4266         ar->search_msg = NULL;
4267
4268         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
4269         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4270
4271         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4272         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4273         talloc_free(tmp_str);
4274
4275         ret = ldb_build_search_req(&search_req,
4276                                    ldb,
4277                                    ar,
4278                                    NULL,
4279                                    LDB_SCOPE_SUBTREE,
4280                                    filter,
4281                                    NULL,
4282                                    NULL,
4283                                    ar,
4284                                    replmd_replicated_apply_search_callback,
4285                                    ar->req);
4286         LDB_REQ_SET_LOCATION(search_req);
4287
4288         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
4289                                       true, NULL);
4290         if (ret != LDB_SUCCESS) {
4291                 return ret;
4292         }
4293
4294         /* we need to cope with cross-partition links, so search for
4295            the GUID over all partitions */
4296         options = talloc(search_req, struct ldb_search_options_control);
4297         if (options == NULL) {
4298                 DEBUG(0, (__location__ ": out of memory\n"));
4299                 return LDB_ERR_OPERATIONS_ERROR;
4300         }
4301         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
4302
4303         ret = ldb_request_add_control(search_req,
4304                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
4305                                       true, options);
4306         if (ret != LDB_SUCCESS) {
4307                 return ret;
4308         }
4309
4310         return ldb_next_request(ar->module, search_req);
4311 }
4312
4313 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
4314                                                       struct ldb_reply *ares)
4315 {
4316         struct ldb_context *ldb;
4317         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4318                                                struct replmd_replicated_request);
4319         ldb = ldb_module_get_ctx(ar->module);
4320
4321         if (!ares) {
4322                 return ldb_module_done(ar->req, NULL, NULL,
4323                                         LDB_ERR_OPERATIONS_ERROR);
4324         }
4325         if (ares->error != LDB_SUCCESS) {
4326                 return ldb_module_done(ar->req, ares->controls,
4327                                         ares->response, ares->error);
4328         }
4329
4330         if (ares->type != LDB_REPLY_DONE) {
4331                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
4332                 return ldb_module_done(ar->req, NULL, NULL,
4333                                         LDB_ERR_OPERATIONS_ERROR);
4334         }
4335
4336         talloc_free(ares);
4337
4338         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4339 }
4340
4341 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
4342 {
4343         struct ldb_context *ldb;
4344         struct ldb_request *change_req;
4345         enum ndr_err_code ndr_err;
4346         struct ldb_message *msg;
4347         struct replUpToDateVectorBlob ouv;
4348         const struct ldb_val *ouv_value;
4349         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
4350         struct replUpToDateVectorBlob nuv;
4351         struct ldb_val nuv_value;
4352         struct ldb_message_element *nuv_el = NULL;
4353         const struct GUID *our_invocation_id;
4354         struct ldb_message_element *orf_el = NULL;
4355         struct repsFromToBlob nrf;
4356         struct ldb_val *nrf_value = NULL;
4357         struct ldb_message_element *nrf_el = NULL;
4358         unsigned int i;
4359         uint32_t j,ni=0;
4360         bool found = false;
4361         time_t t = time(NULL);
4362         NTTIME now;
4363         int ret;
4364         uint32_t instanceType;
4365
4366         ldb = ldb_module_get_ctx(ar->module);
4367         ruv = ar->objs->uptodateness_vector;
4368         ZERO_STRUCT(ouv);
4369         ouv.version = 2;
4370         ZERO_STRUCT(nuv);
4371         nuv.version = 2;
4372
4373         unix_to_nt_time(&now, t);
4374
4375         if (ar->search_msg == NULL) {
4376                 /* this happens for a REPL_OBJ call where we are
4377                    creating the target object by replicating it. The
4378                    subdomain join code does this for the partition DN
4379                 */
4380                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
4381                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4382         }
4383
4384         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
4385         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
4386                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
4387                          ldb_dn_get_linearized(ar->search_msg->dn)));
4388                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4389         }
4390
4391         /*
4392          * first create the new replUpToDateVector
4393          */
4394         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
4395         if (ouv_value) {
4396                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
4397                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4398                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4399                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4400                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4401                 }
4402
4403                 if (ouv.version != 2) {
4404                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4405                 }
4406         }
4407
4408         /*
4409          * the new uptodateness vector will at least
4410          * contain 1 entry, one for the source_dsa
4411          *
4412          * plus optional values from our old vector and the one from the source_dsa
4413          */
4414         nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
4415         if (ruv) nuv.ctr.ctr2.count += ruv->count;
4416         nuv.ctr.ctr2.cursors = talloc_array(ar,
4417                                             struct drsuapi_DsReplicaCursor2,
4418                                             nuv.ctr.ctr2.count);
4419         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4420
4421         /* first copy the old vector */
4422         for (i=0; i < ouv.ctr.ctr2.count; i++) {
4423                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
4424                 ni++;
4425         }
4426
4427         /* get our invocation_id if we have one already attached to the ldb */
4428         our_invocation_id = samdb_ntds_invocation_id(ldb);
4429
4430         /* merge in the source_dsa vector is available */
4431         for (i=0; (ruv && i < ruv->count); i++) {
4432                 found = false;
4433
4434                 if (our_invocation_id &&
4435                     GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4436                                our_invocation_id)) {
4437                         continue;
4438                 }
4439
4440                 for (j=0; j < ni; j++) {
4441                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4442                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4443                                 continue;
4444                         }
4445
4446                         found = true;
4447
4448                         /*
4449                          * we update only the highest_usn and not the latest_sync_success time,
4450                          * because the last success stands for direct replication
4451                          */
4452                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
4453                                 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
4454                         }
4455                         break;
4456                 }
4457
4458                 if (found) continue;
4459
4460                 /* if it's not there yet, add it */
4461                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
4462                 ni++;
4463         }
4464
4465         /*
4466          * merge in the current highwatermark for the source_dsa
4467          */
4468         found = false;
4469         for (j=0; j < ni; j++) {
4470                 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
4471                                 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4472                         continue;
4473                 }
4474
4475                 found = true;
4476
4477                 /*
4478                  * here we update the highest_usn and last_sync_success time
4479                  * because we're directly replicating from the source_dsa
4480                  *
4481                  * and use the tmp_highest_usn because this is what we have just applied
4482                  * to our ldb
4483                  */
4484                 nuv.ctr.ctr2.cursors[j].highest_usn             = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4485                 nuv.ctr.ctr2.cursors[j].last_sync_success       = now;
4486                 break;
4487         }
4488         if (!found) {
4489                 /*
4490                  * here we update the highest_usn and last_sync_success time
4491                  * because we're directly replicating from the source_dsa
4492                  *
4493                  * and use the tmp_highest_usn because this is what we have just applied
4494                  * to our ldb
4495                  */
4496                 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
4497                 nuv.ctr.ctr2.cursors[ni].highest_usn            = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4498                 nuv.ctr.ctr2.cursors[ni].last_sync_success      = now;
4499                 ni++;
4500         }
4501
4502         /*
4503          * finally correct the size of the cursors array
4504          */
4505         nuv.ctr.ctr2.count = ni;
4506
4507         /*
4508          * sort the cursors
4509          */
4510         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
4511
4512         /*
4513          * create the change ldb_message
4514          */
4515         msg = ldb_msg_new(ar);
4516         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4517         msg->dn = ar->search_msg->dn;
4518
4519         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
4520                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
4521         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4522                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4523                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4524         }
4525         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
4526         if (ret != LDB_SUCCESS) {
4527                 return replmd_replicated_request_error(ar, ret);
4528         }
4529         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
4530
4531         /*
4532          * now create the new repsFrom value from the given repsFromTo1 structure
4533          */
4534         ZERO_STRUCT(nrf);
4535         nrf.version                                     = 1;
4536         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
4537         nrf.ctr.ctr1.highwatermark.highest_usn          = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
4538
4539         /*
4540          * first see if we already have a repsFrom value for the current source dsa
4541          * if so we'll later replace this value
4542          */
4543         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
4544         if (orf_el) {
4545                 for (i=0; i < orf_el->num_values; i++) {
4546                         struct repsFromToBlob *trf;
4547
4548                         trf = talloc(ar, struct repsFromToBlob);
4549                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4550
4551                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
4552                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
4553                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4554                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4555                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4556                         }
4557
4558                         if (trf->version != 1) {
4559                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4560                         }
4561
4562                         /*
4563                          * we compare the source dsa objectGUID not the invocation_id
4564                          * because we want only one repsFrom value per source dsa
4565                          * and when the invocation_id of the source dsa has changed we don't need
4566                          * the old repsFrom with the old invocation_id
4567                          */
4568                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
4569                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
4570                                 talloc_free(trf);
4571                                 continue;
4572                         }
4573
4574                         talloc_free(trf);
4575                         nrf_value = &orf_el->values[i];
4576                         break;
4577                 }
4578
4579                 /*
4580                  * copy over all old values to the new ldb_message
4581                  */
4582                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
4583                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4584                 *nrf_el = *orf_el;
4585         }
4586
4587         /*
4588          * if we haven't found an old repsFrom value for the current source dsa
4589          * we'll add a new value
4590          */
4591         if (!nrf_value) {
4592                 struct ldb_val zero_value;
4593                 ZERO_STRUCT(zero_value);
4594                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
4595                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4596
4597                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
4598         }
4599
4600         /* we now fill the value which is already attached to ldb_message */
4601         ndr_err = ndr_push_struct_blob(nrf_value, msg,
4602                                        &nrf,
4603                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
4604         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4605                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4606                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4607         }
4608
4609         /*
4610          * the ldb_message_element for the attribute, has all the old values and the new one
4611          * so we'll replace the whole attribute with all values
4612          */
4613         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
4614
4615         if (CHECK_DEBUGLVL(4)) {
4616                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4617                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
4618                 talloc_free(s);
4619         }
4620
4621         /* prepare the ldb_modify() request */
4622         ret = ldb_build_mod_req(&change_req,
4623                                 ldb,
4624                                 ar,
4625                                 msg,
4626                                 ar->controls,
4627                                 ar,
4628                                 replmd_replicated_uptodate_modify_callback,
4629                                 ar->req);
4630         LDB_REQ_SET_LOCATION(change_req);
4631         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4632
4633         return ldb_next_request(ar->module, change_req);
4634 }
4635
4636 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
4637                                                       struct ldb_reply *ares)
4638 {
4639         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4640                                                struct replmd_replicated_request);
4641         int ret;
4642
4643         if (!ares) {
4644                 return ldb_module_done(ar->req, NULL, NULL,
4645                                         LDB_ERR_OPERATIONS_ERROR);
4646         }
4647         if (ares->error != LDB_SUCCESS &&
4648             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4649                 return ldb_module_done(ar->req, ares->controls,
4650                                         ares->response, ares->error);
4651         }
4652
4653         switch (ares->type) {
4654         case LDB_REPLY_ENTRY:
4655                 ar->search_msg = talloc_steal(ar, ares->message);
4656                 break;
4657
4658         case LDB_REPLY_REFERRAL:
4659                 /* we ignore referrals */
4660                 break;
4661
4662         case LDB_REPLY_DONE:
4663                 ret = replmd_replicated_uptodate_modify(ar);
4664                 if (ret != LDB_SUCCESS) {
4665                         return ldb_module_done(ar->req, NULL, NULL, ret);
4666                 }
4667         }
4668
4669         talloc_free(ares);
4670         return LDB_SUCCESS;
4671 }
4672
4673
4674 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
4675 {
4676         struct ldb_context *ldb;
4677         int ret;
4678         static const char *attrs[] = {
4679                 "replUpToDateVector",
4680                 "repsFrom",
4681                 "instanceType",
4682                 NULL
4683         };
4684         struct ldb_request *search_req;
4685
4686         ldb = ldb_module_get_ctx(ar->module);
4687         ar->search_msg = NULL;
4688
4689         ret = ldb_build_search_req(&search_req,
4690                                    ldb,
4691                                    ar,
4692                                    ar->objs->partition_dn,
4693                                    LDB_SCOPE_BASE,
4694                                    "(objectClass=*)",
4695                                    attrs,
4696                                    NULL,
4697                                    ar,
4698                                    replmd_replicated_uptodate_search_callback,
4699                                    ar->req);
4700         LDB_REQ_SET_LOCATION(search_req);
4701         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4702
4703         return ldb_next_request(ar->module, search_req);
4704 }
4705
4706
4707
4708 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
4709 {
4710         struct ldb_context *ldb;
4711         struct dsdb_extended_replicated_objects *objs;
4712         struct replmd_replicated_request *ar;
4713         struct ldb_control **ctrls;
4714         int ret;
4715         uint32_t i;
4716         struct replmd_private *replmd_private =
4717                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4718         struct dsdb_control_replicated_update *rep_update;
4719
4720         ldb = ldb_module_get_ctx(module);
4721
4722         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
4723
4724         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
4725         if (!objs) {
4726                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
4727                 return LDB_ERR_PROTOCOL_ERROR;
4728         }
4729
4730         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
4731                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
4732                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
4733                 return LDB_ERR_PROTOCOL_ERROR;
4734         }
4735
4736         ar = replmd_ctx_init(module, req);
4737         if (!ar)
4738                 return LDB_ERR_OPERATIONS_ERROR;
4739
4740         /* Set the flags to have the replmd_op_callback run over the full set of objects */
4741         ar->apply_mode = true;
4742         ar->objs = objs;
4743         ar->schema = dsdb_get_schema(ldb, ar);
4744         if (!ar->schema) {
4745                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
4746                 talloc_free(ar);
4747                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4748                 return LDB_ERR_CONSTRAINT_VIOLATION;
4749         }
4750
4751         ctrls = req->controls;
4752
4753         if (req->controls) {
4754                 req->controls = talloc_memdup(ar, req->controls,
4755                                               talloc_get_size(req->controls));
4756                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4757         }
4758
4759         /* This allows layers further down to know if a change came in
4760            over replication and what the replication flags were */
4761         rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
4762         if (rep_update == NULL) {
4763                 return ldb_module_oom(module);
4764         }
4765         rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
4766
4767         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
4768         if (ret != LDB_SUCCESS) {
4769                 return ret;
4770         }
4771
4772         /* If this change contained linked attributes in the body
4773          * (rather than in the links section) we need to update
4774          * backlinks in linked_attributes */
4775         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
4776         if (ret != LDB_SUCCESS) {
4777                 return ret;
4778         }
4779
4780         ar->controls = req->controls;
4781         req->controls = ctrls;
4782
4783         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
4784
4785         /* save away the linked attributes for the end of the
4786            transaction */
4787         for (i=0; i<ar->objs->linked_attributes_count; i++) {
4788                 struct la_entry *la_entry;
4789
4790                 if (replmd_private->la_ctx == NULL) {
4791                         replmd_private->la_ctx = talloc_new(replmd_private);
4792                 }
4793                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
4794                 if (la_entry == NULL) {
4795                         ldb_oom(ldb);
4796                         return LDB_ERR_OPERATIONS_ERROR;
4797                 }
4798                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
4799                 if (la_entry->la == NULL) {
4800                         talloc_free(la_entry);
4801                         ldb_oom(ldb);
4802                         return LDB_ERR_OPERATIONS_ERROR;
4803                 }
4804                 *la_entry->la = ar->objs->linked_attributes[i];
4805
4806                 /* we need to steal the non-scalars so they stay
4807                    around until the end of the transaction */
4808                 talloc_steal(la_entry->la, la_entry->la->identifier);
4809                 talloc_steal(la_entry->la, la_entry->la->value.blob);
4810
4811                 DLIST_ADD(replmd_private->la_list, la_entry);
4812         }
4813
4814         return replmd_replicated_apply_next(ar);
4815 }
4816
4817 /*
4818   process one linked attribute structure
4819  */
4820 static int replmd_process_linked_attribute(struct ldb_module *module,
4821                                            struct la_entry *la_entry,
4822                                            struct ldb_request *parent)
4823 {
4824         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
4825         struct ldb_context *ldb = ldb_module_get_ctx(module);
4826         struct ldb_message *msg;
4827         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
4828         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
4829         int ret;
4830         const struct dsdb_attribute *attr;
4831         struct dsdb_dn *dsdb_dn;
4832         uint64_t seq_num = 0;
4833         struct ldb_message_element *old_el;
4834         WERROR status;
4835         time_t t = time(NULL);
4836         struct ldb_result *res;
4837         const char *attrs[2];
4838         struct parsed_dn *pdn_list, *pdn;
4839         struct GUID guid = GUID_zero();
4840         NTSTATUS ntstatus;
4841         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
4842         const struct GUID *our_invocation_id;
4843
4844 /*
4845 linked_attributes[0]:
4846      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
4847         identifier               : *
4848             identifier: struct drsuapi_DsReplicaObjectIdentifier
4849                 __ndr_size               : 0x0000003a (58)
4850                 __ndr_size_sid           : 0x00000000 (0)
4851                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
4852                 sid                      : S-0-0
4853                 __ndr_size_dn            : 0x00000000 (0)
4854                 dn                       : ''
4855         attid                    : DRSUAPI_ATTID_member (0x1F)
4856         value: struct drsuapi_DsAttributeValue
4857             __ndr_size               : 0x0000007e (126)
4858             blob                     : *
4859                 blob                     : DATA_BLOB length=126
4860         flags                    : 0x00000001 (1)
4861                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
4862         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
4863         meta_data: struct drsuapi_DsReplicaMetaData
4864             version                  : 0x00000015 (21)
4865             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
4866             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
4867             originating_usn          : 0x000000000001e19c (123292)
4868
4869 (for cases where the link is to a normal DN)
4870      &target: struct drsuapi_DsReplicaObjectIdentifier3
4871         __ndr_size               : 0x0000007e (126)
4872         __ndr_size_sid           : 0x0000001c (28)
4873         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
4874         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
4875         __ndr_size_dn            : 0x00000022 (34)
4876         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
4877  */
4878
4879         /* find the attribute being modified */
4880         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
4881         if (attr == NULL) {
4882                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
4883                 talloc_free(tmp_ctx);
4884                 return LDB_ERR_OPERATIONS_ERROR;
4885         }
4886
4887         attrs[0] = attr->lDAPDisplayName;
4888         attrs[1] = NULL;
4889
4890         /* get the existing message from the db for the object with
4891            this GUID, returning attribute being modified. We will then
4892            use this msg as the basis for a modify call */
4893         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
4894                                  DSDB_FLAG_NEXT_MODULE |
4895                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
4896                                  DSDB_SEARCH_SHOW_RECYCLED |
4897                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4898                                  DSDB_SEARCH_REVEAL_INTERNALS,
4899                                  parent,
4900                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
4901         if (ret != LDB_SUCCESS) {
4902                 talloc_free(tmp_ctx);
4903                 return ret;
4904         }
4905         if (res->count != 1) {
4906                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
4907                                        GUID_string(tmp_ctx, &la->identifier->guid));
4908                 talloc_free(tmp_ctx);
4909                 return LDB_ERR_NO_SUCH_OBJECT;
4910         }
4911         msg = res->msgs[0];
4912
4913         if (msg->num_elements == 0) {
4914                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
4915                 if (ret != LDB_SUCCESS) {
4916                         ldb_module_oom(module);
4917                         talloc_free(tmp_ctx);
4918                         return LDB_ERR_OPERATIONS_ERROR;
4919                 }
4920         } else {
4921                 old_el = &msg->elements[0];
4922                 old_el->flags = LDB_FLAG_MOD_REPLACE;
4923         }
4924
4925         /* parse the existing links */
4926         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
4927         if (ret != LDB_SUCCESS) {
4928                 talloc_free(tmp_ctx);
4929                 return ret;
4930         }
4931
4932         /* get our invocationId */
4933         our_invocation_id = samdb_ntds_invocation_id(ldb);
4934         if (!our_invocation_id) {
4935                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
4936                 talloc_free(tmp_ctx);
4937                 return LDB_ERR_OPERATIONS_ERROR;
4938         }
4939
4940         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
4941         if (ret != LDB_SUCCESS) {
4942                 talloc_free(tmp_ctx);
4943                 return ret;
4944         }
4945
4946         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
4947         if (!W_ERROR_IS_OK(status)) {
4948                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
4949                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
4950                 return LDB_ERR_OPERATIONS_ERROR;
4951         }
4952
4953         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
4954         if (!NT_STATUS_IS_OK(ntstatus) && active) {
4955                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
4956                                        old_el->name,
4957                                        ldb_dn_get_linearized(dsdb_dn->dn),
4958                                        ldb_dn_get_linearized(msg->dn));
4959                 return LDB_ERR_OPERATIONS_ERROR;
4960         }
4961
4962         /* re-resolve the DN by GUID, as the DRS server may give us an
4963            old DN value */
4964         ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
4965         if (ret != LDB_SUCCESS) {
4966                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
4967                          GUID_string(tmp_ctx, &guid),
4968                          ldb_dn_get_linearized(dsdb_dn->dn)));
4969         }
4970
4971         /* see if this link already exists */
4972         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
4973         if (pdn != NULL) {
4974                 /* see if this update is newer than what we have already */
4975                 struct GUID invocation_id = GUID_zero();
4976                 uint32_t version = 0;
4977                 uint32_t originating_usn = 0;
4978                 NTTIME change_time = 0;
4979                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
4980
4981                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
4982                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
4983                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
4984                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
4985
4986                 if (!replmd_update_is_newer(&invocation_id,
4987                                             &la->meta_data.originating_invocation_id,
4988                                             version,
4989                                             la->meta_data.version,
4990                                             change_time,
4991                                             la->meta_data.originating_change_time)) {
4992                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
4993                                  old_el->name, ldb_dn_get_linearized(msg->dn),
4994                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
4995                         talloc_free(tmp_ctx);
4996                         return LDB_SUCCESS;
4997                 }
4998
4999                 /* get a seq_num for this change */
5000                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
5001                 if (ret != LDB_SUCCESS) {
5002                         talloc_free(tmp_ctx);
5003                         return ret;
5004                 }
5005
5006                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
5007                         /* remove the existing backlink */
5008                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
5009                         if (ret != LDB_SUCCESS) {
5010                                 talloc_free(tmp_ctx);
5011                                 return ret;
5012                         }
5013                 }
5014
5015                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
5016                                            &la->meta_data.originating_invocation_id,
5017                                            la->meta_data.originating_usn, seq_num,
5018                                            la->meta_data.originating_change_time,
5019                                            la->meta_data.version,
5020                                            !active);
5021                 if (ret != LDB_SUCCESS) {
5022                         talloc_free(tmp_ctx);
5023                         return ret;
5024                 }
5025
5026                 if (active) {
5027                         /* add the new backlink */
5028                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
5029                         if (ret != LDB_SUCCESS) {
5030                                 talloc_free(tmp_ctx);
5031                                 return ret;
5032                         }
5033                 }
5034         } else {
5035                 /* get a seq_num for this change */
5036                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
5037                 if (ret != LDB_SUCCESS) {
5038                         talloc_free(tmp_ctx);
5039                         return ret;
5040                 }
5041
5042                 old_el->values = talloc_realloc(msg->elements, old_el->values,
5043                                                 struct ldb_val, old_el->num_values+1);
5044                 if (!old_el->values) {
5045                         ldb_module_oom(module);
5046                         return LDB_ERR_OPERATIONS_ERROR;
5047                 }
5048                 old_el->num_values++;
5049
5050                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
5051                                           &la->meta_data.originating_invocation_id,
5052                                           la->meta_data.originating_usn, seq_num,
5053                                           la->meta_data.originating_change_time,
5054                                           la->meta_data.version,
5055                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
5056                 if (ret != LDB_SUCCESS) {
5057                         talloc_free(tmp_ctx);
5058                         return ret;
5059                 }
5060
5061                 if (active) {
5062                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
5063                                                   true, attr, false);
5064                         if (ret != LDB_SUCCESS) {
5065                                 talloc_free(tmp_ctx);
5066                                 return ret;
5067                         }
5068                 }
5069         }
5070
5071         /* we only change whenChanged and uSNChanged if the seq_num
5072            has changed */
5073         ret = add_time_element(msg, "whenChanged", t);
5074         if (ret != LDB_SUCCESS) {
5075                 talloc_free(tmp_ctx);
5076                 ldb_operr(ldb);
5077                 return ret;
5078         }
5079
5080         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
5081         if (ret != LDB_SUCCESS) {
5082                 talloc_free(tmp_ctx);
5083                 ldb_operr(ldb);
5084                 return ret;
5085         }
5086
5087         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
5088         if (old_el == NULL) {
5089                 talloc_free(tmp_ctx);
5090                 return ldb_operr(ldb);
5091         }
5092
5093         ret = dsdb_check_single_valued_link(attr, old_el);
5094         if (ret != LDB_SUCCESS) {
5095                 talloc_free(tmp_ctx);
5096                 return ret;
5097         }
5098
5099         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
5100
5101         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
5102         if (ret != LDB_SUCCESS) {
5103                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
5104                           ldb_errstring(ldb),
5105                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
5106                 talloc_free(tmp_ctx);
5107                 return ret;
5108         }
5109
5110         talloc_free(tmp_ctx);
5111
5112         return ret;
5113 }
5114
5115 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
5116 {
5117         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
5118                 return replmd_extended_replicated_objects(module, req);
5119         }
5120
5121         return ldb_next_request(module, req);
5122 }
5123
5124
5125 /*
5126   we hook into the transaction operations to allow us to
5127   perform the linked attribute updates at the end of the whole
5128   transaction. This allows a forward linked attribute to be created
5129   before the object is created. During a vampire, w2k8 sends us linked
5130   attributes before the objects they are part of.
5131  */
5132 static int replmd_start_transaction(struct ldb_module *module)
5133 {
5134         /* create our private structure for this transaction */
5135         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
5136                                                                 struct replmd_private);
5137         replmd_txn_cleanup(replmd_private);
5138
5139         /* free any leftover mod_usn records from cancelled
5140            transactions */
5141         while (replmd_private->ncs) {
5142                 struct nc_entry *e = replmd_private->ncs;
5143                 DLIST_REMOVE(replmd_private->ncs, e);
5144                 talloc_free(e);
5145         }
5146
5147         return ldb_next_start_trans(module);
5148 }
5149
5150 /*
5151   on prepare commit we loop over our queued la_context structures and
5152   apply each of them
5153  */
5154 static int replmd_prepare_commit(struct ldb_module *module)
5155 {
5156         struct replmd_private *replmd_private =
5157                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5158         struct la_entry *la, *prev;
5159         struct la_backlink *bl;
5160         int ret;
5161
5162         /* walk the list backwards, to do the first entry first, as we
5163          * added the entries with DLIST_ADD() which puts them at the
5164          * start of the list */
5165         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
5166                 prev = DLIST_PREV(la);
5167                 DLIST_REMOVE(replmd_private->la_list, la);
5168                 ret = replmd_process_linked_attribute(module, la, NULL);
5169                 if (ret != LDB_SUCCESS) {
5170                         replmd_txn_cleanup(replmd_private);
5171                         return ret;
5172                 }
5173         }
5174
5175         /* process our backlink list, creating and deleting backlinks
5176            as necessary */
5177         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
5178                 ret = replmd_process_backlink(module, bl, NULL);
5179                 if (ret != LDB_SUCCESS) {
5180                         replmd_txn_cleanup(replmd_private);
5181                         return ret;
5182                 }
5183         }
5184
5185         replmd_txn_cleanup(replmd_private);
5186
5187         /* possibly change @REPLCHANGED */
5188         ret = replmd_notify_store(module, NULL);
5189         if (ret != LDB_SUCCESS) {
5190                 return ret;
5191         }
5192
5193         return ldb_next_prepare_commit(module);
5194 }
5195
5196 static int replmd_del_transaction(struct ldb_module *module)
5197 {
5198         struct replmd_private *replmd_private =
5199                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5200         replmd_txn_cleanup(replmd_private);
5201
5202         return ldb_next_del_trans(module);
5203 }
5204
5205
5206 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
5207         .name          = "repl_meta_data",
5208         .init_context      = replmd_init,
5209         .add               = replmd_add,
5210         .modify            = replmd_modify,
5211         .rename            = replmd_rename,
5212         .del               = replmd_delete,
5213         .extended          = replmd_extended,
5214         .start_transaction = replmd_start_transaction,
5215         .prepare_commit    = replmd_prepare_commit,
5216         .del_transaction   = replmd_del_transaction,
5217 };
5218
5219 int ldb_repl_meta_data_module_init(const char *version)
5220 {
5221         LDB_MODULE_CHECK_VERSION(version);
5222         return ldb_register_module(&ldb_repl_meta_data_module_ops);
5223 }