replmd linked attrs: fully parse dn for upgrade check
[sfrench/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 /* When a parsed_dn comes from the database, sometimes it is not really parsed. */
1808
1809 static int really_parse_trusted_dn(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
1810                                    struct parsed_dn *pdn, const char *ldap_oid)
1811 {
1812         NTSTATUS status;
1813         struct dsdb_dn *dsdb_dn = dsdb_dn_parse_trusted(mem_ctx, ldb, pdn->v,
1814                                                         ldap_oid);
1815         if (dsdb_dn == NULL) {
1816                 return LDB_ERR_INVALID_DN_SYNTAX;
1817         }
1818
1819         status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &pdn->guid, "GUID");
1820         if (!NT_STATUS_IS_OK(status)) {
1821                 return LDB_ERR_OPERATIONS_ERROR;
1822         }
1823         pdn->dsdb_dn = dsdb_dn;
1824         return LDB_SUCCESS;
1825 }
1826
1827 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1828 {
1829         return GUID_compare(&pdn1->guid, &pdn2->guid);
1830 }
1831
1832 static int la_guid_compare_with_trusted_dn(struct compare_ctx *ctx,
1833                                            struct parsed_dn *p)
1834 {
1835         /*
1836          * This works like a standard compare function in its return values,
1837          * but has an extra trick to deal with errors: zero is returned and
1838          * ctx->err is set to the ldb error code.
1839          *
1840          * That is, if (as is expected in most cases) you get a non-zero
1841          * result, you don't need to check for errors.
1842          *
1843          * We assume the second argument refers to a DN is from the database
1844          * and has a GUID -- but this GUID might not have been parsed out yet.
1845          */
1846         NTSTATUS status;
1847
1848         if (GUID_all_zero(&p->guid)) {
1849
1850                 if (p->dsdb_dn == NULL) {
1851                         p->dsdb_dn = dsdb_dn_parse_trusted(ctx->mem_ctx, ctx->ldb, p->v,
1852                                                           ctx->ldap_oid);
1853                         if (p->dsdb_dn == NULL) {
1854                                 ctx->err = LDB_ERR_INVALID_DN_SYNTAX;
1855                                 return 0;
1856                         }
1857                 }
1858
1859                 status = dsdb_get_extended_dn_guid(p->dsdb_dn->dn, &p->guid, "GUID");
1860                 if (!NT_STATUS_IS_OK(status)) {
1861                         ctx->err = LDB_ERR_OPERATIONS_ERROR;
1862                         return 0;
1863                 }
1864         }
1865
1866         return GUID_compare(ctx->guid, &p->guid);
1867 }
1868
1869
1870
1871 static int parsed_dn_find(struct ldb_context *ldb, struct parsed_dn *pdn,
1872                           unsigned int count,
1873                           struct GUID *guid,
1874                           struct ldb_dn *target_dn,
1875                           struct parsed_dn **exact,
1876                           struct parsed_dn **next,
1877                           const char *ldap_oid)
1878 {
1879         unsigned int i;
1880         struct compare_ctx ctx;
1881         if (pdn == NULL) {
1882                 *exact = NULL;
1883                 *next = NULL;
1884                 return LDB_SUCCESS;
1885         }
1886
1887         if (unlikely(GUID_all_zero(guid))) {
1888                 /*
1889                  * When updating a link using DRS, we sometimes get a NULL
1890                  * GUID when a forward link has been deleted and its GUID has
1891                  * for some reason been forgotten. The best we can do is try
1892                  * and match by DN via a linear search. Note that this
1893                  * probably only happens in the ADD case, in which we only
1894                  * allow modification of link if it is already deleted, so
1895                  * this seems very close to an elaborate NO-OP, but we are not
1896                  * quite prepared to declare it so.
1897                  *
1898                  * If the DN is not in our list, we have to add it to the
1899                  * beginning of the list, where it would naturally sort.
1900                  */
1901                 struct parsed_dn *p;
1902                 if (target_dn == NULL) {
1903                         /* We don't know the target DN, so we can't search for DN */
1904                         DEBUG(1, ("parsed_dn_find has a NULL GUID for a linked "
1905                                   "attribute but we don't have a DN to compare "
1906                                   "it with\n"));
1907                         return LDB_ERR_OPERATIONS_ERROR;
1908                 }
1909                 *exact = NULL;
1910                 *next = NULL;
1911
1912                 DEBUG(3, ("parsed_dn_find has a NULL GUID for a link to DN "
1913                           "%s; searching through links for it",
1914                           ldb_dn_get_linearized(target_dn)));
1915
1916                 for (i = 0; i < count; i++) {
1917                         int cmp;
1918                         p = &pdn[i];
1919                         if (p->dsdb_dn == NULL) {
1920                                 p->dsdb_dn = dsdb_dn_parse_trusted(pdn, ldb,
1921                                                                    p->v, ldap_oid);
1922                                 if (p->dsdb_dn == NULL) {
1923                                         return LDB_ERR_OPERATIONS_ERROR;
1924                                 }
1925                         }
1926                         cmp = ldb_dn_compare(p->dsdb_dn->dn, target_dn);
1927                         if (cmp == 0) {
1928                                 dsdb_get_extended_dn_guid(p->dsdb_dn->dn,
1929                                                           &p->guid, "GUID");
1930                                 *exact = p;
1931                                 return LDB_SUCCESS;
1932                         }
1933                 }
1934                 /*
1935                  * Here we have a null guid which doesn't match any existing
1936                  * link. This is a bit unexpected because null guids occur
1937                  * when a forward link has been deleted and we are replicating
1938                  * that deletion.
1939                  *
1940                  * The best thing to do is weep into the logs and add the
1941                  * offending link to the beginning of the list which is
1942                  * at least the correct sort position.
1943                  */
1944                 DEBUG(1, ("parsed_dn_find has been given a NULL GUID for a "
1945                           "link to unknown DN %s\n",
1946                           ldb_dn_get_linearized(target_dn)));
1947                 *next = pdn;
1948                 return LDB_SUCCESS;
1949         }
1950
1951         ctx.guid = guid;
1952         ctx.ldb = ldb;
1953         ctx.mem_ctx = pdn;
1954         ctx.ldap_oid = ldap_oid;
1955         ctx.err = 0;
1956
1957         BINARY_ARRAY_SEARCH_GTE(pdn, count, &ctx, la_guid_compare_with_trusted_dn,
1958                                 *exact, *next);
1959
1960         if (ctx.err != 0) {
1961                 return ctx.err;
1962         }
1963         return LDB_SUCCESS;
1964 }
1965
1966 /*
1967   get a series of message element values as an array of DNs and GUIDs
1968   the result is sorted by GUID
1969  */
1970 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1971                           struct ldb_message_element *el, struct parsed_dn **pdn,
1972                           const char *ldap_oid, struct ldb_request *parent)
1973 {
1974         unsigned int i;
1975         bool values_are_sorted = true;
1976         struct ldb_context *ldb = ldb_module_get_ctx(module);
1977
1978         if (el == NULL) {
1979                 *pdn = NULL;
1980                 return LDB_SUCCESS;
1981         }
1982
1983         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1984         if (!*pdn) {
1985                 ldb_module_oom(module);
1986                 return LDB_ERR_OPERATIONS_ERROR;
1987         }
1988
1989         for (i=0; i<el->num_values; i++) {
1990                 struct ldb_val *v = &el->values[i];
1991                 NTSTATUS status;
1992                 struct ldb_dn *dn;
1993                 struct parsed_dn *p;
1994
1995                 p = &(*pdn)[i];
1996
1997                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1998                 if (p->dsdb_dn == NULL) {
1999                         return LDB_ERR_INVALID_DN_SYNTAX;
2000                 }
2001
2002                 dn = p->dsdb_dn->dn;
2003
2004                 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
2005                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2006                         /* we got a DN without a GUID - go find the GUID */
2007                         int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2008                         if (ret != LDB_SUCCESS) {
2009                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
2010                                                        ldb_dn_get_linearized(dn));
2011                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2012                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2013                                     ldb_attr_cmp(el->name, "member") == 0) {
2014                                         return LDB_ERR_UNWILLING_TO_PERFORM;
2015                                 }
2016                                 return ret;
2017                         }
2018                         ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2019                         if (ret != LDB_SUCCESS) {
2020                                 return ret;
2021                         }
2022                 } else if (!NT_STATUS_IS_OK(status)) {
2023                         return LDB_ERR_OPERATIONS_ERROR;
2024                 }
2025                 if (i > 0 && values_are_sorted) {
2026                         int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2027                         if (cmp < 0) {
2028                                 values_are_sorted = false;
2029                         }
2030                 }
2031                 /* keep a pointer to the original ldb_val */
2032                 p->v = v;
2033         }
2034         if (! values_are_sorted) {
2035                 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2036         }
2037         return LDB_SUCCESS;
2038 }
2039
2040 /*
2041  * Get a series of trusted message element values. The result is sorted by
2042  * GUID, even though the GUIDs might not be known. That works because we trust
2043  * the database to give us the elements like that if the
2044  * replmd_private->sorted_links flag is set.
2045  */
2046 static int get_parsed_dns_trusted(struct ldb_module *module,
2047                                   struct replmd_private *replmd_private,
2048                                   TALLOC_CTX *mem_ctx,
2049                                   struct ldb_message_element *el,
2050                                   struct parsed_dn **pdn,
2051                                   const char *ldap_oid,
2052                                   struct ldb_request *parent)
2053 {
2054         unsigned int i;
2055
2056         if (el == NULL) {
2057                 *pdn = NULL;
2058                 return LDB_SUCCESS;
2059         }
2060
2061         if (!replmd_private->sorted_links) {
2062                 /* We need to sort the list. This is the slow old path we want
2063                    to avoid.
2064                  */
2065                 return get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2066                                       parent);
2067         }
2068         /* Here we get a list of 'struct parsed_dns' without the parsing */
2069         *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2070                                  el->num_values);
2071         if (!*pdn) {
2072                 ldb_module_oom(module);
2073                 return LDB_ERR_OPERATIONS_ERROR;
2074         }
2075
2076         for (i = 0; i < el->num_values; i++) {
2077                 (*pdn)[i].v = &el->values[i];
2078         }
2079
2080         return LDB_SUCCESS;
2081 }
2082
2083 /*
2084   build a new extended DN, including all meta data fields
2085
2086   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
2087   RMD_ADDTIME         = originating_add_time
2088   RMD_INVOCID         = originating_invocation_id
2089   RMD_CHANGETIME      = originating_change_time
2090   RMD_ORIGINATING_USN = originating_usn
2091   RMD_LOCAL_USN       = local_usn
2092   RMD_VERSION         = version
2093  */
2094 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2095                                const struct GUID *invocation_id, uint64_t seq_num,
2096                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2097 {
2098         struct ldb_dn *dn = dsdb_dn->dn;
2099         const char *tstring, *usn_string, *flags_string;
2100         struct ldb_val tval;
2101         struct ldb_val iid;
2102         struct ldb_val usnv, local_usnv;
2103         struct ldb_val vers, flagsv;
2104         NTSTATUS status;
2105         int ret;
2106         const char *dnstring;
2107         char *vstring;
2108         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2109
2110         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2111         if (!tstring) {
2112                 return LDB_ERR_OPERATIONS_ERROR;
2113         }
2114         tval = data_blob_string_const(tstring);
2115
2116         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2117         if (!usn_string) {
2118                 return LDB_ERR_OPERATIONS_ERROR;
2119         }
2120         usnv = data_blob_string_const(usn_string);
2121
2122         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2123         if (!usn_string) {
2124                 return LDB_ERR_OPERATIONS_ERROR;
2125         }
2126         local_usnv = data_blob_string_const(usn_string);
2127
2128         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2129         if (!vstring) {
2130                 return LDB_ERR_OPERATIONS_ERROR;
2131         }
2132         vers = data_blob_string_const(vstring);
2133
2134         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2135         if (!NT_STATUS_IS_OK(status)) {
2136                 return LDB_ERR_OPERATIONS_ERROR;
2137         }
2138
2139         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2140         if (!flags_string) {
2141                 return LDB_ERR_OPERATIONS_ERROR;
2142         }
2143         flagsv = data_blob_string_const(flags_string);
2144
2145         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2146         if (ret != LDB_SUCCESS) return ret;
2147         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2148         if (ret != LDB_SUCCESS) return ret;
2149         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2150         if (ret != LDB_SUCCESS) return ret;
2151         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2152         if (ret != LDB_SUCCESS) return ret;
2153         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2154         if (ret != LDB_SUCCESS) return ret;
2155         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2156         if (ret != LDB_SUCCESS) return ret;
2157         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2158         if (ret != LDB_SUCCESS) return ret;
2159
2160         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2161         if (dnstring == NULL) {
2162                 return LDB_ERR_OPERATIONS_ERROR;
2163         }
2164         *v = data_blob_string_const(dnstring);
2165
2166         return LDB_SUCCESS;
2167 }
2168
2169 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2170                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2171                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2172                                 uint32_t version, bool deleted);
2173
2174 /*
2175   check if any links need upgrading from w2k format
2176  */
2177 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2178                                       struct parsed_dn *dns, uint32_t count,
2179                                       struct ldb_message_element *el,
2180                                       const struct GUID *invocation_id,
2181                                       const char *ldap_oid)
2182 {
2183         uint32_t i;
2184         for (i=0; i<count; i++) {
2185                 NTSTATUS status;
2186                 uint32_t version;
2187                 int ret;
2188                 if (dns[i].dsdb_dn == NULL) {
2189                         ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2190                                                       ldap_oid);
2191                         if (ret != LDB_SUCCESS) {
2192                                 return LDB_ERR_INVALID_DN_SYNTAX;
2193                         }
2194                 }
2195
2196                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2197                                                      &version, "RMD_VERSION");
2198                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2199                         /*
2200                          *  We optimistically assume they are all the same; if
2201                          *  the first one is fixed, they are all fixed.
2202                          *
2203                          *  If the first one was *not* fixed and we find a
2204                          *  later one that is, that is an occasion to shout
2205                          *  with DEBUG(0).
2206                          */
2207                         if (i == 0) {
2208                                 return LDB_SUCCESS;
2209                         }
2210                         DEBUG(0, ("Mixed w2k and fixed format "
2211                                   "linked attributes\n"));
2212                         continue;
2213                 }
2214
2215                 /* it's an old one that needs upgrading */
2216                 ret = replmd_update_la_val(el->values, dns[i].v,
2217                                            dns[i].dsdb_dn, dns[i].dsdb_dn,
2218                                            invocation_id, 1, 1, 0, 0, false);
2219                 if (ret != LDB_SUCCESS) {
2220                         return ret;
2221                 }
2222         }
2223         return LDB_SUCCESS;
2224 }
2225
2226 /*
2227   update an extended DN, including all meta data fields
2228
2229   see replmd_build_la_val for value names
2230  */
2231 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2232                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2233                                 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2234                                 uint32_t version, bool deleted)
2235 {
2236         struct ldb_dn *dn = dsdb_dn->dn;
2237         const char *tstring, *usn_string, *flags_string;
2238         struct ldb_val tval;
2239         struct ldb_val iid;
2240         struct ldb_val usnv, local_usnv;
2241         struct ldb_val vers, flagsv;
2242         const struct ldb_val *old_addtime;
2243         uint32_t old_version;
2244         NTSTATUS status;
2245         int ret;
2246         const char *dnstring;
2247         char *vstring;
2248         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2249
2250         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2251         if (!tstring) {
2252                 return LDB_ERR_OPERATIONS_ERROR;
2253         }
2254         tval = data_blob_string_const(tstring);
2255
2256         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2257         if (!usn_string) {
2258                 return LDB_ERR_OPERATIONS_ERROR;
2259         }
2260         usnv = data_blob_string_const(usn_string);
2261
2262         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2263         if (!usn_string) {
2264                 return LDB_ERR_OPERATIONS_ERROR;
2265         }
2266         local_usnv = data_blob_string_const(usn_string);
2267
2268         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2269         if (!NT_STATUS_IS_OK(status)) {
2270                 return LDB_ERR_OPERATIONS_ERROR;
2271         }
2272
2273         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2274         if (!flags_string) {
2275                 return LDB_ERR_OPERATIONS_ERROR;
2276         }
2277         flagsv = data_blob_string_const(flags_string);
2278
2279         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2280         if (ret != LDB_SUCCESS) return ret;
2281
2282         /* get the ADDTIME from the original */
2283         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2284         if (old_addtime == NULL) {
2285                 old_addtime = &tval;
2286         }
2287         if (dsdb_dn != old_dsdb_dn ||
2288             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2289                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2290                 if (ret != LDB_SUCCESS) return ret;
2291         }
2292
2293         /* use our invocation id */
2294         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2295         if (ret != LDB_SUCCESS) return ret;
2296
2297         /* changetime is the current time */
2298         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2299         if (ret != LDB_SUCCESS) return ret;
2300
2301         /* update the USN */
2302         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2303         if (ret != LDB_SUCCESS) return ret;
2304
2305         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2306         if (ret != LDB_SUCCESS) return ret;
2307
2308         /* increase the version by 1 */
2309         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2310         if (NT_STATUS_IS_OK(status) && old_version >= version) {
2311                 version = old_version+1;
2312         }
2313         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2314         vers = data_blob_string_const(vstring);
2315         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2316         if (ret != LDB_SUCCESS) return ret;
2317
2318         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2319         if (dnstring == NULL) {
2320                 return LDB_ERR_OPERATIONS_ERROR;
2321         }
2322         *v = data_blob_string_const(dnstring);
2323
2324         return LDB_SUCCESS;
2325 }
2326
2327 /*
2328   handle adding a linked attribute
2329  */
2330 static int replmd_modify_la_add(struct ldb_module *module,
2331                                 struct replmd_private *replmd_private,
2332                                 const struct dsdb_schema *schema,
2333                                 struct ldb_message *msg,
2334                                 struct ldb_message_element *el,
2335                                 struct ldb_message_element *old_el,
2336                                 const struct dsdb_attribute *schema_attr,
2337                                 uint64_t seq_num,
2338                                 time_t t,
2339                                 struct GUID *msg_guid,
2340                                 struct ldb_request *parent)
2341 {
2342         unsigned int i;
2343         struct parsed_dn *dns, *old_dns;
2344         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2345         int ret;
2346         struct ldb_val *new_values = NULL;
2347         unsigned int num_new_values = 0;
2348         unsigned old_num_values = old_el?old_el->num_values:0;
2349         const struct GUID *invocation_id;
2350         struct ldb_context *ldb = ldb_module_get_ctx(module);
2351         NTTIME now;
2352
2353         unix_to_nt_time(&now, t);
2354
2355         /* get the DNs to be added, fully parsed.
2356          *
2357          * We need full parsing because they came off the wire and we don't
2358          * trust them, besides which we need their details to know where to put
2359          * them.
2360          */
2361         ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2362                              schema_attr->syntax->ldap_oid, parent);
2363         if (ret != LDB_SUCCESS) {
2364                 talloc_free(tmp_ctx);
2365                 return ret;
2366         }
2367
2368         /* get the existing DNs, lazily parsed */
2369         ret = get_parsed_dns_trusted(module, replmd_private,
2370                                      tmp_ctx, old_el, &old_dns,
2371                                      schema_attr->syntax->ldap_oid, parent);
2372
2373         if (ret != LDB_SUCCESS) {
2374                 talloc_free(tmp_ctx);
2375                 return ret;
2376         }
2377
2378         invocation_id = samdb_ntds_invocation_id(ldb);
2379         if (!invocation_id) {
2380                 talloc_free(tmp_ctx);
2381                 return LDB_ERR_OPERATIONS_ERROR;
2382         }
2383
2384         ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2385                                          old_el, invocation_id,
2386                                          schema_attr->syntax->ldap_oid);
2387         if (ret != LDB_SUCCESS) {
2388                 talloc_free(tmp_ctx);
2389                 return ret;
2390         }
2391
2392         /* for each new value, see if it exists already with the same GUID */
2393         for (i=0; i<el->num_values; i++) {
2394                 struct parsed_dn *p;
2395                 struct parsed_dn *next;
2396                 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2397                                          &dns[i].guid,
2398                                          dns[i].dsdb_dn->dn,
2399                                          &p, &next,
2400                                          schema_attr->syntax->ldap_oid);
2401                 if (err != LDB_SUCCESS) {
2402                         talloc_free(tmp_ctx);
2403                         return err;
2404                 }
2405                 if (p == NULL) {
2406                         /* this is a new linked attribute value */
2407                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
2408                         if (new_values == NULL) {
2409                                 ldb_module_oom(module);
2410                                 talloc_free(tmp_ctx);
2411                                 return LDB_ERR_OPERATIONS_ERROR;
2412                         }
2413                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2414                                                   invocation_id, seq_num, seq_num, now, 0, false);
2415                         if (ret != LDB_SUCCESS) {
2416                                 talloc_free(tmp_ctx);
2417                                 return ret;
2418                         }
2419                         num_new_values++;
2420                 } else {
2421                         /* this is only allowed if the GUID was
2422                            previously deleted. */
2423                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2424                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2425                                 struct GUID_txt_buf guid_str;
2426                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
2427                                                        el->name, GUID_buf_string(&p->guid, &guid_str));
2428                                 talloc_free(tmp_ctx);
2429                                 /* error codes for 'member' need to be
2430                                    special cased */
2431                                 if (ldb_attr_cmp(el->name, "member") == 0) {
2432                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
2433                                 } else {
2434                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2435                                 }
2436                         }
2437                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
2438                                                    invocation_id, seq_num, seq_num, now, 0, false);
2439                         if (ret != LDB_SUCCESS) {
2440                                 talloc_free(tmp_ctx);
2441                                 return ret;
2442                         }
2443                 }
2444
2445                 ret = replmd_add_backlink(module, replmd_private,
2446                                           schema, msg_guid, &dns[i].guid,
2447                                           true, schema_attr, true);
2448                 if (ret != LDB_SUCCESS) {
2449                         talloc_free(tmp_ctx);
2450                         return ret;
2451                 }
2452         }
2453
2454         /* add the new ones on to the end of the old values, constructing a new el->values */
2455         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2456                                     struct ldb_val,
2457                                     old_num_values+num_new_values);
2458         if (el->values == NULL) {
2459                 ldb_module_oom(module);
2460                 return LDB_ERR_OPERATIONS_ERROR;
2461         }
2462
2463         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
2464         el->num_values = old_num_values + num_new_values;
2465
2466         talloc_steal(msg->elements, el->values);
2467         talloc_steal(el->values, new_values);
2468
2469         talloc_free(tmp_ctx);
2470
2471         /* we now tell the backend to replace all existing values
2472            with the one we have constructed */
2473         el->flags = LDB_FLAG_MOD_REPLACE;
2474
2475         return LDB_SUCCESS;
2476 }
2477
2478
2479 /*
2480   handle deleting all active linked attributes
2481  */
2482 static int replmd_modify_la_delete(struct ldb_module *module,
2483                                    struct replmd_private *replmd_private,
2484                                    const struct dsdb_schema *schema,
2485                                    struct ldb_message *msg,
2486                                    struct ldb_message_element *el,
2487                                    struct ldb_message_element *old_el,
2488                                    const struct dsdb_attribute *schema_attr,
2489                                    uint64_t seq_num,
2490                                    time_t t,
2491                                    struct GUID *msg_guid,
2492                                    struct ldb_request *parent)
2493 {
2494         unsigned int i;
2495         struct parsed_dn *dns, *old_dns;
2496         TALLOC_CTX *tmp_ctx = NULL;
2497         int ret;
2498         const struct GUID *invocation_id;
2499         struct ldb_context *ldb = ldb_module_get_ctx(module);
2500         struct ldb_control *vanish_links_ctrl = NULL;
2501         bool vanish_links = false;
2502         unsigned int num_to_delete = el->num_values;
2503         NTTIME now;
2504
2505         unix_to_nt_time(&now, t);
2506
2507         /* check if there is nothing to delete */
2508         if ((!old_el || old_el->num_values == 0) &&
2509             el->num_values == 0) {
2510                 return LDB_SUCCESS;
2511         }
2512
2513         if (!old_el || old_el->num_values == 0) {
2514                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2515         }
2516
2517         tmp_ctx = talloc_new(msg);
2518         if (tmp_ctx == NULL) {
2519                 return LDB_ERR_OPERATIONS_ERROR;
2520         }
2521
2522         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2523         if (ret != LDB_SUCCESS) {
2524                 talloc_free(tmp_ctx);
2525                 return ret;
2526         }
2527
2528         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2529         if (ret != LDB_SUCCESS) {
2530                 talloc_free(tmp_ctx);
2531                 return ret;
2532         }
2533
2534         invocation_id = samdb_ntds_invocation_id(ldb);
2535         if (!invocation_id) {
2536                 talloc_free(tmp_ctx);
2537                 return LDB_ERR_OPERATIONS_ERROR;
2538         }
2539
2540         ret = replmd_check_upgrade_links(ldb, old_dns, old_el->num_values,
2541                                          old_el, invocation_id,
2542                                          schema_attr->syntax->ldap_oid);
2543         if (ret != LDB_SUCCESS) {
2544                 talloc_free(tmp_ctx);
2545                 return ret;
2546         }
2547
2548         if (parent) {
2549                 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2550                 if (vanish_links_ctrl) {
2551                         vanish_links = true;
2552                         vanish_links_ctrl->critical = false;
2553                 }
2554         }
2555
2556         el->num_values = 0;
2557         el->values = NULL;
2558
2559         /* see if we are being asked to delete any links that
2560            don't exist or are already deleted */
2561         for (i=0; i < num_to_delete; i++) {
2562                 struct parsed_dn *p = &dns[i];
2563                 struct parsed_dn *p2;
2564                 struct parsed_dn *next = NULL;
2565                 uint32_t rmd_flags;
2566                 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2567                                      &p->guid,
2568                                      NULL,
2569                                      &p2, &next,
2570                                      schema_attr->syntax->ldap_oid);
2571                 if (ret != LDB_SUCCESS) {
2572                         talloc_free(tmp_ctx);
2573                         return ret;
2574                 }
2575
2576                 if (!p2) {
2577                         struct GUID_txt_buf buf;
2578                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2579                                                el->name, GUID_buf_string(&p->guid, &buf));
2580                         if (ldb_attr_cmp(el->name, "member") == 0) {
2581                                 talloc_free(tmp_ctx);
2582                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2583                         } else {
2584                                 talloc_free(tmp_ctx);
2585                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2586                         }
2587                 }
2588                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
2589                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2590                         struct GUID_txt_buf buf;
2591                         const char *guid_str = GUID_buf_string(&p->guid, &buf);
2592                         if (vanish_links) {
2593                                 DEBUG(0, ("Deleting deleted linked attribute %s to %s, "
2594                                           "because vanish_links control is set\n",
2595                                           el->name, guid_str));
2596                                 continue;
2597                         }
2598                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2599                                                el->name, guid_str);
2600                         if (ldb_attr_cmp(el->name, "member") == 0) {
2601                                 talloc_free(tmp_ctx);
2602                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2603                         } else {
2604                                 talloc_free(tmp_ctx);
2605                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2606                         }
2607                 }
2608         }
2609
2610         if (vanish_links) {
2611                 if (num_to_delete == old_el->num_values || num_to_delete == 0) {
2612                         el->flags = LDB_FLAG_MOD_REPLACE;
2613
2614                         for (i = 0; i < old_el->num_values; i++) {
2615                                 ret = replmd_add_backlink(module,
2616                                                           replmd_private,
2617                                                           schema, msg_guid,
2618                                                           &old_dns[i].guid,
2619                                                           false, schema_attr,
2620                                                           true);
2621                                 if (ret != LDB_SUCCESS) {
2622                                         talloc_free(tmp_ctx);
2623                                         return ret;
2624                                 }
2625                         }
2626                         talloc_free(tmp_ctx);
2627                         return LDB_SUCCESS;
2628                 } else {
2629                         unsigned int num_values = 0;
2630                         unsigned int j = 0;
2631                         struct parsed_dn *exact = NULL, *next = NULL;
2632
2633                         for (i = 0; i < old_el->num_values; i++) {
2634                                 ret = parsed_dn_find(ldb, dns, num_to_delete,
2635                                                      &old_dns[i].guid,
2636                                                      NULL,
2637                                                      &exact, &next,
2638                                                      schema_attr->syntax->ldap_oid);
2639                                 if (ret != LDB_SUCCESS) {
2640                                         talloc_free(tmp_ctx);
2641                                         return ret;
2642                                 }
2643
2644                                 if (exact != NULL) {
2645                                         /* The element is in the delete list.
2646                                            mark it dead. */
2647                                         ret = replmd_add_backlink(module,
2648                                                                   replmd_private,
2649                                                                   schema,
2650                                                                   msg_guid,
2651                                                                   &old_dns[i].guid,
2652                                                                   false,
2653                                                                   schema_attr,
2654                                                                   true);
2655                                         if (ret != LDB_SUCCESS) {
2656                                                 talloc_free(tmp_ctx);
2657                                                 return ret;
2658                                         }
2659                                         old_dns[i].v->length = 0;
2660                                 } else {
2661                                         num_values++;
2662                                 }
2663                         }
2664                         for (i = 0; i < old_el->num_values; i++) {
2665                                 if (old_el->values[i].length != 0) {
2666                                         old_el->values[j] = old_el->values[i];
2667                                         j++;
2668                                         if (j == num_values) {
2669                                                 break;
2670                                         }
2671                                 }
2672                         }
2673                         old_el->num_values = num_values;
2674                 }
2675         } else {
2676
2677                 /* for each new value, see if it exists already with the same GUID
2678                    if it is not already deleted and matches the delete list then delete it
2679                 */
2680                 for (i=0; i<old_el->num_values; i++) {
2681                         struct parsed_dn *p = &old_dns[i];
2682                         struct parsed_dn *exact = NULL, *next = NULL;
2683                         uint32_t rmd_flags;
2684
2685                         if (num_to_delete != 0) {
2686                                 ret = parsed_dn_find(ldb, dns, num_to_delete,
2687                                                      &p->guid,
2688                                                      NULL,
2689                                                      &exact, &next,
2690                                                      schema_attr->syntax->ldap_oid);
2691                                 if (ret != LDB_SUCCESS) {
2692                                         talloc_free(tmp_ctx);
2693                                         return ret;
2694                                 }
2695                                 if (exact == NULL) {
2696                                         continue;
2697                                 }
2698                         }
2699
2700                         rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2701                         if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2702
2703                         ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2704                                                    invocation_id, seq_num, seq_num, now, 0, true);
2705                         if (ret != LDB_SUCCESS) {
2706                                 talloc_free(tmp_ctx);
2707                                 return ret;
2708                         }
2709                         ret = replmd_add_backlink(module, replmd_private,
2710                                                   schema, msg_guid, &p->guid,
2711                                                   false, schema_attr, true);
2712                         if (ret != LDB_SUCCESS) {
2713                                 talloc_free(tmp_ctx);
2714                                 return ret;
2715                         }
2716                 }
2717         }
2718         el->values = talloc_steal(msg->elements, old_el->values);
2719         el->num_values = old_el->num_values;
2720
2721         talloc_free(tmp_ctx);
2722
2723         /* we now tell the backend to replace all existing values
2724            with the one we have constructed */
2725         el->flags = LDB_FLAG_MOD_REPLACE;
2726
2727         return LDB_SUCCESS;
2728 }
2729
2730 /*
2731   handle replacing a linked attribute
2732  */
2733 static int replmd_modify_la_replace(struct ldb_module *module,
2734                                     struct replmd_private *replmd_private,
2735                                     const struct dsdb_schema *schema,
2736                                     struct ldb_message *msg,
2737                                     struct ldb_message_element *el,
2738                                     struct ldb_message_element *old_el,
2739                                     const struct dsdb_attribute *schema_attr,
2740                                     uint64_t seq_num,
2741                                     time_t t,
2742                                     struct GUID *msg_guid,
2743                                     struct ldb_request *parent)
2744 {
2745         unsigned int i;
2746         struct parsed_dn *dns, *old_dns;
2747         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2748         int ret;
2749         const struct GUID *invocation_id;
2750         struct ldb_context *ldb = ldb_module_get_ctx(module);
2751         struct ldb_val *new_values = NULL;
2752         unsigned int num_new_values = 0;
2753         unsigned int old_num_values = old_el?old_el->num_values:0;
2754         NTTIME now;
2755
2756         unix_to_nt_time(&now, t);
2757
2758         /* check if there is nothing to replace */
2759         if ((!old_el || old_el->num_values == 0) &&
2760             el->num_values == 0) {
2761                 return LDB_SUCCESS;
2762         }
2763
2764         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2765         if (ret != LDB_SUCCESS) {
2766                 talloc_free(tmp_ctx);
2767                 return ret;
2768         }
2769
2770         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2771         if (ret != LDB_SUCCESS) {
2772                 talloc_free(tmp_ctx);
2773                 return ret;
2774         }
2775
2776         invocation_id = samdb_ntds_invocation_id(ldb);
2777         if (!invocation_id) {
2778                 return LDB_ERR_OPERATIONS_ERROR;
2779         }
2780
2781         ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2782                                          old_el, invocation_id,
2783                                          schema_attr->syntax->ldap_oid);
2784         if (ret != LDB_SUCCESS) {
2785                 talloc_free(tmp_ctx);
2786                 return ret;
2787         }
2788
2789         /* mark all the old ones as deleted */
2790         for (i=0; i<old_num_values; i++) {
2791                 struct parsed_dn *old_p = &old_dns[i];
2792                 struct parsed_dn *exact = NULL, *next = NULL;
2793                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2794
2795                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2796
2797                 ret = replmd_add_backlink(module, replmd_private,
2798                                           schema, msg_guid, &old_dns[i].guid,
2799                                           false, schema_attr, false);
2800                 if (ret != LDB_SUCCESS) {
2801                         talloc_free(tmp_ctx);
2802                         return ret;
2803                 }
2804
2805                 ret = parsed_dn_find(ldb, dns, el->num_values,
2806                                      &old_p->guid,
2807                                      NULL,
2808                                      &exact, &next,
2809                                      schema_attr->syntax->ldap_oid);
2810                 if (ret != LDB_SUCCESS) {
2811                         talloc_free(tmp_ctx);
2812                         return ret;
2813                 }
2814                 if (exact) {
2815                         /* we don't delete it if we are re-adding it */
2816                         continue;
2817                 }
2818
2819                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2820                                            invocation_id, seq_num, seq_num, now, 0, true);
2821                 if (ret != LDB_SUCCESS) {
2822                         talloc_free(tmp_ctx);
2823                         return ret;
2824                 }
2825         }
2826
2827         /* for each new value, either update its meta-data, or add it
2828          * to old_el
2829         */
2830         for (i=0; i<el->num_values; i++) {
2831                 struct parsed_dn *p = &dns[i];
2832                 struct parsed_dn *old_p = NULL, *next = NULL;
2833
2834                 if (old_dns) {
2835                         ret = parsed_dn_find(ldb, old_dns, old_num_values,
2836                                              &p->guid,
2837                                              NULL,
2838                                              &old_p, &next,
2839                                              schema_attr->syntax->ldap_oid);
2840                         if (ret != LDB_SUCCESS) {
2841                                 talloc_free(tmp_ctx);
2842                                 return ret;
2843                         }
2844                 }
2845
2846                 if (old_p != NULL) {
2847                         /* update in place */
2848                         ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2849                                                    old_p->dsdb_dn, invocation_id,
2850                                                    seq_num, seq_num, now, 0, false);
2851                         if (ret != LDB_SUCCESS) {
2852                                 talloc_free(tmp_ctx);
2853                                 return ret;
2854                         }
2855                 } else {
2856                         /* add a new one */
2857                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2858                                                     num_new_values+1);
2859                         if (new_values == NULL) {
2860                                 ldb_module_oom(module);
2861                                 talloc_free(tmp_ctx);
2862                                 return LDB_ERR_OPERATIONS_ERROR;
2863                         }
2864                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2865                                                   invocation_id, seq_num, seq_num, now, 0, false);
2866                         if (ret != LDB_SUCCESS) {
2867                                 talloc_free(tmp_ctx);
2868                                 return ret;
2869                         }
2870                         num_new_values++;
2871                 }
2872
2873                 ret = replmd_add_backlink(module, replmd_private,
2874                                           schema, msg_guid, &dns[i].guid,
2875                                           true, schema_attr, false);
2876                 if (ret != LDB_SUCCESS) {
2877                         talloc_free(tmp_ctx);
2878                         return ret;
2879                 }
2880         }
2881
2882         /* add the new values to the end of old_el */
2883         if (num_new_values != 0) {
2884                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2885                                             struct ldb_val, old_num_values+num_new_values);
2886                 if (el->values == NULL) {
2887                         ldb_module_oom(module);
2888                         return LDB_ERR_OPERATIONS_ERROR;
2889                 }
2890                 memcpy(&el->values[old_num_values], &new_values[0],
2891                        sizeof(struct ldb_val)*num_new_values);
2892                 el->num_values = old_num_values + num_new_values;
2893                 talloc_steal(msg->elements, new_values);
2894         } else {
2895                 el->values = old_el->values;
2896                 el->num_values = old_el->num_values;
2897                 talloc_steal(msg->elements, el->values);
2898         }
2899
2900         talloc_free(tmp_ctx);
2901
2902         /* we now tell the backend to replace all existing values
2903            with the one we have constructed */
2904         el->flags = LDB_FLAG_MOD_REPLACE;
2905
2906         return LDB_SUCCESS;
2907 }
2908
2909
2910 /*
2911   handle linked attributes in modify requests
2912  */
2913 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2914                                                struct replmd_private *replmd_private,
2915                                                struct ldb_message *msg,
2916                                                uint64_t seq_num, time_t t,
2917                                                struct ldb_request *parent)
2918 {
2919         struct ldb_result *res;
2920         unsigned int i;
2921         int ret;
2922         struct ldb_context *ldb = ldb_module_get_ctx(module);
2923         struct ldb_message *old_msg;
2924
2925         const struct dsdb_schema *schema;
2926         struct GUID old_guid;
2927
2928         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2929                 /*
2930                  * Nothing special is required for modifying or vanishing links
2931                  * in fl2000 since they are just strings in a multi-valued
2932                  * attribute.
2933                  */
2934                 struct ldb_control *ctrl = ldb_request_get_control(parent,
2935                                                                    DSDB_CONTROL_REPLMD_VANISH_LINKS);
2936                 if (ctrl) {
2937                         ctrl->critical = false;
2938                 }
2939                 return LDB_SUCCESS;
2940         }
2941
2942         /*
2943          * TODO:
2944          *
2945          * We should restrict this to the intersection of the list of
2946          * linked attributes in the schema and the list of attributes
2947          * being modified.
2948          *
2949          * This will help performance a little, as otherwise we have
2950          * to allocate the entire object value-by-value.
2951          */
2952         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2953                                     DSDB_FLAG_NEXT_MODULE |
2954                                     DSDB_SEARCH_SHOW_RECYCLED |
2955                                     DSDB_SEARCH_REVEAL_INTERNALS |
2956                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2957                                     parent);
2958         if (ret != LDB_SUCCESS) {
2959                 return ret;
2960         }
2961         schema = dsdb_get_schema(ldb, res);
2962         if (!schema) {
2963                 return LDB_ERR_OPERATIONS_ERROR;
2964         }
2965
2966         old_msg = res->msgs[0];
2967
2968         old_guid = samdb_result_guid(old_msg, "objectGUID");
2969
2970         for (i=0; i<msg->num_elements; i++) {
2971                 struct ldb_message_element *el = &msg->elements[i];
2972                 struct ldb_message_element *old_el, *new_el;
2973                 const struct dsdb_attribute *schema_attr
2974                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2975                 if (!schema_attr) {
2976                         ldb_asprintf_errstring(ldb,
2977                                                "%s: attribute %s is not a valid attribute in schema",
2978                                                __FUNCTION__, el->name);
2979                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2980                 }
2981                 if (schema_attr->linkID == 0) {
2982                         continue;
2983                 }
2984                 if ((schema_attr->linkID & 1) == 1) {
2985                         if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2986                                 continue;
2987                         }
2988                         /* Odd is for the target.  Illegal to modify */
2989                         ldb_asprintf_errstring(ldb,
2990                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2991                         return LDB_ERR_UNWILLING_TO_PERFORM;
2992                 }
2993                 old_el = ldb_msg_find_element(old_msg, el->name);
2994                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2995                 case LDB_FLAG_MOD_REPLACE:
2996                         ret = replmd_modify_la_replace(module, replmd_private,
2997                                                        schema, msg, el, old_el,
2998                                                        schema_attr, seq_num, t,
2999                                                        &old_guid, parent);
3000                         break;
3001                 case LDB_FLAG_MOD_DELETE:
3002                         ret = replmd_modify_la_delete(module, replmd_private,
3003                                                       schema, msg, el, old_el,
3004                                                       schema_attr, seq_num, t,
3005                                                       &old_guid, parent);
3006                         break;
3007                 case LDB_FLAG_MOD_ADD:
3008                         ret = replmd_modify_la_add(module, replmd_private,
3009                                                    schema, msg, el, old_el,
3010                                                    schema_attr, seq_num, t,
3011                                                    &old_guid, parent);
3012                         break;
3013                 default:
3014                         ldb_asprintf_errstring(ldb,
3015                                                "invalid flags 0x%x for %s linked attribute",
3016                                                el->flags, el->name);
3017                         return LDB_ERR_UNWILLING_TO_PERFORM;
3018                 }
3019                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3020                         ldb_asprintf_errstring(ldb,
3021                                                "Attribute %s is single valued but more than one value has been supplied",
3022                                                el->name);
3023                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3024                 } else {
3025                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3026                 }
3027
3028
3029
3030                 if (ret != LDB_SUCCESS) {
3031                         return ret;
3032                 }
3033                 if (old_el) {
3034                         ldb_msg_remove_attr(old_msg, el->name);
3035                 }
3036                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3037                 new_el->num_values = el->num_values;
3038                 new_el->values = talloc_steal(msg->elements, el->values);
3039
3040                 /* TODO: this relises a bit too heavily on the exact
3041                    behaviour of ldb_msg_find_element and
3042                    ldb_msg_remove_element */
3043                 old_el = ldb_msg_find_element(msg, el->name);
3044                 if (old_el != el) {
3045                         ldb_msg_remove_element(msg, old_el);
3046                         i--;
3047                 }
3048         }
3049
3050         talloc_free(res);
3051         return ret;
3052 }
3053
3054
3055
3056 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3057 {
3058         struct ldb_context *ldb;
3059         struct replmd_replicated_request *ac;
3060         struct ldb_request *down_req;
3061         struct ldb_message *msg;
3062         time_t t = time(NULL);
3063         int ret;
3064         bool is_urgent = false, rodc = false;
3065         bool is_schema_nc = false;
3066         unsigned int functional_level;
3067         const struct ldb_message_element *guid_el = NULL;
3068         struct ldb_control *sd_propagation_control;
3069         struct replmd_private *replmd_private =
3070                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3071
3072         /* do not manipulate our control entries */
3073         if (ldb_dn_is_special(req->op.mod.message->dn)) {
3074                 return ldb_next_request(module, req);
3075         }
3076
3077         sd_propagation_control = ldb_request_get_control(req,
3078                                         DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3079         if (sd_propagation_control != NULL) {
3080                 if (req->op.mod.message->num_elements != 1) {
3081                         return ldb_module_operr(module);
3082                 }
3083                 ret = strcmp(req->op.mod.message->elements[0].name,
3084                              "nTSecurityDescriptor");
3085                 if (ret != 0) {
3086                         return ldb_module_operr(module);
3087                 }
3088
3089                 return ldb_next_request(module, req);
3090         }
3091
3092         ldb = ldb_module_get_ctx(module);
3093
3094         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3095
3096         guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3097         if (guid_el != NULL) {
3098                 ldb_set_errstring(ldb,
3099                                   "replmd_modify: it's not allowed to change the objectGUID!");
3100                 return LDB_ERR_CONSTRAINT_VIOLATION;
3101         }
3102
3103         ac = replmd_ctx_init(module, req);
3104         if (ac == NULL) {
3105                 return ldb_module_oom(module);
3106         }
3107
3108         functional_level = dsdb_functional_level(ldb);
3109
3110         /* we have to copy the message as the caller might have it as a const */
3111         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3112         if (msg == NULL) {
3113                 ldb_oom(ldb);
3114                 talloc_free(ac);
3115                 return LDB_ERR_OPERATIONS_ERROR;
3116         }
3117
3118         ldb_msg_remove_attr(msg, "whenChanged");
3119         ldb_msg_remove_attr(msg, "uSNChanged");
3120
3121         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3122
3123         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3124                                  msg, &ac->seq_num, t, is_schema_nc,
3125                                  &is_urgent, &rodc);
3126         if (rodc && (ret == LDB_ERR_REFERRAL)) {
3127                 struct loadparm_context *lp_ctx;
3128                 char *referral;
3129
3130                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3131                                          struct loadparm_context);
3132
3133                 referral = talloc_asprintf(req,
3134                                            "ldap://%s/%s",
3135                                            lpcfg_dnsdomain(lp_ctx),
3136                                            ldb_dn_get_linearized(msg->dn));
3137                 ret = ldb_module_send_referral(req, referral);
3138                 talloc_free(ac);
3139                 return ret;
3140         }
3141
3142         if (ret != LDB_SUCCESS) {
3143                 talloc_free(ac);
3144                 return ret;
3145         }
3146
3147         ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3148                                                   msg, ac->seq_num, t, req);
3149         if (ret != LDB_SUCCESS) {
3150                 talloc_free(ac);
3151                 return ret;
3152         }
3153
3154         /* TODO:
3155          * - replace the old object with the newly constructed one
3156          */
3157
3158         ac->is_urgent = is_urgent;
3159
3160         ret = ldb_build_mod_req(&down_req, ldb, ac,
3161                                 msg,
3162                                 req->controls,
3163                                 ac, replmd_op_callback,
3164                                 req);
3165         LDB_REQ_SET_LOCATION(down_req);
3166         if (ret != LDB_SUCCESS) {
3167                 talloc_free(ac);
3168                 return ret;
3169         }
3170
3171         /* current partition control is needed by "replmd_op_callback" */
3172         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3173                 ret = ldb_request_add_control(down_req,
3174                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
3175                                               false, NULL);
3176                 if (ret != LDB_SUCCESS) {
3177                         talloc_free(ac);
3178                         return ret;
3179                 }
3180         }
3181
3182         /* If we are in functional level 2000, then
3183          * replmd_modify_handle_linked_attribs will have done
3184          * nothing */
3185         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3186                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3187                 if (ret != LDB_SUCCESS) {
3188                         talloc_free(ac);
3189                         return ret;
3190                 }
3191         }
3192
3193         talloc_steal(down_req, msg);
3194
3195         /* we only change whenChanged and uSNChanged if the seq_num
3196            has changed */
3197         if (ac->seq_num != 0) {
3198                 ret = add_time_element(msg, "whenChanged", t);
3199                 if (ret != LDB_SUCCESS) {
3200                         talloc_free(ac);
3201                         ldb_operr(ldb);
3202                         return ret;
3203                 }
3204
3205                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3206                 if (ret != LDB_SUCCESS) {
3207                         talloc_free(ac);
3208                         ldb_operr(ldb);
3209                         return ret;
3210                 }
3211         }
3212
3213         /* go on with the call chain */
3214         return ldb_next_request(module, down_req);
3215 }
3216
3217 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3218
3219 /*
3220   handle a rename request
3221
3222   On a rename we need to do an extra ldb_modify which sets the
3223   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
3224  */
3225 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3226 {
3227         struct ldb_context *ldb;
3228         struct replmd_replicated_request *ac;
3229         int ret;
3230         struct ldb_request *down_req;
3231
3232         /* do not manipulate our control entries */
3233         if (ldb_dn_is_special(req->op.mod.message->dn)) {
3234                 return ldb_next_request(module, req);
3235         }
3236
3237         ldb = ldb_module_get_ctx(module);
3238
3239         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3240
3241         ac = replmd_ctx_init(module, req);
3242         if (ac == NULL) {
3243                 return ldb_module_oom(module);
3244         }
3245
3246         ret = ldb_build_rename_req(&down_req, ldb, ac,
3247                                    ac->req->op.rename.olddn,
3248                                    ac->req->op.rename.newdn,
3249                                    ac->req->controls,
3250                                    ac, replmd_rename_callback,
3251                                    ac->req);
3252         LDB_REQ_SET_LOCATION(down_req);
3253         if (ret != LDB_SUCCESS) {
3254                 talloc_free(ac);
3255                 return ret;
3256         }
3257
3258         /* go on with the call chain */
3259         return ldb_next_request(module, down_req);
3260 }
3261
3262 /* After the rename is compleated, update the whenchanged etc */
3263 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3264 {
3265         struct ldb_context *ldb;
3266         struct ldb_request *down_req;
3267         struct ldb_message *msg;
3268         const struct dsdb_attribute *rdn_attr;
3269         const char *rdn_name;
3270         const struct ldb_val *rdn_val;
3271         const char *attrs[5] = { NULL, };
3272         time_t t = time(NULL);
3273         int ret;
3274         bool is_urgent = false, rodc = false;
3275         bool is_schema_nc;
3276         struct replmd_replicated_request *ac =
3277                 talloc_get_type(req->context, struct replmd_replicated_request);
3278         struct replmd_private *replmd_private =
3279                 talloc_get_type(ldb_module_get_private(ac->module),
3280                                 struct replmd_private);
3281
3282         ldb = ldb_module_get_ctx(ac->module);
3283
3284         if (ares->error != LDB_SUCCESS) {
3285                 return ldb_module_done(ac->req, ares->controls,
3286                                         ares->response, ares->error);
3287         }
3288
3289         if (ares->type != LDB_REPLY_DONE) {
3290                 ldb_set_errstring(ldb,
3291                                   "invalid ldb_reply_type in callback");
3292                 talloc_free(ares);
3293                 return ldb_module_done(ac->req, NULL, NULL,
3294                                         LDB_ERR_OPERATIONS_ERROR);
3295         }
3296
3297         /* TODO:
3298          * - replace the old object with the newly constructed one
3299          */
3300
3301         msg = ldb_msg_new(ac);
3302         if (msg == NULL) {
3303                 ldb_oom(ldb);
3304                 return LDB_ERR_OPERATIONS_ERROR;
3305         }
3306
3307         msg->dn = ac->req->op.rename.newdn;
3308
3309         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3310
3311         rdn_name = ldb_dn_get_rdn_name(msg->dn);
3312         if (rdn_name == NULL) {
3313                 talloc_free(ares);
3314                 return ldb_module_done(ac->req, NULL, NULL,
3315                                        ldb_operr(ldb));
3316         }
3317
3318         /* normalize the rdn attribute name */
3319         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3320         if (rdn_attr == NULL) {
3321                 talloc_free(ares);
3322                 return ldb_module_done(ac->req, NULL, NULL,
3323                                        ldb_operr(ldb));
3324         }
3325         rdn_name = rdn_attr->lDAPDisplayName;
3326
3327         rdn_val = ldb_dn_get_rdn_val(msg->dn);
3328         if (rdn_val == NULL) {
3329                 talloc_free(ares);
3330                 return ldb_module_done(ac->req, NULL, NULL,
3331                                        ldb_operr(ldb));
3332         }
3333
3334         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3335                 talloc_free(ares);
3336                 return ldb_module_done(ac->req, NULL, NULL,
3337                                        ldb_oom(ldb));
3338         }
3339         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3340                 talloc_free(ares);
3341                 return ldb_module_done(ac->req, NULL, NULL,
3342                                        ldb_oom(ldb));
3343         }
3344         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3345                 talloc_free(ares);
3346                 return ldb_module_done(ac->req, NULL, NULL,
3347                                        ldb_oom(ldb));
3348         }
3349         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3350                 talloc_free(ares);
3351                 return ldb_module_done(ac->req, NULL, NULL,
3352                                        ldb_oom(ldb));
3353         }
3354
3355         /*
3356          * here we let replmd_update_rpmd() only search for
3357          * the existing "replPropertyMetaData" and rdn_name attributes.
3358          *
3359          * We do not want the existing "name" attribute as
3360          * the "name" attribute needs to get the version
3361          * updated on rename even if the rdn value hasn't changed.
3362          *
3363          * This is the diff of the meta data, for a moved user
3364          * on a w2k8r2 server:
3365          *
3366          * # record 1
3367          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3368          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3369          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
3370          *         version                  : 0x00000001 (1)
3371          *         reserved                 : 0x00000000 (0)
3372          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
3373          *                      local_usn                : 0x00000000000037a5 (14245)
3374          *                 array: struct replPropertyMetaData1
3375          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
3376          * -                    version                  : 0x00000001 (1)
3377          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
3378          * +                    version                  : 0x00000002 (2)
3379          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
3380          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3381          * -                    originating_usn          : 0x00000000000037a5 (14245)
3382          * -                    local_usn                : 0x00000000000037a5 (14245)
3383          * +                    originating_usn          : 0x0000000000003834 (14388)
3384          * +                    local_usn                : 0x0000000000003834 (14388)
3385          *                 array: struct replPropertyMetaData1
3386          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
3387          *                      version                  : 0x00000004 (4)
3388          */
3389         attrs[0] = "replPropertyMetaData";
3390         attrs[1] = "objectClass";
3391         attrs[2] = "instanceType";
3392         attrs[3] = rdn_name;
3393         attrs[4] = NULL;
3394
3395         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3396                                  msg, &ac->seq_num, t,
3397                                  is_schema_nc, &is_urgent, &rodc);
3398         if (rodc && (ret == LDB_ERR_REFERRAL)) {
3399                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
3400                 struct loadparm_context *lp_ctx;
3401                 char *referral;
3402
3403                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3404                                          struct loadparm_context);
3405
3406                 referral = talloc_asprintf(req,
3407                                            "ldap://%s/%s",
3408                                            lpcfg_dnsdomain(lp_ctx),
3409                                            ldb_dn_get_linearized(olddn));
3410                 ret = ldb_module_send_referral(req, referral);
3411                 talloc_free(ares);
3412                 return ldb_module_done(req, NULL, NULL, ret);
3413         }
3414
3415         if (ret != LDB_SUCCESS) {
3416                 talloc_free(ares);
3417                 return ldb_module_done(ac->req, NULL, NULL, ret);
3418         }
3419
3420         if (ac->seq_num == 0) {
3421                 talloc_free(ares);
3422                 return ldb_module_done(ac->req, NULL, NULL,
3423                                        ldb_error(ldb, ret,
3424                                         "internal error seq_num == 0"));
3425         }
3426         ac->is_urgent = is_urgent;
3427
3428         ret = ldb_build_mod_req(&down_req, ldb, ac,
3429                                 msg,
3430                                 req->controls,
3431                                 ac, replmd_op_callback,
3432                                 req);
3433         LDB_REQ_SET_LOCATION(down_req);
3434         if (ret != LDB_SUCCESS) {
3435                 talloc_free(ac);
3436                 return ret;
3437         }
3438
3439         /* current partition control is needed by "replmd_op_callback" */
3440         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3441                 ret = ldb_request_add_control(down_req,
3442                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
3443                                               false, NULL);
3444                 if (ret != LDB_SUCCESS) {
3445                         talloc_free(ac);
3446                         return ret;
3447                 }
3448         }
3449
3450         talloc_steal(down_req, msg);
3451
3452         ret = add_time_element(msg, "whenChanged", t);
3453         if (ret != LDB_SUCCESS) {
3454                 talloc_free(ac);
3455                 ldb_operr(ldb);
3456                 return ret;
3457         }
3458
3459         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3460         if (ret != LDB_SUCCESS) {
3461                 talloc_free(ac);
3462                 ldb_operr(ldb);
3463                 return ret;
3464         }
3465
3466         /* go on with the call chain - do the modify after the rename */
3467         return ldb_next_request(ac->module, down_req);
3468 }
3469
3470 /*
3471  * remove links from objects that point at this object when an object
3472  * is deleted.  We remove it from the NEXT module per MS-DRSR 5.160
3473  * RemoveObj which states that link removal due to the object being
3474  * deleted is NOT an originating update - they just go away!
3475  *
3476  */
3477 static int replmd_delete_remove_link(struct ldb_module *module,
3478                                      const struct dsdb_schema *schema,
3479                                      struct ldb_dn *dn,
3480                                      struct ldb_message_element *el,
3481                                      const struct dsdb_attribute *sa,
3482                                      struct ldb_request *parent)
3483 {
3484         unsigned int i;
3485         TALLOC_CTX *tmp_ctx = talloc_new(module);
3486         struct ldb_context *ldb = ldb_module_get_ctx(module);
3487
3488         for (i=0; i<el->num_values; i++) {
3489                 struct dsdb_dn *dsdb_dn;
3490                 NTSTATUS status;
3491                 int ret;
3492                 struct GUID guid2;
3493                 struct ldb_message *msg;
3494                 const struct dsdb_attribute *target_attr;
3495                 struct ldb_message_element *el2;
3496                 struct ldb_val dn_val;
3497                 uint32_t dsdb_flags = 0;
3498
3499                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3500                         continue;
3501                 }
3502
3503                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3504                 if (!dsdb_dn) {
3505                         talloc_free(tmp_ctx);
3506                         return LDB_ERR_OPERATIONS_ERROR;
3507                 }
3508
3509                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
3510                 if (!NT_STATUS_IS_OK(status)) {
3511                         talloc_free(tmp_ctx);
3512                         return LDB_ERR_OPERATIONS_ERROR;
3513                 }
3514
3515                 /* remove the link */
3516                 msg = ldb_msg_new(tmp_ctx);
3517                 if (!msg) {
3518                         ldb_module_oom(module);
3519                         talloc_free(tmp_ctx);
3520                         return LDB_ERR_OPERATIONS_ERROR;
3521                 }
3522
3523
3524                 msg->dn = dsdb_dn->dn;
3525
3526                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3527                 if (target_attr == NULL) {
3528                         continue;
3529                 }
3530
3531                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3532                 if (ret != LDB_SUCCESS) {
3533                         ldb_module_oom(module);
3534                         talloc_free(tmp_ctx);
3535                         return LDB_ERR_OPERATIONS_ERROR;
3536                 }
3537                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3538                 el2->values = &dn_val;
3539                 el2->num_values = 1;
3540
3541                 /*
3542                  * Ensure that we tell the modification to vanish any linked
3543                  * attributes (not simply mark them as isDeleted = TRUE)
3544                  */
3545                 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3546
3547                 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3548                 if (ret != LDB_SUCCESS) {
3549                         talloc_free(tmp_ctx);
3550                         return ret;
3551                 }
3552         }
3553         talloc_free(tmp_ctx);
3554         return LDB_SUCCESS;
3555 }
3556
3557
3558 /*
3559   handle update of replication meta data for deletion of objects
3560
3561   This also handles the mapping of delete to a rename operation
3562   to allow deletes to be replicated.
3563
3564   It also handles the incoming deleted objects, to ensure they are
3565   fully deleted here.  In that case re_delete is true, and we do not
3566   use this as a signal to change the deleted state, just reinforce it.
3567
3568  */
3569 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3570 {
3571         int ret = LDB_ERR_OTHER;
3572         bool retb, disallow_move_on_delete;
3573         struct ldb_dn *old_dn, *new_dn;
3574         const char *rdn_name;
3575         const struct ldb_val *rdn_value, *new_rdn_value;
3576         struct GUID guid;
3577         struct ldb_context *ldb = ldb_module_get_ctx(module);
3578         const struct dsdb_schema *schema;
3579         struct ldb_message *msg, *old_msg;
3580         struct ldb_message_element *el;
3581         TALLOC_CTX *tmp_ctx;
3582         struct ldb_result *res, *parent_res;
3583         static const char * const preserved_attrs[] = {
3584                 /* yes, this really is a hard coded list. See MS-ADTS
3585                    section 3.1.1.5.5.1.1 */
3586                 "attributeID",
3587                 "attributeSyntax",
3588                 "dNReferenceUpdate",
3589                 "dNSHostName",
3590                 "flatName",
3591                 "governsID",
3592                 "groupType",
3593                 "instanceType",
3594                 "lDAPDisplayName",
3595                 "legacyExchangeDN",
3596                 "isDeleted",
3597                 "isRecycled",
3598                 "lastKnownParent",
3599                 "msDS-LastKnownRDN",
3600                 "msDS-PortLDAP",
3601                 "mS-DS-CreatorSID",
3602                 "mSMQOwnerID",
3603                 "nCName",
3604                 "objectClass",
3605                 "distinguishedName",
3606                 "objectGUID",
3607                 "objectSid",
3608                 "oMSyntax",
3609                 "proxiedObjectName",
3610                 "name",
3611                 "nTSecurityDescriptor",
3612                 "replPropertyMetaData",
3613                 "sAMAccountName",
3614                 "securityIdentifier",
3615                 "sIDHistory",
3616                 "subClassOf",
3617                 "systemFlags",
3618                 "trustPartner",
3619                 "trustDirection",
3620                 "trustType",
3621                 "trustAttributes",
3622                 "userAccountControl",
3623                 "uSNChanged",
3624                 "uSNCreated",
3625                 "whenCreated",
3626                 "whenChanged",
3627                 NULL
3628         };
3629         static const char * const all_attrs[] = {
3630                 DSDB_SECRET_ATTRIBUTES,
3631                 "*",
3632                 NULL
3633         };
3634         unsigned int i, el_count = 0;
3635         uint32_t dsdb_flags = 0;
3636         enum deletion_state deletion_state, next_deletion_state;
3637
3638         if (ldb_dn_is_special(req->op.del.dn)) {
3639                 return ldb_next_request(module, req);
3640         }
3641
3642         /*
3643          * We have to allow dbcheck to remove an object that
3644          * is beyond repair, and to do so totally.  This could
3645          * mean we we can get a partial object from the other
3646          * DC, causing havoc, so dbcheck suggests
3647          * re-replication first.  dbcheck sets both DBCHECK
3648          * and RELAX in this situation.
3649          */
3650         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3651             && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3652                 /* really, really remove it */
3653                 return ldb_next_request(module, req);
3654         }
3655
3656         tmp_ctx = talloc_new(ldb);
3657         if (!tmp_ctx) {
3658                 ldb_oom(ldb);
3659                 return LDB_ERR_OPERATIONS_ERROR;
3660         }
3661
3662         schema = dsdb_get_schema(ldb, tmp_ctx);
3663         if (!schema) {
3664                 talloc_free(tmp_ctx);
3665                 return LDB_ERR_OPERATIONS_ERROR;
3666         }
3667
3668         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3669
3670         /* we need the complete msg off disk, so we can work out which
3671            attributes need to be removed */
3672         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3673                                     DSDB_FLAG_NEXT_MODULE |
3674                                     DSDB_SEARCH_SHOW_RECYCLED |
3675                                     DSDB_SEARCH_REVEAL_INTERNALS |
3676                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3677         if (ret != LDB_SUCCESS) {
3678                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3679                                        "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3680                                        re_delete ? "re-delete" : "delete",
3681                                        ldb_dn_get_linearized(old_dn),
3682                                        ldb_errstring(ldb_module_get_ctx(module)));
3683                 talloc_free(tmp_ctx);
3684                 return ret;
3685         }
3686         old_msg = res->msgs[0];
3687
3688         replmd_deletion_state(module, old_msg,
3689                               &deletion_state,
3690                               &next_deletion_state);
3691
3692         /* This supports us noticing an incoming isDeleted and acting on it */
3693         if (re_delete) {
3694                 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3695                 next_deletion_state = deletion_state;
3696         }
3697
3698         if (next_deletion_state == OBJECT_REMOVED) {
3699                 /*
3700                  * We have to prevent objects being deleted, even if
3701                  * the administrator really wants them gone, as
3702                  * without the tombstone, we can get a partial object
3703                  * from the other DC, causing havoc.
3704                  *
3705                  * The only other valid case is when the 180 day
3706                  * timeout has expired, when relax is specified.
3707                  */
3708                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3709                         /* it is already deleted - really remove it this time */
3710                         talloc_free(tmp_ctx);
3711                         return ldb_next_request(module, req);
3712                 }
3713
3714                 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s.  "
3715                                        "This check is to prevent corruption of the replicated state.",
3716                                        ldb_dn_get_linearized(old_msg->dn));
3717                 return LDB_ERR_UNWILLING_TO_PERFORM;
3718         }
3719
3720         rdn_name = ldb_dn_get_rdn_name(old_dn);
3721         rdn_value = ldb_dn_get_rdn_val(old_dn);
3722         if ((rdn_name == NULL) || (rdn_value == NULL)) {
3723                 talloc_free(tmp_ctx);
3724                 return ldb_operr(ldb);
3725         }
3726
3727         msg = ldb_msg_new(tmp_ctx);
3728         if (msg == NULL) {
3729                 ldb_module_oom(module);
3730                 talloc_free(tmp_ctx);
3731                 return LDB_ERR_OPERATIONS_ERROR;
3732         }
3733
3734         msg->dn = old_dn;
3735
3736         /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3737         disallow_move_on_delete =
3738                 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3739                  & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3740
3741         /* work out where we will be renaming this object to */
3742         if (!disallow_move_on_delete) {
3743                 struct ldb_dn *deleted_objects_dn;
3744                 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3745                                                   &deleted_objects_dn);
3746
3747                 /*
3748                  * We should not move objects if we can't find the
3749                  * deleted objects DN.  Not moving (or otherwise
3750                  * harming) the Deleted Objects DN itself is handled
3751                  * in the caller.
3752                  */
3753                 if (re_delete && (ret != LDB_SUCCESS)) {
3754                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3755                         if (new_dn == NULL) {
3756                                 ldb_module_oom(module);
3757                                 talloc_free(tmp_ctx);
3758                                 return LDB_ERR_OPERATIONS_ERROR;
3759                         }
3760                 } else if (ret != LDB_SUCCESS) {
3761                         /* this is probably an attempted delete on a partition
3762                          * that doesn't allow delete operations, such as the
3763                          * schema partition */
3764                         ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3765                                                ldb_dn_get_linearized(old_dn));
3766                         talloc_free(tmp_ctx);
3767                         return LDB_ERR_UNWILLING_TO_PERFORM;
3768                 } else {
3769                         new_dn = deleted_objects_dn;
3770                 }
3771         } else {
3772                 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3773                 if (new_dn == NULL) {
3774                         ldb_module_oom(module);
3775                         talloc_free(tmp_ctx);
3776                         return LDB_ERR_OPERATIONS_ERROR;
3777                 }
3778         }
3779
3780         if (deletion_state == OBJECT_NOT_DELETED) {
3781                 /* get the objects GUID from the search we just did */
3782                 guid = samdb_result_guid(old_msg, "objectGUID");
3783
3784                 /* Add a formatted child */
3785                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3786                                             rdn_name,
3787                                             ldb_dn_escape_value(tmp_ctx, *rdn_value),
3788                                             GUID_string(tmp_ctx, &guid));
3789                 if (!retb) {
3790                         ldb_asprintf_errstring(ldb, __location__
3791                                                ": Unable to add a formatted child to dn: %s",
3792                                                ldb_dn_get_linearized(new_dn));
3793                         talloc_free(tmp_ctx);
3794                         return LDB_ERR_OPERATIONS_ERROR;
3795                 }
3796
3797                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3798                 if (ret != LDB_SUCCESS) {
3799                         ldb_asprintf_errstring(ldb, __location__
3800                                                ": Failed to add isDeleted string to the msg");
3801                         talloc_free(tmp_ctx);
3802                         return ret;
3803                 }
3804                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3805         } else {
3806                 /*
3807                  * No matter what has happened with other renames etc, try again to
3808                  * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3809                  */
3810
3811                 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3812                 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3813                 if (!retb) {
3814                         ldb_asprintf_errstring(ldb, __location__
3815                                                ": Unable to add a prepare rdn of %s",
3816                                                ldb_dn_get_linearized(rdn));
3817                         talloc_free(tmp_ctx);
3818                         return LDB_ERR_OPERATIONS_ERROR;
3819                 }
3820                 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3821
3822                 retb = ldb_dn_add_child(new_dn, rdn);
3823                 if (!retb) {
3824                         ldb_asprintf_errstring(ldb, __location__
3825                                                ": Unable to add rdn %s to base dn: %s",
3826                                                ldb_dn_get_linearized(rdn),
3827                                                ldb_dn_get_linearized(new_dn));
3828                         talloc_free(tmp_ctx);
3829                         return LDB_ERR_OPERATIONS_ERROR;
3830                 }
3831         }
3832
3833         /*
3834           now we need to modify the object in the following ways:
3835
3836           - add isDeleted=TRUE
3837           - update rDN and name, with new rDN
3838           - remove linked attributes
3839           - remove objectCategory and sAMAccountType
3840           - remove attribs not on the preserved list
3841              - preserved if in above list, or is rDN
3842           - remove all linked attribs from this object
3843           - remove all links from other objects to this object
3844           - add lastKnownParent
3845           - update replPropertyMetaData?
3846
3847           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3848          */
3849
3850         if (deletion_state == OBJECT_NOT_DELETED) {
3851                 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3852                 char *parent_dn_str = NULL;
3853
3854                 /* we need the storage form of the parent GUID */
3855                 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3856                                             parent_dn, NULL,
3857                                             DSDB_FLAG_NEXT_MODULE |
3858                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3859                                             DSDB_SEARCH_REVEAL_INTERNALS|
3860                                             DSDB_SEARCH_SHOW_RECYCLED, req);
3861                 if (ret != LDB_SUCCESS) {
3862                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
3863                                                "repmd_delete: Failed to %s %s, "
3864                                                "because we failed to find it's parent (%s): %s",
3865                                                re_delete ? "re-delete" : "delete",
3866                                                ldb_dn_get_linearized(old_dn),
3867                                                ldb_dn_get_linearized(parent_dn),
3868                                                ldb_errstring(ldb_module_get_ctx(module)));
3869                         talloc_free(tmp_ctx);
3870                         return ret;
3871                 }
3872
3873                 /*
3874                  * Now we can use the DB version,
3875                  * it will have the extended DN info in it
3876                  */
3877                 parent_dn = parent_res->msgs[0]->dn;
3878                 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
3879                                                                parent_dn,
3880                                                                1);
3881                 if (parent_dn_str == NULL) {
3882                         talloc_free(tmp_ctx);
3883                         return ldb_module_oom(module);
3884                 }
3885
3886                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3887                                                parent_dn_str);
3888                 if (ret != LDB_SUCCESS) {
3889                         ldb_asprintf_errstring(ldb, __location__
3890                                                ": Failed to add lastKnownParent "
3891                                                "string when deleting %s",
3892                                                ldb_dn_get_linearized(old_dn));
3893                         talloc_free(tmp_ctx);
3894                         return ret;
3895                 }
3896                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3897
3898                 if (next_deletion_state == OBJECT_DELETED) {
3899                         ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3900                         if (ret != LDB_SUCCESS) {
3901                                 ldb_asprintf_errstring(ldb, __location__
3902                                                        ": Failed to add msDS-LastKnownRDN "
3903                                                        "string when deleting %s",
3904                                                        ldb_dn_get_linearized(old_dn));
3905                                 talloc_free(tmp_ctx);
3906                                 return ret;
3907                         }
3908                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3909                 }
3910         }
3911
3912         switch (next_deletion_state) {
3913
3914         case OBJECT_RECYCLED:
3915         case OBJECT_TOMBSTONE:
3916
3917                 /*
3918                  * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
3919                  * describes what must be removed from a tombstone
3920                  * object
3921                  *
3922                  * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
3923                  * describes what must be removed from a recycled
3924                  * object
3925                  *
3926                  */
3927
3928                 /*
3929                  * we also mark it as recycled, meaning this object can't be
3930                  * recovered (we are stripping its attributes).
3931                  * This is done only if we have this schema object of course ...
3932                  * This behavior is identical to the one of Windows 2008R2 which
3933                  * always set the isRecycled attribute, even if the recycle-bin is
3934                  * not activated and what ever the forest level is.
3935                  */
3936                 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3937                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3938                         if (ret != LDB_SUCCESS) {
3939                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3940                                 ldb_module_oom(module);
3941                                 talloc_free(tmp_ctx);
3942                                 return ret;
3943                         }
3944                         msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3945                 }
3946
3947                 /* work out which of the old attributes we will be removing */
3948                 for (i=0; i<old_msg->num_elements; i++) {
3949                         const struct dsdb_attribute *sa;
3950                         el = &old_msg->elements[i];
3951                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3952                         if (!sa) {
3953                                 talloc_free(tmp_ctx);
3954                                 return LDB_ERR_OPERATIONS_ERROR;
3955                         }
3956                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3957                                 /* don't remove the rDN */
3958                                 continue;
3959                         }
3960                         if (sa->linkID && (sa->linkID & 1)) {
3961                                 /*
3962                                   we have a backlink in this object
3963                                   that needs to be removed. We're not
3964                                   allowed to remove it directly
3965                                   however, so we instead setup a
3966                                   modify to delete the corresponding
3967                                   forward link
3968                                  */
3969                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3970                                 if (ret != LDB_SUCCESS) {
3971                                         const char *old_dn_str
3972                                                 = ldb_dn_get_linearized(old_dn);
3973                                         ldb_asprintf_errstring(ldb,
3974                                                                __location__
3975                                                                ": Failed to remove backlink of "
3976                                                                "%s when deleting %s: %s",
3977                                                                el->name,
3978                                                                old_dn_str,
3979                                                                ldb_errstring(ldb));
3980                                         talloc_free(tmp_ctx);
3981                                         return LDB_ERR_OPERATIONS_ERROR;
3982                                 }
3983                                 /* now we continue, which means we
3984                                    won't remove this backlink
3985                                    directly
3986                                 */
3987                                 continue;
3988                         }
3989                         if (!sa->linkID) {
3990                                 if (ldb_attr_in_list(preserved_attrs, el->name)) {
3991                                         continue;
3992                                 }
3993                                 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
3994                                         continue;
3995                                 }
3996                         } else {
3997                                 /*
3998                                  * Ensure that we tell the modification to vanish any linked
3999                                  * attributes (not simply mark them as isDeleted = TRUE)
4000                                  */
4001                                 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4002                         }
4003                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4004                         if (ret != LDB_SUCCESS) {
4005                                 talloc_free(tmp_ctx);
4006                                 ldb_module_oom(module);
4007                                 return ret;
4008                         }
4009                 }
4010
4011                 break;
4012
4013         case OBJECT_DELETED:
4014                 /*
4015                  * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4016                  * describes what must be removed from a deleted
4017                  * object
4018                  */
4019
4020                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4021                 if (ret != LDB_SUCCESS) {
4022                         talloc_free(tmp_ctx);
4023                         ldb_module_oom(module);
4024                         return ret;
4025                 }
4026
4027                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4028                 if (ret != LDB_SUCCESS) {
4029                         talloc_free(tmp_ctx);
4030                         ldb_module_oom(module);
4031                         return ret;
4032                 }
4033
4034                 break;
4035
4036         default:
4037                 break;
4038         }
4039
4040         if (deletion_state == OBJECT_NOT_DELETED) {
4041                 const struct dsdb_attribute *sa;
4042
4043                 /* work out what the new rdn value is, for updating the
4044                    rDN and name fields */
4045                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4046                 if (new_rdn_value == NULL) {
4047                         talloc_free(tmp_ctx);
4048                         return ldb_operr(ldb);
4049                 }
4050
4051                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4052                 if (!sa) {
4053                         talloc_free(tmp_ctx);
4054                         return LDB_ERR_OPERATIONS_ERROR;
4055                 }
4056
4057                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4058                                         &el);
4059                 if (ret != LDB_SUCCESS) {
4060                         talloc_free(tmp_ctx);
4061                         return ret;
4062                 }
4063                 el->flags = LDB_FLAG_MOD_REPLACE;
4064
4065                 el = ldb_msg_find_element(old_msg, "name");
4066                 if (el) {
4067                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4068                         if (ret != LDB_SUCCESS) {
4069                                 talloc_free(tmp_ctx);
4070                                 return ret;
4071                         }
4072                         el->flags = LDB_FLAG_MOD_REPLACE;
4073                 }
4074         }
4075
4076         /*
4077          * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4078          *
4079          */
4080
4081         /*
4082          * No matter what has happned with other renames, try again to
4083          * get this to be under the deleted DN.
4084          */
4085         if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4086                 /* now rename onto the new DN */
4087                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4088                 if (ret != LDB_SUCCESS){
4089                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4090                                  ldb_dn_get_linearized(old_dn),
4091                                  ldb_dn_get_linearized(new_dn),
4092                                  ldb_errstring(ldb)));
4093                         talloc_free(tmp_ctx);
4094                         return ret;
4095                 }
4096                 msg->dn = new_dn;
4097         }
4098
4099         ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4100         if (ret != LDB_SUCCESS) {
4101                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4102                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4103                 talloc_free(tmp_ctx);
4104                 return ret;
4105         }
4106
4107         talloc_free(tmp_ctx);
4108
4109         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4110 }
4111
4112 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4113 {
4114         return replmd_delete_internals(module, req, false);
4115 }
4116
4117
4118 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4119 {
4120         return ret;
4121 }
4122
4123 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4124 {
4125         int ret = LDB_ERR_OTHER;
4126         /* TODO: do some error mapping */
4127
4128         /* Let the caller know the full WERROR */
4129         ar->objs->error = status;
4130
4131         return ret;
4132 }
4133
4134
4135 static struct replPropertyMetaData1 *
4136 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4137                                         enum drsuapi_DsAttributeId attid)
4138 {
4139         uint32_t i;
4140         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4141
4142         for (i = 0; i < rpmd_ctr->count; i++) {
4143                 if (rpmd_ctr->array[i].attid == attid) {
4144                         return &rpmd_ctr->array[i];
4145                 }
4146         }
4147         return NULL;
4148 }
4149
4150
4151 /*
4152    return true if an update is newer than an existing entry
4153    see section 5.11 of MS-ADTS
4154 */
4155 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4156                                    const struct GUID *update_invocation_id,
4157                                    uint32_t current_version,
4158                                    uint32_t update_version,
4159                                    NTTIME current_change_time,
4160                                    NTTIME update_change_time)
4161 {
4162         if (update_version != current_version) {
4163                 return update_version > current_version;
4164         }
4165         if (update_change_time != current_change_time) {
4166                 return update_change_time > current_change_time;
4167         }
4168         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4169 }
4170
4171 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4172                                                   struct replPropertyMetaData1 *new_m)
4173 {
4174         return replmd_update_is_newer(&cur_m->originating_invocation_id,
4175                                       &new_m->originating_invocation_id,
4176                                       cur_m->version,
4177                                       new_m->version,
4178                                       cur_m->originating_change_time,
4179                                       new_m->originating_change_time);
4180 }
4181
4182 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4183                                                              struct replPropertyMetaData1 *cur_m,
4184                                                              struct replPropertyMetaData1 *new_m)
4185 {
4186         bool cmp;
4187
4188         /*
4189          * If the new replPropertyMetaData entry for this attribute is
4190          * not provided (this happens in the case where we look for
4191          * ATTID_name, but the name was not changed), then the local
4192          * state is clearly still current, as the remote
4193          * server didn't send it due to being older the high watermark
4194          * USN we sent.
4195          */
4196         if (new_m == NULL) {
4197                 return false;
4198         }
4199
4200         if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4201                 /*
4202                  * if we compare equal then do an
4203                  * update. This is used when a client
4204                  * asks for a FULL_SYNC, and can be
4205                  * used to recover a corrupt
4206                  * replica.
4207                  *
4208                  * This call is a bit tricky, what we
4209                  * are doing it turning the 'is_newer'
4210                  * call into a 'not is older' by
4211                  * swapping cur_m and new_m, and negating the
4212                  * outcome.
4213                  */
4214                 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4215                                                              cur_m);
4216         } else {
4217                 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4218                                                             new_m);
4219         }
4220         return cmp;
4221 }
4222
4223
4224 /*
4225   form a conflict DN
4226  */
4227 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4228 {
4229         const struct ldb_val *rdn_val;
4230         const char *rdn_name;
4231         struct ldb_dn *new_dn;
4232
4233         rdn_val = ldb_dn_get_rdn_val(dn);
4234         rdn_name = ldb_dn_get_rdn_name(dn);
4235         if (!rdn_val || !rdn_name) {
4236                 return NULL;
4237         }
4238
4239         new_dn = ldb_dn_copy(mem_ctx, dn);
4240         if (!new_dn) {
4241                 return NULL;
4242         }
4243
4244         if (!ldb_dn_remove_child_components(new_dn, 1)) {
4245                 return NULL;
4246         }
4247
4248         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4249                                   rdn_name,
4250                                   ldb_dn_escape_value(new_dn, *rdn_val),
4251                                   GUID_string(new_dn, guid))) {
4252                 return NULL;
4253         }
4254
4255         return new_dn;
4256 }
4257
4258
4259 /*
4260   perform a modify operation which sets the rDN and name attributes to
4261   their current values. This has the effect of changing these
4262   attributes to have been last updated by the current DC. This is
4263   needed to ensure that renames performed as part of conflict
4264   resolution are propogated to other DCs
4265  */
4266 static int replmd_name_modify(struct replmd_replicated_request *ar,
4267                               struct ldb_request *req, struct ldb_dn *dn)
4268 {
4269         struct ldb_message *msg;
4270         const char *rdn_name;
4271         const struct ldb_val *rdn_val;
4272         const struct dsdb_attribute *rdn_attr;
4273         int ret;
4274
4275         msg = ldb_msg_new(req);
4276         if (msg == NULL) {
4277                 goto failed;
4278         }
4279         msg->dn = dn;
4280
4281         rdn_name = ldb_dn_get_rdn_name(dn);
4282         if (rdn_name == NULL) {
4283                 goto failed;
4284         }
4285
4286         /* normalize the rdn attribute name */
4287         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4288         if (rdn_attr == NULL) {
4289                 goto failed;
4290         }
4291         rdn_name = rdn_attr->lDAPDisplayName;
4292
4293         rdn_val = ldb_dn_get_rdn_val(dn);
4294         if (rdn_val == NULL) {
4295                 goto failed;
4296         }
4297
4298         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4299                 goto failed;
4300         }
4301         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4302                 goto failed;
4303         }
4304         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4305                 goto failed;
4306         }
4307         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4308                 goto failed;
4309         }
4310
4311         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4312         if (ret != LDB_SUCCESS) {
4313                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
4314                          ldb_dn_get_linearized(dn),
4315                          ldb_errstring(ldb_module_get_ctx(ar->module))));
4316                 return ret;
4317         }
4318
4319         talloc_free(msg);
4320
4321         return LDB_SUCCESS;
4322
4323 failed:
4324         talloc_free(msg);
4325         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
4326                  ldb_dn_get_linearized(dn)));
4327         return LDB_ERR_OPERATIONS_ERROR;
4328 }
4329
4330
4331 /*
4332   callback for conflict DN handling where we have renamed the incoming
4333   record. After renaming it, we need to ensure the change of name and
4334   rDN for the incoming record is seen as an originating update by this DC.
4335
4336   This also handles updating lastKnownParent for entries sent to lostAndFound
4337  */
4338 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4339 {
4340         struct replmd_replicated_request *ar =
4341                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4342         struct ldb_dn *conflict_dn = NULL;
4343         int ret;
4344
4345         if (ares->error != LDB_SUCCESS) {
4346                 /* call the normal callback for everything except success */
4347                 return replmd_op_callback(req, ares);
4348         }
4349
4350         switch (req->operation) {
4351         case LDB_ADD:
4352                 conflict_dn = req->op.add.message->dn;
4353                 break;
4354         case LDB_MODIFY:
4355                 conflict_dn = req->op.mod.message->dn;
4356                 break;
4357         default:
4358                 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4359         }
4360
4361         /* perform a modify of the rDN and name of the record */
4362         ret = replmd_name_modify(ar, req, conflict_dn);
4363         if (ret != LDB_SUCCESS) {
4364                 ares->error = ret;
4365                 return replmd_op_callback(req, ares);
4366         }
4367
4368         if (ar->objs->objects[ar->index_current].last_known_parent) {
4369                 struct ldb_message *msg = ldb_msg_new(req);
4370                 if (msg == NULL) {
4371                         ldb_module_oom(ar->module);
4372                         return LDB_ERR_OPERATIONS_ERROR;
4373                 }
4374
4375                 msg->dn = req->op.add.message->dn;
4376
4377                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4378                                                ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4379                 if (ret != LDB_SUCCESS) {
4380                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4381                         ldb_module_oom(ar->module);
4382                         return ret;
4383                 }
4384                 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4385
4386                 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4387                 if (ret != LDB_SUCCESS) {
4388                         DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4389                                  ldb_dn_get_linearized(msg->dn),
4390                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
4391                         return ret;
4392                 }
4393                 TALLOC_FREE(msg);
4394         }
4395
4396         return replmd_op_callback(req, ares);
4397 }
4398
4399 /*
4400   callback for replmd_replicated_apply_add()
4401   This copes with the creation of conflict records in the case where
4402   the DN exists, but with a different objectGUID
4403  */
4404 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))
4405 {
4406         struct ldb_dn *conflict_dn;
4407         struct replmd_replicated_request *ar =
4408                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4409         struct ldb_result *res;
4410         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4411         int ret;
4412         const struct ldb_val *omd_value;
4413         struct replPropertyMetaDataBlob omd, *rmd;
4414         enum ndr_err_code ndr_err;
4415         bool rename_incoming_record, rodc;
4416         struct replPropertyMetaData1 *rmd_name, *omd_name;
4417         struct ldb_message *msg;
4418         struct ldb_request *down_req = NULL;
4419
4420         /* call the normal callback for success */
4421         if (ares->error == LDB_SUCCESS) {
4422                 return callback(req, ares);
4423         }
4424
4425         /*
4426          * we have a conflict, and need to decide if we will keep the
4427          * new record or the old record
4428          */
4429
4430         msg = ar->objs->objects[ar->index_current].msg;
4431         conflict_dn = msg->dn;
4432
4433         /* For failures other than conflicts, fail the whole operation here */
4434         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4435                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4436                                        ldb_dn_get_linearized(conflict_dn),
4437                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
4438
4439                 return ldb_module_done(ar->req, NULL, NULL,
4440                                        LDB_ERR_OPERATIONS_ERROR);
4441         }
4442
4443         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4444         if (ret != LDB_SUCCESS) {
4445                 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)));
4446                 return ldb_module_done(ar->req, NULL, NULL,
4447                                        LDB_ERR_OPERATIONS_ERROR);
4448
4449         }
4450
4451         if (rodc) {
4452                 /*
4453                  * We are on an RODC, or were a GC for this
4454                  * partition, so we have to fail this until
4455                  * someone who owns the partition sorts it
4456                  * out
4457                  */
4458                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4459                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
4460                                        " - We must fail the operation until a master for this partition resolves the conflict",
4461                                        ldb_dn_get_linearized(conflict_dn));
4462                 goto failed;
4463         }
4464
4465         /*
4466          * first we need the replPropertyMetaData attribute from the
4467          * local, conflicting record
4468          */
4469         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4470                                     attrs,
4471                                     DSDB_FLAG_NEXT_MODULE |
4472                                     DSDB_SEARCH_SHOW_DELETED |
4473                                     DSDB_SEARCH_SHOW_RECYCLED, req);
4474         if (ret != LDB_SUCCESS) {
4475                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4476                          ldb_dn_get_linearized(conflict_dn)));
4477                 goto failed;
4478         }
4479
4480         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4481         if (omd_value == NULL) {
4482                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4483                          ldb_dn_get_linearized(conflict_dn)));
4484                 goto failed;
4485         }
4486
4487         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4488                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4489         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4490                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4491                          ldb_dn_get_linearized(conflict_dn)));
4492                 goto failed;
4493         }
4494
4495         rmd = ar->objs->objects[ar->index_current].meta_data;
4496
4497         /*
4498          * we decide which is newer based on the RPMD on the name
4499          * attribute.  See [MS-DRSR] ResolveNameConflict.
4500          *
4501          * We expect omd_name to be present, as this is from a local
4502          * search, but while rmd_name should have been given to us by
4503          * the remote server, if it is missing we just prefer the
4504          * local name in
4505          * replmd_replPropertyMetaData1_new_should_be_taken()
4506          */
4507         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4508         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4509         if (!omd_name) {
4510                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4511                          ldb_dn_get_linearized(conflict_dn)));
4512                 goto failed;
4513         }
4514
4515         /*
4516          * Should we preserve the current record, and so rename the
4517          * incoming record to be a conflict?
4518          */
4519         rename_incoming_record
4520                 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4521                                                                     omd_name, rmd_name);
4522
4523         if (rename_incoming_record) {
4524                 struct GUID guid;
4525                 struct ldb_dn *new_dn;
4526
4527                 guid = samdb_result_guid(msg, "objectGUID");
4528                 if (GUID_all_zero(&guid)) {
4529                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4530                                  ldb_dn_get_linearized(conflict_dn)));
4531                         goto failed;
4532                 }
4533                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4534                 if (new_dn == NULL) {
4535                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4536                                  ldb_dn_get_linearized(conflict_dn)));
4537                         goto failed;
4538                 }
4539
4540                 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4541                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4542
4543                 /* re-submit the request, but with the new DN */
4544                 callback = replmd_op_name_modify_callback;
4545                 msg->dn = new_dn;
4546         } else {
4547                 /* we are renaming the existing record */
4548                 struct GUID guid;
4549                 struct ldb_dn *new_dn;
4550
4551                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4552                 if (GUID_all_zero(&guid)) {
4553                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4554                                  ldb_dn_get_linearized(conflict_dn)));
4555                         goto failed;
4556                 }
4557
4558                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4559                 if (new_dn == NULL) {
4560                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4561                                  ldb_dn_get_linearized(conflict_dn)));
4562                         goto failed;
4563                 }
4564
4565                 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4566                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4567
4568                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4569                                          DSDB_FLAG_OWN_MODULE, req);
4570                 if (ret != LDB_SUCCESS) {
4571                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4572                                  ldb_dn_get_linearized(conflict_dn),
4573                                  ldb_dn_get_linearized(new_dn),
4574                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
4575                         goto failed;
4576                 }
4577
4578                 /*
4579                  * now we need to ensure that the rename is seen as an
4580                  * originating update. We do that with a modify.
4581                  */
4582                 ret = replmd_name_modify(ar, req, new_dn);
4583                 if (ret != LDB_SUCCESS) {
4584                         goto failed;
4585                 }
4586
4587                 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4588                          ldb_dn_get_linearized(req->op.add.message->dn)));
4589         }
4590
4591         ret = ldb_build_add_req(&down_req,
4592                                 ldb_module_get_ctx(ar->module),
4593                                 req,
4594                                 msg,
4595                                 ar->controls,
4596                                 ar,
4597                                 callback,
4598                                 req);
4599         if (ret != LDB_SUCCESS) {
4600                 goto failed;
4601         }
4602         LDB_REQ_SET_LOCATION(down_req);
4603
4604         /* current partition control needed by "repmd_op_callback" */
4605         ret = ldb_request_add_control(down_req,
4606                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4607                                       false, NULL);
4608         if (ret != LDB_SUCCESS) {
4609                 return replmd_replicated_request_error(ar, ret);
4610         }
4611
4612         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4613                 /* this tells the partition module to make it a
4614                    partial replica if creating an NC */
4615                 ret = ldb_request_add_control(down_req,
4616                                               DSDB_CONTROL_PARTIAL_REPLICA,
4617                                               false, NULL);
4618                 if (ret != LDB_SUCCESS) {
4619                         return replmd_replicated_request_error(ar, ret);
4620                 }
4621         }
4622
4623         /*
4624          * Finally we re-run the add, otherwise the new record won't
4625          * exist, as we are here because of that exact failure!
4626          */
4627         return ldb_next_request(ar->module, down_req);
4628 failed:
4629
4630         /* on failure make the caller get the error. This means
4631          * replication will stop with an error, but there is not much
4632          * else we can do.
4633          */
4634         return ldb_module_done(ar->req, NULL, NULL,
4635                                ret);
4636 }
4637
4638 /*
4639   callback for replmd_replicated_apply_add()
4640   This copes with the creation of conflict records in the case where
4641   the DN exists, but with a different objectGUID
4642  */
4643 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4644 {
4645         struct replmd_replicated_request *ar =
4646                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4647
4648         if (ar->objs->objects[ar->index_current].last_known_parent) {
4649                 /* This is like a conflict DN, where we put the object in LostAndFound
4650                    see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4651                 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4652         }
4653
4654         return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4655 }
4656
4657 /*
4658   this is called when a new object comes in over DRS
4659  */
4660 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4661 {
4662         struct ldb_context *ldb;
4663         struct ldb_request *change_req;
4664         enum ndr_err_code ndr_err;
4665         struct ldb_message *msg;
4666         struct replPropertyMetaDataBlob *md;
4667         struct ldb_val md_value;
4668         unsigned int i;
4669         int ret;
4670         bool remote_isDeleted = false;
4671         bool is_schema_nc;
4672         NTTIME now;
4673         time_t t = time(NULL);
4674         const struct ldb_val *rdn_val;
4675         struct replmd_private *replmd_private =
4676                 talloc_get_type(ldb_module_get_private(ar->module),
4677                                 struct replmd_private);
4678         unix_to_nt_time(&now, t);
4679
4680         ldb = ldb_module_get_ctx(ar->module);
4681         msg = ar->objs->objects[ar->index_current].msg;
4682         md = ar->objs->objects[ar->index_current].meta_data;
4683         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4684
4685         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4686         if (ret != LDB_SUCCESS) {
4687                 return replmd_replicated_request_error(ar, ret);
4688         }
4689
4690         ret = dsdb_msg_add_guid(msg,
4691                                 &ar->objs->objects[ar->index_current].object_guid,
4692                                 "objectGUID");
4693         if (ret != LDB_SUCCESS) {
4694                 return replmd_replicated_request_error(ar, ret);
4695         }
4696
4697         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4698         if (ret != LDB_SUCCESS) {
4699                 return replmd_replicated_request_error(ar, ret);
4700         }
4701
4702         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4703         if (ret != LDB_SUCCESS) {
4704                 return replmd_replicated_request_error(ar, ret);
4705         }
4706
4707         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4708         if (ret != LDB_SUCCESS) {
4709                 return replmd_replicated_request_error(ar, ret);
4710         }
4711
4712         /* remove any message elements that have zero values */
4713         for (i=0; i<msg->num_elements; i++) {
4714                 struct ldb_message_element *el = &msg->elements[i];
4715
4716                 if (el->num_values == 0) {
4717                         if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4718                                 ldb_asprintf_errstring(ldb, __location__
4719                                                        ": empty objectClass sent on %s, aborting replication\n",
4720                                                        ldb_dn_get_linearized(msg->dn));
4721                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4722                         }
4723
4724                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4725                                  el->name));
4726                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4727                         msg->num_elements--;
4728                         i--;
4729                         continue;
4730                 }
4731         }
4732
4733         if (DEBUGLVL(4)) {
4734                 struct GUID_txt_buf guid_txt;
4735
4736                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4737                 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4738                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4739                           s));
4740                 talloc_free(s);
4741         }
4742
4743         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4744                                                      "isDeleted", false);
4745
4746         /*
4747          * the meta data array is already sorted by the caller, except
4748          * for the RDN, which needs to be added.
4749          */
4750
4751
4752         rdn_val = ldb_dn_get_rdn_val(msg->dn);
4753         ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4754                                      md, ar, now, is_schema_nc);
4755         if (ret != LDB_SUCCESS) {
4756                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4757                 return replmd_replicated_request_error(ar, ret);
4758         }
4759
4760         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4761         if (ret != LDB_SUCCESS) {
4762                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4763                 return replmd_replicated_request_error(ar, ret);
4764         }
4765
4766         for (i=0; i < md->ctr.ctr1.count; i++) {
4767                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4768         }
4769         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4770                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4771         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4772                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4773                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4774         }
4775         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4776         if (ret != LDB_SUCCESS) {
4777                 return replmd_replicated_request_error(ar, ret);
4778         }
4779
4780         replmd_ldb_message_sort(msg, ar->schema);
4781
4782         if (!remote_isDeleted) {
4783                 ret = dsdb_module_schedule_sd_propagation(ar->module,
4784                                                           ar->objs->partition_dn,
4785                                                           msg->dn, true);
4786                 if (ret != LDB_SUCCESS) {
4787                         return replmd_replicated_request_error(ar, ret);
4788                 }
4789         }
4790
4791         ar->isDeleted = remote_isDeleted;
4792
4793         ret = ldb_build_add_req(&change_req,
4794                                 ldb,
4795                                 ar,
4796                                 msg,
4797                                 ar->controls,
4798                                 ar,
4799                                 replmd_op_add_callback,
4800                                 ar->req);
4801         LDB_REQ_SET_LOCATION(change_req);
4802         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4803
4804         /* current partition control needed by "repmd_op_callback" */
4805         ret = ldb_request_add_control(change_req,
4806                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4807                                       false, NULL);
4808         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4809
4810         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4811                 /* this tells the partition module to make it a
4812                    partial replica if creating an NC */
4813                 ret = ldb_request_add_control(change_req,
4814                                               DSDB_CONTROL_PARTIAL_REPLICA,
4815                                               false, NULL);
4816                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4817         }
4818
4819         return ldb_next_request(ar->module, change_req);
4820 }
4821
4822 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4823                                                               struct ldb_reply *ares)
4824 {
4825         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4826                                                struct replmd_replicated_request);
4827         int ret;
4828
4829         if (!ares) {
4830                 return ldb_module_done(ar->req, NULL, NULL,
4831                                         LDB_ERR_OPERATIONS_ERROR);
4832         }
4833
4834         /*
4835          * The error NO_SUCH_OBJECT is not expected, unless the search
4836          * base is the partition DN, and that case doesn't happen here
4837          * because then we wouldn't get a parent_guid_value in any
4838          * case.
4839          */
4840         if (ares->error != LDB_SUCCESS) {
4841                 return ldb_module_done(ar->req, ares->controls,
4842                                         ares->response, ares->error);
4843         }
4844
4845         switch (ares->type) {
4846         case LDB_REPLY_ENTRY:
4847         {
4848                 struct ldb_message *parent_msg = ares->message;
4849                 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4850                 struct ldb_dn *parent_dn;
4851                 int comp_num;
4852
4853                 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4854                     && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4855                         /* Per MS-DRSR 4.1.10.6.10
4856                          * FindBestParentObject we need to move this
4857                          * new object under a deleted object to
4858                          * lost-and-found */
4859                         struct ldb_dn *nc_root;
4860
4861                         ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4862                         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4863                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4864                                                        "No suitable NC root found for %s.  "
4865                                                        "We need to move this object because parent object %s "
4866                                                        "is deleted, but this object is not.",
4867                                                        ldb_dn_get_linearized(msg->dn),
4868                                                        ldb_dn_get_linearized(parent_msg->dn));
4869                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4870                         } else if (ret != LDB_SUCCESS) {
4871                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4872                                                        "Unable to find NC root for %s: %s. "
4873                                                        "We need to move this object because parent object %s "
4874                                                        "is deleted, but this object is not.",
4875                                                        ldb_dn_get_linearized(msg->dn),
4876                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
4877                                                        ldb_dn_get_linearized(parent_msg->dn));
4878                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4879                         }
4880
4881                         ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
4882                                                 nc_root,
4883                                                 DS_GUID_LOSTANDFOUND_CONTAINER,
4884                                                 &parent_dn);
4885                         if (ret != LDB_SUCCESS) {
4886                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4887                                                        "Unable to find LostAndFound Container for %s "
4888                                                        "in partition %s: %s. "
4889                                                        "We need to move this object because parent object %s "
4890                                                        "is deleted, but this object is not.",
4891                                                        ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
4892                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
4893                                                        ldb_dn_get_linearized(parent_msg->dn));
4894                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4895                         }
4896                         ar->objs->objects[ar->index_current].last_known_parent
4897                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4898
4899                 } else {
4900                         parent_dn
4901                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4902
4903                 }
4904                 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
4905
4906                 comp_num = ldb_dn_get_comp_num(msg->dn);
4907                 if (comp_num > 1) {
4908                         if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
4909                                 talloc_free(ares);
4910                                 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4911                         }
4912                 }
4913                 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
4914                         talloc_free(ares);
4915                         return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4916                 }
4917                 break;
4918         }
4919         case LDB_REPLY_REFERRAL:
4920                 /* we ignore referrals */
4921                 break;
4922
4923         case LDB_REPLY_DONE:
4924
4925                 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
4926                         struct GUID_txt_buf str_buf;
4927                         if (ar->search_msg != NULL) {
4928                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4929                                                        "No parent with GUID %s found for object locally known as %s",
4930                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4931                                                        ldb_dn_get_linearized(ar->search_msg->dn));
4932                         } else {
4933                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4934                                                        "No parent with GUID %s found for object remotely known as %s",
4935                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4936                                                        ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
4937                         }
4938
4939                         /*
4940                          * This error code is really important, as it
4941                          * is the flag back to the callers to retry
4942                          * this with DRSUAPI_DRS_GET_ANC, and so get
4943                          * the parent objects before the child
4944                          * objects
4945                          */
4946                         return ldb_module_done(ar->req, NULL, NULL,
4947                                                replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
4948                 }
4949
4950                 if (ar->search_msg != NULL) {
4951                         ret = replmd_replicated_apply_merge(ar);
4952                 } else {
4953                         ret = replmd_replicated_apply_add(ar);
4954                 }
4955                 if (ret != LDB_SUCCESS) {
4956                         return ldb_module_done(ar->req, NULL, NULL, ret);
4957                 }
4958         }
4959
4960         talloc_free(ares);
4961         return LDB_SUCCESS;
4962 }
4963
4964 /*
4965  * Look for the parent object, so we put the new object in the right
4966  * place This is akin to NameObject in MS-DRSR - this routine and the
4967  * callbacks find the right parent name, and correct name for this
4968  * object
4969  */
4970
4971 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
4972 {
4973         struct ldb_context *ldb;
4974         int ret;
4975         char *tmp_str;
4976         char *filter;
4977         struct ldb_request *search_req;
4978         static const char *attrs[] = {"isDeleted", NULL};
4979         struct GUID_txt_buf guid_str_buf;
4980
4981         ldb = ldb_module_get_ctx(ar->module);
4982
4983         if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
4984                 if (ar->search_msg != NULL) {
4985                         return replmd_replicated_apply_merge(ar);
4986                 } else {
4987                         return replmd_replicated_apply_add(ar);
4988                 }
4989         }
4990
4991         tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
4992                                   &guid_str_buf);
4993
4994         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4995         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
4996
4997         ret = ldb_build_search_req(&search_req,
4998                                    ldb,
4999                                    ar,
5000                                    ar->objs->partition_dn,
5001                                    LDB_SCOPE_SUBTREE,
5002                                    filter,
5003                                    attrs,
5004                                    NULL,
5005                                    ar,
5006                                    replmd_replicated_apply_search_for_parent_callback,
5007                                    ar->req);
5008         LDB_REQ_SET_LOCATION(search_req);
5009
5010         ret = dsdb_request_add_controls(search_req,
5011                                         DSDB_SEARCH_SHOW_RECYCLED|
5012                                         DSDB_SEARCH_SHOW_DELETED|
5013                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
5014         if (ret != LDB_SUCCESS) {
5015                 return ret;
5016         }
5017
5018         return ldb_next_request(ar->module, search_req);
5019 }
5020
5021 /*
5022   handle renames that come in over DRS replication
5023  */
5024 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5025                                            struct ldb_message *msg,
5026                                            struct ldb_request *parent,
5027                                            bool *renamed)
5028 {
5029         int ret;
5030         TALLOC_CTX *tmp_ctx = talloc_new(msg);
5031         struct ldb_result *res;
5032         struct ldb_dn *conflict_dn;
5033         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5034         const struct ldb_val *omd_value;
5035         struct replPropertyMetaDataBlob omd, *rmd;
5036         enum ndr_err_code ndr_err;
5037         bool rename_incoming_record, rodc;
5038         struct replPropertyMetaData1 *rmd_name, *omd_name;
5039         struct ldb_dn *new_dn;
5040         struct GUID guid;
5041
5042         DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5043                  ldb_dn_get_linearized(ar->search_msg->dn),
5044                  ldb_dn_get_linearized(msg->dn)));
5045
5046
5047         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5048                                  DSDB_FLAG_NEXT_MODULE, ar->req);
5049         if (ret == LDB_SUCCESS) {
5050                 talloc_free(tmp_ctx);
5051                 *renamed = true;
5052                 return ret;
5053         }
5054
5055         if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5056                 talloc_free(tmp_ctx);
5057                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5058                                        ldb_dn_get_linearized(ar->search_msg->dn),
5059                                        ldb_dn_get_linearized(msg->dn),
5060                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
5061                 return ret;
5062         }
5063
5064         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5065         if (ret != LDB_SUCCESS) {
5066                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5067                                        "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5068                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
5069                 return LDB_ERR_OPERATIONS_ERROR;
5070         }
5071         /*
5072          * we have a conflict, and need to decide if we will keep the
5073          * new record or the old record
5074          */
5075
5076         conflict_dn = msg->dn;
5077
5078         if (rodc) {
5079                 /*
5080                  * We are on an RODC, or were a GC for this
5081                  * partition, so we have to fail this until
5082                  * someone who owns the partition sorts it
5083                  * out
5084                  */
5085                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5086                                        "Conflict adding object '%s' from incoming replication but we are read only for the partition.  \n"
5087                                        " - We must fail the operation until a master for this partition resolves the conflict",
5088                                        ldb_dn_get_linearized(conflict_dn));
5089                 goto failed;
5090         }
5091
5092         /*
5093          * first we need the replPropertyMetaData attribute from the
5094          * old record
5095          */
5096         ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5097                                     attrs,
5098                                     DSDB_FLAG_NEXT_MODULE |
5099                                     DSDB_SEARCH_SHOW_DELETED |
5100                                     DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5101         if (ret != LDB_SUCCESS) {
5102                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5103                          ldb_dn_get_linearized(conflict_dn)));
5104                 goto failed;
5105         }
5106
5107         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5108         if (omd_value == NULL) {
5109                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5110                          ldb_dn_get_linearized(conflict_dn)));
5111                 goto failed;
5112         }
5113
5114         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5115                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5116         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5117                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5118                          ldb_dn_get_linearized(conflict_dn)));
5119                 goto failed;
5120         }
5121
5122         rmd = ar->objs->objects[ar->index_current].meta_data;
5123
5124         /*
5125          * we decide which is newer based on the RPMD on the name
5126          * attribute.  See [MS-DRSR] ResolveNameConflict.
5127          *
5128          * We expect omd_name to be present, as this is from a local
5129          * search, but while rmd_name should have been given to us by
5130          * the remote server, if it is missing we just prefer the
5131          * local name in
5132          * replmd_replPropertyMetaData1_new_should_be_taken()
5133          */
5134         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5135         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5136         if (!omd_name) {
5137                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5138                          ldb_dn_get_linearized(conflict_dn)));
5139                 goto failed;
5140         }
5141
5142         /*
5143          * Should we preserve the current record, and so rename the
5144          * incoming record to be a conflict?
5145          */
5146         rename_incoming_record =
5147                 !replmd_replPropertyMetaData1_new_should_be_taken(
5148                         ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5149                         omd_name, rmd_name);
5150
5151         if (rename_incoming_record) {
5152
5153                 new_dn = replmd_conflict_dn(msg, msg->dn,
5154                                             &ar->objs->objects[ar->index_current].object_guid);
5155                 if (new_dn == NULL) {
5156                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5157                                                                   "Failed to form conflict DN for %s\n",
5158                                                                   ldb_dn_get_linearized(msg->dn));
5159
5160                         return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5161                 }
5162
5163                 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5164                                          DSDB_FLAG_NEXT_MODULE, ar->req);
5165                 if (ret != LDB_SUCCESS) {
5166                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5167                                                "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5168                                                ldb_dn_get_linearized(conflict_dn),
5169                                                ldb_dn_get_linearized(ar->search_msg->dn),
5170                                                ldb_dn_get_linearized(new_dn),
5171                                                ldb_errstring(ldb_module_get_ctx(ar->module)));
5172                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5173                 }
5174
5175                 msg->dn = new_dn;
5176                 *renamed = true;
5177                 return LDB_SUCCESS;
5178         }
5179
5180         /* we are renaming the existing record */
5181
5182         guid = samdb_result_guid(res->msgs[0], "objectGUID");
5183         if (GUID_all_zero(&guid)) {
5184                 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5185                          ldb_dn_get_linearized(conflict_dn)));
5186                 goto failed;
5187         }
5188
5189         new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5190         if (new_dn == NULL) {
5191                 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5192                          ldb_dn_get_linearized(conflict_dn)));
5193                 goto failed;
5194         }
5195
5196         DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5197                  ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5198
5199         ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5200                                  DSDB_FLAG_OWN_MODULE, ar->req);
5201         if (ret != LDB_SUCCESS) {
5202                 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5203                          ldb_dn_get_linearized(conflict_dn),
5204                          ldb_dn_get_linearized(new_dn),
5205                          ldb_errstring(ldb_module_get_ctx(ar->module))));
5206                 goto failed;
5207         }
5208
5209         /*
5210          * now we need to ensure that the rename is seen as an
5211          * originating update. We do that with a modify.
5212          */
5213         ret = replmd_name_modify(ar, ar->req, new_dn);
5214         if (ret != LDB_SUCCESS) {
5215                 goto failed;
5216         }
5217
5218         DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5219                  ldb_dn_get_linearized(ar->search_msg->dn),
5220                  ldb_dn_get_linearized(msg->dn)));
5221
5222
5223         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5224                                  DSDB_FLAG_NEXT_MODULE, ar->req);
5225         if (ret != LDB_SUCCESS) {
5226                 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5227                          ldb_dn_get_linearized(ar->search_msg->dn),
5228                          ldb_dn_get_linearized(msg->dn),
5229                          ldb_errstring(ldb_module_get_ctx(ar->module))));
5230                         goto failed;
5231         }
5232 failed:
5233
5234         /*
5235          * On failure make the caller get the error
5236          * This means replication will stop with an error,
5237          * but there is not much else we can do.  In the
5238          * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5239          * needed.
5240          */
5241
5242         talloc_free(tmp_ctx);
5243         return ret;
5244 }
5245
5246
5247 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5248 {
5249         struct ldb_context *ldb;
5250         struct ldb_request *change_req;
5251         enum ndr_err_code ndr_err;
5252         struct ldb_message *msg;
5253         struct replPropertyMetaDataBlob *rmd;
5254         struct replPropertyMetaDataBlob omd;
5255         const struct ldb_val *omd_value;
5256         struct replPropertyMetaDataBlob nmd;
5257         struct ldb_val nmd_value;
5258         struct GUID remote_parent_guid;
5259         unsigned int i;
5260         uint32_t j,ni=0;
5261         unsigned int removed_attrs = 0;
5262         int ret;
5263         int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5264         bool isDeleted = false;
5265         bool local_isDeleted = false;
5266         bool remote_isDeleted = false;
5267         bool take_remote_isDeleted = false;
5268         bool sd_updated = false;
5269         bool renamed = false;
5270         bool is_schema_nc = false;
5271         NTSTATUS nt_status;
5272         const struct ldb_val *old_rdn, *new_rdn;
5273         struct replmd_private *replmd_private =
5274                 talloc_get_type(ldb_module_get_private(ar->module),
5275                                 struct replmd_private);
5276         NTTIME now;
5277         time_t t = time(NULL);
5278         unix_to_nt_time(&now, t);
5279
5280         ldb = ldb_module_get_ctx(ar->module);
5281         msg = ar->objs->objects[ar->index_current].msg;
5282
5283         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5284
5285         rmd = ar->objs->objects[ar->index_current].meta_data;
5286         ZERO_STRUCT(omd);
5287         omd.version = 1;
5288
5289         /* find existing meta data */
5290         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5291         if (omd_value) {
5292                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5293                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5294                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5295                         nt_status = ndr_map_error2ntstatus(ndr_err);
5296                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5297                 }
5298
5299                 if (omd.version != 1) {
5300                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5301                 }
5302         }
5303
5304         if (DEBUGLVL(5)) {
5305                 struct GUID_txt_buf guid_txt;
5306
5307                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5308                 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5309                           "%s\n"
5310                           "%s\n",
5311                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5312                           s,
5313                           ndr_print_struct_string(s,
5314                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5315                                                   "existing replPropertyMetaData",
5316                                                   &omd),
5317                           ndr_print_struct_string(s,
5318                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5319                                                   "incoming replPropertyMetaData",
5320                                                   rmd)));
5321                 talloc_free(s);
5322         }
5323
5324         local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5325                                                     "isDeleted", false);
5326         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5327                                                      "isDeleted", false);
5328
5329         /*
5330          * Fill in the remote_parent_guid with the GUID or an all-zero
5331          * GUID.
5332          */
5333         if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5334                 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5335         } else {
5336                 remote_parent_guid = GUID_zero();
5337         }
5338
5339         /*
5340          * To ensure we follow a complex rename chain around, we have
5341          * to confirm that the DN is the same (mostly to confirm the
5342          * RDN) and the parentGUID is the same.
5343          *
5344          * This ensures we keep things under the correct parent, which
5345          * replmd_replicated_handle_rename() will do.
5346          */
5347
5348         if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5349             && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5350                 ret = LDB_SUCCESS;
5351         } else {
5352                 /*
5353                  * handle renames, even just by case that come in over
5354                  * DRS.  Changes in the parent DN don't hit us here,
5355                  * because the search for a parent will clean up those
5356                  * components.
5357                  *
5358                  * We also have already filtered out the case where
5359                  * the peer has an older name to what we have (see
5360                  * replmd_replicated_apply_search_callback())
5361                  */
5362                 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5363         }
5364
5365         if (ret != LDB_SUCCESS) {
5366                 ldb_debug(ldb, LDB_DEBUG_FATAL,
5367                           "replmd_replicated_request rename %s => %s failed - %s\n",
5368                           ldb_dn_get_linearized(ar->search_msg->dn),
5369                           ldb_dn_get_linearized(msg->dn),
5370                           ldb_errstring(ldb));
5371                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5372         }
5373
5374         if (renamed == true) {
5375                 /*
5376                  * Set the callback to one that will fix up the name
5377                  * metadata on the new conflict DN
5378                  */
5379                 callback = replmd_op_name_modify_callback;
5380         }
5381
5382         ZERO_STRUCT(nmd);
5383         nmd.version = 1;
5384         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5385         nmd.ctr.ctr1.array = talloc_array(ar,
5386                                           struct replPropertyMetaData1,
5387                                           nmd.ctr.ctr1.count);
5388         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5389
5390         /* first copy the old meta data */
5391         for (i=0; i < omd.ctr.ctr1.count; i++) {
5392                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
5393                 ni++;
5394         }
5395
5396         ar->seq_num = 0;
5397         /* now merge in the new meta data */
5398         for (i=0; i < rmd->ctr.ctr1.count; i++) {
5399                 bool found = false;
5400
5401                 for (j=0; j < ni; j++) {
5402                         bool cmp;
5403
5404                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5405                                 continue;
5406                         }
5407
5408                         cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5409                                 ar->objs->dsdb_repl_flags,
5410                                 &nmd.ctr.ctr1.array[j],
5411                                 &rmd->ctr.ctr1.array[i]);
5412                         if (cmp) {
5413                                 /* replace the entry */
5414                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5415                                 if (ar->seq_num == 0) {
5416                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5417                                         if (ret != LDB_SUCCESS) {
5418                                                 return replmd_replicated_request_error(ar, ret);
5419                                         }
5420                                 }
5421                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5422                                 switch (nmd.ctr.ctr1.array[j].attid) {
5423                                 case DRSUAPI_ATTID_ntSecurityDescriptor:
5424                                         sd_updated = true;
5425                                         break;
5426                                 case DRSUAPI_ATTID_isDeleted:
5427                                         take_remote_isDeleted = true;
5428                                         break;
5429                                 default:
5430                                         break;
5431                                 }
5432                                 found = true;
5433                                 break;
5434                         }
5435
5436                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5437                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5438                                          msg->elements[i-removed_attrs].name,
5439                                          ldb_dn_get_linearized(msg->dn),
5440                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5441                         }
5442
5443                         /* we don't want to apply this change so remove the attribute */
5444                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5445                         removed_attrs++;
5446
5447                         found = true;
5448                         break;
5449                 }
5450
5451                 if (found) continue;
5452
5453                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5454                 if (ar->seq_num == 0) {
5455                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5456                         if (ret != LDB_SUCCESS) {
5457                                 return replmd_replicated_request_error(ar, ret);
5458                         }
5459                 }
5460                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5461                 switch (nmd.ctr.ctr1.array[ni].attid) {
5462                 case DRSUAPI_ATTID_ntSecurityDescriptor:
5463                         sd_updated = true;
5464                         break;
5465                 case DRSUAPI_ATTID_isDeleted:
5466                         take_remote_isDeleted = true;
5467                         break;
5468                 default:
5469                         break;
5470                 }
5471                 ni++;
5472         }
5473
5474         /*
5475          * finally correct the size of the meta_data array
5476          */
5477         nmd.ctr.ctr1.count = ni;
5478
5479         new_rdn = ldb_dn_get_rdn_val(msg->dn);
5480         old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5481
5482         if (renamed) {
5483                 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5484                                                   &nmd, ar, now, is_schema_nc);
5485                 if (ret != LDB_SUCCESS) {
5486                         ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5487                         return replmd_replicated_request_error(ar, ret);
5488                 }
5489         }
5490         /*
5491          * sort the new meta data array
5492          */
5493         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5494         if (ret != LDB_SUCCESS) {
5495                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5496                 return ret;
5497         }
5498
5499         /*
5500          * Work out if this object is deleted, so we can prune any extra attributes.  See MS-DRSR 4.1.10.6.9
5501          * UpdateObject.
5502          *
5503          * This also controls SD propagation below
5504          */
5505         if (take_remote_isDeleted) {
5506                 isDeleted = remote_isDeleted;
5507         } else {
5508                 isDeleted = local_isDeleted;
5509         }
5510
5511         ar->isDeleted = isDeleted;
5512
5513         /*
5514          * check if some replicated attributes left, otherwise skip the ldb_modify() call
5515          */
5516         if (msg->num_elements == 0) {
5517                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5518                           ar->index_current);
5519
5520                 return replmd_replicated_apply_isDeleted(ar);
5521         }
5522
5523         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5524                   ar->index_current, msg->num_elements);
5525
5526         if (renamed) {
5527                 sd_updated = true;
5528         }
5529
5530         if (sd_updated && !isDeleted) {
5531                 ret = dsdb_module_schedule_sd_propagation(ar->module,
5532                                                           ar->objs->partition_dn,
5533                                                           msg->dn, true);
5534                 if (ret != LDB_SUCCESS) {
5535                         return ldb_operr(ldb);
5536                 }
5537         }
5538
5539         /* create the meta data value */
5540         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5541                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5542         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5543                 nt_status = ndr_map_error2ntstatus(ndr_err);
5544                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5545         }
5546
5547         /*
5548          * when we know that we'll modify the record, add the whenChanged, uSNChanged
5549          * and replPopertyMetaData attributes
5550          */
5551         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5552         if (ret != LDB_SUCCESS) {
5553                 return replmd_replicated_request_error(ar, ret);
5554         }
5555         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5556         if (ret != LDB_SUCCESS) {
5557                 return replmd_replicated_request_error(ar, ret);
5558         }
5559         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5560         if (ret != LDB_SUCCESS) {
5561                 return replmd_replicated_request_error(ar, ret);
5562         }
5563
5564         replmd_ldb_message_sort(msg, ar->schema);
5565
5566         /* we want to replace the old values */
5567         for (i=0; i < msg->num_elements; i++) {
5568                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5569                 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5570                         if (msg->elements[i].num_values == 0) {
5571                                 ldb_asprintf_errstring(ldb, __location__
5572                                                        ": objectClass removed on %s, aborting replication\n",
5573                                                        ldb_dn_get_linearized(msg->dn));
5574                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5575                         }
5576                 }
5577         }
5578
5579         if (DEBUGLVL(4)) {
5580                 struct GUID_txt_buf guid_txt;
5581
5582                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5583                 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5584                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5585                           s));
5586                 talloc_free(s);
5587         }
5588
5589         ret = ldb_build_mod_req(&change_req,
5590                                 ldb,
5591                                 ar,
5592                                 msg,
5593                                 ar->controls,
5594                                 ar,
5595                                 callback,
5596                                 ar->req);
5597         LDB_REQ_SET_LOCATION(change_req);
5598         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5599
5600         /* current partition control needed by "repmd_op_callback" */
5601         ret = ldb_request_add_control(change_req,
5602                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
5603                                       false, NULL);
5604         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5605
5606         return ldb_next_request(ar->module, change_req);
5607 }
5608
5609 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5610                                                    struct ldb_reply *ares)
5611 {
5612         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5613                                                struct replmd_replicated_request);
5614         int ret;
5615
5616         if (!ares) {
5617                 return ldb_module_done(ar->req, NULL, NULL,
5618                                         LDB_ERR_OPERATIONS_ERROR);
5619         }
5620         if (ares->error != LDB_SUCCESS &&
5621             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5622                 return ldb_module_done(ar->req, ares->controls,
5623                                         ares->response, ares->error);
5624         }
5625
5626         switch (ares->type) {
5627         case LDB_REPLY_ENTRY:
5628                 ar->search_msg = talloc_steal(ar, ares->message);
5629                 break;
5630
5631         case LDB_REPLY_REFERRAL:
5632                 /* we ignore referrals */
5633                 break;
5634
5635         case LDB_REPLY_DONE:
5636         {
5637                 struct replPropertyMetaData1 *md_remote;
5638                 struct replPropertyMetaData1 *md_local;
5639
5640                 struct replPropertyMetaDataBlob omd;
5641                 const struct ldb_val *omd_value;
5642                 struct replPropertyMetaDataBlob *rmd;
5643                 struct ldb_message *msg;
5644                 int instanceType;
5645                 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5646                 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5647
5648                 /*
5649                  * This is the ADD case, find the appropriate parent,
5650                  * as this object doesn't exist locally:
5651                  */
5652                 if (ar->search_msg == NULL) {
5653                         ret = replmd_replicated_apply_search_for_parent(ar);
5654                         if (ret != LDB_SUCCESS) {
5655                                 return ldb_module_done(ar->req, NULL, NULL, ret);
5656                         }
5657                         talloc_free(ares);
5658                         return LDB_SUCCESS;
5659                 }
5660
5661                 /*
5662                  * Otherwise, in the MERGE case, work out if we are
5663                  * attempting a rename, and if so find the parent the
5664                  * newly renamed object wants to belong under (which
5665                  * may not be the parent in it's attached string DN
5666                  */
5667                 rmd = ar->objs->objects[ar->index_current].meta_data;
5668                 ZERO_STRUCT(omd);
5669                 omd.version = 1;
5670
5671                 /* find existing meta data */
5672                 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5673                 if (omd_value) {
5674                         enum ndr_err_code ndr_err;
5675                         ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5676                                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5677                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5678                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5679                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5680                         }
5681
5682                         if (omd.version != 1) {
5683                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5684                         }
5685                 }
5686
5687                 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5688
5689                 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5690                 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5691                     && GUID_all_zero(&ar->local_parent_guid)) {
5692                         DEBUG(0, ("Refusing to replicate new version of %s "
5693                                   "as local object has an all-zero parentGUID attribute, "
5694                                   "despite not being an NC root\n",
5695                                   ldb_dn_get_linearized(ar->search_msg->dn)));
5696                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5697                 }
5698
5699                 /*
5700                  * now we need to check for double renames. We could have a
5701                  * local rename pending which our replication partner hasn't
5702                  * received yet. We choose which one wins by looking at the
5703                  * attribute stamps on the two objects, the newer one wins.
5704                  *
5705                  * This also simply applies the correct algorithms for
5706                  * determining if a change was made to name at all, or
5707                  * if the object has just been renamed under the same
5708                  * parent.
5709                  */
5710                 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5711                 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5712                 if (!md_local) {
5713                         DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5714                                  ldb_dn_get_linearized(ar->search_msg->dn)));
5715                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5716                 }
5717
5718                 /*
5719                  * if there is no name attribute given then we have to assume the
5720                  *  object we've received has the older name
5721                  */
5722                 if (replmd_replPropertyMetaData1_new_should_be_taken(
5723                             ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5724                             md_local, md_remote)) {
5725                         struct GUID_txt_buf p_guid_local;
5726                         struct GUID_txt_buf p_guid_remote;
5727                         msg = ar->objs->objects[ar->index_current].msg;
5728
5729                         /* Merge on the existing object, with rename */
5730
5731                         DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5732                                  "as incoming object changing to %s under %s\n",
5733                                  ldb_dn_get_linearized(ar->search_msg->dn),
5734                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5735                                  ldb_dn_get_linearized(msg->dn),
5736                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5737                                                  &p_guid_remote)));
5738                         ret = replmd_replicated_apply_search_for_parent(ar);
5739                 } else {
5740                         struct GUID_txt_buf p_guid_local;
5741                         struct GUID_txt_buf p_guid_remote;
5742                         msg = ar->objs->objects[ar->index_current].msg;
5743
5744                         /*
5745                          * Merge on the existing object, force no
5746                          * rename (code below just to explain why in
5747                          * the DEBUG() logs)
5748                          */
5749
5750                         if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5751                                    ldb_dn_get_linearized(msg->dn)) == 0) {
5752                                 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5753                                     GUID_equal(&ar->local_parent_guid,
5754                                                ar->objs->objects[ar->index_current].parent_guid)
5755                                     == false) {
5756                                         DEBUG(4,(__location__ ": Keeping object %s at under %s "
5757                                                  "despite incoming object changing parent to %s\n",
5758                                                  ldb_dn_get_linearized(ar->search_msg->dn),
5759                                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5760                                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5761                                                                  &p_guid_remote)));
5762                                 }
5763                         } else {
5764                                 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5765                                          " and rejecting older rename to %s under %s\n",
5766                                          ldb_dn_get_linearized(ar->search_msg->dn),
5767                                          GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5768                                          ldb_dn_get_linearized(msg->dn),
5769                                          GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5770                                                          &p_guid_remote)));
5771                         }
5772                         /*
5773                          * This assignment ensures that the strcmp()
5774                          * and GUID_equal() calls in
5775                          * replmd_replicated_apply_merge() avoids the
5776                          * rename call
5777                          */
5778                         ar->objs->objects[ar->index_current].parent_guid =
5779                                 &ar->local_parent_guid;
5780
5781                         msg->dn = ar->search_msg->dn;
5782                         ret = replmd_replicated_apply_merge(ar);
5783                 }
5784                 if (ret != LDB_SUCCESS) {
5785                         return ldb_module_done(ar->req, NULL, NULL, ret);
5786                 }
5787         }
5788         }
5789
5790         talloc_free(ares);
5791         return LDB_SUCCESS;
5792 }
5793
5794 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5795
5796 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5797 {
5798         struct ldb_context *ldb;
5799         int ret;
5800         char *tmp_str;
5801         char *filter;
5802         struct ldb_request *search_req;
5803         static const char *attrs[] = { "repsFrom", "replUpToDateVector",
5804                                        "parentGUID", "instanceType",
5805                                        "replPropertyMetaData", "nTSecurityDescriptor",
5806                                        "isDeleted", NULL };
5807         struct GUID_txt_buf guid_str_buf;
5808
5809         if (ar->index_current >= ar->objs->num_objects) {
5810                 /* done with it, go to next stage */
5811                 return replmd_replicated_uptodate_vector(ar);
5812         }
5813
5814         ldb = ldb_module_get_ctx(ar->module);
5815         ar->search_msg = NULL;
5816         ar->isDeleted = false;
5817
5818         tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5819                                   &guid_str_buf);
5820
5821         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5822         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5823
5824         ret = ldb_build_search_req(&search_req,
5825                                    ldb,
5826                                    ar,
5827                                    ar->objs->partition_dn,
5828                                    LDB_SCOPE_SUBTREE,
5829                                    filter,
5830                                    attrs,
5831                                    NULL,
5832                                    ar,
5833                                    replmd_replicated_apply_search_callback,
5834                                    ar->req);
5835         LDB_REQ_SET_LOCATION(search_req);
5836
5837         ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5838
5839         if (ret != LDB_SUCCESS) {
5840                 return ret;
5841         }
5842
5843         return ldb_next_request(ar->module, search_req);
5844 }
5845
5846 /*
5847  * This is essentially a wrapper for replmd_replicated_apply_next()
5848  *
5849  * This is needed to ensure that both codepaths call this handler.
5850  */
5851 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5852 {
5853         struct ldb_dn *deleted_objects_dn;
5854         struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5855         int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5856                                               &deleted_objects_dn);
5857         if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5858                 /*
5859                  * Do a delete here again, so that if there is
5860                  * anything local that conflicts with this
5861                  * object being deleted, it is removed.  This
5862                  * includes links.  See MS-DRSR 4.1.10.6.9
5863                  * UpdateObject.
5864                  *
5865                  * If the object is already deleted, and there
5866                  * is no more work required, it doesn't do
5867                  * anything.
5868                  */
5869
5870                 /* This has been updated to point to the DN we eventually did the modify on */
5871
5872                 struct ldb_request *del_req;
5873                 struct ldb_result *res;
5874
5875                 TALLOC_CTX *tmp_ctx = talloc_new(ar);
5876                 if (!tmp_ctx) {
5877                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
5878                         return ret;
5879                 }
5880
5881                 res = talloc_zero(tmp_ctx, struct ldb_result);
5882                 if (!res) {
5883                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
5884                         talloc_free(tmp_ctx);
5885                         return ret;
5886                 }
5887
5888                 /* Build a delete request, which hopefully will artually turn into nothing */
5889                 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
5890                                         msg->dn,
5891                                         NULL,
5892                                         res,
5893                                         ldb_modify_default_callback,
5894                                         ar->req);
5895                 LDB_REQ_SET_LOCATION(del_req);
5896                 if (ret != LDB_SUCCESS) {
5897                         talloc_free(tmp_ctx);
5898                         return ret;
5899                 }
5900
5901                 /*
5902                  * This is the guts of the call, call back
5903                  * into our delete code, but setting the
5904                  * re_delete flag so we delete anything that
5905                  * shouldn't be there on a deleted or recycled
5906                  * object
5907                  */
5908                 ret = replmd_delete_internals(ar->module, del_req, true);
5909                 if (ret == LDB_SUCCESS) {
5910                         ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
5911                 }
5912
5913                 talloc_free(tmp_ctx);
5914                 if (ret != LDB_SUCCESS) {
5915                         return ret;
5916                 }
5917         }
5918
5919         ar->index_current++;
5920         return replmd_replicated_apply_next(ar);
5921 }
5922
5923 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
5924                                                       struct ldb_reply *ares)
5925 {
5926         struct ldb_context *ldb;
5927         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5928                                                struct replmd_replicated_request);
5929         ldb = ldb_module_get_ctx(ar->module);
5930
5931         if (!ares) {
5932                 return ldb_module_done(ar->req, NULL, NULL,
5933                                         LDB_ERR_OPERATIONS_ERROR);
5934         }
5935         if (ares->error != LDB_SUCCESS) {
5936                 return ldb_module_done(ar->req, ares->controls,
5937                                         ares->response, ares->error);
5938         }
5939
5940         if (ares->type != LDB_REPLY_DONE) {
5941                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
5942                 return ldb_module_done(ar->req, NULL, NULL,
5943                                         LDB_ERR_OPERATIONS_ERROR);
5944         }
5945
5946         talloc_free(ares);
5947
5948         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5949 }
5950
5951 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
5952 {
5953         struct ldb_context *ldb;
5954         struct ldb_request *change_req;
5955         enum ndr_err_code ndr_err;
5956         struct ldb_message *msg;
5957         struct replUpToDateVectorBlob ouv;
5958         const struct ldb_val *ouv_value;
5959         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
5960         struct replUpToDateVectorBlob nuv;
5961         struct ldb_val nuv_value;
5962         struct ldb_message_element *nuv_el = NULL;
5963         struct ldb_message_element *orf_el = NULL;
5964         struct repsFromToBlob nrf;
5965         struct ldb_val *nrf_value = NULL;
5966         struct ldb_message_element *nrf_el = NULL;
5967         unsigned int i;
5968         uint32_t j,ni=0;
5969         bool found = false;
5970         time_t t = time(NULL);
5971         NTTIME now;
5972         int ret;
5973         uint32_t instanceType;
5974
5975         ldb = ldb_module_get_ctx(ar->module);
5976         ruv = ar->objs->uptodateness_vector;
5977         ZERO_STRUCT(ouv);
5978         ouv.version = 2;
5979         ZERO_STRUCT(nuv);
5980         nuv.version = 2;
5981
5982         unix_to_nt_time(&now, t);
5983
5984         if (ar->search_msg == NULL) {
5985                 /* this happens for a REPL_OBJ call where we are
5986                    creating the target object by replicating it. The
5987                    subdomain join code does this for the partition DN
5988                 */
5989                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
5990                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5991         }
5992
5993         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
5994         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
5995                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
5996                          ldb_dn_get_linearized(ar->search_msg->dn)));
5997                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5998         }
5999
6000         /*
6001          * first create the new replUpToDateVector
6002          */
6003         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6004         if (ouv_value) {
6005                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6006                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6007                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6008                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6009                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6010                 }
6011
6012                 if (ouv.version != 2) {
6013                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6014                 }
6015         }
6016
6017         /*
6018          * the new uptodateness vector will at least
6019          * contain 1 entry, one for the source_dsa
6020          *
6021          * plus optional values from our old vector and the one from the source_dsa
6022          */
6023         nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6024         if (ruv) nuv.ctr.ctr2.count += ruv->count;
6025         nuv.ctr.ctr2.cursors = talloc_array(ar,
6026                                             struct drsuapi_DsReplicaCursor2,
6027                                             nuv.ctr.ctr2.count);
6028         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6029
6030         /* first copy the old vector */
6031         for (i=0; i < ouv.ctr.ctr2.count; i++) {
6032                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6033                 ni++;
6034         }
6035
6036         /* merge in the source_dsa vector is available */
6037         for (i=0; (ruv && i < ruv->count); i++) {
6038                 found = false;
6039
6040                 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6041                                &ar->our_invocation_id)) {
6042                         continue;
6043                 }
6044
6045                 for (j=0; j < ni; j++) {
6046                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6047                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6048                                 continue;
6049                         }
6050
6051                         found = true;
6052
6053                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6054                                 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6055                         }
6056                         break;
6057                 }
6058
6059                 if (found) continue;
6060
6061                 /* if it's not there yet, add it */
6062                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6063                 ni++;
6064         }
6065
6066         /*
6067          * finally correct the size of the cursors array
6068          */
6069         nuv.ctr.ctr2.count = ni;
6070
6071         /*
6072          * sort the cursors
6073          */
6074         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6075
6076         /*
6077          * create the change ldb_message
6078          */
6079         msg = ldb_msg_new(ar);
6080         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6081         msg->dn = ar->search_msg->dn;
6082
6083         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6084                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6085         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6086                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6087                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6088         }
6089         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6090         if (ret != LDB_SUCCESS) {
6091                 return replmd_replicated_request_error(ar, ret);
6092         }
6093         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6094
6095         /*
6096          * now create the new repsFrom value from the given repsFromTo1 structure
6097          */
6098         ZERO_STRUCT(nrf);
6099         nrf.version                                     = 1;
6100         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
6101         nrf.ctr.ctr1.last_attempt                       = now;
6102         nrf.ctr.ctr1.last_success                       = now;
6103         nrf.ctr.ctr1.result_last_attempt                = WERR_OK;
6104
6105         /*
6106          * first see if we already have a repsFrom value for the current source dsa
6107          * if so we'll later replace this value
6108          */
6109         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6110         if (orf_el) {
6111                 for (i=0; i < orf_el->num_values; i++) {
6112                         struct repsFromToBlob *trf;
6113
6114                         trf = talloc(ar, struct repsFromToBlob);
6115                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6116
6117                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6118                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6119                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6120                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6121                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6122                         }
6123
6124                         if (trf->version != 1) {
6125                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6126                         }
6127
6128                         /*
6129                          * we compare the source dsa objectGUID not the invocation_id
6130                          * because we want only one repsFrom value per source dsa
6131                          * and when the invocation_id of the source dsa has changed we don't need
6132                          * the old repsFrom with the old invocation_id
6133                          */
6134                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6135                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
6136                                 talloc_free(trf);
6137                                 continue;
6138                         }
6139
6140                         talloc_free(trf);
6141                         nrf_value = &orf_el->values[i];
6142                         break;
6143                 }
6144
6145                 /*
6146                  * copy over all old values to the new ldb_message
6147                  */
6148                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6149                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6150                 *nrf_el = *orf_el;
6151         }
6152
6153         /*
6154          * if we haven't found an old repsFrom value for the current source dsa
6155          * we'll add a new value
6156          */
6157         if (!nrf_value) {
6158                 struct ldb_val zero_value;
6159                 ZERO_STRUCT(zero_value);
6160                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6161                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6162
6163                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6164         }
6165
6166         /* we now fill the value which is already attached to ldb_message */
6167         ndr_err = ndr_push_struct_blob(nrf_value, msg,
6168                                        &nrf,
6169                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6170         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6171                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6172                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6173         }
6174
6175         /*
6176          * the ldb_message_element for the attribute, has all the old values and the new one
6177          * so we'll replace the whole attribute with all values
6178          */
6179         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6180
6181         if (CHECK_DEBUGLVL(4)) {
6182                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6183                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6184                 talloc_free(s);
6185         }
6186
6187         /* prepare the ldb_modify() request */
6188         ret = ldb_build_mod_req(&change_req,
6189                                 ldb,
6190                                 ar,
6191                                 msg,
6192                                 ar->controls,
6193                                 ar,
6194                                 replmd_replicated_uptodate_modify_callback,
6195                                 ar->req);
6196         LDB_REQ_SET_LOCATION(change_req);
6197         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6198
6199         return ldb_next_request(ar->module, change_req);
6200 }
6201
6202 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6203                                                       struct ldb_reply *ares)
6204 {
6205         struct replmd_replicated_request *ar = talloc_get_type(req->context,
6206                                                struct replmd_replicated_request);
6207         int ret;
6208
6209         if (!ares) {
6210                 return ldb_module_done(ar->req, NULL, NULL,
6211                                         LDB_ERR_OPERATIONS_ERROR);
6212         }
6213         if (ares->error != LDB_SUCCESS &&
6214             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6215                 return ldb_module_done(ar->req, ares->controls,
6216                                         ares->response, ares->error);
6217         }
6218
6219         switch (ares->type) {
6220         case LDB_REPLY_ENTRY:
6221                 ar->search_msg = talloc_steal(ar, ares->message);
6222                 break;
6223
6224         case LDB_REPLY_REFERRAL:
6225                 /* we ignore referrals */
6226                 break;
6227
6228         case LDB_REPLY_DONE:
6229                 ret = replmd_replicated_uptodate_modify(ar);
6230                 if (ret != LDB_SUCCESS) {
6231                         return ldb_module_done(ar->req, NULL, NULL, ret);
6232                 }
6233         }
6234
6235         talloc_free(ares);
6236         return LDB_SUCCESS;
6237 }
6238
6239
6240 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6241 {
6242         struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6243         struct replmd_private *replmd_private =
6244                 talloc_get_type_abort(ldb_module_get_private(ar->module),
6245                 struct replmd_private);
6246         int ret;
6247         static const char *attrs[] = {
6248                 "replUpToDateVector",
6249                 "repsFrom",
6250                 "instanceType",
6251                 NULL
6252         };
6253         struct ldb_request *search_req;
6254
6255         ar->search_msg = NULL;
6256
6257         /*
6258          * Let the caller know that we did an originating updates
6259          */
6260         ar->objs->originating_updates = replmd_private->originating_updates;
6261
6262         ret = ldb_build_search_req(&search_req,
6263                                    ldb,
6264                                    ar,
6265                                    ar->objs->partition_dn,
6266                                    LDB_SCOPE_BASE,
6267                                    "(objectClass=*)",
6268                                    attrs,
6269                                    NULL,
6270                                    ar,
6271                                    replmd_replicated_uptodate_search_callback,
6272                                    ar->req);
6273         LDB_REQ_SET_LOCATION(search_req);
6274         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6275
6276         return ldb_next_request(ar->module, search_req);
6277 }
6278
6279
6280
6281 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6282 {
6283         struct ldb_context *ldb;
6284         struct dsdb_extended_replicated_objects *objs;
6285         struct replmd_replicated_request *ar;
6286         struct ldb_control **ctrls;
6287         int ret;
6288         uint32_t i;
6289         struct replmd_private *replmd_private =
6290                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6291
6292         ldb = ldb_module_get_ctx(module);
6293
6294         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6295
6296         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6297         if (!objs) {
6298                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6299                 return LDB_ERR_PROTOCOL_ERROR;
6300         }
6301
6302         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6303                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6304                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6305                 return LDB_ERR_PROTOCOL_ERROR;
6306         }
6307
6308         ar = replmd_ctx_init(module, req);
6309         if (!ar)
6310                 return LDB_ERR_OPERATIONS_ERROR;
6311
6312         /* Set the flags to have the replmd_op_callback run over the full set of objects */
6313         ar->apply_mode = true;
6314         ar->objs = objs;
6315         ar->schema = dsdb_get_schema(ldb, ar);
6316         if (!ar->schema) {
6317                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6318                 talloc_free(ar);
6319                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6320                 return LDB_ERR_CONSTRAINT_VIOLATION;
6321         }
6322
6323         ctrls = req->controls;
6324
6325         if (req->controls) {
6326                 req->controls = talloc_memdup(ar, req->controls,
6327                                               talloc_get_size(req->controls));
6328                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6329         }
6330
6331         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6332         if (ret != LDB_SUCCESS) {
6333                 return ret;
6334         }
6335
6336         /* If this change contained linked attributes in the body
6337          * (rather than in the links section) we need to update
6338          * backlinks in linked_attributes */
6339         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6340         if (ret != LDB_SUCCESS) {
6341                 return ret;
6342         }
6343
6344         ar->controls = req->controls;
6345         req->controls = ctrls;
6346
6347         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6348
6349         /* save away the linked attributes for the end of the
6350            transaction */
6351         for (i=0; i<ar->objs->linked_attributes_count; i++) {
6352                 struct la_entry *la_entry;
6353
6354                 if (replmd_private->la_ctx == NULL) {
6355                         replmd_private->la_ctx = talloc_new(replmd_private);
6356                 }
6357                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6358                 if (la_entry == NULL) {
6359                         ldb_oom(ldb);
6360                         return LDB_ERR_OPERATIONS_ERROR;
6361                 }
6362                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6363                 if (la_entry->la == NULL) {
6364                         talloc_free(la_entry);
6365                         ldb_oom(ldb);
6366                         return LDB_ERR_OPERATIONS_ERROR;
6367                 }
6368                 *la_entry->la = ar->objs->linked_attributes[i];
6369
6370                 /* we need to steal the non-scalars so they stay
6371                    around until the end of the transaction */
6372                 talloc_steal(la_entry->la, la_entry->la->identifier);
6373                 talloc_steal(la_entry->la, la_entry->la->value.blob);
6374
6375                 DLIST_ADD(replmd_private->la_list, la_entry);
6376         }
6377
6378         return replmd_replicated_apply_next(ar);
6379 }
6380
6381 /*
6382   process one linked attribute structure
6383  */
6384 static int replmd_process_linked_attribute(struct ldb_module *module,
6385                                            struct replmd_private *replmd_private,
6386                                            struct la_entry *la_entry,
6387                                            struct ldb_request *parent)
6388 {
6389         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6390         struct ldb_context *ldb = ldb_module_get_ctx(module);
6391         struct ldb_message *msg;
6392         struct ldb_message *target_msg = NULL;
6393         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6394         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6395         int ret;
6396         const struct dsdb_attribute *attr;
6397         struct dsdb_dn *dsdb_dn;
6398         uint64_t seq_num = 0;
6399         struct ldb_message_element *old_el;
6400         WERROR status;
6401         time_t t = time(NULL);
6402         struct ldb_result *res;
6403         struct ldb_result *target_res;
6404         const char *attrs[4];
6405         const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6406         struct parsed_dn *pdn_list, *pdn, *next;
6407         struct GUID guid = GUID_zero();
6408         NTSTATUS ntstatus;
6409         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6410         const struct GUID *our_invocation_id;
6411
6412         enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6413         enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6414
6415 /*
6416 linked_attributes[0]:
6417      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6418         identifier               : *
6419             identifier: struct drsuapi_DsReplicaObjectIdentifier
6420                 __ndr_size               : 0x0000003a (58)
6421                 __ndr_size_sid           : 0x00000000 (0)
6422                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6423                 sid                      : S-0-0
6424                 __ndr_size_dn            : 0x00000000 (0)
6425                 dn                       : ''
6426         attid                    : DRSUAPI_ATTID_member (0x1F)
6427         value: struct drsuapi_DsAttributeValue
6428             __ndr_size               : 0x0000007e (126)
6429             blob                     : *
6430                 blob                     : DATA_BLOB length=126
6431         flags                    : 0x00000001 (1)
6432                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6433         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
6434         meta_data: struct drsuapi_DsReplicaMetaData
6435             version                  : 0x00000015 (21)
6436             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
6437             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6438             originating_usn          : 0x000000000001e19c (123292)
6439
6440 (for cases where the link is to a normal DN)
6441      &target: struct drsuapi_DsReplicaObjectIdentifier3
6442         __ndr_size               : 0x0000007e (126)
6443         __ndr_size_sid           : 0x0000001c (28)
6444         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
6445         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
6446         __ndr_size_dn            : 0x00000022 (34)
6447         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6448  */
6449
6450         /* find the attribute being modified */
6451         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6452         if (attr == NULL) {
6453                 struct GUID_txt_buf guid_str;
6454                 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6455                                        la->attid,
6456                                        GUID_buf_string(&la->identifier->guid,
6457                                                        &guid_str));
6458                 talloc_free(tmp_ctx);
6459                 return LDB_ERR_OPERATIONS_ERROR;
6460         }
6461
6462         attrs[0] = attr->lDAPDisplayName;
6463         attrs[1] = "isDeleted";
6464         attrs[2] = "isRecycled";
6465         attrs[3] = NULL;
6466
6467         /* get the existing message from the db for the object with
6468            this GUID, returning attribute being modified. We will then
6469            use this msg as the basis for a modify call */
6470         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6471                                  DSDB_FLAG_NEXT_MODULE |
6472                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6473                                  DSDB_SEARCH_SHOW_RECYCLED |
6474                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6475                                  DSDB_SEARCH_REVEAL_INTERNALS,
6476                                  parent,
6477                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6478         if (ret != LDB_SUCCESS) {
6479                 talloc_free(tmp_ctx);
6480                 return ret;
6481         }
6482         if (res->count != 1) {
6483                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6484                                        GUID_string(tmp_ctx, &la->identifier->guid));
6485                 talloc_free(tmp_ctx);
6486                 return LDB_ERR_NO_SUCH_OBJECT;
6487         }
6488         msg = res->msgs[0];
6489
6490         /*
6491          * Check for deleted objects per MS-DRSR 4.1.10.6.13
6492          * ProcessLinkValue, because link updates are not applied to
6493          * recycled and tombstone objects.  We don't have to delete
6494          * any existing link, that should have happened when the
6495          * object deletion was replicated or initiated.
6496          */
6497
6498         replmd_deletion_state(module, msg, &deletion_state, NULL);
6499
6500         if (deletion_state >= OBJECT_RECYCLED) {
6501                 talloc_free(tmp_ctx);
6502                 return LDB_SUCCESS;
6503         }
6504
6505         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6506         if (old_el == NULL) {
6507                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6508                 if (ret != LDB_SUCCESS) {
6509                         ldb_module_oom(module);
6510                         talloc_free(tmp_ctx);
6511                         return LDB_ERR_OPERATIONS_ERROR;
6512                 }
6513         } else {
6514                 old_el->flags = LDB_FLAG_MOD_REPLACE;
6515         }
6516
6517         /* parse the existing links */
6518         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
6519         if (ret != LDB_SUCCESS) {
6520                 talloc_free(tmp_ctx);
6521                 return ret;
6522         }
6523
6524         /* get our invocationId */
6525         our_invocation_id = samdb_ntds_invocation_id(ldb);
6526         if (!our_invocation_id) {
6527                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
6528                 talloc_free(tmp_ctx);
6529                 return LDB_ERR_OPERATIONS_ERROR;
6530         }
6531
6532         ret = replmd_check_upgrade_links(ldb, pdn_list, old_el->num_values,
6533                                          old_el, our_invocation_id,
6534                                          attr->syntax->ldap_oid);
6535         if (ret != LDB_SUCCESS) {
6536                 talloc_free(tmp_ctx);
6537                 return ret;
6538         }
6539
6540         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6541         if (!W_ERROR_IS_OK(status)) {
6542                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6543                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6544                 talloc_free(tmp_ctx);
6545                 return LDB_ERR_OPERATIONS_ERROR;
6546         }
6547
6548         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6549         if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6550                 /*
6551                  * This strange behaviour (allowing a NULL/missing
6552                  * GUID) originally comes from:
6553                  *
6554                  * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6555                  * Author: Andrew Tridgell <tridge@samba.org>
6556                  * Date:   Mon Dec 21 21:21:55 2009 +1100
6557                  *
6558                  *  s4-drs: cope better with NULL GUIDS from DRS
6559                  *
6560                  *  It is valid to get a NULL GUID over DRS for a deleted forward link. We
6561                  *  need to match by DN if possible when seeing if we should update an
6562                  *  existing link.
6563                  *
6564                  *  Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6565                  */
6566
6567                 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6568                                             dsdb_dn->dn, attrs2,
6569                                             DSDB_FLAG_NEXT_MODULE |
6570                                             DSDB_SEARCH_SHOW_RECYCLED |
6571                                             DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6572                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6573                                             parent);
6574         } else if (!NT_STATUS_IS_OK(ntstatus)) {
6575                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6576                                        old_el->name,
6577                                        ldb_dn_get_linearized(dsdb_dn->dn),
6578                                        ldb_dn_get_linearized(msg->dn));
6579                 talloc_free(tmp_ctx);
6580                 return LDB_ERR_OPERATIONS_ERROR;
6581         } else {
6582                 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6583                                          NULL, LDB_SCOPE_SUBTREE,
6584                                          attrs2,
6585                                          DSDB_FLAG_NEXT_MODULE |
6586                                          DSDB_SEARCH_SHOW_RECYCLED |
6587                                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6588                                          DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6589                                          parent,
6590                                          "objectGUID=%s",
6591                                          GUID_string(tmp_ctx, &guid));
6592         }
6593
6594         if (ret != LDB_SUCCESS) {
6595                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6596                                        GUID_string(tmp_ctx, &guid),
6597                                        ldb_errstring(ldb_module_get_ctx(module)));
6598                 talloc_free(tmp_ctx);
6599                 return ret;
6600         }
6601
6602         if (target_res->count == 0) {
6603                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6604                          GUID_string(tmp_ctx, &guid),
6605                          ldb_dn_get_linearized(dsdb_dn->dn)));
6606         } else if (target_res->count != 1) {
6607                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6608                                        GUID_string(tmp_ctx, &guid));
6609                 talloc_free(tmp_ctx);
6610                 return LDB_ERR_OPERATIONS_ERROR;
6611         } else {
6612                 target_msg = target_res->msgs[0];
6613                 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6614         }
6615
6616         /*
6617          * Check for deleted objects per MS-DRSR 4.1.10.6.13
6618          * ProcessLinkValue, because link updates are not applied to
6619          * recycled and tombstone objects.  We don't have to delete
6620          * any existing link, that should have happened when the
6621          * object deletion was replicated or initiated.
6622          */
6623         replmd_deletion_state(module, target_msg,
6624                               &target_deletion_state, NULL);
6625
6626         if (target_deletion_state >= OBJECT_RECYCLED) {
6627                 talloc_free(tmp_ctx);
6628                 return LDB_SUCCESS;
6629         }
6630
6631         /* see if this link already exists */
6632         ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6633                              &guid,
6634                              dsdb_dn->dn,
6635                              &pdn, &next,
6636                              attr->syntax->ldap_oid);
6637         if (ret != LDB_SUCCESS) {
6638                 talloc_free(tmp_ctx);
6639                 return ret;
6640         }
6641
6642
6643         if (pdn != NULL) {
6644                 /* see if this update is newer than what we have already */
6645                 struct GUID invocation_id = GUID_zero();
6646                 uint32_t version = 0;
6647                 uint32_t originating_usn = 0;
6648                 NTTIME change_time = 0;
6649                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6650
6651                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6652                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6653                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6654                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6655
6656                 if (!replmd_update_is_newer(&invocation_id,
6657                                             &la->meta_data.originating_invocation_id,
6658                                             version,
6659                                             la->meta_data.version,
6660                                             change_time,
6661                                             la->meta_data.originating_change_time)) {
6662                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6663                                  old_el->name, ldb_dn_get_linearized(msg->dn),
6664                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6665                         talloc_free(tmp_ctx);
6666                         return LDB_SUCCESS;
6667                 }
6668
6669                 /* get a seq_num for this change */
6670                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6671                 if (ret != LDB_SUCCESS) {
6672                         talloc_free(tmp_ctx);
6673                         return ret;
6674                 }
6675
6676                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6677                         /* remove the existing backlink */
6678                         ret = replmd_add_backlink(module, replmd_private,
6679                                                   schema, &la->identifier->guid,
6680                                                   &guid, false, attr, true);
6681                         if (ret != LDB_SUCCESS) {
6682                                 talloc_free(tmp_ctx);
6683                                 return ret;
6684                         }
6685                 }
6686
6687                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6688                                            &la->meta_data.originating_invocation_id,
6689                                            la->meta_data.originating_usn, seq_num,
6690                                            la->meta_data.originating_change_time,
6691                                            la->meta_data.version,
6692                                            !active);
6693                 if (ret != LDB_SUCCESS) {
6694                         talloc_free(tmp_ctx);
6695                         return ret;
6696                 }
6697
6698                 if (active) {
6699                         /* add the new backlink */
6700                         ret = replmd_add_backlink(module, replmd_private,
6701                                                   schema, &la->identifier->guid,
6702                                                   &guid, true, attr, true);
6703                         if (ret != LDB_SUCCESS) {
6704                                 talloc_free(tmp_ctx);
6705                                 return ret;
6706                         }
6707                 }
6708         } else {
6709                 /* get a seq_num for this change */
6710                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6711                 if (ret != LDB_SUCCESS) {
6712                         talloc_free(tmp_ctx);
6713                         return ret;
6714                 }
6715
6716                 old_el->values = talloc_realloc(msg->elements, old_el->values,
6717                                                 struct ldb_val, old_el->num_values+1);
6718                 if (!old_el->values) {
6719                         ldb_module_oom(module);
6720                         return LDB_ERR_OPERATIONS_ERROR;
6721                 }
6722                 old_el->num_values++;
6723
6724                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
6725                                           &la->meta_data.originating_invocation_id,
6726                                           la->meta_data.originating_usn, seq_num,
6727                                           la->meta_data.originating_change_time,
6728                                           la->meta_data.version,
6729                                           !active);
6730                 if (ret != LDB_SUCCESS) {
6731                         talloc_free(tmp_ctx);
6732                         return ret;
6733                 }
6734
6735                 if (active) {
6736                         ret = replmd_add_backlink(module, replmd_private,
6737                                                   schema, &la->identifier->guid,
6738                                                   &guid, true, attr, true);
6739                         if (ret != LDB_SUCCESS) {
6740                                 talloc_free(tmp_ctx);
6741                                 return ret;
6742                         }
6743                 }
6744         }
6745
6746         /* we only change whenChanged and uSNChanged if the seq_num
6747            has changed */
6748         ret = add_time_element(msg, "whenChanged", t);
6749         if (ret != LDB_SUCCESS) {
6750                 talloc_free(tmp_ctx);
6751                 ldb_operr(ldb);
6752                 return ret;
6753         }
6754
6755         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6756         if (ret != LDB_SUCCESS) {
6757                 talloc_free(tmp_ctx);
6758                 ldb_operr(ldb);
6759                 return ret;
6760         }
6761
6762         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6763         if (old_el == NULL) {
6764                 talloc_free(tmp_ctx);
6765                 return ldb_operr(ldb);
6766         }
6767
6768         ret = dsdb_check_single_valued_link(attr, old_el);
6769         if (ret != LDB_SUCCESS) {
6770                 talloc_free(tmp_ctx);
6771                 return ret;
6772         }
6773
6774         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6775
6776         ret = linked_attr_modify(module, msg, parent);
6777         if (ret != LDB_SUCCESS) {
6778                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6779                           ldb_errstring(ldb),
6780                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6781                 talloc_free(tmp_ctx);
6782                 return ret;
6783         }
6784
6785         talloc_free(tmp_ctx);
6786
6787         return ret;
6788 }
6789
6790 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6791 {
6792         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6793                 return replmd_extended_replicated_objects(module, req);
6794         }
6795
6796         return ldb_next_request(module, req);
6797 }
6798
6799
6800 /*
6801   we hook into the transaction operations to allow us to
6802   perform the linked attribute updates at the end of the whole
6803   transaction. This allows a forward linked attribute to be created
6804   before the object is created. During a vampire, w2k8 sends us linked
6805   attributes before the objects they are part of.
6806  */
6807 static int replmd_start_transaction(struct ldb_module *module)
6808 {
6809         /* create our private structure for this transaction */
6810         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6811                                                                 struct replmd_private);
6812         replmd_txn_cleanup(replmd_private);
6813
6814         /* free any leftover mod_usn records from cancelled
6815            transactions */
6816         while (replmd_private->ncs) {
6817                 struct nc_entry *e = replmd_private->ncs;
6818                 DLIST_REMOVE(replmd_private->ncs, e);
6819                 talloc_free(e);
6820         }
6821
6822         replmd_private->originating_updates = false;
6823
6824         return ldb_next_start_trans(module);
6825 }
6826
6827 /*
6828   on prepare commit we loop over our queued la_context structures and
6829   apply each of them
6830  */
6831 static int replmd_prepare_commit(struct ldb_module *module)
6832 {
6833         struct replmd_private *replmd_private =
6834                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6835         struct la_entry *la, *prev;
6836         struct la_backlink *bl;
6837         int ret;
6838
6839         /* walk the list backwards, to do the first entry first, as we
6840          * added the entries with DLIST_ADD() which puts them at the
6841          * start of the list */
6842         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
6843                 prev = DLIST_PREV(la);
6844                 DLIST_REMOVE(replmd_private->la_list, la);
6845                 ret = replmd_process_linked_attribute(module, replmd_private,
6846                                                       la, NULL);
6847                 if (ret != LDB_SUCCESS) {
6848                         replmd_txn_cleanup(replmd_private);
6849                         return ret;
6850                 }
6851         }
6852
6853         /* process our backlink list, creating and deleting backlinks
6854            as necessary */
6855         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
6856                 ret = replmd_process_backlink(module, bl, NULL);
6857                 if (ret != LDB_SUCCESS) {
6858                         replmd_txn_cleanup(replmd_private);
6859                         return ret;
6860                 }
6861         }
6862
6863         replmd_txn_cleanup(replmd_private);
6864
6865         /* possibly change @REPLCHANGED */
6866         ret = replmd_notify_store(module, NULL);
6867         if (ret != LDB_SUCCESS) {
6868                 return ret;
6869         }
6870
6871         return ldb_next_prepare_commit(module);
6872 }
6873
6874 static int replmd_del_transaction(struct ldb_module *module)
6875 {
6876         struct replmd_private *replmd_private =
6877                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6878         replmd_txn_cleanup(replmd_private);
6879
6880         return ldb_next_del_trans(module);
6881 }
6882
6883
6884 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
6885         .name          = "repl_meta_data",
6886         .init_context      = replmd_init,
6887         .add               = replmd_add,
6888         .modify            = replmd_modify,
6889         .rename            = replmd_rename,
6890         .del               = replmd_delete,
6891         .extended          = replmd_extended,
6892         .start_transaction = replmd_start_transaction,
6893         .prepare_commit    = replmd_prepare_commit,
6894         .del_transaction   = replmd_del_transaction,
6895 };
6896
6897 int ldb_repl_meta_data_module_init(const char *version)
6898 {
6899         LDB_MODULE_CHECK_VERSION(version);
6900         return ldb_register_module(&ldb_repl_meta_data_module_ops);
6901 }