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