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