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