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