s4:dsdb/repl_meta_data: normalize the rdn attribute name based on the schema
[obnox/samba/samba-obnox.git] / source4 / dsdb / samdb / ldb_modules / repl_meta_data.c
1 /*
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8    Copyright (C) Matthieu Patou <mat@samba.org> 2010
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb repl_meta_data module
28  *
29  *  Description: - add a unique objectGUID onto every new record,
30  *               - handle whenCreated, whenChanged timestamps
31  *               - handle uSNCreated, uSNChanged numbers
32  *               - handle replPropertyMetaData attribute
33  *
34  *  Author: Simo Sorce
35  *  Author: Stefan Metzmacher
36  */
37
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "../libds/common/flags.h"
43 #include "librpc/gen_ndr/ndr_misc.h"
44 #include "librpc/gen_ndr/ndr_drsuapi.h"
45 #include "librpc/gen_ndr/ndr_drsblobs.h"
46 #include "param/param.h"
47 #include "libcli/security/security.h"
48 #include "lib/util/dlinklist.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
50 #include "lib/util/binsearch.h"
51 #include "lib/util/tsort.h"
52
53 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                               struct ldb_message *msg, uint64_t *seq_num,
1130                               time_t t,
1131                               bool *is_urgent)
1132 {
1133         const struct ldb_val *omd_value;
1134         enum ndr_err_code ndr_err;
1135         struct replPropertyMetaDataBlob omd;
1136         unsigned int i;
1137         NTTIME now;
1138         const struct GUID *our_invocation_id;
1139         int ret;
1140         const char *attrs[] = { "replPropertyMetaData", "*", NULL };
1141         const char *attrs2[] = { "uSNChanged", "objectClass", NULL };
1142         struct ldb_result *res;
1143         struct ldb_context *ldb;
1144         struct ldb_message_element *objectclass_el;
1145         enum urgent_situation situation;
1146         bool rodc, rmd_is_provided;
1147
1148         ldb = ldb_module_get_ctx(module);
1149
1150         our_invocation_id = samdb_ntds_invocation_id(ldb);
1151         if (!our_invocation_id) {
1152                 /* this happens during an initial vampire while
1153                    updating the schema */
1154                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1155                 return LDB_SUCCESS;
1156         }
1157
1158         unix_to_nt_time(&now, t);
1159
1160         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1161                 rmd_is_provided = true;
1162         } else {
1163                 rmd_is_provided = false;
1164         }
1165
1166         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1167          * otherwise we consider we are updating */
1168         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1169                 situation = REPL_URGENT_ON_DELETE;
1170         } else {
1171                 situation = REPL_URGENT_ON_UPDATE;
1172         }
1173
1174         if (rmd_is_provided) {
1175                 /* In this case the change_replmetadata control was supplied */
1176                 /* We check that it's the only attribute that is provided
1177                  * (it's a rare case so it's better to keep the code simplier)
1178                  * We also check that the highest local_usn is bigger than
1179                  * uSNChanged. */
1180                 uint64_t db_seq;
1181                 if( msg->num_elements != 1 ||
1182                         strncmp(msg->elements[0].name,
1183                                 "replPropertyMetaData", 20) ) {
1184                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1185                                 "a specified replPropertyMetaData attribute or with others\n"));
1186                         return LDB_ERR_OPERATIONS_ERROR;
1187                 }
1188                 if (situation == REPL_URGENT_ON_DELETE) {
1189                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1190                         return LDB_ERR_OPERATIONS_ERROR;
1191                 }
1192                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1193                 if (!omd_value) {
1194                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1195                                  ldb_dn_get_linearized(msg->dn)));
1196                         return LDB_ERR_OPERATIONS_ERROR;
1197                 }
1198                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1199                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1200                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1201                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1202                                  ldb_dn_get_linearized(msg->dn)));
1203                         return LDB_ERR_OPERATIONS_ERROR;
1204                 }
1205                 *seq_num = find_max_local_usn(omd);
1206
1207                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1208                                             DSDB_FLAG_NEXT_MODULE |
1209                                             DSDB_SEARCH_SHOW_RECYCLED |
1210                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1211                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1212                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1213
1214                 if (ret != LDB_SUCCESS || res->count != 1) {
1215                         DEBUG(0,(__location__ ": Object %s failed to find uSNChanged\n",
1216                                  ldb_dn_get_linearized(msg->dn)));
1217                         return LDB_ERR_OPERATIONS_ERROR;
1218                 }
1219
1220                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1221                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1222                                                                 situation)) {
1223                         *is_urgent = true;
1224                 }
1225
1226                 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1227                 if (*seq_num <= db_seq) {
1228                         DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\
1229                                               " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n",
1230                                  (long long)*seq_num, (long long)db_seq));
1231                         return LDB_ERR_OPERATIONS_ERROR;
1232                 }
1233
1234         } else {
1235                 /* search for the existing replPropertyMetaDataBlob. We need
1236                  * to use REVEAL and ask for DNs in storage format to support
1237                  * the check for values being the same in
1238                  * replmd_update_rpmd_element()
1239                  */
1240                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1241                                             DSDB_FLAG_NEXT_MODULE |
1242                                             DSDB_SEARCH_SHOW_RECYCLED |
1243                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1244                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1245                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1246                 if (ret != LDB_SUCCESS || res->count != 1) {
1247                         DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1248                                  ldb_dn_get_linearized(msg->dn)));
1249                         return LDB_ERR_OPERATIONS_ERROR;
1250                 }
1251
1252                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1253                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1254                                                                 situation)) {
1255                         *is_urgent = true;
1256                 }
1257
1258                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1259                 if (!omd_value) {
1260                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1261                                  ldb_dn_get_linearized(msg->dn)));
1262                         return LDB_ERR_OPERATIONS_ERROR;
1263                 }
1264
1265                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1266                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1267                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1268                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1269                                  ldb_dn_get_linearized(msg->dn)));
1270                         return LDB_ERR_OPERATIONS_ERROR;
1271                 }
1272
1273                 if (omd.version != 1) {
1274                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1275                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1276                         return LDB_ERR_OPERATIONS_ERROR;
1277                 }
1278
1279                 for (i=0; i<msg->num_elements; i++) {
1280                         struct ldb_message_element *old_el;
1281                         old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1282                         ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1283                                                          our_invocation_id, now);
1284                         if (ret != LDB_SUCCESS) {
1285                                 return ret;
1286                         }
1287
1288                         if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1289                                 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1290                         }
1291
1292                 }
1293         }
1294         /*
1295          * replmd_update_rpmd_element has done an update if the
1296          * seq_num is set
1297          */
1298         if (*seq_num != 0) {
1299                 struct ldb_val *md_value;
1300                 struct ldb_message_element *el;
1301
1302                 /*if we are RODC and this is a DRSR update then its ok*/
1303                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1304                         ret = samdb_rodc(ldb, &rodc);
1305                         if (ret != LDB_SUCCESS) {
1306                                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1307                         } else if (rodc) {
1308                                 ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n");
1309                                 return LDB_ERR_REFERRAL;
1310                         }
1311                 }
1312
1313                 md_value = talloc(msg, struct ldb_val);
1314                 if (md_value == NULL) {
1315                         ldb_oom(ldb);
1316                         return LDB_ERR_OPERATIONS_ERROR;
1317                 }
1318
1319                 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1320                 if (ret != LDB_SUCCESS) {
1321                         return ret;
1322                 }
1323
1324                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1325                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1326                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1327                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1328                                  ldb_dn_get_linearized(msg->dn)));
1329                         return LDB_ERR_OPERATIONS_ERROR;
1330                 }
1331
1332                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1333                 if (ret != LDB_SUCCESS) {
1334                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1335                                  ldb_dn_get_linearized(msg->dn)));
1336                         return ret;
1337                 }
1338
1339                 el->num_values = 1;
1340                 el->values = md_value;
1341         }
1342
1343         return LDB_SUCCESS;
1344 }
1345
1346 struct parsed_dn {
1347         struct dsdb_dn *dsdb_dn;
1348         struct GUID *guid;
1349         struct ldb_val *v;
1350 };
1351
1352 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1353 {
1354         return GUID_compare(pdn1->guid, pdn2->guid);
1355 }
1356
1357 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1358                                         unsigned int count, struct GUID *guid,
1359                                         struct ldb_dn *dn)
1360 {
1361         struct parsed_dn *ret;
1362         unsigned int i;
1363         if (dn && GUID_all_zero(guid)) {
1364                 /* when updating a link using DRS, we sometimes get a
1365                    NULL GUID. We then need to try and match by DN */
1366                 for (i=0; i<count; i++) {
1367                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1368                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1369                                 return &pdn[i];
1370                         }
1371                 }
1372                 return NULL;
1373         }
1374         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1375         return ret;
1376 }
1377
1378 /*
1379   get a series of message element values as an array of DNs and GUIDs
1380   the result is sorted by GUID
1381  */
1382 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1383                           struct ldb_message_element *el, struct parsed_dn **pdn,
1384                           const char *ldap_oid, struct ldb_request *parent)
1385 {
1386         unsigned int i;
1387         struct ldb_context *ldb = ldb_module_get_ctx(module);
1388
1389         if (el == NULL) {
1390                 *pdn = NULL;
1391                 return LDB_SUCCESS;
1392         }
1393
1394         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1395         if (!*pdn) {
1396                 ldb_module_oom(module);
1397                 return LDB_ERR_OPERATIONS_ERROR;
1398         }
1399
1400         for (i=0; i<el->num_values; i++) {
1401                 struct ldb_val *v = &el->values[i];
1402                 NTSTATUS status;
1403                 struct ldb_dn *dn;
1404                 struct parsed_dn *p;
1405
1406                 p = &(*pdn)[i];
1407
1408                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1409                 if (p->dsdb_dn == NULL) {
1410                         return LDB_ERR_INVALID_DN_SYNTAX;
1411                 }
1412
1413                 dn = p->dsdb_dn->dn;
1414
1415                 p->guid = talloc(*pdn, struct GUID);
1416                 if (p->guid == NULL) {
1417                         ldb_module_oom(module);
1418                         return LDB_ERR_OPERATIONS_ERROR;
1419                 }
1420
1421                 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1422                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1423                         /* we got a DN without a GUID - go find the GUID */
1424                         int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1425                         if (ret != LDB_SUCCESS) {
1426                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1427                                                        ldb_dn_get_linearized(dn));
1428                                 return ret;
1429                         }
1430                         ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1431                         if (ret != LDB_SUCCESS) {
1432                                 return ret;
1433                         }
1434                 } else if (!NT_STATUS_IS_OK(status)) {
1435                         return LDB_ERR_OPERATIONS_ERROR;
1436                 }
1437
1438                 /* keep a pointer to the original ldb_val */
1439                 p->v = v;
1440         }
1441
1442         TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1443
1444         return LDB_SUCCESS;
1445 }
1446
1447 /*
1448   build a new extended DN, including all meta data fields
1449
1450   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1451   RMD_ADDTIME         = originating_add_time
1452   RMD_INVOCID         = originating_invocation_id
1453   RMD_CHANGETIME      = originating_change_time
1454   RMD_ORIGINATING_USN = originating_usn
1455   RMD_LOCAL_USN       = local_usn
1456   RMD_VERSION         = version
1457  */
1458 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1459                                const struct GUID *invocation_id, uint64_t seq_num,
1460                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1461 {
1462         struct ldb_dn *dn = dsdb_dn->dn;
1463         const char *tstring, *usn_string, *flags_string;
1464         struct ldb_val tval;
1465         struct ldb_val iid;
1466         struct ldb_val usnv, local_usnv;
1467         struct ldb_val vers, flagsv;
1468         NTSTATUS status;
1469         int ret;
1470         const char *dnstring;
1471         char *vstring;
1472         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1473
1474         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1475         if (!tstring) {
1476                 return LDB_ERR_OPERATIONS_ERROR;
1477         }
1478         tval = data_blob_string_const(tstring);
1479
1480         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1481         if (!usn_string) {
1482                 return LDB_ERR_OPERATIONS_ERROR;
1483         }
1484         usnv = data_blob_string_const(usn_string);
1485
1486         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1487         if (!usn_string) {
1488                 return LDB_ERR_OPERATIONS_ERROR;
1489         }
1490         local_usnv = data_blob_string_const(usn_string);
1491
1492         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1493         if (!vstring) {
1494                 return LDB_ERR_OPERATIONS_ERROR;
1495         }
1496         vers = data_blob_string_const(vstring);
1497
1498         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1499         if (!NT_STATUS_IS_OK(status)) {
1500                 return LDB_ERR_OPERATIONS_ERROR;
1501         }
1502
1503         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1504         if (!flags_string) {
1505                 return LDB_ERR_OPERATIONS_ERROR;
1506         }
1507         flagsv = data_blob_string_const(flags_string);
1508
1509         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1510         if (ret != LDB_SUCCESS) return ret;
1511         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1512         if (ret != LDB_SUCCESS) return ret;
1513         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1514         if (ret != LDB_SUCCESS) return ret;
1515         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1516         if (ret != LDB_SUCCESS) return ret;
1517         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1518         if (ret != LDB_SUCCESS) return ret;
1519         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1520         if (ret != LDB_SUCCESS) return ret;
1521         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1522         if (ret != LDB_SUCCESS) return ret;
1523
1524         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1525         if (dnstring == NULL) {
1526                 return LDB_ERR_OPERATIONS_ERROR;
1527         }
1528         *v = data_blob_string_const(dnstring);
1529
1530         return LDB_SUCCESS;
1531 }
1532
1533 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1534                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1535                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1536                                 uint32_t version, bool deleted);
1537
1538 /*
1539   check if any links need upgrading from w2k format
1540
1541   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.
1542  */
1543 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1544 {
1545         uint32_t i;
1546         for (i=0; i<count; i++) {
1547                 NTSTATUS status;
1548                 uint32_t version;
1549                 int ret;
1550
1551                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1552                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1553                         continue;
1554                 }
1555
1556                 /* it's an old one that needs upgrading */
1557                 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1558                                            1, 1, 0, 0, false);
1559                 if (ret != LDB_SUCCESS) {
1560                         return ret;
1561                 }
1562         }
1563         return LDB_SUCCESS;
1564 }
1565
1566 /*
1567   update an extended DN, including all meta data fields
1568
1569   see replmd_build_la_val for value names
1570  */
1571 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1572                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1573                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1574                                 uint32_t version, bool deleted)
1575 {
1576         struct ldb_dn *dn = dsdb_dn->dn;
1577         const char *tstring, *usn_string, *flags_string;
1578         struct ldb_val tval;
1579         struct ldb_val iid;
1580         struct ldb_val usnv, local_usnv;
1581         struct ldb_val vers, flagsv;
1582         const struct ldb_val *old_addtime;
1583         uint32_t old_version;
1584         NTSTATUS status;
1585         int ret;
1586         const char *dnstring;
1587         char *vstring;
1588         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1589
1590         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1591         if (!tstring) {
1592                 return LDB_ERR_OPERATIONS_ERROR;
1593         }
1594         tval = data_blob_string_const(tstring);
1595
1596         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1597         if (!usn_string) {
1598                 return LDB_ERR_OPERATIONS_ERROR;
1599         }
1600         usnv = data_blob_string_const(usn_string);
1601
1602         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1603         if (!usn_string) {
1604                 return LDB_ERR_OPERATIONS_ERROR;
1605         }
1606         local_usnv = data_blob_string_const(usn_string);
1607
1608         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1609         if (!NT_STATUS_IS_OK(status)) {
1610                 return LDB_ERR_OPERATIONS_ERROR;
1611         }
1612
1613         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1614         if (!flags_string) {
1615                 return LDB_ERR_OPERATIONS_ERROR;
1616         }
1617         flagsv = data_blob_string_const(flags_string);
1618
1619         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1620         if (ret != LDB_SUCCESS) return ret;
1621
1622         /* get the ADDTIME from the original */
1623         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1624         if (old_addtime == NULL) {
1625                 old_addtime = &tval;
1626         }
1627         if (dsdb_dn != old_dsdb_dn) {
1628                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1629                 if (ret != LDB_SUCCESS) return ret;
1630         }
1631
1632         /* use our invocation id */
1633         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1634         if (ret != LDB_SUCCESS) return ret;
1635
1636         /* changetime is the current time */
1637         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1638         if (ret != LDB_SUCCESS) return ret;
1639
1640         /* update the USN */
1641         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1642         if (ret != LDB_SUCCESS) return ret;
1643
1644         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1645         if (ret != LDB_SUCCESS) return ret;
1646
1647         /* increase the version by 1 */
1648         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1649         if (NT_STATUS_IS_OK(status) && old_version >= version) {
1650                 version = old_version+1;
1651         }
1652         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1653         vers = data_blob_string_const(vstring);
1654         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1655         if (ret != LDB_SUCCESS) return ret;
1656
1657         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1658         if (dnstring == NULL) {
1659                 return LDB_ERR_OPERATIONS_ERROR;
1660         }
1661         *v = data_blob_string_const(dnstring);
1662
1663         return LDB_SUCCESS;
1664 }
1665
1666 /*
1667   handle adding a linked attribute
1668  */
1669 static int replmd_modify_la_add(struct ldb_module *module,
1670                                 const struct dsdb_schema *schema,
1671                                 struct ldb_message *msg,
1672                                 struct ldb_message_element *el,
1673                                 struct ldb_message_element *old_el,
1674                                 const struct dsdb_attribute *schema_attr,
1675                                 uint64_t seq_num,
1676                                 time_t t,
1677                                 struct GUID *msg_guid,
1678                                 struct ldb_request *parent)
1679 {
1680         unsigned int i;
1681         struct parsed_dn *dns, *old_dns;
1682         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1683         int ret;
1684         struct ldb_val *new_values = NULL;
1685         unsigned int num_new_values = 0;
1686         unsigned old_num_values = old_el?old_el->num_values:0;
1687         const struct GUID *invocation_id;
1688         struct ldb_context *ldb = ldb_module_get_ctx(module);
1689         NTTIME now;
1690
1691         unix_to_nt_time(&now, t);
1692
1693         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1694         if (ret != LDB_SUCCESS) {
1695                 talloc_free(tmp_ctx);
1696                 return ret;
1697         }
1698
1699         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1700         if (ret != LDB_SUCCESS) {
1701                 talloc_free(tmp_ctx);
1702                 return ret;
1703         }
1704
1705         invocation_id = samdb_ntds_invocation_id(ldb);
1706         if (!invocation_id) {
1707                 talloc_free(tmp_ctx);
1708                 return LDB_ERR_OPERATIONS_ERROR;
1709         }
1710
1711         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1712         if (ret != LDB_SUCCESS) {
1713                 talloc_free(tmp_ctx);
1714                 return ret;
1715         }
1716
1717         /* for each new value, see if it exists already with the same GUID */
1718         for (i=0; i<el->num_values; i++) {
1719                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1720                 if (p == NULL) {
1721                         /* this is a new linked attribute value */
1722                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1723                         if (new_values == NULL) {
1724                                 ldb_module_oom(module);
1725                                 talloc_free(tmp_ctx);
1726                                 return LDB_ERR_OPERATIONS_ERROR;
1727                         }
1728                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1729                                                   invocation_id, seq_num, seq_num, now, 0, false);
1730                         if (ret != LDB_SUCCESS) {
1731                                 talloc_free(tmp_ctx);
1732                                 return ret;
1733                         }
1734                         num_new_values++;
1735                 } else {
1736                         /* this is only allowed if the GUID was
1737                            previously deleted. */
1738                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1739
1740                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1741                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1742                                                        el->name, GUID_string(tmp_ctx, p->guid));
1743                                 talloc_free(tmp_ctx);
1744                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1745                         }
1746                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1747                                                    invocation_id, seq_num, seq_num, now, 0, false);
1748                         if (ret != LDB_SUCCESS) {
1749                                 talloc_free(tmp_ctx);
1750                                 return ret;
1751                         }
1752                 }
1753
1754                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1755                 if (ret != LDB_SUCCESS) {
1756                         talloc_free(tmp_ctx);
1757                         return ret;
1758                 }
1759         }
1760
1761         /* add the new ones on to the end of the old values, constructing a new el->values */
1762         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1763                                     struct ldb_val,
1764                                     old_num_values+num_new_values);
1765         if (el->values == NULL) {
1766                 ldb_module_oom(module);
1767                 return LDB_ERR_OPERATIONS_ERROR;
1768         }
1769
1770         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1771         el->num_values = old_num_values + num_new_values;
1772
1773         talloc_steal(msg->elements, el->values);
1774         talloc_steal(el->values, new_values);
1775
1776         talloc_free(tmp_ctx);
1777
1778         /* we now tell the backend to replace all existing values
1779            with the one we have constructed */
1780         el->flags = LDB_FLAG_MOD_REPLACE;
1781
1782         return LDB_SUCCESS;
1783 }
1784
1785
1786 /*
1787   handle deleting all active linked attributes
1788  */
1789 static int replmd_modify_la_delete(struct ldb_module *module,
1790                                    const struct dsdb_schema *schema,
1791                                    struct ldb_message *msg,
1792                                    struct ldb_message_element *el,
1793                                    struct ldb_message_element *old_el,
1794                                    const struct dsdb_attribute *schema_attr,
1795                                    uint64_t seq_num,
1796                                    time_t t,
1797                                    struct GUID *msg_guid,
1798                                    struct ldb_request *parent)
1799 {
1800         unsigned int i;
1801         struct parsed_dn *dns, *old_dns;
1802         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1803         int ret;
1804         const struct GUID *invocation_id;
1805         struct ldb_context *ldb = ldb_module_get_ctx(module);
1806         NTTIME now;
1807
1808         unix_to_nt_time(&now, t);
1809
1810         /* check if there is nothing to delete */
1811         if ((!old_el || old_el->num_values == 0) &&
1812             el->num_values == 0) {
1813                 return LDB_SUCCESS;
1814         }
1815
1816         if (!old_el || old_el->num_values == 0) {
1817                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1818         }
1819
1820         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1821         if (ret != LDB_SUCCESS) {
1822                 talloc_free(tmp_ctx);
1823                 return ret;
1824         }
1825
1826         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1827         if (ret != LDB_SUCCESS) {
1828                 talloc_free(tmp_ctx);
1829                 return ret;
1830         }
1831
1832         invocation_id = samdb_ntds_invocation_id(ldb);
1833         if (!invocation_id) {
1834                 return LDB_ERR_OPERATIONS_ERROR;
1835         }
1836
1837         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1838         if (ret != LDB_SUCCESS) {
1839                 talloc_free(tmp_ctx);
1840                 return ret;
1841         }
1842
1843         el->values = NULL;
1844
1845         /* see if we are being asked to delete any links that
1846            don't exist or are already deleted */
1847         for (i=0; i<el->num_values; i++) {
1848                 struct parsed_dn *p = &dns[i];
1849                 struct parsed_dn *p2;
1850                 uint32_t rmd_flags;
1851
1852                 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1853                 if (!p2) {
1854                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1855                                                el->name, GUID_string(tmp_ctx, p->guid));
1856                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
1857                 }
1858                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1859                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1860                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1861                                                el->name, GUID_string(tmp_ctx, p->guid));
1862                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
1863                 }
1864         }
1865
1866         /* for each new value, see if it exists already with the same GUID
1867            if it is not already deleted and matches the delete list then delete it
1868         */
1869         for (i=0; i<old_el->num_values; i++) {
1870                 struct parsed_dn *p = &old_dns[i];
1871                 uint32_t rmd_flags;
1872
1873                 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1874                         continue;
1875                 }
1876
1877                 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1878                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1879
1880                 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1881                                            invocation_id, seq_num, seq_num, now, 0, true);
1882                 if (ret != LDB_SUCCESS) {
1883                         talloc_free(tmp_ctx);
1884                         return ret;
1885                 }
1886
1887                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1888                 if (ret != LDB_SUCCESS) {
1889                         talloc_free(tmp_ctx);
1890                         return ret;
1891                 }
1892         }
1893
1894         el->values = talloc_steal(msg->elements, old_el->values);
1895         el->num_values = old_el->num_values;
1896
1897         talloc_free(tmp_ctx);
1898
1899         /* we now tell the backend to replace all existing values
1900            with the one we have constructed */
1901         el->flags = LDB_FLAG_MOD_REPLACE;
1902
1903         return LDB_SUCCESS;
1904 }
1905
1906 /*
1907   handle replacing a linked attribute
1908  */
1909 static int replmd_modify_la_replace(struct ldb_module *module,
1910                                     const struct dsdb_schema *schema,
1911                                     struct ldb_message *msg,
1912                                     struct ldb_message_element *el,
1913                                     struct ldb_message_element *old_el,
1914                                     const struct dsdb_attribute *schema_attr,
1915                                     uint64_t seq_num,
1916                                     time_t t,
1917                                     struct GUID *msg_guid,
1918                                     struct ldb_request *parent)
1919 {
1920         unsigned int i;
1921         struct parsed_dn *dns, *old_dns;
1922         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1923         int ret;
1924         const struct GUID *invocation_id;
1925         struct ldb_context *ldb = ldb_module_get_ctx(module);
1926         struct ldb_val *new_values = NULL;
1927         unsigned int num_new_values = 0;
1928         unsigned int old_num_values = old_el?old_el->num_values:0;
1929         NTTIME now;
1930
1931         unix_to_nt_time(&now, t);
1932
1933         /* check if there is nothing to replace */
1934         if ((!old_el || old_el->num_values == 0) &&
1935             el->num_values == 0) {
1936                 return LDB_SUCCESS;
1937         }
1938
1939         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1940         if (ret != LDB_SUCCESS) {
1941                 talloc_free(tmp_ctx);
1942                 return ret;
1943         }
1944
1945         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1946         if (ret != LDB_SUCCESS) {
1947                 talloc_free(tmp_ctx);
1948                 return ret;
1949         }
1950
1951         invocation_id = samdb_ntds_invocation_id(ldb);
1952         if (!invocation_id) {
1953                 return LDB_ERR_OPERATIONS_ERROR;
1954         }
1955
1956         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1957         if (ret != LDB_SUCCESS) {
1958                 talloc_free(tmp_ctx);
1959                 return ret;
1960         }
1961
1962         /* mark all the old ones as deleted */
1963         for (i=0; i<old_num_values; i++) {
1964                 struct parsed_dn *old_p = &old_dns[i];
1965                 struct parsed_dn *p;
1966                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
1967
1968                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1969
1970                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
1971                 if (ret != LDB_SUCCESS) {
1972                         talloc_free(tmp_ctx);
1973                         return ret;
1974                 }
1975
1976                 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
1977                 if (p) {
1978                         /* we don't delete it if we are re-adding it */
1979                         continue;
1980                 }
1981
1982                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
1983                                            invocation_id, seq_num, seq_num, now, 0, true);
1984                 if (ret != LDB_SUCCESS) {
1985                         talloc_free(tmp_ctx);
1986                         return ret;
1987                 }
1988         }
1989
1990         /* for each new value, either update its meta-data, or add it
1991          * to old_el
1992         */
1993         for (i=0; i<el->num_values; i++) {
1994                 struct parsed_dn *p = &dns[i], *old_p;
1995
1996                 if (old_dns &&
1997                     (old_p = parsed_dn_find(old_dns,
1998                                             old_num_values, p->guid, NULL)) != NULL) {
1999                         /* update in place */
2000                         ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn,
2001                                                    old_p->dsdb_dn, invocation_id,
2002                                                    seq_num, seq_num, now, 0, false);
2003                         if (ret != LDB_SUCCESS) {
2004                                 talloc_free(tmp_ctx);
2005                                 return ret;
2006                         }
2007                 } else {
2008                         /* add a new one */
2009                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2010                                                     num_new_values+1);
2011                         if (new_values == NULL) {
2012                                 ldb_module_oom(module);
2013                                 talloc_free(tmp_ctx);
2014                                 return LDB_ERR_OPERATIONS_ERROR;
2015                         }
2016                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2017                                                   invocation_id, seq_num, seq_num, now, 0, false);
2018                         if (ret != LDB_SUCCESS) {
2019                                 talloc_free(tmp_ctx);
2020                                 return ret;
2021                         }
2022                         num_new_values++;
2023                 }
2024
2025                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2026                 if (ret != LDB_SUCCESS) {
2027                         talloc_free(tmp_ctx);
2028                         return ret;
2029                 }
2030         }
2031
2032         /* add the new values to the end of old_el */
2033         if (num_new_values != 0) {
2034                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2035                                             struct ldb_val, old_num_values+num_new_values);
2036                 if (el->values == NULL) {
2037                         ldb_module_oom(module);
2038                         return LDB_ERR_OPERATIONS_ERROR;
2039                 }
2040                 memcpy(&el->values[old_num_values], &new_values[0],
2041                        sizeof(struct ldb_val)*num_new_values);
2042                 el->num_values = old_num_values + num_new_values;
2043                 talloc_steal(msg->elements, new_values);
2044         } else {
2045                 el->values = old_el->values;
2046                 el->num_values = old_el->num_values;
2047                 talloc_steal(msg->elements, el->values);
2048         }
2049
2050         talloc_free(tmp_ctx);
2051
2052         /* we now tell the backend to replace all existing values
2053            with the one we have constructed */
2054         el->flags = LDB_FLAG_MOD_REPLACE;
2055
2056         return LDB_SUCCESS;
2057 }
2058
2059
2060 /*
2061   handle linked attributes in modify requests
2062  */
2063 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2064                                                struct ldb_message *msg,
2065                                                uint64_t seq_num, time_t t,
2066                                                struct ldb_request *parent)
2067 {
2068         struct ldb_result *res;
2069         unsigned int i;
2070         int ret;
2071         struct ldb_context *ldb = ldb_module_get_ctx(module);
2072         struct ldb_message *old_msg;
2073
2074         const struct dsdb_schema *schema;
2075         struct GUID old_guid;
2076
2077         if (seq_num == 0) {
2078                 /* there the replmd_update_rpmd code has already
2079                  * checked and saw that there are no linked
2080                  * attributes */
2081                 return LDB_SUCCESS;
2082         }
2083
2084         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2085                 /* don't do anything special for linked attributes */
2086                 return LDB_SUCCESS;
2087         }
2088
2089         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2090                                     DSDB_FLAG_NEXT_MODULE |
2091                                     DSDB_SEARCH_SHOW_RECYCLED |
2092                                     DSDB_SEARCH_REVEAL_INTERNALS |
2093                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2094                                     parent);
2095         if (ret != LDB_SUCCESS) {
2096                 return ret;
2097         }
2098         schema = dsdb_get_schema(ldb, res);
2099         if (!schema) {
2100                 return LDB_ERR_OPERATIONS_ERROR;
2101         }
2102
2103         old_msg = res->msgs[0];
2104
2105         old_guid = samdb_result_guid(old_msg, "objectGUID");
2106
2107         for (i=0; i<msg->num_elements; i++) {
2108                 struct ldb_message_element *el = &msg->elements[i];
2109                 struct ldb_message_element *old_el, *new_el;
2110                 const struct dsdb_attribute *schema_attr
2111                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2112                 if (!schema_attr) {
2113                         ldb_asprintf_errstring(ldb,
2114                                                "%s: attribute %s is not a valid attribute in schema",
2115                                                __FUNCTION__, el->name);
2116                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2117                 }
2118                 if (schema_attr->linkID == 0) {
2119                         continue;
2120                 }
2121                 if ((schema_attr->linkID & 1) == 1) {
2122                         /* Odd is for the target.  Illegal to modify */
2123                         ldb_asprintf_errstring(ldb,
2124                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2125                         return LDB_ERR_UNWILLING_TO_PERFORM;
2126                 }
2127                 old_el = ldb_msg_find_element(old_msg, el->name);
2128                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2129                 case LDB_FLAG_MOD_REPLACE:
2130                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2131                         break;
2132                 case LDB_FLAG_MOD_DELETE:
2133                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2134                         break;
2135                 case LDB_FLAG_MOD_ADD:
2136                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2137                         break;
2138                 default:
2139                         ldb_asprintf_errstring(ldb,
2140                                                "invalid flags 0x%x for %s linked attribute",
2141                                                el->flags, el->name);
2142                         return LDB_ERR_UNWILLING_TO_PERFORM;
2143                 }
2144                 if (ret != LDB_SUCCESS) {
2145                         return ret;
2146                 }
2147                 if (old_el) {
2148                         ldb_msg_remove_attr(old_msg, el->name);
2149                 }
2150                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2151                 new_el->num_values = el->num_values;
2152                 new_el->values = talloc_steal(msg->elements, el->values);
2153
2154                 /* TODO: this relises a bit too heavily on the exact
2155                    behaviour of ldb_msg_find_element and
2156                    ldb_msg_remove_element */
2157                 old_el = ldb_msg_find_element(msg, el->name);
2158                 if (old_el != el) {
2159                         ldb_msg_remove_element(msg, old_el);
2160                         i--;
2161                 }
2162         }
2163
2164         talloc_free(res);
2165         return ret;
2166 }
2167
2168
2169
2170 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2171 {
2172         struct ldb_context *ldb;
2173         struct replmd_replicated_request *ac;
2174         struct ldb_request *down_req;
2175         struct ldb_message *msg;
2176         time_t t = time(NULL);
2177         int ret;
2178         bool is_urgent = false;
2179         struct loadparm_context *lp_ctx;
2180         char *referral;
2181         unsigned int functional_level;
2182         const DATA_BLOB *guid_blob;
2183
2184         /* do not manipulate our control entries */
2185         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2186                 return ldb_next_request(module, req);
2187         }
2188
2189         ldb = ldb_module_get_ctx(module);
2190
2191         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2192
2193         guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2194         if ( guid_blob != NULL ) {
2195                 ldb_set_errstring(ldb,
2196                                   "replmd_modify: it's not allowed to change the objectGUID!");
2197                 return LDB_ERR_CONSTRAINT_VIOLATION;
2198         }
2199
2200         ac = replmd_ctx_init(module, req);
2201         if (ac == NULL) {
2202                 return ldb_module_oom(module);
2203         }
2204
2205         functional_level = dsdb_functional_level(ldb);
2206
2207         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2208                                  struct loadparm_context);
2209
2210         /* we have to copy the message as the caller might have it as a const */
2211         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2212         if (msg == NULL) {
2213                 ldb_oom(ldb);
2214                 talloc_free(ac);
2215                 return LDB_ERR_OPERATIONS_ERROR;
2216         }
2217
2218         ldb_msg_remove_attr(msg, "whenChanged");
2219         ldb_msg_remove_attr(msg, "uSNChanged");
2220
2221         ret = replmd_update_rpmd(module, ac->schema, req, msg, &ac->seq_num, t, &is_urgent);
2222         if (ret == LDB_ERR_REFERRAL) {
2223                 referral = talloc_asprintf(req,
2224                                            "ldap://%s/%s",
2225                                            lpcfg_dnsdomain(lp_ctx),
2226                                            ldb_dn_get_linearized(msg->dn));
2227                 ret = ldb_module_send_referral(req, referral);
2228                 talloc_free(ac);
2229                 return ldb_module_done(req, NULL, NULL, ret);
2230         }
2231
2232         if (ret != LDB_SUCCESS) {
2233                 talloc_free(ac);
2234                 return ret;
2235         }
2236
2237         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2238         if (ret != LDB_SUCCESS) {
2239                 talloc_free(ac);
2240                 return ret;
2241         }
2242
2243         /* TODO:
2244          * - replace the old object with the newly constructed one
2245          */
2246
2247         ac->is_urgent = is_urgent;
2248
2249         ret = ldb_build_mod_req(&down_req, ldb, ac,
2250                                 msg,
2251                                 req->controls,
2252                                 ac, replmd_op_callback,
2253                                 req);
2254         LDB_REQ_SET_LOCATION(down_req);
2255         if (ret != LDB_SUCCESS) {
2256                 talloc_free(ac);
2257                 return ret;
2258         }
2259
2260         /* current partition control is needed by "replmd_op_callback" */
2261         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2262                 ret = ldb_request_add_control(down_req,
2263                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2264                                               false, NULL);
2265                 if (ret != LDB_SUCCESS) {
2266                         talloc_free(ac);
2267                         return ret;
2268                 }
2269         }
2270
2271         /* If we are in functional level 2000, then
2272          * replmd_modify_handle_linked_attribs will have done
2273          * nothing */
2274         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2275                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2276                 if (ret != LDB_SUCCESS) {
2277                         talloc_free(ac);
2278                         return ret;
2279                 }
2280         }
2281
2282         talloc_steal(down_req, msg);
2283
2284         /* we only change whenChanged and uSNChanged if the seq_num
2285            has changed */
2286         if (ac->seq_num != 0) {
2287                 ret = add_time_element(msg, "whenChanged", t);
2288                 if (ret != LDB_SUCCESS) {
2289                         talloc_free(ac);
2290                         return ret;
2291                 }
2292
2293                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2294                 if (ret != LDB_SUCCESS) {
2295                         talloc_free(ac);
2296                         return ret;
2297                 }
2298         }
2299
2300         /* go on with the call chain */
2301         return ldb_next_request(module, down_req);
2302 }
2303
2304 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2305
2306 /*
2307   handle a rename request
2308
2309   On a rename we need to do an extra ldb_modify which sets the
2310   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2311  */
2312 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2313 {
2314         struct ldb_context *ldb;
2315         struct replmd_replicated_request *ac;
2316         int ret;
2317         struct ldb_request *down_req;
2318
2319         /* do not manipulate our control entries */
2320         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2321                 return ldb_next_request(module, req);
2322         }
2323
2324         ldb = ldb_module_get_ctx(module);
2325
2326         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2327
2328         ac = replmd_ctx_init(module, req);
2329         if (ac == NULL) {
2330                 return ldb_module_oom(module);
2331         }
2332
2333         ret = ldb_build_rename_req(&down_req, ldb, ac,
2334                                    ac->req->op.rename.olddn,
2335                                    ac->req->op.rename.newdn,
2336                                    ac->req->controls,
2337                                    ac, replmd_rename_callback,
2338                                    ac->req);
2339         LDB_REQ_SET_LOCATION(down_req);
2340         if (ret != LDB_SUCCESS) {
2341                 talloc_free(ac);
2342                 return ret;
2343         }
2344
2345         /* go on with the call chain */
2346         return ldb_next_request(module, down_req);
2347 }
2348
2349 /* After the rename is compleated, update the whenchanged etc */
2350 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2351 {
2352         struct ldb_context *ldb;
2353         struct replmd_replicated_request *ac;
2354         struct ldb_request *down_req;
2355         struct ldb_message *msg;
2356         time_t t = time(NULL);
2357         int ret;
2358
2359         ac = talloc_get_type(req->context, struct replmd_replicated_request);
2360         ldb = ldb_module_get_ctx(ac->module);
2361
2362         if (ares->error != LDB_SUCCESS) {
2363                 return ldb_module_done(ac->req, ares->controls,
2364                                         ares->response, ares->error);
2365         }
2366
2367         if (ares->type != LDB_REPLY_DONE) {
2368                 ldb_set_errstring(ldb,
2369                                   "invalid ldb_reply_type in callback");
2370                 talloc_free(ares);
2371                 return ldb_module_done(ac->req, NULL, NULL,
2372                                         LDB_ERR_OPERATIONS_ERROR);
2373         }
2374
2375         /* Get a sequence number from the backend */
2376         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
2377         if (ret != LDB_SUCCESS) {
2378                 return ret;
2379         }
2380
2381         /* TODO:
2382          * - replace the old object with the newly constructed one
2383          */
2384
2385         msg = ldb_msg_new(ac);
2386         if (msg == NULL) {
2387                 ldb_oom(ldb);
2388                 return LDB_ERR_OPERATIONS_ERROR;
2389         }
2390
2391         msg->dn = ac->req->op.rename.newdn;
2392
2393         ret = ldb_build_mod_req(&down_req, ldb, ac,
2394                                 msg,
2395                                 req->controls,
2396                                 ac, replmd_op_callback,
2397                                 req);
2398         LDB_REQ_SET_LOCATION(down_req);
2399         if (ret != LDB_SUCCESS) {
2400                 talloc_free(ac);
2401                 return ret;
2402         }
2403
2404         /* current partition control is needed by "replmd_op_callback" */
2405         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2406                 ret = ldb_request_add_control(down_req,
2407                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2408                                               false, NULL);
2409                 if (ret != LDB_SUCCESS) {
2410                         talloc_free(ac);
2411                         return ret;
2412                 }
2413         }
2414
2415         talloc_steal(down_req, msg);
2416
2417         ret = add_time_element(msg, "whenChanged", t);
2418         if (ret != LDB_SUCCESS) {
2419                 talloc_free(ac);
2420                 return ret;
2421         }
2422
2423         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2424         if (ret != LDB_SUCCESS) {
2425                 talloc_free(ac);
2426                 return ret;
2427         }
2428
2429         /* go on with the call chain - do the modify after the rename */
2430         return ldb_next_request(ac->module, down_req);
2431 }
2432
2433 /*
2434    remove links from objects that point at this object when an object
2435    is deleted
2436  */
2437 static int replmd_delete_remove_link(struct ldb_module *module,
2438                                      const struct dsdb_schema *schema,
2439                                      struct ldb_dn *dn,
2440                                      struct ldb_message_element *el,
2441                                      const struct dsdb_attribute *sa,
2442                                      struct ldb_request *parent)
2443 {
2444         unsigned int i;
2445         TALLOC_CTX *tmp_ctx = talloc_new(module);
2446         struct ldb_context *ldb = ldb_module_get_ctx(module);
2447
2448         for (i=0; i<el->num_values; i++) {
2449                 struct dsdb_dn *dsdb_dn;
2450                 NTSTATUS status;
2451                 int ret;
2452                 struct GUID guid2;
2453                 struct ldb_message *msg;
2454                 const struct dsdb_attribute *target_attr;
2455                 struct ldb_message_element *el2;
2456                 struct ldb_val dn_val;
2457
2458                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2459                         continue;
2460                 }
2461
2462                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2463                 if (!dsdb_dn) {
2464                         talloc_free(tmp_ctx);
2465                         return LDB_ERR_OPERATIONS_ERROR;
2466                 }
2467
2468                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2469                 if (!NT_STATUS_IS_OK(status)) {
2470                         talloc_free(tmp_ctx);
2471                         return LDB_ERR_OPERATIONS_ERROR;
2472                 }
2473
2474                 /* remove the link */
2475                 msg = ldb_msg_new(tmp_ctx);
2476                 if (!msg) {
2477                         ldb_module_oom(module);
2478                         talloc_free(tmp_ctx);
2479                         return LDB_ERR_OPERATIONS_ERROR;
2480                 }
2481
2482
2483                 msg->dn = dsdb_dn->dn;
2484
2485                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2486                 if (target_attr == NULL) {
2487                         continue;
2488                 }
2489
2490                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2491                 if (ret != LDB_SUCCESS) {
2492                         ldb_module_oom(module);
2493                         talloc_free(tmp_ctx);
2494                         return LDB_ERR_OPERATIONS_ERROR;
2495                 }
2496                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2497                 el2->values = &dn_val;
2498                 el2->num_values = 1;
2499
2500                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2501                 if (ret != LDB_SUCCESS) {
2502                         talloc_free(tmp_ctx);
2503                         return ret;
2504                 }
2505         }
2506         talloc_free(tmp_ctx);
2507         return LDB_SUCCESS;
2508 }
2509
2510
2511 /*
2512   handle update of replication meta data for deletion of objects
2513
2514   This also handles the mapping of delete to a rename operation
2515   to allow deletes to be replicated.
2516  */
2517 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2518 {
2519         int ret = LDB_ERR_OTHER;
2520         bool retb, disallow_move_on_delete;
2521         struct ldb_dn *old_dn, *new_dn;
2522         const char *rdn_name;
2523         const struct ldb_val *rdn_value, *new_rdn_value;
2524         struct GUID guid;
2525         struct ldb_context *ldb = ldb_module_get_ctx(module);
2526         const struct dsdb_schema *schema;
2527         struct ldb_message *msg, *old_msg;
2528         struct ldb_message_element *el;
2529         TALLOC_CTX *tmp_ctx;
2530         struct ldb_result *res, *parent_res;
2531         const char *preserved_attrs[] = {
2532                 /* yes, this really is a hard coded list. See MS-ADTS
2533                    section 3.1.1.5.5.1.1 */
2534                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2535                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2536                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2537                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2538                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2539                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2540                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2541                 "whenChanged", NULL};
2542         unsigned int i, el_count = 0;
2543         enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2544                                                 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2545         enum deletion_state deletion_state, next_deletion_state;
2546         bool enabled;
2547
2548         if (ldb_dn_is_special(req->op.del.dn)) {
2549                 return ldb_next_request(module, req);
2550         }
2551
2552         tmp_ctx = talloc_new(ldb);
2553         if (!tmp_ctx) {
2554                 ldb_oom(ldb);
2555                 return LDB_ERR_OPERATIONS_ERROR;
2556         }
2557
2558         schema = dsdb_get_schema(ldb, tmp_ctx);
2559         if (!schema) {
2560                 return LDB_ERR_OPERATIONS_ERROR;
2561         }
2562
2563         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2564
2565         /* we need the complete msg off disk, so we can work out which
2566            attributes need to be removed */
2567         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2568                                     DSDB_FLAG_NEXT_MODULE |
2569                                     DSDB_SEARCH_SHOW_RECYCLED |
2570                                     DSDB_SEARCH_REVEAL_INTERNALS |
2571                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2572         if (ret != LDB_SUCCESS) {
2573                 talloc_free(tmp_ctx);
2574                 return ret;
2575         }
2576         old_msg = res->msgs[0];
2577
2578
2579         ret = dsdb_recyclebin_enabled(module, &enabled);
2580         if (ret != LDB_SUCCESS) {
2581                 talloc_free(tmp_ctx);
2582                 return ret;
2583         }
2584
2585         if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2586                 if (!enabled) {
2587                         deletion_state = OBJECT_TOMBSTONE;
2588                         next_deletion_state = OBJECT_REMOVED;
2589                 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2590                         deletion_state = OBJECT_RECYCLED;
2591                         next_deletion_state = OBJECT_REMOVED;
2592                 } else {
2593                         deletion_state = OBJECT_DELETED;
2594                         next_deletion_state = OBJECT_RECYCLED;
2595                 }
2596         } else {
2597                 deletion_state = OBJECT_NOT_DELETED;
2598                 if (enabled) {
2599                         next_deletion_state = OBJECT_DELETED;
2600                 } else {
2601                         next_deletion_state = OBJECT_TOMBSTONE;
2602                 }
2603         }
2604
2605         if (next_deletion_state == OBJECT_REMOVED) {
2606                 struct auth_session_info *session_info =
2607                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2608                 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2609                         ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2610                                         ldb_dn_get_linearized(old_msg->dn));
2611                         return LDB_ERR_UNWILLING_TO_PERFORM;
2612                 }
2613
2614                 /* it is already deleted - really remove it this time */
2615                 talloc_free(tmp_ctx);
2616                 return ldb_next_request(module, req);
2617         }
2618
2619         rdn_name = ldb_dn_get_rdn_name(old_dn);
2620         rdn_value = ldb_dn_get_rdn_val(old_dn);
2621         if ((rdn_name == NULL) || (rdn_value == NULL)) {
2622                 talloc_free(tmp_ctx);
2623                 return ldb_operr(ldb);
2624         }
2625
2626         msg = ldb_msg_new(tmp_ctx);
2627         if (msg == NULL) {
2628                 ldb_module_oom(module);
2629                 talloc_free(tmp_ctx);
2630                 return LDB_ERR_OPERATIONS_ERROR;
2631         }
2632
2633         msg->dn = old_dn;
2634
2635         if (deletion_state == OBJECT_NOT_DELETED){
2636                 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2637                 disallow_move_on_delete =
2638                         (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2639                                 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2640
2641                 /* work out where we will be renaming this object to */
2642                 if (!disallow_move_on_delete) {
2643                         ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2644                                                           &new_dn);
2645                         if (ret != LDB_SUCCESS) {
2646                                 /* this is probably an attempted delete on a partition
2647                                  * that doesn't allow delete operations, such as the
2648                                  * schema partition */
2649                                 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2650                                                            ldb_dn_get_linearized(old_dn));
2651                                 talloc_free(tmp_ctx);
2652                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2653                         }
2654                 } else {
2655                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2656                         if (new_dn == NULL) {
2657                                 ldb_module_oom(module);
2658                                 talloc_free(tmp_ctx);
2659                                 return LDB_ERR_OPERATIONS_ERROR;
2660                         }
2661                 }
2662
2663                 /* get the objects GUID from the search we just did */
2664                 guid = samdb_result_guid(old_msg, "objectGUID");
2665
2666                 /* Add a formatted child */
2667                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2668                                                 rdn_name,
2669                                                 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2670                                                 GUID_string(tmp_ctx, &guid));
2671                 if (!retb) {
2672                         DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2673                                         ldb_dn_get_linearized(new_dn)));
2674                         talloc_free(tmp_ctx);
2675                         return LDB_ERR_OPERATIONS_ERROR;
2676                 }
2677
2678                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2679                 if (ret != LDB_SUCCESS) {
2680                         DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2681                         ldb_module_oom(module);
2682                         talloc_free(tmp_ctx);
2683                         return ret;
2684                 }
2685                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2686         }
2687
2688         /*
2689           now we need to modify the object in the following ways:
2690
2691           - add isDeleted=TRUE
2692           - update rDN and name, with new rDN
2693           - remove linked attributes
2694           - remove objectCategory and sAMAccountType
2695           - remove attribs not on the preserved list
2696              - preserved if in above list, or is rDN
2697           - remove all linked attribs from this object
2698           - remove all links from other objects to this object
2699           - add lastKnownParent
2700           - update replPropertyMetaData?
2701
2702           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2703          */
2704
2705         /* we need the storage form of the parent GUID */
2706         ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2707                                     ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2708                                     DSDB_FLAG_NEXT_MODULE |
2709                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2710                                     DSDB_SEARCH_REVEAL_INTERNALS|
2711                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2712         if (ret != LDB_SUCCESS) {
2713                 talloc_free(tmp_ctx);
2714                 return ret;
2715         }
2716
2717         if (deletion_state == OBJECT_NOT_DELETED){
2718                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2719                                                    ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2720                 if (ret != LDB_SUCCESS) {
2721                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2722                         ldb_module_oom(module);
2723                         talloc_free(tmp_ctx);
2724                         return ret;
2725                 }
2726                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2727         }
2728
2729         switch (next_deletion_state){
2730
2731         case OBJECT_DELETED:
2732
2733                 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2734                 if (ret != LDB_SUCCESS) {
2735                         DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2736                         ldb_module_oom(module);
2737                         talloc_free(tmp_ctx);
2738                         return ret;
2739                 }
2740                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2741
2742                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_DELETE, NULL);
2743                 if (ret != LDB_SUCCESS) {
2744                         talloc_free(tmp_ctx);
2745                         ldb_module_oom(module);
2746                         return ret;
2747                 }
2748
2749                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_DELETE, NULL);
2750                 if (ret != LDB_SUCCESS) {
2751                         talloc_free(tmp_ctx);
2752                         ldb_module_oom(module);
2753                         return ret;
2754                 }
2755
2756                 break;
2757
2758         case OBJECT_RECYCLED:
2759         case OBJECT_TOMBSTONE:
2760
2761                 /* we also mark it as recycled, meaning this object can't be
2762                    recovered (we are stripping its attributes) */
2763                 if (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008_R2) {
2764                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2765                         if (ret != LDB_SUCCESS) {
2766                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2767                                 ldb_module_oom(module);
2768                                 talloc_free(tmp_ctx);
2769                                 return ret;
2770                         }
2771                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2772                 }
2773
2774                 /* work out which of the old attributes we will be removing */
2775                 for (i=0; i<old_msg->num_elements; i++) {
2776                         const struct dsdb_attribute *sa;
2777                         el = &old_msg->elements[i];
2778                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2779                         if (!sa) {
2780                                 talloc_free(tmp_ctx);
2781                                 return LDB_ERR_OPERATIONS_ERROR;
2782                         }
2783                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2784                                 /* don't remove the rDN */
2785                                 continue;
2786                         }
2787                         if (sa->linkID && sa->linkID & 1) {
2788                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
2789                                 if (ret != LDB_SUCCESS) {
2790                                         talloc_free(tmp_ctx);
2791                                         return LDB_ERR_OPERATIONS_ERROR;
2792                                 }
2793                                 continue;
2794                         }
2795                         if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
2796                                 continue;
2797                         }
2798                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
2799                         if (ret != LDB_SUCCESS) {
2800                                 talloc_free(tmp_ctx);
2801                                 ldb_module_oom(module);
2802                                 return ret;
2803                         }
2804                 }
2805                 break;
2806
2807         default:
2808                 break;
2809         }
2810
2811         if (deletion_state == OBJECT_NOT_DELETED) {
2812                 const struct dsdb_attribute *sa;
2813
2814                 /* work out what the new rdn value is, for updating the
2815                    rDN and name fields */
2816                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
2817                 if (new_rdn_value == NULL) {
2818                         talloc_free(tmp_ctx);
2819                         return ldb_operr(ldb);
2820                 }
2821
2822                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
2823                 if (!sa) {
2824                         talloc_free(tmp_ctx);
2825                         return LDB_ERR_OPERATIONS_ERROR;
2826                 }
2827
2828                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
2829                                         &el);
2830                 if (ret != LDB_SUCCESS) {
2831                         talloc_free(tmp_ctx);
2832                         return ret;
2833                 }
2834                 el->flags = LDB_FLAG_MOD_REPLACE;
2835
2836                 el = ldb_msg_find_element(old_msg, "name");
2837                 if (el) {
2838                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
2839                         if (ret != LDB_SUCCESS) {
2840                                 talloc_free(tmp_ctx);
2841                                 return ret;
2842                         }
2843                         el->flags = LDB_FLAG_MOD_REPLACE;
2844                 }
2845         }
2846
2847         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
2848         if (ret != LDB_SUCCESS) {
2849                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
2850                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
2851                 talloc_free(tmp_ctx);
2852                 return ret;
2853         }
2854
2855         if (deletion_state == OBJECT_NOT_DELETED) {
2856                 /* now rename onto the new DN */
2857                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
2858                 if (ret != LDB_SUCCESS){
2859                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
2860                                  ldb_dn_get_linearized(old_dn),
2861                                  ldb_dn_get_linearized(new_dn),
2862                                  ldb_errstring(ldb)));
2863                         talloc_free(tmp_ctx);
2864                         return ret;
2865                 }
2866         }
2867
2868         talloc_free(tmp_ctx);
2869
2870         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
2871 }
2872
2873
2874
2875 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
2876 {
2877         return ret;
2878 }
2879
2880 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
2881 {
2882         int ret = LDB_ERR_OTHER;
2883         /* TODO: do some error mapping */
2884         return ret;
2885 }
2886
2887
2888 static struct replPropertyMetaData1 *
2889 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
2890                                         enum drsuapi_DsAttributeId attid)
2891 {
2892         uint32_t i;
2893         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
2894
2895         for (i = 0; i < rpmd_ctr->count; i++) {
2896                 if (rpmd_ctr->array[i].attid == attid) {
2897                         return &rpmd_ctr->array[i];
2898                 }
2899         }
2900         return NULL;
2901 }
2902
2903
2904 /*
2905    return true if an update is newer than an existing entry
2906    see section 5.11 of MS-ADTS
2907 */
2908 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
2909                                    const struct GUID *update_invocation_id,
2910                                    uint32_t current_version,
2911                                    uint32_t update_version,
2912                                    NTTIME current_change_time,
2913                                    NTTIME update_change_time)
2914 {
2915         if (update_version != current_version) {
2916                 return update_version > current_version;
2917         }
2918         if (update_change_time != current_change_time) {
2919                 return update_change_time > current_change_time;
2920         }
2921         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
2922 }
2923
2924 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
2925                                                   struct replPropertyMetaData1 *new_m)
2926 {
2927         return replmd_update_is_newer(&cur_m->originating_invocation_id,
2928                                       &new_m->originating_invocation_id,
2929                                       cur_m->version,
2930                                       new_m->version,
2931                                       cur_m->originating_change_time,
2932                                       new_m->originating_change_time);
2933 }
2934
2935
2936 /*
2937   form a conflict DN
2938  */
2939 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
2940 {
2941         const struct ldb_val *rdn_val;
2942         const char *rdn_name;
2943         struct ldb_dn *new_dn;
2944
2945         rdn_val = ldb_dn_get_rdn_val(dn);
2946         rdn_name = ldb_dn_get_rdn_name(dn);
2947         if (!rdn_val || !rdn_name) {
2948                 return NULL;
2949         }
2950
2951         new_dn = ldb_dn_copy(mem_ctx, dn);
2952         if (!new_dn) {
2953                 return NULL;
2954         }
2955
2956         if (!ldb_dn_remove_child_components(new_dn, 1)) {
2957                 return NULL;
2958         }
2959
2960         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
2961                                   rdn_name,
2962                                   ldb_dn_escape_value(new_dn, *rdn_val),
2963                                   GUID_string(new_dn, guid))) {
2964                 return NULL;
2965         }
2966
2967         return new_dn;
2968 }
2969
2970
2971 /*
2972   perform a modify operation which sets the rDN and name attributes to
2973   their current values. This has the effect of changing these
2974   attributes to have been last updated by the current DC. This is
2975   needed to ensure that renames performed as part of conflict
2976   resolution are propogated to other DCs
2977  */
2978 static int replmd_name_modify(struct replmd_replicated_request *ar,
2979                               struct ldb_request *req, struct ldb_dn *dn)
2980 {
2981         struct ldb_message *msg;
2982         const char *rdn_name;
2983         const struct ldb_val *rdn_val;
2984         const struct dsdb_attribute *rdn_attr;
2985         int ret;
2986
2987         msg = ldb_msg_new(req);
2988         if (msg == NULL) {
2989                 goto failed;
2990         }
2991         msg->dn = dn;
2992
2993         rdn_name = ldb_dn_get_rdn_name(dn);
2994         if (rdn_name == NULL) {
2995                 goto failed;
2996         }
2997
2998         /* normalize the rdn attribute name */
2999         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3000         if (rdn_attr == NULL) {
3001                 goto failed;
3002         }
3003         rdn_name = rdn_attr->lDAPDisplayName;
3004
3005         rdn_val = ldb_dn_get_rdn_val(dn);
3006         if (rdn_val == NULL) {
3007                 goto failed;
3008         }
3009
3010         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3011                 goto failed;
3012         }
3013         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3014                 goto failed;
3015         }
3016         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3017                 goto failed;
3018         }
3019         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3020                 goto failed;
3021         }
3022
3023         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3024         if (ret != LDB_SUCCESS) {
3025                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3026                          ldb_dn_get_linearized(dn),
3027                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3028                 return ret;
3029         }
3030
3031         talloc_free(msg);
3032
3033         return LDB_SUCCESS;
3034
3035 failed:
3036         talloc_free(msg);
3037         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3038                  ldb_dn_get_linearized(dn)));
3039         return LDB_ERR_OPERATIONS_ERROR;
3040 }
3041
3042
3043 /*
3044   callback for conflict DN handling where we have renamed the incoming
3045   record. After renaming it, we need to ensure the change of name and
3046   rDN for the incoming record is seen as an originating update by this DC.
3047  */
3048 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3049 {
3050         struct replmd_replicated_request *ar =
3051                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3052         int ret;
3053
3054         if (ares->error != LDB_SUCCESS) {
3055                 /* call the normal callback for everything except success */
3056                 return replmd_op_callback(req, ares);
3057         }
3058
3059         /* perform a modify of the rDN and name of the record */
3060         ret = replmd_name_modify(ar, req, req->op.add.message->dn);
3061         if (ret != LDB_SUCCESS) {
3062                 ares->error = ret;
3063                 return replmd_op_callback(req, ares);
3064         }
3065
3066         return replmd_op_callback(req, ares);
3067 }
3068
3069 /*
3070   callback for replmd_replicated_apply_add()
3071   This copes with the creation of conflict records in the case where
3072   the DN exists, but with a different objectGUID
3073  */
3074 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3075 {
3076         struct ldb_dn *conflict_dn;
3077         struct replmd_replicated_request *ar =
3078                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3079         struct ldb_result *res;
3080         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3081         int ret;
3082         const struct ldb_val *rmd_value, *omd_value;
3083         struct replPropertyMetaDataBlob omd, rmd;
3084         enum ndr_err_code ndr_err;
3085         bool rename_incoming_record;
3086         struct replPropertyMetaData1 *rmd_name, *omd_name;
3087
3088         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3089                 /* call the normal callback for everything except
3090                    conflicts */
3091                 return replmd_op_callback(req, ares);
3092         }
3093
3094         /*
3095          * we have a conflict, and need to decide if we will keep the
3096          * new record or the old record
3097          */
3098         conflict_dn = req->op.add.message->dn;
3099
3100         /*
3101          * first we need the replPropertyMetaData attribute from the
3102          * old record
3103          */
3104         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3105                                     attrs,
3106                                     DSDB_FLAG_NEXT_MODULE |
3107                                     DSDB_SEARCH_SHOW_DELETED |
3108                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3109         if (ret != LDB_SUCCESS) {
3110                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3111                          ldb_dn_get_linearized(conflict_dn)));
3112                 goto failed;
3113         }
3114
3115         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3116         if (omd_value == NULL) {
3117                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3118                          ldb_dn_get_linearized(conflict_dn)));
3119                 goto failed;
3120         }
3121
3122         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3123                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3124         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3125                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3126                          ldb_dn_get_linearized(conflict_dn)));
3127                 goto failed;
3128         }
3129
3130         /*
3131          * and the replPropertyMetaData attribute from the
3132          * new record
3133          */
3134         rmd_value = ldb_msg_find_ldb_val(req->op.add.message, "replPropertyMetaData");
3135         if (rmd_value == NULL) {
3136                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for new record '%s'\n",
3137                          ldb_dn_get_linearized(conflict_dn)));
3138                 goto failed;
3139         }
3140
3141         ndr_err = ndr_pull_struct_blob(rmd_value, req, &rmd,
3142                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3143         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3144                 DEBUG(0,(__location__ ": Failed to parse new replPropertyMetaData for %s\n",
3145                          ldb_dn_get_linearized(conflict_dn)));
3146                 goto failed;
3147         }
3148
3149         /* we decide which is newer based on the RPMD on the name
3150            attribute.  See [MS-DRSR] ResolveNameConflict */
3151         rmd_name = replmd_replPropertyMetaData1_find_attid(&rmd, DRSUAPI_ATTID_name);
3152         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3153         if (!rmd_name || !omd_name) {
3154                 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3155                          ldb_dn_get_linearized(conflict_dn)));
3156                 goto failed;
3157         }
3158
3159         rename_incoming_record = !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3160
3161         if (rename_incoming_record) {
3162                 struct GUID guid;
3163                 struct ldb_dn *new_dn;
3164                 struct ldb_message *new_msg;
3165
3166                 guid = samdb_result_guid(req->op.add.message, "objectGUID");
3167                 if (GUID_all_zero(&guid)) {
3168                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3169                                  ldb_dn_get_linearized(conflict_dn)));
3170                         goto failed;
3171                 }
3172                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3173                 if (new_dn == NULL) {
3174                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3175                                  ldb_dn_get_linearized(conflict_dn)));
3176                         goto failed;
3177                 }
3178
3179                 DEBUG(1,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3180                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3181
3182                 /* re-submit the request, but with a different
3183                    callback, so we don't loop forever. */
3184                 new_msg = ldb_msg_copy_shallow(req, req->op.add.message);
3185                 if (!new_msg) {
3186                         goto failed;
3187                         DEBUG(0,(__location__ ": Failed to copy conflict DN message for %s\n",
3188                                  ldb_dn_get_linearized(conflict_dn)));
3189                 }
3190                 new_msg->dn = new_dn;
3191                 req->op.add.message = new_msg;
3192                 req->callback = replmd_op_name_modify_callback;
3193
3194                 return ldb_next_request(ar->module, req);
3195         } else {
3196                 /* we are renaming the existing record */
3197                 struct GUID guid;
3198                 struct ldb_dn *new_dn;
3199
3200                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3201                 if (GUID_all_zero(&guid)) {
3202                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3203                                  ldb_dn_get_linearized(conflict_dn)));
3204                         goto failed;
3205                 }
3206
3207                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3208                 if (new_dn == NULL) {
3209                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3210                                  ldb_dn_get_linearized(conflict_dn)));
3211                         goto failed;
3212                 }
3213
3214                 DEBUG(1,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
3215                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3216
3217                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3218                                          DSDB_FLAG_OWN_MODULE, req);
3219                 if (ret != LDB_SUCCESS) {
3220                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3221                                  ldb_dn_get_linearized(conflict_dn),
3222                                  ldb_dn_get_linearized(new_dn),
3223                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3224                         goto failed;
3225                 }
3226
3227                 /*
3228                  * now we need to ensure that the rename is seen as an
3229                  * originating update. We do that with a modify.
3230                  */
3231                 ret = replmd_name_modify(ar, req, new_dn);
3232                 if (ret != LDB_SUCCESS) {
3233                         goto failed;
3234                 }
3235
3236                 req->callback = replmd_op_callback;
3237
3238                 return ldb_next_request(ar->module, req);
3239         }
3240
3241 failed:
3242         /* on failure do the original callback. This means replication
3243          * will stop with an error, but there is not much else we can
3244          * do
3245          */
3246         return replmd_op_callback(req, ares);
3247 }
3248
3249 /*
3250   this is called when a new object comes in over DRS
3251  */
3252 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3253 {
3254         struct ldb_context *ldb;
3255         struct ldb_request *change_req;
3256         enum ndr_err_code ndr_err;
3257         struct ldb_message *msg;
3258         struct replPropertyMetaDataBlob *md;
3259         struct ldb_val md_value;
3260         unsigned int i;
3261         int ret;
3262
3263         /*
3264          * TODO: check if the parent object exist
3265          */
3266
3267         /*
3268          * TODO: handle the conflict case where an object with the
3269          *       same name exist
3270          */
3271
3272         ldb = ldb_module_get_ctx(ar->module);
3273         msg = ar->objs->objects[ar->index_current].msg;
3274         md = ar->objs->objects[ar->index_current].meta_data;
3275
3276         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3277         if (ret != LDB_SUCCESS) {
3278                 return replmd_replicated_request_error(ar, ret);
3279         }
3280
3281         ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
3282         if (ret != LDB_SUCCESS) {
3283                 return replmd_replicated_request_error(ar, ret);
3284         }
3285
3286         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3287         if (ret != LDB_SUCCESS) {
3288                 return replmd_replicated_request_error(ar, ret);
3289         }
3290
3291         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
3292         if (ret != LDB_SUCCESS) {
3293                 return replmd_replicated_request_error(ar, ret);
3294         }
3295
3296         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3297         if (ret != LDB_SUCCESS) {
3298                 return replmd_replicated_request_error(ar, ret);
3299         }
3300
3301         /* remove any message elements that have zero values */
3302         for (i=0; i<msg->num_elements; i++) {
3303                 struct ldb_message_element *el = &msg->elements[i];
3304
3305                 if (el->num_values == 0) {
3306                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
3307                                  el->name));
3308                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
3309                         msg->num_elements--;
3310                         i--;
3311                         continue;
3312                 }
3313         }
3314
3315         /*
3316          * the meta data array is already sorted by the caller
3317          */
3318         for (i=0; i < md->ctr.ctr1.count; i++) {
3319                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3320         }
3321         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3322                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3323         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3324                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3325                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3326         }
3327         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3328         if (ret != LDB_SUCCESS) {
3329                 return replmd_replicated_request_error(ar, ret);
3330         }
3331
3332         replmd_ldb_message_sort(msg, ar->schema);
3333
3334         if (DEBUGLVL(4)) {
3335                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3336                 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3337                 talloc_free(s);
3338         }
3339
3340         ret = ldb_build_add_req(&change_req,
3341                                 ldb,
3342                                 ar,
3343                                 msg,
3344                                 ar->controls,
3345                                 ar,
3346                                 replmd_op_add_callback,
3347                                 ar->req);
3348         LDB_REQ_SET_LOCATION(change_req);
3349         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3350
3351         /* current partition control needed by "repmd_op_callback" */
3352         ret = ldb_request_add_control(change_req,
3353                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3354                                       false, NULL);
3355         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3356
3357         return ldb_next_request(ar->module, change_req);
3358 }
3359
3360 /*
3361   handle renames that come in over DRS replication
3362  */
3363 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
3364                                            struct ldb_message *msg,
3365                                            struct replPropertyMetaDataBlob *rmd,
3366                                            struct replPropertyMetaDataBlob *omd,
3367                                            struct ldb_request *parent)
3368 {
3369         struct replPropertyMetaData1 *md_remote;
3370         struct replPropertyMetaData1 *md_local;
3371
3372         if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3373                 /* no rename */
3374                 return LDB_SUCCESS;
3375         }
3376
3377         /* now we need to check for double renames. We could have a
3378          * local rename pending which our replication partner hasn't
3379          * received yet. We choose which one wins by looking at the
3380          * attribute stamps on the two objects, the newer one wins
3381          */
3382         md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3383         md_local  = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3384         /* if there is no name attribute then we have to assume the
3385            object we've received is in fact newer */
3386         if (!md_remote || !md_local ||
3387             replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3388                 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3389                          ldb_dn_get_linearized(ar->search_msg->dn),
3390                          ldb_dn_get_linearized(msg->dn)));
3391                 /* pass rename to the next module
3392                  * so it doesn't appear as an originating update */
3393                 return dsdb_module_rename(ar->module,
3394                                           ar->search_msg->dn, msg->dn,
3395                                           DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX, parent);
3396         }
3397
3398         /* we're going to keep our old object */
3399         DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
3400                  ldb_dn_get_linearized(ar->search_msg->dn),
3401                  ldb_dn_get_linearized(msg->dn)));
3402         return LDB_SUCCESS;
3403 }
3404
3405
3406 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
3407 {
3408         struct ldb_context *ldb;
3409         struct ldb_request *change_req;
3410         enum ndr_err_code ndr_err;
3411         struct ldb_message *msg;
3412         struct replPropertyMetaDataBlob *rmd;
3413         struct replPropertyMetaDataBlob omd;
3414         const struct ldb_val *omd_value;
3415         struct replPropertyMetaDataBlob nmd;
3416         struct ldb_val nmd_value;
3417         unsigned int i;
3418         uint32_t j,ni=0;
3419         unsigned int removed_attrs = 0;
3420         int ret;
3421
3422         ldb = ldb_module_get_ctx(ar->module);
3423         msg = ar->objs->objects[ar->index_current].msg;
3424         rmd = ar->objs->objects[ar->index_current].meta_data;
3425         ZERO_STRUCT(omd);
3426         omd.version = 1;
3427
3428         /* find existing meta data */
3429         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
3430         if (omd_value) {
3431                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
3432                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3433                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3434                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3435                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3436                 }
3437
3438                 if (omd.version != 1) {
3439                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3440                 }
3441         }
3442
3443         /* handle renames that come in over DRS */
3444         ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
3445         if (ret != LDB_SUCCESS) {
3446                 ldb_debug(ldb, LDB_DEBUG_FATAL,
3447                           "replmd_replicated_request rename %s => %s failed - %s\n",
3448                           ldb_dn_get_linearized(ar->search_msg->dn),
3449                           ldb_dn_get_linearized(msg->dn),
3450                           ldb_errstring(ldb));
3451                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
3452         }
3453
3454         ZERO_STRUCT(nmd);
3455         nmd.version = 1;
3456         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
3457         nmd.ctr.ctr1.array = talloc_array(ar,
3458                                           struct replPropertyMetaData1,
3459                                           nmd.ctr.ctr1.count);
3460         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3461
3462         /* first copy the old meta data */
3463         for (i=0; i < omd.ctr.ctr1.count; i++) {
3464                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
3465                 ni++;
3466         }
3467
3468         ar->seq_num = 0;
3469         /* now merge in the new meta data */
3470         for (i=0; i < rmd->ctr.ctr1.count; i++) {
3471                 bool found = false;
3472
3473                 for (j=0; j < ni; j++) {
3474                         bool cmp;
3475
3476                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
3477                                 continue;
3478                         }
3479
3480                         cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
3481                                                                     &rmd->ctr.ctr1.array[i]);
3482                         if (cmp) {
3483                                 /* replace the entry */
3484                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
3485                                 if (ar->seq_num == 0) {
3486                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3487                                         if (ret != LDB_SUCCESS) {
3488                                                 return replmd_replicated_request_error(ar, ret);
3489                                         }
3490                                 }
3491                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
3492                                 found = true;
3493                                 break;
3494                         }
3495
3496                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
3497                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
3498                                          msg->elements[i-removed_attrs].name,
3499                                          ldb_dn_get_linearized(msg->dn),
3500                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
3501                         }
3502
3503                         /* we don't want to apply this change so remove the attribute */
3504                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
3505                         removed_attrs++;
3506
3507                         found = true;
3508                         break;
3509                 }
3510
3511                 if (found) continue;
3512
3513                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
3514                 if (ar->seq_num == 0) {
3515                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3516                         if (ret != LDB_SUCCESS) {
3517                                 return replmd_replicated_request_error(ar, ret);
3518                         }
3519                 }
3520                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
3521                 ni++;
3522         }
3523
3524         /*
3525          * finally correct the size of the meta_data array
3526          */
3527         nmd.ctr.ctr1.count = ni;
3528
3529         /*
3530          * the rdn attribute (the alias for the name attribute),
3531          * 'cn' for most objects is the last entry in the meta data array
3532          * we have stored
3533          *
3534          * sort the new meta data array
3535          */
3536         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
3537         if (ret != LDB_SUCCESS) {
3538                 return ret;
3539         }
3540
3541         /*
3542          * check if some replicated attributes left, otherwise skip the ldb_modify() call
3543          */
3544         if (msg->num_elements == 0) {
3545                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
3546                           ar->index_current);
3547
3548                 ar->index_current++;
3549                 return replmd_replicated_apply_next(ar);
3550         }
3551
3552         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
3553                   ar->index_current, msg->num_elements);
3554
3555         /* create the meta data value */
3556         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
3557                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3558         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3559                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3560                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3561         }
3562
3563         /*
3564          * when we know that we'll modify the record, add the whenChanged, uSNChanged
3565          * and replPopertyMetaData attributes
3566          */
3567         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3568         if (ret != LDB_SUCCESS) {
3569                 return replmd_replicated_request_error(ar, ret);
3570         }
3571         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3572         if (ret != LDB_SUCCESS) {
3573                 return replmd_replicated_request_error(ar, ret);
3574         }
3575         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
3576         if (ret != LDB_SUCCESS) {
3577                 return replmd_replicated_request_error(ar, ret);
3578         }
3579
3580         replmd_ldb_message_sort(msg, ar->schema);
3581
3582         /* we want to replace the old values */
3583         for (i=0; i < msg->num_elements; i++) {
3584                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3585         }
3586
3587         if (DEBUGLVL(4)) {
3588                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3589                 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
3590                 talloc_free(s);
3591         }
3592
3593         ret = ldb_build_mod_req(&change_req,
3594                                 ldb,
3595                                 ar,
3596                                 msg,
3597                                 ar->controls,
3598                                 ar,
3599                                 replmd_op_callback,
3600                                 ar->req);
3601         LDB_REQ_SET_LOCATION(change_req);
3602         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3603
3604         /* current partition control needed by "repmd_op_callback" */
3605         ret = ldb_request_add_control(change_req,
3606                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3607                                       false, NULL);
3608         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3609
3610         return ldb_next_request(ar->module, change_req);
3611 }
3612
3613 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
3614                                                    struct ldb_reply *ares)
3615 {
3616         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3617                                                struct replmd_replicated_request);
3618         int ret;
3619
3620         if (!ares) {
3621                 return ldb_module_done(ar->req, NULL, NULL,
3622                                         LDB_ERR_OPERATIONS_ERROR);
3623         }
3624         if (ares->error != LDB_SUCCESS &&
3625             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3626                 return ldb_module_done(ar->req, ares->controls,
3627                                         ares->response, ares->error);
3628         }
3629
3630         switch (ares->type) {
3631         case LDB_REPLY_ENTRY:
3632                 ar->search_msg = talloc_steal(ar, ares->message);
3633                 break;
3634
3635         case LDB_REPLY_REFERRAL:
3636                 /* we ignore referrals */
3637                 break;
3638
3639         case LDB_REPLY_DONE:
3640                 if (ar->search_msg != NULL) {
3641                         ret = replmd_replicated_apply_merge(ar);
3642                 } else {
3643                         ret = replmd_replicated_apply_add(ar);
3644                 }
3645                 if (ret != LDB_SUCCESS) {
3646                         return ldb_module_done(ar->req, NULL, NULL, ret);
3647                 }
3648         }
3649
3650         talloc_free(ares);
3651         return LDB_SUCCESS;
3652 }
3653
3654 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3655
3656 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3657 {
3658         struct ldb_context *ldb;
3659         int ret;
3660         char *tmp_str;
3661         char *filter;
3662         struct ldb_request *search_req;
3663         struct ldb_search_options_control *options;
3664
3665         if (ar->index_current >= ar->objs->num_objects) {
3666                 /* done with it, go to next stage */
3667                 return replmd_replicated_uptodate_vector(ar);
3668         }
3669
3670         ldb = ldb_module_get_ctx(ar->module);
3671         ar->search_msg = NULL;
3672
3673         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3674         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3675
3676         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3677         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3678         talloc_free(tmp_str);
3679
3680         ret = ldb_build_search_req(&search_req,
3681                                    ldb,
3682                                    ar,
3683                                    NULL,
3684                                    LDB_SCOPE_SUBTREE,
3685                                    filter,
3686                                    NULL,
3687                                    NULL,
3688                                    ar,
3689                                    replmd_replicated_apply_search_callback,
3690                                    ar->req);
3691         LDB_REQ_SET_LOCATION(search_req);
3692
3693         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
3694                                       true, NULL);
3695         if (ret != LDB_SUCCESS) {
3696                 return ret;
3697         }
3698
3699         /* we need to cope with cross-partition links, so search for
3700            the GUID over all partitions */
3701         options = talloc(search_req, struct ldb_search_options_control);
3702         if (options == NULL) {
3703                 DEBUG(0, (__location__ ": out of memory\n"));
3704                 return LDB_ERR_OPERATIONS_ERROR;
3705         }
3706         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3707
3708         ret = ldb_request_add_control(search_req,
3709                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
3710                                       true, options);
3711         if (ret != LDB_SUCCESS) {
3712                 return ret;
3713         }
3714
3715         return ldb_next_request(ar->module, search_req);
3716 }
3717
3718 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
3719                                                       struct ldb_reply *ares)
3720 {
3721         struct ldb_context *ldb;
3722         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3723                                                struct replmd_replicated_request);
3724         ldb = ldb_module_get_ctx(ar->module);
3725
3726         if (!ares) {
3727                 return ldb_module_done(ar->req, NULL, NULL,
3728                                         LDB_ERR_OPERATIONS_ERROR);
3729         }
3730         if (ares->error != LDB_SUCCESS) {
3731                 return ldb_module_done(ar->req, ares->controls,
3732                                         ares->response, ares->error);
3733         }
3734
3735         if (ares->type != LDB_REPLY_DONE) {
3736                 ldb_set_errstring(ldb, "Invalid reply type\n!");
3737                 return ldb_module_done(ar->req, NULL, NULL,
3738                                         LDB_ERR_OPERATIONS_ERROR);
3739         }
3740
3741         talloc_free(ares);
3742
3743         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3744 }
3745
3746 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3747 {
3748         struct ldb_context *ldb;
3749         struct ldb_request *change_req;
3750         enum ndr_err_code ndr_err;
3751         struct ldb_message *msg;
3752         struct replUpToDateVectorBlob ouv;
3753         const struct ldb_val *ouv_value;
3754         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3755         struct replUpToDateVectorBlob nuv;
3756         struct ldb_val nuv_value;
3757         struct ldb_message_element *nuv_el = NULL;
3758         const struct GUID *our_invocation_id;
3759         struct ldb_message_element *orf_el = NULL;
3760         struct repsFromToBlob nrf;
3761         struct ldb_val *nrf_value = NULL;
3762         struct ldb_message_element *nrf_el = NULL;
3763         unsigned int i;
3764         uint32_t j,ni=0;
3765         bool found = false;
3766         time_t t = time(NULL);
3767         NTTIME now;
3768         int ret;
3769         uint32_t instanceType;
3770
3771         ldb = ldb_module_get_ctx(ar->module);
3772         ruv = ar->objs->uptodateness_vector;
3773         ZERO_STRUCT(ouv);
3774         ouv.version = 2;
3775         ZERO_STRUCT(nuv);
3776         nuv.version = 2;
3777
3778         unix_to_nt_time(&now, t);
3779
3780         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
3781         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
3782                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
3783                          ldb_dn_get_linearized(ar->search_msg->dn)));
3784                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3785         }
3786
3787         /*
3788          * first create the new replUpToDateVector
3789          */
3790         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
3791         if (ouv_value) {
3792                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
3793                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
3794                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3795                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3796                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3797                 }
3798
3799                 if (ouv.version != 2) {
3800                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3801                 }
3802         }
3803
3804         /*
3805          * the new uptodateness vector will at least
3806          * contain 1 entry, one for the source_dsa
3807          *
3808          * plus optional values from our old vector and the one from the source_dsa
3809          */
3810         nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
3811         if (ruv) nuv.ctr.ctr2.count += ruv->count;
3812         nuv.ctr.ctr2.cursors = talloc_array(ar,
3813                                             struct drsuapi_DsReplicaCursor2,
3814                                             nuv.ctr.ctr2.count);
3815         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3816
3817         /* first copy the old vector */
3818         for (i=0; i < ouv.ctr.ctr2.count; i++) {
3819                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
3820                 ni++;
3821         }
3822
3823         /* get our invocation_id if we have one already attached to the ldb */
3824         our_invocation_id = samdb_ntds_invocation_id(ldb);
3825
3826         /* merge in the source_dsa vector is available */
3827         for (i=0; (ruv && i < ruv->count); i++) {
3828                 found = false;
3829
3830                 if (our_invocation_id &&
3831                     GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3832                                our_invocation_id)) {
3833                         continue;
3834                 }
3835
3836                 for (j=0; j < ni; j++) {
3837                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
3838                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3839                                 continue;
3840                         }
3841
3842                         found = true;
3843
3844                         /*
3845                          * we update only the highest_usn and not the latest_sync_success time,
3846                          * because the last success stands for direct replication
3847                          */
3848                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
3849                                 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
3850                         }
3851                         break;
3852                 }
3853
3854                 if (found) continue;
3855
3856                 /* if it's not there yet, add it */
3857                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
3858                 ni++;
3859         }
3860
3861         /*
3862          * merge in the current highwatermark for the source_dsa
3863          */
3864         found = false;
3865         for (j=0; j < ni; j++) {
3866                 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
3867                                 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
3868                         continue;
3869                 }
3870
3871                 found = true;
3872
3873                 /*
3874                  * here we update the highest_usn and last_sync_success time
3875                  * because we're directly replicating from the source_dsa
3876                  *
3877                  * and use the tmp_highest_usn because this is what we have just applied
3878                  * to our ldb
3879                  */
3880                 nuv.ctr.ctr2.cursors[j].highest_usn             = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3881                 nuv.ctr.ctr2.cursors[j].last_sync_success       = now;
3882                 break;
3883         }
3884         if (!found) {
3885                 /*
3886                  * here we update the highest_usn and last_sync_success time
3887                  * because we're directly replicating from the source_dsa
3888                  *
3889                  * and use the tmp_highest_usn because this is what we have just applied
3890                  * to our ldb
3891                  */
3892                 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
3893                 nuv.ctr.ctr2.cursors[ni].highest_usn            = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
3894                 nuv.ctr.ctr2.cursors[ni].last_sync_success      = now;
3895                 ni++;
3896         }
3897
3898         /*
3899          * finally correct the size of the cursors array
3900          */
3901         nuv.ctr.ctr2.count = ni;
3902
3903         /*
3904          * sort the cursors
3905          */
3906         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
3907
3908         /*
3909          * create the change ldb_message
3910          */
3911         msg = ldb_msg_new(ar);
3912         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3913         msg->dn = ar->search_msg->dn;
3914
3915         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
3916                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
3917         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3918                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3919                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3920         }
3921         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
3922         if (ret != LDB_SUCCESS) {
3923                 return replmd_replicated_request_error(ar, ret);
3924         }
3925         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
3926
3927         /*
3928          * now create the new repsFrom value from the given repsFromTo1 structure
3929          */
3930         ZERO_STRUCT(nrf);
3931         nrf.version                                     = 1;
3932         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
3933         nrf.ctr.ctr1.highwatermark.highest_usn          = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
3934
3935         /*
3936          * first see if we already have a repsFrom value for the current source dsa
3937          * if so we'll later replace this value
3938          */
3939         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
3940         if (orf_el) {
3941                 for (i=0; i < orf_el->num_values; i++) {
3942                         struct repsFromToBlob *trf;
3943
3944                         trf = talloc(ar, struct repsFromToBlob);
3945                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3946
3947                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
3948                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
3949                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3950                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3951                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3952                         }
3953
3954                         if (trf->version != 1) {
3955                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3956                         }
3957
3958                         /*
3959                          * we compare the source dsa objectGUID not the invocation_id
3960                          * because we want only one repsFrom value per source dsa
3961                          * and when the invocation_id of the source dsa has changed we don't need
3962                          * the old repsFrom with the old invocation_id
3963                          */
3964                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
3965                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
3966                                 talloc_free(trf);
3967                                 continue;
3968                         }
3969
3970                         talloc_free(trf);
3971                         nrf_value = &orf_el->values[i];
3972                         break;
3973                 }
3974
3975                 /*
3976                  * copy over all old values to the new ldb_message
3977                  */
3978                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
3979                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3980                 *nrf_el = *orf_el;
3981         }
3982
3983         /*
3984          * if we haven't found an old repsFrom value for the current source dsa
3985          * we'll add a new value
3986          */
3987         if (!nrf_value) {
3988                 struct ldb_val zero_value;
3989                 ZERO_STRUCT(zero_value);
3990                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
3991                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3992
3993                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
3994         }
3995
3996         /* we now fill the value which is already attached to ldb_message */
3997         ndr_err = ndr_push_struct_blob(nrf_value, msg,
3998                                        &nrf,
3999                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
4000         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4001                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4002                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4003         }
4004
4005         /*
4006          * the ldb_message_element for the attribute, has all the old values and the new one
4007          * so we'll replace the whole attribute with all values
4008          */
4009         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
4010
4011         if (DEBUGLVL(4)) {
4012                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4013                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
4014                 talloc_free(s);
4015         }
4016
4017         /* prepare the ldb_modify() request */
4018         ret = ldb_build_mod_req(&change_req,
4019                                 ldb,
4020                                 ar,
4021                                 msg,
4022                                 ar->controls,
4023                                 ar,
4024                                 replmd_replicated_uptodate_modify_callback,
4025                                 ar->req);
4026         LDB_REQ_SET_LOCATION(change_req);
4027         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4028
4029         return ldb_next_request(ar->module, change_req);
4030 }
4031
4032 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
4033                                                       struct ldb_reply *ares)
4034 {
4035         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4036                                                struct replmd_replicated_request);
4037         int ret;
4038
4039         if (!ares) {
4040                 return ldb_module_done(ar->req, NULL, NULL,
4041                                         LDB_ERR_OPERATIONS_ERROR);
4042         }
4043         if (ares->error != LDB_SUCCESS &&
4044             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4045                 return ldb_module_done(ar->req, ares->controls,
4046                                         ares->response, ares->error);
4047         }
4048
4049         switch (ares->type) {
4050         case LDB_REPLY_ENTRY:
4051                 ar->search_msg = talloc_steal(ar, ares->message);
4052                 break;
4053
4054         case LDB_REPLY_REFERRAL:
4055                 /* we ignore referrals */
4056                 break;
4057
4058         case LDB_REPLY_DONE:
4059                 if (ar->search_msg == NULL) {
4060                         ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4061                 } else {
4062                         ret = replmd_replicated_uptodate_modify(ar);
4063                 }
4064                 if (ret != LDB_SUCCESS) {
4065                         return ldb_module_done(ar->req, NULL, NULL, ret);
4066                 }
4067         }
4068
4069         talloc_free(ares);
4070         return LDB_SUCCESS;
4071 }
4072
4073
4074 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
4075 {
4076         struct ldb_context *ldb;
4077         int ret;
4078         static const char *attrs[] = {
4079                 "replUpToDateVector",
4080                 "repsFrom",
4081                 "instanceType",
4082                 NULL
4083         };
4084         struct ldb_request *search_req;
4085
4086         ldb = ldb_module_get_ctx(ar->module);
4087         ar->search_msg = NULL;
4088
4089         ret = ldb_build_search_req(&search_req,
4090                                    ldb,
4091                                    ar,
4092                                    ar->objs->partition_dn,
4093                                    LDB_SCOPE_BASE,
4094                                    "(objectClass=*)",
4095                                    attrs,
4096                                    NULL,
4097                                    ar,
4098                                    replmd_replicated_uptodate_search_callback,
4099                                    ar->req);
4100         LDB_REQ_SET_LOCATION(search_req);
4101         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4102
4103         return ldb_next_request(ar->module, search_req);
4104 }
4105
4106
4107
4108 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
4109 {
4110         struct ldb_context *ldb;
4111         struct dsdb_extended_replicated_objects *objs;
4112         struct replmd_replicated_request *ar;
4113         struct ldb_control **ctrls;
4114         int ret;
4115         uint32_t i;
4116         struct replmd_private *replmd_private =
4117                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4118
4119         ldb = ldb_module_get_ctx(module);
4120
4121         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
4122
4123         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
4124         if (!objs) {
4125                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
4126                 return LDB_ERR_PROTOCOL_ERROR;
4127         }
4128
4129         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
4130                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
4131                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
4132                 return LDB_ERR_PROTOCOL_ERROR;
4133         }
4134
4135         ar = replmd_ctx_init(module, req);
4136         if (!ar)
4137                 return LDB_ERR_OPERATIONS_ERROR;
4138
4139         /* Set the flags to have the replmd_op_callback run over the full set of objects */
4140         ar->apply_mode = true;
4141         ar->objs = objs;
4142         ar->schema = dsdb_get_schema(ldb, ar);
4143         if (!ar->schema) {
4144                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
4145                 talloc_free(ar);
4146                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4147                 return LDB_ERR_CONSTRAINT_VIOLATION;
4148         }
4149
4150         ctrls = req->controls;
4151
4152         if (req->controls) {
4153                 req->controls = talloc_memdup(ar, req->controls,
4154                                               talloc_get_size(req->controls));
4155                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4156         }
4157
4158         /* This allows layers further down to know if a change came in over replication */
4159         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
4160         if (ret != LDB_SUCCESS) {
4161                 return ret;
4162         }
4163
4164         /* If this change contained linked attributes in the body
4165          * (rather than in the links section) we need to update
4166          * backlinks in linked_attributes */
4167         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
4168         if (ret != LDB_SUCCESS) {
4169                 return ret;
4170         }
4171
4172         ar->controls = req->controls;
4173         req->controls = ctrls;
4174
4175         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
4176
4177         /* save away the linked attributes for the end of the
4178            transaction */
4179         for (i=0; i<ar->objs->linked_attributes_count; i++) {
4180                 struct la_entry *la_entry;
4181
4182                 if (replmd_private->la_ctx == NULL) {
4183                         replmd_private->la_ctx = talloc_new(replmd_private);
4184                 }
4185                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
4186                 if (la_entry == NULL) {
4187                         ldb_oom(ldb);
4188                         return LDB_ERR_OPERATIONS_ERROR;
4189                 }
4190                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
4191                 if (la_entry->la == NULL) {
4192                         talloc_free(la_entry);
4193                         ldb_oom(ldb);
4194                         return LDB_ERR_OPERATIONS_ERROR;
4195                 }
4196                 *la_entry->la = ar->objs->linked_attributes[i];
4197
4198                 /* we need to steal the non-scalars so they stay
4199                    around until the end of the transaction */
4200                 talloc_steal(la_entry->la, la_entry->la->identifier);
4201                 talloc_steal(la_entry->la, la_entry->la->value.blob);
4202
4203                 DLIST_ADD(replmd_private->la_list, la_entry);
4204         }
4205
4206         return replmd_replicated_apply_next(ar);
4207 }
4208
4209 /*
4210   process one linked attribute structure
4211  */
4212 static int replmd_process_linked_attribute(struct ldb_module *module,
4213                                            struct la_entry *la_entry,
4214                                            struct ldb_request *parent)
4215 {
4216         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
4217         struct ldb_context *ldb = ldb_module_get_ctx(module);
4218         struct ldb_message *msg;
4219         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
4220         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
4221         int ret;
4222         const struct dsdb_attribute *attr;
4223         struct dsdb_dn *dsdb_dn;
4224         uint64_t seq_num = 0;
4225         struct ldb_message_element *old_el;
4226         WERROR status;
4227         time_t t = time(NULL);
4228         struct ldb_result *res;
4229         const char *attrs[2];
4230         struct parsed_dn *pdn_list, *pdn;
4231         struct GUID guid = GUID_zero();
4232         NTSTATUS ntstatus;
4233         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
4234         const struct GUID *our_invocation_id;
4235
4236 /*
4237 linked_attributes[0]:
4238      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
4239         identifier               : *
4240             identifier: struct drsuapi_DsReplicaObjectIdentifier
4241                 __ndr_size               : 0x0000003a (58)
4242                 __ndr_size_sid           : 0x00000000 (0)
4243                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
4244                 sid                      : S-0-0
4245                 __ndr_size_dn            : 0x00000000 (0)
4246                 dn                       : ''
4247         attid                    : DRSUAPI_ATTID_member (0x1F)
4248         value: struct drsuapi_DsAttributeValue
4249             __ndr_size               : 0x0000007e (126)
4250             blob                     : *
4251                 blob                     : DATA_BLOB length=126
4252         flags                    : 0x00000001 (1)
4253                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
4254         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
4255         meta_data: struct drsuapi_DsReplicaMetaData
4256             version                  : 0x00000015 (21)
4257             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
4258             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
4259             originating_usn          : 0x000000000001e19c (123292)
4260
4261 (for cases where the link is to a normal DN)
4262      &target: struct drsuapi_DsReplicaObjectIdentifier3
4263         __ndr_size               : 0x0000007e (126)
4264         __ndr_size_sid           : 0x0000001c (28)
4265         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
4266         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
4267         __ndr_size_dn            : 0x00000022 (34)
4268         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
4269  */
4270
4271         /* find the attribute being modified */
4272         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
4273         if (attr == NULL) {
4274                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
4275                 talloc_free(tmp_ctx);
4276                 return LDB_ERR_OPERATIONS_ERROR;
4277         }
4278
4279         attrs[0] = attr->lDAPDisplayName;
4280         attrs[1] = NULL;
4281
4282         /* get the existing message from the db for the object with
4283            this GUID, returning attribute being modified. We will then
4284            use this msg as the basis for a modify call */
4285         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
4286                                  DSDB_FLAG_NEXT_MODULE |
4287                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
4288                                  DSDB_SEARCH_SHOW_RECYCLED |
4289                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4290                                  DSDB_SEARCH_REVEAL_INTERNALS,
4291                                  parent,
4292                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
4293         if (ret != LDB_SUCCESS) {
4294                 talloc_free(tmp_ctx);
4295                 return ret;
4296         }
4297         if (res->count != 1) {
4298                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
4299                                        GUID_string(tmp_ctx, &la->identifier->guid));
4300                 talloc_free(tmp_ctx);
4301                 return LDB_ERR_NO_SUCH_OBJECT;
4302         }
4303         msg = res->msgs[0];
4304
4305         if (msg->num_elements == 0) {
4306                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
4307                 if (ret != LDB_SUCCESS) {
4308                         ldb_module_oom(module);
4309                         talloc_free(tmp_ctx);
4310                         return LDB_ERR_OPERATIONS_ERROR;
4311                 }
4312         } else {
4313                 old_el = &msg->elements[0];
4314                 old_el->flags = LDB_FLAG_MOD_REPLACE;
4315         }
4316
4317         /* parse the existing links */
4318         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
4319         if (ret != LDB_SUCCESS) {
4320                 talloc_free(tmp_ctx);
4321                 return ret;
4322         }
4323
4324         /* get our invocationId */
4325         our_invocation_id = samdb_ntds_invocation_id(ldb);
4326         if (!our_invocation_id) {
4327                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
4328                 talloc_free(tmp_ctx);
4329                 return LDB_ERR_OPERATIONS_ERROR;
4330         }
4331
4332         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
4333         if (ret != LDB_SUCCESS) {
4334                 talloc_free(tmp_ctx);
4335                 return ret;
4336         }
4337
4338         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
4339         if (!W_ERROR_IS_OK(status)) {
4340                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
4341                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
4342                 return LDB_ERR_OPERATIONS_ERROR;
4343         }
4344
4345         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
4346         if (!NT_STATUS_IS_OK(ntstatus) && active) {
4347                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
4348                                        old_el->name,
4349                                        ldb_dn_get_linearized(dsdb_dn->dn),
4350                                        ldb_dn_get_linearized(msg->dn));
4351                 return LDB_ERR_OPERATIONS_ERROR;
4352         }
4353
4354         /* re-resolve the DN by GUID, as the DRS server may give us an
4355            old DN value */
4356         ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
4357         if (ret != LDB_SUCCESS) {
4358                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s",
4359                          GUID_string(tmp_ctx, &guid),
4360                          ldb_dn_get_linearized(dsdb_dn->dn)));
4361         }
4362
4363         /* see if this link already exists */
4364         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
4365         if (pdn != NULL) {
4366                 /* see if this update is newer than what we have already */
4367                 struct GUID invocation_id = GUID_zero();
4368                 uint32_t version = 0;
4369                 uint32_t originating_usn = 0;
4370                 NTTIME change_time = 0;
4371                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
4372
4373                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
4374                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
4375                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
4376                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
4377
4378                 if (!replmd_update_is_newer(&invocation_id,
4379                                             &la->meta_data.originating_invocation_id,
4380                                             version,
4381                                             la->meta_data.version,
4382                                             change_time,
4383                                             la->meta_data.originating_change_time)) {
4384                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
4385                                  old_el->name, ldb_dn_get_linearized(msg->dn),
4386                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
4387                         talloc_free(tmp_ctx);
4388                         return LDB_SUCCESS;
4389                 }
4390
4391                 /* get a seq_num for this change */
4392                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4393                 if (ret != LDB_SUCCESS) {
4394                         talloc_free(tmp_ctx);
4395                         return ret;
4396                 }
4397
4398                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
4399                         /* remove the existing backlink */
4400                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
4401                         if (ret != LDB_SUCCESS) {
4402                                 talloc_free(tmp_ctx);
4403                                 return ret;
4404                         }
4405                 }
4406
4407                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
4408                                            &la->meta_data.originating_invocation_id,
4409                                            la->meta_data.originating_usn, seq_num,
4410                                            la->meta_data.originating_change_time,
4411                                            la->meta_data.version,
4412                                            !active);
4413                 if (ret != LDB_SUCCESS) {
4414                         talloc_free(tmp_ctx);
4415                         return ret;
4416                 }
4417
4418                 if (active) {
4419                         /* add the new backlink */
4420                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
4421                         if (ret != LDB_SUCCESS) {
4422                                 talloc_free(tmp_ctx);
4423                                 return ret;
4424                         }
4425                 }
4426         } else {
4427                 /* get a seq_num for this change */
4428                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4429                 if (ret != LDB_SUCCESS) {
4430                         talloc_free(tmp_ctx);
4431                         return ret;
4432                 }
4433
4434                 old_el->values = talloc_realloc(msg->elements, old_el->values,
4435                                                 struct ldb_val, old_el->num_values+1);
4436                 if (!old_el->values) {
4437                         ldb_module_oom(module);
4438                         return LDB_ERR_OPERATIONS_ERROR;
4439                 }
4440                 old_el->num_values++;
4441
4442                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
4443                                           &la->meta_data.originating_invocation_id,
4444                                           la->meta_data.originating_usn, seq_num,
4445                                           la->meta_data.originating_change_time,
4446                                           la->meta_data.version,
4447                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
4448                 if (ret != LDB_SUCCESS) {
4449                         talloc_free(tmp_ctx);
4450                         return ret;
4451                 }
4452
4453                 if (active) {
4454                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
4455                                                   true, attr, false);
4456                         if (ret != LDB_SUCCESS) {
4457                                 talloc_free(tmp_ctx);
4458                                 return ret;
4459                         }
4460                 }
4461         }
4462
4463         /* we only change whenChanged and uSNChanged if the seq_num
4464            has changed */
4465         if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
4466                 talloc_free(tmp_ctx);
4467                 return ldb_operr(ldb);
4468         }
4469
4470         if (add_uint64_element(ldb, msg, "uSNChanged",
4471                                seq_num) != LDB_SUCCESS) {
4472                 talloc_free(tmp_ctx);
4473                 return ldb_operr(ldb);
4474         }
4475
4476         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
4477         if (old_el == NULL) {
4478                 talloc_free(tmp_ctx);
4479                 return ldb_operr(ldb);
4480         }
4481
4482         ret = dsdb_check_single_valued_link(attr, old_el);
4483         if (ret != LDB_SUCCESS) {
4484                 talloc_free(tmp_ctx);
4485                 return ret;
4486         }
4487
4488         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
4489
4490         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
4491         if (ret != LDB_SUCCESS) {
4492                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
4493                           ldb_errstring(ldb),
4494                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
4495                 talloc_free(tmp_ctx);
4496                 return ret;
4497         }
4498
4499         talloc_free(tmp_ctx);
4500
4501         return ret;
4502 }
4503
4504 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
4505 {
4506         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
4507                 return replmd_extended_replicated_objects(module, req);
4508         }
4509
4510         return ldb_next_request(module, req);
4511 }
4512
4513
4514 /*
4515   we hook into the transaction operations to allow us to
4516   perform the linked attribute updates at the end of the whole
4517   transaction. This allows a forward linked attribute to be created
4518   before the object is created. During a vampire, w2k8 sends us linked
4519   attributes before the objects they are part of.
4520  */
4521 static int replmd_start_transaction(struct ldb_module *module)
4522 {
4523         /* create our private structure for this transaction */
4524         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
4525                                                                 struct replmd_private);
4526         replmd_txn_cleanup(replmd_private);
4527
4528         /* free any leftover mod_usn records from cancelled
4529            transactions */
4530         while (replmd_private->ncs) {
4531                 struct nc_entry *e = replmd_private->ncs;
4532                 DLIST_REMOVE(replmd_private->ncs, e);
4533                 talloc_free(e);
4534         }
4535
4536         return ldb_next_start_trans(module);
4537 }
4538
4539 /*
4540   on prepare commit we loop over our queued la_context structures and
4541   apply each of them
4542  */
4543 static int replmd_prepare_commit(struct ldb_module *module)
4544 {
4545         struct replmd_private *replmd_private =
4546                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4547         struct la_entry *la, *prev;
4548         struct la_backlink *bl;
4549         int ret;
4550
4551         /* walk the list backwards, to do the first entry first, as we
4552          * added the entries with DLIST_ADD() which puts them at the
4553          * start of the list */
4554         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
4555                 prev = DLIST_PREV(la);
4556                 DLIST_REMOVE(replmd_private->la_list, la);
4557                 ret = replmd_process_linked_attribute(module, la, NULL);
4558                 if (ret != LDB_SUCCESS) {
4559                         replmd_txn_cleanup(replmd_private);
4560                         return ret;
4561                 }
4562         }
4563
4564         /* process our backlink list, creating and deleting backlinks
4565            as necessary */
4566         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
4567                 ret = replmd_process_backlink(module, bl, NULL);
4568                 if (ret != LDB_SUCCESS) {
4569                         replmd_txn_cleanup(replmd_private);
4570                         return ret;
4571                 }
4572         }
4573
4574         replmd_txn_cleanup(replmd_private);
4575
4576         /* possibly change @REPLCHANGED */
4577         ret = replmd_notify_store(module, NULL);
4578         if (ret != LDB_SUCCESS) {
4579                 return ret;
4580         }
4581
4582         return ldb_next_prepare_commit(module);
4583 }
4584
4585 static int replmd_del_transaction(struct ldb_module *module)
4586 {
4587         struct replmd_private *replmd_private =
4588                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4589         replmd_txn_cleanup(replmd_private);
4590
4591         return ldb_next_del_trans(module);
4592 }
4593
4594
4595 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
4596         .name          = "repl_meta_data",
4597         .init_context      = replmd_init,
4598         .add               = replmd_add,
4599         .modify            = replmd_modify,
4600         .rename            = replmd_rename,
4601         .del               = replmd_delete,
4602         .extended          = replmd_extended,
4603         .start_transaction = replmd_start_transaction,
4604         .prepare_commit    = replmd_prepare_commit,
4605         .del_transaction   = replmd_del_transaction,
4606 };
4607
4608 int ldb_repl_meta_data_module_init(const char *version)
4609 {
4610         LDB_MODULE_CHECK_VERSION(version);
4611         return ldb_register_module(&ldb_repl_meta_data_module_ops);
4612 }