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