s4:repl_meta_data LDB module - remove pointless debug messages
[nivanova/samba-autobuild/.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)
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 rodc, rmd_is_provided;
1171
1172         if (rename_attrs) {
1173                 attrs = rename_attrs;
1174         } else {
1175                 attrs = attrs1;
1176         }
1177
1178         ldb = ldb_module_get_ctx(module);
1179
1180         our_invocation_id = samdb_ntds_invocation_id(ldb);
1181         if (!our_invocation_id) {
1182                 /* this happens during an initial vampire while
1183                    updating the schema */
1184                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1185                 return LDB_SUCCESS;
1186         }
1187
1188         unix_to_nt_time(&now, t);
1189
1190         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1191                 rmd_is_provided = true;
1192         } else {
1193                 rmd_is_provided = false;
1194         }
1195
1196         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1197          * otherwise we consider we are updating */
1198         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1199                 situation = REPL_URGENT_ON_DELETE;
1200         } else if (rename_attrs) {
1201                 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1202         } else {
1203                 situation = REPL_URGENT_ON_UPDATE;
1204         }
1205
1206         if (rmd_is_provided) {
1207                 /* In this case the change_replmetadata control was supplied */
1208                 /* We check that it's the only attribute that is provided
1209                  * (it's a rare case so it's better to keep the code simplier)
1210                  * We also check that the highest local_usn is bigger than
1211                  * uSNChanged. */
1212                 uint64_t db_seq;
1213                 if( msg->num_elements != 1 ||
1214                         strncmp(msg->elements[0].name,
1215                                 "replPropertyMetaData", 20) ) {
1216                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1217                                 "a specified replPropertyMetaData attribute or with others\n"));
1218                         return LDB_ERR_OPERATIONS_ERROR;
1219                 }
1220                 if (situation != REPL_URGENT_ON_UPDATE) {
1221                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1222                         return LDB_ERR_OPERATIONS_ERROR;
1223                 }
1224                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1225                 if (!omd_value) {
1226                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1227                                  ldb_dn_get_linearized(msg->dn)));
1228                         return LDB_ERR_OPERATIONS_ERROR;
1229                 }
1230                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1231                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1232                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1233                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1234                                  ldb_dn_get_linearized(msg->dn)));
1235                         return LDB_ERR_OPERATIONS_ERROR;
1236                 }
1237                 *seq_num = find_max_local_usn(omd);
1238
1239                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1240                                             DSDB_FLAG_NEXT_MODULE |
1241                                             DSDB_SEARCH_SHOW_RECYCLED |
1242                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1243                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1244                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1245
1246                 if (ret != LDB_SUCCESS) {
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_asprintf_errstring(ldb, "RODC modify is forbidden\n");
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;
2249         struct loadparm_context *lp_ctx;
2250         char *referral;
2251         unsigned int functional_level;
2252         const DATA_BLOB *guid_blob;
2253
2254         /* do not manipulate our control entries */
2255         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2256                 return ldb_next_request(module, req);
2257         }
2258
2259         ldb = ldb_module_get_ctx(module);
2260
2261         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2262
2263         guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2264         if ( guid_blob != NULL ) {
2265                 ldb_set_errstring(ldb,
2266                                   "replmd_modify: it's not allowed to change the objectGUID!");
2267                 return LDB_ERR_CONSTRAINT_VIOLATION;
2268         }
2269
2270         ac = replmd_ctx_init(module, req);
2271         if (ac == NULL) {
2272                 return ldb_module_oom(module);
2273         }
2274
2275         functional_level = dsdb_functional_level(ldb);
2276
2277         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2278                                  struct loadparm_context);
2279
2280         /* we have to copy the message as the caller might have it as a const */
2281         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2282         if (msg == NULL) {
2283                 ldb_oom(ldb);
2284                 talloc_free(ac);
2285                 return LDB_ERR_OPERATIONS_ERROR;
2286         }
2287
2288         ldb_msg_remove_attr(msg, "whenChanged");
2289         ldb_msg_remove_attr(msg, "uSNChanged");
2290
2291         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2292                                  msg, &ac->seq_num, t, &is_urgent);
2293         if (ret == LDB_ERR_REFERRAL) {
2294                 referral = talloc_asprintf(req,
2295                                            "ldap://%s/%s",
2296                                            lpcfg_dnsdomain(lp_ctx),
2297                                            ldb_dn_get_linearized(msg->dn));
2298                 ret = ldb_module_send_referral(req, referral);
2299                 talloc_free(ac);
2300                 return ldb_module_done(req, NULL, NULL, ret);
2301         }
2302
2303         if (ret != LDB_SUCCESS) {
2304                 talloc_free(ac);
2305                 return ret;
2306         }
2307
2308         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2309         if (ret != LDB_SUCCESS) {
2310                 talloc_free(ac);
2311                 return ret;
2312         }
2313
2314         /* TODO:
2315          * - replace the old object with the newly constructed one
2316          */
2317
2318         ac->is_urgent = is_urgent;
2319
2320         ret = ldb_build_mod_req(&down_req, ldb, ac,
2321                                 msg,
2322                                 req->controls,
2323                                 ac, replmd_op_callback,
2324                                 req);
2325         LDB_REQ_SET_LOCATION(down_req);
2326         if (ret != LDB_SUCCESS) {
2327                 talloc_free(ac);
2328                 return ret;
2329         }
2330
2331         /* current partition control is needed by "replmd_op_callback" */
2332         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2333                 ret = ldb_request_add_control(down_req,
2334                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2335                                               false, NULL);
2336                 if (ret != LDB_SUCCESS) {
2337                         talloc_free(ac);
2338                         return ret;
2339                 }
2340         }
2341
2342         /* If we are in functional level 2000, then
2343          * replmd_modify_handle_linked_attribs will have done
2344          * nothing */
2345         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2346                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2347                 if (ret != LDB_SUCCESS) {
2348                         talloc_free(ac);
2349                         return ret;
2350                 }
2351         }
2352
2353         talloc_steal(down_req, msg);
2354
2355         /* we only change whenChanged and uSNChanged if the seq_num
2356            has changed */
2357         if (ac->seq_num != 0) {
2358                 ret = add_time_element(msg, "whenChanged", t);
2359                 if (ret != LDB_SUCCESS) {
2360                         talloc_free(ac);
2361                         ldb_operr(ldb);
2362                         return ret;
2363                 }
2364
2365                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2366                 if (ret != LDB_SUCCESS) {
2367                         talloc_free(ac);
2368                         ldb_operr(ldb);
2369                         return ret;
2370                 }
2371         }
2372
2373         /* go on with the call chain */
2374         return ldb_next_request(module, down_req);
2375 }
2376
2377 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2378
2379 /*
2380   handle a rename request
2381
2382   On a rename we need to do an extra ldb_modify which sets the
2383   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2384  */
2385 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2386 {
2387         struct ldb_context *ldb;
2388         struct replmd_replicated_request *ac;
2389         int ret;
2390         struct ldb_request *down_req;
2391
2392         /* do not manipulate our control entries */
2393         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2394                 return ldb_next_request(module, req);
2395         }
2396
2397         ldb = ldb_module_get_ctx(module);
2398
2399         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2400
2401         ac = replmd_ctx_init(module, req);
2402         if (ac == NULL) {
2403                 return ldb_module_oom(module);
2404         }
2405
2406         ret = ldb_build_rename_req(&down_req, ldb, ac,
2407                                    ac->req->op.rename.olddn,
2408                                    ac->req->op.rename.newdn,
2409                                    ac->req->controls,
2410                                    ac, replmd_rename_callback,
2411                                    ac->req);
2412         LDB_REQ_SET_LOCATION(down_req);
2413         if (ret != LDB_SUCCESS) {
2414                 talloc_free(ac);
2415                 return ret;
2416         }
2417
2418         /* go on with the call chain */
2419         return ldb_next_request(module, down_req);
2420 }
2421
2422 /* After the rename is compleated, update the whenchanged etc */
2423 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2424 {
2425         struct ldb_context *ldb;
2426         struct replmd_replicated_request *ac;
2427         struct ldb_request *down_req;
2428         struct ldb_message *msg;
2429         const struct dsdb_attribute *rdn_attr;
2430         const char *rdn_name;
2431         const struct ldb_val *rdn_val;
2432         const char *attrs[5] = { NULL, };
2433         time_t t = time(NULL);
2434         int ret;
2435         bool is_urgent = false;
2436
2437         ac = talloc_get_type(req->context, struct replmd_replicated_request);
2438         ldb = ldb_module_get_ctx(ac->module);
2439
2440         if (ares->error != LDB_SUCCESS) {
2441                 return ldb_module_done(ac->req, ares->controls,
2442                                         ares->response, ares->error);
2443         }
2444
2445         if (ares->type != LDB_REPLY_DONE) {
2446                 ldb_set_errstring(ldb,
2447                                   "invalid ldb_reply_type in callback");
2448                 talloc_free(ares);
2449                 return ldb_module_done(ac->req, NULL, NULL,
2450                                         LDB_ERR_OPERATIONS_ERROR);
2451         }
2452
2453         /* TODO:
2454          * - replace the old object with the newly constructed one
2455          */
2456
2457         msg = ldb_msg_new(ac);
2458         if (msg == NULL) {
2459                 ldb_oom(ldb);
2460                 return LDB_ERR_OPERATIONS_ERROR;
2461         }
2462
2463         msg->dn = ac->req->op.rename.newdn;
2464
2465         rdn_name = ldb_dn_get_rdn_name(msg->dn);
2466         if (rdn_name == NULL) {
2467                 talloc_free(ares);
2468                 return ldb_module_done(ac->req, NULL, NULL,
2469                                        ldb_operr(ldb));
2470         }
2471
2472         /* normalize the rdn attribute name */
2473         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2474         if (rdn_attr == NULL) {
2475                 talloc_free(ares);
2476                 return ldb_module_done(ac->req, NULL, NULL,
2477                                        ldb_operr(ldb));
2478         }
2479         rdn_name = rdn_attr->lDAPDisplayName;
2480
2481         rdn_val = ldb_dn_get_rdn_val(msg->dn);
2482         if (rdn_val == NULL) {
2483                 talloc_free(ares);
2484                 return ldb_module_done(ac->req, NULL, NULL,
2485                                        ldb_operr(ldb));
2486         }
2487
2488         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2489                 talloc_free(ares);
2490                 return ldb_module_done(ac->req, NULL, NULL,
2491                                        ldb_oom(ldb));
2492         }
2493         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2494                 talloc_free(ares);
2495                 return ldb_module_done(ac->req, NULL, NULL,
2496                                        ldb_oom(ldb));
2497         }
2498         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2499                 talloc_free(ares);
2500                 return ldb_module_done(ac->req, NULL, NULL,
2501                                        ldb_oom(ldb));
2502         }
2503         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2504                 talloc_free(ares);
2505                 return ldb_module_done(ac->req, NULL, NULL,
2506                                        ldb_oom(ldb));
2507         }
2508
2509         /*
2510          * here we let replmd_update_rpmd() only search for
2511          * the existing "replPropertyMetaData" and rdn_name attributes.
2512          *
2513          * We do not want the existing "name" attribute as
2514          * the "name" attribute needs to get the version
2515          * updated on rename even if the rdn value hasn't changed.
2516          *
2517          * This is the diff of the meta data, for a moved user
2518          * on a w2k8r2 server:
2519          *
2520          * # record 1
2521          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2522          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2523          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
2524          *         version                  : 0x00000001 (1)
2525          *         reserved                 : 0x00000000 (0)
2526          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
2527          *                      local_usn                : 0x00000000000037a5 (14245)
2528          *                 array: struct replPropertyMetaData1
2529          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
2530          * -                    version                  : 0x00000001 (1)
2531          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
2532          * +                    version                  : 0x00000002 (2)
2533          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
2534          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2535          * -                    originating_usn          : 0x00000000000037a5 (14245)
2536          * -                    local_usn                : 0x00000000000037a5 (14245)
2537          * +                    originating_usn          : 0x0000000000003834 (14388)
2538          * +                    local_usn                : 0x0000000000003834 (14388)
2539          *                 array: struct replPropertyMetaData1
2540          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
2541          *                      version                  : 0x00000004 (4)
2542          */
2543         attrs[0] = "replPropertyMetaData";
2544         attrs[1] = "objectClass";
2545         attrs[2] = "instanceType";
2546         attrs[3] = rdn_name;
2547         attrs[4] = NULL;
2548
2549         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2550                                  msg, &ac->seq_num, t, &is_urgent);
2551         if (ret == LDB_ERR_REFERRAL) {
2552                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2553                 struct loadparm_context *lp_ctx;
2554                 char *referral;
2555
2556                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2557                                          struct loadparm_context);
2558
2559                 referral = talloc_asprintf(req,
2560                                            "ldap://%s/%s",
2561                                            lpcfg_dnsdomain(lp_ctx),
2562                                            ldb_dn_get_linearized(olddn));
2563                 ret = ldb_module_send_referral(req, referral);
2564                 talloc_free(ares);
2565                 return ldb_module_done(req, NULL, NULL, ret);
2566         }
2567
2568         if (ret != LDB_SUCCESS) {
2569                 talloc_free(ares);
2570                 return ldb_module_done(ac->req, NULL, NULL,
2571                                        ldb_error(ldb, ret,
2572                                         "failed to call replmd_update_rpmd()"));
2573         }
2574
2575         if (ac->seq_num == 0) {
2576                 talloc_free(ares);
2577                 return ldb_module_done(ac->req, NULL, NULL,
2578                                        ldb_error(ldb, ret,
2579                                         "internal error seq_num == 0"));
2580         }
2581         ac->is_urgent = is_urgent;
2582
2583         ret = ldb_build_mod_req(&down_req, ldb, ac,
2584                                 msg,
2585                                 req->controls,
2586                                 ac, replmd_op_callback,
2587                                 req);
2588         LDB_REQ_SET_LOCATION(down_req);
2589         if (ret != LDB_SUCCESS) {
2590                 talloc_free(ac);
2591                 return ret;
2592         }
2593
2594         /* current partition control is needed by "replmd_op_callback" */
2595         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2596                 ret = ldb_request_add_control(down_req,
2597                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2598                                               false, NULL);
2599                 if (ret != LDB_SUCCESS) {
2600                         talloc_free(ac);
2601                         return ret;
2602                 }
2603         }
2604
2605         talloc_steal(down_req, msg);
2606
2607         ret = add_time_element(msg, "whenChanged", t);
2608         if (ret != LDB_SUCCESS) {
2609                 talloc_free(ac);
2610                 ldb_operr(ldb);
2611                 return ret;
2612         }
2613
2614         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2615         if (ret != LDB_SUCCESS) {
2616                 talloc_free(ac);
2617                 ldb_operr(ldb);
2618                 return ret;
2619         }
2620
2621         /* go on with the call chain - do the modify after the rename */
2622         return ldb_next_request(ac->module, down_req);
2623 }
2624
2625 /*
2626    remove links from objects that point at this object when an object
2627    is deleted
2628  */
2629 static int replmd_delete_remove_link(struct ldb_module *module,
2630                                      const struct dsdb_schema *schema,
2631                                      struct ldb_dn *dn,
2632                                      struct ldb_message_element *el,
2633                                      const struct dsdb_attribute *sa,
2634                                      struct ldb_request *parent)
2635 {
2636         unsigned int i;
2637         TALLOC_CTX *tmp_ctx = talloc_new(module);
2638         struct ldb_context *ldb = ldb_module_get_ctx(module);
2639
2640         for (i=0; i<el->num_values; i++) {
2641                 struct dsdb_dn *dsdb_dn;
2642                 NTSTATUS status;
2643                 int ret;
2644                 struct GUID guid2;
2645                 struct ldb_message *msg;
2646                 const struct dsdb_attribute *target_attr;
2647                 struct ldb_message_element *el2;
2648                 struct ldb_val dn_val;
2649
2650                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2651                         continue;
2652                 }
2653
2654                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2655                 if (!dsdb_dn) {
2656                         talloc_free(tmp_ctx);
2657                         return LDB_ERR_OPERATIONS_ERROR;
2658                 }
2659
2660                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2661                 if (!NT_STATUS_IS_OK(status)) {
2662                         talloc_free(tmp_ctx);
2663                         return LDB_ERR_OPERATIONS_ERROR;
2664                 }
2665
2666                 /* remove the link */
2667                 msg = ldb_msg_new(tmp_ctx);
2668                 if (!msg) {
2669                         ldb_module_oom(module);
2670                         talloc_free(tmp_ctx);
2671                         return LDB_ERR_OPERATIONS_ERROR;
2672                 }
2673
2674
2675                 msg->dn = dsdb_dn->dn;
2676
2677                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2678                 if (target_attr == NULL) {
2679                         continue;
2680                 }
2681
2682                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2683                 if (ret != LDB_SUCCESS) {
2684                         ldb_module_oom(module);
2685                         talloc_free(tmp_ctx);
2686                         return LDB_ERR_OPERATIONS_ERROR;
2687                 }
2688                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2689                 el2->values = &dn_val;
2690                 el2->num_values = 1;
2691
2692                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2693                 if (ret != LDB_SUCCESS) {
2694                         talloc_free(tmp_ctx);
2695                         return ret;
2696                 }
2697         }
2698         talloc_free(tmp_ctx);
2699         return LDB_SUCCESS;
2700 }
2701
2702
2703 /*
2704   handle update of replication meta data for deletion of objects
2705
2706   This also handles the mapping of delete to a rename operation
2707   to allow deletes to be replicated.
2708  */
2709 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2710 {
2711         int ret = LDB_ERR_OTHER;
2712         bool retb, disallow_move_on_delete;
2713         struct ldb_dn *old_dn, *new_dn;
2714         const char *rdn_name;
2715         const struct ldb_val *rdn_value, *new_rdn_value;
2716         struct GUID guid;
2717         struct ldb_context *ldb = ldb_module_get_ctx(module);
2718         const struct dsdb_schema *schema;
2719         struct ldb_message *msg, *old_msg;
2720         struct ldb_message_element *el;
2721         TALLOC_CTX *tmp_ctx;
2722         struct ldb_result *res, *parent_res;
2723         const char *preserved_attrs[] = {
2724                 /* yes, this really is a hard coded list. See MS-ADTS
2725                    section 3.1.1.5.5.1.1 */
2726                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2727                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2728                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2729                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2730                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2731                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2732                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2733                 "whenChanged", NULL};
2734         unsigned int i, el_count = 0;
2735         enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2736                                                 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2737         enum deletion_state deletion_state, next_deletion_state;
2738         bool enabled;
2739         int functional_level;
2740
2741         if (ldb_dn_is_special(req->op.del.dn)) {
2742                 return ldb_next_request(module, req);
2743         }
2744
2745         tmp_ctx = talloc_new(ldb);
2746         if (!tmp_ctx) {
2747                 ldb_oom(ldb);
2748                 return LDB_ERR_OPERATIONS_ERROR;
2749         }
2750
2751         schema = dsdb_get_schema(ldb, tmp_ctx);
2752         if (!schema) {
2753                 return LDB_ERR_OPERATIONS_ERROR;
2754         }
2755
2756         functional_level = dsdb_functional_level(ldb);
2757
2758         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2759
2760         /* we need the complete msg off disk, so we can work out which
2761            attributes need to be removed */
2762         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2763                                     DSDB_FLAG_NEXT_MODULE |
2764                                     DSDB_SEARCH_SHOW_RECYCLED |
2765                                     DSDB_SEARCH_REVEAL_INTERNALS |
2766                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2767         if (ret != LDB_SUCCESS) {
2768                 talloc_free(tmp_ctx);
2769                 return ret;
2770         }
2771         old_msg = res->msgs[0];
2772
2773
2774         ret = dsdb_recyclebin_enabled(module, &enabled);
2775         if (ret != LDB_SUCCESS) {
2776                 talloc_free(tmp_ctx);
2777                 return ret;
2778         }
2779
2780         if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2781                 if (!enabled) {
2782                         deletion_state = OBJECT_TOMBSTONE;
2783                         next_deletion_state = OBJECT_REMOVED;
2784                 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2785                         deletion_state = OBJECT_RECYCLED;
2786                         next_deletion_state = OBJECT_REMOVED;
2787                 } else {
2788                         deletion_state = OBJECT_DELETED;
2789                         next_deletion_state = OBJECT_RECYCLED;
2790                 }
2791         } else {
2792                 deletion_state = OBJECT_NOT_DELETED;
2793                 if (enabled) {
2794                         next_deletion_state = OBJECT_DELETED;
2795                 } else {
2796                         next_deletion_state = OBJECT_TOMBSTONE;
2797                 }
2798         }
2799
2800         if (next_deletion_state == OBJECT_REMOVED) {
2801                 struct auth_session_info *session_info =
2802                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2803                 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2804                         ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2805                                         ldb_dn_get_linearized(old_msg->dn));
2806                         return LDB_ERR_UNWILLING_TO_PERFORM;
2807                 }
2808
2809                 /* it is already deleted - really remove it this time */
2810                 talloc_free(tmp_ctx);
2811                 return ldb_next_request(module, req);
2812         }
2813
2814         rdn_name = ldb_dn_get_rdn_name(old_dn);
2815         rdn_value = ldb_dn_get_rdn_val(old_dn);
2816         if ((rdn_name == NULL) || (rdn_value == NULL)) {
2817                 talloc_free(tmp_ctx);
2818                 return ldb_operr(ldb);
2819         }
2820
2821         msg = ldb_msg_new(tmp_ctx);
2822         if (msg == NULL) {
2823                 ldb_module_oom(module);
2824                 talloc_free(tmp_ctx);
2825                 return LDB_ERR_OPERATIONS_ERROR;
2826         }
2827
2828         msg->dn = old_dn;
2829
2830         if (deletion_state == OBJECT_NOT_DELETED){
2831                 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2832                 disallow_move_on_delete =
2833                         (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2834                                 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2835
2836                 /* work out where we will be renaming this object to */
2837                 if (!disallow_move_on_delete) {
2838                         ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2839                                                           &new_dn);
2840                         if (ret != LDB_SUCCESS) {
2841                                 /* this is probably an attempted delete on a partition
2842                                  * that doesn't allow delete operations, such as the
2843                                  * schema partition */
2844                                 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2845                                                            ldb_dn_get_linearized(old_dn));
2846                                 talloc_free(tmp_ctx);
2847                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2848                         }
2849                 } else {
2850                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2851                         if (new_dn == NULL) {
2852                                 ldb_module_oom(module);
2853                                 talloc_free(tmp_ctx);
2854                                 return LDB_ERR_OPERATIONS_ERROR;
2855                         }
2856                 }
2857
2858                 /* get the objects GUID from the search we just did */
2859                 guid = samdb_result_guid(old_msg, "objectGUID");
2860
2861                 /* Add a formatted child */
2862                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2863                                                 rdn_name,
2864                                                 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2865                                                 GUID_string(tmp_ctx, &guid));
2866                 if (!retb) {
2867                         DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2868                                         ldb_dn_get_linearized(new_dn)));
2869                         talloc_free(tmp_ctx);
2870                         return LDB_ERR_OPERATIONS_ERROR;
2871                 }
2872
2873                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2874                 if (ret != LDB_SUCCESS) {
2875                         DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2876                         ldb_module_oom(module);
2877                         talloc_free(tmp_ctx);
2878                         return ret;
2879                 }
2880                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2881         }
2882
2883         /*
2884           now we need to modify the object in the following ways:
2885
2886           - add isDeleted=TRUE
2887           - update rDN and name, with new rDN
2888           - remove linked attributes
2889           - remove objectCategory and sAMAccountType
2890           - remove attribs not on the preserved list
2891              - preserved if in above list, or is rDN
2892           - remove all linked attribs from this object
2893           - remove all links from other objects to this object
2894           - add lastKnownParent
2895           - update replPropertyMetaData?
2896
2897           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2898          */
2899
2900         /* we need the storage form of the parent GUID */
2901         ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2902                                     ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2903                                     DSDB_FLAG_NEXT_MODULE |
2904                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2905                                     DSDB_SEARCH_REVEAL_INTERNALS|
2906                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2907         if (ret != LDB_SUCCESS) {
2908                 talloc_free(tmp_ctx);
2909                 return ret;
2910         }
2911
2912         if (deletion_state == OBJECT_NOT_DELETED){
2913                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2914                                                    ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2915                 if (ret != LDB_SUCCESS) {
2916                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2917                         ldb_module_oom(module);
2918                         talloc_free(tmp_ctx);
2919                         return ret;
2920                 }
2921                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2922         }
2923
2924         switch (next_deletion_state){
2925
2926         case OBJECT_DELETED:
2927
2928                 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2929                 if (ret != LDB_SUCCESS) {
2930                         DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2931                         ldb_module_oom(module);
2932                         talloc_free(tmp_ctx);
2933                         return ret;
2934                 }
2935                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2936
2937                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
2938                 if (ret != LDB_SUCCESS) {
2939                         talloc_free(tmp_ctx);
2940                         ldb_module_oom(module);
2941                         return ret;
2942                 }
2943
2944                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
2945                 if (ret != LDB_SUCCESS) {
2946                         talloc_free(tmp_ctx);
2947                         ldb_module_oom(module);
2948                         return ret;
2949                 }
2950
2951                 break;
2952
2953         case OBJECT_RECYCLED:
2954         case OBJECT_TOMBSTONE:
2955
2956                 /* we also mark it as recycled, meaning this object can't be
2957                    recovered (we are stripping its attributes) */
2958                 if (functional_level >= DS_DOMAIN_FUNCTION_2008_R2) {
2959                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2960                         if (ret != LDB_SUCCESS) {
2961                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2962                                 ldb_module_oom(module);
2963                                 talloc_free(tmp_ctx);
2964                                 return ret;
2965                         }
2966                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2967                 }
2968
2969                 /* work out which of the old attributes we will be removing */
2970                 for (i=0; i<old_msg->num_elements; i++) {
2971                         const struct dsdb_attribute *sa;
2972                         el = &old_msg->elements[i];
2973                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2974                         if (!sa) {
2975                                 talloc_free(tmp_ctx);
2976                                 return LDB_ERR_OPERATIONS_ERROR;
2977                         }
2978                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2979                                 /* don't remove the rDN */
2980                                 continue;
2981                         }
2982                         if (sa->linkID && (sa->linkID & 1)) {
2983                                 /*
2984                                   we have a backlink in this object
2985                                   that needs to be removed. We're not
2986                                   allowed to remove it directly
2987                                   however, so we instead setup a
2988                                   modify to delete the corresponding
2989                                   forward link
2990                                  */
2991                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
2992                                 if (ret != LDB_SUCCESS) {
2993                                         talloc_free(tmp_ctx);
2994                                         return LDB_ERR_OPERATIONS_ERROR;
2995                                 }
2996                                 /* now we continue, which means we
2997                                    won't remove this backlink
2998                                    directly
2999                                 */
3000                                 continue;
3001                         }
3002                         if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
3003                                 continue;
3004                         }
3005                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3006                         if (ret != LDB_SUCCESS) {
3007                                 talloc_free(tmp_ctx);
3008                                 ldb_module_oom(module);
3009                                 return ret;
3010                         }
3011                 }
3012                 break;
3013
3014         default:
3015                 break;
3016         }
3017
3018         if (deletion_state == OBJECT_NOT_DELETED) {
3019                 const struct dsdb_attribute *sa;
3020
3021                 /* work out what the new rdn value is, for updating the
3022                    rDN and name fields */
3023                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3024                 if (new_rdn_value == NULL) {
3025                         talloc_free(tmp_ctx);
3026                         return ldb_operr(ldb);
3027                 }
3028
3029                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3030                 if (!sa) {
3031                         talloc_free(tmp_ctx);
3032                         return LDB_ERR_OPERATIONS_ERROR;
3033                 }
3034
3035                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3036                                         &el);
3037                 if (ret != LDB_SUCCESS) {
3038                         talloc_free(tmp_ctx);
3039                         return ret;
3040                 }
3041                 el->flags = LDB_FLAG_MOD_REPLACE;
3042
3043                 el = ldb_msg_find_element(old_msg, "name");
3044                 if (el) {
3045                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3046                         if (ret != LDB_SUCCESS) {
3047                                 talloc_free(tmp_ctx);
3048                                 return ret;
3049                         }
3050                         el->flags = LDB_FLAG_MOD_REPLACE;
3051                 }
3052         }
3053
3054         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3055         if (ret != LDB_SUCCESS) {
3056                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3057                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3058                 talloc_free(tmp_ctx);
3059                 return ret;
3060         }
3061
3062         if (deletion_state == OBJECT_NOT_DELETED) {
3063                 /* now rename onto the new DN */
3064                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3065                 if (ret != LDB_SUCCESS){
3066                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3067                                  ldb_dn_get_linearized(old_dn),
3068                                  ldb_dn_get_linearized(new_dn),
3069                                  ldb_errstring(ldb)));
3070                         talloc_free(tmp_ctx);
3071                         return ret;
3072                 }
3073         }
3074
3075         talloc_free(tmp_ctx);
3076
3077         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3078 }
3079
3080
3081
3082 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3083 {
3084         return ret;
3085 }
3086
3087 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3088 {
3089         int ret = LDB_ERR_OTHER;
3090         /* TODO: do some error mapping */
3091         return ret;
3092 }
3093
3094
3095 static struct replPropertyMetaData1 *
3096 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3097                                         enum drsuapi_DsAttributeId attid)
3098 {
3099         uint32_t i;
3100         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3101
3102         for (i = 0; i < rpmd_ctr->count; i++) {
3103                 if (rpmd_ctr->array[i].attid == attid) {
3104                         return &rpmd_ctr->array[i];
3105                 }
3106         }
3107         return NULL;
3108 }
3109
3110
3111 /*
3112    return true if an update is newer than an existing entry
3113    see section 5.11 of MS-ADTS
3114 */
3115 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3116                                    const struct GUID *update_invocation_id,
3117                                    uint32_t current_version,
3118                                    uint32_t update_version,
3119                                    NTTIME current_change_time,
3120                                    NTTIME update_change_time)
3121 {
3122         if (update_version != current_version) {
3123                 return update_version > current_version;
3124         }
3125         if (update_change_time != current_change_time) {
3126                 return update_change_time > current_change_time;
3127         }
3128         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3129 }
3130
3131 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3132                                                   struct replPropertyMetaData1 *new_m)
3133 {
3134         return replmd_update_is_newer(&cur_m->originating_invocation_id,
3135                                       &new_m->originating_invocation_id,
3136                                       cur_m->version,
3137                                       new_m->version,
3138                                       cur_m->originating_change_time,
3139                                       new_m->originating_change_time);
3140 }
3141
3142
3143 /*
3144   form a conflict DN
3145  */
3146 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3147 {
3148         const struct ldb_val *rdn_val;
3149         const char *rdn_name;
3150         struct ldb_dn *new_dn;
3151
3152         rdn_val = ldb_dn_get_rdn_val(dn);
3153         rdn_name = ldb_dn_get_rdn_name(dn);
3154         if (!rdn_val || !rdn_name) {
3155                 return NULL;
3156         }
3157
3158         new_dn = ldb_dn_copy(mem_ctx, dn);
3159         if (!new_dn) {
3160                 return NULL;
3161         }
3162
3163         if (!ldb_dn_remove_child_components(new_dn, 1)) {
3164                 return NULL;
3165         }
3166
3167         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3168                                   rdn_name,
3169                                   ldb_dn_escape_value(new_dn, *rdn_val),
3170                                   GUID_string(new_dn, guid))) {
3171                 return NULL;
3172         }
3173
3174         return new_dn;
3175 }
3176
3177
3178 /*
3179   perform a modify operation which sets the rDN and name attributes to
3180   their current values. This has the effect of changing these
3181   attributes to have been last updated by the current DC. This is
3182   needed to ensure that renames performed as part of conflict
3183   resolution are propogated to other DCs
3184  */
3185 static int replmd_name_modify(struct replmd_replicated_request *ar,
3186                               struct ldb_request *req, struct ldb_dn *dn)
3187 {
3188         struct ldb_message *msg;
3189         const char *rdn_name;
3190         const struct ldb_val *rdn_val;
3191         const struct dsdb_attribute *rdn_attr;
3192         int ret;
3193
3194         msg = ldb_msg_new(req);
3195         if (msg == NULL) {
3196                 goto failed;
3197         }
3198         msg->dn = dn;
3199
3200         rdn_name = ldb_dn_get_rdn_name(dn);
3201         if (rdn_name == NULL) {
3202                 goto failed;
3203         }
3204
3205         /* normalize the rdn attribute name */
3206         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3207         if (rdn_attr == NULL) {
3208                 goto failed;
3209         }
3210         rdn_name = rdn_attr->lDAPDisplayName;
3211
3212         rdn_val = ldb_dn_get_rdn_val(dn);
3213         if (rdn_val == NULL) {
3214                 goto failed;
3215         }
3216
3217         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3218                 goto failed;
3219         }
3220         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3221                 goto failed;
3222         }
3223         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3224                 goto failed;
3225         }
3226         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3227                 goto failed;
3228         }
3229
3230         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3231         if (ret != LDB_SUCCESS) {
3232                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3233                          ldb_dn_get_linearized(dn),
3234                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3235                 return ret;
3236         }
3237
3238         talloc_free(msg);
3239
3240         return LDB_SUCCESS;
3241
3242 failed:
3243         talloc_free(msg);
3244         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3245                  ldb_dn_get_linearized(dn)));
3246         return LDB_ERR_OPERATIONS_ERROR;
3247 }
3248
3249
3250 /*
3251   callback for conflict DN handling where we have renamed the incoming
3252   record. After renaming it, we need to ensure the change of name and
3253   rDN for the incoming record is seen as an originating update by this DC.
3254  */
3255 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3256 {
3257         struct replmd_replicated_request *ar =
3258                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3259         int ret;
3260
3261         if (ares->error != LDB_SUCCESS) {
3262                 /* call the normal callback for everything except success */
3263                 return replmd_op_callback(req, ares);
3264         }
3265
3266         /* perform a modify of the rDN and name of the record */
3267         ret = replmd_name_modify(ar, req, req->op.add.message->dn);
3268         if (ret != LDB_SUCCESS) {
3269                 ares->error = ret;
3270                 return replmd_op_callback(req, ares);
3271         }
3272
3273         return replmd_op_callback(req, ares);
3274 }
3275
3276 /*
3277   callback for replmd_replicated_apply_add()
3278   This copes with the creation of conflict records in the case where
3279   the DN exists, but with a different objectGUID
3280  */
3281 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3282 {
3283         struct ldb_dn *conflict_dn;
3284         struct replmd_replicated_request *ar =
3285                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3286         struct ldb_result *res;
3287         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3288         int ret;
3289         const struct ldb_val *rmd_value, *omd_value;
3290         struct replPropertyMetaDataBlob omd, rmd;
3291         enum ndr_err_code ndr_err;
3292         bool rename_incoming_record, rodc;
3293         struct replPropertyMetaData1 *rmd_name, *omd_name;
3294
3295         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3296                 /* call the normal callback for everything except
3297                    conflicts */
3298                 return replmd_op_callback(req, ares);
3299         }
3300
3301         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
3302         if (ret != LDB_SUCCESS) {
3303                 return ret;
3304         }
3305         /*
3306          * we have a conflict, and need to decide if we will keep the
3307          * new record or the old record
3308          */
3309         conflict_dn = req->op.add.message->dn;
3310
3311         if (rodc) {
3312                 /*
3313                  * We are on an RODC, or were a GC for this
3314                  * partition, so we have to fail this until
3315                  * someone who owns the partition sorts it
3316                  * out 
3317                  */
3318                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), 
3319                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
3320                                        " - We must fail the operation until a master for this partition resolves the conflict",
3321                                        ldb_dn_get_linearized(conflict_dn));
3322                 goto failed;
3323         }
3324
3325         /*
3326          * we have a conflict, and need to decide if we will keep the
3327          * new record or the old record
3328          */
3329         conflict_dn = req->op.add.message->dn;
3330
3331         /*
3332          * first we need the replPropertyMetaData attribute from the
3333          * old record
3334          */
3335         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3336                                     attrs,
3337                                     DSDB_FLAG_NEXT_MODULE |
3338                                     DSDB_SEARCH_SHOW_DELETED |
3339                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3340         if (ret != LDB_SUCCESS) {
3341                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3342                          ldb_dn_get_linearized(conflict_dn)));
3343                 goto failed;
3344         }
3345
3346         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3347         if (omd_value == NULL) {
3348                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3349                          ldb_dn_get_linearized(conflict_dn)));
3350                 goto failed;
3351         }
3352
3353         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3354                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3355         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3356                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3357                          ldb_dn_get_linearized(conflict_dn)));
3358                 goto failed;
3359         }
3360
3361         /*
3362          * and the replPropertyMetaData attribute from the
3363          * new record
3364          */
3365         rmd_value = ldb_msg_find_ldb_val(req->op.add.message, "replPropertyMetaData");
3366         if (rmd_value == NULL) {
3367                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for new record '%s'\n",
3368                          ldb_dn_get_linearized(conflict_dn)));
3369                 goto failed;
3370         }
3371
3372         ndr_err = ndr_pull_struct_blob(rmd_value, req, &rmd,
3373                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3374         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3375                 DEBUG(0,(__location__ ": Failed to parse new replPropertyMetaData for %s\n",
3376                          ldb_dn_get_linearized(conflict_dn)));
3377                 goto failed;
3378         }
3379
3380         /* we decide which is newer based on the RPMD on the name
3381            attribute.  See [MS-DRSR] ResolveNameConflict */
3382         rmd_name = replmd_replPropertyMetaData1_find_attid(&rmd, DRSUAPI_ATTID_name);
3383         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3384         if (!rmd_name || !omd_name) {
3385                 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3386                          ldb_dn_get_linearized(conflict_dn)));
3387                 goto failed;
3388         }
3389
3390         rename_incoming_record = !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3391
3392         if (rename_incoming_record) {
3393                 struct GUID guid;
3394                 struct ldb_dn *new_dn;
3395                 struct ldb_message *new_msg;
3396
3397                 guid = samdb_result_guid(req->op.add.message, "objectGUID");
3398                 if (GUID_all_zero(&guid)) {
3399                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3400                                  ldb_dn_get_linearized(conflict_dn)));
3401                         goto failed;
3402                 }
3403                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3404                 if (new_dn == NULL) {
3405                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3406                                  ldb_dn_get_linearized(conflict_dn)));
3407                         goto failed;
3408                 }
3409
3410                 DEBUG(1,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3411                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3412
3413                 /* re-submit the request, but with a different
3414                    callback, so we don't loop forever. */
3415                 new_msg = ldb_msg_copy_shallow(req, req->op.add.message);
3416                 if (!new_msg) {
3417                         goto failed;
3418                         DEBUG(0,(__location__ ": Failed to copy conflict DN message for %s\n",
3419                                  ldb_dn_get_linearized(conflict_dn)));
3420                 }
3421                 new_msg->dn = new_dn;
3422                 req->op.add.message = new_msg;
3423                 req->callback = replmd_op_name_modify_callback;
3424
3425                 return ldb_next_request(ar->module, req);
3426         } else {
3427                 /* we are renaming the existing record */
3428                 struct GUID guid;
3429                 struct ldb_dn *new_dn;
3430
3431                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3432                 if (GUID_all_zero(&guid)) {
3433                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3434                                  ldb_dn_get_linearized(conflict_dn)));
3435                         goto failed;
3436                 }
3437
3438                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3439                 if (new_dn == NULL) {
3440                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3441                                  ldb_dn_get_linearized(conflict_dn)));
3442                         goto failed;
3443                 }
3444
3445                 DEBUG(1,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
3446                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3447
3448                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3449                                          DSDB_FLAG_OWN_MODULE, req);
3450                 if (ret != LDB_SUCCESS) {
3451                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3452                                  ldb_dn_get_linearized(conflict_dn),
3453                                  ldb_dn_get_linearized(new_dn),
3454                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3455                         goto failed;
3456                 }
3457
3458                 /*
3459                  * now we need to ensure that the rename is seen as an
3460                  * originating update. We do that with a modify.
3461                  */
3462                 ret = replmd_name_modify(ar, req, new_dn);
3463                 if (ret != LDB_SUCCESS) {
3464                         goto failed;
3465                 }
3466
3467                 req->callback = replmd_op_callback;
3468
3469                 return ldb_next_request(ar->module, req);
3470         }
3471
3472 failed:
3473         /* on failure do the original callback. This means replication
3474          * will stop with an error, but there is not much else we can
3475          * do
3476          */
3477         return replmd_op_callback(req, ares);
3478 }
3479
3480 /*
3481   this is called when a new object comes in over DRS
3482  */
3483 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3484 {
3485         struct ldb_context *ldb;
3486         struct ldb_request *change_req;
3487         enum ndr_err_code ndr_err;
3488         struct ldb_message *msg;
3489         struct replPropertyMetaDataBlob *md;
3490         struct ldb_val md_value;
3491         unsigned int i;
3492         int ret;
3493
3494         /*
3495          * TODO: check if the parent object exist
3496          */
3497
3498         /*
3499          * TODO: handle the conflict case where an object with the
3500          *       same name exist
3501          */
3502
3503         ldb = ldb_module_get_ctx(ar->module);
3504         msg = ar->objs->objects[ar->index_current].msg;
3505         md = ar->objs->objects[ar->index_current].meta_data;
3506
3507         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3508         if (ret != LDB_SUCCESS) {
3509                 return replmd_replicated_request_error(ar, ret);
3510         }
3511
3512         ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
3513         if (ret != LDB_SUCCESS) {
3514                 return replmd_replicated_request_error(ar, ret);
3515         }
3516
3517         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3518         if (ret != LDB_SUCCESS) {
3519                 return replmd_replicated_request_error(ar, ret);
3520         }
3521
3522         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
3523         if (ret != LDB_SUCCESS) {
3524                 return replmd_replicated_request_error(ar, ret);
3525         }
3526
3527         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3528         if (ret != LDB_SUCCESS) {
3529                 return replmd_replicated_request_error(ar, ret);
3530         }
3531
3532         /* remove any message elements that have zero values */
3533         for (i=0; i<msg->num_elements; i++) {
3534                 struct ldb_message_element *el = &msg->elements[i];
3535
3536                 if (el->num_values == 0) {
3537                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
3538                                  el->name));
3539                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
3540                         msg->num_elements--;
3541                         i--;
3542                         continue;
3543                 }
3544         }
3545
3546         /*
3547          * the meta data array is already sorted by the caller
3548          */
3549         for (i=0; i < md->ctr.ctr1.count; i++) {
3550                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3551         }
3552         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3553                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3554         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3555                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3556                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3557         }
3558         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3559         if (ret != LDB_SUCCESS) {
3560                 return replmd_replicated_request_error(ar, ret);
3561         }
3562
3563         replmd_ldb_message_sort(msg, ar->schema);
3564
3565         if (DEBUGLVL(4)) {
3566                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3567                 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3568                 talloc_free(s);
3569         }
3570
3571         ret = ldb_build_add_req(&change_req,
3572                                 ldb,
3573                                 ar,
3574                                 msg,
3575                                 ar->controls,
3576                                 ar,
3577                                 replmd_op_add_callback,
3578                                 ar->req);
3579         LDB_REQ_SET_LOCATION(change_req);
3580         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3581
3582         /* current partition control needed by "repmd_op_callback" */
3583         ret = ldb_request_add_control(change_req,
3584                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3585                                       false, NULL);
3586         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3587
3588         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
3589                 /* this tells the partition module to make it a
3590                    partial replica if creating an NC */
3591                 ret = ldb_request_add_control(change_req,
3592                                               DSDB_CONTROL_PARTIAL_REPLICA,
3593                                               false, NULL);
3594                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3595         }
3596
3597         return ldb_next_request(ar->module, change_req);
3598 }
3599
3600 /*
3601   handle renames that come in over DRS replication
3602  */
3603 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
3604                                            struct ldb_message *msg,
3605                                            struct replPropertyMetaDataBlob *rmd,
3606                                            struct replPropertyMetaDataBlob *omd,
3607                                            struct ldb_request *parent)
3608 {
3609         struct replPropertyMetaData1 *md_remote;
3610         struct replPropertyMetaData1 *md_local;
3611
3612         if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3613                 /* no rename */
3614                 return LDB_SUCCESS;
3615         }
3616
3617         /* now we need to check for double renames. We could have a
3618          * local rename pending which our replication partner hasn't
3619          * received yet. We choose which one wins by looking at the
3620          * attribute stamps on the two objects, the newer one wins
3621          */
3622         md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3623         md_local  = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3624         /* if there is no name attribute then we have to assume the
3625            object we've received is in fact newer */
3626         if (!md_remote || !md_local ||
3627             replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3628                 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3629                          ldb_dn_get_linearized(ar->search_msg->dn),
3630                          ldb_dn_get_linearized(msg->dn)));
3631                 /* pass rename to the next module
3632                  * so it doesn't appear as an originating update */
3633                 return dsdb_module_rename(ar->module,
3634                                           ar->search_msg->dn, msg->dn,
3635                                           DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX, parent);
3636         }
3637
3638         /* we're going to keep our old object */
3639         DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
3640                  ldb_dn_get_linearized(ar->search_msg->dn),
3641                  ldb_dn_get_linearized(msg->dn)));
3642         return LDB_SUCCESS;
3643 }
3644
3645
3646 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
3647 {
3648         struct ldb_context *ldb;
3649         struct ldb_request *change_req;
3650         enum ndr_err_code ndr_err;
3651         struct ldb_message *msg;
3652         struct replPropertyMetaDataBlob *rmd;
3653         struct replPropertyMetaDataBlob omd;
3654         const struct ldb_val *omd_value;
3655         struct replPropertyMetaDataBlob nmd;
3656         struct ldb_val nmd_value;
3657         unsigned int i;
3658         uint32_t j,ni=0;
3659         unsigned int removed_attrs = 0;
3660         int ret;
3661
3662         ldb = ldb_module_get_ctx(ar->module);
3663         msg = ar->objs->objects[ar->index_current].msg;
3664         rmd = ar->objs->objects[ar->index_current].meta_data;
3665         ZERO_STRUCT(omd);
3666         omd.version = 1;
3667
3668         /* find existing meta data */
3669         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
3670         if (omd_value) {
3671                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
3672                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3673                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3674                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3675                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3676                 }
3677
3678                 if (omd.version != 1) {
3679                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3680                 }
3681         }
3682
3683         /* handle renames that come in over DRS */
3684         ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
3685         if (ret != LDB_SUCCESS) {
3686                 ldb_debug(ldb, LDB_DEBUG_FATAL,
3687                           "replmd_replicated_request rename %s => %s failed - %s\n",
3688                           ldb_dn_get_linearized(ar->search_msg->dn),
3689                           ldb_dn_get_linearized(msg->dn),
3690                           ldb_errstring(ldb));
3691                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
3692         }
3693
3694         ZERO_STRUCT(nmd);
3695         nmd.version = 1;
3696         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
3697         nmd.ctr.ctr1.array = talloc_array(ar,
3698                                           struct replPropertyMetaData1,
3699                                           nmd.ctr.ctr1.count);
3700         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3701
3702         /* first copy the old meta data */
3703         for (i=0; i < omd.ctr.ctr1.count; i++) {
3704                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
3705                 ni++;
3706         }
3707
3708         ar->seq_num = 0;
3709         /* now merge in the new meta data */
3710         for (i=0; i < rmd->ctr.ctr1.count; i++) {
3711                 bool found = false;
3712
3713                 for (j=0; j < ni; j++) {
3714                         bool cmp;
3715
3716                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
3717                                 continue;
3718                         }
3719
3720                         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
3721                                 /* if we compare equal then do an
3722                                    update. This is used when a client
3723                                    asks for a FULL_SYNC, and can be
3724                                    used to recover a corrupt
3725                                    replica */
3726                                 cmp = !replmd_replPropertyMetaData1_is_newer(&rmd->ctr.ctr1.array[i],
3727                                                                              &nmd.ctr.ctr1.array[j]);
3728                         } else {
3729                                 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
3730                                                                             &rmd->ctr.ctr1.array[i]);
3731                         }
3732                         if (cmp) {
3733                                 /* replace the entry */
3734                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
3735                                 if (ar->seq_num == 0) {
3736                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3737                                         if (ret != LDB_SUCCESS) {
3738                                                 return replmd_replicated_request_error(ar, ret);
3739                                         }
3740                                 }
3741                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
3742                                 found = true;
3743                                 break;
3744                         }
3745
3746                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
3747                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
3748                                          msg->elements[i-removed_attrs].name,
3749                                          ldb_dn_get_linearized(msg->dn),
3750                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
3751                         }
3752
3753                         /* we don't want to apply this change so remove the attribute */
3754                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
3755                         removed_attrs++;
3756
3757                         found = true;
3758                         break;
3759                 }
3760
3761                 if (found) continue;
3762
3763                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
3764                 if (ar->seq_num == 0) {
3765                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3766                         if (ret != LDB_SUCCESS) {
3767                                 return replmd_replicated_request_error(ar, ret);
3768                         }
3769                 }
3770                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
3771                 ni++;
3772         }
3773
3774         /*
3775          * finally correct the size of the meta_data array
3776          */
3777         nmd.ctr.ctr1.count = ni;
3778
3779         /*
3780          * the rdn attribute (the alias for the name attribute),
3781          * 'cn' for most objects is the last entry in the meta data array
3782          * we have stored
3783          *
3784          * sort the new meta data array
3785          */
3786         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
3787         if (ret != LDB_SUCCESS) {
3788                 return ret;
3789         }
3790
3791         /*
3792          * check if some replicated attributes left, otherwise skip the ldb_modify() call
3793          */
3794         if (msg->num_elements == 0) {
3795                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
3796                           ar->index_current);
3797
3798                 ar->index_current++;
3799                 return replmd_replicated_apply_next(ar);
3800         }
3801
3802         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
3803                   ar->index_current, msg->num_elements);
3804
3805         /* create the meta data value */
3806         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
3807                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3808         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3809                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3810                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3811         }
3812
3813         /*
3814          * when we know that we'll modify the record, add the whenChanged, uSNChanged
3815          * and replPopertyMetaData attributes
3816          */
3817         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3818         if (ret != LDB_SUCCESS) {
3819                 return replmd_replicated_request_error(ar, ret);
3820         }
3821         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3822         if (ret != LDB_SUCCESS) {
3823                 return replmd_replicated_request_error(ar, ret);
3824         }
3825         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
3826         if (ret != LDB_SUCCESS) {
3827                 return replmd_replicated_request_error(ar, ret);
3828         }
3829
3830         replmd_ldb_message_sort(msg, ar->schema);
3831
3832         /* we want to replace the old values */
3833         for (i=0; i < msg->num_elements; i++) {
3834                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3835         }
3836
3837         if (DEBUGLVL(4)) {
3838                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3839                 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
3840                 talloc_free(s);
3841         }
3842
3843         ret = ldb_build_mod_req(&change_req,
3844                                 ldb,
3845                                 ar,
3846                                 msg,
3847                                 ar->controls,
3848                                 ar,
3849                                 replmd_op_callback,
3850                                 ar->req);
3851         LDB_REQ_SET_LOCATION(change_req);
3852         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3853
3854         /* current partition control needed by "repmd_op_callback" */
3855         ret = ldb_request_add_control(change_req,
3856                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3857                                       false, NULL);
3858         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3859
3860         return ldb_next_request(ar->module, change_req);
3861 }
3862
3863 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
3864                                                    struct ldb_reply *ares)
3865 {
3866         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3867                                                struct replmd_replicated_request);
3868         int ret;
3869
3870         if (!ares) {
3871                 return ldb_module_done(ar->req, NULL, NULL,
3872                                         LDB_ERR_OPERATIONS_ERROR);
3873         }
3874         if (ares->error != LDB_SUCCESS &&
3875             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3876                 return ldb_module_done(ar->req, ares->controls,
3877                                         ares->response, ares->error);
3878         }
3879
3880         switch (ares->type) {
3881         case LDB_REPLY_ENTRY:
3882                 ar->search_msg = talloc_steal(ar, ares->message);
3883                 break;
3884
3885         case LDB_REPLY_REFERRAL:
3886                 /* we ignore referrals */
3887                 break;
3888
3889         case LDB_REPLY_DONE:
3890                 if (ar->search_msg != NULL) {
3891                         ret = replmd_replicated_apply_merge(ar);
3892                 } else {
3893                         ret = replmd_replicated_apply_add(ar);
3894                 }
3895                 if (ret != LDB_SUCCESS) {
3896                         return ldb_module_done(ar->req, NULL, NULL, ret);
3897                 }
3898         }
3899
3900         talloc_free(ares);
3901         return LDB_SUCCESS;
3902 }
3903
3904 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3905
3906 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3907 {
3908         struct ldb_context *ldb;
3909         int ret;
3910         char *tmp_str;
3911         char *filter;
3912         struct ldb_request *search_req;
3913         struct ldb_search_options_control *options;
3914
3915         if (ar->index_current >= ar->objs->num_objects) {
3916                 /* done with it, go to next stage */
3917                 return replmd_replicated_uptodate_vector(ar);
3918         }
3919
3920         ldb = ldb_module_get_ctx(ar->module);
3921         ar->search_msg = NULL;
3922
3923         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3924         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3925
3926         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3927         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3928         talloc_free(tmp_str);
3929
3930         ret = ldb_build_search_req(&search_req,
3931                                    ldb,
3932                                    ar,
3933                                    NULL,
3934                                    LDB_SCOPE_SUBTREE,
3935                                    filter,
3936                                    NULL,
3937                                    NULL,
3938                                    ar,
3939                                    replmd_replicated_apply_search_callback,
3940                                    ar->req);
3941         LDB_REQ_SET_LOCATION(search_req);
3942
3943         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
3944                                       true, NULL);
3945         if (ret != LDB_SUCCESS) {
3946                 return ret;
3947         }
3948
3949         /* we need to cope with cross-partition links, so search for
3950            the GUID over all partitions */
3951         options = talloc(search_req, struct ldb_search_options_control);
3952         if (options == NULL) {
3953                 DEBUG(0, (__location__ ": out of memory\n"));
3954                 return LDB_ERR_OPERATIONS_ERROR;
3955         }
3956         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3957
3958         ret = ldb_request_add_control(search_req,
3959                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
3960                                       true, options);
3961         if (ret != LDB_SUCCESS) {
3962                 return ret;
3963         }
3964
3965         return ldb_next_request(ar->module, search_req);
3966 }
3967
3968 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
3969                                                       struct ldb_reply *ares)
3970 {
3971         struct ldb_context *ldb;
3972         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3973                                                struct replmd_replicated_request);
3974         ldb = ldb_module_get_ctx(ar->module);
3975
3976         if (!ares) {
3977                 return ldb_module_done(ar->req, NULL, NULL,
3978                                         LDB_ERR_OPERATIONS_ERROR);
3979         }
3980         if (ares->error != LDB_SUCCESS) {
3981                 return ldb_module_done(ar->req, ares->controls,
3982                                         ares->response, ares->error);
3983         }
3984
3985         if (ares->type != LDB_REPLY_DONE) {
3986                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
3987                 return ldb_module_done(ar->req, NULL, NULL,
3988                                         LDB_ERR_OPERATIONS_ERROR);
3989         }
3990
3991         talloc_free(ares);
3992
3993         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3994 }
3995
3996 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3997 {
3998         struct ldb_context *ldb;
3999         struct ldb_request *change_req;
4000         enum ndr_err_code ndr_err;
4001         struct ldb_message *msg;
4002         struct replUpToDateVectorBlob ouv;
4003         const struct ldb_val *ouv_value;
4004         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
4005         struct replUpToDateVectorBlob nuv;
4006         struct ldb_val nuv_value;
4007         struct ldb_message_element *nuv_el = NULL;
4008         const struct GUID *our_invocation_id;
4009         struct ldb_message_element *orf_el = NULL;
4010         struct repsFromToBlob nrf;
4011         struct ldb_val *nrf_value = NULL;
4012         struct ldb_message_element *nrf_el = NULL;
4013         unsigned int i;
4014         uint32_t j,ni=0;
4015         bool found = false;
4016         time_t t = time(NULL);
4017         NTTIME now;
4018         int ret;
4019         uint32_t instanceType;
4020
4021         ldb = ldb_module_get_ctx(ar->module);
4022         ruv = ar->objs->uptodateness_vector;
4023         ZERO_STRUCT(ouv);
4024         ouv.version = 2;
4025         ZERO_STRUCT(nuv);
4026         nuv.version = 2;
4027
4028         unix_to_nt_time(&now, t);
4029
4030         if (ar->search_msg == NULL) {
4031                 /* this happens for a REPL_OBJ call where we are
4032                    creating the target object by replicating it. The
4033                    subdomain join code does this for the partition DN
4034                 */
4035                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
4036                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4037         }
4038
4039         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
4040         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
4041                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
4042                          ldb_dn_get_linearized(ar->search_msg->dn)));
4043                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4044         }
4045
4046         /*
4047          * first create the new replUpToDateVector
4048          */
4049         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
4050         if (ouv_value) {
4051                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
4052                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4053                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4054                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4055                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4056                 }
4057
4058                 if (ouv.version != 2) {
4059                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4060                 }
4061         }
4062
4063         /*
4064          * the new uptodateness vector will at least
4065          * contain 1 entry, one for the source_dsa
4066          *
4067          * plus optional values from our old vector and the one from the source_dsa
4068          */
4069         nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
4070         if (ruv) nuv.ctr.ctr2.count += ruv->count;
4071         nuv.ctr.ctr2.cursors = talloc_array(ar,
4072                                             struct drsuapi_DsReplicaCursor2,
4073                                             nuv.ctr.ctr2.count);
4074         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4075
4076         /* first copy the old vector */
4077         for (i=0; i < ouv.ctr.ctr2.count; i++) {
4078                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
4079                 ni++;
4080         }
4081
4082         /* get our invocation_id if we have one already attached to the ldb */
4083         our_invocation_id = samdb_ntds_invocation_id(ldb);
4084
4085         /* merge in the source_dsa vector is available */
4086         for (i=0; (ruv && i < ruv->count); i++) {
4087                 found = false;
4088
4089                 if (our_invocation_id &&
4090                     GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4091                                our_invocation_id)) {
4092                         continue;
4093                 }
4094
4095                 for (j=0; j < ni; j++) {
4096                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4097                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4098                                 continue;
4099                         }
4100
4101                         found = true;
4102
4103                         /*
4104                          * we update only the highest_usn and not the latest_sync_success time,
4105                          * because the last success stands for direct replication
4106                          */
4107                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
4108                                 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
4109                         }
4110                         break;
4111                 }
4112
4113                 if (found) continue;
4114
4115                 /* if it's not there yet, add it */
4116                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
4117                 ni++;
4118         }
4119
4120         /*
4121          * merge in the current highwatermark for the source_dsa
4122          */
4123         found = false;
4124         for (j=0; j < ni; j++) {
4125                 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
4126                                 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4127                         continue;
4128                 }
4129
4130                 found = true;
4131
4132                 /*
4133                  * here we update the highest_usn and last_sync_success time
4134                  * because we're directly replicating from the source_dsa
4135                  *
4136                  * and use the tmp_highest_usn because this is what we have just applied
4137                  * to our ldb
4138                  */
4139                 nuv.ctr.ctr2.cursors[j].highest_usn             = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4140                 nuv.ctr.ctr2.cursors[j].last_sync_success       = now;
4141                 break;
4142         }
4143         if (!found) {
4144                 /*
4145                  * here we update the highest_usn and last_sync_success time
4146                  * because we're directly replicating from the source_dsa
4147                  *
4148                  * and use the tmp_highest_usn because this is what we have just applied
4149                  * to our ldb
4150                  */
4151                 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
4152                 nuv.ctr.ctr2.cursors[ni].highest_usn            = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4153                 nuv.ctr.ctr2.cursors[ni].last_sync_success      = now;
4154                 ni++;
4155         }
4156
4157         /*
4158          * finally correct the size of the cursors array
4159          */
4160         nuv.ctr.ctr2.count = ni;
4161
4162         /*
4163          * sort the cursors
4164          */
4165         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
4166
4167         /*
4168          * create the change ldb_message
4169          */
4170         msg = ldb_msg_new(ar);
4171         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4172         msg->dn = ar->search_msg->dn;
4173
4174         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
4175                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
4176         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4177                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4178                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4179         }
4180         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
4181         if (ret != LDB_SUCCESS) {
4182                 return replmd_replicated_request_error(ar, ret);
4183         }
4184         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
4185
4186         /*
4187          * now create the new repsFrom value from the given repsFromTo1 structure
4188          */
4189         ZERO_STRUCT(nrf);
4190         nrf.version                                     = 1;
4191         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
4192         nrf.ctr.ctr1.highwatermark.highest_usn          = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
4193
4194         /*
4195          * first see if we already have a repsFrom value for the current source dsa
4196          * if so we'll later replace this value
4197          */
4198         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
4199         if (orf_el) {
4200                 for (i=0; i < orf_el->num_values; i++) {
4201                         struct repsFromToBlob *trf;
4202
4203                         trf = talloc(ar, struct repsFromToBlob);
4204                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4205
4206                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
4207                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
4208                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4209                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4210                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4211                         }
4212
4213                         if (trf->version != 1) {
4214                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4215                         }
4216
4217                         /*
4218                          * we compare the source dsa objectGUID not the invocation_id
4219                          * because we want only one repsFrom value per source dsa
4220                          * and when the invocation_id of the source dsa has changed we don't need
4221                          * the old repsFrom with the old invocation_id
4222                          */
4223                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
4224                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
4225                                 talloc_free(trf);
4226                                 continue;
4227                         }
4228
4229                         talloc_free(trf);
4230                         nrf_value = &orf_el->values[i];
4231                         break;
4232                 }
4233
4234                 /*
4235                  * copy over all old values to the new ldb_message
4236                  */
4237                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
4238                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4239                 *nrf_el = *orf_el;
4240         }
4241
4242         /*
4243          * if we haven't found an old repsFrom value for the current source dsa
4244          * we'll add a new value
4245          */
4246         if (!nrf_value) {
4247                 struct ldb_val zero_value;
4248                 ZERO_STRUCT(zero_value);
4249                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
4250                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4251
4252                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
4253         }
4254
4255         /* we now fill the value which is already attached to ldb_message */
4256         ndr_err = ndr_push_struct_blob(nrf_value, msg,
4257                                        &nrf,
4258                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
4259         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4260                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4261                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4262         }
4263
4264         /*
4265          * the ldb_message_element for the attribute, has all the old values and the new one
4266          * so we'll replace the whole attribute with all values
4267          */
4268         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
4269
4270         if (CHECK_DEBUGLVL(4)) {
4271                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4272                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
4273                 talloc_free(s);
4274         }
4275
4276         /* prepare the ldb_modify() request */
4277         ret = ldb_build_mod_req(&change_req,
4278                                 ldb,
4279                                 ar,
4280                                 msg,
4281                                 ar->controls,
4282                                 ar,
4283                                 replmd_replicated_uptodate_modify_callback,
4284                                 ar->req);
4285         LDB_REQ_SET_LOCATION(change_req);
4286         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4287
4288         return ldb_next_request(ar->module, change_req);
4289 }
4290
4291 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
4292                                                       struct ldb_reply *ares)
4293 {
4294         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4295                                                struct replmd_replicated_request);
4296         int ret;
4297
4298         if (!ares) {
4299                 return ldb_module_done(ar->req, NULL, NULL,
4300                                         LDB_ERR_OPERATIONS_ERROR);
4301         }
4302         if (ares->error != LDB_SUCCESS &&
4303             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4304                 return ldb_module_done(ar->req, ares->controls,
4305                                         ares->response, ares->error);
4306         }
4307
4308         switch (ares->type) {
4309         case LDB_REPLY_ENTRY:
4310                 ar->search_msg = talloc_steal(ar, ares->message);
4311                 break;
4312
4313         case LDB_REPLY_REFERRAL:
4314                 /* we ignore referrals */
4315                 break;
4316
4317         case LDB_REPLY_DONE:
4318                 ret = replmd_replicated_uptodate_modify(ar);
4319                 if (ret != LDB_SUCCESS) {
4320                         return ldb_module_done(ar->req, NULL, NULL, ret);
4321                 }
4322         }
4323
4324         talloc_free(ares);
4325         return LDB_SUCCESS;
4326 }
4327
4328
4329 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
4330 {
4331         struct ldb_context *ldb;
4332         int ret;
4333         static const char *attrs[] = {
4334                 "replUpToDateVector",
4335                 "repsFrom",
4336                 "instanceType",
4337                 NULL
4338         };
4339         struct ldb_request *search_req;
4340
4341         ldb = ldb_module_get_ctx(ar->module);
4342         ar->search_msg = NULL;
4343
4344         ret = ldb_build_search_req(&search_req,
4345                                    ldb,
4346                                    ar,
4347                                    ar->objs->partition_dn,
4348                                    LDB_SCOPE_BASE,
4349                                    "(objectClass=*)",
4350                                    attrs,
4351                                    NULL,
4352                                    ar,
4353                                    replmd_replicated_uptodate_search_callback,
4354                                    ar->req);
4355         LDB_REQ_SET_LOCATION(search_req);
4356         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4357
4358         return ldb_next_request(ar->module, search_req);
4359 }
4360
4361
4362
4363 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
4364 {
4365         struct ldb_context *ldb;
4366         struct dsdb_extended_replicated_objects *objs;
4367         struct replmd_replicated_request *ar;
4368         struct ldb_control **ctrls;
4369         int ret;
4370         uint32_t i;
4371         struct replmd_private *replmd_private =
4372                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4373         struct dsdb_control_replicated_update *rep_update;
4374
4375         ldb = ldb_module_get_ctx(module);
4376
4377         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
4378
4379         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
4380         if (!objs) {
4381                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
4382                 return LDB_ERR_PROTOCOL_ERROR;
4383         }
4384
4385         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
4386                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
4387                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
4388                 return LDB_ERR_PROTOCOL_ERROR;
4389         }
4390
4391         ar = replmd_ctx_init(module, req);
4392         if (!ar)
4393                 return LDB_ERR_OPERATIONS_ERROR;
4394
4395         /* Set the flags to have the replmd_op_callback run over the full set of objects */
4396         ar->apply_mode = true;
4397         ar->objs = objs;
4398         ar->schema = dsdb_get_schema(ldb, ar);
4399         if (!ar->schema) {
4400                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
4401                 talloc_free(ar);
4402                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4403                 return LDB_ERR_CONSTRAINT_VIOLATION;
4404         }
4405
4406         ctrls = req->controls;
4407
4408         if (req->controls) {
4409                 req->controls = talloc_memdup(ar, req->controls,
4410                                               talloc_get_size(req->controls));
4411                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4412         }
4413
4414         /* This allows layers further down to know if a change came in
4415            over replication and what the replication flags were */
4416         rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
4417         if (rep_update == NULL) {
4418                 return ldb_module_oom(module);
4419         }
4420         rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
4421
4422         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
4423         if (ret != LDB_SUCCESS) {
4424                 return ret;
4425         }
4426
4427         /* If this change contained linked attributes in the body
4428          * (rather than in the links section) we need to update
4429          * backlinks in linked_attributes */
4430         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
4431         if (ret != LDB_SUCCESS) {
4432                 return ret;
4433         }
4434
4435         ar->controls = req->controls;
4436         req->controls = ctrls;
4437
4438         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
4439
4440         /* save away the linked attributes for the end of the
4441            transaction */
4442         for (i=0; i<ar->objs->linked_attributes_count; i++) {
4443                 struct la_entry *la_entry;
4444
4445                 if (replmd_private->la_ctx == NULL) {
4446                         replmd_private->la_ctx = talloc_new(replmd_private);
4447                 }
4448                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
4449                 if (la_entry == NULL) {
4450                         ldb_oom(ldb);
4451                         return LDB_ERR_OPERATIONS_ERROR;
4452                 }
4453                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
4454                 if (la_entry->la == NULL) {
4455                         talloc_free(la_entry);
4456                         ldb_oom(ldb);
4457                         return LDB_ERR_OPERATIONS_ERROR;
4458                 }
4459                 *la_entry->la = ar->objs->linked_attributes[i];
4460
4461                 /* we need to steal the non-scalars so they stay
4462                    around until the end of the transaction */
4463                 talloc_steal(la_entry->la, la_entry->la->identifier);
4464                 talloc_steal(la_entry->la, la_entry->la->value.blob);
4465
4466                 DLIST_ADD(replmd_private->la_list, la_entry);
4467         }
4468
4469         return replmd_replicated_apply_next(ar);
4470 }
4471
4472 /*
4473   process one linked attribute structure
4474  */
4475 static int replmd_process_linked_attribute(struct ldb_module *module,
4476                                            struct la_entry *la_entry,
4477                                            struct ldb_request *parent)
4478 {
4479         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
4480         struct ldb_context *ldb = ldb_module_get_ctx(module);
4481         struct ldb_message *msg;
4482         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
4483         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
4484         int ret;
4485         const struct dsdb_attribute *attr;
4486         struct dsdb_dn *dsdb_dn;
4487         uint64_t seq_num = 0;
4488         struct ldb_message_element *old_el;
4489         WERROR status;
4490         time_t t = time(NULL);
4491         struct ldb_result *res;
4492         const char *attrs[2];
4493         struct parsed_dn *pdn_list, *pdn;
4494         struct GUID guid = GUID_zero();
4495         NTSTATUS ntstatus;
4496         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
4497         const struct GUID *our_invocation_id;
4498
4499 /*
4500 linked_attributes[0]:
4501      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
4502         identifier               : *
4503             identifier: struct drsuapi_DsReplicaObjectIdentifier
4504                 __ndr_size               : 0x0000003a (58)
4505                 __ndr_size_sid           : 0x00000000 (0)
4506                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
4507                 sid                      : S-0-0
4508                 __ndr_size_dn            : 0x00000000 (0)
4509                 dn                       : ''
4510         attid                    : DRSUAPI_ATTID_member (0x1F)
4511         value: struct drsuapi_DsAttributeValue
4512             __ndr_size               : 0x0000007e (126)
4513             blob                     : *
4514                 blob                     : DATA_BLOB length=126
4515         flags                    : 0x00000001 (1)
4516                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
4517         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
4518         meta_data: struct drsuapi_DsReplicaMetaData
4519             version                  : 0x00000015 (21)
4520             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
4521             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
4522             originating_usn          : 0x000000000001e19c (123292)
4523
4524 (for cases where the link is to a normal DN)
4525      &target: struct drsuapi_DsReplicaObjectIdentifier3
4526         __ndr_size               : 0x0000007e (126)
4527         __ndr_size_sid           : 0x0000001c (28)
4528         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
4529         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
4530         __ndr_size_dn            : 0x00000022 (34)
4531         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
4532  */
4533
4534         /* find the attribute being modified */
4535         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
4536         if (attr == NULL) {
4537                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
4538                 talloc_free(tmp_ctx);
4539                 return LDB_ERR_OPERATIONS_ERROR;
4540         }
4541
4542         attrs[0] = attr->lDAPDisplayName;
4543         attrs[1] = NULL;
4544
4545         /* get the existing message from the db for the object with
4546            this GUID, returning attribute being modified. We will then
4547            use this msg as the basis for a modify call */
4548         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
4549                                  DSDB_FLAG_NEXT_MODULE |
4550                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
4551                                  DSDB_SEARCH_SHOW_RECYCLED |
4552                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4553                                  DSDB_SEARCH_REVEAL_INTERNALS,
4554                                  parent,
4555                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
4556         if (ret != LDB_SUCCESS) {
4557                 talloc_free(tmp_ctx);
4558                 return ret;
4559         }
4560         if (res->count != 1) {
4561                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
4562                                        GUID_string(tmp_ctx, &la->identifier->guid));
4563                 talloc_free(tmp_ctx);
4564                 return LDB_ERR_NO_SUCH_OBJECT;
4565         }
4566         msg = res->msgs[0];
4567
4568         if (msg->num_elements == 0) {
4569                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
4570                 if (ret != LDB_SUCCESS) {
4571                         ldb_module_oom(module);
4572                         talloc_free(tmp_ctx);
4573                         return LDB_ERR_OPERATIONS_ERROR;
4574                 }
4575         } else {
4576                 old_el = &msg->elements[0];
4577                 old_el->flags = LDB_FLAG_MOD_REPLACE;
4578         }
4579
4580         /* parse the existing links */
4581         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
4582         if (ret != LDB_SUCCESS) {
4583                 talloc_free(tmp_ctx);
4584                 return ret;
4585         }
4586
4587         /* get our invocationId */
4588         our_invocation_id = samdb_ntds_invocation_id(ldb);
4589         if (!our_invocation_id) {
4590                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
4591                 talloc_free(tmp_ctx);
4592                 return LDB_ERR_OPERATIONS_ERROR;
4593         }
4594
4595         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
4596         if (ret != LDB_SUCCESS) {
4597                 talloc_free(tmp_ctx);
4598                 return ret;
4599         }
4600
4601         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
4602         if (!W_ERROR_IS_OK(status)) {
4603                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
4604                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
4605                 return LDB_ERR_OPERATIONS_ERROR;
4606         }
4607
4608         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
4609         if (!NT_STATUS_IS_OK(ntstatus) && active) {
4610                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
4611                                        old_el->name,
4612                                        ldb_dn_get_linearized(dsdb_dn->dn),
4613                                        ldb_dn_get_linearized(msg->dn));
4614                 return LDB_ERR_OPERATIONS_ERROR;
4615         }
4616
4617         /* re-resolve the DN by GUID, as the DRS server may give us an
4618            old DN value */
4619         ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
4620         if (ret != LDB_SUCCESS) {
4621                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
4622                          GUID_string(tmp_ctx, &guid),
4623                          ldb_dn_get_linearized(dsdb_dn->dn)));
4624         }
4625
4626         /* see if this link already exists */
4627         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
4628         if (pdn != NULL) {
4629                 /* see if this update is newer than what we have already */
4630                 struct GUID invocation_id = GUID_zero();
4631                 uint32_t version = 0;
4632                 uint32_t originating_usn = 0;
4633                 NTTIME change_time = 0;
4634                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
4635
4636                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
4637                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
4638                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
4639                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
4640
4641                 if (!replmd_update_is_newer(&invocation_id,
4642                                             &la->meta_data.originating_invocation_id,
4643                                             version,
4644                                             la->meta_data.version,
4645                                             change_time,
4646                                             la->meta_data.originating_change_time)) {
4647                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
4648                                  old_el->name, ldb_dn_get_linearized(msg->dn),
4649                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
4650                         talloc_free(tmp_ctx);
4651                         return LDB_SUCCESS;
4652                 }
4653
4654                 /* get a seq_num for this change */
4655                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4656                 if (ret != LDB_SUCCESS) {
4657                         talloc_free(tmp_ctx);
4658                         return ret;
4659                 }
4660
4661                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
4662                         /* remove the existing backlink */
4663                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
4664                         if (ret != LDB_SUCCESS) {
4665                                 talloc_free(tmp_ctx);
4666                                 return ret;
4667                         }
4668                 }
4669
4670                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
4671                                            &la->meta_data.originating_invocation_id,
4672                                            la->meta_data.originating_usn, seq_num,
4673                                            la->meta_data.originating_change_time,
4674                                            la->meta_data.version,
4675                                            !active);
4676                 if (ret != LDB_SUCCESS) {
4677                         talloc_free(tmp_ctx);
4678                         return ret;
4679                 }
4680
4681                 if (active) {
4682                         /* add the new backlink */
4683                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
4684                         if (ret != LDB_SUCCESS) {
4685                                 talloc_free(tmp_ctx);
4686                                 return ret;
4687                         }
4688                 }
4689         } else {
4690                 /* get a seq_num for this change */
4691                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4692                 if (ret != LDB_SUCCESS) {
4693                         talloc_free(tmp_ctx);
4694                         return ret;
4695                 }
4696
4697                 old_el->values = talloc_realloc(msg->elements, old_el->values,
4698                                                 struct ldb_val, old_el->num_values+1);
4699                 if (!old_el->values) {
4700                         ldb_module_oom(module);
4701                         return LDB_ERR_OPERATIONS_ERROR;
4702                 }
4703                 old_el->num_values++;
4704
4705                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
4706                                           &la->meta_data.originating_invocation_id,
4707                                           la->meta_data.originating_usn, seq_num,
4708                                           la->meta_data.originating_change_time,
4709                                           la->meta_data.version,
4710                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
4711                 if (ret != LDB_SUCCESS) {
4712                         talloc_free(tmp_ctx);
4713                         return ret;
4714                 }
4715
4716                 if (active) {
4717                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
4718                                                   true, attr, false);
4719                         if (ret != LDB_SUCCESS) {
4720                                 talloc_free(tmp_ctx);
4721                                 return ret;
4722                         }
4723                 }
4724         }
4725
4726         /* we only change whenChanged and uSNChanged if the seq_num
4727            has changed */
4728         ret = add_time_element(msg, "whenChanged", t);
4729         if (ret != LDB_SUCCESS) {
4730                 talloc_free(tmp_ctx);
4731                 ldb_operr(ldb);
4732                 return ret;
4733         }
4734
4735         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
4736         if (ret != LDB_SUCCESS) {
4737                 talloc_free(tmp_ctx);
4738                 ldb_operr(ldb);
4739                 return ret;
4740         }
4741
4742         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
4743         if (old_el == NULL) {
4744                 talloc_free(tmp_ctx);
4745                 return ldb_operr(ldb);
4746         }
4747
4748         ret = dsdb_check_single_valued_link(attr, old_el);
4749         if (ret != LDB_SUCCESS) {
4750                 talloc_free(tmp_ctx);
4751                 return ret;
4752         }
4753
4754         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
4755
4756         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
4757         if (ret != LDB_SUCCESS) {
4758                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
4759                           ldb_errstring(ldb),
4760                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
4761                 talloc_free(tmp_ctx);
4762                 return ret;
4763         }
4764
4765         talloc_free(tmp_ctx);
4766
4767         return ret;
4768 }
4769
4770 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
4771 {
4772         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
4773                 return replmd_extended_replicated_objects(module, req);
4774         }
4775
4776         return ldb_next_request(module, req);
4777 }
4778
4779
4780 /*
4781   we hook into the transaction operations to allow us to
4782   perform the linked attribute updates at the end of the whole
4783   transaction. This allows a forward linked attribute to be created
4784   before the object is created. During a vampire, w2k8 sends us linked
4785   attributes before the objects they are part of.
4786  */
4787 static int replmd_start_transaction(struct ldb_module *module)
4788 {
4789         /* create our private structure for this transaction */
4790         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
4791                                                                 struct replmd_private);
4792         replmd_txn_cleanup(replmd_private);
4793
4794         /* free any leftover mod_usn records from cancelled
4795            transactions */
4796         while (replmd_private->ncs) {
4797                 struct nc_entry *e = replmd_private->ncs;
4798                 DLIST_REMOVE(replmd_private->ncs, e);
4799                 talloc_free(e);
4800         }
4801
4802         return ldb_next_start_trans(module);
4803 }
4804
4805 /*
4806   on prepare commit we loop over our queued la_context structures and
4807   apply each of them
4808  */
4809 static int replmd_prepare_commit(struct ldb_module *module)
4810 {
4811         struct replmd_private *replmd_private =
4812                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4813         struct la_entry *la, *prev;
4814         struct la_backlink *bl;
4815         int ret;
4816
4817         /* walk the list backwards, to do the first entry first, as we
4818          * added the entries with DLIST_ADD() which puts them at the
4819          * start of the list */
4820         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
4821                 prev = DLIST_PREV(la);
4822                 DLIST_REMOVE(replmd_private->la_list, la);
4823                 ret = replmd_process_linked_attribute(module, la, NULL);
4824                 if (ret != LDB_SUCCESS) {
4825                         replmd_txn_cleanup(replmd_private);
4826                         return ret;
4827                 }
4828         }
4829
4830         /* process our backlink list, creating and deleting backlinks
4831            as necessary */
4832         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
4833                 ret = replmd_process_backlink(module, bl, NULL);
4834                 if (ret != LDB_SUCCESS) {
4835                         replmd_txn_cleanup(replmd_private);
4836                         return ret;
4837                 }
4838         }
4839
4840         replmd_txn_cleanup(replmd_private);
4841
4842         /* possibly change @REPLCHANGED */
4843         ret = replmd_notify_store(module, NULL);
4844         if (ret != LDB_SUCCESS) {
4845                 return ret;
4846         }
4847
4848         return ldb_next_prepare_commit(module);
4849 }
4850
4851 static int replmd_del_transaction(struct ldb_module *module)
4852 {
4853         struct replmd_private *replmd_private =
4854                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4855         replmd_txn_cleanup(replmd_private);
4856
4857         return ldb_next_del_trans(module);
4858 }
4859
4860
4861 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
4862         .name          = "repl_meta_data",
4863         .init_context      = replmd_init,
4864         .add               = replmd_add,
4865         .modify            = replmd_modify,
4866         .rename            = replmd_rename,
4867         .del               = replmd_delete,
4868         .extended          = replmd_extended,
4869         .start_transaction = replmd_start_transaction,
4870         .prepare_commit    = replmd_prepare_commit,
4871         .del_transaction   = replmd_del_transaction,
4872 };
4873
4874 int ldb_repl_meta_data_module_init(const char *version)
4875 {
4876         LDB_MODULE_CHECK_VERSION(version);
4877         return ldb_register_module(&ldb_repl_meta_data_module_ops);
4878 }