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