s4-dsdb: when replacing linked attribute take always the new dn as the old dn might...
[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
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8    Copyright (C) Matthieu Patou <mat@samba.org> 2010
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 struct replmd_private {
54         TALLOC_CTX *la_ctx;
55         struct la_entry *la_list;
56         TALLOC_CTX *bl_ctx;
57         struct la_backlink *la_backlinks;
58         struct nc_entry {
59                 struct nc_entry *prev, *next;
60                 struct ldb_dn *dn;
61                 uint64_t mod_usn;
62                 uint64_t mod_usn_urgent;
63         } *ncs;
64 };
65
66 struct la_entry {
67         struct la_entry *next, *prev;
68         struct drsuapi_DsReplicaLinkedAttribute *la;
69 };
70
71 struct replmd_replicated_request {
72         struct ldb_module *module;
73         struct ldb_request *req;
74
75         const struct dsdb_schema *schema;
76
77         /* the controls we pass down */
78         struct ldb_control **controls;
79
80         /* details for the mode where we apply a bunch of inbound replication meessages */
81         bool apply_mode;
82         uint32_t index_current;
83         struct dsdb_extended_replicated_objects *objs;
84
85         struct ldb_message *search_msg;
86
87         uint64_t seq_num;
88         bool is_urgent;
89 };
90
91 enum urgent_situation {
92         REPL_URGENT_ON_CREATE = 1,
93         REPL_URGENT_ON_UPDATE = 2,
94         REPL_URGENT_ON_DELETE = 4
95 };
96
97
98 static const struct {
99         const char *update_name;
100         enum urgent_situation repl_situation;
101 } urgent_objects[] = {
102                 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
103                 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
104                 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
105                 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
106                 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
107                 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
108                 {NULL, 0}
109 };
110
111 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
112 static const char *urgent_attrs[] = {
113                 "lockoutTime",
114                 "pwdLastSet",
115                 "userAccountControl",
116                 NULL
117 };
118
119
120 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
121                                         enum urgent_situation situation)
122 {
123         unsigned int i, j;
124         for (i=0; urgent_objects[i].update_name; i++) {
125
126                 if ((situation & urgent_objects[i].repl_situation) == 0) {
127                         continue;
128                 }
129
130                 for (j=0; j<objectclass_el->num_values; j++) {
131                         const struct ldb_val *v = &objectclass_el->values[j];
132                         if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
133                                 return true;
134                         }
135                 }
136         }
137         return false;
138 }
139
140 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
141 {
142         if (ldb_attr_in_list(urgent_attrs, el->name)) {
143                 return true;
144         }
145         return false;
146 }
147
148
149 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
150
151 /*
152   initialise the module
153   allocate the private structure and build the list
154   of partition DNs for use by replmd_notify()
155  */
156 static int replmd_init(struct ldb_module *module)
157 {
158         struct replmd_private *replmd_private;
159         struct ldb_context *ldb = ldb_module_get_ctx(module);
160
161         replmd_private = talloc_zero(module, struct replmd_private);
162         if (replmd_private == NULL) {
163                 ldb_oom(ldb);
164                 return LDB_ERR_OPERATIONS_ERROR;
165         }
166         ldb_module_set_private(module, replmd_private);
167
168         return ldb_next_init(module);
169 }
170
171 /*
172   cleanup our per-transaction contexts
173  */
174 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
175 {
176         talloc_free(replmd_private->la_ctx);
177         replmd_private->la_list = NULL;
178         replmd_private->la_ctx = NULL;
179
180         talloc_free(replmd_private->bl_ctx);
181         replmd_private->la_backlinks = NULL;
182         replmd_private->bl_ctx = NULL;
183 }
184
185
186 struct la_backlink {
187         struct la_backlink *next, *prev;
188         const char *attr_name;
189         struct GUID forward_guid, target_guid;
190         bool active;
191 };
192
193 /*
194   process a backlinks we accumulated during a transaction, adding and
195   deleting the backlinks from the target objects
196  */
197 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
198 {
199         struct ldb_dn *target_dn, *source_dn;
200         int ret;
201         struct ldb_context *ldb = ldb_module_get_ctx(module);
202         struct ldb_message *msg;
203         TALLOC_CTX *tmp_ctx = talloc_new(bl);
204         char *dn_string;
205
206         /*
207           - find DN of target
208           - find DN of source
209           - construct ldb_message
210               - either an add or a delete
211          */
212         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
213         if (ret != LDB_SUCCESS) {
214                 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
215                          GUID_string(bl, &bl->target_guid)));
216                 return LDB_SUCCESS;
217         }
218
219         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
220         if (ret != LDB_SUCCESS) {
221                 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
222                                        GUID_string(bl, &bl->forward_guid));
223                 talloc_free(tmp_ctx);
224                 return ret;
225         }
226
227         msg = ldb_msg_new(tmp_ctx);
228         if (msg == NULL) {
229                 ldb_module_oom(module);
230                 talloc_free(tmp_ctx);
231                 return LDB_ERR_OPERATIONS_ERROR;
232         }
233
234         /* construct a ldb_message for adding/deleting the backlink */
235         msg->dn = target_dn;
236         dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
237         if (!dn_string) {
238                 ldb_module_oom(module);
239                 talloc_free(tmp_ctx);
240                 return LDB_ERR_OPERATIONS_ERROR;
241         }
242         ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
243         if (ret != LDB_SUCCESS) {
244                 talloc_free(tmp_ctx);
245                 return ret;
246         }
247         msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
248
249         /* a backlink should never be single valued. Unfortunately the
250            exchange schema has a attribute
251            msExchBridgeheadedLocalConnectorsDNBL which is single
252            valued and a backlink. We need to cope with that by
253            ignoring the single value flag */
254         msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
255
256         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
257         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
258                 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
259                    cope with possible corruption where the backlink has
260                    already been removed */
261                 DEBUG(0,("WARNING: backlink from %s already removed from %s - %s\n",
262                          ldb_dn_get_linearized(target_dn),
263                          ldb_dn_get_linearized(source_dn),
264                          ldb_errstring(ldb)));
265                 ret = LDB_SUCCESS;
266         } else if (ret != LDB_SUCCESS) {
267                 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
268                                        bl->active?"add":"remove",
269                                        ldb_dn_get_linearized(source_dn),
270                                        ldb_dn_get_linearized(target_dn),
271                                        ldb_errstring(ldb));
272                 talloc_free(tmp_ctx);
273                 return ret;
274         }
275         talloc_free(tmp_ctx);
276         return ret;
277 }
278
279 /*
280   add a backlink to the list of backlinks to add/delete in the prepare
281   commit
282  */
283 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
284                                struct GUID *forward_guid, struct GUID *target_guid,
285                                bool active, const struct dsdb_attribute *schema_attr, bool immediate)
286 {
287         const struct dsdb_attribute *target_attr;
288         struct la_backlink *bl;
289         struct replmd_private *replmd_private =
290                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
291
292         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
293         if (!target_attr) {
294                 /*
295                  * windows 2003 has a broken schema where the
296                  * definition of msDS-IsDomainFor is missing (which is
297                  * supposed to be the backlink of the
298                  * msDS-HasDomainNCs attribute
299                  */
300                 return LDB_SUCCESS;
301         }
302
303         /* see if its already in the list */
304         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
305                 if (GUID_equal(forward_guid, &bl->forward_guid) &&
306                     GUID_equal(target_guid, &bl->target_guid) &&
307                     (target_attr->lDAPDisplayName == bl->attr_name ||
308                      strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
309                         break;
310                 }
311         }
312
313         if (bl) {
314                 /* we found an existing one */
315                 if (bl->active == active) {
316                         return LDB_SUCCESS;
317                 }
318                 DLIST_REMOVE(replmd_private->la_backlinks, bl);
319                 talloc_free(bl);
320                 return LDB_SUCCESS;
321         }
322
323         if (replmd_private->bl_ctx == NULL) {
324                 replmd_private->bl_ctx = talloc_new(replmd_private);
325                 if (replmd_private->bl_ctx == NULL) {
326                         ldb_module_oom(module);
327                         return LDB_ERR_OPERATIONS_ERROR;
328                 }
329         }
330
331         /* its a new one */
332         bl = talloc(replmd_private->bl_ctx, struct la_backlink);
333         if (bl == NULL) {
334                 ldb_module_oom(module);
335                 return LDB_ERR_OPERATIONS_ERROR;
336         }
337
338         /* Ensure the schema does not go away before the bl->attr_name is used */
339         if (!talloc_reference(bl, schema)) {
340                 talloc_free(bl);
341                 ldb_module_oom(module);
342                 return LDB_ERR_OPERATIONS_ERROR;
343         }
344
345         bl->attr_name = target_attr->lDAPDisplayName;
346         bl->forward_guid = *forward_guid;
347         bl->target_guid = *target_guid;
348         bl->active = active;
349
350         /* the caller may ask for this backlink to be processed
351            immediately */
352         if (immediate) {
353                 int ret = replmd_process_backlink(module, bl, NULL);
354                 talloc_free(bl);
355                 return ret;
356         }
357
358         DLIST_ADD(replmd_private->la_backlinks, bl);
359
360         return LDB_SUCCESS;
361 }
362
363
364 /*
365  * Callback for most write operations in this module:
366  *
367  * notify the repl task that a object has changed. The notifies are
368  * gathered up in the replmd_private structure then written to the
369  * @REPLCHANGED object in each partition during the prepare_commit
370  */
371 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
372 {
373         int ret;
374         struct replmd_replicated_request *ac =
375                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
376         struct replmd_private *replmd_private =
377                 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
378         struct nc_entry *modified_partition;
379         struct ldb_control *partition_ctrl;
380         const struct dsdb_control_current_partition *partition;
381
382         struct ldb_control **controls;
383
384         partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
385
386         controls = ares->controls;
387         if (ldb_request_get_control(ac->req,
388                                     DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
389                 /*
390                  * Remove the current partition control from what we pass up
391                  * the chain if it hasn't been requested manually.
392                  */
393                 controls = ldb_controls_except_specified(ares->controls, ares,
394                                                          partition_ctrl);
395         }
396
397         if (ares->error != LDB_SUCCESS) {
398                 DEBUG(0,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
399                 return ldb_module_done(ac->req, controls,
400                                         ares->response, ares->error);
401         }
402
403         if (ares->type != LDB_REPLY_DONE) {
404                 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
405                 return ldb_module_done(ac->req, NULL,
406                                        NULL, LDB_ERR_OPERATIONS_ERROR);
407         }
408
409         if (!partition_ctrl) {
410                 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
411                 return ldb_module_done(ac->req, NULL,
412                                        NULL, LDB_ERR_OPERATIONS_ERROR);
413         }
414
415         partition = talloc_get_type_abort(partition_ctrl->data,
416                                     struct dsdb_control_current_partition);
417
418         if (ac->seq_num > 0) {
419                 for (modified_partition = replmd_private->ncs; modified_partition;
420                      modified_partition = modified_partition->next) {
421                         if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
422                                 break;
423                         }
424                 }
425
426                 if (modified_partition == NULL) {
427                         modified_partition = talloc_zero(replmd_private, struct nc_entry);
428                         if (!modified_partition) {
429                                 ldb_oom(ldb_module_get_ctx(ac->module));
430                                 return ldb_module_done(ac->req, NULL,
431                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
432                         }
433                         modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
434                         if (!modified_partition->dn) {
435                                 ldb_oom(ldb_module_get_ctx(ac->module));
436                                 return ldb_module_done(ac->req, NULL,
437                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
438                         }
439                         DLIST_ADD(replmd_private->ncs, modified_partition);
440                 }
441
442                 if (ac->seq_num > modified_partition->mod_usn) {
443                         modified_partition->mod_usn = ac->seq_num;
444                         if (ac->is_urgent) {
445                                 modified_partition->mod_usn_urgent = ac->seq_num;
446                         }
447                 }
448         }
449
450         if (ac->apply_mode) {
451                 talloc_free(ares);
452                 ac->index_current++;
453
454                 ret = replmd_replicated_apply_next(ac);
455                 if (ret != LDB_SUCCESS) {
456                         return ldb_module_done(ac->req, NULL, NULL, ret);
457                 }
458                 return ret;
459         } else {
460                 /* free the partition control container here, for the
461                  * common path.  Other cases will have it cleaned up
462                  * eventually with the ares */
463                 talloc_free(partition_ctrl);
464                 return ldb_module_done(ac->req, controls,
465                                        ares->response, LDB_SUCCESS);
466         }
467 }
468
469
470 /*
471  * update a @REPLCHANGED record in each partition if there have been
472  * any writes of replicated data in the partition
473  */
474 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
475 {
476         struct replmd_private *replmd_private =
477                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
478
479         while (replmd_private->ncs) {
480                 int ret;
481                 struct nc_entry *modified_partition = replmd_private->ncs;
482
483                 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
484                                                      modified_partition->mod_usn,
485                                                      modified_partition->mod_usn_urgent, parent);
486                 if (ret != LDB_SUCCESS) {
487                         DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
488                                  ldb_dn_get_linearized(modified_partition->dn)));
489                         return ret;
490                 }
491                 DLIST_REMOVE(replmd_private->ncs, modified_partition);
492                 talloc_free(modified_partition);
493         }
494
495         return LDB_SUCCESS;
496 }
497
498
499 /*
500   created a replmd_replicated_request context
501  */
502 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
503                                                          struct ldb_request *req)
504 {
505         struct ldb_context *ldb;
506         struct replmd_replicated_request *ac;
507
508         ldb = ldb_module_get_ctx(module);
509
510         ac = talloc_zero(req, struct replmd_replicated_request);
511         if (ac == NULL) {
512                 ldb_oom(ldb);
513                 return NULL;
514         }
515
516         ac->module = module;
517         ac->req = req;
518
519         ac->schema = dsdb_get_schema(ldb, ac);
520         if (!ac->schema) {
521                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
522                               "replmd_modify: no dsdb_schema loaded");
523                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
524                 return NULL;
525         }
526
527         return ac;
528 }
529
530 /*
531   add a time element to a record
532 */
533 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
534 {
535         struct ldb_message_element *el;
536         char *s;
537         int ret;
538
539         if (ldb_msg_find_element(msg, attr) != NULL) {
540                 return LDB_SUCCESS;
541         }
542
543         s = ldb_timestring(msg, t);
544         if (s == NULL) {
545                 return LDB_ERR_OPERATIONS_ERROR;
546         }
547
548         ret = ldb_msg_add_string(msg, attr, s);
549         if (ret != LDB_SUCCESS) {
550                 return ret;
551         }
552
553         el = ldb_msg_find_element(msg, attr);
554         /* always set as replace. This works because on add ops, the flag
555            is ignored */
556         el->flags = LDB_FLAG_MOD_REPLACE;
557
558         return LDB_SUCCESS;
559 }
560
561 /*
562   add a uint64_t element to a record
563 */
564 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
565                               const char *attr, uint64_t v)
566 {
567         struct ldb_message_element *el;
568         int ret;
569
570         if (ldb_msg_find_element(msg, attr) != NULL) {
571                 return LDB_SUCCESS;
572         }
573
574         ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
575         if (ret != LDB_SUCCESS) {
576                 return ret;
577         }
578
579         el = ldb_msg_find_element(msg, attr);
580         /* always set as replace. This works because on add ops, the flag
581            is ignored */
582         el->flags = LDB_FLAG_MOD_REPLACE;
583
584         return LDB_SUCCESS;
585 }
586
587 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
588                                                    const struct replPropertyMetaData1 *m2,
589                                                    const uint32_t *rdn_attid)
590 {
591         if (m1->attid == m2->attid) {
592                 return 0;
593         }
594
595         /*
596          * the rdn attribute should be at the end!
597          * so we need to return a value greater than zero
598          * which means m1 is greater than m2
599          */
600         if (m1->attid == *rdn_attid) {
601                 return 1;
602         }
603
604         /*
605          * the rdn attribute should be at the end!
606          * so we need to return a value less than zero
607          * which means m2 is greater than m1
608          */
609         if (m2->attid == *rdn_attid) {
610                 return -1;
611         }
612
613         return m1->attid > m2->attid ? 1 : -1;
614 }
615
616 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
617                                                 const struct dsdb_schema *schema,
618                                                 struct ldb_dn *dn)
619 {
620         const char *rdn_name;
621         const struct dsdb_attribute *rdn_sa;
622
623         rdn_name = ldb_dn_get_rdn_name(dn);
624         if (!rdn_name) {
625                 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
626                 return LDB_ERR_OPERATIONS_ERROR;
627         }
628
629         rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
630         if (rdn_sa == NULL) {
631                 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
632                 return LDB_ERR_OPERATIONS_ERROR;
633         }
634
635         DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
636                  rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
637
638         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
639
640         return LDB_SUCCESS;
641 }
642
643 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
644                                                  const struct ldb_message_element *e2,
645                                                  const struct dsdb_schema *schema)
646 {
647         const struct dsdb_attribute *a1;
648         const struct dsdb_attribute *a2;
649
650         /*
651          * TODO: make this faster by caching the dsdb_attribute pointer
652          *       on the ldb_messag_element
653          */
654
655         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
656         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
657
658         /*
659          * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
660          *       in the schema
661          */
662         if (!a1 || !a2) {
663                 return strcasecmp(e1->name, e2->name);
664         }
665         if (a1->attributeID_id == a2->attributeID_id) {
666                 return 0;
667         }
668         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
669 }
670
671 static void replmd_ldb_message_sort(struct ldb_message *msg,
672                                     const struct dsdb_schema *schema)
673 {
674         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
675 }
676
677 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
678                                const struct GUID *invocation_id, uint64_t seq_num,
679                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
680
681
682 /*
683   fix up linked attributes in replmd_add.
684   This involves setting up the right meta-data in extended DN
685   components, and creating backlinks to the object
686  */
687 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
688                              uint64_t seq_num, const struct GUID *invocationId, time_t t,
689                              struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
690 {
691         unsigned int i;
692         TALLOC_CTX *tmp_ctx = talloc_new(el->values);
693         struct ldb_context *ldb = ldb_module_get_ctx(module);
694
695         /* We will take a reference to the schema in replmd_add_backlink */
696         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
697         NTTIME now;
698
699         unix_to_nt_time(&now, t);
700
701         for (i=0; i<el->num_values; i++) {
702                 struct ldb_val *v = &el->values[i];
703                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
704                 struct GUID target_guid;
705                 NTSTATUS status;
706                 int ret;
707
708                 /* note that the DN already has the extended
709                    components from the extended_dn_store module */
710                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
711                 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
712                         ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
713                         if (ret != LDB_SUCCESS) {
714                                 talloc_free(tmp_ctx);
715                                 return ret;
716                         }
717                         ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
718                         if (ret != LDB_SUCCESS) {
719                                 talloc_free(tmp_ctx);
720                                 return ret;
721                         }
722                 }
723
724                 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
725                                           seq_num, seq_num, now, 0, false);
726                 if (ret != LDB_SUCCESS) {
727                         talloc_free(tmp_ctx);
728                         return ret;
729                 }
730
731                 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
732                 if (ret != LDB_SUCCESS) {
733                         talloc_free(tmp_ctx);
734                         return ret;
735                 }
736         }
737
738         talloc_free(tmp_ctx);
739         return LDB_SUCCESS;
740 }
741
742
743 /*
744   intercept add requests
745  */
746 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
747 {
748         struct ldb_context *ldb;
749         struct ldb_control *control;
750         struct replmd_replicated_request *ac;
751         enum ndr_err_code ndr_err;
752         struct ldb_request *down_req;
753         struct ldb_message *msg;
754         const DATA_BLOB *guid_blob;
755         struct GUID guid;
756         struct replPropertyMetaDataBlob nmd;
757         struct ldb_val nmd_value;
758         const struct GUID *our_invocation_id;
759         time_t t = time(NULL);
760         NTTIME now;
761         char *time_str;
762         int ret;
763         unsigned int i;
764         unsigned int functional_level;
765         uint32_t ni=0;
766         bool allow_add_guid = false;
767         bool remove_current_guid = false;
768         bool is_urgent = false;
769         struct ldb_message_element *objectclass_el;
770
771         /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
772         control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
773         if (control) {
774                 allow_add_guid = true;
775         }
776
777         /* do not manipulate our control entries */
778         if (ldb_dn_is_special(req->op.add.message->dn)) {
779                 return ldb_next_request(module, req);
780         }
781
782         ldb = ldb_module_get_ctx(module);
783
784         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
785
786         guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
787         if (guid_blob != NULL) {
788                 if (!allow_add_guid) {
789                         ldb_set_errstring(ldb,
790                                           "replmd_add: it's not allowed to add an object with objectGUID!");
791                         return LDB_ERR_UNWILLING_TO_PERFORM;
792                 } else {
793                         NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
794                         if (!NT_STATUS_IS_OK(status)) {
795                                 ldb_set_errstring(ldb,
796                                                   "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
797                                 return LDB_ERR_UNWILLING_TO_PERFORM;
798                         }
799                         /* we remove this attribute as it can be a string and
800                          * will not be treated correctly and then we will re-add
801                          * it later on in the good format */
802                         remove_current_guid = true;
803                 }
804         } else {
805                 /* a new GUID */
806                 guid = GUID_random();
807         }
808
809         ac = replmd_ctx_init(module, req);
810         if (ac == NULL) {
811                 return ldb_module_oom(module);
812         }
813
814         functional_level = dsdb_functional_level(ldb);
815
816         /* Get a sequence number from the backend */
817         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
818         if (ret != LDB_SUCCESS) {
819                 talloc_free(ac);
820                 return ret;
821         }
822
823         /* get our invocationId */
824         our_invocation_id = samdb_ntds_invocation_id(ldb);
825         if (!our_invocation_id) {
826                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
827                               "replmd_add: unable to find invocationId\n");
828                 talloc_free(ac);
829                 return LDB_ERR_OPERATIONS_ERROR;
830         }
831
832         /* we have to copy the message as the caller might have it as a const */
833         msg = ldb_msg_copy_shallow(ac, req->op.add.message);
834         if (msg == NULL) {
835                 ldb_oom(ldb);
836                 talloc_free(ac);
837                 return LDB_ERR_OPERATIONS_ERROR;
838         }
839
840         /* generated times */
841         unix_to_nt_time(&now, t);
842         time_str = ldb_timestring(msg, t);
843         if (!time_str) {
844                 ldb_oom(ldb);
845                 talloc_free(ac);
846                 return LDB_ERR_OPERATIONS_ERROR;
847         }
848         if (remove_current_guid) {
849                 ldb_msg_remove_attr(msg,"objectGUID");
850         }
851
852         /*
853          * remove autogenerated attributes
854          */
855         ldb_msg_remove_attr(msg, "whenCreated");
856         ldb_msg_remove_attr(msg, "whenChanged");
857         ldb_msg_remove_attr(msg, "uSNCreated");
858         ldb_msg_remove_attr(msg, "uSNChanged");
859         ldb_msg_remove_attr(msg, "replPropertyMetaData");
860
861         /*
862          * readd replicated attributes
863          */
864         ret = ldb_msg_add_string(msg, "whenCreated", time_str);
865         if (ret != LDB_SUCCESS) {
866                 ldb_oom(ldb);
867                 talloc_free(ac);
868                 return ret;
869         }
870
871         /* build the replication meta_data */
872         ZERO_STRUCT(nmd);
873         nmd.version             = 1;
874         nmd.ctr.ctr1.count      = msg->num_elements;
875         nmd.ctr.ctr1.array      = talloc_array(msg,
876                                                struct replPropertyMetaData1,
877                                                nmd.ctr.ctr1.count);
878         if (!nmd.ctr.ctr1.array) {
879                 ldb_oom(ldb);
880                 talloc_free(ac);
881                 return LDB_ERR_OPERATIONS_ERROR;
882         }
883
884         for (i=0; i < msg->num_elements; i++) {
885                 struct ldb_message_element *e = &msg->elements[i];
886                 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
887                 const struct dsdb_attribute *sa;
888
889                 if (e->name[0] == '@') continue;
890
891                 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
892                 if (!sa) {
893                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
894                                       "replmd_add: attribute '%s' not defined in schema\n",
895                                       e->name);
896                         talloc_free(ac);
897                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
898                 }
899
900                 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
901                         /* if the attribute is not replicated (0x00000001)
902                          * or constructed (0x00000004) it has no metadata
903                          */
904                         continue;
905                 }
906
907                 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
908                         ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa, req);
909                         if (ret != LDB_SUCCESS) {
910                                 talloc_free(ac);
911                                 return ret;
912                         }
913                         /* linked attributes are not stored in
914                            replPropertyMetaData in FL above w2k */
915                         continue;
916                 }
917
918                 m->attid                        = sa->attributeID_id;
919                 m->version                      = 1;
920                 m->originating_change_time      = now;
921                 m->originating_invocation_id    = *our_invocation_id;
922                 m->originating_usn              = ac->seq_num;
923                 m->local_usn                    = ac->seq_num;
924                 ni++;
925         }
926
927         /* fix meta data count */
928         nmd.ctr.ctr1.count = ni;
929
930         /*
931          * sort meta data array, and move the rdn attribute entry to the end
932          */
933         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
934         if (ret != LDB_SUCCESS) {
935                 talloc_free(ac);
936                 return ret;
937         }
938
939         /* generated NDR encoded values */
940         ndr_err = ndr_push_struct_blob(&nmd_value, msg,
941                                        &nmd,
942                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
943         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
944                 ldb_oom(ldb);
945                 talloc_free(ac);
946                 return LDB_ERR_OPERATIONS_ERROR;
947         }
948
949         /*
950          * add the autogenerated values
951          */
952         ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
953         if (ret != LDB_SUCCESS) {
954                 ldb_oom(ldb);
955                 talloc_free(ac);
956                 return ret;
957         }
958         ret = ldb_msg_add_string(msg, "whenChanged", time_str);
959         if (ret != LDB_SUCCESS) {
960                 ldb_oom(ldb);
961                 talloc_free(ac);
962                 return ret;
963         }
964         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
965         if (ret != LDB_SUCCESS) {
966                 ldb_oom(ldb);
967                 talloc_free(ac);
968                 return ret;
969         }
970         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
971         if (ret != LDB_SUCCESS) {
972                 ldb_oom(ldb);
973                 talloc_free(ac);
974                 return ret;
975         }
976         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
977         if (ret != LDB_SUCCESS) {
978                 ldb_oom(ldb);
979                 talloc_free(ac);
980                 return ret;
981         }
982
983         /*
984          * sort the attributes by attid before storing the object
985          */
986         replmd_ldb_message_sort(msg, ac->schema);
987
988         objectclass_el = ldb_msg_find_element(msg, "objectClass");
989         is_urgent = replmd_check_urgent_objectclass(objectclass_el,
990                                                         REPL_URGENT_ON_CREATE);
991
992         ac->is_urgent = is_urgent;
993         ret = ldb_build_add_req(&down_req, ldb, ac,
994                                 msg,
995                                 req->controls,
996                                 ac, replmd_op_callback,
997                                 req);
998
999         LDB_REQ_SET_LOCATION(down_req);
1000         if (ret != LDB_SUCCESS) {
1001                 talloc_free(ac);
1002                 return ret;
1003         }
1004
1005         /* current partition control is needed by "replmd_op_callback" */
1006         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1007                 ret = ldb_request_add_control(down_req,
1008                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
1009                                               false, NULL);
1010                 if (ret != LDB_SUCCESS) {
1011                         talloc_free(ac);
1012                         return ret;
1013                 }
1014         }
1015
1016         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1017                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1018                 if (ret != LDB_SUCCESS) {
1019                         talloc_free(ac);
1020                         return ret;
1021                 }
1022         }
1023
1024         /* mark the control done */
1025         if (control) {
1026                 control->critical = 0;
1027         }
1028
1029         /* go on with the call chain */
1030         return ldb_next_request(module, down_req);
1031 }
1032
1033
1034 /*
1035  * update the replPropertyMetaData for one element
1036  */
1037 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1038                                       struct ldb_message *msg,
1039                                       struct ldb_message_element *el,
1040                                       struct ldb_message_element *old_el,
1041                                       struct replPropertyMetaDataBlob *omd,
1042                                       const struct dsdb_schema *schema,
1043                                       uint64_t *seq_num,
1044                                       const struct GUID *our_invocation_id,
1045                                       NTTIME now,
1046                                       struct ldb_request *req)
1047 {
1048         uint32_t i;
1049         const struct dsdb_attribute *a;
1050         struct replPropertyMetaData1 *md1;
1051
1052         a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1053         if (a == NULL) {
1054                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1055                         /* allow this to make it possible for dbcheck
1056                            to remove bad attributes */
1057                         return LDB_SUCCESS;
1058                 }
1059
1060                 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1061                          el->name));
1062                 return LDB_ERR_OPERATIONS_ERROR;
1063         }
1064
1065         if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1066                 return LDB_SUCCESS;
1067         }
1068
1069         /* if the attribute's value haven't changed then return LDB_SUCCESS     */
1070         if (old_el != NULL && ldb_msg_element_compare(el, old_el) == 0) {
1071                 return LDB_SUCCESS;
1072         }
1073
1074         for (i=0; i<omd->ctr.ctr1.count; i++) {
1075                 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1076         }
1077
1078         if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1079                 /* linked attributes are not stored in
1080                    replPropertyMetaData in FL above w2k, but we do
1081                    raise the seqnum for the object  */
1082                 if (*seq_num == 0 &&
1083                     ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1084                         return LDB_ERR_OPERATIONS_ERROR;
1085                 }
1086                 return LDB_SUCCESS;
1087         }
1088
1089         if (i == omd->ctr.ctr1.count) {
1090                 /* we need to add a new one */
1091                 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1092                                                      struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1093                 if (omd->ctr.ctr1.array == NULL) {
1094                         ldb_oom(ldb);
1095                         return LDB_ERR_OPERATIONS_ERROR;
1096                 }
1097                 omd->ctr.ctr1.count++;
1098                 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1099         }
1100
1101         /* Get a new sequence number from the backend. We only do this
1102          * if we have a change that requires a new
1103          * replPropertyMetaData element
1104          */
1105         if (*seq_num == 0) {
1106                 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1107                 if (ret != LDB_SUCCESS) {
1108                         return LDB_ERR_OPERATIONS_ERROR;
1109                 }
1110         }
1111
1112         md1 = &omd->ctr.ctr1.array[i];
1113         md1->version++;
1114         md1->attid                     = a->attributeID_id;
1115         md1->originating_change_time   = now;
1116         md1->originating_invocation_id = *our_invocation_id;
1117         md1->originating_usn           = *seq_num;
1118         md1->local_usn                 = *seq_num;
1119
1120         return LDB_SUCCESS;
1121 }
1122
1123 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1124 {
1125         uint32_t count = omd.ctr.ctr1.count;
1126         uint64_t max = 0;
1127         uint32_t i;
1128         for (i=0; i < count; i++) {
1129                 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1130                 if (max < m.local_usn) {
1131                         max = m.local_usn;
1132                 }
1133         }
1134         return max;
1135 }
1136
1137 /*
1138  * update the replPropertyMetaData object each time we modify an
1139  * object. This is needed for DRS replication, as the merge on the
1140  * client is based on this object
1141  */
1142 static int replmd_update_rpmd(struct ldb_module *module,
1143                               const struct dsdb_schema *schema,
1144                               struct ldb_request *req,
1145                               const char * const *rename_attrs,
1146                               struct ldb_message *msg, uint64_t *seq_num,
1147                               time_t t,
1148                               bool *is_urgent)
1149 {
1150         const struct ldb_val *omd_value;
1151         enum ndr_err_code ndr_err;
1152         struct replPropertyMetaDataBlob omd;
1153         unsigned int i;
1154         NTTIME now;
1155         const struct GUID *our_invocation_id;
1156         int ret;
1157         const char * const *attrs = NULL;
1158         const char * const attrs1[] = { "replPropertyMetaData", "*", NULL };
1159         const char * const attrs2[] = { "uSNChanged", "objectClass", NULL };
1160         struct ldb_result *res;
1161         struct ldb_context *ldb;
1162         struct ldb_message_element *objectclass_el;
1163         enum urgent_situation situation;
1164         bool rodc, rmd_is_provided;
1165
1166         if (rename_attrs) {
1167                 attrs = rename_attrs;
1168         } else {
1169                 attrs = attrs1;
1170         }
1171
1172         ldb = ldb_module_get_ctx(module);
1173
1174         our_invocation_id = samdb_ntds_invocation_id(ldb);
1175         if (!our_invocation_id) {
1176                 /* this happens during an initial vampire while
1177                    updating the schema */
1178                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1179                 return LDB_SUCCESS;
1180         }
1181
1182         unix_to_nt_time(&now, t);
1183
1184         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1185                 rmd_is_provided = true;
1186         } else {
1187                 rmd_is_provided = false;
1188         }
1189
1190         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1191          * otherwise we consider we are updating */
1192         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1193                 situation = REPL_URGENT_ON_DELETE;
1194         } else if (rename_attrs) {
1195                 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1196         } else {
1197                 situation = REPL_URGENT_ON_UPDATE;
1198         }
1199
1200         if (rmd_is_provided) {
1201                 /* In this case the change_replmetadata control was supplied */
1202                 /* We check that it's the only attribute that is provided
1203                  * (it's a rare case so it's better to keep the code simplier)
1204                  * We also check that the highest local_usn is bigger than
1205                  * uSNChanged. */
1206                 uint64_t db_seq;
1207                 if( msg->num_elements != 1 ||
1208                         strncmp(msg->elements[0].name,
1209                                 "replPropertyMetaData", 20) ) {
1210                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1211                                 "a specified replPropertyMetaData attribute or with others\n"));
1212                         return LDB_ERR_OPERATIONS_ERROR;
1213                 }
1214                 if (situation != REPL_URGENT_ON_UPDATE) {
1215                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1216                         return LDB_ERR_OPERATIONS_ERROR;
1217                 }
1218                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1219                 if (!omd_value) {
1220                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1221                                  ldb_dn_get_linearized(msg->dn)));
1222                         return LDB_ERR_OPERATIONS_ERROR;
1223                 }
1224                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1225                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1226                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1227                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1228                                  ldb_dn_get_linearized(msg->dn)));
1229                         return LDB_ERR_OPERATIONS_ERROR;
1230                 }
1231                 *seq_num = find_max_local_usn(omd);
1232
1233                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1234                                             DSDB_FLAG_NEXT_MODULE |
1235                                             DSDB_SEARCH_SHOW_RECYCLED |
1236                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1237                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1238                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1239
1240                 if (ret != LDB_SUCCESS || res->count != 1) {
1241                         DEBUG(0,(__location__ ": Object %s failed to find uSNChanged\n",
1242                                  ldb_dn_get_linearized(msg->dn)));
1243                         return LDB_ERR_OPERATIONS_ERROR;
1244                 }
1245
1246                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1247                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1248                                                                 situation)) {
1249                         *is_urgent = true;
1250                 }
1251
1252                 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1253                 if (*seq_num <= db_seq) {
1254                         DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\
1255                                               " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n",
1256                                  (long long)*seq_num, (long long)db_seq));
1257                         return LDB_ERR_OPERATIONS_ERROR;
1258                 }
1259
1260         } else {
1261                 /* search for the existing replPropertyMetaDataBlob. We need
1262                  * to use REVEAL and ask for DNs in storage format to support
1263                  * the check for values being the same in
1264                  * replmd_update_rpmd_element()
1265                  */
1266                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1267                                             DSDB_FLAG_NEXT_MODULE |
1268                                             DSDB_SEARCH_SHOW_RECYCLED |
1269                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1270                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1271                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1272                 if (ret != LDB_SUCCESS || res->count != 1) {
1273                         DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1274                                  ldb_dn_get_linearized(msg->dn)));
1275                         return LDB_ERR_OPERATIONS_ERROR;
1276                 }
1277
1278                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1279                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1280                                                                 situation)) {
1281                         *is_urgent = true;
1282                 }
1283
1284                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1285                 if (!omd_value) {
1286                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1287                                  ldb_dn_get_linearized(msg->dn)));
1288                         return LDB_ERR_OPERATIONS_ERROR;
1289                 }
1290
1291                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1292                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1293                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1294                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1295                                  ldb_dn_get_linearized(msg->dn)));
1296                         return LDB_ERR_OPERATIONS_ERROR;
1297                 }
1298
1299                 if (omd.version != 1) {
1300                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1301                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1302                         return LDB_ERR_OPERATIONS_ERROR;
1303                 }
1304
1305                 for (i=0; i<msg->num_elements; i++) {
1306                         struct ldb_message_element *old_el;
1307                         old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1308                         ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1309                                                          our_invocation_id, now, req);
1310                         if (ret != LDB_SUCCESS) {
1311                                 return ret;
1312                         }
1313
1314                         if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1315                                 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1316                         }
1317
1318                 }
1319         }
1320         /*
1321          * replmd_update_rpmd_element has done an update if the
1322          * seq_num is set
1323          */
1324         if (*seq_num != 0) {
1325                 struct ldb_val *md_value;
1326                 struct ldb_message_element *el;
1327
1328                 /*if we are RODC and this is a DRSR update then its ok*/
1329                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1330                         ret = samdb_rodc(ldb, &rodc);
1331                         if (ret != LDB_SUCCESS) {
1332                                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1333                         } else if (rodc) {
1334                                 ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n");
1335                                 return LDB_ERR_REFERRAL;
1336                         }
1337                 }
1338
1339                 md_value = talloc(msg, struct ldb_val);
1340                 if (md_value == NULL) {
1341                         ldb_oom(ldb);
1342                         return LDB_ERR_OPERATIONS_ERROR;
1343                 }
1344
1345                 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1346                 if (ret != LDB_SUCCESS) {
1347                         return ret;
1348                 }
1349
1350                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1351                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1352                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1353                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1354                                  ldb_dn_get_linearized(msg->dn)));
1355                         return LDB_ERR_OPERATIONS_ERROR;
1356                 }
1357
1358                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1359                 if (ret != LDB_SUCCESS) {
1360                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1361                                  ldb_dn_get_linearized(msg->dn)));
1362                         return ret;
1363                 }
1364
1365                 el->num_values = 1;
1366                 el->values = md_value;
1367         }
1368
1369         return LDB_SUCCESS;
1370 }
1371
1372 struct parsed_dn {
1373         struct dsdb_dn *dsdb_dn;
1374         struct GUID *guid;
1375         struct ldb_val *v;
1376 };
1377
1378 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1379 {
1380         return GUID_compare(pdn1->guid, pdn2->guid);
1381 }
1382
1383 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1384                                         unsigned int count, struct GUID *guid,
1385                                         struct ldb_dn *dn)
1386 {
1387         struct parsed_dn *ret;
1388         unsigned int i;
1389         if (dn && GUID_all_zero(guid)) {
1390                 /* when updating a link using DRS, we sometimes get a
1391                    NULL GUID. We then need to try and match by DN */
1392                 for (i=0; i<count; i++) {
1393                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1394                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1395                                 return &pdn[i];
1396                         }
1397                 }
1398                 return NULL;
1399         }
1400         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1401         return ret;
1402 }
1403
1404 /*
1405   get a series of message element values as an array of DNs and GUIDs
1406   the result is sorted by GUID
1407  */
1408 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1409                           struct ldb_message_element *el, struct parsed_dn **pdn,
1410                           const char *ldap_oid, struct ldb_request *parent)
1411 {
1412         unsigned int i;
1413         struct ldb_context *ldb = ldb_module_get_ctx(module);
1414
1415         if (el == NULL) {
1416                 *pdn = NULL;
1417                 return LDB_SUCCESS;
1418         }
1419
1420         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1421         if (!*pdn) {
1422                 ldb_module_oom(module);
1423                 return LDB_ERR_OPERATIONS_ERROR;
1424         }
1425
1426         for (i=0; i<el->num_values; i++) {
1427                 struct ldb_val *v = &el->values[i];
1428                 NTSTATUS status;
1429                 struct ldb_dn *dn;
1430                 struct parsed_dn *p;
1431
1432                 p = &(*pdn)[i];
1433
1434                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1435                 if (p->dsdb_dn == NULL) {
1436                         return LDB_ERR_INVALID_DN_SYNTAX;
1437                 }
1438
1439                 dn = p->dsdb_dn->dn;
1440
1441                 p->guid = talloc(*pdn, struct GUID);
1442                 if (p->guid == NULL) {
1443                         ldb_module_oom(module);
1444                         return LDB_ERR_OPERATIONS_ERROR;
1445                 }
1446
1447                 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1448                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1449                         /* we got a DN without a GUID - go find the GUID */
1450                         int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1451                         if (ret != LDB_SUCCESS) {
1452                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1453                                                        ldb_dn_get_linearized(dn));
1454                                 return ret;
1455                         }
1456                         ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1457                         if (ret != LDB_SUCCESS) {
1458                                 return ret;
1459                         }
1460                 } else if (!NT_STATUS_IS_OK(status)) {
1461                         return LDB_ERR_OPERATIONS_ERROR;
1462                 }
1463
1464                 /* keep a pointer to the original ldb_val */
1465                 p->v = v;
1466         }
1467
1468         TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1469
1470         return LDB_SUCCESS;
1471 }
1472
1473 /*
1474   build a new extended DN, including all meta data fields
1475
1476   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1477   RMD_ADDTIME         = originating_add_time
1478   RMD_INVOCID         = originating_invocation_id
1479   RMD_CHANGETIME      = originating_change_time
1480   RMD_ORIGINATING_USN = originating_usn
1481   RMD_LOCAL_USN       = local_usn
1482   RMD_VERSION         = version
1483  */
1484 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1485                                const struct GUID *invocation_id, uint64_t seq_num,
1486                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1487 {
1488         struct ldb_dn *dn = dsdb_dn->dn;
1489         const char *tstring, *usn_string, *flags_string;
1490         struct ldb_val tval;
1491         struct ldb_val iid;
1492         struct ldb_val usnv, local_usnv;
1493         struct ldb_val vers, flagsv;
1494         NTSTATUS status;
1495         int ret;
1496         const char *dnstring;
1497         char *vstring;
1498         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1499
1500         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1501         if (!tstring) {
1502                 return LDB_ERR_OPERATIONS_ERROR;
1503         }
1504         tval = data_blob_string_const(tstring);
1505
1506         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1507         if (!usn_string) {
1508                 return LDB_ERR_OPERATIONS_ERROR;
1509         }
1510         usnv = data_blob_string_const(usn_string);
1511
1512         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1513         if (!usn_string) {
1514                 return LDB_ERR_OPERATIONS_ERROR;
1515         }
1516         local_usnv = data_blob_string_const(usn_string);
1517
1518         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1519         if (!vstring) {
1520                 return LDB_ERR_OPERATIONS_ERROR;
1521         }
1522         vers = data_blob_string_const(vstring);
1523
1524         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1525         if (!NT_STATUS_IS_OK(status)) {
1526                 return LDB_ERR_OPERATIONS_ERROR;
1527         }
1528
1529         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1530         if (!flags_string) {
1531                 return LDB_ERR_OPERATIONS_ERROR;
1532         }
1533         flagsv = data_blob_string_const(flags_string);
1534
1535         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1536         if (ret != LDB_SUCCESS) return ret;
1537         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1538         if (ret != LDB_SUCCESS) return ret;
1539         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1540         if (ret != LDB_SUCCESS) return ret;
1541         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1542         if (ret != LDB_SUCCESS) return ret;
1543         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1544         if (ret != LDB_SUCCESS) return ret;
1545         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1546         if (ret != LDB_SUCCESS) return ret;
1547         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1548         if (ret != LDB_SUCCESS) return ret;
1549
1550         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1551         if (dnstring == NULL) {
1552                 return LDB_ERR_OPERATIONS_ERROR;
1553         }
1554         *v = data_blob_string_const(dnstring);
1555
1556         return LDB_SUCCESS;
1557 }
1558
1559 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1560                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1561                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1562                                 uint32_t version, bool deleted);
1563
1564 /*
1565   check if any links need upgrading from w2k format
1566
1567   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.
1568  */
1569 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1570 {
1571         uint32_t i;
1572         for (i=0; i<count; i++) {
1573                 NTSTATUS status;
1574                 uint32_t version;
1575                 int ret;
1576
1577                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1578                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1579                         continue;
1580                 }
1581
1582                 /* it's an old one that needs upgrading */
1583                 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1584                                            1, 1, 0, 0, false);
1585                 if (ret != LDB_SUCCESS) {
1586                         return ret;
1587                 }
1588         }
1589         return LDB_SUCCESS;
1590 }
1591
1592 /*
1593   update an extended DN, including all meta data fields
1594
1595   see replmd_build_la_val for value names
1596  */
1597 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1598                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1599                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1600                                 uint32_t version, bool deleted)
1601 {
1602         struct ldb_dn *dn = dsdb_dn->dn;
1603         const char *tstring, *usn_string, *flags_string;
1604         struct ldb_val tval;
1605         struct ldb_val iid;
1606         struct ldb_val usnv, local_usnv;
1607         struct ldb_val vers, flagsv;
1608         const struct ldb_val *old_addtime;
1609         uint32_t old_version;
1610         NTSTATUS status;
1611         int ret;
1612         const char *dnstring;
1613         char *vstring;
1614         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1615
1616         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1617         if (!tstring) {
1618                 return LDB_ERR_OPERATIONS_ERROR;
1619         }
1620         tval = data_blob_string_const(tstring);
1621
1622         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1623         if (!usn_string) {
1624                 return LDB_ERR_OPERATIONS_ERROR;
1625         }
1626         usnv = data_blob_string_const(usn_string);
1627
1628         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1629         if (!usn_string) {
1630                 return LDB_ERR_OPERATIONS_ERROR;
1631         }
1632         local_usnv = data_blob_string_const(usn_string);
1633
1634         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1635         if (!NT_STATUS_IS_OK(status)) {
1636                 return LDB_ERR_OPERATIONS_ERROR;
1637         }
1638
1639         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1640         if (!flags_string) {
1641                 return LDB_ERR_OPERATIONS_ERROR;
1642         }
1643         flagsv = data_blob_string_const(flags_string);
1644
1645         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1646         if (ret != LDB_SUCCESS) return ret;
1647
1648         /* get the ADDTIME from the original */
1649         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1650         if (old_addtime == NULL) {
1651                 old_addtime = &tval;
1652         }
1653         if (dsdb_dn != old_dsdb_dn ||
1654             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1655                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1656                 if (ret != LDB_SUCCESS) return ret;
1657         }
1658
1659         /* use our invocation id */
1660         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1661         if (ret != LDB_SUCCESS) return ret;
1662
1663         /* changetime is the current time */
1664         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1665         if (ret != LDB_SUCCESS) return ret;
1666
1667         /* update the USN */
1668         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1669         if (ret != LDB_SUCCESS) return ret;
1670
1671         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1672         if (ret != LDB_SUCCESS) return ret;
1673
1674         /* increase the version by 1 */
1675         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1676         if (NT_STATUS_IS_OK(status) && old_version >= version) {
1677                 version = old_version+1;
1678         }
1679         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1680         vers = data_blob_string_const(vstring);
1681         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1682         if (ret != LDB_SUCCESS) return ret;
1683
1684         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1685         if (dnstring == NULL) {
1686                 return LDB_ERR_OPERATIONS_ERROR;
1687         }
1688         *v = data_blob_string_const(dnstring);
1689
1690         return LDB_SUCCESS;
1691 }
1692
1693 /*
1694   handle adding a linked attribute
1695  */
1696 static int replmd_modify_la_add(struct ldb_module *module,
1697                                 const struct dsdb_schema *schema,
1698                                 struct ldb_message *msg,
1699                                 struct ldb_message_element *el,
1700                                 struct ldb_message_element *old_el,
1701                                 const struct dsdb_attribute *schema_attr,
1702                                 uint64_t seq_num,
1703                                 time_t t,
1704                                 struct GUID *msg_guid,
1705                                 struct ldb_request *parent)
1706 {
1707         unsigned int i;
1708         struct parsed_dn *dns, *old_dns;
1709         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1710         int ret;
1711         struct ldb_val *new_values = NULL;
1712         unsigned int num_new_values = 0;
1713         unsigned old_num_values = old_el?old_el->num_values:0;
1714         const struct GUID *invocation_id;
1715         struct ldb_context *ldb = ldb_module_get_ctx(module);
1716         NTTIME now;
1717
1718         unix_to_nt_time(&now, t);
1719
1720         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1721         if (ret != LDB_SUCCESS) {
1722                 talloc_free(tmp_ctx);
1723                 return ret;
1724         }
1725
1726         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1727         if (ret != LDB_SUCCESS) {
1728                 talloc_free(tmp_ctx);
1729                 return ret;
1730         }
1731
1732         invocation_id = samdb_ntds_invocation_id(ldb);
1733         if (!invocation_id) {
1734                 talloc_free(tmp_ctx);
1735                 return LDB_ERR_OPERATIONS_ERROR;
1736         }
1737
1738         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1739         if (ret != LDB_SUCCESS) {
1740                 talloc_free(tmp_ctx);
1741                 return ret;
1742         }
1743
1744         /* for each new value, see if it exists already with the same GUID */
1745         for (i=0; i<el->num_values; i++) {
1746                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1747                 if (p == NULL) {
1748                         /* this is a new linked attribute value */
1749                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1750                         if (new_values == NULL) {
1751                                 ldb_module_oom(module);
1752                                 talloc_free(tmp_ctx);
1753                                 return LDB_ERR_OPERATIONS_ERROR;
1754                         }
1755                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1756                                                   invocation_id, seq_num, seq_num, now, 0, false);
1757                         if (ret != LDB_SUCCESS) {
1758                                 talloc_free(tmp_ctx);
1759                                 return ret;
1760                         }
1761                         num_new_values++;
1762                 } else {
1763                         /* this is only allowed if the GUID was
1764                            previously deleted. */
1765                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1766
1767                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1768                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1769                                                        el->name, GUID_string(tmp_ctx, p->guid));
1770                                 talloc_free(tmp_ctx);
1771                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1772                         }
1773                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1774                                                    invocation_id, seq_num, seq_num, now, 0, false);
1775                         if (ret != LDB_SUCCESS) {
1776                                 talloc_free(tmp_ctx);
1777                                 return ret;
1778                         }
1779                 }
1780
1781                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1782                 if (ret != LDB_SUCCESS) {
1783                         talloc_free(tmp_ctx);
1784                         return ret;
1785                 }
1786         }
1787
1788         /* add the new ones on to the end of the old values, constructing a new el->values */
1789         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1790                                     struct ldb_val,
1791                                     old_num_values+num_new_values);
1792         if (el->values == NULL) {
1793                 ldb_module_oom(module);
1794                 return LDB_ERR_OPERATIONS_ERROR;
1795         }
1796
1797         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1798         el->num_values = old_num_values + num_new_values;
1799
1800         talloc_steal(msg->elements, el->values);
1801         talloc_steal(el->values, new_values);
1802
1803         talloc_free(tmp_ctx);
1804
1805         /* we now tell the backend to replace all existing values
1806            with the one we have constructed */
1807         el->flags = LDB_FLAG_MOD_REPLACE;
1808
1809         return LDB_SUCCESS;
1810 }
1811
1812
1813 /*
1814   handle deleting all active linked attributes
1815  */
1816 static int replmd_modify_la_delete(struct ldb_module *module,
1817                                    const struct dsdb_schema *schema,
1818                                    struct ldb_message *msg,
1819                                    struct ldb_message_element *el,
1820                                    struct ldb_message_element *old_el,
1821                                    const struct dsdb_attribute *schema_attr,
1822                                    uint64_t seq_num,
1823                                    time_t t,
1824                                    struct GUID *msg_guid,
1825                                    struct ldb_request *parent)
1826 {
1827         unsigned int i;
1828         struct parsed_dn *dns, *old_dns;
1829         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1830         int ret;
1831         const struct GUID *invocation_id;
1832         struct ldb_context *ldb = ldb_module_get_ctx(module);
1833         NTTIME now;
1834
1835         unix_to_nt_time(&now, t);
1836
1837         /* check if there is nothing to delete */
1838         if ((!old_el || old_el->num_values == 0) &&
1839             el->num_values == 0) {
1840                 return LDB_SUCCESS;
1841         }
1842
1843         if (!old_el || old_el->num_values == 0) {
1844                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1845         }
1846
1847         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1848         if (ret != LDB_SUCCESS) {
1849                 talloc_free(tmp_ctx);
1850                 return ret;
1851         }
1852
1853         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1854         if (ret != LDB_SUCCESS) {
1855                 talloc_free(tmp_ctx);
1856                 return ret;
1857         }
1858
1859         invocation_id = samdb_ntds_invocation_id(ldb);
1860         if (!invocation_id) {
1861                 return LDB_ERR_OPERATIONS_ERROR;
1862         }
1863
1864         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1865         if (ret != LDB_SUCCESS) {
1866                 talloc_free(tmp_ctx);
1867                 return ret;
1868         }
1869
1870         el->values = NULL;
1871
1872         /* see if we are being asked to delete any links that
1873            don't exist or are already deleted */
1874         for (i=0; i<el->num_values; i++) {
1875                 struct parsed_dn *p = &dns[i];
1876                 struct parsed_dn *p2;
1877                 uint32_t rmd_flags;
1878
1879                 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1880                 if (!p2) {
1881                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1882                                                el->name, GUID_string(tmp_ctx, p->guid));
1883                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
1884                 }
1885                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1886                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1887                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1888                                                el->name, GUID_string(tmp_ctx, p->guid));
1889                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
1890                 }
1891         }
1892
1893         /* for each new value, see if it exists already with the same GUID
1894            if it is not already deleted and matches the delete list then delete it
1895         */
1896         for (i=0; i<old_el->num_values; i++) {
1897                 struct parsed_dn *p = &old_dns[i];
1898                 uint32_t rmd_flags;
1899
1900                 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1901                         continue;
1902                 }
1903
1904                 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1905                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1906
1907                 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1908                                            invocation_id, seq_num, seq_num, now, 0, true);
1909                 if (ret != LDB_SUCCESS) {
1910                         talloc_free(tmp_ctx);
1911                         return ret;
1912                 }
1913
1914                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1915                 if (ret != LDB_SUCCESS) {
1916                         talloc_free(tmp_ctx);
1917                         return ret;
1918                 }
1919         }
1920
1921         el->values = talloc_steal(msg->elements, old_el->values);
1922         el->num_values = old_el->num_values;
1923
1924         talloc_free(tmp_ctx);
1925
1926         /* we now tell the backend to replace all existing values
1927            with the one we have constructed */
1928         el->flags = LDB_FLAG_MOD_REPLACE;
1929
1930         return LDB_SUCCESS;
1931 }
1932
1933 /*
1934   handle replacing a linked attribute
1935  */
1936 static int replmd_modify_la_replace(struct ldb_module *module,
1937                                     const struct dsdb_schema *schema,
1938                                     struct ldb_message *msg,
1939                                     struct ldb_message_element *el,
1940                                     struct ldb_message_element *old_el,
1941                                     const struct dsdb_attribute *schema_attr,
1942                                     uint64_t seq_num,
1943                                     time_t t,
1944                                     struct GUID *msg_guid,
1945                                     struct ldb_request *parent)
1946 {
1947         unsigned int i;
1948         struct parsed_dn *dns, *old_dns;
1949         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1950         int ret;
1951         const struct GUID *invocation_id;
1952         struct ldb_context *ldb = ldb_module_get_ctx(module);
1953         struct ldb_val *new_values = NULL;
1954         unsigned int num_new_values = 0;
1955         unsigned int old_num_values = old_el?old_el->num_values:0;
1956         NTTIME now;
1957
1958         unix_to_nt_time(&now, t);
1959
1960         /* check if there is nothing to replace */
1961         if ((!old_el || old_el->num_values == 0) &&
1962             el->num_values == 0) {
1963                 return LDB_SUCCESS;
1964         }
1965
1966         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1967         if (ret != LDB_SUCCESS) {
1968                 talloc_free(tmp_ctx);
1969                 return ret;
1970         }
1971
1972         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1973         if (ret != LDB_SUCCESS) {
1974                 talloc_free(tmp_ctx);
1975                 return ret;
1976         }
1977
1978         invocation_id = samdb_ntds_invocation_id(ldb);
1979         if (!invocation_id) {
1980                 return LDB_ERR_OPERATIONS_ERROR;
1981         }
1982
1983         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1984         if (ret != LDB_SUCCESS) {
1985                 talloc_free(tmp_ctx);
1986                 return ret;
1987         }
1988
1989         /* mark all the old ones as deleted */
1990         for (i=0; i<old_num_values; i++) {
1991                 struct parsed_dn *old_p = &old_dns[i];
1992                 struct parsed_dn *p;
1993                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1994
1995                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1996
1997                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1998                 if (ret != LDB_SUCCESS) {
1999                         talloc_free(tmp_ctx);
2000                         return ret;
2001                 }
2002
2003                 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
2004                 if (p) {
2005                         /* we don't delete it if we are re-adding it */
2006                         continue;
2007                 }
2008
2009                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2010                                            invocation_id, seq_num, seq_num, now, 0, true);
2011                 if (ret != LDB_SUCCESS) {
2012                         talloc_free(tmp_ctx);
2013                         return ret;
2014                 }
2015         }
2016
2017         /* for each new value, either update its meta-data, or add it
2018          * to old_el
2019         */
2020         for (i=0; i<el->num_values; i++) {
2021                 struct parsed_dn *p = &dns[i], *old_p;
2022
2023                 if (old_dns &&
2024                     (old_p = parsed_dn_find(old_dns,
2025                                             old_num_values, p->guid, NULL)) != NULL) {
2026                         /* update in place */
2027                         ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2028                                                    old_p->dsdb_dn, invocation_id,
2029                                                    seq_num, seq_num, now, 0, false);
2030                         if (ret != LDB_SUCCESS) {
2031                                 talloc_free(tmp_ctx);
2032                                 return ret;
2033                         }
2034                 } else {
2035                         /* add a new one */
2036                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2037                                                     num_new_values+1);
2038                         if (new_values == NULL) {
2039                                 ldb_module_oom(module);
2040                                 talloc_free(tmp_ctx);
2041                                 return LDB_ERR_OPERATIONS_ERROR;
2042                         }
2043                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2044                                                   invocation_id, seq_num, seq_num, now, 0, false);
2045                         if (ret != LDB_SUCCESS) {
2046                                 talloc_free(tmp_ctx);
2047                                 return ret;
2048                         }
2049                         num_new_values++;
2050                 }
2051
2052                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2053                 if (ret != LDB_SUCCESS) {
2054                         talloc_free(tmp_ctx);
2055                         return ret;
2056                 }
2057         }
2058
2059         /* add the new values to the end of old_el */
2060         if (num_new_values != 0) {
2061                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2062                                             struct ldb_val, old_num_values+num_new_values);
2063                 if (el->values == NULL) {
2064                         ldb_module_oom(module);
2065                         return LDB_ERR_OPERATIONS_ERROR;
2066                 }
2067                 memcpy(&el->values[old_num_values], &new_values[0],
2068                        sizeof(struct ldb_val)*num_new_values);
2069                 el->num_values = old_num_values + num_new_values;
2070                 talloc_steal(msg->elements, new_values);
2071         } else {
2072                 el->values = old_el->values;
2073                 el->num_values = old_el->num_values;
2074                 talloc_steal(msg->elements, el->values);
2075         }
2076
2077         talloc_free(tmp_ctx);
2078
2079         /* we now tell the backend to replace all existing values
2080            with the one we have constructed */
2081         el->flags = LDB_FLAG_MOD_REPLACE;
2082
2083         return LDB_SUCCESS;
2084 }
2085
2086
2087 /*
2088   handle linked attributes in modify requests
2089  */
2090 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2091                                                struct ldb_message *msg,
2092                                                uint64_t seq_num, time_t t,
2093                                                struct ldb_request *parent)
2094 {
2095         struct ldb_result *res;
2096         unsigned int i;
2097         int ret;
2098         struct ldb_context *ldb = ldb_module_get_ctx(module);
2099         struct ldb_message *old_msg;
2100
2101         const struct dsdb_schema *schema;
2102         struct GUID old_guid;
2103
2104         if (seq_num == 0) {
2105                 /* there the replmd_update_rpmd code has already
2106                  * checked and saw that there are no linked
2107                  * attributes */
2108                 return LDB_SUCCESS;
2109         }
2110
2111         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2112                 /* don't do anything special for linked attributes */
2113                 return LDB_SUCCESS;
2114         }
2115
2116         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2117                                     DSDB_FLAG_NEXT_MODULE |
2118                                     DSDB_SEARCH_SHOW_RECYCLED |
2119                                     DSDB_SEARCH_REVEAL_INTERNALS |
2120                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2121                                     parent);
2122         if (ret != LDB_SUCCESS) {
2123                 return ret;
2124         }
2125         schema = dsdb_get_schema(ldb, res);
2126         if (!schema) {
2127                 return LDB_ERR_OPERATIONS_ERROR;
2128         }
2129
2130         old_msg = res->msgs[0];
2131
2132         old_guid = samdb_result_guid(old_msg, "objectGUID");
2133
2134         for (i=0; i<msg->num_elements; i++) {
2135                 struct ldb_message_element *el = &msg->elements[i];
2136                 struct ldb_message_element *old_el, *new_el;
2137                 const struct dsdb_attribute *schema_attr
2138                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2139                 if (!schema_attr) {
2140                         ldb_asprintf_errstring(ldb,
2141                                                "%s: attribute %s is not a valid attribute in schema",
2142                                                __FUNCTION__, el->name);
2143                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2144                 }
2145                 if (schema_attr->linkID == 0) {
2146                         continue;
2147                 }
2148                 if ((schema_attr->linkID & 1) == 1) {
2149                         /* Odd is for the target.  Illegal to modify */
2150                         ldb_asprintf_errstring(ldb,
2151                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2152                         return LDB_ERR_UNWILLING_TO_PERFORM;
2153                 }
2154                 old_el = ldb_msg_find_element(old_msg, el->name);
2155                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2156                 case LDB_FLAG_MOD_REPLACE:
2157                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2158                         break;
2159                 case LDB_FLAG_MOD_DELETE:
2160                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2161                         break;
2162                 case LDB_FLAG_MOD_ADD:
2163                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2164                         break;
2165                 default:
2166                         ldb_asprintf_errstring(ldb,
2167                                                "invalid flags 0x%x for %s linked attribute",
2168                                                el->flags, el->name);
2169                         return LDB_ERR_UNWILLING_TO_PERFORM;
2170                 }
2171                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2172                         ldb_asprintf_errstring(ldb,
2173                                                "Attribute %s is single valued but more than one value has been supplied",
2174                                                el->name);
2175                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2176                 } else {
2177                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2178                 }
2179
2180
2181
2182                 if (ret != LDB_SUCCESS) {
2183                         return ret;
2184                 }
2185                 if (old_el) {
2186                         ldb_msg_remove_attr(old_msg, el->name);
2187                 }
2188                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2189                 new_el->num_values = el->num_values;
2190                 new_el->values = talloc_steal(msg->elements, el->values);
2191
2192                 /* TODO: this relises a bit too heavily on the exact
2193                    behaviour of ldb_msg_find_element and
2194                    ldb_msg_remove_element */
2195                 old_el = ldb_msg_find_element(msg, el->name);
2196                 if (old_el != el) {
2197                         ldb_msg_remove_element(msg, old_el);
2198                         i--;
2199                 }
2200         }
2201
2202         talloc_free(res);
2203         return ret;
2204 }
2205
2206
2207
2208 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2209 {
2210         struct ldb_context *ldb;
2211         struct replmd_replicated_request *ac;
2212         struct ldb_request *down_req;
2213         struct ldb_message *msg;
2214         time_t t = time(NULL);
2215         int ret;
2216         bool is_urgent = false;
2217         struct loadparm_context *lp_ctx;
2218         char *referral;
2219         unsigned int functional_level;
2220         const DATA_BLOB *guid_blob;
2221
2222         /* do not manipulate our control entries */
2223         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2224                 return ldb_next_request(module, req);
2225         }
2226
2227         ldb = ldb_module_get_ctx(module);
2228
2229         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2230
2231         guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2232         if ( guid_blob != NULL ) {
2233                 ldb_set_errstring(ldb,
2234                                   "replmd_modify: it's not allowed to change the objectGUID!");
2235                 return LDB_ERR_CONSTRAINT_VIOLATION;
2236         }
2237
2238         ac = replmd_ctx_init(module, req);
2239         if (ac == NULL) {
2240                 return ldb_module_oom(module);
2241         }
2242
2243         functional_level = dsdb_functional_level(ldb);
2244
2245         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2246                                  struct loadparm_context);
2247
2248         /* we have to copy the message as the caller might have it as a const */
2249         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2250         if (msg == NULL) {
2251                 ldb_oom(ldb);
2252                 talloc_free(ac);
2253                 return LDB_ERR_OPERATIONS_ERROR;
2254         }
2255
2256         ldb_msg_remove_attr(msg, "whenChanged");
2257         ldb_msg_remove_attr(msg, "uSNChanged");
2258
2259         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2260                                  msg, &ac->seq_num, t, &is_urgent);
2261         if (ret == LDB_ERR_REFERRAL) {
2262                 referral = talloc_asprintf(req,
2263                                            "ldap://%s/%s",
2264                                            lpcfg_dnsdomain(lp_ctx),
2265                                            ldb_dn_get_linearized(msg->dn));
2266                 ret = ldb_module_send_referral(req, referral);
2267                 talloc_free(ac);
2268                 return ldb_module_done(req, NULL, NULL, ret);
2269         }
2270
2271         if (ret != LDB_SUCCESS) {
2272                 talloc_free(ac);
2273                 return ret;
2274         }
2275
2276         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2277         if (ret != LDB_SUCCESS) {
2278                 talloc_free(ac);
2279                 return ret;
2280         }
2281
2282         /* TODO:
2283          * - replace the old object with the newly constructed one
2284          */
2285
2286         ac->is_urgent = is_urgent;
2287
2288         ret = ldb_build_mod_req(&down_req, ldb, ac,
2289                                 msg,
2290                                 req->controls,
2291                                 ac, replmd_op_callback,
2292                                 req);
2293         LDB_REQ_SET_LOCATION(down_req);
2294         if (ret != LDB_SUCCESS) {
2295                 talloc_free(ac);
2296                 return ret;
2297         }
2298
2299         /* current partition control is needed by "replmd_op_callback" */
2300         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2301                 ret = ldb_request_add_control(down_req,
2302                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2303                                               false, NULL);
2304                 if (ret != LDB_SUCCESS) {
2305                         talloc_free(ac);
2306                         return ret;
2307                 }
2308         }
2309
2310         /* If we are in functional level 2000, then
2311          * replmd_modify_handle_linked_attribs will have done
2312          * nothing */
2313         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2314                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2315                 if (ret != LDB_SUCCESS) {
2316                         talloc_free(ac);
2317                         return ret;
2318                 }
2319         }
2320
2321         talloc_steal(down_req, msg);
2322
2323         /* we only change whenChanged and uSNChanged if the seq_num
2324            has changed */
2325         if (ac->seq_num != 0) {
2326                 ret = add_time_element(msg, "whenChanged", t);
2327                 if (ret != LDB_SUCCESS) {
2328                         talloc_free(ac);
2329                         return ret;
2330                 }
2331
2332                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2333                 if (ret != LDB_SUCCESS) {
2334                         talloc_free(ac);
2335                         return ret;
2336                 }
2337         }
2338
2339         /* go on with the call chain */
2340         return ldb_next_request(module, down_req);
2341 }
2342
2343 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2344
2345 /*
2346   handle a rename request
2347
2348   On a rename we need to do an extra ldb_modify which sets the
2349   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2350  */
2351 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2352 {
2353         struct ldb_context *ldb;
2354         struct replmd_replicated_request *ac;
2355         int ret;
2356         struct ldb_request *down_req;
2357
2358         /* do not manipulate our control entries */
2359         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2360                 return ldb_next_request(module, req);
2361         }
2362
2363         ldb = ldb_module_get_ctx(module);
2364
2365         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2366
2367         ac = replmd_ctx_init(module, req);
2368         if (ac == NULL) {
2369                 return ldb_module_oom(module);
2370         }
2371
2372         ret = ldb_build_rename_req(&down_req, ldb, ac,
2373                                    ac->req->op.rename.olddn,
2374                                    ac->req->op.rename.newdn,
2375                                    ac->req->controls,
2376                                    ac, replmd_rename_callback,
2377                                    ac->req);
2378         LDB_REQ_SET_LOCATION(down_req);
2379         if (ret != LDB_SUCCESS) {
2380                 talloc_free(ac);
2381                 return ret;
2382         }
2383
2384         /* go on with the call chain */
2385         return ldb_next_request(module, down_req);
2386 }
2387
2388 /* After the rename is compleated, update the whenchanged etc */
2389 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2390 {
2391         struct ldb_context *ldb;
2392         struct replmd_replicated_request *ac;
2393         struct ldb_request *down_req;
2394         struct ldb_message *msg;
2395         const struct dsdb_attribute *rdn_attr;
2396         const char *rdn_name;
2397         const struct ldb_val *rdn_val;
2398         const char *attrs[4] = { NULL, };
2399         time_t t = time(NULL);
2400         int ret;
2401         bool is_urgent = false;
2402
2403         ac = talloc_get_type(req->context, struct replmd_replicated_request);
2404         ldb = ldb_module_get_ctx(ac->module);
2405
2406         if (ares->error != LDB_SUCCESS) {
2407                 return ldb_module_done(ac->req, ares->controls,
2408                                         ares->response, ares->error);
2409         }
2410
2411         if (ares->type != LDB_REPLY_DONE) {
2412                 ldb_set_errstring(ldb,
2413                                   "invalid ldb_reply_type in callback");
2414                 talloc_free(ares);
2415                 return ldb_module_done(ac->req, NULL, NULL,
2416                                         LDB_ERR_OPERATIONS_ERROR);
2417         }
2418
2419         /* TODO:
2420          * - replace the old object with the newly constructed one
2421          */
2422
2423         msg = ldb_msg_new(ac);
2424         if (msg == NULL) {
2425                 ldb_oom(ldb);
2426                 return LDB_ERR_OPERATIONS_ERROR;
2427         }
2428
2429         msg->dn = ac->req->op.rename.newdn;
2430
2431         rdn_name = ldb_dn_get_rdn_name(msg->dn);
2432         if (rdn_name == NULL) {
2433                 talloc_free(ares);
2434                 return ldb_module_done(ac->req, NULL, NULL,
2435                                        ldb_operr(ldb));
2436         }
2437
2438         /* normalize the rdn attribute name */
2439         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2440         if (rdn_attr == NULL) {
2441                 talloc_free(ares);
2442                 return ldb_module_done(ac->req, NULL, NULL,
2443                                        ldb_operr(ldb));
2444         }
2445         rdn_name = rdn_attr->lDAPDisplayName;
2446
2447         rdn_val = ldb_dn_get_rdn_val(msg->dn);
2448         if (rdn_val == NULL) {
2449                 talloc_free(ares);
2450                 return ldb_module_done(ac->req, NULL, NULL,
2451                                        ldb_operr(ldb));
2452         }
2453
2454         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2455                 talloc_free(ares);
2456                 return ldb_module_done(ac->req, NULL, NULL,
2457                                        ldb_oom(ldb));
2458         }
2459         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2460                 talloc_free(ares);
2461                 return ldb_module_done(ac->req, NULL, NULL,
2462                                        ldb_oom(ldb));
2463         }
2464         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2465                 talloc_free(ares);
2466                 return ldb_module_done(ac->req, NULL, NULL,
2467                                        ldb_oom(ldb));
2468         }
2469         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2470                 talloc_free(ares);
2471                 return ldb_module_done(ac->req, NULL, NULL,
2472                                        ldb_oom(ldb));
2473         }
2474
2475         /*
2476          * here we let replmd_update_rpmd() only search for
2477          * the existing "replPropertyMetaData" and rdn_name attributes.
2478          *
2479          * We do not want the existing "name" attribute as
2480          * the "name" attribute needs to get the version
2481          * updated on rename even if the rdn value hasn't changed.
2482          *
2483          * This is the diff of the meta data, for a moved user
2484          * on a w2k8r2 server:
2485          *
2486          * # record 1
2487          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2488          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2489          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
2490          *         version                  : 0x00000001 (1)
2491          *         reserved                 : 0x00000000 (0)
2492          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
2493          *                      local_usn                : 0x00000000000037a5 (14245)
2494          *                 array: struct replPropertyMetaData1
2495          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
2496          * -                    version                  : 0x00000001 (1)
2497          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
2498          * +                    version                  : 0x00000002 (2)
2499          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
2500          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2501          * -                    originating_usn          : 0x00000000000037a5 (14245)
2502          * -                    local_usn                : 0x00000000000037a5 (14245)
2503          * +                    originating_usn          : 0x0000000000003834 (14388)
2504          * +                    local_usn                : 0x0000000000003834 (14388)
2505          *                 array: struct replPropertyMetaData1
2506          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
2507          *                      version                  : 0x00000004 (4)
2508          */
2509         attrs[0] = "replPropertyMetaData";
2510         attrs[1] = "objectClass";
2511         attrs[2] = rdn_name;
2512         attrs[3] = NULL;
2513
2514         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2515                                  msg, &ac->seq_num, t, &is_urgent);
2516         if (ret == LDB_ERR_REFERRAL) {
2517                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2518                 struct loadparm_context *lp_ctx;
2519                 char *referral;
2520
2521                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2522                                          struct loadparm_context);
2523
2524                 referral = talloc_asprintf(req,
2525                                            "ldap://%s/%s",
2526                                            lpcfg_dnsdomain(lp_ctx),
2527                                            ldb_dn_get_linearized(olddn));
2528                 ret = ldb_module_send_referral(req, referral);
2529                 talloc_free(ac);
2530                 return ldb_module_done(req, NULL, NULL, ret);
2531         }
2532
2533         if (ret != LDB_SUCCESS) {
2534                 talloc_free(ares);
2535                 return ldb_module_done(ac->req, NULL, NULL,
2536                                        ldb_error(ldb, ret,
2537                                         "failed to call replmd_update_rpmd()"));
2538         }
2539
2540         if (ac->seq_num == 0) {
2541                 talloc_free(ares);
2542                 return ldb_module_done(ac->req, NULL, NULL,
2543                                        ldb_error(ldb, ret,
2544                                         "internal error seq_num == 0"));
2545         }
2546         ac->is_urgent = is_urgent;
2547
2548         ret = ldb_build_mod_req(&down_req, ldb, ac,
2549                                 msg,
2550                                 req->controls,
2551                                 ac, replmd_op_callback,
2552                                 req);
2553         LDB_REQ_SET_LOCATION(down_req);
2554         if (ret != LDB_SUCCESS) {
2555                 talloc_free(ac);
2556                 return ret;
2557         }
2558
2559         /* current partition control is needed by "replmd_op_callback" */
2560         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2561                 ret = ldb_request_add_control(down_req,
2562                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2563                                               false, NULL);
2564                 if (ret != LDB_SUCCESS) {
2565                         talloc_free(ac);
2566                         return ret;
2567                 }
2568         }
2569
2570         talloc_steal(down_req, msg);
2571
2572         ret = add_time_element(msg, "whenChanged", t);
2573         if (ret != LDB_SUCCESS) {
2574                 talloc_free(ac);
2575                 return ret;
2576         }
2577
2578         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2579         if (ret != LDB_SUCCESS) {
2580                 talloc_free(ac);
2581                 return ret;
2582         }
2583
2584         /* go on with the call chain - do the modify after the rename */
2585         return ldb_next_request(ac->module, down_req);
2586 }
2587
2588 /*
2589    remove links from objects that point at this object when an object
2590    is deleted
2591  */
2592 static int replmd_delete_remove_link(struct ldb_module *module,
2593                                      const struct dsdb_schema *schema,
2594                                      struct ldb_dn *dn,
2595                                      struct ldb_message_element *el,
2596                                      const struct dsdb_attribute *sa,
2597                                      struct ldb_request *parent)
2598 {
2599         unsigned int i;
2600         TALLOC_CTX *tmp_ctx = talloc_new(module);
2601         struct ldb_context *ldb = ldb_module_get_ctx(module);
2602
2603         for (i=0; i<el->num_values; i++) {
2604                 struct dsdb_dn *dsdb_dn;
2605                 NTSTATUS status;
2606                 int ret;
2607                 struct GUID guid2;
2608                 struct ldb_message *msg;
2609                 const struct dsdb_attribute *target_attr;
2610                 struct ldb_message_element *el2;
2611                 struct ldb_val dn_val;
2612
2613                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2614                         continue;
2615                 }
2616
2617                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2618                 if (!dsdb_dn) {
2619                         talloc_free(tmp_ctx);
2620                         return LDB_ERR_OPERATIONS_ERROR;
2621                 }
2622
2623                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2624                 if (!NT_STATUS_IS_OK(status)) {
2625                         talloc_free(tmp_ctx);
2626                         return LDB_ERR_OPERATIONS_ERROR;
2627                 }
2628
2629                 /* remove the link */
2630                 msg = ldb_msg_new(tmp_ctx);
2631                 if (!msg) {
2632                         ldb_module_oom(module);
2633                         talloc_free(tmp_ctx);
2634                         return LDB_ERR_OPERATIONS_ERROR;
2635                 }
2636
2637
2638                 msg->dn = dsdb_dn->dn;
2639
2640                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2641                 if (target_attr == NULL) {
2642                         continue;
2643                 }
2644
2645                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2646                 if (ret != LDB_SUCCESS) {
2647                         ldb_module_oom(module);
2648                         talloc_free(tmp_ctx);
2649                         return LDB_ERR_OPERATIONS_ERROR;
2650                 }
2651                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2652                 el2->values = &dn_val;
2653                 el2->num_values = 1;
2654
2655                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2656                 if (ret != LDB_SUCCESS) {
2657                         talloc_free(tmp_ctx);
2658                         return ret;
2659                 }
2660         }
2661         talloc_free(tmp_ctx);
2662         return LDB_SUCCESS;
2663 }
2664
2665
2666 /*
2667   handle update of replication meta data for deletion of objects
2668
2669   This also handles the mapping of delete to a rename operation
2670   to allow deletes to be replicated.
2671  */
2672 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2673 {
2674         int ret = LDB_ERR_OTHER;
2675         bool retb, disallow_move_on_delete;
2676         struct ldb_dn *old_dn, *new_dn;
2677         const char *rdn_name;
2678         const struct ldb_val *rdn_value, *new_rdn_value;
2679         struct GUID guid;
2680         struct ldb_context *ldb = ldb_module_get_ctx(module);
2681         const struct dsdb_schema *schema;
2682         struct ldb_message *msg, *old_msg;
2683         struct ldb_message_element *el;
2684         TALLOC_CTX *tmp_ctx;
2685         struct ldb_result *res, *parent_res;
2686         const char *preserved_attrs[] = {
2687                 /* yes, this really is a hard coded list. See MS-ADTS
2688                    section 3.1.1.5.5.1.1 */
2689                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2690                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2691                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2692                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2693                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2694                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2695                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2696                 "whenChanged", NULL};
2697         unsigned int i, el_count = 0;
2698         enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2699                                                 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2700         enum deletion_state deletion_state, next_deletion_state;
2701         bool enabled;
2702
2703         if (ldb_dn_is_special(req->op.del.dn)) {
2704                 return ldb_next_request(module, req);
2705         }
2706
2707         tmp_ctx = talloc_new(ldb);
2708         if (!tmp_ctx) {
2709                 ldb_oom(ldb);
2710                 return LDB_ERR_OPERATIONS_ERROR;
2711         }
2712
2713         schema = dsdb_get_schema(ldb, tmp_ctx);
2714         if (!schema) {
2715                 return LDB_ERR_OPERATIONS_ERROR;
2716         }
2717
2718         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2719
2720         /* we need the complete msg off disk, so we can work out which
2721            attributes need to be removed */
2722         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2723                                     DSDB_FLAG_NEXT_MODULE |
2724                                     DSDB_SEARCH_SHOW_RECYCLED |
2725                                     DSDB_SEARCH_REVEAL_INTERNALS |
2726                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2727         if (ret != LDB_SUCCESS) {
2728                 talloc_free(tmp_ctx);
2729                 return ret;
2730         }
2731         old_msg = res->msgs[0];
2732
2733
2734         ret = dsdb_recyclebin_enabled(module, &enabled);
2735         if (ret != LDB_SUCCESS) {
2736                 talloc_free(tmp_ctx);
2737                 return ret;
2738         }
2739
2740         if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2741                 if (!enabled) {
2742                         deletion_state = OBJECT_TOMBSTONE;
2743                         next_deletion_state = OBJECT_REMOVED;
2744                 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2745                         deletion_state = OBJECT_RECYCLED;
2746                         next_deletion_state = OBJECT_REMOVED;
2747                 } else {
2748                         deletion_state = OBJECT_DELETED;
2749                         next_deletion_state = OBJECT_RECYCLED;
2750                 }
2751         } else {
2752                 deletion_state = OBJECT_NOT_DELETED;
2753                 if (enabled) {
2754                         next_deletion_state = OBJECT_DELETED;
2755                 } else {
2756                         next_deletion_state = OBJECT_TOMBSTONE;
2757                 }
2758         }
2759
2760         if (next_deletion_state == OBJECT_REMOVED) {
2761                 struct auth_session_info *session_info =
2762                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2763                 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2764                         ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2765                                         ldb_dn_get_linearized(old_msg->dn));
2766                         return LDB_ERR_UNWILLING_TO_PERFORM;
2767                 }
2768
2769                 /* it is already deleted - really remove it this time */
2770                 talloc_free(tmp_ctx);
2771                 return ldb_next_request(module, req);
2772         }
2773
2774         rdn_name = ldb_dn_get_rdn_name(old_dn);
2775         rdn_value = ldb_dn_get_rdn_val(old_dn);
2776         if ((rdn_name == NULL) || (rdn_value == NULL)) {
2777                 talloc_free(tmp_ctx);
2778                 return ldb_operr(ldb);
2779         }
2780
2781         msg = ldb_msg_new(tmp_ctx);
2782         if (msg == NULL) {
2783                 ldb_module_oom(module);
2784                 talloc_free(tmp_ctx);
2785                 return LDB_ERR_OPERATIONS_ERROR;
2786         }
2787
2788         msg->dn = old_dn;
2789
2790         if (deletion_state == OBJECT_NOT_DELETED){
2791                 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2792                 disallow_move_on_delete =
2793                         (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2794                                 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2795
2796                 /* work out where we will be renaming this object to */
2797                 if (!disallow_move_on_delete) {
2798                         ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2799                                                           &new_dn);
2800                         if (ret != LDB_SUCCESS) {
2801                                 /* this is probably an attempted delete on a partition
2802                                  * that doesn't allow delete operations, such as the
2803                                  * schema partition */
2804                                 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2805                                                            ldb_dn_get_linearized(old_dn));
2806                                 talloc_free(tmp_ctx);
2807                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2808                         }
2809                 } else {
2810                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2811                         if (new_dn == NULL) {
2812                                 ldb_module_oom(module);
2813                                 talloc_free(tmp_ctx);
2814                                 return LDB_ERR_OPERATIONS_ERROR;
2815                         }
2816                 }
2817
2818                 /* get the objects GUID from the search we just did */
2819                 guid = samdb_result_guid(old_msg, "objectGUID");
2820
2821                 /* Add a formatted child */
2822                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2823                                                 rdn_name,
2824                                                 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2825                                                 GUID_string(tmp_ctx, &guid));
2826                 if (!retb) {
2827                         DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2828                                         ldb_dn_get_linearized(new_dn)));
2829                         talloc_free(tmp_ctx);
2830                         return LDB_ERR_OPERATIONS_ERROR;
2831                 }
2832
2833                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2834                 if (ret != LDB_SUCCESS) {
2835                         DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2836                         ldb_module_oom(module);
2837                         talloc_free(tmp_ctx);
2838                         return ret;
2839                 }
2840                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2841         }
2842
2843         /*
2844           now we need to modify the object in the following ways:
2845
2846           - add isDeleted=TRUE
2847           - update rDN and name, with new rDN
2848           - remove linked attributes
2849           - remove objectCategory and sAMAccountType
2850           - remove attribs not on the preserved list
2851              - preserved if in above list, or is rDN
2852           - remove all linked attribs from this object
2853           - remove all links from other objects to this object
2854           - add lastKnownParent
2855           - update replPropertyMetaData?
2856
2857           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2858          */
2859
2860         /* we need the storage form of the parent GUID */
2861         ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2862                                     ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2863                                     DSDB_FLAG_NEXT_MODULE |
2864                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2865                                     DSDB_SEARCH_REVEAL_INTERNALS|
2866                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2867         if (ret != LDB_SUCCESS) {
2868                 talloc_free(tmp_ctx);
2869                 return ret;
2870         }
2871
2872         if (deletion_state == OBJECT_NOT_DELETED){
2873                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2874                                                    ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2875                 if (ret != LDB_SUCCESS) {
2876                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2877                         ldb_module_oom(module);
2878                         talloc_free(tmp_ctx);
2879                         return ret;
2880                 }
2881                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2882         }
2883
2884         switch (next_deletion_state){
2885
2886         case OBJECT_DELETED:
2887
2888                 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2889                 if (ret != LDB_SUCCESS) {
2890                         DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2891                         ldb_module_oom(module);
2892                         talloc_free(tmp_ctx);
2893                         return ret;
2894                 }
2895                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2896
2897                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_DELETE, NULL);
2898                 if (ret != LDB_SUCCESS) {
2899                         talloc_free(tmp_ctx);
2900                         ldb_module_oom(module);
2901                         return ret;
2902                 }
2903
2904                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_DELETE, NULL);
2905                 if (ret != LDB_SUCCESS) {
2906                         talloc_free(tmp_ctx);
2907                         ldb_module_oom(module);
2908                         return ret;
2909                 }
2910
2911                 break;
2912
2913         case OBJECT_RECYCLED:
2914         case OBJECT_TOMBSTONE:
2915
2916                 /* we also mark it as recycled, meaning this object can't be
2917                    recovered (we are stripping its attributes) */
2918                 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2919                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2920                         if (ret != LDB_SUCCESS) {
2921                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2922                                 ldb_module_oom(module);
2923                                 talloc_free(tmp_ctx);
2924                                 return ret;
2925                         }
2926                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2927                 }
2928
2929                 /* work out which of the old attributes we will be removing */
2930                 for (i=0; i<old_msg->num_elements; i++) {
2931                         const struct dsdb_attribute *sa;
2932                         el = &old_msg->elements[i];
2933                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2934                         if (!sa) {
2935                                 talloc_free(tmp_ctx);
2936                                 return LDB_ERR_OPERATIONS_ERROR;
2937                         }
2938                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2939                                 /* don't remove the rDN */
2940                                 continue;
2941                         }
2942                         if (sa->linkID && sa->linkID & 1) {
2943                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
2944                                 if (ret != LDB_SUCCESS) {
2945                                         talloc_free(tmp_ctx);
2946                                         return LDB_ERR_OPERATIONS_ERROR;
2947                                 }
2948                                 continue;
2949                         }
2950                         if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2951                                 continue;
2952                         }
2953                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2954                         if (ret != LDB_SUCCESS) {
2955                                 talloc_free(tmp_ctx);
2956                                 ldb_module_oom(module);
2957                                 return ret;
2958                         }
2959                 }
2960                 break;
2961
2962         default:
2963                 break;
2964         }
2965
2966         if (deletion_state == OBJECT_NOT_DELETED) {
2967                 const struct dsdb_attribute *sa;
2968
2969                 /* work out what the new rdn value is, for updating the
2970                    rDN and name fields */
2971                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2972                 if (new_rdn_value == NULL) {
2973                         talloc_free(tmp_ctx);
2974                         return ldb_operr(ldb);
2975                 }
2976
2977                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
2978                 if (!sa) {
2979                         talloc_free(tmp_ctx);
2980                         return LDB_ERR_OPERATIONS_ERROR;
2981                 }
2982
2983                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
2984                                         &el);
2985                 if (ret != LDB_SUCCESS) {
2986                         talloc_free(tmp_ctx);
2987                         return ret;
2988                 }
2989                 el->flags = LDB_FLAG_MOD_REPLACE;
2990
2991                 el = ldb_msg_find_element(old_msg, "name");
2992                 if (el) {
2993                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2994                         if (ret != LDB_SUCCESS) {
2995                                 talloc_free(tmp_ctx);
2996                                 return ret;
2997                         }
2998                         el->flags = LDB_FLAG_MOD_REPLACE;
2999                 }
3000         }
3001
3002         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3003         if (ret != LDB_SUCCESS) {
3004                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3005                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3006                 talloc_free(tmp_ctx);
3007                 return ret;
3008         }
3009
3010         if (deletion_state == OBJECT_NOT_DELETED) {
3011                 /* now rename onto the new DN */
3012                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3013                 if (ret != LDB_SUCCESS){
3014                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3015                                  ldb_dn_get_linearized(old_dn),
3016                                  ldb_dn_get_linearized(new_dn),
3017                                  ldb_errstring(ldb)));
3018                         talloc_free(tmp_ctx);
3019                         return ret;
3020                 }
3021         }
3022
3023         talloc_free(tmp_ctx);
3024
3025         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3026 }
3027
3028
3029
3030 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3031 {
3032         return ret;
3033 }
3034
3035 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3036 {
3037         int ret = LDB_ERR_OTHER;
3038         /* TODO: do some error mapping */
3039         return ret;
3040 }
3041
3042
3043 static struct replPropertyMetaData1 *
3044 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3045                                         enum drsuapi_DsAttributeId attid)
3046 {
3047         uint32_t i;
3048         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3049
3050         for (i = 0; i < rpmd_ctr->count; i++) {
3051                 if (rpmd_ctr->array[i].attid == attid) {
3052                         return &rpmd_ctr->array[i];
3053                 }
3054         }
3055         return NULL;
3056 }
3057
3058
3059 /*
3060    return true if an update is newer than an existing entry
3061    see section 5.11 of MS-ADTS
3062 */
3063 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3064                                    const struct GUID *update_invocation_id,
3065                                    uint32_t current_version,
3066                                    uint32_t update_version,
3067                                    NTTIME current_change_time,
3068                                    NTTIME update_change_time)
3069 {
3070         if (update_version != current_version) {
3071                 return update_version > current_version;
3072         }
3073         if (update_change_time != current_change_time) {
3074                 return update_change_time > current_change_time;
3075         }
3076         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3077 }
3078
3079 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3080                                                   struct replPropertyMetaData1 *new_m)
3081 {
3082         return replmd_update_is_newer(&cur_m->originating_invocation_id,
3083                                       &new_m->originating_invocation_id,
3084                                       cur_m->version,
3085                                       new_m->version,
3086                                       cur_m->originating_change_time,
3087                                       new_m->originating_change_time);
3088 }
3089
3090
3091 /*
3092   form a conflict DN
3093  */
3094 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3095 {
3096         const struct ldb_val *rdn_val;
3097         const char *rdn_name;
3098         struct ldb_dn *new_dn;
3099
3100         rdn_val = ldb_dn_get_rdn_val(dn);
3101         rdn_name = ldb_dn_get_rdn_name(dn);
3102         if (!rdn_val || !rdn_name) {
3103                 return NULL;
3104         }
3105
3106         new_dn = ldb_dn_copy(mem_ctx, dn);
3107         if (!new_dn) {
3108                 return NULL;
3109         }
3110
3111         if (!ldb_dn_remove_child_components(new_dn, 1)) {
3112                 return NULL;
3113         }
3114
3115         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3116                                   rdn_name,
3117                                   ldb_dn_escape_value(new_dn, *rdn_val),
3118                                   GUID_string(new_dn, guid))) {
3119                 return NULL;
3120         }
3121
3122         return new_dn;
3123 }
3124
3125
3126 /*
3127   perform a modify operation which sets the rDN and name attributes to
3128   their current values. This has the effect of changing these
3129   attributes to have been last updated by the current DC. This is
3130   needed to ensure that renames performed as part of conflict
3131   resolution are propogated to other DCs
3132  */
3133 static int replmd_name_modify(struct replmd_replicated_request *ar,
3134                               struct ldb_request *req, struct ldb_dn *dn)
3135 {
3136         struct ldb_message *msg;
3137         const char *rdn_name;
3138         const struct ldb_val *rdn_val;
3139         const struct dsdb_attribute *rdn_attr;
3140         int ret;
3141
3142         msg = ldb_msg_new(req);
3143         if (msg == NULL) {
3144                 goto failed;
3145         }
3146         msg->dn = dn;
3147
3148         rdn_name = ldb_dn_get_rdn_name(dn);
3149         if (rdn_name == NULL) {
3150                 goto failed;
3151         }
3152
3153         /* normalize the rdn attribute name */
3154         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3155         if (rdn_attr == NULL) {
3156                 goto failed;
3157         }
3158         rdn_name = rdn_attr->lDAPDisplayName;
3159
3160         rdn_val = ldb_dn_get_rdn_val(dn);
3161         if (rdn_val == NULL) {
3162                 goto failed;
3163         }
3164
3165         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3166                 goto failed;
3167         }
3168         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3169                 goto failed;
3170         }
3171         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3172                 goto failed;
3173         }
3174         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3175                 goto failed;
3176         }
3177
3178         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3179         if (ret != LDB_SUCCESS) {
3180                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3181                          ldb_dn_get_linearized(dn),
3182                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3183                 return ret;
3184         }
3185
3186         talloc_free(msg);
3187
3188         return LDB_SUCCESS;
3189
3190 failed:
3191         talloc_free(msg);
3192         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3193                  ldb_dn_get_linearized(dn)));
3194         return LDB_ERR_OPERATIONS_ERROR;
3195 }
3196
3197
3198 /*
3199   callback for conflict DN handling where we have renamed the incoming
3200   record. After renaming it, we need to ensure the change of name and
3201   rDN for the incoming record is seen as an originating update by this DC.
3202  */
3203 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3204 {
3205         struct replmd_replicated_request *ar =
3206                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3207         int ret;
3208
3209         if (ares->error != LDB_SUCCESS) {
3210                 /* call the normal callback for everything except success */
3211                 return replmd_op_callback(req, ares);
3212         }
3213
3214         /* perform a modify of the rDN and name of the record */
3215         ret = replmd_name_modify(ar, req, req->op.add.message->dn);
3216         if (ret != LDB_SUCCESS) {
3217                 ares->error = ret;
3218                 return replmd_op_callback(req, ares);
3219         }
3220
3221         return replmd_op_callback(req, ares);
3222 }
3223
3224 /*
3225   callback for replmd_replicated_apply_add()
3226   This copes with the creation of conflict records in the case where
3227   the DN exists, but with a different objectGUID
3228  */
3229 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3230 {
3231         struct ldb_dn *conflict_dn;
3232         struct replmd_replicated_request *ar =
3233                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3234         struct ldb_result *res;
3235         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3236         int ret;
3237         const struct ldb_val *rmd_value, *omd_value;
3238         struct replPropertyMetaDataBlob omd, rmd;
3239         enum ndr_err_code ndr_err;
3240         bool rename_incoming_record;
3241         struct replPropertyMetaData1 *rmd_name, *omd_name;
3242
3243         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3244                 /* call the normal callback for everything except
3245                    conflicts */
3246                 return replmd_op_callback(req, ares);
3247         }
3248
3249         /*
3250          * we have a conflict, and need to decide if we will keep the
3251          * new record or the old record
3252          */
3253         conflict_dn = req->op.add.message->dn;
3254
3255         /*
3256          * first we need the replPropertyMetaData attribute from the
3257          * old record
3258          */
3259         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3260                                     attrs,
3261                                     DSDB_FLAG_NEXT_MODULE |
3262                                     DSDB_SEARCH_SHOW_DELETED |
3263                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3264         if (ret != LDB_SUCCESS) {
3265                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3266                          ldb_dn_get_linearized(conflict_dn)));
3267                 goto failed;
3268         }
3269
3270         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3271         if (omd_value == NULL) {
3272                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3273                          ldb_dn_get_linearized(conflict_dn)));
3274                 goto failed;
3275         }
3276
3277         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3278                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3279         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3280                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3281                          ldb_dn_get_linearized(conflict_dn)));
3282                 goto failed;
3283         }
3284
3285         /*
3286          * and the replPropertyMetaData attribute from the
3287          * new record
3288          */
3289         rmd_value = ldb_msg_find_ldb_val(req->op.add.message, "replPropertyMetaData");
3290         if (rmd_value == NULL) {
3291                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for new record '%s'\n",
3292                          ldb_dn_get_linearized(conflict_dn)));
3293                 goto failed;
3294         }
3295
3296         ndr_err = ndr_pull_struct_blob(rmd_value, req, &rmd,
3297                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3298         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3299                 DEBUG(0,(__location__ ": Failed to parse new replPropertyMetaData for %s\n",
3300                          ldb_dn_get_linearized(conflict_dn)));
3301                 goto failed;
3302         }
3303
3304         /* we decide which is newer based on the RPMD on the name
3305            attribute.  See [MS-DRSR] ResolveNameConflict */
3306         rmd_name = replmd_replPropertyMetaData1_find_attid(&rmd, DRSUAPI_ATTID_name);
3307         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3308         if (!rmd_name || !omd_name) {
3309                 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3310                          ldb_dn_get_linearized(conflict_dn)));
3311                 goto failed;
3312         }
3313
3314         rename_incoming_record = !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3315
3316         if (rename_incoming_record) {
3317                 struct GUID guid;
3318                 struct ldb_dn *new_dn;
3319                 struct ldb_message *new_msg;
3320
3321                 guid = samdb_result_guid(req->op.add.message, "objectGUID");
3322                 if (GUID_all_zero(&guid)) {
3323                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3324                                  ldb_dn_get_linearized(conflict_dn)));
3325                         goto failed;
3326                 }
3327                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3328                 if (new_dn == NULL) {
3329                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3330                                  ldb_dn_get_linearized(conflict_dn)));
3331                         goto failed;
3332                 }
3333
3334                 DEBUG(1,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3335                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3336
3337                 /* re-submit the request, but with a different
3338                    callback, so we don't loop forever. */
3339                 new_msg = ldb_msg_copy_shallow(req, req->op.add.message);
3340                 if (!new_msg) {
3341                         goto failed;
3342                         DEBUG(0,(__location__ ": Failed to copy conflict DN message for %s\n",
3343                                  ldb_dn_get_linearized(conflict_dn)));
3344                 }
3345                 new_msg->dn = new_dn;
3346                 req->op.add.message = new_msg;
3347                 req->callback = replmd_op_name_modify_callback;
3348
3349                 return ldb_next_request(ar->module, req);
3350         } else {
3351                 /* we are renaming the existing record */
3352                 struct GUID guid;
3353                 struct ldb_dn *new_dn;
3354
3355                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3356                 if (GUID_all_zero(&guid)) {
3357                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3358                                  ldb_dn_get_linearized(conflict_dn)));
3359                         goto failed;
3360                 }
3361
3362                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3363                 if (new_dn == NULL) {
3364                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3365                                  ldb_dn_get_linearized(conflict_dn)));
3366                         goto failed;
3367                 }
3368
3369                 DEBUG(1,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
3370                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3371
3372                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3373                                          DSDB_FLAG_OWN_MODULE, req);
3374                 if (ret != LDB_SUCCESS) {
3375                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3376                                  ldb_dn_get_linearized(conflict_dn),
3377                                  ldb_dn_get_linearized(new_dn),
3378                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3379                         goto failed;
3380                 }
3381
3382                 /*
3383                  * now we need to ensure that the rename is seen as an
3384                  * originating update. We do that with a modify.
3385                  */
3386                 ret = replmd_name_modify(ar, req, new_dn);
3387                 if (ret != LDB_SUCCESS) {
3388                         goto failed;
3389                 }
3390
3391                 req->callback = replmd_op_callback;
3392
3393                 return ldb_next_request(ar->module, req);
3394         }
3395
3396 failed:
3397         /* on failure do the original callback. This means replication
3398          * will stop with an error, but there is not much else we can
3399          * do
3400          */
3401         return replmd_op_callback(req, ares);
3402 }
3403
3404 /*
3405   this is called when a new object comes in over DRS
3406  */
3407 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3408 {
3409         struct ldb_context *ldb;
3410         struct ldb_request *change_req;
3411         enum ndr_err_code ndr_err;
3412         struct ldb_message *msg;
3413         struct replPropertyMetaDataBlob *md;
3414         struct ldb_val md_value;
3415         unsigned int i;
3416         int ret;
3417
3418         /*
3419          * TODO: check if the parent object exist
3420          */
3421
3422         /*
3423          * TODO: handle the conflict case where an object with the
3424          *       same name exist
3425          */
3426
3427         ldb = ldb_module_get_ctx(ar->module);
3428         msg = ar->objs->objects[ar->index_current].msg;
3429         md = ar->objs->objects[ar->index_current].meta_data;
3430
3431         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3432         if (ret != LDB_SUCCESS) {
3433                 return replmd_replicated_request_error(ar, ret);
3434         }
3435
3436         ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
3437         if (ret != LDB_SUCCESS) {
3438                 return replmd_replicated_request_error(ar, ret);
3439         }
3440
3441         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3442         if (ret != LDB_SUCCESS) {
3443                 return replmd_replicated_request_error(ar, ret);
3444         }
3445
3446         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
3447         if (ret != LDB_SUCCESS) {
3448                 return replmd_replicated_request_error(ar, ret);
3449         }
3450
3451         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3452         if (ret != LDB_SUCCESS) {
3453                 return replmd_replicated_request_error(ar, ret);
3454         }
3455
3456         /* remove any message elements that have zero values */
3457         for (i=0; i<msg->num_elements; i++) {
3458                 struct ldb_message_element *el = &msg->elements[i];
3459
3460                 if (el->num_values == 0) {
3461                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
3462                                  el->name));
3463                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
3464                         msg->num_elements--;
3465                         i--;
3466                         continue;
3467                 }
3468         }
3469
3470         /*
3471          * the meta data array is already sorted by the caller
3472          */
3473         for (i=0; i < md->ctr.ctr1.count; i++) {
3474                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3475         }
3476         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3477                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3478         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3479                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3480                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3481         }
3482         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3483         if (ret != LDB_SUCCESS) {
3484                 return replmd_replicated_request_error(ar, ret);
3485         }
3486
3487         replmd_ldb_message_sort(msg, ar->schema);
3488
3489         if (DEBUGLVL(4)) {
3490                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3491                 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3492                 talloc_free(s);
3493         }
3494
3495         ret = ldb_build_add_req(&change_req,
3496                                 ldb,
3497                                 ar,
3498                                 msg,
3499                                 ar->controls,
3500                                 ar,
3501                                 replmd_op_add_callback,
3502                                 ar->req);
3503         LDB_REQ_SET_LOCATION(change_req);
3504         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3505
3506         /* current partition control needed by "repmd_op_callback" */
3507         ret = ldb_request_add_control(change_req,
3508                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3509                                       false, NULL);
3510         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3511
3512         return ldb_next_request(ar->module, change_req);
3513 }
3514
3515 /*
3516   handle renames that come in over DRS replication
3517  */
3518 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
3519                                            struct ldb_message *msg,
3520                                            struct replPropertyMetaDataBlob *rmd,
3521                                            struct replPropertyMetaDataBlob *omd,
3522                                            struct ldb_request *parent)
3523 {
3524         struct replPropertyMetaData1 *md_remote;
3525         struct replPropertyMetaData1 *md_local;
3526
3527         if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3528                 /* no rename */
3529                 return LDB_SUCCESS;
3530         }
3531
3532         /* now we need to check for double renames. We could have a
3533          * local rename pending which our replication partner hasn't
3534          * received yet. We choose which one wins by looking at the
3535          * attribute stamps on the two objects, the newer one wins
3536          */
3537         md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3538         md_local  = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3539         /* if there is no name attribute then we have to assume the
3540            object we've received is in fact newer */
3541         if (!md_remote || !md_local ||
3542             replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3543                 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3544                          ldb_dn_get_linearized(ar->search_msg->dn),
3545                          ldb_dn_get_linearized(msg->dn)));
3546                 /* pass rename to the next module
3547                  * so it doesn't appear as an originating update */
3548                 return dsdb_module_rename(ar->module,
3549                                           ar->search_msg->dn, msg->dn,
3550                                           DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX, parent);
3551         }
3552
3553         /* we're going to keep our old object */
3554         DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
3555                  ldb_dn_get_linearized(ar->search_msg->dn),
3556                  ldb_dn_get_linearized(msg->dn)));
3557         return LDB_SUCCESS;
3558 }
3559
3560
3561 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
3562 {
3563         struct ldb_context *ldb;
3564         struct ldb_request *change_req;
3565         enum ndr_err_code ndr_err;
3566         struct ldb_message *msg;
3567         struct replPropertyMetaDataBlob *rmd;
3568         struct replPropertyMetaDataBlob omd;
3569         const struct ldb_val *omd_value;
3570         struct replPropertyMetaDataBlob nmd;
3571         struct ldb_val nmd_value;
3572         unsigned int i;
3573         uint32_t j,ni=0;
3574         unsigned int removed_attrs = 0;
3575         int ret;
3576
3577         ldb = ldb_module_get_ctx(ar->module);
3578         msg = ar->objs->objects[ar->index_current].msg;
3579         rmd = ar->objs->objects[ar->index_current].meta_data;
3580         ZERO_STRUCT(omd);
3581         omd.version = 1;
3582
3583         /* find existing meta data */
3584         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
3585         if (omd_value) {
3586                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
3587                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3588                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3589                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3590                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3591                 }
3592
3593                 if (omd.version != 1) {
3594                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3595                 }
3596         }
3597
3598         /* handle renames that come in over DRS */
3599         ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
3600         if (ret != LDB_SUCCESS) {
3601                 ldb_debug(ldb, LDB_DEBUG_FATAL,
3602                           "replmd_replicated_request rename %s => %s failed - %s\n",
3603                           ldb_dn_get_linearized(ar->search_msg->dn),
3604                           ldb_dn_get_linearized(msg->dn),
3605                           ldb_errstring(ldb));
3606                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
3607         }
3608
3609         ZERO_STRUCT(nmd);
3610         nmd.version = 1;
3611         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
3612         nmd.ctr.ctr1.array = talloc_array(ar,
3613                                           struct replPropertyMetaData1,
3614                                           nmd.ctr.ctr1.count);
3615         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3616
3617         /* first copy the old meta data */
3618         for (i=0; i < omd.ctr.ctr1.count; i++) {
3619                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
3620                 ni++;
3621         }
3622
3623         ar->seq_num = 0;
3624         /* now merge in the new meta data */
3625         for (i=0; i < rmd->ctr.ctr1.count; i++) {
3626                 bool found = false;
3627
3628                 for (j=0; j < ni; j++) {
3629                         bool cmp;
3630
3631                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
3632                                 continue;
3633                         }
3634
3635                         cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
3636                                                                     &rmd->ctr.ctr1.array[i]);
3637                         if (cmp) {
3638                                 /* replace the entry */
3639                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
3640                                 if (ar->seq_num == 0) {
3641                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3642                                         if (ret != LDB_SUCCESS) {
3643                                                 return replmd_replicated_request_error(ar, ret);
3644                                         }
3645                                 }
3646                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
3647                                 found = true;
3648                                 break;
3649                         }
3650
3651                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
3652                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
3653                                          msg->elements[i-removed_attrs].name,
3654                                          ldb_dn_get_linearized(msg->dn),
3655                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
3656                         }
3657
3658                         /* we don't want to apply this change so remove the attribute */
3659                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
3660                         removed_attrs++;
3661
3662                         found = true;
3663                         break;
3664                 }
3665
3666                 if (found) continue;
3667
3668                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
3669                 if (ar->seq_num == 0) {
3670                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3671                         if (ret != LDB_SUCCESS) {
3672                                 return replmd_replicated_request_error(ar, ret);
3673                         }
3674                 }
3675                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
3676                 ni++;
3677         }
3678
3679         /*
3680          * finally correct the size of the meta_data array
3681          */
3682         nmd.ctr.ctr1.count = ni;
3683
3684         /*
3685          * the rdn attribute (the alias for the name attribute),
3686          * 'cn' for most objects is the last entry in the meta data array
3687          * we have stored
3688          *
3689          * sort the new meta data array
3690          */
3691         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
3692         if (ret != LDB_SUCCESS) {
3693                 return ret;
3694         }
3695
3696         /*
3697          * check if some replicated attributes left, otherwise skip the ldb_modify() call
3698          */
3699         if (msg->num_elements == 0) {
3700                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
3701                           ar->index_current);
3702
3703                 ar->index_current++;
3704                 return replmd_replicated_apply_next(ar);
3705         }
3706
3707         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
3708                   ar->index_current, msg->num_elements);
3709
3710         /* create the meta data value */
3711         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
3712                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3713         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3714                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3715                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3716         }
3717
3718         /*
3719          * when we know that we'll modify the record, add the whenChanged, uSNChanged
3720          * and replPopertyMetaData attributes
3721          */
3722         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3723         if (ret != LDB_SUCCESS) {
3724                 return replmd_replicated_request_error(ar, ret);
3725         }
3726         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3727         if (ret != LDB_SUCCESS) {
3728                 return replmd_replicated_request_error(ar, ret);
3729         }
3730         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
3731         if (ret != LDB_SUCCESS) {
3732                 return replmd_replicated_request_error(ar, ret);
3733         }
3734
3735         replmd_ldb_message_sort(msg, ar->schema);
3736
3737         /* we want to replace the old values */
3738         for (i=0; i < msg->num_elements; i++) {
3739                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3740         }
3741
3742         if (DEBUGLVL(4)) {
3743                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3744                 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
3745                 talloc_free(s);
3746         }
3747
3748         ret = ldb_build_mod_req(&change_req,
3749                                 ldb,
3750                                 ar,
3751                                 msg,
3752                                 ar->controls,
3753                                 ar,
3754                                 replmd_op_callback,
3755                                 ar->req);
3756         LDB_REQ_SET_LOCATION(change_req);
3757         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3758
3759         /* current partition control needed by "repmd_op_callback" */
3760         ret = ldb_request_add_control(change_req,
3761                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3762                                       false, NULL);
3763         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3764
3765         return ldb_next_request(ar->module, change_req);
3766 }
3767
3768 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
3769                                                    struct ldb_reply *ares)
3770 {
3771         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3772                                                struct replmd_replicated_request);
3773         int ret;
3774
3775         if (!ares) {
3776                 return ldb_module_done(ar->req, NULL, NULL,
3777                                         LDB_ERR_OPERATIONS_ERROR);
3778         }
3779         if (ares->error != LDB_SUCCESS &&
3780             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3781                 return ldb_module_done(ar->req, ares->controls,
3782                                         ares->response, ares->error);
3783         }
3784
3785         switch (ares->type) {
3786         case LDB_REPLY_ENTRY:
3787                 ar->search_msg = talloc_steal(ar, ares->message);
3788                 break;
3789
3790         case LDB_REPLY_REFERRAL:
3791                 /* we ignore referrals */
3792                 break;
3793
3794         case LDB_REPLY_DONE:
3795                 if (ar->search_msg != NULL) {
3796                         ret = replmd_replicated_apply_merge(ar);
3797                 } else {
3798                         ret = replmd_replicated_apply_add(ar);
3799                 }
3800                 if (ret != LDB_SUCCESS) {
3801                         return ldb_module_done(ar->req, NULL, NULL, ret);
3802                 }
3803         }
3804
3805         talloc_free(ares);
3806         return LDB_SUCCESS;
3807 }
3808
3809 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3810
3811 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3812 {
3813         struct ldb_context *ldb;
3814         int ret;
3815         char *tmp_str;
3816         char *filter;
3817         struct ldb_request *search_req;
3818         struct ldb_search_options_control *options;
3819
3820         if (ar->index_current >= ar->objs->num_objects) {
3821                 /* done with it, go to next stage */
3822                 return replmd_replicated_uptodate_vector(ar);
3823         }
3824
3825         ldb = ldb_module_get_ctx(ar->module);
3826         ar->search_msg = NULL;
3827
3828         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3829         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3830
3831         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3832         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3833         talloc_free(tmp_str);
3834
3835         ret = ldb_build_search_req(&search_req,
3836                                    ldb,
3837                                    ar,
3838                                    NULL,
3839                                    LDB_SCOPE_SUBTREE,
3840                                    filter,
3841                                    NULL,
3842                                    NULL,
3843                                    ar,
3844                                    replmd_replicated_apply_search_callback,
3845                                    ar->req);
3846         LDB_REQ_SET_LOCATION(search_req);
3847
3848         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
3849                                       true, NULL);
3850         if (ret != LDB_SUCCESS) {
3851                 return ret;
3852         }
3853
3854         /* we need to cope with cross-partition links, so search for
3855            the GUID over all partitions */
3856         options = talloc(search_req, struct ldb_search_options_control);
3857         if (options == NULL) {
3858                 DEBUG(0, (__location__ ": out of memory\n"));
3859                 return LDB_ERR_OPERATIONS_ERROR;
3860         }
3861         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3862
3863         ret = ldb_request_add_control(search_req,
3864                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
3865                                       true, options);
3866         if (ret != LDB_SUCCESS) {
3867                 return ret;
3868         }
3869
3870         return ldb_next_request(ar->module, search_req);
3871 }
3872
3873 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
3874                                                       struct ldb_reply *ares)
3875 {
3876         struct ldb_context *ldb;
3877         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3878                                                struct replmd_replicated_request);
3879         ldb = ldb_module_get_ctx(ar->module);
3880
3881         if (!ares) {
3882                 return ldb_module_done(ar->req, NULL, NULL,
3883                                         LDB_ERR_OPERATIONS_ERROR);
3884         }
3885         if (ares->error != LDB_SUCCESS) {
3886                 return ldb_module_done(ar->req, ares->controls,
3887                                         ares->response, ares->error);
3888         }
3889
3890         if (ares->type != LDB_REPLY_DONE) {
3891                 ldb_set_errstring(ldb, "Invalid reply type\n!");
3892                 return ldb_module_done(ar->req, NULL, NULL,
3893                                         LDB_ERR_OPERATIONS_ERROR);
3894         }
3895
3896         talloc_free(ares);
3897
3898         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3899 }
3900
3901 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3902 {
3903         struct ldb_context *ldb;
3904         struct ldb_request *change_req;
3905         enum ndr_err_code ndr_err;
3906         struct ldb_message *msg;
3907         struct replUpToDateVectorBlob ouv;
3908         const struct ldb_val *ouv_value;
3909         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3910         struct replUpToDateVectorBlob nuv;
3911         struct ldb_val nuv_value;
3912         struct ldb_message_element *nuv_el = NULL;
3913         const struct GUID *our_invocation_id;
3914         struct ldb_message_element *orf_el = NULL;
3915         struct repsFromToBlob nrf;
3916         struct ldb_val *nrf_value = NULL;
3917         struct ldb_message_element *nrf_el = NULL;
3918         unsigned int i;
3919         uint32_t j,ni=0;
3920         bool found = false;
3921         time_t t = time(NULL);
3922         NTTIME now;
3923         int ret;
3924         uint32_t instanceType;
3925
3926         ldb = ldb_module_get_ctx(ar->module);
3927         ruv = ar->objs->uptodateness_vector;
3928         ZERO_STRUCT(ouv);
3929         ouv.version = 2;
3930         ZERO_STRUCT(nuv);
3931         nuv.version = 2;
3932
3933         unix_to_nt_time(&now, t);
3934
3935         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
3936         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
3937                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
3938                          ldb_dn_get_linearized(ar->search_msg->dn)));
3939                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3940         }
3941
3942         /*
3943          * first create the new replUpToDateVector
3944          */
3945         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
3946         if (ouv_value) {
3947                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
3948                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3949                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3950                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3951                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3952                 }
3953
3954                 if (ouv.version != 2) {
3955                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3956                 }
3957         }
3958
3959         /*
3960          * the new uptodateness vector will at least
3961          * contain 1 entry, one for the source_dsa
3962          *
3963          * plus optional values from our old vector and the one from the source_dsa
3964          */
3965         nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
3966         if (ruv) nuv.ctr.ctr2.count += ruv->count;
3967         nuv.ctr.ctr2.cursors = talloc_array(ar,
3968                                             struct drsuapi_DsReplicaCursor2,
3969                                             nuv.ctr.ctr2.count);
3970         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3971
3972         /* first copy the old vector */
3973         for (i=0; i < ouv.ctr.ctr2.count; i++) {
3974                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
3975                 ni++;
3976         }
3977
3978         /* get our invocation_id if we have one already attached to the ldb */
3979         our_invocation_id = samdb_ntds_invocation_id(ldb);
3980
3981         /* merge in the source_dsa vector is available */
3982         for (i=0; (ruv && i < ruv->count); i++) {
3983                 found = false;
3984
3985                 if (our_invocation_id &&
3986                     GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3987                                our_invocation_id)) {
3988                         continue;
3989                 }
3990
3991                 for (j=0; j < ni; j++) {
3992                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3993                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3994                                 continue;
3995                         }
3996
3997                         found = true;
3998
3999                         /*
4000                          * we update only the highest_usn and not the latest_sync_success time,
4001                          * because the last success stands for direct replication
4002                          */
4003                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
4004                                 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
4005                         }
4006                         break;
4007                 }
4008
4009                 if (found) continue;
4010
4011                 /* if it's not there yet, add it */
4012                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
4013                 ni++;
4014         }
4015
4016         /*
4017          * merge in the current highwatermark for the source_dsa
4018          */
4019         found = false;
4020         for (j=0; j < ni; j++) {
4021                 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
4022                                 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4023                         continue;
4024                 }
4025
4026                 found = true;
4027
4028                 /*
4029                  * here we update the highest_usn and last_sync_success time
4030                  * because we're directly replicating from the source_dsa
4031                  *
4032                  * and use the tmp_highest_usn because this is what we have just applied
4033                  * to our ldb
4034                  */
4035                 nuv.ctr.ctr2.cursors[j].highest_usn             = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4036                 nuv.ctr.ctr2.cursors[j].last_sync_success       = now;
4037                 break;
4038         }
4039         if (!found) {
4040                 /*
4041                  * here we update the highest_usn and last_sync_success time
4042                  * because we're directly replicating from the source_dsa
4043                  *
4044                  * and use the tmp_highest_usn because this is what we have just applied
4045                  * to our ldb
4046                  */
4047                 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
4048                 nuv.ctr.ctr2.cursors[ni].highest_usn            = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4049                 nuv.ctr.ctr2.cursors[ni].last_sync_success      = now;
4050                 ni++;
4051         }
4052
4053         /*
4054          * finally correct the size of the cursors array
4055          */
4056         nuv.ctr.ctr2.count = ni;
4057
4058         /*
4059          * sort the cursors
4060          */
4061         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
4062
4063         /*
4064          * create the change ldb_message
4065          */
4066         msg = ldb_msg_new(ar);
4067         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4068         msg->dn = ar->search_msg->dn;
4069
4070         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
4071                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
4072         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4073                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4074                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4075         }
4076         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
4077         if (ret != LDB_SUCCESS) {
4078                 return replmd_replicated_request_error(ar, ret);
4079         }
4080         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
4081
4082         /*
4083          * now create the new repsFrom value from the given repsFromTo1 structure
4084          */
4085         ZERO_STRUCT(nrf);
4086         nrf.version                                     = 1;
4087         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
4088         nrf.ctr.ctr1.highwatermark.highest_usn          = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
4089
4090         /*
4091          * first see if we already have a repsFrom value for the current source dsa
4092          * if so we'll later replace this value
4093          */
4094         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
4095         if (orf_el) {
4096                 for (i=0; i < orf_el->num_values; i++) {
4097                         struct repsFromToBlob *trf;
4098
4099                         trf = talloc(ar, struct repsFromToBlob);
4100                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4101
4102                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
4103                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
4104                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4105                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4106                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4107                         }
4108
4109                         if (trf->version != 1) {
4110                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4111                         }
4112
4113                         /*
4114                          * we compare the source dsa objectGUID not the invocation_id
4115                          * because we want only one repsFrom value per source dsa
4116                          * and when the invocation_id of the source dsa has changed we don't need
4117                          * the old repsFrom with the old invocation_id
4118                          */
4119                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
4120                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
4121                                 talloc_free(trf);
4122                                 continue;
4123                         }
4124
4125                         talloc_free(trf);
4126                         nrf_value = &orf_el->values[i];
4127                         break;
4128                 }
4129
4130                 /*
4131                  * copy over all old values to the new ldb_message
4132                  */
4133                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
4134                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4135                 *nrf_el = *orf_el;
4136         }
4137
4138         /*
4139          * if we haven't found an old repsFrom value for the current source dsa
4140          * we'll add a new value
4141          */
4142         if (!nrf_value) {
4143                 struct ldb_val zero_value;
4144                 ZERO_STRUCT(zero_value);
4145                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
4146                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4147
4148                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
4149         }
4150
4151         /* we now fill the value which is already attached to ldb_message */
4152         ndr_err = ndr_push_struct_blob(nrf_value, msg,
4153                                        &nrf,
4154                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
4155         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4156                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4157                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4158         }
4159
4160         /*
4161          * the ldb_message_element for the attribute, has all the old values and the new one
4162          * so we'll replace the whole attribute with all values
4163          */
4164         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
4165
4166         if (DEBUGLVL(4)) {
4167                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4168                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
4169                 talloc_free(s);
4170         }
4171
4172         /* prepare the ldb_modify() request */
4173         ret = ldb_build_mod_req(&change_req,
4174                                 ldb,
4175                                 ar,
4176                                 msg,
4177                                 ar->controls,
4178                                 ar,
4179                                 replmd_replicated_uptodate_modify_callback,
4180                                 ar->req);
4181         LDB_REQ_SET_LOCATION(change_req);
4182         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4183
4184         return ldb_next_request(ar->module, change_req);
4185 }
4186
4187 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
4188                                                       struct ldb_reply *ares)
4189 {
4190         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4191                                                struct replmd_replicated_request);
4192         int ret;
4193
4194         if (!ares) {
4195                 return ldb_module_done(ar->req, NULL, NULL,
4196                                         LDB_ERR_OPERATIONS_ERROR);
4197         }
4198         if (ares->error != LDB_SUCCESS &&
4199             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4200                 return ldb_module_done(ar->req, ares->controls,
4201                                         ares->response, ares->error);
4202         }
4203
4204         switch (ares->type) {
4205         case LDB_REPLY_ENTRY:
4206                 ar->search_msg = talloc_steal(ar, ares->message);
4207                 break;
4208
4209         case LDB_REPLY_REFERRAL:
4210                 /* we ignore referrals */
4211                 break;
4212
4213         case LDB_REPLY_DONE:
4214                 if (ar->search_msg == NULL) {
4215                         ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4216                 } else {
4217                         ret = replmd_replicated_uptodate_modify(ar);
4218                 }
4219                 if (ret != LDB_SUCCESS) {
4220                         return ldb_module_done(ar->req, NULL, NULL, ret);
4221                 }
4222         }
4223
4224         talloc_free(ares);
4225         return LDB_SUCCESS;
4226 }
4227
4228
4229 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
4230 {
4231         struct ldb_context *ldb;
4232         int ret;
4233         static const char *attrs[] = {
4234                 "replUpToDateVector",
4235                 "repsFrom",
4236                 "instanceType",
4237                 NULL
4238         };
4239         struct ldb_request *search_req;
4240
4241         ldb = ldb_module_get_ctx(ar->module);
4242         ar->search_msg = NULL;
4243
4244         ret = ldb_build_search_req(&search_req,
4245                                    ldb,
4246                                    ar,
4247                                    ar->objs->partition_dn,
4248                                    LDB_SCOPE_BASE,
4249                                    "(objectClass=*)",
4250                                    attrs,
4251                                    NULL,
4252                                    ar,
4253                                    replmd_replicated_uptodate_search_callback,
4254                                    ar->req);
4255         LDB_REQ_SET_LOCATION(search_req);
4256         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4257
4258         return ldb_next_request(ar->module, search_req);
4259 }
4260
4261
4262
4263 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
4264 {
4265         struct ldb_context *ldb;
4266         struct dsdb_extended_replicated_objects *objs;
4267         struct replmd_replicated_request *ar;
4268         struct ldb_control **ctrls;
4269         int ret;
4270         uint32_t i;
4271         struct replmd_private *replmd_private =
4272                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4273
4274         ldb = ldb_module_get_ctx(module);
4275
4276         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
4277
4278         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
4279         if (!objs) {
4280                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
4281                 return LDB_ERR_PROTOCOL_ERROR;
4282         }
4283
4284         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
4285                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
4286                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
4287                 return LDB_ERR_PROTOCOL_ERROR;
4288         }
4289
4290         ar = replmd_ctx_init(module, req);
4291         if (!ar)
4292                 return LDB_ERR_OPERATIONS_ERROR;
4293
4294         /* Set the flags to have the replmd_op_callback run over the full set of objects */
4295         ar->apply_mode = true;
4296         ar->objs = objs;
4297         ar->schema = dsdb_get_schema(ldb, ar);
4298         if (!ar->schema) {
4299                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
4300                 talloc_free(ar);
4301                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4302                 return LDB_ERR_CONSTRAINT_VIOLATION;
4303         }
4304
4305         ctrls = req->controls;
4306
4307         if (req->controls) {
4308                 req->controls = talloc_memdup(ar, req->controls,
4309                                               talloc_get_size(req->controls));
4310                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4311         }
4312
4313         /* This allows layers further down to know if a change came in over replication */
4314         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
4315         if (ret != LDB_SUCCESS) {
4316                 return ret;
4317         }
4318
4319         /* If this change contained linked attributes in the body
4320          * (rather than in the links section) we need to update
4321          * backlinks in linked_attributes */
4322         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
4323         if (ret != LDB_SUCCESS) {
4324                 return ret;
4325         }
4326
4327         ar->controls = req->controls;
4328         req->controls = ctrls;
4329
4330         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
4331
4332         /* save away the linked attributes for the end of the
4333            transaction */
4334         for (i=0; i<ar->objs->linked_attributes_count; i++) {
4335                 struct la_entry *la_entry;
4336
4337                 if (replmd_private->la_ctx == NULL) {
4338                         replmd_private->la_ctx = talloc_new(replmd_private);
4339                 }
4340                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
4341                 if (la_entry == NULL) {
4342                         ldb_oom(ldb);
4343                         return LDB_ERR_OPERATIONS_ERROR;
4344                 }
4345                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
4346                 if (la_entry->la == NULL) {
4347                         talloc_free(la_entry);
4348                         ldb_oom(ldb);
4349                         return LDB_ERR_OPERATIONS_ERROR;
4350                 }
4351                 *la_entry->la = ar->objs->linked_attributes[i];
4352
4353                 /* we need to steal the non-scalars so they stay
4354                    around until the end of the transaction */
4355                 talloc_steal(la_entry->la, la_entry->la->identifier);
4356                 talloc_steal(la_entry->la, la_entry->la->value.blob);
4357
4358                 DLIST_ADD(replmd_private->la_list, la_entry);
4359         }
4360
4361         return replmd_replicated_apply_next(ar);
4362 }
4363
4364 /*
4365   process one linked attribute structure
4366  */
4367 static int replmd_process_linked_attribute(struct ldb_module *module,
4368                                            struct la_entry *la_entry,
4369                                            struct ldb_request *parent)
4370 {
4371         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
4372         struct ldb_context *ldb = ldb_module_get_ctx(module);
4373         struct ldb_message *msg;
4374         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
4375         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
4376         int ret;
4377         const struct dsdb_attribute *attr;
4378         struct dsdb_dn *dsdb_dn;
4379         uint64_t seq_num = 0;
4380         struct ldb_message_element *old_el;
4381         WERROR status;
4382         time_t t = time(NULL);
4383         struct ldb_result *res;
4384         const char *attrs[2];
4385         struct parsed_dn *pdn_list, *pdn;
4386         struct GUID guid = GUID_zero();
4387         NTSTATUS ntstatus;
4388         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
4389         const struct GUID *our_invocation_id;
4390
4391 /*
4392 linked_attributes[0]:
4393      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
4394         identifier               : *
4395             identifier: struct drsuapi_DsReplicaObjectIdentifier
4396                 __ndr_size               : 0x0000003a (58)
4397                 __ndr_size_sid           : 0x00000000 (0)
4398                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
4399                 sid                      : S-0-0
4400                 __ndr_size_dn            : 0x00000000 (0)
4401                 dn                       : ''
4402         attid                    : DRSUAPI_ATTID_member (0x1F)
4403         value: struct drsuapi_DsAttributeValue
4404             __ndr_size               : 0x0000007e (126)
4405             blob                     : *
4406                 blob                     : DATA_BLOB length=126
4407         flags                    : 0x00000001 (1)
4408                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
4409         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
4410         meta_data: struct drsuapi_DsReplicaMetaData
4411             version                  : 0x00000015 (21)
4412             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
4413             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
4414             originating_usn          : 0x000000000001e19c (123292)
4415
4416 (for cases where the link is to a normal DN)
4417      &target: struct drsuapi_DsReplicaObjectIdentifier3
4418         __ndr_size               : 0x0000007e (126)
4419         __ndr_size_sid           : 0x0000001c (28)
4420         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
4421         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
4422         __ndr_size_dn            : 0x00000022 (34)
4423         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
4424  */
4425
4426         /* find the attribute being modified */
4427         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
4428         if (attr == NULL) {
4429                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
4430                 talloc_free(tmp_ctx);
4431                 return LDB_ERR_OPERATIONS_ERROR;
4432         }
4433
4434         attrs[0] = attr->lDAPDisplayName;
4435         attrs[1] = NULL;
4436
4437         /* get the existing message from the db for the object with
4438            this GUID, returning attribute being modified. We will then
4439            use this msg as the basis for a modify call */
4440         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
4441                                  DSDB_FLAG_NEXT_MODULE |
4442                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
4443                                  DSDB_SEARCH_SHOW_RECYCLED |
4444                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4445                                  DSDB_SEARCH_REVEAL_INTERNALS,
4446                                  parent,
4447                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
4448         if (ret != LDB_SUCCESS) {
4449                 talloc_free(tmp_ctx);
4450                 return ret;
4451         }
4452         if (res->count != 1) {
4453                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
4454                                        GUID_string(tmp_ctx, &la->identifier->guid));
4455                 talloc_free(tmp_ctx);
4456                 return LDB_ERR_NO_SUCH_OBJECT;
4457         }
4458         msg = res->msgs[0];
4459
4460         if (msg->num_elements == 0) {
4461                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
4462                 if (ret != LDB_SUCCESS) {
4463                         ldb_module_oom(module);
4464                         talloc_free(tmp_ctx);
4465                         return LDB_ERR_OPERATIONS_ERROR;
4466                 }
4467         } else {
4468                 old_el = &msg->elements[0];
4469                 old_el->flags = LDB_FLAG_MOD_REPLACE;
4470         }
4471
4472         /* parse the existing links */
4473         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
4474         if (ret != LDB_SUCCESS) {
4475                 talloc_free(tmp_ctx);
4476                 return ret;
4477         }
4478
4479         /* get our invocationId */
4480         our_invocation_id = samdb_ntds_invocation_id(ldb);
4481         if (!our_invocation_id) {
4482                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
4483                 talloc_free(tmp_ctx);
4484                 return LDB_ERR_OPERATIONS_ERROR;
4485         }
4486
4487         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
4488         if (ret != LDB_SUCCESS) {
4489                 talloc_free(tmp_ctx);
4490                 return ret;
4491         }
4492
4493         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
4494         if (!W_ERROR_IS_OK(status)) {
4495                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
4496                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
4497                 return LDB_ERR_OPERATIONS_ERROR;
4498         }
4499
4500         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
4501         if (!NT_STATUS_IS_OK(ntstatus) && active) {
4502                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
4503                                        old_el->name,
4504                                        ldb_dn_get_linearized(dsdb_dn->dn),
4505                                        ldb_dn_get_linearized(msg->dn));
4506                 return LDB_ERR_OPERATIONS_ERROR;
4507         }
4508
4509         /* re-resolve the DN by GUID, as the DRS server may give us an
4510            old DN value */
4511         ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
4512         if (ret != LDB_SUCCESS) {
4513                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s",
4514                          GUID_string(tmp_ctx, &guid),
4515                          ldb_dn_get_linearized(dsdb_dn->dn)));
4516         }
4517
4518         /* see if this link already exists */
4519         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
4520         if (pdn != NULL) {
4521                 /* see if this update is newer than what we have already */
4522                 struct GUID invocation_id = GUID_zero();
4523                 uint32_t version = 0;
4524                 uint32_t originating_usn = 0;
4525                 NTTIME change_time = 0;
4526                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
4527
4528                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
4529                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
4530                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
4531                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
4532
4533                 if (!replmd_update_is_newer(&invocation_id,
4534                                             &la->meta_data.originating_invocation_id,
4535                                             version,
4536                                             la->meta_data.version,
4537                                             change_time,
4538                                             la->meta_data.originating_change_time)) {
4539                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
4540                                  old_el->name, ldb_dn_get_linearized(msg->dn),
4541                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
4542                         talloc_free(tmp_ctx);
4543                         return LDB_SUCCESS;
4544                 }
4545
4546                 /* get a seq_num for this change */
4547                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4548                 if (ret != LDB_SUCCESS) {
4549                         talloc_free(tmp_ctx);
4550                         return ret;
4551                 }
4552
4553                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
4554                         /* remove the existing backlink */
4555                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
4556                         if (ret != LDB_SUCCESS) {
4557                                 talloc_free(tmp_ctx);
4558                                 return ret;
4559                         }
4560                 }
4561
4562                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
4563                                            &la->meta_data.originating_invocation_id,
4564                                            la->meta_data.originating_usn, seq_num,
4565                                            la->meta_data.originating_change_time,
4566                                            la->meta_data.version,
4567                                            !active);
4568                 if (ret != LDB_SUCCESS) {
4569                         talloc_free(tmp_ctx);
4570                         return ret;
4571                 }
4572
4573                 if (active) {
4574                         /* add the new backlink */
4575                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
4576                         if (ret != LDB_SUCCESS) {
4577                                 talloc_free(tmp_ctx);
4578                                 return ret;
4579                         }
4580                 }
4581         } else {
4582                 /* get a seq_num for this change */
4583                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4584                 if (ret != LDB_SUCCESS) {
4585                         talloc_free(tmp_ctx);
4586                         return ret;
4587                 }
4588
4589                 old_el->values = talloc_realloc(msg->elements, old_el->values,
4590                                                 struct ldb_val, old_el->num_values+1);
4591                 if (!old_el->values) {
4592                         ldb_module_oom(module);
4593                         return LDB_ERR_OPERATIONS_ERROR;
4594                 }
4595                 old_el->num_values++;
4596
4597                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
4598                                           &la->meta_data.originating_invocation_id,
4599                                           la->meta_data.originating_usn, seq_num,
4600                                           la->meta_data.originating_change_time,
4601                                           la->meta_data.version,
4602                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
4603                 if (ret != LDB_SUCCESS) {
4604                         talloc_free(tmp_ctx);
4605                         return ret;
4606                 }
4607
4608                 if (active) {
4609                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
4610                                                   true, attr, false);
4611                         if (ret != LDB_SUCCESS) {
4612                                 talloc_free(tmp_ctx);
4613                                 return ret;
4614                         }
4615                 }
4616         }
4617
4618         /* we only change whenChanged and uSNChanged if the seq_num
4619            has changed */
4620         if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
4621                 talloc_free(tmp_ctx);
4622                 return ldb_operr(ldb);
4623         }
4624
4625         if (add_uint64_element(ldb, msg, "uSNChanged",
4626                                seq_num) != LDB_SUCCESS) {
4627                 talloc_free(tmp_ctx);
4628                 return ldb_operr(ldb);
4629         }
4630
4631         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
4632         if (old_el == NULL) {
4633                 talloc_free(tmp_ctx);
4634                 return ldb_operr(ldb);
4635         }
4636
4637         ret = dsdb_check_single_valued_link(attr, old_el);
4638         if (ret != LDB_SUCCESS) {
4639                 talloc_free(tmp_ctx);
4640                 return ret;
4641         }
4642
4643         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
4644
4645         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
4646         if (ret != LDB_SUCCESS) {
4647                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
4648                           ldb_errstring(ldb),
4649                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
4650                 talloc_free(tmp_ctx);
4651                 return ret;
4652         }
4653
4654         talloc_free(tmp_ctx);
4655
4656         return ret;
4657 }
4658
4659 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
4660 {
4661         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
4662                 return replmd_extended_replicated_objects(module, req);
4663         }
4664
4665         return ldb_next_request(module, req);
4666 }
4667
4668
4669 /*
4670   we hook into the transaction operations to allow us to
4671   perform the linked attribute updates at the end of the whole
4672   transaction. This allows a forward linked attribute to be created
4673   before the object is created. During a vampire, w2k8 sends us linked
4674   attributes before the objects they are part of.
4675  */
4676 static int replmd_start_transaction(struct ldb_module *module)
4677 {
4678         /* create our private structure for this transaction */
4679         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
4680                                                                 struct replmd_private);
4681         replmd_txn_cleanup(replmd_private);
4682
4683         /* free any leftover mod_usn records from cancelled
4684            transactions */
4685         while (replmd_private->ncs) {
4686                 struct nc_entry *e = replmd_private->ncs;
4687                 DLIST_REMOVE(replmd_private->ncs, e);
4688                 talloc_free(e);
4689         }
4690
4691         return ldb_next_start_trans(module);
4692 }
4693
4694 /*
4695   on prepare commit we loop over our queued la_context structures and
4696   apply each of them
4697  */
4698 static int replmd_prepare_commit(struct ldb_module *module)
4699 {
4700         struct replmd_private *replmd_private =
4701                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4702         struct la_entry *la, *prev;
4703         struct la_backlink *bl;
4704         int ret;
4705
4706         /* walk the list backwards, to do the first entry first, as we
4707          * added the entries with DLIST_ADD() which puts them at the
4708          * start of the list */
4709         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
4710                 prev = DLIST_PREV(la);
4711                 DLIST_REMOVE(replmd_private->la_list, la);
4712                 ret = replmd_process_linked_attribute(module, la, NULL);
4713                 if (ret != LDB_SUCCESS) {
4714                         replmd_txn_cleanup(replmd_private);
4715                         return ret;
4716                 }
4717         }
4718
4719         /* process our backlink list, creating and deleting backlinks
4720            as necessary */
4721         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
4722                 ret = replmd_process_backlink(module, bl, NULL);
4723                 if (ret != LDB_SUCCESS) {
4724                         replmd_txn_cleanup(replmd_private);
4725                         return ret;
4726                 }
4727         }
4728
4729         replmd_txn_cleanup(replmd_private);
4730
4731         /* possibly change @REPLCHANGED */
4732         ret = replmd_notify_store(module, NULL);
4733         if (ret != LDB_SUCCESS) {
4734                 return ret;
4735         }
4736
4737         return ldb_next_prepare_commit(module);
4738 }
4739
4740 static int replmd_del_transaction(struct ldb_module *module)
4741 {
4742         struct replmd_private *replmd_private =
4743                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4744         replmd_txn_cleanup(replmd_private);
4745
4746         return ldb_next_del_trans(module);
4747 }
4748
4749
4750 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
4751         .name          = "repl_meta_data",
4752         .init_context      = replmd_init,
4753         .add               = replmd_add,
4754         .modify            = replmd_modify,
4755         .rename            = replmd_rename,
4756         .del               = replmd_delete,
4757         .extended          = replmd_extended,
4758         .start_transaction = replmd_start_transaction,
4759         .prepare_commit    = replmd_prepare_commit,
4760         .del_transaction   = replmd_del_transaction,
4761 };
4762
4763 int ldb_repl_meta_data_module_init(const char *version)
4764 {
4765         LDB_MODULE_CHECK_VERSION(version);
4766         return ldb_register_module(&ldb_repl_meta_data_module_ops);
4767 }