s4:repl_meta_data LDB module - don't intercept the partition LDB module referrals
[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(3,("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(5,("%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, bool *rodc)
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", "instanceType", 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 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) {
1247                         return ret;
1248                 }
1249
1250                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1251                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1252                                                                 situation)) {
1253                         *is_urgent = true;
1254                 }
1255
1256                 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1257                 if (*seq_num <= db_seq) {
1258                         DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\
1259                                               " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n",
1260                                  (long long)*seq_num, (long long)db_seq));
1261                         return LDB_ERR_OPERATIONS_ERROR;
1262                 }
1263
1264         } else {
1265                 /* search for the existing replPropertyMetaDataBlob. We need
1266                  * to use REVEAL and ask for DNs in storage format to support
1267                  * the check for values being the same in
1268                  * replmd_update_rpmd_element()
1269                  */
1270                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1271                                             DSDB_FLAG_NEXT_MODULE |
1272                                             DSDB_SEARCH_SHOW_RECYCLED |
1273                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1274                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1275                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1276                 if (ret != LDB_SUCCESS) {
1277                         return ret;
1278                 }
1279
1280                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1281                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1282                                                                 situation)) {
1283                         *is_urgent = true;
1284                 }
1285
1286                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1287                 if (!omd_value) {
1288                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1289                                  ldb_dn_get_linearized(msg->dn)));
1290                         return LDB_ERR_OPERATIONS_ERROR;
1291                 }
1292
1293                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1294                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1295                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1296                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1297                                  ldb_dn_get_linearized(msg->dn)));
1298                         return LDB_ERR_OPERATIONS_ERROR;
1299                 }
1300
1301                 if (omd.version != 1) {
1302                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1303                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1304                         return LDB_ERR_OPERATIONS_ERROR;
1305                 }
1306
1307                 for (i=0; i<msg->num_elements; i++) {
1308                         struct ldb_message_element *old_el;
1309                         old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1310                         ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1311                                                          our_invocation_id, now, req);
1312                         if (ret != LDB_SUCCESS) {
1313                                 return ret;
1314                         }
1315
1316                         if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1317                                 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1318                         }
1319
1320                 }
1321         }
1322         /*
1323          * replmd_update_rpmd_element has done an update if the
1324          * seq_num is set
1325          */
1326         if (*seq_num != 0) {
1327                 struct ldb_val *md_value;
1328                 struct ldb_message_element *el;
1329
1330                 /*if we are RODC and this is a DRSR update then its ok*/
1331                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1332                         unsigned instanceType;
1333
1334                         ret = samdb_rodc(ldb, rodc);
1335                         if (ret != LDB_SUCCESS) {
1336                                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1337                         } else if (*rodc) {
1338                                 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1339                                 return LDB_ERR_REFERRAL;
1340                         }
1341
1342                         instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1343                         if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1344                                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1345                                                  "cannot change replicated attribute on partial replica");
1346                         }
1347                 }
1348
1349                 md_value = talloc(msg, struct ldb_val);
1350                 if (md_value == NULL) {
1351                         ldb_oom(ldb);
1352                         return LDB_ERR_OPERATIONS_ERROR;
1353                 }
1354
1355                 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1356                 if (ret != LDB_SUCCESS) {
1357                         return ret;
1358                 }
1359
1360                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1361                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1362                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1363                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1364                                  ldb_dn_get_linearized(msg->dn)));
1365                         return LDB_ERR_OPERATIONS_ERROR;
1366                 }
1367
1368                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1369                 if (ret != LDB_SUCCESS) {
1370                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1371                                  ldb_dn_get_linearized(msg->dn)));
1372                         return ret;
1373                 }
1374
1375                 el->num_values = 1;
1376                 el->values = md_value;
1377         }
1378
1379         return LDB_SUCCESS;
1380 }
1381
1382 struct parsed_dn {
1383         struct dsdb_dn *dsdb_dn;
1384         struct GUID *guid;
1385         struct ldb_val *v;
1386 };
1387
1388 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1389 {
1390         return GUID_compare(pdn1->guid, pdn2->guid);
1391 }
1392
1393 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1394                                         unsigned int count, struct GUID *guid,
1395                                         struct ldb_dn *dn)
1396 {
1397         struct parsed_dn *ret;
1398         unsigned int i;
1399         if (dn && GUID_all_zero(guid)) {
1400                 /* when updating a link using DRS, we sometimes get a
1401                    NULL GUID. We then need to try and match by DN */
1402                 for (i=0; i<count; i++) {
1403                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1404                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1405                                 return &pdn[i];
1406                         }
1407                 }
1408                 return NULL;
1409         }
1410         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1411         return ret;
1412 }
1413
1414 /*
1415   get a series of message element values as an array of DNs and GUIDs
1416   the result is sorted by GUID
1417  */
1418 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1419                           struct ldb_message_element *el, struct parsed_dn **pdn,
1420                           const char *ldap_oid, struct ldb_request *parent)
1421 {
1422         unsigned int i;
1423         struct ldb_context *ldb = ldb_module_get_ctx(module);
1424
1425         if (el == NULL) {
1426                 *pdn = NULL;
1427                 return LDB_SUCCESS;
1428         }
1429
1430         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1431         if (!*pdn) {
1432                 ldb_module_oom(module);
1433                 return LDB_ERR_OPERATIONS_ERROR;
1434         }
1435
1436         for (i=0; i<el->num_values; i++) {
1437                 struct ldb_val *v = &el->values[i];
1438                 NTSTATUS status;
1439                 struct ldb_dn *dn;
1440                 struct parsed_dn *p;
1441
1442                 p = &(*pdn)[i];
1443
1444                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1445                 if (p->dsdb_dn == NULL) {
1446                         return LDB_ERR_INVALID_DN_SYNTAX;
1447                 }
1448
1449                 dn = p->dsdb_dn->dn;
1450
1451                 p->guid = talloc(*pdn, struct GUID);
1452                 if (p->guid == NULL) {
1453                         ldb_module_oom(module);
1454                         return LDB_ERR_OPERATIONS_ERROR;
1455                 }
1456
1457                 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1458                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1459                         /* we got a DN without a GUID - go find the GUID */
1460                         int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1461                         if (ret != LDB_SUCCESS) {
1462                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1463                                                        ldb_dn_get_linearized(dn));
1464                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1465                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1466                                     ldb_attr_cmp(el->name, "member") == 0) {
1467                                         return LDB_ERR_UNWILLING_TO_PERFORM;
1468                                 }
1469                                 return ret;
1470                         }
1471                         ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1472                         if (ret != LDB_SUCCESS) {
1473                                 return ret;
1474                         }
1475                 } else if (!NT_STATUS_IS_OK(status)) {
1476                         return LDB_ERR_OPERATIONS_ERROR;
1477                 }
1478
1479                 /* keep a pointer to the original ldb_val */
1480                 p->v = v;
1481         }
1482
1483         TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1484
1485         return LDB_SUCCESS;
1486 }
1487
1488 /*
1489   build a new extended DN, including all meta data fields
1490
1491   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1492   RMD_ADDTIME         = originating_add_time
1493   RMD_INVOCID         = originating_invocation_id
1494   RMD_CHANGETIME      = originating_change_time
1495   RMD_ORIGINATING_USN = originating_usn
1496   RMD_LOCAL_USN       = local_usn
1497   RMD_VERSION         = version
1498  */
1499 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1500                                const struct GUID *invocation_id, uint64_t seq_num,
1501                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1502 {
1503         struct ldb_dn *dn = dsdb_dn->dn;
1504         const char *tstring, *usn_string, *flags_string;
1505         struct ldb_val tval;
1506         struct ldb_val iid;
1507         struct ldb_val usnv, local_usnv;
1508         struct ldb_val vers, flagsv;
1509         NTSTATUS status;
1510         int ret;
1511         const char *dnstring;
1512         char *vstring;
1513         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1514
1515         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1516         if (!tstring) {
1517                 return LDB_ERR_OPERATIONS_ERROR;
1518         }
1519         tval = data_blob_string_const(tstring);
1520
1521         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1522         if (!usn_string) {
1523                 return LDB_ERR_OPERATIONS_ERROR;
1524         }
1525         usnv = data_blob_string_const(usn_string);
1526
1527         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1528         if (!usn_string) {
1529                 return LDB_ERR_OPERATIONS_ERROR;
1530         }
1531         local_usnv = data_blob_string_const(usn_string);
1532
1533         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1534         if (!vstring) {
1535                 return LDB_ERR_OPERATIONS_ERROR;
1536         }
1537         vers = data_blob_string_const(vstring);
1538
1539         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1540         if (!NT_STATUS_IS_OK(status)) {
1541                 return LDB_ERR_OPERATIONS_ERROR;
1542         }
1543
1544         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1545         if (!flags_string) {
1546                 return LDB_ERR_OPERATIONS_ERROR;
1547         }
1548         flagsv = data_blob_string_const(flags_string);
1549
1550         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1551         if (ret != LDB_SUCCESS) return ret;
1552         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1553         if (ret != LDB_SUCCESS) return ret;
1554         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1555         if (ret != LDB_SUCCESS) return ret;
1556         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1557         if (ret != LDB_SUCCESS) return ret;
1558         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1559         if (ret != LDB_SUCCESS) return ret;
1560         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1561         if (ret != LDB_SUCCESS) return ret;
1562         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1563         if (ret != LDB_SUCCESS) return ret;
1564
1565         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1566         if (dnstring == NULL) {
1567                 return LDB_ERR_OPERATIONS_ERROR;
1568         }
1569         *v = data_blob_string_const(dnstring);
1570
1571         return LDB_SUCCESS;
1572 }
1573
1574 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1575                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1576                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1577                                 uint32_t version, bool deleted);
1578
1579 /*
1580   check if any links need upgrading from w2k format
1581
1582   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.
1583  */
1584 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1585 {
1586         uint32_t i;
1587         for (i=0; i<count; i++) {
1588                 NTSTATUS status;
1589                 uint32_t version;
1590                 int ret;
1591
1592                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1593                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1594                         continue;
1595                 }
1596
1597                 /* it's an old one that needs upgrading */
1598                 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1599                                            1, 1, 0, 0, false);
1600                 if (ret != LDB_SUCCESS) {
1601                         return ret;
1602                 }
1603         }
1604         return LDB_SUCCESS;
1605 }
1606
1607 /*
1608   update an extended DN, including all meta data fields
1609
1610   see replmd_build_la_val for value names
1611  */
1612 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1613                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1614                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1615                                 uint32_t version, bool deleted)
1616 {
1617         struct ldb_dn *dn = dsdb_dn->dn;
1618         const char *tstring, *usn_string, *flags_string;
1619         struct ldb_val tval;
1620         struct ldb_val iid;
1621         struct ldb_val usnv, local_usnv;
1622         struct ldb_val vers, flagsv;
1623         const struct ldb_val *old_addtime;
1624         uint32_t old_version;
1625         NTSTATUS status;
1626         int ret;
1627         const char *dnstring;
1628         char *vstring;
1629         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1630
1631         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1632         if (!tstring) {
1633                 return LDB_ERR_OPERATIONS_ERROR;
1634         }
1635         tval = data_blob_string_const(tstring);
1636
1637         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1638         if (!usn_string) {
1639                 return LDB_ERR_OPERATIONS_ERROR;
1640         }
1641         usnv = data_blob_string_const(usn_string);
1642
1643         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1644         if (!usn_string) {
1645                 return LDB_ERR_OPERATIONS_ERROR;
1646         }
1647         local_usnv = data_blob_string_const(usn_string);
1648
1649         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1650         if (!NT_STATUS_IS_OK(status)) {
1651                 return LDB_ERR_OPERATIONS_ERROR;
1652         }
1653
1654         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1655         if (!flags_string) {
1656                 return LDB_ERR_OPERATIONS_ERROR;
1657         }
1658         flagsv = data_blob_string_const(flags_string);
1659
1660         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1661         if (ret != LDB_SUCCESS) return ret;
1662
1663         /* get the ADDTIME from the original */
1664         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1665         if (old_addtime == NULL) {
1666                 old_addtime = &tval;
1667         }
1668         if (dsdb_dn != old_dsdb_dn ||
1669             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1670                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1671                 if (ret != LDB_SUCCESS) return ret;
1672         }
1673
1674         /* use our invocation id */
1675         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1676         if (ret != LDB_SUCCESS) return ret;
1677
1678         /* changetime is the current time */
1679         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1680         if (ret != LDB_SUCCESS) return ret;
1681
1682         /* update the USN */
1683         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1684         if (ret != LDB_SUCCESS) return ret;
1685
1686         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1687         if (ret != LDB_SUCCESS) return ret;
1688
1689         /* increase the version by 1 */
1690         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1691         if (NT_STATUS_IS_OK(status) && old_version >= version) {
1692                 version = old_version+1;
1693         }
1694         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1695         vers = data_blob_string_const(vstring);
1696         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1697         if (ret != LDB_SUCCESS) return ret;
1698
1699         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1700         if (dnstring == NULL) {
1701                 return LDB_ERR_OPERATIONS_ERROR;
1702         }
1703         *v = data_blob_string_const(dnstring);
1704
1705         return LDB_SUCCESS;
1706 }
1707
1708 /*
1709   handle adding a linked attribute
1710  */
1711 static int replmd_modify_la_add(struct ldb_module *module,
1712                                 const struct dsdb_schema *schema,
1713                                 struct ldb_message *msg,
1714                                 struct ldb_message_element *el,
1715                                 struct ldb_message_element *old_el,
1716                                 const struct dsdb_attribute *schema_attr,
1717                                 uint64_t seq_num,
1718                                 time_t t,
1719                                 struct GUID *msg_guid,
1720                                 struct ldb_request *parent)
1721 {
1722         unsigned int i;
1723         struct parsed_dn *dns, *old_dns;
1724         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1725         int ret;
1726         struct ldb_val *new_values = NULL;
1727         unsigned int num_new_values = 0;
1728         unsigned old_num_values = old_el?old_el->num_values:0;
1729         const struct GUID *invocation_id;
1730         struct ldb_context *ldb = ldb_module_get_ctx(module);
1731         NTTIME now;
1732
1733         unix_to_nt_time(&now, t);
1734
1735         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1736         if (ret != LDB_SUCCESS) {
1737                 talloc_free(tmp_ctx);
1738                 return ret;
1739         }
1740
1741         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1742         if (ret != LDB_SUCCESS) {
1743                 talloc_free(tmp_ctx);
1744                 return ret;
1745         }
1746
1747         invocation_id = samdb_ntds_invocation_id(ldb);
1748         if (!invocation_id) {
1749                 talloc_free(tmp_ctx);
1750                 return LDB_ERR_OPERATIONS_ERROR;
1751         }
1752
1753         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1754         if (ret != LDB_SUCCESS) {
1755                 talloc_free(tmp_ctx);
1756                 return ret;
1757         }
1758
1759         /* for each new value, see if it exists already with the same GUID */
1760         for (i=0; i<el->num_values; i++) {
1761                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1762                 if (p == NULL) {
1763                         /* this is a new linked attribute value */
1764                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1765                         if (new_values == NULL) {
1766                                 ldb_module_oom(module);
1767                                 talloc_free(tmp_ctx);
1768                                 return LDB_ERR_OPERATIONS_ERROR;
1769                         }
1770                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1771                                                   invocation_id, seq_num, seq_num, now, 0, false);
1772                         if (ret != LDB_SUCCESS) {
1773                                 talloc_free(tmp_ctx);
1774                                 return ret;
1775                         }
1776                         num_new_values++;
1777                 } else {
1778                         /* this is only allowed if the GUID was
1779                            previously deleted. */
1780                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1781
1782                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1783                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1784                                                        el->name, GUID_string(tmp_ctx, p->guid));
1785                                 talloc_free(tmp_ctx);
1786                                 /* error codes for 'member' need to be
1787                                    special cased */
1788                                 if (ldb_attr_cmp(el->name, "member") == 0) {
1789                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
1790                                 } else {
1791                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1792                                 }
1793                         }
1794                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1795                                                    invocation_id, seq_num, seq_num, now, 0, false);
1796                         if (ret != LDB_SUCCESS) {
1797                                 talloc_free(tmp_ctx);
1798                                 return ret;
1799                         }
1800                 }
1801
1802                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1803                 if (ret != LDB_SUCCESS) {
1804                         talloc_free(tmp_ctx);
1805                         return ret;
1806                 }
1807         }
1808
1809         /* add the new ones on to the end of the old values, constructing a new el->values */
1810         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1811                                     struct ldb_val,
1812                                     old_num_values+num_new_values);
1813         if (el->values == NULL) {
1814                 ldb_module_oom(module);
1815                 return LDB_ERR_OPERATIONS_ERROR;
1816         }
1817
1818         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1819         el->num_values = old_num_values + num_new_values;
1820
1821         talloc_steal(msg->elements, el->values);
1822         talloc_steal(el->values, new_values);
1823
1824         talloc_free(tmp_ctx);
1825
1826         /* we now tell the backend to replace all existing values
1827            with the one we have constructed */
1828         el->flags = LDB_FLAG_MOD_REPLACE;
1829
1830         return LDB_SUCCESS;
1831 }
1832
1833
1834 /*
1835   handle deleting all active linked attributes
1836  */
1837 static int replmd_modify_la_delete(struct ldb_module *module,
1838                                    const struct dsdb_schema *schema,
1839                                    struct ldb_message *msg,
1840                                    struct ldb_message_element *el,
1841                                    struct ldb_message_element *old_el,
1842                                    const struct dsdb_attribute *schema_attr,
1843                                    uint64_t seq_num,
1844                                    time_t t,
1845                                    struct GUID *msg_guid,
1846                                    struct ldb_request *parent)
1847 {
1848         unsigned int i;
1849         struct parsed_dn *dns, *old_dns;
1850         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1851         int ret;
1852         const struct GUID *invocation_id;
1853         struct ldb_context *ldb = ldb_module_get_ctx(module);
1854         NTTIME now;
1855
1856         unix_to_nt_time(&now, t);
1857
1858         /* check if there is nothing to delete */
1859         if ((!old_el || old_el->num_values == 0) &&
1860             el->num_values == 0) {
1861                 return LDB_SUCCESS;
1862         }
1863
1864         if (!old_el || old_el->num_values == 0) {
1865                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1866         }
1867
1868         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1869         if (ret != LDB_SUCCESS) {
1870                 talloc_free(tmp_ctx);
1871                 return ret;
1872         }
1873
1874         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1875         if (ret != LDB_SUCCESS) {
1876                 talloc_free(tmp_ctx);
1877                 return ret;
1878         }
1879
1880         invocation_id = samdb_ntds_invocation_id(ldb);
1881         if (!invocation_id) {
1882                 return LDB_ERR_OPERATIONS_ERROR;
1883         }
1884
1885         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1886         if (ret != LDB_SUCCESS) {
1887                 talloc_free(tmp_ctx);
1888                 return ret;
1889         }
1890
1891         el->values = NULL;
1892
1893         /* see if we are being asked to delete any links that
1894            don't exist or are already deleted */
1895         for (i=0; i<el->num_values; i++) {
1896                 struct parsed_dn *p = &dns[i];
1897                 struct parsed_dn *p2;
1898                 uint32_t rmd_flags;
1899
1900                 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1901                 if (!p2) {
1902                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1903                                                el->name, GUID_string(tmp_ctx, p->guid));
1904                         if (ldb_attr_cmp(el->name, "member") == 0) {
1905                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1906                         } else {
1907                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1908                         }
1909                 }
1910                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1911                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1912                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1913                                                el->name, GUID_string(tmp_ctx, p->guid));
1914                         if (ldb_attr_cmp(el->name, "member") == 0) {
1915                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1916                         } else {
1917                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1918                         }
1919                 }
1920         }
1921
1922         /* for each new value, see if it exists already with the same GUID
1923            if it is not already deleted and matches the delete list then delete it
1924         */
1925         for (i=0; i<old_el->num_values; i++) {
1926                 struct parsed_dn *p = &old_dns[i];
1927                 uint32_t rmd_flags;
1928
1929                 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1930                         continue;
1931                 }
1932
1933                 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1934                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1935
1936                 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1937                                            invocation_id, seq_num, seq_num, now, 0, true);
1938                 if (ret != LDB_SUCCESS) {
1939                         talloc_free(tmp_ctx);
1940                         return ret;
1941                 }
1942
1943                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1944                 if (ret != LDB_SUCCESS) {
1945                         talloc_free(tmp_ctx);
1946                         return ret;
1947                 }
1948         }
1949
1950         el->values = talloc_steal(msg->elements, old_el->values);
1951         el->num_values = old_el->num_values;
1952
1953         talloc_free(tmp_ctx);
1954
1955         /* we now tell the backend to replace all existing values
1956            with the one we have constructed */
1957         el->flags = LDB_FLAG_MOD_REPLACE;
1958
1959         return LDB_SUCCESS;
1960 }
1961
1962 /*
1963   handle replacing a linked attribute
1964  */
1965 static int replmd_modify_la_replace(struct ldb_module *module,
1966                                     const struct dsdb_schema *schema,
1967                                     struct ldb_message *msg,
1968                                     struct ldb_message_element *el,
1969                                     struct ldb_message_element *old_el,
1970                                     const struct dsdb_attribute *schema_attr,
1971                                     uint64_t seq_num,
1972                                     time_t t,
1973                                     struct GUID *msg_guid,
1974                                     struct ldb_request *parent)
1975 {
1976         unsigned int i;
1977         struct parsed_dn *dns, *old_dns;
1978         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1979         int ret;
1980         const struct GUID *invocation_id;
1981         struct ldb_context *ldb = ldb_module_get_ctx(module);
1982         struct ldb_val *new_values = NULL;
1983         unsigned int num_new_values = 0;
1984         unsigned int old_num_values = old_el?old_el->num_values:0;
1985         NTTIME now;
1986
1987         unix_to_nt_time(&now, t);
1988
1989         /* check if there is nothing to replace */
1990         if ((!old_el || old_el->num_values == 0) &&
1991             el->num_values == 0) {
1992                 return LDB_SUCCESS;
1993         }
1994
1995         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1996         if (ret != LDB_SUCCESS) {
1997                 talloc_free(tmp_ctx);
1998                 return ret;
1999         }
2000
2001         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2002         if (ret != LDB_SUCCESS) {
2003                 talloc_free(tmp_ctx);
2004                 return ret;
2005         }
2006
2007         invocation_id = samdb_ntds_invocation_id(ldb);
2008         if (!invocation_id) {
2009                 return LDB_ERR_OPERATIONS_ERROR;
2010         }
2011
2012         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2013         if (ret != LDB_SUCCESS) {
2014                 talloc_free(tmp_ctx);
2015                 return ret;
2016         }
2017
2018         /* mark all the old ones as deleted */
2019         for (i=0; i<old_num_values; i++) {
2020                 struct parsed_dn *old_p = &old_dns[i];
2021                 struct parsed_dn *p;
2022                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2023
2024                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2025
2026                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
2027                 if (ret != LDB_SUCCESS) {
2028                         talloc_free(tmp_ctx);
2029                         return ret;
2030                 }
2031
2032                 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
2033                 if (p) {
2034                         /* we don't delete it if we are re-adding it */
2035                         continue;
2036                 }
2037
2038                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2039                                            invocation_id, seq_num, seq_num, now, 0, true);
2040                 if (ret != LDB_SUCCESS) {
2041                         talloc_free(tmp_ctx);
2042                         return ret;
2043                 }
2044         }
2045
2046         /* for each new value, either update its meta-data, or add it
2047          * to old_el
2048         */
2049         for (i=0; i<el->num_values; i++) {
2050                 struct parsed_dn *p = &dns[i], *old_p;
2051
2052                 if (old_dns &&
2053                     (old_p = parsed_dn_find(old_dns,
2054                                             old_num_values, p->guid, NULL)) != NULL) {
2055                         /* update in place */
2056                         ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2057                                                    old_p->dsdb_dn, invocation_id,
2058                                                    seq_num, seq_num, now, 0, false);
2059                         if (ret != LDB_SUCCESS) {
2060                                 talloc_free(tmp_ctx);
2061                                 return ret;
2062                         }
2063                 } else {
2064                         /* add a new one */
2065                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2066                                                     num_new_values+1);
2067                         if (new_values == NULL) {
2068                                 ldb_module_oom(module);
2069                                 talloc_free(tmp_ctx);
2070                                 return LDB_ERR_OPERATIONS_ERROR;
2071                         }
2072                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2073                                                   invocation_id, seq_num, seq_num, now, 0, false);
2074                         if (ret != LDB_SUCCESS) {
2075                                 talloc_free(tmp_ctx);
2076                                 return ret;
2077                         }
2078                         num_new_values++;
2079                 }
2080
2081                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2082                 if (ret != LDB_SUCCESS) {
2083                         talloc_free(tmp_ctx);
2084                         return ret;
2085                 }
2086         }
2087
2088         /* add the new values to the end of old_el */
2089         if (num_new_values != 0) {
2090                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2091                                             struct ldb_val, old_num_values+num_new_values);
2092                 if (el->values == NULL) {
2093                         ldb_module_oom(module);
2094                         return LDB_ERR_OPERATIONS_ERROR;
2095                 }
2096                 memcpy(&el->values[old_num_values], &new_values[0],
2097                        sizeof(struct ldb_val)*num_new_values);
2098                 el->num_values = old_num_values + num_new_values;
2099                 talloc_steal(msg->elements, new_values);
2100         } else {
2101                 el->values = old_el->values;
2102                 el->num_values = old_el->num_values;
2103                 talloc_steal(msg->elements, el->values);
2104         }
2105
2106         talloc_free(tmp_ctx);
2107
2108         /* we now tell the backend to replace all existing values
2109            with the one we have constructed */
2110         el->flags = LDB_FLAG_MOD_REPLACE;
2111
2112         return LDB_SUCCESS;
2113 }
2114
2115
2116 /*
2117   handle linked attributes in modify requests
2118  */
2119 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2120                                                struct ldb_message *msg,
2121                                                uint64_t seq_num, time_t t,
2122                                                struct ldb_request *parent)
2123 {
2124         struct ldb_result *res;
2125         unsigned int i;
2126         int ret;
2127         struct ldb_context *ldb = ldb_module_get_ctx(module);
2128         struct ldb_message *old_msg;
2129
2130         const struct dsdb_schema *schema;
2131         struct GUID old_guid;
2132
2133         if (seq_num == 0) {
2134                 /* there the replmd_update_rpmd code has already
2135                  * checked and saw that there are no linked
2136                  * attributes */
2137                 return LDB_SUCCESS;
2138         }
2139
2140         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2141                 /* don't do anything special for linked attributes */
2142                 return LDB_SUCCESS;
2143         }
2144
2145         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2146                                     DSDB_FLAG_NEXT_MODULE |
2147                                     DSDB_SEARCH_SHOW_RECYCLED |
2148                                     DSDB_SEARCH_REVEAL_INTERNALS |
2149                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2150                                     parent);
2151         if (ret != LDB_SUCCESS) {
2152                 return ret;
2153         }
2154         schema = dsdb_get_schema(ldb, res);
2155         if (!schema) {
2156                 return LDB_ERR_OPERATIONS_ERROR;
2157         }
2158
2159         old_msg = res->msgs[0];
2160
2161         old_guid = samdb_result_guid(old_msg, "objectGUID");
2162
2163         for (i=0; i<msg->num_elements; i++) {
2164                 struct ldb_message_element *el = &msg->elements[i];
2165                 struct ldb_message_element *old_el, *new_el;
2166                 const struct dsdb_attribute *schema_attr
2167                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2168                 if (!schema_attr) {
2169                         ldb_asprintf_errstring(ldb,
2170                                                "%s: attribute %s is not a valid attribute in schema",
2171                                                __FUNCTION__, el->name);
2172                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2173                 }
2174                 if (schema_attr->linkID == 0) {
2175                         continue;
2176                 }
2177                 if ((schema_attr->linkID & 1) == 1) {
2178                         if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2179                                 continue;
2180                         }
2181                         /* Odd is for the target.  Illegal to modify */
2182                         ldb_asprintf_errstring(ldb,
2183                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2184                         return LDB_ERR_UNWILLING_TO_PERFORM;
2185                 }
2186                 old_el = ldb_msg_find_element(old_msg, el->name);
2187                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2188                 case LDB_FLAG_MOD_REPLACE:
2189                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2190                         break;
2191                 case LDB_FLAG_MOD_DELETE:
2192                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2193                         break;
2194                 case LDB_FLAG_MOD_ADD:
2195                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2196                         break;
2197                 default:
2198                         ldb_asprintf_errstring(ldb,
2199                                                "invalid flags 0x%x for %s linked attribute",
2200                                                el->flags, el->name);
2201                         return LDB_ERR_UNWILLING_TO_PERFORM;
2202                 }
2203                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2204                         ldb_asprintf_errstring(ldb,
2205                                                "Attribute %s is single valued but more than one value has been supplied",
2206                                                el->name);
2207                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2208                 } else {
2209                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2210                 }
2211
2212
2213
2214                 if (ret != LDB_SUCCESS) {
2215                         return ret;
2216                 }
2217                 if (old_el) {
2218                         ldb_msg_remove_attr(old_msg, el->name);
2219                 }
2220                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2221                 new_el->num_values = el->num_values;
2222                 new_el->values = talloc_steal(msg->elements, el->values);
2223
2224                 /* TODO: this relises a bit too heavily on the exact
2225                    behaviour of ldb_msg_find_element and
2226                    ldb_msg_remove_element */
2227                 old_el = ldb_msg_find_element(msg, el->name);
2228                 if (old_el != el) {
2229                         ldb_msg_remove_element(msg, old_el);
2230                         i--;
2231                 }
2232         }
2233
2234         talloc_free(res);
2235         return ret;
2236 }
2237
2238
2239
2240 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2241 {
2242         struct ldb_context *ldb;
2243         struct replmd_replicated_request *ac;
2244         struct ldb_request *down_req;
2245         struct ldb_message *msg;
2246         time_t t = time(NULL);
2247         int ret;
2248         bool is_urgent = false, rodc = false;
2249         unsigned int functional_level;
2250         const DATA_BLOB *guid_blob;
2251
2252         /* do not manipulate our control entries */
2253         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2254                 return ldb_next_request(module, req);
2255         }
2256
2257         ldb = ldb_module_get_ctx(module);
2258
2259         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2260
2261         guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2262         if ( guid_blob != NULL ) {
2263                 ldb_set_errstring(ldb,
2264                                   "replmd_modify: it's not allowed to change the objectGUID!");
2265                 return LDB_ERR_CONSTRAINT_VIOLATION;
2266         }
2267
2268         ac = replmd_ctx_init(module, req);
2269         if (ac == NULL) {
2270                 return ldb_module_oom(module);
2271         }
2272
2273         functional_level = dsdb_functional_level(ldb);
2274
2275         /* we have to copy the message as the caller might have it as a const */
2276         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2277         if (msg == NULL) {
2278                 ldb_oom(ldb);
2279                 talloc_free(ac);
2280                 return LDB_ERR_OPERATIONS_ERROR;
2281         }
2282
2283         ldb_msg_remove_attr(msg, "whenChanged");
2284         ldb_msg_remove_attr(msg, "uSNChanged");
2285
2286         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2287                                  msg, &ac->seq_num, t, &is_urgent, &rodc);
2288         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2289                 struct loadparm_context *lp_ctx;
2290                 char *referral;
2291
2292                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2293                                          struct loadparm_context);
2294
2295                 referral = talloc_asprintf(req,
2296                                            "ldap://%s/%s",
2297                                            lpcfg_dnsdomain(lp_ctx),
2298                                            ldb_dn_get_linearized(msg->dn));
2299                 ret = ldb_module_send_referral(req, referral);
2300                 talloc_free(ac);
2301                 return ret;
2302         }
2303
2304         if (ret != LDB_SUCCESS) {
2305                 talloc_free(ac);
2306                 return ret;
2307         }
2308
2309         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2310         if (ret != LDB_SUCCESS) {
2311                 talloc_free(ac);
2312                 return ret;
2313         }
2314
2315         /* TODO:
2316          * - replace the old object with the newly constructed one
2317          */
2318
2319         ac->is_urgent = is_urgent;
2320
2321         ret = ldb_build_mod_req(&down_req, ldb, ac,
2322                                 msg,
2323                                 req->controls,
2324                                 ac, replmd_op_callback,
2325                                 req);
2326         LDB_REQ_SET_LOCATION(down_req);
2327         if (ret != LDB_SUCCESS) {
2328                 talloc_free(ac);
2329                 return ret;
2330         }
2331
2332         /* current partition control is needed by "replmd_op_callback" */
2333         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2334                 ret = ldb_request_add_control(down_req,
2335                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2336                                               false, NULL);
2337                 if (ret != LDB_SUCCESS) {
2338                         talloc_free(ac);
2339                         return ret;
2340                 }
2341         }
2342
2343         /* If we are in functional level 2000, then
2344          * replmd_modify_handle_linked_attribs will have done
2345          * nothing */
2346         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2347                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2348                 if (ret != LDB_SUCCESS) {
2349                         talloc_free(ac);
2350                         return ret;
2351                 }
2352         }
2353
2354         talloc_steal(down_req, msg);
2355
2356         /* we only change whenChanged and uSNChanged if the seq_num
2357            has changed */
2358         if (ac->seq_num != 0) {
2359                 ret = add_time_element(msg, "whenChanged", t);
2360                 if (ret != LDB_SUCCESS) {
2361                         talloc_free(ac);
2362                         ldb_operr(ldb);
2363                         return ret;
2364                 }
2365
2366                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2367                 if (ret != LDB_SUCCESS) {
2368                         talloc_free(ac);
2369                         ldb_operr(ldb);
2370                         return ret;
2371                 }
2372         }
2373
2374         /* go on with the call chain */
2375         return ldb_next_request(module, down_req);
2376 }
2377
2378 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2379
2380 /*
2381   handle a rename request
2382
2383   On a rename we need to do an extra ldb_modify which sets the
2384   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2385  */
2386 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2387 {
2388         struct ldb_context *ldb;
2389         struct replmd_replicated_request *ac;
2390         int ret;
2391         struct ldb_request *down_req;
2392
2393         /* do not manipulate our control entries */
2394         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2395                 return ldb_next_request(module, req);
2396         }
2397
2398         ldb = ldb_module_get_ctx(module);
2399
2400         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2401
2402         ac = replmd_ctx_init(module, req);
2403         if (ac == NULL) {
2404                 return ldb_module_oom(module);
2405         }
2406
2407         ret = ldb_build_rename_req(&down_req, ldb, ac,
2408                                    ac->req->op.rename.olddn,
2409                                    ac->req->op.rename.newdn,
2410                                    ac->req->controls,
2411                                    ac, replmd_rename_callback,
2412                                    ac->req);
2413         LDB_REQ_SET_LOCATION(down_req);
2414         if (ret != LDB_SUCCESS) {
2415                 talloc_free(ac);
2416                 return ret;
2417         }
2418
2419         /* go on with the call chain */
2420         return ldb_next_request(module, down_req);
2421 }
2422
2423 /* After the rename is compleated, update the whenchanged etc */
2424 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2425 {
2426         struct ldb_context *ldb;
2427         struct replmd_replicated_request *ac;
2428         struct ldb_request *down_req;
2429         struct ldb_message *msg;
2430         const struct dsdb_attribute *rdn_attr;
2431         const char *rdn_name;
2432         const struct ldb_val *rdn_val;
2433         const char *attrs[5] = { NULL, };
2434         time_t t = time(NULL);
2435         int ret;
2436         bool is_urgent = false, rodc = false;
2437
2438         ac = talloc_get_type(req->context, struct replmd_replicated_request);
2439         ldb = ldb_module_get_ctx(ac->module);
2440
2441         if (ares->error != LDB_SUCCESS) {
2442                 return ldb_module_done(ac->req, ares->controls,
2443                                         ares->response, ares->error);
2444         }
2445
2446         if (ares->type != LDB_REPLY_DONE) {
2447                 ldb_set_errstring(ldb,
2448                                   "invalid ldb_reply_type in callback");
2449                 talloc_free(ares);
2450                 return ldb_module_done(ac->req, NULL, NULL,
2451                                         LDB_ERR_OPERATIONS_ERROR);
2452         }
2453
2454         /* TODO:
2455          * - replace the old object with the newly constructed one
2456          */
2457
2458         msg = ldb_msg_new(ac);
2459         if (msg == NULL) {
2460                 ldb_oom(ldb);
2461                 return LDB_ERR_OPERATIONS_ERROR;
2462         }
2463
2464         msg->dn = ac->req->op.rename.newdn;
2465
2466         rdn_name = ldb_dn_get_rdn_name(msg->dn);
2467         if (rdn_name == NULL) {
2468                 talloc_free(ares);
2469                 return ldb_module_done(ac->req, NULL, NULL,
2470                                        ldb_operr(ldb));
2471         }
2472
2473         /* normalize the rdn attribute name */
2474         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2475         if (rdn_attr == NULL) {
2476                 talloc_free(ares);
2477                 return ldb_module_done(ac->req, NULL, NULL,
2478                                        ldb_operr(ldb));
2479         }
2480         rdn_name = rdn_attr->lDAPDisplayName;
2481
2482         rdn_val = ldb_dn_get_rdn_val(msg->dn);
2483         if (rdn_val == NULL) {
2484                 talloc_free(ares);
2485                 return ldb_module_done(ac->req, NULL, NULL,
2486                                        ldb_operr(ldb));
2487         }
2488
2489         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2490                 talloc_free(ares);
2491                 return ldb_module_done(ac->req, NULL, NULL,
2492                                        ldb_oom(ldb));
2493         }
2494         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2495                 talloc_free(ares);
2496                 return ldb_module_done(ac->req, NULL, NULL,
2497                                        ldb_oom(ldb));
2498         }
2499         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2500                 talloc_free(ares);
2501                 return ldb_module_done(ac->req, NULL, NULL,
2502                                        ldb_oom(ldb));
2503         }
2504         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2505                 talloc_free(ares);
2506                 return ldb_module_done(ac->req, NULL, NULL,
2507                                        ldb_oom(ldb));
2508         }
2509
2510         /*
2511          * here we let replmd_update_rpmd() only search for
2512          * the existing "replPropertyMetaData" and rdn_name attributes.
2513          *
2514          * We do not want the existing "name" attribute as
2515          * the "name" attribute needs to get the version
2516          * updated on rename even if the rdn value hasn't changed.
2517          *
2518          * This is the diff of the meta data, for a moved user
2519          * on a w2k8r2 server:
2520          *
2521          * # record 1
2522          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2523          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2524          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
2525          *         version                  : 0x00000001 (1)
2526          *         reserved                 : 0x00000000 (0)
2527          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
2528          *                      local_usn                : 0x00000000000037a5 (14245)
2529          *                 array: struct replPropertyMetaData1
2530          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
2531          * -                    version                  : 0x00000001 (1)
2532          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
2533          * +                    version                  : 0x00000002 (2)
2534          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
2535          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2536          * -                    originating_usn          : 0x00000000000037a5 (14245)
2537          * -                    local_usn                : 0x00000000000037a5 (14245)
2538          * +                    originating_usn          : 0x0000000000003834 (14388)
2539          * +                    local_usn                : 0x0000000000003834 (14388)
2540          *                 array: struct replPropertyMetaData1
2541          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
2542          *                      version                  : 0x00000004 (4)
2543          */
2544         attrs[0] = "replPropertyMetaData";
2545         attrs[1] = "objectClass";
2546         attrs[2] = "instanceType";
2547         attrs[3] = rdn_name;
2548         attrs[4] = NULL;
2549
2550         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2551                                  msg, &ac->seq_num, t, &is_urgent, &rodc);
2552         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2553                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2554                 struct loadparm_context *lp_ctx;
2555                 char *referral;
2556
2557                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2558                                          struct loadparm_context);
2559
2560                 referral = talloc_asprintf(req,
2561                                            "ldap://%s/%s",
2562                                            lpcfg_dnsdomain(lp_ctx),
2563                                            ldb_dn_get_linearized(olddn));
2564                 ret = ldb_module_send_referral(req, referral);
2565                 talloc_free(ares);
2566                 return ldb_module_done(req, NULL, NULL, ret);
2567         }
2568
2569         if (ret != LDB_SUCCESS) {
2570                 talloc_free(ares);
2571                 return ldb_module_done(ac->req, NULL, NULL, ret);
2572         }
2573
2574         if (ac->seq_num == 0) {
2575                 talloc_free(ares);
2576                 return ldb_module_done(ac->req, NULL, NULL,
2577                                        ldb_error(ldb, ret,
2578                                         "internal error seq_num == 0"));
2579         }
2580         ac->is_urgent = is_urgent;
2581
2582         ret = ldb_build_mod_req(&down_req, ldb, ac,
2583                                 msg,
2584                                 req->controls,
2585                                 ac, replmd_op_callback,
2586                                 req);
2587         LDB_REQ_SET_LOCATION(down_req);
2588         if (ret != LDB_SUCCESS) {
2589                 talloc_free(ac);
2590                 return ret;
2591         }
2592
2593         /* current partition control is needed by "replmd_op_callback" */
2594         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2595                 ret = ldb_request_add_control(down_req,
2596                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2597                                               false, NULL);
2598                 if (ret != LDB_SUCCESS) {
2599                         talloc_free(ac);
2600                         return ret;
2601                 }
2602         }
2603
2604         talloc_steal(down_req, msg);
2605
2606         ret = add_time_element(msg, "whenChanged", t);
2607         if (ret != LDB_SUCCESS) {
2608                 talloc_free(ac);
2609                 ldb_operr(ldb);
2610                 return ret;
2611         }
2612
2613         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2614         if (ret != LDB_SUCCESS) {
2615                 talloc_free(ac);
2616                 ldb_operr(ldb);
2617                 return ret;
2618         }
2619
2620         /* go on with the call chain - do the modify after the rename */
2621         return ldb_next_request(ac->module, down_req);
2622 }
2623
2624 /*
2625    remove links from objects that point at this object when an object
2626    is deleted
2627  */
2628 static int replmd_delete_remove_link(struct ldb_module *module,
2629                                      const struct dsdb_schema *schema,
2630                                      struct ldb_dn *dn,
2631                                      struct ldb_message_element *el,
2632                                      const struct dsdb_attribute *sa,
2633                                      struct ldb_request *parent)
2634 {
2635         unsigned int i;
2636         TALLOC_CTX *tmp_ctx = talloc_new(module);
2637         struct ldb_context *ldb = ldb_module_get_ctx(module);
2638
2639         for (i=0; i<el->num_values; i++) {
2640                 struct dsdb_dn *dsdb_dn;
2641                 NTSTATUS status;
2642                 int ret;
2643                 struct GUID guid2;
2644                 struct ldb_message *msg;
2645                 const struct dsdb_attribute *target_attr;
2646                 struct ldb_message_element *el2;
2647                 struct ldb_val dn_val;
2648
2649                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2650                         continue;
2651                 }
2652
2653                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2654                 if (!dsdb_dn) {
2655                         talloc_free(tmp_ctx);
2656                         return LDB_ERR_OPERATIONS_ERROR;
2657                 }
2658
2659                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2660                 if (!NT_STATUS_IS_OK(status)) {
2661                         talloc_free(tmp_ctx);
2662                         return LDB_ERR_OPERATIONS_ERROR;
2663                 }
2664
2665                 /* remove the link */
2666                 msg = ldb_msg_new(tmp_ctx);
2667                 if (!msg) {
2668                         ldb_module_oom(module);
2669                         talloc_free(tmp_ctx);
2670                         return LDB_ERR_OPERATIONS_ERROR;
2671                 }
2672
2673
2674                 msg->dn = dsdb_dn->dn;
2675
2676                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2677                 if (target_attr == NULL) {
2678                         continue;
2679                 }
2680
2681                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2682                 if (ret != LDB_SUCCESS) {
2683                         ldb_module_oom(module);
2684                         talloc_free(tmp_ctx);
2685                         return LDB_ERR_OPERATIONS_ERROR;
2686                 }
2687                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2688                 el2->values = &dn_val;
2689                 el2->num_values = 1;
2690
2691                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2692                 if (ret != LDB_SUCCESS) {
2693                         talloc_free(tmp_ctx);
2694                         return ret;
2695                 }
2696         }
2697         talloc_free(tmp_ctx);
2698         return LDB_SUCCESS;
2699 }
2700
2701
2702 /*
2703   handle update of replication meta data for deletion of objects
2704
2705   This also handles the mapping of delete to a rename operation
2706   to allow deletes to be replicated.
2707  */
2708 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2709 {
2710         int ret = LDB_ERR_OTHER;
2711         bool retb, disallow_move_on_delete;
2712         struct ldb_dn *old_dn, *new_dn;
2713         const char *rdn_name;
2714         const struct ldb_val *rdn_value, *new_rdn_value;
2715         struct GUID guid;
2716         struct ldb_context *ldb = ldb_module_get_ctx(module);
2717         const struct dsdb_schema *schema;
2718         struct ldb_message *msg, *old_msg;
2719         struct ldb_message_element *el;
2720         TALLOC_CTX *tmp_ctx;
2721         struct ldb_result *res, *parent_res;
2722         const char *preserved_attrs[] = {
2723                 /* yes, this really is a hard coded list. See MS-ADTS
2724                    section 3.1.1.5.5.1.1 */
2725                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2726                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2727                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2728                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2729                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2730                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2731                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2732                 "whenChanged", NULL};
2733         unsigned int i, el_count = 0;
2734         enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2735                                                 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2736         enum deletion_state deletion_state, next_deletion_state;
2737         bool enabled;
2738         int functional_level;
2739
2740         if (ldb_dn_is_special(req->op.del.dn)) {
2741                 return ldb_next_request(module, req);
2742         }
2743
2744         tmp_ctx = talloc_new(ldb);
2745         if (!tmp_ctx) {
2746                 ldb_oom(ldb);
2747                 return LDB_ERR_OPERATIONS_ERROR;
2748         }
2749
2750         schema = dsdb_get_schema(ldb, tmp_ctx);
2751         if (!schema) {
2752                 return LDB_ERR_OPERATIONS_ERROR;
2753         }
2754
2755         functional_level = dsdb_functional_level(ldb);
2756
2757         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2758
2759         /* we need the complete msg off disk, so we can work out which
2760            attributes need to be removed */
2761         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2762                                     DSDB_FLAG_NEXT_MODULE |
2763                                     DSDB_SEARCH_SHOW_RECYCLED |
2764                                     DSDB_SEARCH_REVEAL_INTERNALS |
2765                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2766         if (ret != LDB_SUCCESS) {
2767                 talloc_free(tmp_ctx);
2768                 return ret;
2769         }
2770         old_msg = res->msgs[0];
2771
2772
2773         ret = dsdb_recyclebin_enabled(module, &enabled);
2774         if (ret != LDB_SUCCESS) {
2775                 talloc_free(tmp_ctx);
2776                 return ret;
2777         }
2778
2779         if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2780                 if (!enabled) {
2781                         deletion_state = OBJECT_TOMBSTONE;
2782                         next_deletion_state = OBJECT_REMOVED;
2783                 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2784                         deletion_state = OBJECT_RECYCLED;
2785                         next_deletion_state = OBJECT_REMOVED;
2786                 } else {
2787                         deletion_state = OBJECT_DELETED;
2788                         next_deletion_state = OBJECT_RECYCLED;
2789                 }
2790         } else {
2791                 deletion_state = OBJECT_NOT_DELETED;
2792                 if (enabled) {
2793                         next_deletion_state = OBJECT_DELETED;
2794                 } else {
2795                         next_deletion_state = OBJECT_TOMBSTONE;
2796                 }
2797         }
2798
2799         if (next_deletion_state == OBJECT_REMOVED) {
2800                 struct auth_session_info *session_info =
2801                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2802                 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2803                         ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2804                                         ldb_dn_get_linearized(old_msg->dn));
2805                         return LDB_ERR_UNWILLING_TO_PERFORM;
2806                 }
2807
2808                 /* it is already deleted - really remove it this time */
2809                 talloc_free(tmp_ctx);
2810                 return ldb_next_request(module, req);
2811         }
2812
2813         rdn_name = ldb_dn_get_rdn_name(old_dn);
2814         rdn_value = ldb_dn_get_rdn_val(old_dn);
2815         if ((rdn_name == NULL) || (rdn_value == NULL)) {
2816                 talloc_free(tmp_ctx);
2817                 return ldb_operr(ldb);
2818         }
2819
2820         msg = ldb_msg_new(tmp_ctx);
2821         if (msg == NULL) {
2822                 ldb_module_oom(module);
2823                 talloc_free(tmp_ctx);
2824                 return LDB_ERR_OPERATIONS_ERROR;
2825         }
2826
2827         msg->dn = old_dn;
2828
2829         if (deletion_state == OBJECT_NOT_DELETED){
2830                 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2831                 disallow_move_on_delete =
2832                         (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2833                                 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2834
2835                 /* work out where we will be renaming this object to */
2836                 if (!disallow_move_on_delete) {
2837                         ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2838                                                           &new_dn);
2839                         if (ret != LDB_SUCCESS) {
2840                                 /* this is probably an attempted delete on a partition
2841                                  * that doesn't allow delete operations, such as the
2842                                  * schema partition */
2843                                 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2844                                                            ldb_dn_get_linearized(old_dn));
2845                                 talloc_free(tmp_ctx);
2846                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2847                         }
2848                 } else {
2849                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2850                         if (new_dn == NULL) {
2851                                 ldb_module_oom(module);
2852                                 talloc_free(tmp_ctx);
2853                                 return LDB_ERR_OPERATIONS_ERROR;
2854                         }
2855                 }
2856
2857                 /* get the objects GUID from the search we just did */
2858                 guid = samdb_result_guid(old_msg, "objectGUID");
2859
2860                 /* Add a formatted child */
2861                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2862                                                 rdn_name,
2863                                                 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2864                                                 GUID_string(tmp_ctx, &guid));
2865                 if (!retb) {
2866                         DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2867                                         ldb_dn_get_linearized(new_dn)));
2868                         talloc_free(tmp_ctx);
2869                         return LDB_ERR_OPERATIONS_ERROR;
2870                 }
2871
2872                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2873                 if (ret != LDB_SUCCESS) {
2874                         DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2875                         ldb_module_oom(module);
2876                         talloc_free(tmp_ctx);
2877                         return ret;
2878                 }
2879                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2880         }
2881
2882         /*
2883           now we need to modify the object in the following ways:
2884
2885           - add isDeleted=TRUE
2886           - update rDN and name, with new rDN
2887           - remove linked attributes
2888           - remove objectCategory and sAMAccountType
2889           - remove attribs not on the preserved list
2890              - preserved if in above list, or is rDN
2891           - remove all linked attribs from this object
2892           - remove all links from other objects to this object
2893           - add lastKnownParent
2894           - update replPropertyMetaData?
2895
2896           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2897          */
2898
2899         /* we need the storage form of the parent GUID */
2900         ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2901                                     ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2902                                     DSDB_FLAG_NEXT_MODULE |
2903                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2904                                     DSDB_SEARCH_REVEAL_INTERNALS|
2905                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2906         if (ret != LDB_SUCCESS) {
2907                 talloc_free(tmp_ctx);
2908                 return ret;
2909         }
2910
2911         if (deletion_state == OBJECT_NOT_DELETED){
2912                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2913                                                    ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2914                 if (ret != LDB_SUCCESS) {
2915                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2916                         ldb_module_oom(module);
2917                         talloc_free(tmp_ctx);
2918                         return ret;
2919                 }
2920                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2921         }
2922
2923         switch (next_deletion_state){
2924
2925         case OBJECT_DELETED:
2926
2927                 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2928                 if (ret != LDB_SUCCESS) {
2929                         DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2930                         ldb_module_oom(module);
2931                         talloc_free(tmp_ctx);
2932                         return ret;
2933                 }
2934                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2935
2936                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
2937                 if (ret != LDB_SUCCESS) {
2938                         talloc_free(tmp_ctx);
2939                         ldb_module_oom(module);
2940                         return ret;
2941                 }
2942
2943                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
2944                 if (ret != LDB_SUCCESS) {
2945                         talloc_free(tmp_ctx);
2946                         ldb_module_oom(module);
2947                         return ret;
2948                 }
2949
2950                 break;
2951
2952         case OBJECT_RECYCLED:
2953         case OBJECT_TOMBSTONE:
2954
2955                 /* we also mark it as recycled, meaning this object can't be
2956                    recovered (we are stripping its attributes) */
2957                 if (functional_level >= DS_DOMAIN_FUNCTION_2008_R2) {
2958                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2959                         if (ret != LDB_SUCCESS) {
2960                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2961                                 ldb_module_oom(module);
2962                                 talloc_free(tmp_ctx);
2963                                 return ret;
2964                         }
2965                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2966                 }
2967
2968                 /* work out which of the old attributes we will be removing */
2969                 for (i=0; i<old_msg->num_elements; i++) {
2970                         const struct dsdb_attribute *sa;
2971                         el = &old_msg->elements[i];
2972                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2973                         if (!sa) {
2974                                 talloc_free(tmp_ctx);
2975                                 return LDB_ERR_OPERATIONS_ERROR;
2976                         }
2977                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2978                                 /* don't remove the rDN */
2979                                 continue;
2980                         }
2981                         if (sa->linkID && (sa->linkID & 1)) {
2982                                 /*
2983                                   we have a backlink in this object
2984                                   that needs to be removed. We're not
2985                                   allowed to remove it directly
2986                                   however, so we instead setup a
2987                                   modify to delete the corresponding
2988                                   forward link
2989                                  */
2990                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
2991                                 if (ret != LDB_SUCCESS) {
2992                                         talloc_free(tmp_ctx);
2993                                         return LDB_ERR_OPERATIONS_ERROR;
2994                                 }
2995                                 /* now we continue, which means we
2996                                    won't remove this backlink
2997                                    directly
2998                                 */
2999                                 continue;
3000                         }
3001                         if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
3002                                 continue;
3003                         }
3004                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3005                         if (ret != LDB_SUCCESS) {
3006                                 talloc_free(tmp_ctx);
3007                                 ldb_module_oom(module);
3008                                 return ret;
3009                         }
3010                 }
3011                 break;
3012
3013         default:
3014                 break;
3015         }
3016
3017         if (deletion_state == OBJECT_NOT_DELETED) {
3018                 const struct dsdb_attribute *sa;
3019
3020                 /* work out what the new rdn value is, for updating the
3021                    rDN and name fields */
3022                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3023                 if (new_rdn_value == NULL) {
3024                         talloc_free(tmp_ctx);
3025                         return ldb_operr(ldb);
3026                 }
3027
3028                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3029                 if (!sa) {
3030                         talloc_free(tmp_ctx);
3031                         return LDB_ERR_OPERATIONS_ERROR;
3032                 }
3033
3034                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3035                                         &el);
3036                 if (ret != LDB_SUCCESS) {
3037                         talloc_free(tmp_ctx);
3038                         return ret;
3039                 }
3040                 el->flags = LDB_FLAG_MOD_REPLACE;
3041
3042                 el = ldb_msg_find_element(old_msg, "name");
3043                 if (el) {
3044                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3045                         if (ret != LDB_SUCCESS) {
3046                                 talloc_free(tmp_ctx);
3047                                 return ret;
3048                         }
3049                         el->flags = LDB_FLAG_MOD_REPLACE;
3050                 }
3051         }
3052
3053         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3054         if (ret != LDB_SUCCESS) {
3055                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3056                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3057                 talloc_free(tmp_ctx);
3058                 return ret;
3059         }
3060
3061         if (deletion_state == OBJECT_NOT_DELETED) {
3062                 /* now rename onto the new DN */
3063                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3064                 if (ret != LDB_SUCCESS){
3065                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3066                                  ldb_dn_get_linearized(old_dn),
3067                                  ldb_dn_get_linearized(new_dn),
3068                                  ldb_errstring(ldb)));
3069                         talloc_free(tmp_ctx);
3070                         return ret;
3071                 }
3072         }
3073
3074         talloc_free(tmp_ctx);
3075
3076         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3077 }
3078
3079
3080
3081 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3082 {
3083         return ret;
3084 }
3085
3086 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3087 {
3088         int ret = LDB_ERR_OTHER;
3089         /* TODO: do some error mapping */
3090         return ret;
3091 }
3092
3093
3094 static struct replPropertyMetaData1 *
3095 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3096                                         enum drsuapi_DsAttributeId attid)
3097 {
3098         uint32_t i;
3099         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3100
3101         for (i = 0; i < rpmd_ctr->count; i++) {
3102                 if (rpmd_ctr->array[i].attid == attid) {
3103                         return &rpmd_ctr->array[i];
3104                 }
3105         }
3106         return NULL;
3107 }
3108
3109
3110 /*
3111    return true if an update is newer than an existing entry
3112    see section 5.11 of MS-ADTS
3113 */
3114 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3115                                    const struct GUID *update_invocation_id,
3116                                    uint32_t current_version,
3117                                    uint32_t update_version,
3118                                    NTTIME current_change_time,
3119                                    NTTIME update_change_time)
3120 {
3121         if (update_version != current_version) {
3122                 return update_version > current_version;
3123         }
3124         if (update_change_time != current_change_time) {
3125                 return update_change_time > current_change_time;
3126         }
3127         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3128 }
3129
3130 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3131                                                   struct replPropertyMetaData1 *new_m)
3132 {
3133         return replmd_update_is_newer(&cur_m->originating_invocation_id,
3134                                       &new_m->originating_invocation_id,
3135                                       cur_m->version,
3136                                       new_m->version,
3137                                       cur_m->originating_change_time,
3138                                       new_m->originating_change_time);
3139 }
3140
3141
3142 /*
3143   form a conflict DN
3144  */
3145 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3146 {
3147         const struct ldb_val *rdn_val;
3148         const char *rdn_name;
3149         struct ldb_dn *new_dn;
3150
3151         rdn_val = ldb_dn_get_rdn_val(dn);
3152         rdn_name = ldb_dn_get_rdn_name(dn);
3153         if (!rdn_val || !rdn_name) {
3154                 return NULL;
3155         }
3156
3157         new_dn = ldb_dn_copy(mem_ctx, dn);
3158         if (!new_dn) {
3159                 return NULL;
3160         }
3161
3162         if (!ldb_dn_remove_child_components(new_dn, 1)) {
3163                 return NULL;
3164         }
3165
3166         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3167                                   rdn_name,
3168                                   ldb_dn_escape_value(new_dn, *rdn_val),
3169                                   GUID_string(new_dn, guid))) {
3170                 return NULL;
3171         }
3172
3173         return new_dn;
3174 }
3175
3176
3177 /*
3178   perform a modify operation which sets the rDN and name attributes to
3179   their current values. This has the effect of changing these
3180   attributes to have been last updated by the current DC. This is
3181   needed to ensure that renames performed as part of conflict
3182   resolution are propogated to other DCs
3183  */
3184 static int replmd_name_modify(struct replmd_replicated_request *ar,
3185                               struct ldb_request *req, struct ldb_dn *dn)
3186 {
3187         struct ldb_message *msg;
3188         const char *rdn_name;
3189         const struct ldb_val *rdn_val;
3190         const struct dsdb_attribute *rdn_attr;
3191         int ret;
3192
3193         msg = ldb_msg_new(req);
3194         if (msg == NULL) {
3195                 goto failed;
3196         }
3197         msg->dn = dn;
3198
3199         rdn_name = ldb_dn_get_rdn_name(dn);
3200         if (rdn_name == NULL) {
3201                 goto failed;
3202         }
3203
3204         /* normalize the rdn attribute name */
3205         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3206         if (rdn_attr == NULL) {
3207                 goto failed;
3208         }
3209         rdn_name = rdn_attr->lDAPDisplayName;
3210
3211         rdn_val = ldb_dn_get_rdn_val(dn);
3212         if (rdn_val == NULL) {
3213                 goto failed;
3214         }
3215
3216         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3217                 goto failed;
3218         }
3219         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3220                 goto failed;
3221         }
3222         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3223                 goto failed;
3224         }
3225         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3226                 goto failed;
3227         }
3228
3229         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3230         if (ret != LDB_SUCCESS) {
3231                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3232                          ldb_dn_get_linearized(dn),
3233                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3234                 return ret;
3235         }
3236
3237         talloc_free(msg);
3238
3239         return LDB_SUCCESS;
3240
3241 failed:
3242         talloc_free(msg);
3243         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3244                  ldb_dn_get_linearized(dn)));
3245         return LDB_ERR_OPERATIONS_ERROR;
3246 }
3247
3248
3249 /*
3250   callback for conflict DN handling where we have renamed the incoming
3251   record. After renaming it, we need to ensure the change of name and
3252   rDN for the incoming record is seen as an originating update by this DC.
3253  */
3254 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3255 {
3256         struct replmd_replicated_request *ar =
3257                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3258         int ret;
3259
3260         if (ares->error != LDB_SUCCESS) {
3261                 /* call the normal callback for everything except success */
3262                 return replmd_op_callback(req, ares);
3263         }
3264
3265         /* perform a modify of the rDN and name of the record */
3266         ret = replmd_name_modify(ar, req, req->op.add.message->dn);
3267         if (ret != LDB_SUCCESS) {
3268                 ares->error = ret;
3269                 return replmd_op_callback(req, ares);
3270         }
3271
3272         return replmd_op_callback(req, ares);
3273 }
3274
3275 /*
3276   callback for replmd_replicated_apply_add()
3277   This copes with the creation of conflict records in the case where
3278   the DN exists, but with a different objectGUID
3279  */
3280 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3281 {
3282         struct ldb_dn *conflict_dn;
3283         struct replmd_replicated_request *ar =
3284                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3285         struct ldb_result *res;
3286         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3287         int ret;
3288         const struct ldb_val *rmd_value, *omd_value;
3289         struct replPropertyMetaDataBlob omd, rmd;
3290         enum ndr_err_code ndr_err;
3291         bool rename_incoming_record, rodc;
3292         struct replPropertyMetaData1 *rmd_name, *omd_name;
3293
3294         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3295                 /* call the normal callback for everything except
3296                    conflicts */
3297                 return replmd_op_callback(req, ares);
3298         }
3299
3300         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
3301         if (ret != LDB_SUCCESS) {
3302                 return ret;
3303         }
3304         /*
3305          * we have a conflict, and need to decide if we will keep the
3306          * new record or the old record
3307          */
3308         conflict_dn = req->op.add.message->dn;
3309
3310         if (rodc) {
3311                 /*
3312                  * We are on an RODC, or were a GC for this
3313                  * partition, so we have to fail this until
3314                  * someone who owns the partition sorts it
3315                  * out 
3316                  */
3317                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), 
3318                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
3319                                        " - We must fail the operation until a master for this partition resolves the conflict",
3320                                        ldb_dn_get_linearized(conflict_dn));
3321                 goto failed;
3322         }
3323
3324         /*
3325          * we have a conflict, and need to decide if we will keep the
3326          * new record or the old record
3327          */
3328         conflict_dn = req->op.add.message->dn;
3329
3330         /*
3331          * first we need the replPropertyMetaData attribute from the
3332          * old record
3333          */
3334         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3335                                     attrs,
3336                                     DSDB_FLAG_NEXT_MODULE |
3337                                     DSDB_SEARCH_SHOW_DELETED |
3338                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3339         if (ret != LDB_SUCCESS) {
3340                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3341                          ldb_dn_get_linearized(conflict_dn)));
3342                 goto failed;
3343         }
3344
3345         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3346         if (omd_value == NULL) {
3347                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3348                          ldb_dn_get_linearized(conflict_dn)));
3349                 goto failed;
3350         }
3351
3352         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3353                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3354         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3355                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3356                          ldb_dn_get_linearized(conflict_dn)));
3357                 goto failed;
3358         }
3359
3360         /*
3361          * and the replPropertyMetaData attribute from the
3362          * new record
3363          */
3364         rmd_value = ldb_msg_find_ldb_val(req->op.add.message, "replPropertyMetaData");
3365         if (rmd_value == NULL) {
3366                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for new record '%s'\n",
3367                          ldb_dn_get_linearized(conflict_dn)));
3368                 goto failed;
3369         }
3370
3371         ndr_err = ndr_pull_struct_blob(rmd_value, req, &rmd,
3372                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3373         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3374                 DEBUG(0,(__location__ ": Failed to parse new replPropertyMetaData for %s\n",
3375                          ldb_dn_get_linearized(conflict_dn)));
3376                 goto failed;
3377         }
3378
3379         /* we decide which is newer based on the RPMD on the name
3380            attribute.  See [MS-DRSR] ResolveNameConflict */
3381         rmd_name = replmd_replPropertyMetaData1_find_attid(&rmd, DRSUAPI_ATTID_name);
3382         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3383         if (!rmd_name || !omd_name) {
3384                 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3385                          ldb_dn_get_linearized(conflict_dn)));
3386                 goto failed;
3387         }
3388
3389         rename_incoming_record = !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3390
3391         if (rename_incoming_record) {
3392                 struct GUID guid;
3393                 struct ldb_dn *new_dn;
3394                 struct ldb_message *new_msg;
3395
3396                 guid = samdb_result_guid(req->op.add.message, "objectGUID");
3397                 if (GUID_all_zero(&guid)) {
3398                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3399                                  ldb_dn_get_linearized(conflict_dn)));
3400                         goto failed;
3401                 }
3402                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3403                 if (new_dn == NULL) {
3404                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3405                                  ldb_dn_get_linearized(conflict_dn)));
3406                         goto failed;
3407                 }
3408
3409                 DEBUG(1,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3410                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3411
3412                 /* re-submit the request, but with a different
3413                    callback, so we don't loop forever. */
3414                 new_msg = ldb_msg_copy_shallow(req, req->op.add.message);
3415                 if (!new_msg) {
3416                         goto failed;
3417                         DEBUG(0,(__location__ ": Failed to copy conflict DN message for %s\n",
3418                                  ldb_dn_get_linearized(conflict_dn)));
3419                 }
3420                 new_msg->dn = new_dn;
3421                 req->op.add.message = new_msg;
3422                 req->callback = replmd_op_name_modify_callback;
3423
3424                 return ldb_next_request(ar->module, req);
3425         } else {
3426                 /* we are renaming the existing record */
3427                 struct GUID guid;
3428                 struct ldb_dn *new_dn;
3429
3430                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3431                 if (GUID_all_zero(&guid)) {
3432                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3433                                  ldb_dn_get_linearized(conflict_dn)));
3434                         goto failed;
3435                 }
3436
3437                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3438                 if (new_dn == NULL) {
3439                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3440                                  ldb_dn_get_linearized(conflict_dn)));
3441                         goto failed;
3442                 }
3443
3444                 DEBUG(1,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
3445                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3446
3447                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3448                                          DSDB_FLAG_OWN_MODULE, req);
3449                 if (ret != LDB_SUCCESS) {
3450                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3451                                  ldb_dn_get_linearized(conflict_dn),
3452                                  ldb_dn_get_linearized(new_dn),
3453                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3454                         goto failed;
3455                 }
3456
3457                 /*
3458                  * now we need to ensure that the rename is seen as an
3459                  * originating update. We do that with a modify.
3460                  */
3461                 ret = replmd_name_modify(ar, req, new_dn);
3462                 if (ret != LDB_SUCCESS) {
3463                         goto failed;
3464                 }
3465
3466                 req->callback = replmd_op_callback;
3467
3468                 return ldb_next_request(ar->module, req);
3469         }
3470
3471 failed:
3472         /* on failure do the original callback. This means replication
3473          * will stop with an error, but there is not much else we can
3474          * do
3475          */
3476         return replmd_op_callback(req, ares);
3477 }
3478
3479 /*
3480   this is called when a new object comes in over DRS
3481  */
3482 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3483 {
3484         struct ldb_context *ldb;
3485         struct ldb_request *change_req;
3486         enum ndr_err_code ndr_err;
3487         struct ldb_message *msg;
3488         struct replPropertyMetaDataBlob *md;
3489         struct ldb_val md_value;
3490         unsigned int i;
3491         int ret;
3492
3493         /*
3494          * TODO: check if the parent object exist
3495          */
3496
3497         /*
3498          * TODO: handle the conflict case where an object with the
3499          *       same name exist
3500          */
3501
3502         ldb = ldb_module_get_ctx(ar->module);
3503         msg = ar->objs->objects[ar->index_current].msg;
3504         md = ar->objs->objects[ar->index_current].meta_data;
3505
3506         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3507         if (ret != LDB_SUCCESS) {
3508                 return replmd_replicated_request_error(ar, ret);
3509         }
3510
3511         ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
3512         if (ret != LDB_SUCCESS) {
3513                 return replmd_replicated_request_error(ar, ret);
3514         }
3515
3516         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3517         if (ret != LDB_SUCCESS) {
3518                 return replmd_replicated_request_error(ar, ret);
3519         }
3520
3521         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
3522         if (ret != LDB_SUCCESS) {
3523                 return replmd_replicated_request_error(ar, ret);
3524         }
3525
3526         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3527         if (ret != LDB_SUCCESS) {
3528                 return replmd_replicated_request_error(ar, ret);
3529         }
3530
3531         /* remove any message elements that have zero values */
3532         for (i=0; i<msg->num_elements; i++) {
3533                 struct ldb_message_element *el = &msg->elements[i];
3534
3535                 if (el->num_values == 0) {
3536                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
3537                                  el->name));
3538                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
3539                         msg->num_elements--;
3540                         i--;
3541                         continue;
3542                 }
3543         }
3544
3545         /*
3546          * the meta data array is already sorted by the caller
3547          */
3548         for (i=0; i < md->ctr.ctr1.count; i++) {
3549                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3550         }
3551         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3552                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3553         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3554                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3555                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3556         }
3557         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3558         if (ret != LDB_SUCCESS) {
3559                 return replmd_replicated_request_error(ar, ret);
3560         }
3561
3562         replmd_ldb_message_sort(msg, ar->schema);
3563
3564         if (DEBUGLVL(4)) {
3565                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3566                 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3567                 talloc_free(s);
3568         }
3569
3570         ret = ldb_build_add_req(&change_req,
3571                                 ldb,
3572                                 ar,
3573                                 msg,
3574                                 ar->controls,
3575                                 ar,
3576                                 replmd_op_add_callback,
3577                                 ar->req);
3578         LDB_REQ_SET_LOCATION(change_req);
3579         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3580
3581         /* current partition control needed by "repmd_op_callback" */
3582         ret = ldb_request_add_control(change_req,
3583                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3584                                       false, NULL);
3585         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3586
3587         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
3588                 /* this tells the partition module to make it a
3589                    partial replica if creating an NC */
3590                 ret = ldb_request_add_control(change_req,
3591                                               DSDB_CONTROL_PARTIAL_REPLICA,
3592                                               false, NULL);
3593                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3594         }
3595
3596         return ldb_next_request(ar->module, change_req);
3597 }
3598
3599 /*
3600   handle renames that come in over DRS replication
3601  */
3602 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
3603                                            struct ldb_message *msg,
3604                                            struct replPropertyMetaDataBlob *rmd,
3605                                            struct replPropertyMetaDataBlob *omd,
3606                                            struct ldb_request *parent)
3607 {
3608         struct replPropertyMetaData1 *md_remote;
3609         struct replPropertyMetaData1 *md_local;
3610
3611         if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3612                 /* no rename */
3613                 return LDB_SUCCESS;
3614         }
3615
3616         /* now we need to check for double renames. We could have a
3617          * local rename pending which our replication partner hasn't
3618          * received yet. We choose which one wins by looking at the
3619          * attribute stamps on the two objects, the newer one wins
3620          */
3621         md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3622         md_local  = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3623         /* if there is no name attribute then we have to assume the
3624            object we've received is in fact newer */
3625         if (!md_remote || !md_local ||
3626             replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3627                 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3628                          ldb_dn_get_linearized(ar->search_msg->dn),
3629                          ldb_dn_get_linearized(msg->dn)));
3630                 /* pass rename to the next module
3631                  * so it doesn't appear as an originating update */
3632                 return dsdb_module_rename(ar->module,
3633                                           ar->search_msg->dn, msg->dn,
3634                                           DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX, parent);
3635         }
3636
3637         /* we're going to keep our old object */
3638         DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
3639                  ldb_dn_get_linearized(ar->search_msg->dn),
3640                  ldb_dn_get_linearized(msg->dn)));
3641         return LDB_SUCCESS;
3642 }
3643
3644
3645 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
3646 {
3647         struct ldb_context *ldb;
3648         struct ldb_request *change_req;
3649         enum ndr_err_code ndr_err;
3650         struct ldb_message *msg;
3651         struct replPropertyMetaDataBlob *rmd;
3652         struct replPropertyMetaDataBlob omd;
3653         const struct ldb_val *omd_value;
3654         struct replPropertyMetaDataBlob nmd;
3655         struct ldb_val nmd_value;
3656         unsigned int i;
3657         uint32_t j,ni=0;
3658         unsigned int removed_attrs = 0;
3659         int ret;
3660
3661         ldb = ldb_module_get_ctx(ar->module);
3662         msg = ar->objs->objects[ar->index_current].msg;
3663         rmd = ar->objs->objects[ar->index_current].meta_data;
3664         ZERO_STRUCT(omd);
3665         omd.version = 1;
3666
3667         /* find existing meta data */
3668         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
3669         if (omd_value) {
3670                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
3671                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3672                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3673                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3674                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3675                 }
3676
3677                 if (omd.version != 1) {
3678                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3679                 }
3680         }
3681
3682         /* handle renames that come in over DRS */
3683         ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
3684         if (ret != LDB_SUCCESS) {
3685                 ldb_debug(ldb, LDB_DEBUG_FATAL,
3686                           "replmd_replicated_request rename %s => %s failed - %s\n",
3687                           ldb_dn_get_linearized(ar->search_msg->dn),
3688                           ldb_dn_get_linearized(msg->dn),
3689                           ldb_errstring(ldb));
3690                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
3691         }
3692
3693         ZERO_STRUCT(nmd);
3694         nmd.version = 1;
3695         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
3696         nmd.ctr.ctr1.array = talloc_array(ar,
3697                                           struct replPropertyMetaData1,
3698                                           nmd.ctr.ctr1.count);
3699         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3700
3701         /* first copy the old meta data */
3702         for (i=0; i < omd.ctr.ctr1.count; i++) {
3703                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
3704                 ni++;
3705         }
3706
3707         ar->seq_num = 0;
3708         /* now merge in the new meta data */
3709         for (i=0; i < rmd->ctr.ctr1.count; i++) {
3710                 bool found = false;
3711
3712                 for (j=0; j < ni; j++) {
3713                         bool cmp;
3714
3715                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
3716                                 continue;
3717                         }
3718
3719                         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
3720                                 /* if we compare equal then do an
3721                                    update. This is used when a client
3722                                    asks for a FULL_SYNC, and can be
3723                                    used to recover a corrupt
3724                                    replica */
3725                                 cmp = !replmd_replPropertyMetaData1_is_newer(&rmd->ctr.ctr1.array[i],
3726                                                                              &nmd.ctr.ctr1.array[j]);
3727                         } else {
3728                                 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
3729                                                                             &rmd->ctr.ctr1.array[i]);
3730                         }
3731                         if (cmp) {
3732                                 /* replace the entry */
3733                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
3734                                 if (ar->seq_num == 0) {
3735                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3736                                         if (ret != LDB_SUCCESS) {
3737                                                 return replmd_replicated_request_error(ar, ret);
3738                                         }
3739                                 }
3740                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
3741                                 found = true;
3742                                 break;
3743                         }
3744
3745                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
3746                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
3747                                          msg->elements[i-removed_attrs].name,
3748                                          ldb_dn_get_linearized(msg->dn),
3749                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
3750                         }
3751
3752                         /* we don't want to apply this change so remove the attribute */
3753                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
3754                         removed_attrs++;
3755
3756                         found = true;
3757                         break;
3758                 }
3759
3760                 if (found) continue;
3761
3762                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
3763                 if (ar->seq_num == 0) {
3764                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3765                         if (ret != LDB_SUCCESS) {
3766                                 return replmd_replicated_request_error(ar, ret);
3767                         }
3768                 }
3769                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
3770                 ni++;
3771         }
3772
3773         /*
3774          * finally correct the size of the meta_data array
3775          */
3776         nmd.ctr.ctr1.count = ni;
3777
3778         /*
3779          * the rdn attribute (the alias for the name attribute),
3780          * 'cn' for most objects is the last entry in the meta data array
3781          * we have stored
3782          *
3783          * sort the new meta data array
3784          */
3785         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
3786         if (ret != LDB_SUCCESS) {
3787                 return ret;
3788         }
3789
3790         /*
3791          * check if some replicated attributes left, otherwise skip the ldb_modify() call
3792          */
3793         if (msg->num_elements == 0) {
3794                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
3795                           ar->index_current);
3796
3797                 ar->index_current++;
3798                 return replmd_replicated_apply_next(ar);
3799         }
3800
3801         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
3802                   ar->index_current, msg->num_elements);
3803
3804         /* create the meta data value */
3805         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
3806                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3807         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3808                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3809                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3810         }
3811
3812         /*
3813          * when we know that we'll modify the record, add the whenChanged, uSNChanged
3814          * and replPopertyMetaData attributes
3815          */
3816         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3817         if (ret != LDB_SUCCESS) {
3818                 return replmd_replicated_request_error(ar, ret);
3819         }
3820         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3821         if (ret != LDB_SUCCESS) {
3822                 return replmd_replicated_request_error(ar, ret);
3823         }
3824         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
3825         if (ret != LDB_SUCCESS) {
3826                 return replmd_replicated_request_error(ar, ret);
3827         }
3828
3829         replmd_ldb_message_sort(msg, ar->schema);
3830
3831         /* we want to replace the old values */
3832         for (i=0; i < msg->num_elements; i++) {
3833                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3834         }
3835
3836         if (DEBUGLVL(4)) {
3837                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3838                 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
3839                 talloc_free(s);
3840         }
3841
3842         ret = ldb_build_mod_req(&change_req,
3843                                 ldb,
3844                                 ar,
3845                                 msg,
3846                                 ar->controls,
3847                                 ar,
3848                                 replmd_op_callback,
3849                                 ar->req);
3850         LDB_REQ_SET_LOCATION(change_req);
3851         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3852
3853         /* current partition control needed by "repmd_op_callback" */
3854         ret = ldb_request_add_control(change_req,
3855                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3856                                       false, NULL);
3857         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3858
3859         return ldb_next_request(ar->module, change_req);
3860 }
3861
3862 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
3863                                                    struct ldb_reply *ares)
3864 {
3865         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3866                                                struct replmd_replicated_request);
3867         int ret;
3868
3869         if (!ares) {
3870                 return ldb_module_done(ar->req, NULL, NULL,
3871                                         LDB_ERR_OPERATIONS_ERROR);
3872         }
3873         if (ares->error != LDB_SUCCESS &&
3874             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3875                 return ldb_module_done(ar->req, ares->controls,
3876                                         ares->response, ares->error);
3877         }
3878
3879         switch (ares->type) {
3880         case LDB_REPLY_ENTRY:
3881                 ar->search_msg = talloc_steal(ar, ares->message);
3882                 break;
3883
3884         case LDB_REPLY_REFERRAL:
3885                 /* we ignore referrals */
3886                 break;
3887
3888         case LDB_REPLY_DONE:
3889                 if (ar->search_msg != NULL) {
3890                         ret = replmd_replicated_apply_merge(ar);
3891                 } else {
3892                         ret = replmd_replicated_apply_add(ar);
3893                 }
3894                 if (ret != LDB_SUCCESS) {
3895                         return ldb_module_done(ar->req, NULL, NULL, ret);
3896                 }
3897         }
3898
3899         talloc_free(ares);
3900         return LDB_SUCCESS;
3901 }
3902
3903 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3904
3905 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3906 {
3907         struct ldb_context *ldb;
3908         int ret;
3909         char *tmp_str;
3910         char *filter;
3911         struct ldb_request *search_req;
3912         struct ldb_search_options_control *options;
3913
3914         if (ar->index_current >= ar->objs->num_objects) {
3915                 /* done with it, go to next stage */
3916                 return replmd_replicated_uptodate_vector(ar);
3917         }
3918
3919         ldb = ldb_module_get_ctx(ar->module);
3920         ar->search_msg = NULL;
3921
3922         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3923         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3924
3925         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3926         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3927         talloc_free(tmp_str);
3928
3929         ret = ldb_build_search_req(&search_req,
3930                                    ldb,
3931                                    ar,
3932                                    NULL,
3933                                    LDB_SCOPE_SUBTREE,
3934                                    filter,
3935                                    NULL,
3936                                    NULL,
3937                                    ar,
3938                                    replmd_replicated_apply_search_callback,
3939                                    ar->req);
3940         LDB_REQ_SET_LOCATION(search_req);
3941
3942         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
3943                                       true, NULL);
3944         if (ret != LDB_SUCCESS) {
3945                 return ret;
3946         }
3947
3948         /* we need to cope with cross-partition links, so search for
3949            the GUID over all partitions */
3950         options = talloc(search_req, struct ldb_search_options_control);
3951         if (options == NULL) {
3952                 DEBUG(0, (__location__ ": out of memory\n"));
3953                 return LDB_ERR_OPERATIONS_ERROR;
3954         }
3955         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3956
3957         ret = ldb_request_add_control(search_req,
3958                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
3959                                       true, options);
3960         if (ret != LDB_SUCCESS) {
3961                 return ret;
3962         }
3963
3964         return ldb_next_request(ar->module, search_req);
3965 }
3966
3967 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
3968                                                       struct ldb_reply *ares)
3969 {
3970         struct ldb_context *ldb;
3971         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3972                                                struct replmd_replicated_request);
3973         ldb = ldb_module_get_ctx(ar->module);
3974
3975         if (!ares) {
3976                 return ldb_module_done(ar->req, NULL, NULL,
3977                                         LDB_ERR_OPERATIONS_ERROR);
3978         }
3979         if (ares->error != LDB_SUCCESS) {
3980                 return ldb_module_done(ar->req, ares->controls,
3981                                         ares->response, ares->error);
3982         }
3983
3984         if (ares->type != LDB_REPLY_DONE) {
3985                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
3986                 return ldb_module_done(ar->req, NULL, NULL,
3987                                         LDB_ERR_OPERATIONS_ERROR);
3988         }
3989
3990         talloc_free(ares);
3991
3992         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3993 }
3994
3995 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3996 {
3997         struct ldb_context *ldb;
3998         struct ldb_request *change_req;
3999         enum ndr_err_code ndr_err;
4000         struct ldb_message *msg;
4001         struct replUpToDateVectorBlob ouv;
4002         const struct ldb_val *ouv_value;
4003         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
4004         struct replUpToDateVectorBlob nuv;
4005         struct ldb_val nuv_value;
4006         struct ldb_message_element *nuv_el = NULL;
4007         const struct GUID *our_invocation_id;
4008         struct ldb_message_element *orf_el = NULL;
4009         struct repsFromToBlob nrf;
4010         struct ldb_val *nrf_value = NULL;
4011         struct ldb_message_element *nrf_el = NULL;
4012         unsigned int i;
4013         uint32_t j,ni=0;
4014         bool found = false;
4015         time_t t = time(NULL);
4016         NTTIME now;
4017         int ret;
4018         uint32_t instanceType;
4019
4020         ldb = ldb_module_get_ctx(ar->module);
4021         ruv = ar->objs->uptodateness_vector;
4022         ZERO_STRUCT(ouv);
4023         ouv.version = 2;
4024         ZERO_STRUCT(nuv);
4025         nuv.version = 2;
4026
4027         unix_to_nt_time(&now, t);
4028
4029         if (ar->search_msg == NULL) {
4030                 /* this happens for a REPL_OBJ call where we are
4031                    creating the target object by replicating it. The
4032                    subdomain join code does this for the partition DN
4033                 */
4034                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
4035                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4036         }
4037
4038         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
4039         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
4040                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
4041                          ldb_dn_get_linearized(ar->search_msg->dn)));
4042                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4043         }
4044
4045         /*
4046          * first create the new replUpToDateVector
4047          */
4048         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
4049         if (ouv_value) {
4050                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
4051                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4052                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4053                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4054                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4055                 }
4056
4057                 if (ouv.version != 2) {
4058                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4059                 }
4060         }
4061
4062         /*
4063          * the new uptodateness vector will at least
4064          * contain 1 entry, one for the source_dsa
4065          *
4066          * plus optional values from our old vector and the one from the source_dsa
4067          */
4068         nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
4069         if (ruv) nuv.ctr.ctr2.count += ruv->count;
4070         nuv.ctr.ctr2.cursors = talloc_array(ar,
4071                                             struct drsuapi_DsReplicaCursor2,
4072                                             nuv.ctr.ctr2.count);
4073         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4074
4075         /* first copy the old vector */
4076         for (i=0; i < ouv.ctr.ctr2.count; i++) {
4077                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
4078                 ni++;
4079         }
4080
4081         /* get our invocation_id if we have one already attached to the ldb */
4082         our_invocation_id = samdb_ntds_invocation_id(ldb);
4083
4084         /* merge in the source_dsa vector is available */
4085         for (i=0; (ruv && i < ruv->count); i++) {
4086                 found = false;
4087
4088                 if (our_invocation_id &&
4089                     GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4090                                our_invocation_id)) {
4091                         continue;
4092                 }
4093
4094                 for (j=0; j < ni; j++) {
4095                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4096                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4097                                 continue;
4098                         }
4099
4100                         found = true;
4101
4102                         /*
4103                          * we update only the highest_usn and not the latest_sync_success time,
4104                          * because the last success stands for direct replication
4105                          */
4106                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
4107                                 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
4108                         }
4109                         break;
4110                 }
4111
4112                 if (found) continue;
4113
4114                 /* if it's not there yet, add it */
4115                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
4116                 ni++;
4117         }
4118
4119         /*
4120          * merge in the current highwatermark for the source_dsa
4121          */
4122         found = false;
4123         for (j=0; j < ni; j++) {
4124                 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
4125                                 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4126                         continue;
4127                 }
4128
4129                 found = true;
4130
4131                 /*
4132                  * here we update the highest_usn and last_sync_success time
4133                  * because we're directly replicating from the source_dsa
4134                  *
4135                  * and use the tmp_highest_usn because this is what we have just applied
4136                  * to our ldb
4137                  */
4138                 nuv.ctr.ctr2.cursors[j].highest_usn             = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4139                 nuv.ctr.ctr2.cursors[j].last_sync_success       = now;
4140                 break;
4141         }
4142         if (!found) {
4143                 /*
4144                  * here we update the highest_usn and last_sync_success time
4145                  * because we're directly replicating from the source_dsa
4146                  *
4147                  * and use the tmp_highest_usn because this is what we have just applied
4148                  * to our ldb
4149                  */
4150                 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
4151                 nuv.ctr.ctr2.cursors[ni].highest_usn            = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4152                 nuv.ctr.ctr2.cursors[ni].last_sync_success      = now;
4153                 ni++;
4154         }
4155
4156         /*
4157          * finally correct the size of the cursors array
4158          */
4159         nuv.ctr.ctr2.count = ni;
4160
4161         /*
4162          * sort the cursors
4163          */
4164         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
4165
4166         /*
4167          * create the change ldb_message
4168          */
4169         msg = ldb_msg_new(ar);
4170         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4171         msg->dn = ar->search_msg->dn;
4172
4173         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
4174                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
4175         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4176                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4177                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4178         }
4179         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
4180         if (ret != LDB_SUCCESS) {
4181                 return replmd_replicated_request_error(ar, ret);
4182         }
4183         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
4184
4185         /*
4186          * now create the new repsFrom value from the given repsFromTo1 structure
4187          */
4188         ZERO_STRUCT(nrf);
4189         nrf.version                                     = 1;
4190         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
4191         nrf.ctr.ctr1.highwatermark.highest_usn          = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
4192
4193         /*
4194          * first see if we already have a repsFrom value for the current source dsa
4195          * if so we'll later replace this value
4196          */
4197         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
4198         if (orf_el) {
4199                 for (i=0; i < orf_el->num_values; i++) {
4200                         struct repsFromToBlob *trf;
4201
4202                         trf = talloc(ar, struct repsFromToBlob);
4203                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4204
4205                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
4206                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
4207                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4208                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4209                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4210                         }
4211
4212                         if (trf->version != 1) {
4213                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4214                         }
4215
4216                         /*
4217                          * we compare the source dsa objectGUID not the invocation_id
4218                          * because we want only one repsFrom value per source dsa
4219                          * and when the invocation_id of the source dsa has changed we don't need
4220                          * the old repsFrom with the old invocation_id
4221                          */
4222                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
4223                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
4224                                 talloc_free(trf);
4225                                 continue;
4226                         }
4227
4228                         talloc_free(trf);
4229                         nrf_value = &orf_el->values[i];
4230                         break;
4231                 }
4232
4233                 /*
4234                  * copy over all old values to the new ldb_message
4235                  */
4236                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
4237                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4238                 *nrf_el = *orf_el;
4239         }
4240
4241         /*
4242          * if we haven't found an old repsFrom value for the current source dsa
4243          * we'll add a new value
4244          */
4245         if (!nrf_value) {
4246                 struct ldb_val zero_value;
4247                 ZERO_STRUCT(zero_value);
4248                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
4249                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4250
4251                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
4252         }
4253
4254         /* we now fill the value which is already attached to ldb_message */
4255         ndr_err = ndr_push_struct_blob(nrf_value, msg,
4256                                        &nrf,
4257                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
4258         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4259                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4260                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4261         }
4262
4263         /*
4264          * the ldb_message_element for the attribute, has all the old values and the new one
4265          * so we'll replace the whole attribute with all values
4266          */
4267         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
4268
4269         if (CHECK_DEBUGLVL(4)) {
4270                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4271                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
4272                 talloc_free(s);
4273         }
4274
4275         /* prepare the ldb_modify() request */
4276         ret = ldb_build_mod_req(&change_req,
4277                                 ldb,
4278                                 ar,
4279                                 msg,
4280                                 ar->controls,
4281                                 ar,
4282                                 replmd_replicated_uptodate_modify_callback,
4283                                 ar->req);
4284         LDB_REQ_SET_LOCATION(change_req);
4285         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4286
4287         return ldb_next_request(ar->module, change_req);
4288 }
4289
4290 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
4291                                                       struct ldb_reply *ares)
4292 {
4293         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4294                                                struct replmd_replicated_request);
4295         int ret;
4296
4297         if (!ares) {
4298                 return ldb_module_done(ar->req, NULL, NULL,
4299                                         LDB_ERR_OPERATIONS_ERROR);
4300         }
4301         if (ares->error != LDB_SUCCESS &&
4302             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4303                 return ldb_module_done(ar->req, ares->controls,
4304                                         ares->response, ares->error);
4305         }
4306
4307         switch (ares->type) {
4308         case LDB_REPLY_ENTRY:
4309                 ar->search_msg = talloc_steal(ar, ares->message);
4310                 break;
4311
4312         case LDB_REPLY_REFERRAL:
4313                 /* we ignore referrals */
4314                 break;
4315
4316         case LDB_REPLY_DONE:
4317                 ret = replmd_replicated_uptodate_modify(ar);
4318                 if (ret != LDB_SUCCESS) {
4319                         return ldb_module_done(ar->req, NULL, NULL, ret);
4320                 }
4321         }
4322
4323         talloc_free(ares);
4324         return LDB_SUCCESS;
4325 }
4326
4327
4328 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
4329 {
4330         struct ldb_context *ldb;
4331         int ret;
4332         static const char *attrs[] = {
4333                 "replUpToDateVector",
4334                 "repsFrom",
4335                 "instanceType",
4336                 NULL
4337         };
4338         struct ldb_request *search_req;
4339
4340         ldb = ldb_module_get_ctx(ar->module);
4341         ar->search_msg = NULL;
4342
4343         ret = ldb_build_search_req(&search_req,
4344                                    ldb,
4345                                    ar,
4346                                    ar->objs->partition_dn,
4347                                    LDB_SCOPE_BASE,
4348                                    "(objectClass=*)",
4349                                    attrs,
4350                                    NULL,
4351                                    ar,
4352                                    replmd_replicated_uptodate_search_callback,
4353                                    ar->req);
4354         LDB_REQ_SET_LOCATION(search_req);
4355         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4356
4357         return ldb_next_request(ar->module, search_req);
4358 }
4359
4360
4361
4362 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
4363 {
4364         struct ldb_context *ldb;
4365         struct dsdb_extended_replicated_objects *objs;
4366         struct replmd_replicated_request *ar;
4367         struct ldb_control **ctrls;
4368         int ret;
4369         uint32_t i;
4370         struct replmd_private *replmd_private =
4371                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4372         struct dsdb_control_replicated_update *rep_update;
4373
4374         ldb = ldb_module_get_ctx(module);
4375
4376         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
4377
4378         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
4379         if (!objs) {
4380                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
4381                 return LDB_ERR_PROTOCOL_ERROR;
4382         }
4383
4384         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
4385                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
4386                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
4387                 return LDB_ERR_PROTOCOL_ERROR;
4388         }
4389
4390         ar = replmd_ctx_init(module, req);
4391         if (!ar)
4392                 return LDB_ERR_OPERATIONS_ERROR;
4393
4394         /* Set the flags to have the replmd_op_callback run over the full set of objects */
4395         ar->apply_mode = true;
4396         ar->objs = objs;
4397         ar->schema = dsdb_get_schema(ldb, ar);
4398         if (!ar->schema) {
4399                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
4400                 talloc_free(ar);
4401                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4402                 return LDB_ERR_CONSTRAINT_VIOLATION;
4403         }
4404
4405         ctrls = req->controls;
4406
4407         if (req->controls) {
4408                 req->controls = talloc_memdup(ar, req->controls,
4409                                               talloc_get_size(req->controls));
4410                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4411         }
4412
4413         /* This allows layers further down to know if a change came in
4414            over replication and what the replication flags were */
4415         rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
4416         if (rep_update == NULL) {
4417                 return ldb_module_oom(module);
4418         }
4419         rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
4420
4421         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
4422         if (ret != LDB_SUCCESS) {
4423                 return ret;
4424         }
4425
4426         /* If this change contained linked attributes in the body
4427          * (rather than in the links section) we need to update
4428          * backlinks in linked_attributes */
4429         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
4430         if (ret != LDB_SUCCESS) {
4431                 return ret;
4432         }
4433
4434         ar->controls = req->controls;
4435         req->controls = ctrls;
4436
4437         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
4438
4439         /* save away the linked attributes for the end of the
4440            transaction */
4441         for (i=0; i<ar->objs->linked_attributes_count; i++) {
4442                 struct la_entry *la_entry;
4443
4444                 if (replmd_private->la_ctx == NULL) {
4445                         replmd_private->la_ctx = talloc_new(replmd_private);
4446                 }
4447                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
4448                 if (la_entry == NULL) {
4449                         ldb_oom(ldb);
4450                         return LDB_ERR_OPERATIONS_ERROR;
4451                 }
4452                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
4453                 if (la_entry->la == NULL) {
4454                         talloc_free(la_entry);
4455                         ldb_oom(ldb);
4456                         return LDB_ERR_OPERATIONS_ERROR;
4457                 }
4458                 *la_entry->la = ar->objs->linked_attributes[i];
4459
4460                 /* we need to steal the non-scalars so they stay
4461                    around until the end of the transaction */
4462                 talloc_steal(la_entry->la, la_entry->la->identifier);
4463                 talloc_steal(la_entry->la, la_entry->la->value.blob);
4464
4465                 DLIST_ADD(replmd_private->la_list, la_entry);
4466         }
4467
4468         return replmd_replicated_apply_next(ar);
4469 }
4470
4471 /*
4472   process one linked attribute structure
4473  */
4474 static int replmd_process_linked_attribute(struct ldb_module *module,
4475                                            struct la_entry *la_entry,
4476                                            struct ldb_request *parent)
4477 {
4478         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
4479         struct ldb_context *ldb = ldb_module_get_ctx(module);
4480         struct ldb_message *msg;
4481         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
4482         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
4483         int ret;
4484         const struct dsdb_attribute *attr;
4485         struct dsdb_dn *dsdb_dn;
4486         uint64_t seq_num = 0;
4487         struct ldb_message_element *old_el;
4488         WERROR status;
4489         time_t t = time(NULL);
4490         struct ldb_result *res;
4491         const char *attrs[2];
4492         struct parsed_dn *pdn_list, *pdn;
4493         struct GUID guid = GUID_zero();
4494         NTSTATUS ntstatus;
4495         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
4496         const struct GUID *our_invocation_id;
4497
4498 /*
4499 linked_attributes[0]:
4500      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
4501         identifier               : *
4502             identifier: struct drsuapi_DsReplicaObjectIdentifier
4503                 __ndr_size               : 0x0000003a (58)
4504                 __ndr_size_sid           : 0x00000000 (0)
4505                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
4506                 sid                      : S-0-0
4507                 __ndr_size_dn            : 0x00000000 (0)
4508                 dn                       : ''
4509         attid                    : DRSUAPI_ATTID_member (0x1F)
4510         value: struct drsuapi_DsAttributeValue
4511             __ndr_size               : 0x0000007e (126)
4512             blob                     : *
4513                 blob                     : DATA_BLOB length=126
4514         flags                    : 0x00000001 (1)
4515                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
4516         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
4517         meta_data: struct drsuapi_DsReplicaMetaData
4518             version                  : 0x00000015 (21)
4519             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
4520             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
4521             originating_usn          : 0x000000000001e19c (123292)
4522
4523 (for cases where the link is to a normal DN)
4524      &target: struct drsuapi_DsReplicaObjectIdentifier3
4525         __ndr_size               : 0x0000007e (126)
4526         __ndr_size_sid           : 0x0000001c (28)
4527         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
4528         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
4529         __ndr_size_dn            : 0x00000022 (34)
4530         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
4531  */
4532
4533         /* find the attribute being modified */
4534         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
4535         if (attr == NULL) {
4536                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
4537                 talloc_free(tmp_ctx);
4538                 return LDB_ERR_OPERATIONS_ERROR;
4539         }
4540
4541         attrs[0] = attr->lDAPDisplayName;
4542         attrs[1] = NULL;
4543
4544         /* get the existing message from the db for the object with
4545            this GUID, returning attribute being modified. We will then
4546            use this msg as the basis for a modify call */
4547         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
4548                                  DSDB_FLAG_NEXT_MODULE |
4549                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
4550                                  DSDB_SEARCH_SHOW_RECYCLED |
4551                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4552                                  DSDB_SEARCH_REVEAL_INTERNALS,
4553                                  parent,
4554                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
4555         if (ret != LDB_SUCCESS) {
4556                 talloc_free(tmp_ctx);
4557                 return ret;
4558         }
4559         if (res->count != 1) {
4560                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
4561                                        GUID_string(tmp_ctx, &la->identifier->guid));
4562                 talloc_free(tmp_ctx);
4563                 return LDB_ERR_NO_SUCH_OBJECT;
4564         }
4565         msg = res->msgs[0];
4566
4567         if (msg->num_elements == 0) {
4568                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
4569                 if (ret != LDB_SUCCESS) {
4570                         ldb_module_oom(module);
4571                         talloc_free(tmp_ctx);
4572                         return LDB_ERR_OPERATIONS_ERROR;
4573                 }
4574         } else {
4575                 old_el = &msg->elements[0];
4576                 old_el->flags = LDB_FLAG_MOD_REPLACE;
4577         }
4578
4579         /* parse the existing links */
4580         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
4581         if (ret != LDB_SUCCESS) {
4582                 talloc_free(tmp_ctx);
4583                 return ret;
4584         }
4585
4586         /* get our invocationId */
4587         our_invocation_id = samdb_ntds_invocation_id(ldb);
4588         if (!our_invocation_id) {
4589                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
4590                 talloc_free(tmp_ctx);
4591                 return LDB_ERR_OPERATIONS_ERROR;
4592         }
4593
4594         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
4595         if (ret != LDB_SUCCESS) {
4596                 talloc_free(tmp_ctx);
4597                 return ret;
4598         }
4599
4600         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
4601         if (!W_ERROR_IS_OK(status)) {
4602                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
4603                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
4604                 return LDB_ERR_OPERATIONS_ERROR;
4605         }
4606
4607         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
4608         if (!NT_STATUS_IS_OK(ntstatus) && active) {
4609                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
4610                                        old_el->name,
4611                                        ldb_dn_get_linearized(dsdb_dn->dn),
4612                                        ldb_dn_get_linearized(msg->dn));
4613                 return LDB_ERR_OPERATIONS_ERROR;
4614         }
4615
4616         /* re-resolve the DN by GUID, as the DRS server may give us an
4617            old DN value */
4618         ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
4619         if (ret != LDB_SUCCESS) {
4620                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
4621                          GUID_string(tmp_ctx, &guid),
4622                          ldb_dn_get_linearized(dsdb_dn->dn)));
4623         }
4624
4625         /* see if this link already exists */
4626         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
4627         if (pdn != NULL) {
4628                 /* see if this update is newer than what we have already */
4629                 struct GUID invocation_id = GUID_zero();
4630                 uint32_t version = 0;
4631                 uint32_t originating_usn = 0;
4632                 NTTIME change_time = 0;
4633                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
4634
4635                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
4636                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
4637                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
4638                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
4639
4640                 if (!replmd_update_is_newer(&invocation_id,
4641                                             &la->meta_data.originating_invocation_id,
4642                                             version,
4643                                             la->meta_data.version,
4644                                             change_time,
4645                                             la->meta_data.originating_change_time)) {
4646                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
4647                                  old_el->name, ldb_dn_get_linearized(msg->dn),
4648                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
4649                         talloc_free(tmp_ctx);
4650                         return LDB_SUCCESS;
4651                 }
4652
4653                 /* get a seq_num for this change */
4654                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4655                 if (ret != LDB_SUCCESS) {
4656                         talloc_free(tmp_ctx);
4657                         return ret;
4658                 }
4659
4660                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
4661                         /* remove the existing backlink */
4662                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
4663                         if (ret != LDB_SUCCESS) {
4664                                 talloc_free(tmp_ctx);
4665                                 return ret;
4666                         }
4667                 }
4668
4669                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
4670                                            &la->meta_data.originating_invocation_id,
4671                                            la->meta_data.originating_usn, seq_num,
4672                                            la->meta_data.originating_change_time,
4673                                            la->meta_data.version,
4674                                            !active);
4675                 if (ret != LDB_SUCCESS) {
4676                         talloc_free(tmp_ctx);
4677                         return ret;
4678                 }
4679
4680                 if (active) {
4681                         /* add the new backlink */
4682                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
4683                         if (ret != LDB_SUCCESS) {
4684                                 talloc_free(tmp_ctx);
4685                                 return ret;
4686                         }
4687                 }
4688         } else {
4689                 /* get a seq_num for this change */
4690                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4691                 if (ret != LDB_SUCCESS) {
4692                         talloc_free(tmp_ctx);
4693                         return ret;
4694                 }
4695
4696                 old_el->values = talloc_realloc(msg->elements, old_el->values,
4697                                                 struct ldb_val, old_el->num_values+1);
4698                 if (!old_el->values) {
4699                         ldb_module_oom(module);
4700                         return LDB_ERR_OPERATIONS_ERROR;
4701                 }
4702                 old_el->num_values++;
4703
4704                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
4705                                           &la->meta_data.originating_invocation_id,
4706                                           la->meta_data.originating_usn, seq_num,
4707                                           la->meta_data.originating_change_time,
4708                                           la->meta_data.version,
4709                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
4710                 if (ret != LDB_SUCCESS) {
4711                         talloc_free(tmp_ctx);
4712                         return ret;
4713                 }
4714
4715                 if (active) {
4716                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
4717                                                   true, attr, false);
4718                         if (ret != LDB_SUCCESS) {
4719                                 talloc_free(tmp_ctx);
4720                                 return ret;
4721                         }
4722                 }
4723         }
4724
4725         /* we only change whenChanged and uSNChanged if the seq_num
4726            has changed */
4727         ret = add_time_element(msg, "whenChanged", t);
4728         if (ret != LDB_SUCCESS) {
4729                 talloc_free(tmp_ctx);
4730                 ldb_operr(ldb);
4731                 return ret;
4732         }
4733
4734         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
4735         if (ret != LDB_SUCCESS) {
4736                 talloc_free(tmp_ctx);
4737                 ldb_operr(ldb);
4738                 return ret;
4739         }
4740
4741         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
4742         if (old_el == NULL) {
4743                 talloc_free(tmp_ctx);
4744                 return ldb_operr(ldb);
4745         }
4746
4747         ret = dsdb_check_single_valued_link(attr, old_el);
4748         if (ret != LDB_SUCCESS) {
4749                 talloc_free(tmp_ctx);
4750                 return ret;
4751         }
4752
4753         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
4754
4755         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
4756         if (ret != LDB_SUCCESS) {
4757                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
4758                           ldb_errstring(ldb),
4759                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
4760                 talloc_free(tmp_ctx);
4761                 return ret;
4762         }
4763
4764         talloc_free(tmp_ctx);
4765
4766         return ret;
4767 }
4768
4769 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
4770 {
4771         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
4772                 return replmd_extended_replicated_objects(module, req);
4773         }
4774
4775         return ldb_next_request(module, req);
4776 }
4777
4778
4779 /*
4780   we hook into the transaction operations to allow us to
4781   perform the linked attribute updates at the end of the whole
4782   transaction. This allows a forward linked attribute to be created
4783   before the object is created. During a vampire, w2k8 sends us linked
4784   attributes before the objects they are part of.
4785  */
4786 static int replmd_start_transaction(struct ldb_module *module)
4787 {
4788         /* create our private structure for this transaction */
4789         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
4790                                                                 struct replmd_private);
4791         replmd_txn_cleanup(replmd_private);
4792
4793         /* free any leftover mod_usn records from cancelled
4794            transactions */
4795         while (replmd_private->ncs) {
4796                 struct nc_entry *e = replmd_private->ncs;
4797                 DLIST_REMOVE(replmd_private->ncs, e);
4798                 talloc_free(e);
4799         }
4800
4801         return ldb_next_start_trans(module);
4802 }
4803
4804 /*
4805   on prepare commit we loop over our queued la_context structures and
4806   apply each of them
4807  */
4808 static int replmd_prepare_commit(struct ldb_module *module)
4809 {
4810         struct replmd_private *replmd_private =
4811                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4812         struct la_entry *la, *prev;
4813         struct la_backlink *bl;
4814         int ret;
4815
4816         /* walk the list backwards, to do the first entry first, as we
4817          * added the entries with DLIST_ADD() which puts them at the
4818          * start of the list */
4819         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
4820                 prev = DLIST_PREV(la);
4821                 DLIST_REMOVE(replmd_private->la_list, la);
4822                 ret = replmd_process_linked_attribute(module, la, NULL);
4823                 if (ret != LDB_SUCCESS) {
4824                         replmd_txn_cleanup(replmd_private);
4825                         return ret;
4826                 }
4827         }
4828
4829         /* process our backlink list, creating and deleting backlinks
4830            as necessary */
4831         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
4832                 ret = replmd_process_backlink(module, bl, NULL);
4833                 if (ret != LDB_SUCCESS) {
4834                         replmd_txn_cleanup(replmd_private);
4835                         return ret;
4836                 }
4837         }
4838
4839         replmd_txn_cleanup(replmd_private);
4840
4841         /* possibly change @REPLCHANGED */
4842         ret = replmd_notify_store(module, NULL);
4843         if (ret != LDB_SUCCESS) {
4844                 return ret;
4845         }
4846
4847         return ldb_next_prepare_commit(module);
4848 }
4849
4850 static int replmd_del_transaction(struct ldb_module *module)
4851 {
4852         struct replmd_private *replmd_private =
4853                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4854         replmd_txn_cleanup(replmd_private);
4855
4856         return ldb_next_del_trans(module);
4857 }
4858
4859
4860 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
4861         .name          = "repl_meta_data",
4862         .init_context      = replmd_init,
4863         .add               = replmd_add,
4864         .modify            = replmd_modify,
4865         .rename            = replmd_rename,
4866         .del               = replmd_delete,
4867         .extended          = replmd_extended,
4868         .start_transaction = replmd_start_transaction,
4869         .prepare_commit    = replmd_prepare_commit,
4870         .del_transaction   = replmd_del_transaction,
4871 };
4872
4873 int ldb_repl_meta_data_module_init(const char *version)
4874 {
4875         LDB_MODULE_CHECK_VERSION(version);
4876         return ldb_register_module(&ldb_repl_meta_data_module_ops);
4877 }