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