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