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