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