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