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