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