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