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