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