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