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