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