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