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