s4-drs: Fixes bugs regarding Urgent Replication on wrong situations
[samba.git] / source4 / dsdb / samdb / ldb_modules / repl_meta_data.c
1 /* 
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 /*
24  *  Name: ldb
25  *
26  *  Component: ldb repl_meta_data module
27  *
28  *  Description: - add a unique objectGUID onto every new record,
29  *               - handle whenCreated, whenChanged timestamps
30  *               - handle uSNCreated, uSNChanged numbers
31  *               - handle replPropertyMetaData attribute
32  *
33  *  Author: Simo Sorce
34  *  Author: Stefan Metzmacher
35  */
36
37 #include "includes.h"
38 #include "ldb_module.h"
39 #include "dsdb/samdb/samdb.h"
40 #include "dsdb/common/proto.h"
41 #include "../libds/common/flags.h"
42 #include "librpc/gen_ndr/ndr_misc.h"
43 #include "librpc/gen_ndr/ndr_drsuapi.h"
44 #include "librpc/gen_ndr/ndr_drsblobs.h"
45 #include "param/param.h"
46 #include "libcli/security/dom_sid.h"
47 #include "lib/util/dlinklist.h"
48 #include "dsdb/samdb/ldb_modules/util.h"
49 #include "lib/util/binsearch.h"
50 #include "libcli/security/security.h"
51 #include "lib/util/tsort.h"
52
53 #define W2K3_LINKED_ATTRIBUTES 1
54
55 struct replmd_private {
56         TALLOC_CTX *la_ctx;
57         struct la_entry *la_list;
58         TALLOC_CTX *bl_ctx;
59         struct la_backlink *la_backlinks;
60         struct nc_entry {
61                 struct nc_entry *prev, *next;
62                 struct ldb_dn *dn;
63                 uint64_t mod_usn;
64                 uint64_t mod_usn_urgent;
65         } *ncs;
66 };
67
68 struct la_entry {
69         struct la_entry *next, *prev;
70         struct drsuapi_DsReplicaLinkedAttribute *la;
71 };
72
73 struct replmd_replicated_request {
74         struct ldb_module *module;
75         struct ldb_request *req;
76
77         const struct dsdb_schema *schema;
78
79         /* the controls we pass down */
80         struct ldb_control **controls;
81
82         /* details for the mode where we apply a bunch of inbound replication meessages */
83         bool apply_mode;
84         uint32_t index_current;
85         struct dsdb_extended_replicated_objects *objs;
86
87         struct ldb_message *search_msg;
88
89         uint64_t seq_num;
90         bool is_urgent;
91 };
92
93 enum urgent_situation {
94         REPL_URGENT_ON_CREATE = 1,
95         REPL_URGENT_ON_UPDATE = 2,
96         REPL_URGENT_ON_DELETE = 4
97 };
98
99
100 static const struct {
101         const char *update_name;
102         enum urgent_situation repl_situation;
103 } urgent_objects[] = {
104                 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
105                 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
106                 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
107                 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
108                 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
109                 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
110                 {NULL, 0}
111 };
112
113 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
114 static const char *urgent_attrs[] = {
115                 "lockoutTime",
116                 "pwdLastSet",
117                 "userAccountControl",
118                 NULL
119 };
120
121
122 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
123                                         enum urgent_situation situation)
124 {
125         int i, j;
126         for (i=0; urgent_objects[i].update_name; i++) {
127
128                 if ((situation & urgent_objects[i].repl_situation) == 0) {
129                         continue;
130                 }
131
132                 for (j=0; j<objectclass_el->num_values; j++) {
133                         const struct ldb_val *v = &objectclass_el->values[j];
134                         if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
135                                 return true;
136                         }
137                 }
138         }
139         return false;
140 }
141
142 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
143 {
144         if (ldb_attr_in_list(urgent_attrs, el->name)) {
145                 return true;
146         }
147         return false;
148 }
149
150
151 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
152
153 /*
154   initialise the module
155   allocate the private structure and build the list
156   of partition DNs for use by replmd_notify()
157  */
158 static int replmd_init(struct ldb_module *module)
159 {
160         struct replmd_private *replmd_private;
161         struct ldb_context *ldb = ldb_module_get_ctx(module);
162
163         replmd_private = talloc_zero(module, struct replmd_private);
164         if (replmd_private == NULL) {
165                 ldb_oom(ldb);
166                 return LDB_ERR_OPERATIONS_ERROR;
167         }
168         ldb_module_set_private(module, replmd_private);
169
170         return ldb_next_init(module);
171 }
172
173 /*
174   cleanup our per-transaction contexts
175  */
176 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
177 {
178         talloc_free(replmd_private->la_ctx);
179         replmd_private->la_list = NULL;
180         replmd_private->la_ctx = NULL;
181
182         talloc_free(replmd_private->bl_ctx);
183         replmd_private->la_backlinks = NULL;
184         replmd_private->bl_ctx = NULL;
185 }
186
187
188 struct la_backlink {
189         struct la_backlink *next, *prev;
190         const char *attr_name;
191         struct GUID forward_guid, target_guid;
192         bool active;
193 };
194
195 /*
196   process a backlinks we accumulated during a transaction, adding and
197   deleting the backlinks from the target objects
198  */
199 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl)
200 {
201         struct ldb_dn *target_dn, *source_dn;
202         int ret;
203         struct ldb_context *ldb = ldb_module_get_ctx(module);
204         struct ldb_message *msg;
205         TALLOC_CTX *tmp_ctx = talloc_new(bl);
206         char *dn_string;
207
208         /*
209           - find DN of target
210           - find DN of source
211           - construct ldb_message
212               - either an add or a delete
213          */
214         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn);
215         if (ret != LDB_SUCCESS) {
216                 ldb_asprintf_errstring(ldb, "Failed to find target DN for linked attribute with GUID %s\n",
217                                        GUID_string(bl, &bl->target_guid));
218                 talloc_free(tmp_ctx);
219                 return ret;
220         }
221
222         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn);
223         if (ret != LDB_SUCCESS) {
224                 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
225                                        GUID_string(bl, &bl->forward_guid));
226                 talloc_free(tmp_ctx);
227                 return ret;
228         }
229
230         msg = ldb_msg_new(tmp_ctx);
231         if (msg == NULL) {
232                 ldb_module_oom(module);
233                 talloc_free(tmp_ctx);
234                 return LDB_ERR_OPERATIONS_ERROR;
235         }
236
237         /* construct a ldb_message for adding/deleting the backlink */
238         msg->dn = target_dn;
239         dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
240         if (!dn_string) {
241                 ldb_module_oom(module);
242                 talloc_free(tmp_ctx);
243                 return LDB_ERR_OPERATIONS_ERROR;
244         }
245         ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
246         if (ret != LDB_SUCCESS) {
247                 talloc_free(tmp_ctx);
248                 return ret;
249         }
250         msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
251
252         ret = dsdb_module_modify(module, msg, 0);
253         if (ret != LDB_SUCCESS) {
254                 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
255                                        bl->active?"add":"remove",
256                                        ldb_dn_get_linearized(source_dn),
257                                        ldb_dn_get_linearized(target_dn),
258                                        ldb_errstring(ldb));
259                 talloc_free(tmp_ctx);
260                 return ret;
261         }
262         talloc_free(tmp_ctx);
263         return ret;
264 }
265
266 /*
267   add a backlink to the list of backlinks to add/delete in the prepare
268   commit
269  */
270 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
271                                struct GUID *forward_guid, struct GUID *target_guid,
272                                bool active, const struct dsdb_attribute *schema_attr, bool immediate)
273 {
274         const struct dsdb_attribute *target_attr;
275         struct la_backlink *bl;
276         struct replmd_private *replmd_private =
277                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
278
279         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
280         if (!target_attr) {
281                 /*
282                  * windows 2003 has a broken schema where the
283                  * definition of msDS-IsDomainFor is missing (which is
284                  * supposed to be the backlink of the
285                  * msDS-HasDomainNCs attribute
286                  */
287                 return LDB_SUCCESS;
288         }
289
290         /* see if its already in the list */
291         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
292                 if (GUID_equal(forward_guid, &bl->forward_guid) &&
293                     GUID_equal(target_guid, &bl->target_guid) &&
294                     (target_attr->lDAPDisplayName == bl->attr_name ||
295                      strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
296                         break;
297                 }
298         }
299
300         if (bl) {
301                 /* we found an existing one */
302                 if (bl->active == active) {
303                         return LDB_SUCCESS;
304                 }
305                 DLIST_REMOVE(replmd_private->la_backlinks, bl);
306                 talloc_free(bl);
307                 return LDB_SUCCESS;
308         }
309
310         if (replmd_private->bl_ctx == NULL) {
311                 replmd_private->bl_ctx = talloc_new(replmd_private);
312                 if (replmd_private->bl_ctx == NULL) {
313                         ldb_module_oom(module);
314                         return LDB_ERR_OPERATIONS_ERROR;
315                 }
316         }
317
318         /* its a new one */
319         bl = talloc(replmd_private->bl_ctx, struct la_backlink);
320         if (bl == NULL) {
321                 ldb_module_oom(module);
322                 return LDB_ERR_OPERATIONS_ERROR;
323         }
324
325         bl->attr_name = target_attr->lDAPDisplayName;
326         bl->forward_guid = *forward_guid;
327         bl->target_guid = *target_guid;
328         bl->active = active;
329
330         /* the caller may ask for this backlink to be processed
331            immediately */
332         if (immediate) {
333                 int ret = replmd_process_backlink(module, bl);
334                 talloc_free(bl);
335                 return ret;
336         }
337
338         DLIST_ADD(replmd_private->la_backlinks, bl);
339
340         return LDB_SUCCESS;
341 }
342
343
344 /*
345  * Callback for most write operations in this module:
346  * 
347  * notify the repl task that a object has changed. The notifies are
348  * gathered up in the replmd_private structure then written to the
349  * @REPLCHANGED object in each partition during the prepare_commit
350  */
351 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
352 {
353         int ret;
354         struct replmd_replicated_request *ac = 
355                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
356         struct replmd_private *replmd_private = 
357                 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
358         struct nc_entry *modified_partition;
359         struct ldb_control *partition_ctrl;
360         const struct dsdb_control_current_partition *partition;
361
362         struct ldb_control **controls;
363
364         partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
365
366         /* Remove the 'partition' control from what we pass up the chain */
367         controls = controls_except_specified(ares->controls, ares, partition_ctrl);
368
369         if (ares->error != LDB_SUCCESS) {
370                 return ldb_module_done(ac->req, controls,
371                                         ares->response, ares->error);
372         }
373
374         if (ares->type != LDB_REPLY_DONE) {
375                 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
376                 return ldb_module_done(ac->req, NULL,
377                                        NULL, LDB_ERR_OPERATIONS_ERROR);
378         }
379
380         if (!partition_ctrl) {
381                 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
382                 return ldb_module_done(ac->req, NULL,
383                                        NULL, LDB_ERR_OPERATIONS_ERROR);
384         }
385
386         partition = talloc_get_type_abort(partition_ctrl->data,
387                                     struct dsdb_control_current_partition);
388         
389         if (ac->seq_num > 0) {
390                 for (modified_partition = replmd_private->ncs; modified_partition; 
391                      modified_partition = modified_partition->next) {
392                         if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
393                                 break;
394                         }
395                 }
396                 
397                 if (modified_partition == NULL) {
398                         modified_partition = talloc_zero(replmd_private, struct nc_entry);
399                         if (!modified_partition) {
400                                 ldb_oom(ldb_module_get_ctx(ac->module));
401                                 return ldb_module_done(ac->req, NULL,
402                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
403                         }
404                         modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
405                         if (!modified_partition->dn) {
406                                 ldb_oom(ldb_module_get_ctx(ac->module));
407                                 return ldb_module_done(ac->req, NULL,
408                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
409                         }
410                         DLIST_ADD(replmd_private->ncs, modified_partition);
411                 }
412
413                 if (ac->seq_num > modified_partition->mod_usn) {
414                         modified_partition->mod_usn = ac->seq_num;
415                         if (ac->is_urgent) {
416                                 modified_partition->mod_usn_urgent = ac->seq_num;
417                         }
418                 }
419         }
420
421         if (ac->apply_mode) {
422                 talloc_free(ares);
423                 ac->index_current++;
424                 
425                 ret = replmd_replicated_apply_next(ac);
426                 if (ret != LDB_SUCCESS) {
427                         return ldb_module_done(ac->req, NULL, NULL, ret);
428                 }
429                 return ret;
430         } else {
431                 /* free the partition control container here, for the
432                  * common path.  Other cases will have it cleaned up
433                  * eventually with the ares */
434                 talloc_free(partition_ctrl);
435                 return ldb_module_done(ac->req, 
436                                        controls_except_specified(controls, ares, partition_ctrl),
437                                        ares->response, LDB_SUCCESS);
438         }
439 }
440
441
442 /*
443  * update a @REPLCHANGED record in each partition if there have been
444  * any writes of replicated data in the partition
445  */
446 static int replmd_notify_store(struct ldb_module *module)
447 {
448         struct replmd_private *replmd_private =
449                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
450         struct ldb_context *ldb = ldb_module_get_ctx(module);
451
452         while (replmd_private->ncs) {
453                 int ret;
454                 struct nc_entry *modified_partition = replmd_private->ncs;
455
456                 ret = dsdb_save_partition_usn(ldb, modified_partition->dn,
457                                                 modified_partition->mod_usn,
458                                                 modified_partition->mod_usn_urgent);
459                 if (ret != LDB_SUCCESS) {
460                         DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
461                                  ldb_dn_get_linearized(modified_partition->dn)));
462                         return ret;
463                 }
464                 DLIST_REMOVE(replmd_private->ncs, modified_partition);
465                 talloc_free(modified_partition);
466         }
467
468         return LDB_SUCCESS;
469 }
470
471
472 /*
473   created a replmd_replicated_request context
474  */
475 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
476                                                          struct ldb_request *req)
477 {
478         struct ldb_context *ldb;
479         struct replmd_replicated_request *ac;
480
481         ldb = ldb_module_get_ctx(module);
482
483         ac = talloc_zero(req, struct replmd_replicated_request);
484         if (ac == NULL) {
485                 ldb_oom(ldb);
486                 return NULL;
487         }
488
489         ac->module = module;
490         ac->req = req;
491
492         ac->schema = dsdb_get_schema(ldb);
493         if (!ac->schema) {
494                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
495                               "replmd_modify: no dsdb_schema loaded");
496                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
497                 return NULL;
498         }
499
500         return ac;
501 }
502
503 /*
504   add a time element to a record
505 */
506 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
507 {
508         struct ldb_message_element *el;
509         char *s;
510
511         if (ldb_msg_find_element(msg, attr) != NULL) {
512                 return LDB_SUCCESS;
513         }
514
515         s = ldb_timestring(msg, t);
516         if (s == NULL) {
517                 return LDB_ERR_OPERATIONS_ERROR;
518         }
519
520         if (ldb_msg_add_string(msg, attr, s) != LDB_SUCCESS) {
521                 return LDB_ERR_OPERATIONS_ERROR;
522         }
523
524         el = ldb_msg_find_element(msg, attr);
525         /* always set as replace. This works because on add ops, the flag
526            is ignored */
527         el->flags = LDB_FLAG_MOD_REPLACE;
528
529         return LDB_SUCCESS;
530 }
531
532 /*
533   add a uint64_t element to a record
534 */
535 static int add_uint64_element(struct ldb_message *msg, const char *attr, uint64_t v)
536 {
537         struct ldb_message_element *el;
538
539         if (ldb_msg_find_element(msg, attr) != NULL) {
540                 return LDB_SUCCESS;
541         }
542
543         if (ldb_msg_add_fmt(msg, attr, "%llu", (unsigned long long)v) != LDB_SUCCESS) {
544                 return LDB_ERR_OPERATIONS_ERROR;
545         }
546
547         el = ldb_msg_find_element(msg, attr);
548         /* always set as replace. This works because on add ops, the flag
549            is ignored */
550         el->flags = LDB_FLAG_MOD_REPLACE;
551
552         return LDB_SUCCESS;
553 }
554
555 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
556                                                    const struct replPropertyMetaData1 *m2,
557                                                    const uint32_t *rdn_attid)
558 {
559         if (m1->attid == m2->attid) {
560                 return 0;
561         }
562
563         /*
564          * the rdn attribute should be at the end!
565          * so we need to return a value greater than zero
566          * which means m1 is greater than m2
567          */
568         if (m1->attid == *rdn_attid) {
569                 return 1;
570         }
571
572         /*
573          * the rdn attribute should be at the end!
574          * so we need to return a value less than zero
575          * which means m2 is greater than m1
576          */
577         if (m2->attid == *rdn_attid) {
578                 return -1;
579         }
580
581         return m1->attid > m2->attid ? 1 : -1;
582 }
583
584 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
585                                                 const struct dsdb_schema *schema,
586                                                 struct ldb_dn *dn)
587 {
588         const char *rdn_name;
589         const struct dsdb_attribute *rdn_sa;
590
591         rdn_name = ldb_dn_get_rdn_name(dn);
592         if (!rdn_name) {
593                 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
594                 return LDB_ERR_OPERATIONS_ERROR;
595         }
596
597         rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
598         if (rdn_sa == NULL) {
599                 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
600                 return LDB_ERR_OPERATIONS_ERROR;                
601         }
602
603         DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n", 
604                  rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
605
606         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
607
608         return LDB_SUCCESS;
609 }
610
611 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
612                                                  const struct ldb_message_element *e2,
613                                                  const struct dsdb_schema *schema)
614 {
615         const struct dsdb_attribute *a1;
616         const struct dsdb_attribute *a2;
617
618         /* 
619          * TODO: make this faster by caching the dsdb_attribute pointer
620          *       on the ldb_messag_element
621          */
622
623         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
624         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
625
626         /*
627          * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
628          *       in the schema
629          */
630         if (!a1 || !a2) {
631                 return strcasecmp(e1->name, e2->name);
632         }
633         if (a1->attributeID_id == a2->attributeID_id) {
634                 return 0;
635         }
636         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
637 }
638
639 static void replmd_ldb_message_sort(struct ldb_message *msg,
640                                     const struct dsdb_schema *schema)
641 {
642         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
643 }
644
645 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
646                                const struct GUID *invocation_id, uint64_t seq_num,
647                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
648
649
650 /*
651   fix up linked attributes in replmd_add.
652   This involves setting up the right meta-data in extended DN
653   components, and creating backlinks to the object
654  */
655 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
656                              uint64_t seq_num, const struct GUID *invocationId, time_t t,
657                              struct GUID *guid, const struct dsdb_attribute *sa)
658 {
659         int i;
660         TALLOC_CTX *tmp_ctx = talloc_new(el->values);
661         struct ldb_context *ldb = ldb_module_get_ctx(module);
662         struct dsdb_schema *schema = dsdb_get_schema(ldb);
663         NTTIME now;
664
665         unix_to_nt_time(&now, t);
666
667         for (i=0; i<el->num_values; i++) {
668                 struct ldb_val *v = &el->values[i];
669                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
670                 struct GUID target_guid;
671                 NTSTATUS status;
672                 int ret;
673
674                 /* note that the DN already has the extended
675                    components from the extended_dn_store module */
676                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
677                 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
678                         ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid);
679                         if (ret != LDB_SUCCESS) {
680                                 talloc_free(tmp_ctx);
681                                 return ret;
682                         }
683                         ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
684                         if (ret != LDB_SUCCESS) {
685                                 talloc_free(tmp_ctx);
686                                 return ret;
687                         }
688                 }
689
690                 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
691                                           seq_num, seq_num, now, 0, false);
692                 if (ret != LDB_SUCCESS) {
693                         talloc_free(tmp_ctx);
694                         return ret;
695                 }
696
697                 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
698                 if (ret != LDB_SUCCESS) {
699                         talloc_free(tmp_ctx);
700                         return ret;
701                 }
702         }
703
704         talloc_free(tmp_ctx);
705         return LDB_SUCCESS;
706 }
707
708
709 /*
710   intercept add requests
711  */
712 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
713 {
714         struct ldb_context *ldb;
715         struct ldb_control *control;
716         struct replmd_replicated_request *ac;
717         enum ndr_err_code ndr_err;
718         struct ldb_request *down_req;
719         struct ldb_message *msg;
720         const DATA_BLOB *guid_blob;
721         struct GUID guid;
722         struct replPropertyMetaDataBlob nmd;
723         struct ldb_val nmd_value;
724         const struct GUID *our_invocation_id;
725         time_t t = time(NULL);
726         NTTIME now;
727         char *time_str;
728         int ret;
729         uint32_t i, ni=0;
730         bool allow_add_guid = false;
731         bool remove_current_guid = false;
732         bool is_urgent = false;
733         struct ldb_message_element *objectclass_el;
734
735         /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
736         control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
737         if (control) {
738                 allow_add_guid = true;
739         }
740
741         /* do not manipulate our control entries */
742         if (ldb_dn_is_special(req->op.add.message->dn)) {
743                 return ldb_next_request(module, req);
744         }
745
746         ldb = ldb_module_get_ctx(module);
747
748         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
749
750         ac = replmd_ctx_init(module, req);
751         if (!ac) {
752                 return LDB_ERR_OPERATIONS_ERROR;
753         }
754
755         guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
756         if ( guid_blob != NULL ) {
757                 if( !allow_add_guid ) {
758                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
759                               "replmd_add: it's not allowed to add an object with objectGUID\n");
760                         talloc_free(ac);
761                         return LDB_ERR_UNWILLING_TO_PERFORM;
762                 } else {
763                         NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
764                         if ( !NT_STATUS_IS_OK(status)) {
765                                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
766                                       "replmd_add: Unable to parse as a GUID the attribute objectGUID\n");
767                                 talloc_free(ac);
768                                 return LDB_ERR_UNWILLING_TO_PERFORM;
769                         }
770                         /* we remove this attribute as it can be a string and will not be treated 
771                         correctly and then we will readd it latter on in the good format*/
772                         remove_current_guid = true;
773                 }
774         } else {
775                 /* a new GUID */
776                 guid = GUID_random();
777         }
778
779         /* Get a sequence number from the backend */
780         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
781         if (ret != LDB_SUCCESS) {
782                 talloc_free(ac);
783                 return ret;
784         }
785
786         /* get our invocationId */
787         our_invocation_id = samdb_ntds_invocation_id(ldb);
788         if (!our_invocation_id) {
789                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
790                               "replmd_add: unable to find invocationId\n");
791                 talloc_free(ac);
792                 return LDB_ERR_OPERATIONS_ERROR;
793         }
794
795         /* we have to copy the message as the caller might have it as a const */
796         msg = ldb_msg_copy_shallow(ac, req->op.add.message);
797         if (msg == NULL) {
798                 ldb_oom(ldb);
799                 talloc_free(ac);
800                 return LDB_ERR_OPERATIONS_ERROR;
801         }
802
803         /* generated times */
804         unix_to_nt_time(&now, t);
805         time_str = ldb_timestring(msg, t);
806         if (!time_str) {
807                 ldb_oom(ldb);
808                 talloc_free(ac);
809                 return LDB_ERR_OPERATIONS_ERROR;
810         }
811         if (remove_current_guid) {
812                 ldb_msg_remove_attr(msg,"objectGUID");
813         }
814
815         /* 
816          * remove autogenerated attributes
817          */
818         ldb_msg_remove_attr(msg, "whenCreated");
819         ldb_msg_remove_attr(msg, "whenChanged");
820         ldb_msg_remove_attr(msg, "uSNCreated");
821         ldb_msg_remove_attr(msg, "uSNChanged");
822         ldb_msg_remove_attr(msg, "replPropertyMetaData");
823
824         /*
825          * readd replicated attributes
826          */
827         ret = ldb_msg_add_string(msg, "whenCreated", time_str);
828         if (ret != LDB_SUCCESS) {
829                 ldb_oom(ldb);
830                 talloc_free(ac);
831                 return ret;
832         }
833
834         /* build the replication meta_data */
835         ZERO_STRUCT(nmd);
836         nmd.version             = 1;
837         nmd.ctr.ctr1.count      = msg->num_elements;
838         nmd.ctr.ctr1.array      = talloc_array(msg,
839                                                struct replPropertyMetaData1,
840                                                nmd.ctr.ctr1.count);
841         if (!nmd.ctr.ctr1.array) {
842                 ldb_oom(ldb);
843                 talloc_free(ac);
844                 return LDB_ERR_OPERATIONS_ERROR;
845         }
846
847         for (i=0; i < msg->num_elements; i++) {
848                 struct ldb_message_element *e = &msg->elements[i];
849                 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
850                 const struct dsdb_attribute *sa;
851
852                 if (e->name[0] == '@') continue;
853
854                 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
855                 if (!sa) {
856                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
857                                       "replmd_add: attribute '%s' not defined in schema\n",
858                                       e->name);
859                         talloc_free(ac);
860                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
861                 }
862
863                 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
864                         /* if the attribute is not replicated (0x00000001)
865                          * or constructed (0x00000004) it has no metadata
866                          */
867                         continue;
868                 }
869
870 #if W2K3_LINKED_ATTRIBUTES
871                 if (sa->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
872                         ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa);
873                         if (ret != LDB_SUCCESS) {
874                                 talloc_free(ac);
875                                 return ret;
876                         }
877                         /* linked attributes are not stored in
878                            replPropertyMetaData in FL above w2k */
879                         continue;
880                 }
881 #endif
882
883                 m->attid                        = sa->attributeID_id;
884                 m->version                      = 1;
885                 m->originating_change_time      = now;
886                 m->originating_invocation_id    = *our_invocation_id;
887                 m->originating_usn              = ac->seq_num;
888                 m->local_usn                    = ac->seq_num;
889                 ni++;
890         }
891
892         /* fix meta data count */
893         nmd.ctr.ctr1.count = ni;
894
895         /*
896          * sort meta data array, and move the rdn attribute entry to the end
897          */
898         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
899         if (ret != LDB_SUCCESS) {
900                 talloc_free(ac);
901                 return ret;
902         }
903
904         /* generated NDR encoded values */
905         ndr_err = ndr_push_struct_blob(&nmd_value, msg, 
906                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
907                                        &nmd,
908                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
909         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
910                 ldb_oom(ldb);
911                 talloc_free(ac);
912                 return LDB_ERR_OPERATIONS_ERROR;
913         }
914
915         /*
916          * add the autogenerated values
917          */
918         ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
919         if (ret != LDB_SUCCESS) {
920                 ldb_oom(ldb);
921                 talloc_free(ac);
922                 return ret;
923         }
924         ret = ldb_msg_add_string(msg, "whenChanged", time_str);
925         if (ret != LDB_SUCCESS) {
926                 ldb_oom(ldb);
927                 talloc_free(ac);
928                 return ret;
929         }
930         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
931         if (ret != LDB_SUCCESS) {
932                 ldb_oom(ldb);
933                 talloc_free(ac);
934                 return ret;
935         }
936         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
937         if (ret != LDB_SUCCESS) {
938                 ldb_oom(ldb);
939                 talloc_free(ac);
940                 return ret;
941         }
942         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
943         if (ret != LDB_SUCCESS) {
944                 ldb_oom(ldb);
945                 talloc_free(ac);
946                 return ret;
947         }
948
949         /*
950          * sort the attributes by attid before storing the object
951          */
952         replmd_ldb_message_sort(msg, ac->schema);
953
954         objectclass_el = ldb_msg_find_element(msg, "objectClass");
955         is_urgent = replmd_check_urgent_objectclass(objectclass_el,
956                                                         REPL_URGENT_ON_CREATE);
957
958         ac->is_urgent = is_urgent;
959         ret = ldb_build_add_req(&down_req, ldb, ac,
960                                 msg,
961                                 req->controls,
962                                 ac, replmd_op_callback,
963                                 req);
964
965         if (ret != LDB_SUCCESS) {
966                 talloc_free(ac);
967                 return ret;
968         }
969
970         /* mark the control done */
971         if (control) {
972                 control->critical = 0;
973         }
974
975         /* go on with the call chain */
976         return ldb_next_request(module, down_req);
977 }
978
979
980 /*
981  * update the replPropertyMetaData for one element
982  */
983 static int replmd_update_rpmd_element(struct ldb_context *ldb,
984                                       struct ldb_message *msg,
985                                       struct ldb_message_element *el,
986                                       struct replPropertyMetaDataBlob *omd,
987                                       const struct dsdb_schema *schema,
988                                       uint64_t *seq_num,
989                                       const struct GUID *our_invocation_id,
990                                       NTTIME now)
991 {
992         int i;
993         const struct dsdb_attribute *a;
994         struct replPropertyMetaData1 *md1;
995
996         a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
997         if (a == NULL) {
998                 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
999                          el->name));
1000                 return LDB_ERR_OPERATIONS_ERROR;
1001         }
1002
1003         if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1004                 return LDB_SUCCESS;
1005         }
1006
1007         for (i=0; i<omd->ctr.ctr1.count; i++) {
1008                 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1009         }
1010
1011 #if W2K3_LINKED_ATTRIBUTES
1012         if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1013                 /* linked attributes are not stored in
1014                    replPropertyMetaData in FL above w2k, but we do
1015                    raise the seqnum for the object  */
1016                 if (*seq_num == 0 &&
1017                     ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1018                         return LDB_ERR_OPERATIONS_ERROR;
1019                 }
1020                 return LDB_SUCCESS;
1021         }
1022 #endif
1023
1024         if (i == omd->ctr.ctr1.count) {
1025                 /* we need to add a new one */
1026                 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array, 
1027                                                      struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1028                 if (omd->ctr.ctr1.array == NULL) {
1029                         ldb_oom(ldb);
1030                         return LDB_ERR_OPERATIONS_ERROR;
1031                 }
1032                 omd->ctr.ctr1.count++;
1033                 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1034         }
1035
1036         /* Get a new sequence number from the backend. We only do this
1037          * if we have a change that requires a new
1038          * replPropertyMetaData element 
1039          */
1040         if (*seq_num == 0) {
1041                 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1042                 if (ret != LDB_SUCCESS) {
1043                         return LDB_ERR_OPERATIONS_ERROR;
1044                 }
1045         }
1046
1047         md1 = &omd->ctr.ctr1.array[i];
1048         md1->version++;
1049         md1->attid                     = a->attributeID_id;
1050         md1->originating_change_time   = now;
1051         md1->originating_invocation_id = *our_invocation_id;
1052         md1->originating_usn           = *seq_num;
1053         md1->local_usn                 = *seq_num;
1054         
1055         return LDB_SUCCESS;
1056 }
1057
1058 /*
1059  * update the replPropertyMetaData object each time we modify an
1060  * object. This is needed for DRS replication, as the merge on the
1061  * client is based on this object 
1062  */
1063 static int replmd_update_rpmd(struct ldb_module *module, 
1064                               const struct dsdb_schema *schema, 
1065                               struct ldb_message *msg, uint64_t *seq_num,
1066                               time_t t,
1067                               bool *is_urgent)
1068 {
1069         const struct ldb_val *omd_value;
1070         enum ndr_err_code ndr_err;
1071         struct replPropertyMetaDataBlob omd;
1072         int i;
1073         NTTIME now;
1074         const struct GUID *our_invocation_id;
1075         int ret;
1076         const char *attrs[] = { "replPropertyMetaData" , "objectClass", NULL };
1077         struct ldb_result *res;
1078         struct ldb_context *ldb;
1079         struct ldb_message_element *objectclass_el;
1080         enum urgent_situation situation;
1081
1082         ldb = ldb_module_get_ctx(module);
1083
1084         our_invocation_id = samdb_ntds_invocation_id(ldb);
1085         if (!our_invocation_id) {
1086                 /* this happens during an initial vampire while
1087                    updating the schema */
1088                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1089                 return LDB_SUCCESS;
1090         }
1091
1092         unix_to_nt_time(&now, t);
1093
1094         /* search for the existing replPropertyMetaDataBlob */
1095         ret = dsdb_search_dn_with_deleted(ldb, msg, &res, msg->dn, attrs);
1096         if (ret != LDB_SUCCESS || res->count != 1) {
1097                 DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1098                          ldb_dn_get_linearized(msg->dn)));
1099                 return LDB_ERR_OPERATIONS_ERROR;
1100         }
1101
1102         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1103          * otherwise we consider we are updating */
1104         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1105                 situation = REPL_URGENT_ON_DELETE;
1106         } else {
1107                 situation = REPL_URGENT_ON_UPDATE;
1108         }
1109
1110         objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1111         if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1112                                                         situation)) {
1113                 *is_urgent = true;
1114         }
1115
1116         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1117         if (!omd_value) {
1118                 DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1119                          ldb_dn_get_linearized(msg->dn)));
1120                 return LDB_ERR_OPERATIONS_ERROR;
1121         }
1122
1123         ndr_err = ndr_pull_struct_blob(omd_value, msg,
1124                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
1125                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1126         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1127                 DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1128                          ldb_dn_get_linearized(msg->dn)));
1129                 return LDB_ERR_OPERATIONS_ERROR;
1130         }
1131
1132         if (omd.version != 1) {
1133                 DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1134                          omd.version, ldb_dn_get_linearized(msg->dn)));
1135                 return LDB_ERR_OPERATIONS_ERROR;
1136         }
1137
1138         for (i=0; i<msg->num_elements; i++) {
1139                 ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], &omd, schema, seq_num,
1140                                                  our_invocation_id, now);
1141                 if (ret != LDB_SUCCESS) {
1142                         return ret;
1143                 }
1144
1145                 if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1146                         *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1147                 }
1148
1149         }
1150
1151         /*
1152          * replmd_update_rpmd_element has done an update if the
1153          * seq_num is set
1154          */
1155         if (*seq_num != 0) {
1156                 struct ldb_val *md_value;
1157                 struct ldb_message_element *el;
1158
1159                 md_value = talloc(msg, struct ldb_val);
1160                 if (md_value == NULL) {
1161                         ldb_oom(ldb);
1162                         return LDB_ERR_OPERATIONS_ERROR;
1163                 }
1164
1165                 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1166                 if (ret != LDB_SUCCESS) {
1167                         return ret;
1168                 }
1169
1170                 ndr_err = ndr_push_struct_blob(md_value, msg, 
1171                                                lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
1172                                                &omd,
1173                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1174                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1175                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1176                                  ldb_dn_get_linearized(msg->dn)));
1177                         return LDB_ERR_OPERATIONS_ERROR;
1178                 }
1179
1180                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1181                 if (ret != LDB_SUCCESS) {
1182                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1183                                  ldb_dn_get_linearized(msg->dn)));
1184                         return ret;
1185                 }
1186
1187                 el->num_values = 1;
1188                 el->values = md_value;
1189         }
1190
1191         return LDB_SUCCESS;     
1192 }
1193
1194 struct parsed_dn {
1195         struct dsdb_dn *dsdb_dn;
1196         struct GUID *guid;
1197         struct ldb_val *v;
1198 };
1199
1200 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1201 {
1202         return GUID_compare(pdn1->guid, pdn2->guid);
1203 }
1204
1205 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn, int count, struct GUID *guid, struct ldb_dn *dn)
1206 {
1207         struct parsed_dn *ret;
1208         if (dn && GUID_all_zero(guid)) {
1209                 /* when updating a link using DRS, we sometimes get a
1210                    NULL GUID. We then need to try and match by DN */
1211                 int i;
1212                 for (i=0; i<count; i++) {
1213                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1214                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1215                                 return &pdn[i];
1216                         }
1217                 }
1218                 return NULL;
1219         }
1220         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1221         return ret;
1222 }
1223
1224 /*
1225   get a series of message element values as an array of DNs and GUIDs
1226   the result is sorted by GUID
1227  */
1228 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1229                           struct ldb_message_element *el, struct parsed_dn **pdn,
1230                           const char *ldap_oid)
1231 {
1232         int i;
1233         struct ldb_context *ldb = ldb_module_get_ctx(module);
1234
1235         if (el == NULL) {
1236                 *pdn = NULL;
1237                 return LDB_SUCCESS;
1238         }
1239
1240         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1241         if (!*pdn) {
1242                 ldb_module_oom(module);
1243                 return LDB_ERR_OPERATIONS_ERROR;
1244         }
1245
1246         for (i=0; i<el->num_values; i++) {
1247                 struct ldb_val *v = &el->values[i];
1248                 NTSTATUS status;
1249                 struct ldb_dn *dn;
1250                 struct parsed_dn *p;
1251
1252                 p = &(*pdn)[i];
1253
1254                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1255                 if (p->dsdb_dn == NULL) {
1256                         return LDB_ERR_INVALID_DN_SYNTAX;
1257                 }
1258
1259                 dn = p->dsdb_dn->dn;
1260
1261                 p->guid = talloc(*pdn, struct GUID);
1262                 if (p->guid == NULL) {
1263                         ldb_module_oom(module);
1264                         return LDB_ERR_OPERATIONS_ERROR;
1265                 }
1266
1267                 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1268                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1269                         /* we got a DN without a GUID - go find the GUID */
1270                         int ret = dsdb_module_guid_by_dn(module, dn, p->guid);
1271                         if (ret != LDB_SUCCESS) {
1272                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1273                                                        ldb_dn_get_linearized(dn));
1274                                 return ret;
1275                         }
1276                         ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1277                         if (ret != LDB_SUCCESS) {
1278                                 return ret;
1279                         }
1280                 } else if (!NT_STATUS_IS_OK(status)) {
1281                         return LDB_ERR_OPERATIONS_ERROR;
1282                 }
1283
1284                 /* keep a pointer to the original ldb_val */
1285                 p->v = v;
1286         }
1287
1288         TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1289
1290         return LDB_SUCCESS;
1291 }
1292
1293 /*
1294   build a new extended DN, including all meta data fields
1295
1296   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1297   RMD_ADDTIME         = originating_add_time
1298   RMD_INVOCID         = originating_invocation_id
1299   RMD_CHANGETIME      = originating_change_time
1300   RMD_ORIGINATING_USN = originating_usn
1301   RMD_LOCAL_USN       = local_usn
1302   RMD_VERSION         = version
1303  */
1304 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1305                                const struct GUID *invocation_id, uint64_t seq_num,
1306                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1307 {
1308         struct ldb_dn *dn = dsdb_dn->dn;
1309         const char *tstring, *usn_string, *flags_string;
1310         struct ldb_val tval;
1311         struct ldb_val iid;
1312         struct ldb_val usnv, local_usnv;
1313         struct ldb_val vers, flagsv;
1314         NTSTATUS status;
1315         int ret;
1316         const char *dnstring;
1317         char *vstring;
1318         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1319
1320         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1321         if (!tstring) {
1322                 return LDB_ERR_OPERATIONS_ERROR;
1323         }
1324         tval = data_blob_string_const(tstring);
1325
1326         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1327         if (!usn_string) {
1328                 return LDB_ERR_OPERATIONS_ERROR;
1329         }
1330         usnv = data_blob_string_const(usn_string);
1331
1332         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1333         if (!usn_string) {
1334                 return LDB_ERR_OPERATIONS_ERROR;
1335         }
1336         local_usnv = data_blob_string_const(usn_string);
1337
1338         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1339         if (!vstring) {
1340                 return LDB_ERR_OPERATIONS_ERROR;
1341         }
1342         vers = data_blob_string_const(vstring);
1343
1344         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1345         if (!NT_STATUS_IS_OK(status)) {
1346                 return LDB_ERR_OPERATIONS_ERROR;
1347         }
1348
1349         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1350         if (!flags_string) {
1351                 return LDB_ERR_OPERATIONS_ERROR;
1352         }
1353         flagsv = data_blob_string_const(flags_string);
1354
1355         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1356         if (ret != LDB_SUCCESS) return ret;
1357         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1358         if (ret != LDB_SUCCESS) return ret;
1359         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1360         if (ret != LDB_SUCCESS) return ret;
1361         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1362         if (ret != LDB_SUCCESS) return ret;
1363         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1364         if (ret != LDB_SUCCESS) return ret;
1365         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1366         if (ret != LDB_SUCCESS) return ret;
1367         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1368         if (ret != LDB_SUCCESS) return ret;
1369
1370         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1371         if (dnstring == NULL) {
1372                 return LDB_ERR_OPERATIONS_ERROR;
1373         }
1374         *v = data_blob_string_const(dnstring);
1375
1376         return LDB_SUCCESS;
1377 }
1378
1379 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1380                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1381                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1382                                 uint32_t version, bool deleted);
1383
1384 /*
1385   check if any links need upgrading from w2k format
1386  */
1387 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, const struct GUID *invocation_id)
1388 {
1389         int i;
1390         for (i=0; i<count; i++) {
1391                 NTSTATUS status;
1392                 uint32_t version;
1393                 int ret;
1394
1395                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1396                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1397                         continue;
1398                 }
1399
1400                 /* it's an old one that needs upgrading */
1401                 ret = replmd_update_la_val(dns, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1402                                            1, 1, 0, 0, false);
1403                 if (ret != LDB_SUCCESS) {
1404                         return ret;
1405                 }
1406         }
1407         return LDB_SUCCESS;
1408 }
1409
1410 /*
1411   update an extended DN, including all meta data fields
1412
1413   see replmd_build_la_val for value names
1414  */
1415 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1416                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1417                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1418                                 uint32_t version, bool deleted)
1419 {
1420         struct ldb_dn *dn = dsdb_dn->dn;
1421         const char *tstring, *usn_string, *flags_string;
1422         struct ldb_val tval;
1423         struct ldb_val iid;
1424         struct ldb_val usnv, local_usnv;
1425         struct ldb_val vers, flagsv;
1426         const struct ldb_val *old_addtime;
1427         uint32_t old_version;
1428         NTSTATUS status;
1429         int ret;
1430         const char *dnstring;
1431         char *vstring;
1432         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1433
1434         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1435         if (!tstring) {
1436                 return LDB_ERR_OPERATIONS_ERROR;
1437         }
1438         tval = data_blob_string_const(tstring);
1439
1440         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1441         if (!usn_string) {
1442                 return LDB_ERR_OPERATIONS_ERROR;
1443         }
1444         usnv = data_blob_string_const(usn_string);
1445
1446         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1447         if (!usn_string) {
1448                 return LDB_ERR_OPERATIONS_ERROR;
1449         }
1450         local_usnv = data_blob_string_const(usn_string);
1451
1452         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1453         if (!NT_STATUS_IS_OK(status)) {
1454                 return LDB_ERR_OPERATIONS_ERROR;
1455         }
1456
1457         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1458         if (!flags_string) {
1459                 return LDB_ERR_OPERATIONS_ERROR;
1460         }
1461         flagsv = data_blob_string_const(flags_string);
1462
1463         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1464         if (ret != LDB_SUCCESS) return ret;
1465
1466         /* get the ADDTIME from the original */
1467         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1468         if (old_addtime == NULL) {
1469                 old_addtime = &tval;
1470         }
1471         if (dsdb_dn != old_dsdb_dn) {
1472                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1473                 if (ret != LDB_SUCCESS) return ret;
1474         }
1475
1476         /* use our invocation id */
1477         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1478         if (ret != LDB_SUCCESS) return ret;
1479
1480         /* changetime is the current time */
1481         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1482         if (ret != LDB_SUCCESS) return ret;
1483
1484         /* update the USN */
1485         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1486         if (ret != LDB_SUCCESS) return ret;
1487
1488         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1489         if (ret != LDB_SUCCESS) return ret;
1490
1491         /* increase the version by 1 */
1492         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1493         if (NT_STATUS_IS_OK(status) && old_version >= version) {
1494                 version = old_version+1;
1495         }
1496         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1497         vers = data_blob_string_const(vstring);
1498         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1499         if (ret != LDB_SUCCESS) return ret;
1500
1501         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1502         if (dnstring == NULL) {
1503                 return LDB_ERR_OPERATIONS_ERROR;
1504         }
1505         *v = data_blob_string_const(dnstring);
1506
1507         return LDB_SUCCESS;
1508 }
1509
1510 /*
1511   handle adding a linked attribute
1512  */
1513 static int replmd_modify_la_add(struct ldb_module *module,
1514                                 struct dsdb_schema *schema,
1515                                 struct ldb_message *msg,
1516                                 struct ldb_message_element *el,
1517                                 struct ldb_message_element *old_el,
1518                                 const struct dsdb_attribute *schema_attr,
1519                                 uint64_t seq_num,
1520                                 time_t t,
1521                                 struct GUID *msg_guid)
1522 {
1523         int i;
1524         struct parsed_dn *dns, *old_dns;
1525         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1526         int ret;
1527         struct ldb_val *new_values = NULL;
1528         unsigned int num_new_values = 0;
1529         unsigned old_num_values = old_el?old_el->num_values:0;
1530         const struct GUID *invocation_id;
1531         struct ldb_context *ldb = ldb_module_get_ctx(module);
1532         NTTIME now;
1533
1534         unix_to_nt_time(&now, t);
1535
1536         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1537         if (ret != LDB_SUCCESS) {
1538                 talloc_free(tmp_ctx);
1539                 return ret;
1540         }
1541
1542         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1543         if (ret != LDB_SUCCESS) {
1544                 talloc_free(tmp_ctx);
1545                 return ret;
1546         }
1547
1548         invocation_id = samdb_ntds_invocation_id(ldb);
1549         if (!invocation_id) {
1550                 talloc_free(tmp_ctx);
1551                 return LDB_ERR_OPERATIONS_ERROR;
1552         }
1553
1554         ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1555         if (ret != LDB_SUCCESS) {
1556                 talloc_free(tmp_ctx);
1557                 return ret;
1558         }
1559
1560         /* for each new value, see if it exists already with the same GUID */
1561         for (i=0; i<el->num_values; i++) {
1562                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1563                 if (p == NULL) {
1564                         /* this is a new linked attribute value */
1565                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1566                         if (new_values == NULL) {
1567                                 ldb_module_oom(module);
1568                                 talloc_free(tmp_ctx);
1569                                 return LDB_ERR_OPERATIONS_ERROR;
1570                         }
1571                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1572                                                   invocation_id, seq_num, seq_num, now, 0, false);
1573                         if (ret != LDB_SUCCESS) {
1574                                 talloc_free(tmp_ctx);
1575                                 return ret;
1576                         }
1577                         num_new_values++;
1578                 } else {
1579                         /* this is only allowed if the GUID was
1580                            previously deleted. */
1581                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1582
1583                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1584                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1585                                                        el->name, GUID_string(tmp_ctx, p->guid));
1586                                 talloc_free(tmp_ctx);
1587                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1588                         }
1589                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1590                                                    invocation_id, seq_num, seq_num, now, 0, false);
1591                         if (ret != LDB_SUCCESS) {
1592                                 talloc_free(tmp_ctx);
1593                                 return ret;
1594                         }
1595                 }
1596
1597                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1598                 if (ret != LDB_SUCCESS) {
1599                         talloc_free(tmp_ctx);
1600                         return ret;
1601                 }
1602         }
1603
1604         /* add the new ones on to the end of the old values, constructing a new el->values */
1605         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1606                                     struct ldb_val,
1607                                     old_num_values+num_new_values);
1608         if (el->values == NULL) {
1609                 ldb_module_oom(module);
1610                 return LDB_ERR_OPERATIONS_ERROR;
1611         }
1612
1613         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1614         el->num_values = old_num_values + num_new_values;
1615
1616         talloc_steal(msg->elements, el->values);
1617         talloc_steal(el->values, new_values);
1618
1619         talloc_free(tmp_ctx);
1620
1621         /* we now tell the backend to replace all existing values
1622            with the one we have constructed */
1623         el->flags = LDB_FLAG_MOD_REPLACE;
1624
1625         return LDB_SUCCESS;
1626 }
1627
1628
1629 /*
1630   handle deleting all active linked attributes
1631  */
1632 static int replmd_modify_la_delete(struct ldb_module *module,
1633                                    struct dsdb_schema *schema,
1634                                    struct ldb_message *msg,
1635                                    struct ldb_message_element *el,
1636                                    struct ldb_message_element *old_el,
1637                                    const struct dsdb_attribute *schema_attr,
1638                                    uint64_t seq_num,
1639                                    time_t t,
1640                                    struct GUID *msg_guid)
1641 {
1642         int i;
1643         struct parsed_dn *dns, *old_dns;
1644         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1645         int ret;
1646         const struct GUID *invocation_id;
1647         struct ldb_context *ldb = ldb_module_get_ctx(module);
1648         NTTIME now;
1649
1650         unix_to_nt_time(&now, t);
1651
1652         /* check if there is nothing to delete */
1653         if ((!old_el || old_el->num_values == 0) &&
1654             el->num_values == 0) {
1655                 return LDB_SUCCESS;
1656         }
1657
1658         if (!old_el || old_el->num_values == 0) {
1659                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1660         }
1661
1662         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1663         if (ret != LDB_SUCCESS) {
1664                 talloc_free(tmp_ctx);
1665                 return ret;
1666         }
1667
1668         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1669         if (ret != LDB_SUCCESS) {
1670                 talloc_free(tmp_ctx);
1671                 return ret;
1672         }
1673
1674         invocation_id = samdb_ntds_invocation_id(ldb);
1675         if (!invocation_id) {
1676                 return LDB_ERR_OPERATIONS_ERROR;
1677         }
1678
1679         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, invocation_id);
1680         if (ret != LDB_SUCCESS) {
1681                 talloc_free(tmp_ctx);
1682                 return ret;
1683         }
1684
1685         el->values = NULL;
1686
1687         /* see if we are being asked to delete any links that
1688            don't exist or are already deleted */
1689         for (i=0; i<el->num_values; i++) {
1690                 struct parsed_dn *p = &dns[i];
1691                 struct parsed_dn *p2;
1692                 uint32_t rmd_flags;
1693
1694                 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1695                 if (!p2) {
1696                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1697                                                el->name, GUID_string(tmp_ctx, p->guid));
1698                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
1699                 }
1700                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1701                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1702                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1703                                                el->name, GUID_string(tmp_ctx, p->guid));
1704                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
1705                 }
1706         }
1707
1708         /* for each new value, see if it exists already with the same GUID
1709            if it is not already deleted and matches the delete list then delete it
1710         */
1711         for (i=0; i<old_el->num_values; i++) {
1712                 struct parsed_dn *p = &old_dns[i];
1713                 uint32_t rmd_flags;
1714
1715                 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1716                         continue;
1717                 }
1718
1719                 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1720                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1721
1722                 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1723                                            invocation_id, seq_num, seq_num, now, 0, true);
1724                 if (ret != LDB_SUCCESS) {
1725                         talloc_free(tmp_ctx);
1726                         return ret;
1727                 }
1728
1729                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1730                 if (ret != LDB_SUCCESS) {
1731                         talloc_free(tmp_ctx);
1732                         return ret;
1733                 }
1734         }
1735
1736         el->values = talloc_steal(msg->elements, old_el->values);
1737         el->num_values = old_el->num_values;
1738
1739         talloc_free(tmp_ctx);
1740
1741         /* we now tell the backend to replace all existing values
1742            with the one we have constructed */
1743         el->flags = LDB_FLAG_MOD_REPLACE;
1744
1745         return LDB_SUCCESS;
1746 }
1747
1748 /*
1749   handle replacing a linked attribute
1750  */
1751 static int replmd_modify_la_replace(struct ldb_module *module,
1752                                     struct dsdb_schema *schema,
1753                                     struct ldb_message *msg,
1754                                     struct ldb_message_element *el,
1755                                     struct ldb_message_element *old_el,
1756                                     const struct dsdb_attribute *schema_attr,
1757                                     uint64_t seq_num,
1758                                     time_t t,
1759                                     struct GUID *msg_guid)
1760 {
1761         int i;
1762         struct parsed_dn *dns, *old_dns;
1763         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1764         int ret;
1765         const struct GUID *invocation_id;
1766         struct ldb_context *ldb = ldb_module_get_ctx(module);
1767         struct ldb_val *new_values = NULL;
1768         uint32_t num_new_values = 0;
1769         unsigned old_num_values = old_el?old_el->num_values:0;
1770         NTTIME now;
1771
1772         unix_to_nt_time(&now, t);
1773
1774         /* check if there is nothing to replace */
1775         if ((!old_el || old_el->num_values == 0) &&
1776             el->num_values == 0) {
1777                 return LDB_SUCCESS;
1778         }
1779
1780         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid);
1781         if (ret != LDB_SUCCESS) {
1782                 talloc_free(tmp_ctx);
1783                 return ret;
1784         }
1785
1786         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid);
1787         if (ret != LDB_SUCCESS) {
1788                 talloc_free(tmp_ctx);
1789                 return ret;
1790         }
1791
1792         invocation_id = samdb_ntds_invocation_id(ldb);
1793         if (!invocation_id) {
1794                 return LDB_ERR_OPERATIONS_ERROR;
1795         }
1796
1797         ret = replmd_check_upgrade_links(old_dns, old_num_values, invocation_id);
1798         if (ret != LDB_SUCCESS) {
1799                 talloc_free(tmp_ctx);
1800                 return ret;
1801         }
1802
1803         /* mark all the old ones as deleted */
1804         for (i=0; i<old_num_values; i++) {
1805                 struct parsed_dn *old_p = &old_dns[i];
1806                 struct parsed_dn *p;
1807                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1808
1809                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1810
1811                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1812                 if (ret != LDB_SUCCESS) {
1813                         talloc_free(tmp_ctx);
1814                         return ret;
1815                 }
1816
1817                 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1818                 if (p) {
1819                         /* we don't delete it if we are re-adding it */
1820                         continue;
1821                 }
1822
1823                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1824                                            invocation_id, seq_num, seq_num, now, 0, true);
1825                 if (ret != LDB_SUCCESS) {
1826                         talloc_free(tmp_ctx);
1827                         return ret;
1828                 }
1829         }
1830
1831         /* for each new value, either update its meta-data, or add it
1832          * to old_el
1833         */
1834         for (i=0; i<el->num_values; i++) {
1835                 struct parsed_dn *p = &dns[i], *old_p;
1836
1837                 if (old_dns &&
1838                     (old_p = parsed_dn_find(old_dns,
1839                                             old_num_values, p->guid, NULL)) != NULL) {
1840                         /* update in place */
1841                         ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
1842                                                    old_p->dsdb_dn, invocation_id,
1843                                                    seq_num, seq_num, now, 0, false);
1844                         if (ret != LDB_SUCCESS) {
1845                                 talloc_free(tmp_ctx);
1846                                 return ret;
1847                         }
1848                 } else {
1849                         /* add a new one */
1850                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
1851                                                     num_new_values+1);
1852                         if (new_values == NULL) {
1853                                 ldb_module_oom(module);
1854                                 talloc_free(tmp_ctx);
1855                                 return LDB_ERR_OPERATIONS_ERROR;
1856                         }
1857                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1858                                                   invocation_id, seq_num, seq_num, now, 0, false);
1859                         if (ret != LDB_SUCCESS) {
1860                                 talloc_free(tmp_ctx);
1861                                 return ret;
1862                         }
1863                         num_new_values++;
1864                 }
1865
1866                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
1867                 if (ret != LDB_SUCCESS) {
1868                         talloc_free(tmp_ctx);
1869                         return ret;
1870                 }
1871         }
1872
1873         /* add the new values to the end of old_el */
1874         if (num_new_values != 0) {
1875                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1876                                             struct ldb_val, old_num_values+num_new_values);
1877                 if (el->values == NULL) {
1878                         ldb_module_oom(module);
1879                         return LDB_ERR_OPERATIONS_ERROR;
1880                 }
1881                 memcpy(&el->values[old_num_values], &new_values[0],
1882                        sizeof(struct ldb_val)*num_new_values);
1883                 el->num_values = old_num_values + num_new_values;
1884                 talloc_steal(msg->elements, new_values);
1885         } else {
1886                 el->values = old_el->values;
1887                 el->num_values = old_el->num_values;
1888                 talloc_steal(msg->elements, el->values);
1889         }
1890
1891         talloc_free(tmp_ctx);
1892
1893         /* we now tell the backend to replace all existing values
1894            with the one we have constructed */
1895         el->flags = LDB_FLAG_MOD_REPLACE;
1896
1897         return LDB_SUCCESS;
1898 }
1899
1900
1901 /*
1902   handle linked attributes in modify requests
1903  */
1904 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
1905                                                struct ldb_message *msg,
1906                                                uint64_t seq_num, time_t t)
1907 {
1908         struct ldb_result *res;
1909         int ret, i;
1910         struct ldb_context *ldb = ldb_module_get_ctx(module);
1911         struct ldb_message *old_msg;
1912         struct dsdb_schema *schema = dsdb_get_schema(ldb);
1913         struct GUID old_guid;
1914
1915         if (seq_num == 0) {
1916                 /* there the replmd_update_rpmd code has already
1917                  * checked and saw that there are no linked
1918                  * attributes */
1919                 return LDB_SUCCESS;
1920         }
1921
1922 #if !W2K3_LINKED_ATTRIBUTES
1923         return LDB_SUCCESS;
1924 #endif
1925
1926         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
1927                 /* don't do anything special for linked attributes */
1928                 return LDB_SUCCESS;
1929         }
1930
1931         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
1932                                     DSDB_SEARCH_SHOW_DELETED |
1933                                     DSDB_SEARCH_REVEAL_INTERNALS |
1934                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
1935         if (ret != LDB_SUCCESS) {
1936                 return ret;
1937         }
1938         old_msg = res->msgs[0];
1939
1940         old_guid = samdb_result_guid(old_msg, "objectGUID");
1941
1942         for (i=0; i<msg->num_elements; i++) {
1943                 struct ldb_message_element *el = &msg->elements[i];
1944                 struct ldb_message_element *old_el, *new_el;
1945                 const struct dsdb_attribute *schema_attr
1946                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1947                 if (!schema_attr) {
1948                         ldb_asprintf_errstring(ldb,
1949                                                "attribute %s is not a valid attribute in schema", el->name);
1950                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
1951                 }
1952                 if (schema_attr->linkID == 0) {
1953                         continue;
1954                 }
1955                 if ((schema_attr->linkID & 1) == 1) {
1956                         /* Odd is for the target.  Illegal to modify */
1957                         ldb_asprintf_errstring(ldb,
1958                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
1959                         return LDB_ERR_UNWILLING_TO_PERFORM;
1960                 }
1961                 old_el = ldb_msg_find_element(old_msg, el->name);
1962                 switch (el->flags & LDB_FLAG_MOD_MASK) {
1963                 case LDB_FLAG_MOD_REPLACE:
1964                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1965                         break;
1966                 case LDB_FLAG_MOD_DELETE:
1967                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1968                         break;
1969                 case LDB_FLAG_MOD_ADD:
1970                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid);
1971                         break;
1972                 default:
1973                         ldb_asprintf_errstring(ldb,
1974                                                "invalid flags 0x%x for %s linked attribute",
1975                                                el->flags, el->name);
1976                         return LDB_ERR_UNWILLING_TO_PERFORM;
1977                 }
1978                 if (ret != LDB_SUCCESS) {
1979                         return ret;
1980                 }
1981                 if (old_el) {
1982                         ldb_msg_remove_attr(old_msg, el->name);
1983                 }
1984                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
1985                 new_el->num_values = el->num_values;
1986                 new_el->values = talloc_steal(msg->elements, el->values);
1987
1988                 /* TODO: this relises a bit too heavily on the exact
1989                    behaviour of ldb_msg_find_element and
1990                    ldb_msg_remove_element */
1991                 old_el = ldb_msg_find_element(msg, el->name);
1992                 if (old_el != el) {
1993                         ldb_msg_remove_element(msg, old_el);
1994                         i--;
1995                 }
1996         }
1997
1998         talloc_free(res);
1999         return ret;
2000 }
2001
2002
2003
2004 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2005 {
2006         struct ldb_context *ldb;
2007         struct replmd_replicated_request *ac;
2008         struct ldb_request *down_req;
2009         struct ldb_message *msg;
2010         time_t t = time(NULL);
2011         int ret;
2012         bool is_urgent = false;
2013
2014         /* do not manipulate our control entries */
2015         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2016                 return ldb_next_request(module, req);
2017         }
2018
2019         ldb = ldb_module_get_ctx(module);
2020
2021         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2022
2023         ac = replmd_ctx_init(module, req);
2024         if (!ac) {
2025                 return LDB_ERR_OPERATIONS_ERROR;
2026         }
2027
2028         /* we have to copy the message as the caller might have it as a const */
2029         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2030         if (msg == NULL) {
2031                 ldb_oom(ldb);
2032                 talloc_free(ac);
2033                 return LDB_ERR_OPERATIONS_ERROR;
2034         }
2035
2036         ldb_msg_remove_attr(msg, "whenChanged");
2037         ldb_msg_remove_attr(msg, "uSNChanged");
2038
2039         ret = replmd_update_rpmd(module, ac->schema, msg, &ac->seq_num, t, &is_urgent);
2040         if (ret != LDB_SUCCESS) {
2041                 talloc_free(ac);
2042                 return ret;
2043         }
2044
2045         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t);
2046         if (ret != LDB_SUCCESS) {
2047                 talloc_free(ac);
2048                 return ret;
2049         }
2050
2051         /* TODO:
2052          * - replace the old object with the newly constructed one
2053          */
2054
2055         ac->is_urgent = is_urgent;
2056
2057         ret = ldb_build_mod_req(&down_req, ldb, ac,
2058                                 msg,
2059                                 req->controls,
2060                                 ac, replmd_op_callback,
2061                                 req);
2062         if (ret != LDB_SUCCESS) {
2063                 talloc_free(ac);
2064                 return ret;
2065         }
2066         talloc_steal(down_req, msg);
2067
2068         /* we only change whenChanged and uSNChanged if the seq_num
2069            has changed */
2070         if (ac->seq_num != 0) {
2071                 if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2072                         talloc_free(ac);
2073                         return ret;
2074                 }
2075
2076                 if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2077                         talloc_free(ac);
2078                         return ret;
2079                 }
2080         }
2081
2082         /* go on with the call chain */
2083         return ldb_next_request(module, down_req);
2084 }
2085
2086 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2087
2088 /*
2089   handle a rename request
2090
2091   On a rename we need to do an extra ldb_modify which sets the
2092   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2093  */
2094 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2095 {
2096         struct ldb_context *ldb;
2097         struct replmd_replicated_request *ac;
2098         int ret;
2099         struct ldb_request *down_req;
2100
2101         /* do not manipulate our control entries */
2102         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2103                 return ldb_next_request(module, req);
2104         }
2105
2106         ldb = ldb_module_get_ctx(module);
2107
2108         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2109
2110         ac = replmd_ctx_init(module, req);
2111         if (!ac) {
2112                 return LDB_ERR_OPERATIONS_ERROR;
2113         }
2114         ret = ldb_build_rename_req(&down_req, ldb, ac,
2115                                    ac->req->op.rename.olddn,
2116                                    ac->req->op.rename.newdn,
2117                                    ac->req->controls,
2118                                    ac, replmd_rename_callback,
2119                                    ac->req);
2120
2121         if (ret != LDB_SUCCESS) {
2122                 talloc_free(ac);
2123                 return ret;
2124         }
2125
2126         /* go on with the call chain */
2127         return ldb_next_request(module, down_req);
2128 }
2129
2130 /* After the rename is compleated, update the whenchanged etc */
2131 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2132 {
2133         struct ldb_context *ldb;
2134         struct replmd_replicated_request *ac;
2135         struct ldb_request *down_req;
2136         struct ldb_message *msg;
2137         time_t t = time(NULL);
2138         int ret;
2139
2140         ac = talloc_get_type(req->context, struct replmd_replicated_request);
2141         ldb = ldb_module_get_ctx(ac->module);
2142
2143         if (ares->error != LDB_SUCCESS) {
2144                 return ldb_module_done(ac->req, ares->controls,
2145                                         ares->response, ares->error);
2146         }
2147
2148         if (ares->type != LDB_REPLY_DONE) {
2149                 ldb_set_errstring(ldb,
2150                                   "invalid ldb_reply_type in callback");
2151                 talloc_free(ares);
2152                 return ldb_module_done(ac->req, NULL, NULL,
2153                                         LDB_ERR_OPERATIONS_ERROR);
2154         }
2155
2156         /* Get a sequence number from the backend */
2157         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2158         if (ret != LDB_SUCCESS) {
2159                 return ret;
2160         }
2161
2162         /* TODO:
2163          * - replace the old object with the newly constructed one
2164          */
2165
2166         msg = ldb_msg_new(ac);
2167         if (msg == NULL) {
2168                 ldb_oom(ldb);
2169                 return LDB_ERR_OPERATIONS_ERROR;
2170         }
2171
2172         msg->dn = ac->req->op.rename.newdn;
2173
2174         ret = ldb_build_mod_req(&down_req, ldb, ac,
2175                                 msg,
2176                                 req->controls,
2177                                 ac, replmd_op_callback,
2178                                 req);
2179
2180         if (ret != LDB_SUCCESS) {
2181                 talloc_free(ac);
2182                 return ret;
2183         }
2184         talloc_steal(down_req, msg);
2185
2186         if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
2187                 talloc_free(ac);
2188                 return ret;
2189         }
2190         
2191         if (add_uint64_element(msg, "uSNChanged", ac->seq_num) != LDB_SUCCESS) {
2192                 talloc_free(ac);
2193                 return ret;
2194         }
2195
2196         /* go on with the call chain - do the modify after the rename */
2197         return ldb_next_request(ac->module, down_req);
2198 }
2199
2200 /*
2201    remove links from objects that point at this object when an object
2202    is deleted
2203  */
2204 static int replmd_delete_remove_link(struct ldb_module *module,
2205                                      struct dsdb_schema *schema,
2206                                      struct ldb_dn *dn,
2207                                      struct ldb_message_element *el,
2208                                      const struct dsdb_attribute *sa)
2209 {
2210         int i;
2211         TALLOC_CTX *tmp_ctx = talloc_new(module);
2212         struct ldb_context *ldb = ldb_module_get_ctx(module);
2213
2214         for (i=0; i<el->num_values; i++) {
2215                 struct dsdb_dn *dsdb_dn;
2216                 NTSTATUS status;
2217                 int ret;
2218                 struct GUID guid2;
2219                 struct ldb_message *msg;
2220                 const struct dsdb_attribute *target_attr;
2221                 struct ldb_message_element *el2;
2222                 struct ldb_val dn_val;
2223
2224                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2225                         continue;
2226                 }
2227
2228                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2229                 if (!dsdb_dn) {
2230                         talloc_free(tmp_ctx);
2231                         return LDB_ERR_OPERATIONS_ERROR;
2232                 }
2233
2234                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2235                 if (!NT_STATUS_IS_OK(status)) {
2236                         talloc_free(tmp_ctx);
2237                         return LDB_ERR_OPERATIONS_ERROR;
2238                 }
2239
2240                 /* remove the link */
2241                 msg = ldb_msg_new(tmp_ctx);
2242                 if (!msg) {
2243                         ldb_module_oom(module);
2244                         talloc_free(tmp_ctx);
2245                         return LDB_ERR_OPERATIONS_ERROR;
2246                 }
2247
2248
2249                 msg->dn = dsdb_dn->dn;
2250
2251                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2252                 if (target_attr == NULL) {
2253                         continue;
2254                 }
2255
2256                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2257                 if (ret != LDB_SUCCESS) {
2258                         ldb_module_oom(module);
2259                         talloc_free(tmp_ctx);
2260                         return LDB_ERR_OPERATIONS_ERROR;
2261                 }
2262                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2263                 el2->values = &dn_val;
2264                 el2->num_values = 1;
2265
2266                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2267                 if (ret != LDB_SUCCESS) {
2268                         talloc_free(tmp_ctx);
2269                         return ret;
2270                 }
2271         }
2272         talloc_free(tmp_ctx);
2273         return LDB_SUCCESS;
2274 }
2275
2276
2277 /*
2278   handle update of replication meta data for deletion of objects
2279
2280   This also handles the mapping of delete to a rename operation
2281   to allow deletes to be replicated.
2282  */
2283 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2284 {
2285         int ret = LDB_ERR_OTHER;
2286         bool retb;
2287         struct ldb_dn *old_dn, *new_dn;
2288         const char *rdn_name;
2289         const struct ldb_val *rdn_value, *new_rdn_value;
2290         struct GUID guid;
2291         struct ldb_context *ldb = ldb_module_get_ctx(module);
2292         struct dsdb_schema *schema = dsdb_get_schema(ldb);
2293         struct ldb_message *msg, *old_msg;
2294         struct ldb_message_element *el;
2295         TALLOC_CTX *tmp_ctx;
2296         struct ldb_result *res, *parent_res;
2297         const char *preserved_attrs[] = {
2298                 /* yes, this really is a hard coded list. See MS-ADTS
2299                    section 3.1.1.5.5.1.1 */
2300                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2301                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2302                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2303                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2304                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2305                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2306                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2307                 "whenChanged", NULL};
2308         uint32_t el_count = 0;
2309         int i;
2310
2311         if (ldb_dn_is_special(req->op.del.dn)) {
2312                 return ldb_next_request(module, req);
2313         }
2314
2315         tmp_ctx = talloc_new(ldb);
2316
2317         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2318
2319         /* we need the complete msg off disk, so we can work out which
2320            attributes need to be removed */
2321         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2322                                     DSDB_SEARCH_SHOW_DELETED |
2323                                     DSDB_SEARCH_REVEAL_INTERNALS |
2324                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
2325         if (ret != LDB_SUCCESS) {
2326                 talloc_free(tmp_ctx);
2327                 return ret;
2328         }
2329         old_msg = res->msgs[0];
2330
2331         if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2332                 struct auth_session_info *session_info =
2333                         (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2334                 if (security_session_user_level(session_info) != SECURITY_SYSTEM) {
2335                         ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2336                                                ldb_dn_get_linearized(old_msg->dn));
2337                         return LDB_ERR_UNWILLING_TO_PERFORM;
2338                 }
2339
2340                 /* it is already deleted - really remove it this time */
2341                 talloc_free(tmp_ctx);
2342                 return ldb_next_request(module, req);
2343         }
2344
2345         /* work out where we will be renaming this object to */
2346         ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn, &new_dn);
2347         if (ret != LDB_SUCCESS) {
2348                 /* this is probably an attempted delete on a partition
2349                  * that doesn't allow delete operations, such as the
2350                  * schema partition */
2351                 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2352                                        ldb_dn_get_linearized(old_dn));
2353                 talloc_free(tmp_ctx);
2354                 return LDB_ERR_UNWILLING_TO_PERFORM;
2355         }
2356
2357         rdn_name = ldb_dn_get_rdn_name(old_dn);
2358         rdn_value = ldb_dn_get_rdn_val(old_dn);
2359
2360         /* get the objects GUID from the search we just did */
2361         guid = samdb_result_guid(old_msg, "objectGUID");
2362
2363         /* Add a formatted child */
2364         retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2365                                     rdn_name,
2366                                     rdn_value->data,
2367                                     GUID_string(tmp_ctx, &guid));
2368         if (!retb) {
2369                 DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2370                                 ldb_dn_get_linearized(new_dn)));
2371                 talloc_free(tmp_ctx);
2372                 return LDB_ERR_OPERATIONS_ERROR;
2373         }
2374
2375         /*
2376           now we need to modify the object in the following ways:
2377
2378           - add isDeleted=TRUE
2379           - update rDN and name, with new rDN
2380           - remove linked attributes
2381           - remove objectCategory and sAMAccountType
2382           - remove attribs not on the preserved list
2383              - preserved if in above list, or is rDN
2384           - remove all linked attribs from this object
2385           - remove all links from other objects to this object
2386           - add lastKnownParent
2387           - update replPropertyMetaData?
2388
2389           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2390          */
2391
2392         msg = ldb_msg_new(tmp_ctx);
2393         if (msg == NULL) {
2394                 ldb_module_oom(module);
2395                 talloc_free(tmp_ctx);
2396                 return LDB_ERR_OPERATIONS_ERROR;
2397         }
2398
2399         msg->dn = old_dn;
2400
2401         ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2402         if (ret != LDB_SUCCESS) {
2403                 DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2404                 ldb_module_oom(module);
2405                 talloc_free(tmp_ctx);
2406                 return ret;
2407         }
2408         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2409
2410         /* we also mark it as recycled, meaning this object can't be
2411            recovered (we are stripping its attributes) */
2412         if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2413                 ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2414                 if (ret != LDB_SUCCESS) {
2415                         DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2416                         ldb_module_oom(module);
2417                         talloc_free(tmp_ctx);
2418                         return ret;
2419                 }
2420                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2421         }
2422
2423         /* we need the storage form of the parent GUID */
2424         ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2425                                     ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2426                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2427                                     DSDB_SEARCH_REVEAL_INTERNALS);
2428         if (ret != LDB_SUCCESS) {
2429                 talloc_free(tmp_ctx);
2430                 return ret;
2431         }
2432
2433         ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2434                                        ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2435         if (ret != LDB_SUCCESS) {
2436                 DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2437                 ldb_module_oom(module);
2438                 talloc_free(tmp_ctx);
2439                 return ret;
2440         }
2441         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2442
2443         /* work out which of the old attributes we will be removing */
2444         for (i=0; i<old_msg->num_elements; i++) {
2445                 const struct dsdb_attribute *sa;
2446                 el = &old_msg->elements[i];
2447                 sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2448                 if (!sa) {
2449                         talloc_free(tmp_ctx);
2450                         return LDB_ERR_OPERATIONS_ERROR;
2451                 }
2452                 if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2453                         /* don't remove the rDN */
2454                         continue;
2455                 }
2456
2457                 if (sa->linkID && sa->linkID & 1) {
2458                         ret = replmd_delete_remove_link(module, schema, old_dn, el, sa);
2459                         if (ret != LDB_SUCCESS) {
2460                                 talloc_free(tmp_ctx);
2461                                 return LDB_ERR_OPERATIONS_ERROR;
2462                         }
2463                         continue;
2464                 }
2465
2466                 if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2467                         continue;
2468                 }
2469
2470                 ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2471                 if (ret != LDB_SUCCESS) {
2472                         talloc_free(tmp_ctx);
2473                         ldb_module_oom(module);
2474                         return ret;
2475                 }
2476         }
2477
2478         /* work out what the new rdn value is, for updating the
2479            rDN and name fields */
2480         new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2481         ret = ldb_msg_add_value(msg, rdn_name, new_rdn_value, &el);
2482         if (ret != LDB_SUCCESS) {
2483                 talloc_free(tmp_ctx);
2484                 return ret;
2485         }
2486         el->flags = LDB_FLAG_MOD_REPLACE;
2487
2488         el = ldb_msg_find_element(old_msg, "name");
2489         if (el) {
2490                 ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2491                 if (ret != LDB_SUCCESS) {
2492                         talloc_free(tmp_ctx);
2493                         return ret;
2494                 }
2495                 el->flags = LDB_FLAG_MOD_REPLACE;
2496         }
2497
2498         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE);
2499         if (ret != LDB_SUCCESS) {
2500                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2501                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2502                 talloc_free(tmp_ctx);
2503                 return ret;
2504         }
2505
2506         /* now rename onto the new DN */
2507         ret = dsdb_module_rename(module, old_dn, new_dn, 0);
2508         if (ret != LDB_SUCCESS){
2509                 DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2510                          ldb_dn_get_linearized(old_dn),
2511                          ldb_dn_get_linearized(new_dn),
2512                          ldb_errstring(ldb)));
2513                 talloc_free(tmp_ctx);
2514                 return ret;
2515         }
2516
2517         talloc_free(tmp_ctx);
2518
2519         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2520 }
2521
2522
2523
2524 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2525 {
2526         return ret;
2527 }
2528
2529 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2530 {
2531         int ret = LDB_ERR_OTHER;
2532         /* TODO: do some error mapping */
2533         return ret;
2534 }
2535
2536 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
2537 {
2538         struct ldb_context *ldb;
2539         struct ldb_request *change_req;
2540         enum ndr_err_code ndr_err;
2541         struct ldb_message *msg;
2542         struct replPropertyMetaDataBlob *md;
2543         struct ldb_val md_value;
2544         uint32_t i;
2545         int ret;
2546
2547         /*
2548          * TODO: check if the parent object exist
2549          */
2550
2551         /*
2552          * TODO: handle the conflict case where an object with the
2553          *       same name exist
2554          */
2555
2556         ldb = ldb_module_get_ctx(ar->module);
2557         msg = ar->objs->objects[ar->index_current].msg;
2558         md = ar->objs->objects[ar->index_current].meta_data;
2559
2560         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2561         if (ret != LDB_SUCCESS) {
2562                 return replmd_replicated_request_error(ar, ret);
2563         }
2564
2565         ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
2566         if (ret != LDB_SUCCESS) {
2567                 return replmd_replicated_request_error(ar, ret);
2568         }
2569
2570         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2571         if (ret != LDB_SUCCESS) {
2572                 return replmd_replicated_request_error(ar, ret);
2573         }
2574
2575         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
2576         if (ret != LDB_SUCCESS) {
2577                 return replmd_replicated_request_error(ar, ret);
2578         }
2579
2580         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2581         if (ret != LDB_SUCCESS) {
2582                 return replmd_replicated_request_error(ar, ret);
2583         }
2584
2585         /* remove any message elements that have zero values */
2586         for (i=0; i<msg->num_elements; i++) {
2587                 struct ldb_message_element *el = &msg->elements[i];
2588
2589                 if (el->num_values == 0) {
2590                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
2591                                  el->name));
2592                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
2593                         msg->num_elements--;
2594                         i--;
2595                         continue;
2596                 }
2597         }
2598         
2599         /*
2600          * the meta data array is already sorted by the caller
2601          */
2602         for (i=0; i < md->ctr.ctr1.count; i++) {
2603                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
2604         }
2605         ndr_err = ndr_push_struct_blob(&md_value, msg, 
2606                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2607                                        md,
2608                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2609         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2610                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2611                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2612         }
2613         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
2614         if (ret != LDB_SUCCESS) {
2615                 return replmd_replicated_request_error(ar, ret);
2616         }
2617
2618         replmd_ldb_message_sort(msg, ar->schema);
2619
2620         if (DEBUGLVL(4)) {
2621                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
2622                 DEBUG(4, ("DRS replication add message:\n%s\n", s));
2623                 talloc_free(s);
2624         }
2625
2626         ret = ldb_build_add_req(&change_req,
2627                                 ldb,
2628                                 ar,
2629                                 msg,
2630                                 ar->controls,
2631                                 ar,
2632                                 replmd_op_callback,
2633                                 ar->req);
2634         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2635
2636         return ldb_next_request(ar->module, change_req);
2637 }
2638
2639 /*
2640    return true if an update is newer than an existing entry
2641    see section 5.11 of MS-ADTS
2642 */
2643 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2644                                    const struct GUID *update_invocation_id,
2645                                    uint32_t current_version,
2646                                    uint32_t update_version,
2647                                    NTTIME current_change_time,
2648                                    NTTIME update_change_time)
2649 {
2650         if (update_version != current_version) {
2651                 return update_version > current_version;
2652         }
2653         if (update_change_time > current_change_time) {
2654                 return true;
2655         }
2656         if (update_change_time == current_change_time) {
2657                 return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2658         }
2659         return false;
2660 }
2661
2662 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2663                                                   struct replPropertyMetaData1 *new_m)
2664 {
2665         return replmd_update_is_newer(&cur_m->originating_invocation_id,
2666                                       &new_m->originating_invocation_id,
2667                                       cur_m->version,
2668                                       new_m->version,
2669                                       cur_m->originating_change_time,
2670                                       new_m->originating_change_time);
2671 }
2672
2673 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
2674 {
2675         struct ldb_context *ldb;
2676         struct ldb_request *change_req;
2677         enum ndr_err_code ndr_err;
2678         struct ldb_message *msg;
2679         struct replPropertyMetaDataBlob *rmd;
2680         struct replPropertyMetaDataBlob omd;
2681         const struct ldb_val *omd_value;
2682         struct replPropertyMetaDataBlob nmd;
2683         struct ldb_val nmd_value;
2684         uint32_t i,j,ni=0;
2685         uint32_t removed_attrs = 0;
2686         int ret;
2687
2688         ldb = ldb_module_get_ctx(ar->module);
2689         msg = ar->objs->objects[ar->index_current].msg;
2690         rmd = ar->objs->objects[ar->index_current].meta_data;
2691         ZERO_STRUCT(omd);
2692         omd.version = 1;
2693
2694         /*
2695          * TODO: check repl data is correct after a rename
2696          */
2697         if (ldb_dn_compare(msg->dn, ar->search_msg->dn) != 0) {
2698                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_request rename %s => %s\n",
2699                           ldb_dn_get_linearized(ar->search_msg->dn),
2700                           ldb_dn_get_linearized(msg->dn));
2701                 if (dsdb_module_rename(ar->module,
2702                                        ar->search_msg->dn, msg->dn,
2703                                        DSDB_FLAG_OWN_MODULE) != LDB_SUCCESS) {
2704                         ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_replicated_request rename %s => %s failed - %s\n",
2705                                   ldb_dn_get_linearized(ar->search_msg->dn),
2706                                   ldb_dn_get_linearized(msg->dn),
2707                                   ldb_errstring(ldb));
2708                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
2709                 }
2710         }
2711
2712         /* find existing meta data */
2713         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
2714         if (omd_value) {
2715                 ndr_err = ndr_pull_struct_blob(omd_value, ar,
2716                                                lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &omd,
2717                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
2718                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2719                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2720                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2721                 }
2722
2723                 if (omd.version != 1) {
2724                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
2725                 }
2726         }
2727
2728         ZERO_STRUCT(nmd);
2729         nmd.version = 1;
2730         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
2731         nmd.ctr.ctr1.array = talloc_array(ar,
2732                                           struct replPropertyMetaData1,
2733                                           nmd.ctr.ctr1.count);
2734         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2735
2736         /* first copy the old meta data */
2737         for (i=0; i < omd.ctr.ctr1.count; i++) {
2738                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
2739                 ni++;
2740         }
2741
2742         /* now merge in the new meta data */
2743         for (i=0; i < rmd->ctr.ctr1.count; i++) {
2744                 bool found = false;
2745
2746                 for (j=0; j < ni; j++) {
2747                         bool cmp;
2748
2749                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
2750                                 continue;
2751                         }
2752
2753                         cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
2754                                                                     &rmd->ctr.ctr1.array[i]);
2755                         if (cmp) {
2756                                 /* replace the entry */
2757                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
2758                                 found = true;
2759                                 break;
2760                         }
2761
2762                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTRIBUTE_instanceType) {
2763                                 DEBUG(1,("Discarding older DRS attribute update to %s on %s from %s\n",
2764                                          msg->elements[i-removed_attrs].name,
2765                                          ldb_dn_get_linearized(msg->dn),
2766                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
2767                         }
2768
2769                         /* we don't want to apply this change so remove the attribute */
2770                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
2771                         removed_attrs++;
2772
2773                         found = true;
2774                         break;
2775                 }
2776
2777                 if (found) continue;
2778
2779                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
2780                 ni++;
2781         }
2782
2783         /*
2784          * finally correct the size of the meta_data array
2785          */
2786         nmd.ctr.ctr1.count = ni;
2787
2788         /*
2789          * the rdn attribute (the alias for the name attribute),
2790          * 'cn' for most objects is the last entry in the meta data array
2791          * we have stored
2792          *
2793          * sort the new meta data array
2794          */
2795         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
2796         if (ret != LDB_SUCCESS) {
2797                 return ret;
2798         }
2799
2800         /*
2801          * check if some replicated attributes left, otherwise skip the ldb_modify() call
2802          */
2803         if (msg->num_elements == 0) {
2804                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
2805                           ar->index_current);
2806
2807                 ar->index_current++;
2808                 return replmd_replicated_apply_next(ar);
2809         }
2810
2811         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
2812                   ar->index_current, msg->num_elements);
2813
2814         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
2815         if (ret != LDB_SUCCESS) {
2816                 return replmd_replicated_request_error(ar, ret);
2817         }
2818
2819         for (i=0; i<ni; i++) {
2820                 nmd.ctr.ctr1.array[i].local_usn = ar->seq_num;
2821         }
2822
2823         /* create the meta data value */
2824         ndr_err = ndr_push_struct_blob(&nmd_value, msg, 
2825                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
2826                                        &nmd,
2827                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
2828         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2829                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2830                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
2831         }
2832
2833         /*
2834          * when we know that we'll modify the record, add the whenChanged, uSNChanged
2835          * and replPopertyMetaData attributes
2836          */
2837         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
2838         if (ret != LDB_SUCCESS) {
2839                 return replmd_replicated_request_error(ar, ret);
2840         }
2841         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
2842         if (ret != LDB_SUCCESS) {
2843                 return replmd_replicated_request_error(ar, ret);
2844         }
2845         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
2846         if (ret != LDB_SUCCESS) {
2847                 return replmd_replicated_request_error(ar, ret);
2848         }
2849
2850         replmd_ldb_message_sort(msg, ar->schema);
2851
2852         /* we want to replace the old values */
2853         for (i=0; i < msg->num_elements; i++) {
2854                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
2855         }
2856
2857         if (DEBUGLVL(4)) {
2858                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
2859                 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
2860                 talloc_free(s);
2861         }
2862
2863         ret = ldb_build_mod_req(&change_req,
2864                                 ldb,
2865                                 ar,
2866                                 msg,
2867                                 ar->controls,
2868                                 ar,
2869                                 replmd_op_callback,
2870                                 ar->req);
2871         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2872
2873         return ldb_next_request(ar->module, change_req);
2874 }
2875
2876 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
2877                                                    struct ldb_reply *ares)
2878 {
2879         struct replmd_replicated_request *ar = talloc_get_type(req->context,
2880                                                struct replmd_replicated_request);
2881         int ret;
2882
2883         if (!ares) {
2884                 return ldb_module_done(ar->req, NULL, NULL,
2885                                         LDB_ERR_OPERATIONS_ERROR);
2886         }
2887         if (ares->error != LDB_SUCCESS &&
2888             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
2889                 return ldb_module_done(ar->req, ares->controls,
2890                                         ares->response, ares->error);
2891         }
2892
2893         switch (ares->type) {
2894         case LDB_REPLY_ENTRY:
2895                 ar->search_msg = talloc_steal(ar, ares->message);
2896                 break;
2897
2898         case LDB_REPLY_REFERRAL:
2899                 /* we ignore referrals */
2900                 break;
2901
2902         case LDB_REPLY_DONE:
2903                 if (ar->search_msg != NULL) {
2904                         ret = replmd_replicated_apply_merge(ar);
2905                 } else {
2906                         ret = replmd_replicated_apply_add(ar);
2907                 }
2908                 if (ret != LDB_SUCCESS) {
2909                         return ldb_module_done(ar->req, NULL, NULL, ret);
2910                 }
2911         }
2912
2913         talloc_free(ares);
2914         return LDB_SUCCESS;
2915 }
2916
2917 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
2918
2919 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
2920 {
2921         struct ldb_context *ldb;
2922         int ret;
2923         char *tmp_str;
2924         char *filter;
2925         struct ldb_request *search_req;
2926         struct ldb_search_options_control *options;
2927
2928         if (ar->index_current >= ar->objs->num_objects) {
2929                 /* done with it, go to next stage */
2930                 return replmd_replicated_uptodate_vector(ar);
2931         }
2932
2933         ldb = ldb_module_get_ctx(ar->module);
2934         ar->search_msg = NULL;
2935
2936         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
2937         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2938
2939         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
2940         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
2941         talloc_free(tmp_str);
2942
2943         ret = ldb_build_search_req(&search_req,
2944                                    ldb,
2945                                    ar,
2946                                    NULL,
2947                                    LDB_SCOPE_SUBTREE,
2948                                    filter,
2949                                    NULL,
2950                                    NULL,
2951                                    ar,
2952                                    replmd_replicated_apply_search_callback,
2953                                    ar->req);
2954
2955         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
2956         if (ret != LDB_SUCCESS) {
2957                 return ret;
2958         }
2959
2960         /* we need to cope with cross-partition links, so search for
2961            the GUID over all partitions */
2962         options = talloc(search_req, struct ldb_search_options_control);
2963         if (options == NULL) {
2964                 DEBUG(0, (__location__ ": out of memory\n"));
2965                 return LDB_ERR_OPERATIONS_ERROR;
2966         }
2967         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
2968
2969         ret = ldb_request_add_control(search_req,
2970                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
2971                                       true, options);
2972         if (ret != LDB_SUCCESS) {
2973                 return ret;
2974         }
2975
2976         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
2977
2978         return ldb_next_request(ar->module, search_req);
2979 }
2980
2981 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
2982                                                       struct ldb_reply *ares)
2983 {
2984         struct ldb_context *ldb;
2985         struct replmd_replicated_request *ar = talloc_get_type(req->context,
2986                                                struct replmd_replicated_request);
2987         ldb = ldb_module_get_ctx(ar->module);
2988
2989         if (!ares) {
2990                 return ldb_module_done(ar->req, NULL, NULL,
2991                                         LDB_ERR_OPERATIONS_ERROR);
2992         }
2993         if (ares->error != LDB_SUCCESS) {
2994                 return ldb_module_done(ar->req, ares->controls,
2995                                         ares->response, ares->error);
2996         }
2997
2998         if (ares->type != LDB_REPLY_DONE) {
2999                 ldb_set_errstring(ldb, "Invalid reply type\n!");
3000                 return ldb_module_done(ar->req, NULL, NULL,
3001                                         LDB_ERR_OPERATIONS_ERROR);
3002         }
3003
3004         talloc_free(ares);
3005
3006         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3007 }
3008
3009 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3010 {
3011         struct ldb_context *ldb;
3012         struct ldb_request *change_req;
3013         enum ndr_err_code ndr_err;
3014         struct ldb_message *msg;
3015         struct replUpToDateVectorBlob ouv;
3016         const struct ldb_val *ouv_value;
3017         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3018         struct replUpToDateVectorBlob nuv;
3019         struct ldb_val nuv_value;
3020         struct ldb_message_element *nuv_el = NULL;
3021         const struct GUID *our_invocation_id;
3022         struct ldb_message_element *orf_el = NULL;
3023         struct repsFromToBlob nrf;
3024         struct ldb_val *nrf_value = NULL;
3025         struct ldb_message_element *nrf_el = NULL;
3026         uint32_t i,j,ni=0;
3027         bool found = false;
3028         time_t t = time(NULL);
3029         NTTIME now;
3030         int ret;
3031
3032         ldb = ldb_module_get_ctx(ar->module);
3033         ruv = ar->objs->uptodateness_vector;
3034         ZERO_STRUCT(ouv);
3035         ouv.version = 2;
3036         ZERO_STRUCT(nuv);
3037         nuv.version = 2;
3038
3039         unix_to_nt_time(&now, t);
3040
3041         /*
3042          * first create the new replUpToDateVector
3043          */
3044         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
3045         if (ouv_value) {
3046                 ndr_err = ndr_pull_struct_blob(ouv_value, ar,
3047                                                lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), &ouv,
3048                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3049                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3050                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3051                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3052                 }
3053
3054                 if (ouv.version != 2) {
3055                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3056                 }
3057         }
3058
3059         /*
3060          * the new uptodateness vector will at least
3061          * contain 1 entry, one for the source_dsa
3062          *
3063          * plus optional values from our old vector and the one from the source_dsa
3064          */
3065         nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
3066         if (ruv) nuv.ctr.ctr2.count += ruv->count;
3067         nuv.ctr.ctr2.cursors = talloc_array(ar,
3068                                             struct drsuapi_DsReplicaCursor2,
3069                                             nuv.ctr.ctr2.count);
3070         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3071
3072         /* first copy the old vector */
3073         for (i=0; i < ouv.ctr.ctr2.count; i++) {
3074                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
3075                 ni++;
3076         }
3077
3078         /* get our invocation_id if we have one already attached to the ldb */
3079         our_invocation_id = samdb_ntds_invocation_id(ldb);
3080
3081         /* merge in the source_dsa vector is available */
3082         for (i=0; (ruv && i < ruv->count); i++) {
3083                 found = false;
3084
3085                 if (our_invocation_id &&
3086                     GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3087                                our_invocation_id)) {
3088                         continue;
3089                 }
3090
3091                 for (j=0; j < ni; j++) {
3092                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3093                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3094                                 continue;
3095                         }
3096
3097                         found = true;
3098
3099                         /*
3100                          * we update only the highest_usn and not the latest_sync_success time,
3101                          * because the last success stands for direct replication
3102                          */
3103                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3104                                 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3105                         }
3106                         break;                  
3107                 }
3108
3109                 if (found) continue;
3110
3111                 /* if it's not there yet, add it */
3112                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3113                 ni++;
3114         }
3115
3116         /*
3117          * merge in the current highwatermark for the source_dsa
3118          */
3119         found = false;
3120         for (j=0; j < ni; j++) {
3121                 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
3122                                 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3123                         continue;
3124                 }
3125
3126                 found = true;
3127
3128                 /*
3129                  * here we update the highest_usn and last_sync_success time
3130                  * because we're directly replicating from the source_dsa
3131                  *
3132                  * and use the tmp_highest_usn because this is what we have just applied
3133                  * to our ldb
3134                  */
3135                 nuv.ctr.ctr2.cursors[j].highest_usn             = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3136                 nuv.ctr.ctr2.cursors[j].last_sync_success       = now;
3137                 break;
3138         }
3139         if (!found) {
3140                 /*
3141                  * here we update the highest_usn and last_sync_success time
3142                  * because we're directly replicating from the source_dsa
3143                  *
3144                  * and use the tmp_highest_usn because this is what we have just applied
3145                  * to our ldb
3146                  */
3147                 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
3148                 nuv.ctr.ctr2.cursors[ni].highest_usn            = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3149                 nuv.ctr.ctr2.cursors[ni].last_sync_success      = now;
3150                 ni++;
3151         }
3152
3153         /*
3154          * finally correct the size of the cursors array
3155          */
3156         nuv.ctr.ctr2.count = ni;
3157
3158         /*
3159          * sort the cursors
3160          */
3161         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
3162
3163         /*
3164          * create the change ldb_message
3165          */
3166         msg = ldb_msg_new(ar);
3167         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3168         msg->dn = ar->search_msg->dn;
3169
3170         ndr_err = ndr_push_struct_blob(&nuv_value, msg, 
3171                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), 
3172                                        &nuv,
3173                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3174         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3175                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3176                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3177         }
3178         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3179         if (ret != LDB_SUCCESS) {
3180                 return replmd_replicated_request_error(ar, ret);
3181         }
3182         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3183
3184         /*
3185          * now create the new repsFrom value from the given repsFromTo1 structure
3186          */
3187         ZERO_STRUCT(nrf);
3188         nrf.version                                     = 1;
3189         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
3190         /* and fix some values... */
3191         nrf.ctr.ctr1.consecutive_sync_failures          = 0;
3192         nrf.ctr.ctr1.last_success                       = now;
3193         nrf.ctr.ctr1.last_attempt                       = now;
3194         nrf.ctr.ctr1.result_last_attempt                = WERR_OK;
3195         nrf.ctr.ctr1.highwatermark.highest_usn          = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3196
3197         /*
3198          * first see if we already have a repsFrom value for the current source dsa
3199          * if so we'll later replace this value
3200          */
3201         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3202         if (orf_el) {
3203                 for (i=0; i < orf_el->num_values; i++) {
3204                         struct repsFromToBlob *trf;
3205
3206                         trf = talloc(ar, struct repsFromToBlob);
3207                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3208
3209                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")), trf,
3210                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3211                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3212                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3213                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3214                         }
3215
3216                         if (trf->version != 1) {
3217                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3218                         }
3219
3220                         /*
3221                          * we compare the source dsa objectGUID not the invocation_id
3222                          * because we want only one repsFrom value per source dsa
3223                          * and when the invocation_id of the source dsa has changed we don't need 
3224                          * the old repsFrom with the old invocation_id
3225                          */
3226                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3227                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
3228                                 talloc_free(trf);
3229                                 continue;
3230                         }
3231
3232                         talloc_free(trf);
3233                         nrf_value = &orf_el->values[i];
3234                         break;
3235                 }
3236
3237                 /*
3238                  * copy over all old values to the new ldb_message
3239                  */
3240                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3241                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3242                 *nrf_el = *orf_el;
3243         }
3244
3245         /*
3246          * if we haven't found an old repsFrom value for the current source dsa
3247          * we'll add a new value
3248          */
3249         if (!nrf_value) {
3250                 struct ldb_val zero_value;
3251                 ZERO_STRUCT(zero_value);
3252                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3253                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3254
3255                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3256         }
3257
3258         /* we now fill the value which is already attached to ldb_message */
3259         ndr_err = ndr_push_struct_blob(nrf_value, msg, 
3260                                        lp_iconv_convenience(ldb_get_opaque(ldb, "loadparm")),
3261                                        &nrf,
3262                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
3263         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3264                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3265                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3266         }
3267
3268         /* 
3269          * the ldb_message_element for the attribute, has all the old values and the new one
3270          * so we'll replace the whole attribute with all values
3271          */
3272         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
3273
3274         if (DEBUGLVL(4)) {
3275                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3276                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
3277                 talloc_free(s);
3278         }
3279
3280         /* prepare the ldb_modify() request */
3281         ret = ldb_build_mod_req(&change_req,
3282                                 ldb,
3283                                 ar,
3284                                 msg,
3285                                 ar->controls,
3286                                 ar,
3287                                 replmd_replicated_uptodate_modify_callback,
3288                                 ar->req);
3289         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3290
3291         return ldb_next_request(ar->module, change_req);
3292 }
3293
3294 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
3295                                                       struct ldb_reply *ares)
3296 {
3297         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3298                                                struct replmd_replicated_request);
3299         int ret;
3300
3301         if (!ares) {
3302                 return ldb_module_done(ar->req, NULL, NULL,
3303                                         LDB_ERR_OPERATIONS_ERROR);
3304         }
3305         if (ares->error != LDB_SUCCESS &&
3306             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3307                 return ldb_module_done(ar->req, ares->controls,
3308                                         ares->response, ares->error);
3309         }
3310
3311         switch (ares->type) {
3312         case LDB_REPLY_ENTRY:
3313                 ar->search_msg = talloc_steal(ar, ares->message);
3314                 break;
3315
3316         case LDB_REPLY_REFERRAL:
3317                 /* we ignore referrals */
3318                 break;
3319
3320         case LDB_REPLY_DONE:
3321                 if (ar->search_msg == NULL) {
3322                         ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3323                 } else {
3324                         ret = replmd_replicated_uptodate_modify(ar);
3325                 }
3326                 if (ret != LDB_SUCCESS) {
3327                         return ldb_module_done(ar->req, NULL, NULL, ret);
3328                 }
3329         }
3330
3331         talloc_free(ares);
3332         return LDB_SUCCESS;
3333 }
3334
3335
3336 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
3337 {
3338         struct ldb_context *ldb;
3339         int ret;
3340         static const char *attrs[] = {
3341                 "replUpToDateVector",
3342                 "repsFrom",
3343                 NULL
3344         };
3345         struct ldb_request *search_req;
3346
3347         ldb = ldb_module_get_ctx(ar->module);
3348         ar->search_msg = NULL;
3349
3350         ret = ldb_build_search_req(&search_req,
3351                                    ldb,
3352                                    ar,
3353                                    ar->objs->partition_dn,
3354                                    LDB_SCOPE_BASE,
3355                                    "(objectClass=*)",
3356                                    attrs,
3357                                    NULL,
3358                                    ar,
3359                                    replmd_replicated_uptodate_search_callback,
3360                                    ar->req);
3361         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3362
3363         return ldb_next_request(ar->module, search_req);
3364 }
3365
3366
3367
3368 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
3369 {
3370         struct ldb_context *ldb;
3371         struct dsdb_extended_replicated_objects *objs;
3372         struct replmd_replicated_request *ar;
3373         struct ldb_control **ctrls;
3374         int ret, i;
3375         struct replmd_private *replmd_private = 
3376                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3377
3378         ldb = ldb_module_get_ctx(module);
3379
3380         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
3381
3382         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
3383         if (!objs) {
3384                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
3385                 return LDB_ERR_PROTOCOL_ERROR;
3386         }
3387
3388         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
3389                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
3390                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
3391                 return LDB_ERR_PROTOCOL_ERROR;
3392         }
3393
3394         ar = replmd_ctx_init(module, req);
3395         if (!ar)
3396                 return LDB_ERR_OPERATIONS_ERROR;
3397
3398         /* Set the flags to have the replmd_op_callback run over the full set of objects */
3399         ar->apply_mode = true;
3400         ar->objs = objs;
3401         ar->schema = dsdb_get_schema(ldb);
3402         if (!ar->schema) {
3403                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
3404                 talloc_free(ar);
3405                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
3406                 return LDB_ERR_CONSTRAINT_VIOLATION;
3407         }
3408
3409         ctrls = req->controls;
3410
3411         if (req->controls) {
3412                 req->controls = talloc_memdup(ar, req->controls,
3413                                               talloc_get_size(req->controls));
3414                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3415         }
3416
3417         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
3418         if (ret != LDB_SUCCESS) {
3419                 return ret;
3420         }
3421
3422         ar->controls = req->controls;
3423         req->controls = ctrls;
3424
3425         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
3426
3427         /* save away the linked attributes for the end of the
3428            transaction */
3429         for (i=0; i<ar->objs->linked_attributes_count; i++) {
3430                 struct la_entry *la_entry;
3431
3432                 if (replmd_private->la_ctx == NULL) {
3433                         replmd_private->la_ctx = talloc_new(replmd_private);
3434                 }
3435                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
3436                 if (la_entry == NULL) {
3437                         ldb_oom(ldb);
3438                         return LDB_ERR_OPERATIONS_ERROR;
3439                 }
3440                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
3441                 if (la_entry->la == NULL) {
3442                         talloc_free(la_entry);
3443                         ldb_oom(ldb);
3444                         return LDB_ERR_OPERATIONS_ERROR;
3445                 }
3446                 *la_entry->la = ar->objs->linked_attributes[i];
3447
3448                 /* we need to steal the non-scalars so they stay
3449                    around until the end of the transaction */
3450                 talloc_steal(la_entry->la, la_entry->la->identifier);
3451                 talloc_steal(la_entry->la, la_entry->la->value.blob);
3452
3453                 DLIST_ADD(replmd_private->la_list, la_entry);
3454         }
3455
3456         return replmd_replicated_apply_next(ar);
3457 }
3458
3459 /*
3460   process one linked attribute structure
3461  */
3462 static int replmd_process_linked_attribute(struct ldb_module *module,
3463                                            struct la_entry *la_entry)
3464 {                                          
3465         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
3466         struct ldb_context *ldb = ldb_module_get_ctx(module);
3467         struct dsdb_schema *schema = dsdb_get_schema(ldb);
3468         struct ldb_message *msg;
3469         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
3470         int ret;
3471         const struct dsdb_attribute *attr;
3472         struct dsdb_dn *dsdb_dn;
3473         uint64_t seq_num = 0;
3474         struct ldb_message_element *old_el;
3475         WERROR status;
3476         time_t t = time(NULL);
3477         struct ldb_result *res;
3478         const char *attrs[2];
3479         struct parsed_dn *pdn_list, *pdn;
3480         struct GUID guid = GUID_zero();
3481         NTSTATUS ntstatus;
3482         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
3483         const struct GUID *our_invocation_id;
3484
3485 /*
3486 linked_attributes[0]:                                                     
3487      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute 
3488         identifier               : *                                      
3489             identifier: struct drsuapi_DsReplicaObjectIdentifier          
3490                 __ndr_size               : 0x0000003a (58)                
3491                 __ndr_size_sid           : 0x00000000 (0)                 
3492                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
3493                 sid                      : S-0-0                               
3494                 __ndr_size_dn            : 0x00000000 (0)                      
3495                 dn                       : ''                                  
3496         attid                    : DRSUAPI_ATTRIBUTE_member (0x1F)             
3497         value: struct drsuapi_DsAttributeValue                                 
3498             __ndr_size               : 0x0000007e (126)                        
3499             blob                     : *                                       
3500                 blob                     : DATA_BLOB length=126                
3501         flags                    : 0x00000001 (1)                              
3502                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE                      
3503         originating_add_time     : Wed Sep  2 22:20:01 2009 EST                
3504         meta_data: struct drsuapi_DsReplicaMetaData                            
3505             version                  : 0x00000015 (21)                         
3506             originating_change_time  : Wed Sep  2 23:39:07 2009 EST            
3507             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64    
3508             originating_usn          : 0x000000000001e19c (123292)             
3509
3510 (for cases where the link is to a normal DN)
3511      &target: struct drsuapi_DsReplicaObjectIdentifier3                        
3512         __ndr_size               : 0x0000007e (126)                            
3513         __ndr_size_sid           : 0x0000001c (28)                             
3514         guid                     : 7639e594-db75-4086-b0d4-67890ae46031        
3515         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
3516         __ndr_size_dn            : 0x00000022 (34)                                
3517         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'           
3518  */
3519         
3520         /* find the attribute being modified */
3521         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
3522         if (attr == NULL) {
3523                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
3524                 talloc_free(tmp_ctx);
3525                 return LDB_ERR_OPERATIONS_ERROR;
3526         }
3527
3528         attrs[0] = attr->lDAPDisplayName;
3529         attrs[1] = NULL;
3530
3531         /* get the existing message from the db for the object with
3532            this GUID, returning attribute being modified. We will then
3533            use this msg as the basis for a modify call */
3534         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
3535                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
3536                                  DSDB_SEARCH_SHOW_DELETED |
3537                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3538                                  DSDB_SEARCH_REVEAL_INTERNALS,
3539                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
3540         if (ret != LDB_SUCCESS) {
3541                 talloc_free(tmp_ctx);
3542                 return ret;
3543         }
3544         if (res->count != 1) {
3545                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
3546                                        GUID_string(tmp_ctx, &la->identifier->guid));
3547                 talloc_free(tmp_ctx);
3548                 return LDB_ERR_NO_SUCH_OBJECT;
3549         }
3550         msg = res->msgs[0];
3551
3552         if (msg->num_elements == 0) {
3553                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
3554                 if (ret != LDB_SUCCESS) {
3555                         ldb_module_oom(module);
3556                         talloc_free(tmp_ctx);
3557                         return LDB_ERR_OPERATIONS_ERROR;
3558                 }
3559         } else {
3560                 old_el = &msg->elements[0];
3561                 old_el->flags = LDB_FLAG_MOD_REPLACE;
3562         }
3563
3564         /* parse the existing links */
3565         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid);
3566         if (ret != LDB_SUCCESS) {
3567                 talloc_free(tmp_ctx);
3568                 return ret;
3569         }
3570
3571         /* get our invocationId */
3572         our_invocation_id = samdb_ntds_invocation_id(ldb);
3573         if (!our_invocation_id) {
3574                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
3575                 talloc_free(tmp_ctx);
3576                 return LDB_ERR_OPERATIONS_ERROR;
3577         }
3578
3579         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, our_invocation_id);
3580         if (ret != LDB_SUCCESS) {
3581                 talloc_free(tmp_ctx);
3582                 return ret;
3583         }
3584
3585         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
3586         if (!W_ERROR_IS_OK(status)) {
3587                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
3588                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
3589                 return LDB_ERR_OPERATIONS_ERROR;
3590         }
3591
3592         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
3593         if (!NT_STATUS_IS_OK(ntstatus) && active) {
3594                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
3595                                        old_el->name,
3596                                        ldb_dn_get_linearized(dsdb_dn->dn),
3597                                        ldb_dn_get_linearized(msg->dn));
3598                 return LDB_ERR_OPERATIONS_ERROR;
3599         }
3600
3601         /* re-resolve the DN by GUID, as the DRS server may give us an
3602            old DN value */
3603         ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn);
3604         if (ret != LDB_SUCCESS) {
3605                 ldb_asprintf_errstring(ldb, __location__ ": Failed to re-resolve GUID %s",
3606                                        GUID_string(tmp_ctx, &guid));
3607                 talloc_free(tmp_ctx);
3608                 return ret;
3609         }
3610
3611         /* see if this link already exists */
3612         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
3613         if (pdn != NULL) {
3614                 /* see if this update is newer than what we have already */
3615                 struct GUID invocation_id = GUID_zero();
3616                 uint32_t version = 0;
3617                 NTTIME change_time = 0;
3618                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
3619
3620                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
3621                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
3622                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
3623
3624                 if (!replmd_update_is_newer(&invocation_id,
3625                                             &la->meta_data.originating_invocation_id,
3626                                             version,
3627                                             la->meta_data.version,
3628                                             change_time,
3629                                             la->meta_data.originating_change_time)) {
3630                         DEBUG(1,("Discarding older DRS linked attribute update to %s on %s from %s\n",
3631                                  old_el->name, ldb_dn_get_linearized(msg->dn),
3632                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
3633                         talloc_free(tmp_ctx);
3634                         return LDB_SUCCESS;
3635                 }
3636
3637                 /* get a seq_num for this change */
3638                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3639                 if (ret != LDB_SUCCESS) {
3640                         talloc_free(tmp_ctx);
3641                         return ret;
3642                 }
3643
3644                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
3645                         /* remove the existing backlink */
3646                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
3647                         if (ret != LDB_SUCCESS) {
3648                                 talloc_free(tmp_ctx);
3649                                 return ret;
3650                         }
3651                 }
3652
3653                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
3654                                            &la->meta_data.originating_invocation_id,
3655                                            la->meta_data.originating_usn, seq_num,
3656                                            la->meta_data.originating_change_time,
3657                                            la->meta_data.version,
3658                                            !active);
3659                 if (ret != LDB_SUCCESS) {
3660                         talloc_free(tmp_ctx);
3661                         return ret;
3662                 }
3663
3664                 if (active) {
3665                         /* add the new backlink */
3666                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
3667                         if (ret != LDB_SUCCESS) {
3668                                 talloc_free(tmp_ctx);
3669                                 return ret;
3670                         }
3671                 }
3672         } else {
3673                 /* get a seq_num for this change */
3674                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
3675                 if (ret != LDB_SUCCESS) {
3676                         talloc_free(tmp_ctx);
3677                         return ret;
3678                 }
3679
3680                 old_el->values = talloc_realloc(msg->elements, old_el->values,
3681                                                 struct ldb_val, old_el->num_values+1);
3682                 if (!old_el->values) {
3683                         ldb_module_oom(module);
3684                         return LDB_ERR_OPERATIONS_ERROR;
3685                 }
3686                 old_el->num_values++;
3687
3688                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
3689                                           &la->meta_data.originating_invocation_id,
3690                                           la->meta_data.originating_usn, seq_num,
3691                                           la->meta_data.originating_change_time,
3692                                           la->meta_data.version,
3693                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
3694                 if (ret != LDB_SUCCESS) {
3695                         talloc_free(tmp_ctx);
3696                         return ret;
3697                 }
3698
3699                 if (active) {
3700                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
3701                                                   true, attr, false);
3702                         if (ret != LDB_SUCCESS) {
3703                                 talloc_free(tmp_ctx);
3704                                 return ret;
3705                         }
3706                 }
3707         }
3708
3709         /* we only change whenChanged and uSNChanged if the seq_num
3710            has changed */
3711         if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
3712                 talloc_free(tmp_ctx);
3713                 return LDB_ERR_OPERATIONS_ERROR;
3714         }
3715
3716         if (add_uint64_element(msg, "uSNChanged", seq_num) != LDB_SUCCESS) {
3717                 talloc_free(tmp_ctx);
3718                 return LDB_ERR_OPERATIONS_ERROR;
3719         }
3720
3721         ret = dsdb_check_single_valued_link(attr, old_el);
3722         if (ret != LDB_SUCCESS) {
3723                 talloc_free(tmp_ctx);
3724                 return ret;
3725         }
3726
3727         ret = dsdb_module_modify(module, msg, DSDB_MODIFY_RELAX);
3728         if (ret != LDB_SUCCESS) {
3729                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
3730                           ldb_errstring(ldb),
3731                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
3732                 talloc_free(tmp_ctx);
3733                 return ret;
3734         }
3735         
3736         talloc_free(tmp_ctx);
3737
3738         return ret;     
3739 }
3740
3741 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
3742 {
3743         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
3744                 return replmd_extended_replicated_objects(module, req);
3745         }
3746
3747         return ldb_next_request(module, req);
3748 }
3749
3750
3751 /*
3752   we hook into the transaction operations to allow us to 
3753   perform the linked attribute updates at the end of the whole
3754   transaction. This allows a forward linked attribute to be created
3755   before the object is created. During a vampire, w2k8 sends us linked
3756   attributes before the objects they are part of.
3757  */
3758 static int replmd_start_transaction(struct ldb_module *module)
3759 {
3760         /* create our private structure for this transaction */
3761         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
3762                                                                 struct replmd_private);
3763         replmd_txn_cleanup(replmd_private);
3764
3765         /* free any leftover mod_usn records from cancelled
3766            transactions */
3767         while (replmd_private->ncs) {
3768                 struct nc_entry *e = replmd_private->ncs;
3769                 DLIST_REMOVE(replmd_private->ncs, e);
3770                 talloc_free(e);
3771         }
3772
3773         return ldb_next_start_trans(module);
3774 }
3775
3776 /*
3777   on prepare commit we loop over our queued la_context structures and
3778   apply each of them  
3779  */
3780 static int replmd_prepare_commit(struct ldb_module *module)
3781 {
3782         struct replmd_private *replmd_private = 
3783                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3784         struct la_entry *la, *prev;
3785         struct la_backlink *bl;
3786         int ret;
3787
3788         /* walk the list backwards, to do the first entry first, as we
3789          * added the entries with DLIST_ADD() which puts them at the
3790          * start of the list */
3791         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
3792                 prev = DLIST_PREV(la);
3793                 DLIST_REMOVE(replmd_private->la_list, la);
3794                 ret = replmd_process_linked_attribute(module, la);
3795                 if (ret != LDB_SUCCESS) {
3796                         replmd_txn_cleanup(replmd_private);
3797                         return ret;
3798                 }
3799         }
3800
3801         /* process our backlink list, creating and deleting backlinks
3802            as necessary */
3803         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
3804                 ret = replmd_process_backlink(module, bl);
3805                 if (ret != LDB_SUCCESS) {
3806                         replmd_txn_cleanup(replmd_private);
3807                         return ret;
3808                 }
3809         }
3810
3811         replmd_txn_cleanup(replmd_private);
3812
3813         /* possibly change @REPLCHANGED */
3814         ret = replmd_notify_store(module);
3815         if (ret != LDB_SUCCESS) {
3816                 return ret;
3817         }
3818         
3819         return ldb_next_prepare_commit(module);
3820 }
3821
3822 static int replmd_del_transaction(struct ldb_module *module)
3823 {
3824         struct replmd_private *replmd_private = 
3825                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3826         replmd_txn_cleanup(replmd_private);
3827
3828         return ldb_next_del_trans(module);
3829 }
3830
3831
3832 _PUBLIC_ const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
3833         .name          = "repl_meta_data",
3834         .init_context      = replmd_init,
3835         .add               = replmd_add,
3836         .modify            = replmd_modify,
3837         .rename            = replmd_rename,
3838         .del               = replmd_delete,
3839         .extended          = replmd_extended,
3840         .start_transaction = replmd_start_transaction,
3841         .prepare_commit    = replmd_prepare_commit,
3842         .del_transaction   = replmd_del_transaction,
3843 };