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