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