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