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