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