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