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