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