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