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