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