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