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