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