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