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