dsdb: fix double-free in replication failure case on RODC
[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 || res->count != 1) {
1247                         DEBUG(0,(__location__ ": Object %s failed to find uSNChanged\n",
1248                                  ldb_dn_get_linearized(msg->dn)));
1249                         return LDB_ERR_OPERATIONS_ERROR;
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 || res->count != 1) {
1279                         DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1280                                  ldb_dn_get_linearized(msg->dn)));
1281                         return LDB_ERR_OPERATIONS_ERROR;
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                         /* Odd is for the target.  Illegal to modify */
2183                         ldb_asprintf_errstring(ldb,
2184                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2185                         return LDB_ERR_UNWILLING_TO_PERFORM;
2186                 }
2187                 old_el = ldb_msg_find_element(old_msg, el->name);
2188                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2189                 case LDB_FLAG_MOD_REPLACE:
2190                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2191                         break;
2192                 case LDB_FLAG_MOD_DELETE:
2193                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2194                         break;
2195                 case LDB_FLAG_MOD_ADD:
2196                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2197                         break;
2198                 default:
2199                         ldb_asprintf_errstring(ldb,
2200                                                "invalid flags 0x%x for %s linked attribute",
2201                                                el->flags, el->name);
2202                         return LDB_ERR_UNWILLING_TO_PERFORM;
2203                 }
2204                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2205                         ldb_asprintf_errstring(ldb,
2206                                                "Attribute %s is single valued but more than one value has been supplied",
2207                                                el->name);
2208                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2209                 } else {
2210                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2211                 }
2212
2213
2214
2215                 if (ret != LDB_SUCCESS) {
2216                         return ret;
2217                 }
2218                 if (old_el) {
2219                         ldb_msg_remove_attr(old_msg, el->name);
2220                 }
2221                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2222                 new_el->num_values = el->num_values;
2223                 new_el->values = talloc_steal(msg->elements, el->values);
2224
2225                 /* TODO: this relises a bit too heavily on the exact
2226                    behaviour of ldb_msg_find_element and
2227                    ldb_msg_remove_element */
2228                 old_el = ldb_msg_find_element(msg, el->name);
2229                 if (old_el != el) {
2230                         ldb_msg_remove_element(msg, old_el);
2231                         i--;
2232                 }
2233         }
2234
2235         talloc_free(res);
2236         return ret;
2237 }
2238
2239
2240
2241 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2242 {
2243         struct ldb_context *ldb;
2244         struct replmd_replicated_request *ac;
2245         struct ldb_request *down_req;
2246         struct ldb_message *msg;
2247         time_t t = time(NULL);
2248         int ret;
2249         bool is_urgent = false;
2250         struct loadparm_context *lp_ctx;
2251         char *referral;
2252         unsigned int functional_level;
2253         const DATA_BLOB *guid_blob;
2254
2255         /* do not manipulate our control entries */
2256         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2257                 return ldb_next_request(module, req);
2258         }
2259
2260         ldb = ldb_module_get_ctx(module);
2261
2262         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2263
2264         guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2265         if ( guid_blob != NULL ) {
2266                 ldb_set_errstring(ldb,
2267                                   "replmd_modify: it's not allowed to change the objectGUID!");
2268                 return LDB_ERR_CONSTRAINT_VIOLATION;
2269         }
2270
2271         ac = replmd_ctx_init(module, req);
2272         if (ac == NULL) {
2273                 return ldb_module_oom(module);
2274         }
2275
2276         functional_level = dsdb_functional_level(ldb);
2277
2278         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2279                                  struct loadparm_context);
2280
2281         /* we have to copy the message as the caller might have it as a const */
2282         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2283         if (msg == NULL) {
2284                 ldb_oom(ldb);
2285                 talloc_free(ac);
2286                 return LDB_ERR_OPERATIONS_ERROR;
2287         }
2288
2289         ldb_msg_remove_attr(msg, "whenChanged");
2290         ldb_msg_remove_attr(msg, "uSNChanged");
2291
2292         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2293                                  msg, &ac->seq_num, t, &is_urgent);
2294         if (ret == LDB_ERR_REFERRAL) {
2295                 referral = talloc_asprintf(req,
2296                                            "ldap://%s/%s",
2297                                            lpcfg_dnsdomain(lp_ctx),
2298                                            ldb_dn_get_linearized(msg->dn));
2299                 ret = ldb_module_send_referral(req, referral);
2300                 talloc_free(ac);
2301                 return ldb_module_done(req, NULL, NULL, ret);
2302         }
2303
2304         if (ret != LDB_SUCCESS) {
2305                 talloc_free(ac);
2306                 return ret;
2307         }
2308
2309         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2310         if (ret != LDB_SUCCESS) {
2311                 talloc_free(ac);
2312                 return ret;
2313         }
2314
2315         /* TODO:
2316          * - replace the old object with the newly constructed one
2317          */
2318
2319         ac->is_urgent = is_urgent;
2320
2321         ret = ldb_build_mod_req(&down_req, ldb, ac,
2322                                 msg,
2323                                 req->controls,
2324                                 ac, replmd_op_callback,
2325                                 req);
2326         LDB_REQ_SET_LOCATION(down_req);
2327         if (ret != LDB_SUCCESS) {
2328                 talloc_free(ac);
2329                 return ret;
2330         }
2331
2332         /* current partition control is needed by "replmd_op_callback" */
2333         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2334                 ret = ldb_request_add_control(down_req,
2335                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2336                                               false, NULL);
2337                 if (ret != LDB_SUCCESS) {
2338                         talloc_free(ac);
2339                         return ret;
2340                 }
2341         }
2342
2343         /* If we are in functional level 2000, then
2344          * replmd_modify_handle_linked_attribs will have done
2345          * nothing */
2346         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2347                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2348                 if (ret != LDB_SUCCESS) {
2349                         talloc_free(ac);
2350                         return ret;
2351                 }
2352         }
2353
2354         talloc_steal(down_req, msg);
2355
2356         /* we only change whenChanged and uSNChanged if the seq_num
2357            has changed */
2358         if (ac->seq_num != 0) {
2359                 ret = add_time_element(msg, "whenChanged", t);
2360                 if (ret != LDB_SUCCESS) {
2361                         talloc_free(ac);
2362                         return ret;
2363                 }
2364
2365                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2366                 if (ret != LDB_SUCCESS) {
2367                         talloc_free(ac);
2368                         return ret;
2369                 }
2370         }
2371
2372         /* go on with the call chain */
2373         return ldb_next_request(module, down_req);
2374 }
2375
2376 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2377
2378 /*
2379   handle a rename request
2380
2381   On a rename we need to do an extra ldb_modify which sets the
2382   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2383  */
2384 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2385 {
2386         struct ldb_context *ldb;
2387         struct replmd_replicated_request *ac;
2388         int ret;
2389         struct ldb_request *down_req;
2390
2391         /* do not manipulate our control entries */
2392         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2393                 return ldb_next_request(module, req);
2394         }
2395
2396         ldb = ldb_module_get_ctx(module);
2397
2398         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2399
2400         ac = replmd_ctx_init(module, req);
2401         if (ac == NULL) {
2402                 return ldb_module_oom(module);
2403         }
2404
2405         ret = ldb_build_rename_req(&down_req, ldb, ac,
2406                                    ac->req->op.rename.olddn,
2407                                    ac->req->op.rename.newdn,
2408                                    ac->req->controls,
2409                                    ac, replmd_rename_callback,
2410                                    ac->req);
2411         LDB_REQ_SET_LOCATION(down_req);
2412         if (ret != LDB_SUCCESS) {
2413                 talloc_free(ac);
2414                 return ret;
2415         }
2416
2417         /* go on with the call chain */
2418         return ldb_next_request(module, down_req);
2419 }
2420
2421 /* After the rename is compleated, update the whenchanged etc */
2422 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2423 {
2424         struct ldb_context *ldb;
2425         struct replmd_replicated_request *ac;
2426         struct ldb_request *down_req;
2427         struct ldb_message *msg;
2428         const struct dsdb_attribute *rdn_attr;
2429         const char *rdn_name;
2430         const struct ldb_val *rdn_val;
2431         const char *attrs[5] = { NULL, };
2432         time_t t = time(NULL);
2433         int ret;
2434         bool is_urgent = false;
2435
2436         ac = talloc_get_type(req->context, struct replmd_replicated_request);
2437         ldb = ldb_module_get_ctx(ac->module);
2438
2439         if (ares->error != LDB_SUCCESS) {
2440                 return ldb_module_done(ac->req, ares->controls,
2441                                         ares->response, ares->error);
2442         }
2443
2444         if (ares->type != LDB_REPLY_DONE) {
2445                 ldb_set_errstring(ldb,
2446                                   "invalid ldb_reply_type in callback");
2447                 talloc_free(ares);
2448                 return ldb_module_done(ac->req, NULL, NULL,
2449                                         LDB_ERR_OPERATIONS_ERROR);
2450         }
2451
2452         /* TODO:
2453          * - replace the old object with the newly constructed one
2454          */
2455
2456         msg = ldb_msg_new(ac);
2457         if (msg == NULL) {
2458                 ldb_oom(ldb);
2459                 return LDB_ERR_OPERATIONS_ERROR;
2460         }
2461
2462         msg->dn = ac->req->op.rename.newdn;
2463
2464         rdn_name = ldb_dn_get_rdn_name(msg->dn);
2465         if (rdn_name == NULL) {
2466                 talloc_free(ares);
2467                 return ldb_module_done(ac->req, NULL, NULL,
2468                                        ldb_operr(ldb));
2469         }
2470
2471         /* normalize the rdn attribute name */
2472         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2473         if (rdn_attr == NULL) {
2474                 talloc_free(ares);
2475                 return ldb_module_done(ac->req, NULL, NULL,
2476                                        ldb_operr(ldb));
2477         }
2478         rdn_name = rdn_attr->lDAPDisplayName;
2479
2480         rdn_val = ldb_dn_get_rdn_val(msg->dn);
2481         if (rdn_val == NULL) {
2482                 talloc_free(ares);
2483                 return ldb_module_done(ac->req, NULL, NULL,
2484                                        ldb_operr(ldb));
2485         }
2486
2487         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2488                 talloc_free(ares);
2489                 return ldb_module_done(ac->req, NULL, NULL,
2490                                        ldb_oom(ldb));
2491         }
2492         if (ldb_msg_add_value(msg, rdn_name, rdn_val, 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_empty(msg, "name", LDB_FLAG_MOD_REPLACE, 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_value(msg, "name", rdn_val, NULL) != 0) {
2503                 talloc_free(ares);
2504                 return ldb_module_done(ac->req, NULL, NULL,
2505                                        ldb_oom(ldb));
2506         }
2507
2508         /*
2509          * here we let replmd_update_rpmd() only search for
2510          * the existing "replPropertyMetaData" and rdn_name attributes.
2511          *
2512          * We do not want the existing "name" attribute as
2513          * the "name" attribute needs to get the version
2514          * updated on rename even if the rdn value hasn't changed.
2515          *
2516          * This is the diff of the meta data, for a moved user
2517          * on a w2k8r2 server:
2518          *
2519          * # record 1
2520          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2521          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2522          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
2523          *         version                  : 0x00000001 (1)
2524          *         reserved                 : 0x00000000 (0)
2525          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
2526          *                      local_usn                : 0x00000000000037a5 (14245)
2527          *                 array: struct replPropertyMetaData1
2528          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
2529          * -                    version                  : 0x00000001 (1)
2530          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
2531          * +                    version                  : 0x00000002 (2)
2532          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
2533          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2534          * -                    originating_usn          : 0x00000000000037a5 (14245)
2535          * -                    local_usn                : 0x00000000000037a5 (14245)
2536          * +                    originating_usn          : 0x0000000000003834 (14388)
2537          * +                    local_usn                : 0x0000000000003834 (14388)
2538          *                 array: struct replPropertyMetaData1
2539          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
2540          *                      version                  : 0x00000004 (4)
2541          */
2542         attrs[0] = "replPropertyMetaData";
2543         attrs[1] = "objectClass";
2544         attrs[2] = "instanceType";
2545         attrs[3] = rdn_name;
2546         attrs[4] = NULL;
2547
2548         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2549                                  msg, &ac->seq_num, t, &is_urgent);
2550         if (ret == LDB_ERR_REFERRAL) {
2551                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2552                 struct loadparm_context *lp_ctx;
2553                 char *referral;
2554
2555                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2556                                          struct loadparm_context);
2557
2558                 referral = talloc_asprintf(req,
2559                                            "ldap://%s/%s",
2560                                            lpcfg_dnsdomain(lp_ctx),
2561                                            ldb_dn_get_linearized(olddn));
2562                 ret = ldb_module_send_referral(req, referral);
2563                 talloc_free(ares);
2564                 return ldb_module_done(req, NULL, NULL, ret);
2565         }
2566
2567         if (ret != LDB_SUCCESS) {
2568                 talloc_free(ares);
2569                 return ldb_module_done(ac->req, NULL, NULL,
2570                                        ldb_error(ldb, ret,
2571                                         "failed to call replmd_update_rpmd()"));
2572         }
2573
2574         if (ac->seq_num == 0) {
2575                 talloc_free(ares);
2576                 return ldb_module_done(ac->req, NULL, NULL,
2577                                        ldb_error(ldb, ret,
2578                                         "internal error seq_num == 0"));
2579         }
2580         ac->is_urgent = is_urgent;
2581
2582         ret = ldb_build_mod_req(&down_req, ldb, ac,
2583                                 msg,
2584                                 req->controls,
2585                                 ac, replmd_op_callback,
2586                                 req);
2587         LDB_REQ_SET_LOCATION(down_req);
2588         if (ret != LDB_SUCCESS) {
2589                 talloc_free(ac);
2590                 return ret;
2591         }
2592
2593         /* current partition control is needed by "replmd_op_callback" */
2594         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2595                 ret = ldb_request_add_control(down_req,
2596                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2597                                               false, NULL);
2598                 if (ret != LDB_SUCCESS) {
2599                         talloc_free(ac);
2600                         return ret;
2601                 }
2602         }
2603
2604         talloc_steal(down_req, msg);
2605
2606         ret = add_time_element(msg, "whenChanged", t);
2607         if (ret != LDB_SUCCESS) {
2608                 talloc_free(ac);
2609                 return ret;
2610         }
2611
2612         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2613         if (ret != LDB_SUCCESS) {
2614                 talloc_free(ac);
2615                 return ret;
2616         }
2617
2618         /* go on with the call chain - do the modify after the rename */
2619         return ldb_next_request(ac->module, down_req);
2620 }
2621
2622 /*
2623    remove links from objects that point at this object when an object
2624    is deleted
2625  */
2626 static int replmd_delete_remove_link(struct ldb_module *module,
2627                                      const struct dsdb_schema *schema,
2628                                      struct ldb_dn *dn,
2629                                      struct ldb_message_element *el,
2630                                      const struct dsdb_attribute *sa,
2631                                      struct ldb_request *parent)
2632 {
2633         unsigned int i;
2634         TALLOC_CTX *tmp_ctx = talloc_new(module);
2635         struct ldb_context *ldb = ldb_module_get_ctx(module);
2636
2637         for (i=0; i<el->num_values; i++) {
2638                 struct dsdb_dn *dsdb_dn;
2639                 NTSTATUS status;
2640                 int ret;
2641                 struct GUID guid2;
2642                 struct ldb_message *msg;
2643                 const struct dsdb_attribute *target_attr;
2644                 struct ldb_message_element *el2;
2645                 struct ldb_val dn_val;
2646
2647                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2648                         continue;
2649                 }
2650
2651                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2652                 if (!dsdb_dn) {
2653                         talloc_free(tmp_ctx);
2654                         return LDB_ERR_OPERATIONS_ERROR;
2655                 }
2656
2657                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2658                 if (!NT_STATUS_IS_OK(status)) {
2659                         talloc_free(tmp_ctx);
2660                         return LDB_ERR_OPERATIONS_ERROR;
2661                 }
2662
2663                 /* remove the link */
2664                 msg = ldb_msg_new(tmp_ctx);
2665                 if (!msg) {
2666                         ldb_module_oom(module);
2667                         talloc_free(tmp_ctx);
2668                         return LDB_ERR_OPERATIONS_ERROR;
2669                 }
2670
2671
2672                 msg->dn = dsdb_dn->dn;
2673
2674                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2675                 if (target_attr == NULL) {
2676                         continue;
2677                 }
2678
2679                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2680                 if (ret != LDB_SUCCESS) {
2681                         ldb_module_oom(module);
2682                         talloc_free(tmp_ctx);
2683                         return LDB_ERR_OPERATIONS_ERROR;
2684                 }
2685                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2686                 el2->values = &dn_val;
2687                 el2->num_values = 1;
2688
2689                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2690                 if (ret != LDB_SUCCESS) {
2691                         talloc_free(tmp_ctx);
2692                         return ret;
2693                 }
2694         }
2695         talloc_free(tmp_ctx);
2696         return LDB_SUCCESS;
2697 }
2698
2699
2700 /*
2701   handle update of replication meta data for deletion of objects
2702
2703   This also handles the mapping of delete to a rename operation
2704   to allow deletes to be replicated.
2705  */
2706 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2707 {
2708         int ret = LDB_ERR_OTHER;
2709         bool retb, disallow_move_on_delete;
2710         struct ldb_dn *old_dn, *new_dn;
2711         const char *rdn_name;
2712         const struct ldb_val *rdn_value, *new_rdn_value;
2713         struct GUID guid;
2714         struct ldb_context *ldb = ldb_module_get_ctx(module);
2715         const struct dsdb_schema *schema;
2716         struct ldb_message *msg, *old_msg;
2717         struct ldb_message_element *el;
2718         TALLOC_CTX *tmp_ctx;
2719         struct ldb_result *res, *parent_res;
2720         const char *preserved_attrs[] = {
2721                 /* yes, this really is a hard coded list. See MS-ADTS
2722                    section 3.1.1.5.5.1.1 */
2723                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2724                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2725                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2726                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2727                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2728                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2729                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2730                 "whenChanged", NULL};
2731         unsigned int i, el_count = 0;
2732         enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2733                                                 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2734         enum deletion_state deletion_state, next_deletion_state;
2735         bool enabled;
2736         int functional_level;
2737
2738         if (ldb_dn_is_special(req->op.del.dn)) {
2739                 return ldb_next_request(module, req);
2740         }
2741
2742         tmp_ctx = talloc_new(ldb);
2743         if (!tmp_ctx) {
2744                 ldb_oom(ldb);
2745                 return LDB_ERR_OPERATIONS_ERROR;
2746         }
2747
2748         schema = dsdb_get_schema(ldb, tmp_ctx);
2749         if (!schema) {
2750                 return LDB_ERR_OPERATIONS_ERROR;
2751         }
2752
2753         functional_level = dsdb_functional_level(ldb);
2754
2755         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2756
2757         /* we need the complete msg off disk, so we can work out which
2758            attributes need to be removed */
2759         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2760                                     DSDB_FLAG_NEXT_MODULE |
2761                                     DSDB_SEARCH_SHOW_RECYCLED |
2762                                     DSDB_SEARCH_REVEAL_INTERNALS |
2763                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2764         if (ret != LDB_SUCCESS) {
2765                 talloc_free(tmp_ctx);
2766                 return ret;
2767         }
2768         old_msg = res->msgs[0];
2769
2770
2771         ret = dsdb_recyclebin_enabled(module, &enabled);
2772         if (ret != LDB_SUCCESS) {
2773                 talloc_free(tmp_ctx);
2774                 return ret;
2775         }
2776
2777         if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2778                 if (!enabled) {
2779                         deletion_state = OBJECT_TOMBSTONE;
2780                         next_deletion_state = OBJECT_REMOVED;
2781                 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2782                         deletion_state = OBJECT_RECYCLED;
2783                         next_deletion_state = OBJECT_REMOVED;
2784                 } else {
2785                         deletion_state = OBJECT_DELETED;
2786                         next_deletion_state = OBJECT_RECYCLED;
2787                 }
2788         } else {
2789                 deletion_state = OBJECT_NOT_DELETED;
2790                 if (enabled) {
2791                         next_deletion_state = OBJECT_DELETED;
2792                 } else {
2793                         next_deletion_state = OBJECT_TOMBSTONE;
2794                 }
2795         }
2796
2797         if (next_deletion_state == OBJECT_REMOVED) {
2798                 struct auth_session_info *session_info =
2799                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2800                 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2801                         ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2802                                         ldb_dn_get_linearized(old_msg->dn));
2803                         return LDB_ERR_UNWILLING_TO_PERFORM;
2804                 }
2805
2806                 /* it is already deleted - really remove it this time */
2807                 talloc_free(tmp_ctx);
2808                 return ldb_next_request(module, req);
2809         }
2810
2811         rdn_name = ldb_dn_get_rdn_name(old_dn);
2812         rdn_value = ldb_dn_get_rdn_val(old_dn);
2813         if ((rdn_name == NULL) || (rdn_value == NULL)) {
2814                 talloc_free(tmp_ctx);
2815                 return ldb_operr(ldb);
2816         }
2817
2818         msg = ldb_msg_new(tmp_ctx);
2819         if (msg == NULL) {
2820                 ldb_module_oom(module);
2821                 talloc_free(tmp_ctx);
2822                 return LDB_ERR_OPERATIONS_ERROR;
2823         }
2824
2825         msg->dn = old_dn;
2826
2827         if (deletion_state == OBJECT_NOT_DELETED){
2828                 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2829                 disallow_move_on_delete =
2830                         (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2831                                 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2832
2833                 /* work out where we will be renaming this object to */
2834                 if (!disallow_move_on_delete) {
2835                         ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2836                                                           &new_dn);
2837                         if (ret != LDB_SUCCESS) {
2838                                 /* this is probably an attempted delete on a partition
2839                                  * that doesn't allow delete operations, such as the
2840                                  * schema partition */
2841                                 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2842                                                            ldb_dn_get_linearized(old_dn));
2843                                 talloc_free(tmp_ctx);
2844                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2845                         }
2846                 } else {
2847                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2848                         if (new_dn == NULL) {
2849                                 ldb_module_oom(module);
2850                                 talloc_free(tmp_ctx);
2851                                 return LDB_ERR_OPERATIONS_ERROR;
2852                         }
2853                 }
2854
2855                 /* get the objects GUID from the search we just did */
2856                 guid = samdb_result_guid(old_msg, "objectGUID");
2857
2858                 /* Add a formatted child */
2859                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2860                                                 rdn_name,
2861                                                 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2862                                                 GUID_string(tmp_ctx, &guid));
2863                 if (!retb) {
2864                         DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2865                                         ldb_dn_get_linearized(new_dn)));
2866                         talloc_free(tmp_ctx);
2867                         return LDB_ERR_OPERATIONS_ERROR;
2868                 }
2869
2870                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2871                 if (ret != LDB_SUCCESS) {
2872                         DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2873                         ldb_module_oom(module);
2874                         talloc_free(tmp_ctx);
2875                         return ret;
2876                 }
2877                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2878         }
2879
2880         /*
2881           now we need to modify the object in the following ways:
2882
2883           - add isDeleted=TRUE
2884           - update rDN and name, with new rDN
2885           - remove linked attributes
2886           - remove objectCategory and sAMAccountType
2887           - remove attribs not on the preserved list
2888              - preserved if in above list, or is rDN
2889           - remove all linked attribs from this object
2890           - remove all links from other objects to this object
2891           - add lastKnownParent
2892           - update replPropertyMetaData?
2893
2894           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2895          */
2896
2897         /* we need the storage form of the parent GUID */
2898         ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2899                                     ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2900                                     DSDB_FLAG_NEXT_MODULE |
2901                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2902                                     DSDB_SEARCH_REVEAL_INTERNALS|
2903                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2904         if (ret != LDB_SUCCESS) {
2905                 talloc_free(tmp_ctx);
2906                 return ret;
2907         }
2908
2909         if (deletion_state == OBJECT_NOT_DELETED){
2910                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2911                                                    ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2912                 if (ret != LDB_SUCCESS) {
2913                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2914                         ldb_module_oom(module);
2915                         talloc_free(tmp_ctx);
2916                         return ret;
2917                 }
2918                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2919         }
2920
2921         switch (next_deletion_state){
2922
2923         case OBJECT_DELETED:
2924
2925                 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2926                 if (ret != LDB_SUCCESS) {
2927                         DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2928                         ldb_module_oom(module);
2929                         talloc_free(tmp_ctx);
2930                         return ret;
2931                 }
2932                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2933
2934                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_DELETE, NULL);
2935                 if (ret != LDB_SUCCESS) {
2936                         talloc_free(tmp_ctx);
2937                         ldb_module_oom(module);
2938                         return ret;
2939                 }
2940
2941                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_DELETE, NULL);
2942                 if (ret != LDB_SUCCESS) {
2943                         talloc_free(tmp_ctx);
2944                         ldb_module_oom(module);
2945                         return ret;
2946                 }
2947
2948                 break;
2949
2950         case OBJECT_RECYCLED:
2951         case OBJECT_TOMBSTONE:
2952
2953                 /* we also mark it as recycled, meaning this object can't be
2954                    recovered (we are stripping its attributes) */
2955                 if (functional_level >= DS_DOMAIN_FUNCTION_2008_R2) {
2956                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2957                         if (ret != LDB_SUCCESS) {
2958                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2959                                 ldb_module_oom(module);
2960                                 talloc_free(tmp_ctx);
2961                                 return ret;
2962                         }
2963                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2964                 }
2965
2966                 /* work out which of the old attributes we will be removing */
2967                 for (i=0; i<old_msg->num_elements; i++) {
2968                         const struct dsdb_attribute *sa;
2969                         el = &old_msg->elements[i];
2970                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2971                         if (!sa) {
2972                                 talloc_free(tmp_ctx);
2973                                 return LDB_ERR_OPERATIONS_ERROR;
2974                         }
2975                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2976                                 /* don't remove the rDN */
2977                                 continue;
2978                         }
2979                         if (sa->linkID && (sa->linkID & 1)) {
2980                                 /*
2981                                   we have a backlink in this object
2982                                   that needs to be removed. We're not
2983                                   allowed to remove it directly
2984                                   however, so we instead setup a
2985                                   modify to delete the corresponding
2986                                   forward link
2987                                  */
2988                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
2989                                 if (ret != LDB_SUCCESS) {
2990                                         talloc_free(tmp_ctx);
2991                                         return LDB_ERR_OPERATIONS_ERROR;
2992                                 }
2993                                 /* now we continue, which means we
2994                                    won't remove this backlink
2995                                    directly
2996                                 */
2997                                 continue;
2998                         }
2999                         if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
3000                                 continue;
3001                         }
3002                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3003                         if (ret != LDB_SUCCESS) {
3004                                 talloc_free(tmp_ctx);
3005                                 ldb_module_oom(module);
3006                                 return ret;
3007                         }
3008                 }
3009                 break;
3010
3011         default:
3012                 break;
3013         }
3014
3015         if (deletion_state == OBJECT_NOT_DELETED) {
3016                 const struct dsdb_attribute *sa;
3017
3018                 /* work out what the new rdn value is, for updating the
3019                    rDN and name fields */
3020                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3021                 if (new_rdn_value == NULL) {
3022                         talloc_free(tmp_ctx);
3023                         return ldb_operr(ldb);
3024                 }
3025
3026                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3027                 if (!sa) {
3028                         talloc_free(tmp_ctx);
3029                         return LDB_ERR_OPERATIONS_ERROR;
3030                 }
3031
3032                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3033                                         &el);
3034                 if (ret != LDB_SUCCESS) {
3035                         talloc_free(tmp_ctx);
3036                         return ret;
3037                 }
3038                 el->flags = LDB_FLAG_MOD_REPLACE;
3039
3040                 el = ldb_msg_find_element(old_msg, "name");
3041                 if (el) {
3042                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3043                         if (ret != LDB_SUCCESS) {
3044                                 talloc_free(tmp_ctx);
3045                                 return ret;
3046                         }
3047                         el->flags = LDB_FLAG_MOD_REPLACE;
3048                 }
3049         }
3050
3051         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3052         if (ret != LDB_SUCCESS) {
3053                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3054                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3055                 talloc_free(tmp_ctx);
3056                 return ret;
3057         }
3058
3059         if (deletion_state == OBJECT_NOT_DELETED) {
3060                 /* now rename onto the new DN */
3061                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3062                 if (ret != LDB_SUCCESS){
3063                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3064                                  ldb_dn_get_linearized(old_dn),
3065                                  ldb_dn_get_linearized(new_dn),
3066                                  ldb_errstring(ldb)));
3067                         talloc_free(tmp_ctx);
3068                         return ret;
3069                 }
3070         }
3071
3072         talloc_free(tmp_ctx);
3073
3074         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3075 }
3076
3077
3078
3079 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3080 {
3081         return ret;
3082 }
3083
3084 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3085 {
3086         int ret = LDB_ERR_OTHER;
3087         /* TODO: do some error mapping */
3088         return ret;
3089 }
3090
3091
3092 static struct replPropertyMetaData1 *
3093 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3094                                         enum drsuapi_DsAttributeId attid)
3095 {
3096         uint32_t i;
3097         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3098
3099         for (i = 0; i < rpmd_ctr->count; i++) {
3100                 if (rpmd_ctr->array[i].attid == attid) {
3101                         return &rpmd_ctr->array[i];
3102                 }
3103         }
3104         return NULL;
3105 }
3106
3107
3108 /*
3109    return true if an update is newer than an existing entry
3110    see section 5.11 of MS-ADTS
3111 */
3112 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3113                                    const struct GUID *update_invocation_id,
3114                                    uint32_t current_version,
3115                                    uint32_t update_version,
3116                                    NTTIME current_change_time,
3117                                    NTTIME update_change_time)
3118 {
3119         if (update_version != current_version) {
3120                 return update_version > current_version;
3121         }
3122         if (update_change_time != current_change_time) {
3123                 return update_change_time > current_change_time;
3124         }
3125         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3126 }
3127
3128 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3129                                                   struct replPropertyMetaData1 *new_m)
3130 {
3131         return replmd_update_is_newer(&cur_m->originating_invocation_id,
3132                                       &new_m->originating_invocation_id,
3133                                       cur_m->version,
3134                                       new_m->version,
3135                                       cur_m->originating_change_time,
3136                                       new_m->originating_change_time);
3137 }
3138
3139
3140 /*
3141   form a conflict DN
3142  */
3143 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3144 {
3145         const struct ldb_val *rdn_val;
3146         const char *rdn_name;
3147         struct ldb_dn *new_dn;
3148
3149         rdn_val = ldb_dn_get_rdn_val(dn);
3150         rdn_name = ldb_dn_get_rdn_name(dn);
3151         if (!rdn_val || !rdn_name) {
3152                 return NULL;
3153         }
3154
3155         new_dn = ldb_dn_copy(mem_ctx, dn);
3156         if (!new_dn) {
3157                 return NULL;
3158         }
3159
3160         if (!ldb_dn_remove_child_components(new_dn, 1)) {
3161                 return NULL;
3162         }
3163
3164         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3165                                   rdn_name,
3166                                   ldb_dn_escape_value(new_dn, *rdn_val),
3167                                   GUID_string(new_dn, guid))) {
3168                 return NULL;
3169         }
3170
3171         return new_dn;
3172 }
3173
3174
3175 /*
3176   perform a modify operation which sets the rDN and name attributes to
3177   their current values. This has the effect of changing these
3178   attributes to have been last updated by the current DC. This is
3179   needed to ensure that renames performed as part of conflict
3180   resolution are propogated to other DCs
3181  */
3182 static int replmd_name_modify(struct replmd_replicated_request *ar,
3183                               struct ldb_request *req, struct ldb_dn *dn)
3184 {
3185         struct ldb_message *msg;
3186         const char *rdn_name;
3187         const struct ldb_val *rdn_val;
3188         const struct dsdb_attribute *rdn_attr;
3189         int ret;
3190
3191         msg = ldb_msg_new(req);
3192         if (msg == NULL) {
3193                 goto failed;
3194         }
3195         msg->dn = dn;
3196
3197         rdn_name = ldb_dn_get_rdn_name(dn);
3198         if (rdn_name == NULL) {
3199                 goto failed;
3200         }
3201
3202         /* normalize the rdn attribute name */
3203         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3204         if (rdn_attr == NULL) {
3205                 goto failed;
3206         }
3207         rdn_name = rdn_attr->lDAPDisplayName;
3208
3209         rdn_val = ldb_dn_get_rdn_val(dn);
3210         if (rdn_val == NULL) {
3211                 goto failed;
3212         }
3213
3214         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3215                 goto failed;
3216         }
3217         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3218                 goto failed;
3219         }
3220         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3221                 goto failed;
3222         }
3223         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3224                 goto failed;
3225         }
3226
3227         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3228         if (ret != LDB_SUCCESS) {
3229                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3230                          ldb_dn_get_linearized(dn),
3231                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3232                 return ret;
3233         }
3234
3235         talloc_free(msg);
3236
3237         return LDB_SUCCESS;
3238
3239 failed:
3240         talloc_free(msg);
3241         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3242                  ldb_dn_get_linearized(dn)));
3243         return LDB_ERR_OPERATIONS_ERROR;
3244 }
3245
3246
3247 /*
3248   callback for conflict DN handling where we have renamed the incoming
3249   record. After renaming it, we need to ensure the change of name and
3250   rDN for the incoming record is seen as an originating update by this DC.
3251  */
3252 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3253 {
3254         struct replmd_replicated_request *ar =
3255                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3256         int ret;
3257
3258         if (ares->error != LDB_SUCCESS) {
3259                 /* call the normal callback for everything except success */
3260                 return replmd_op_callback(req, ares);
3261         }
3262
3263         /* perform a modify of the rDN and name of the record */
3264         ret = replmd_name_modify(ar, req, req->op.add.message->dn);
3265         if (ret != LDB_SUCCESS) {
3266                 ares->error = ret;
3267                 return replmd_op_callback(req, ares);
3268         }
3269
3270         return replmd_op_callback(req, ares);
3271 }
3272
3273 /*
3274   callback for replmd_replicated_apply_add()
3275   This copes with the creation of conflict records in the case where
3276   the DN exists, but with a different objectGUID
3277  */
3278 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3279 {
3280         struct ldb_dn *conflict_dn;
3281         struct replmd_replicated_request *ar =
3282                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3283         struct ldb_result *res;
3284         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3285         int ret;
3286         const struct ldb_val *rmd_value, *omd_value;
3287         struct replPropertyMetaDataBlob omd, rmd;
3288         enum ndr_err_code ndr_err;
3289         bool rename_incoming_record;
3290         struct replPropertyMetaData1 *rmd_name, *omd_name;
3291
3292         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3293                 /* call the normal callback for everything except
3294                    conflicts */
3295                 return replmd_op_callback(req, ares);
3296         }
3297
3298         /*
3299          * we have a conflict, and need to decide if we will keep the
3300          * new record or the old record
3301          */
3302         conflict_dn = req->op.add.message->dn;
3303
3304         /*
3305          * first we need the replPropertyMetaData attribute from the
3306          * old record
3307          */
3308         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3309                                     attrs,
3310                                     DSDB_FLAG_NEXT_MODULE |
3311                                     DSDB_SEARCH_SHOW_DELETED |
3312                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3313         if (ret != LDB_SUCCESS) {
3314                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3315                          ldb_dn_get_linearized(conflict_dn)));
3316                 goto failed;
3317         }
3318
3319         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3320         if (omd_value == NULL) {
3321                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3322                          ldb_dn_get_linearized(conflict_dn)));
3323                 goto failed;
3324         }
3325
3326         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3327                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3328         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3329                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3330                          ldb_dn_get_linearized(conflict_dn)));
3331                 goto failed;
3332         }
3333
3334         /*
3335          * and the replPropertyMetaData attribute from the
3336          * new record
3337          */
3338         rmd_value = ldb_msg_find_ldb_val(req->op.add.message, "replPropertyMetaData");
3339         if (rmd_value == NULL) {
3340                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for new record '%s'\n",
3341                          ldb_dn_get_linearized(conflict_dn)));
3342                 goto failed;
3343         }
3344
3345         ndr_err = ndr_pull_struct_blob(rmd_value, req, &rmd,
3346                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3347         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3348                 DEBUG(0,(__location__ ": Failed to parse new replPropertyMetaData for %s\n",
3349                          ldb_dn_get_linearized(conflict_dn)));
3350                 goto failed;
3351         }
3352
3353         /* we decide which is newer based on the RPMD on the name
3354            attribute.  See [MS-DRSR] ResolveNameConflict */
3355         rmd_name = replmd_replPropertyMetaData1_find_attid(&rmd, DRSUAPI_ATTID_name);
3356         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3357         if (!rmd_name || !omd_name) {
3358                 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3359                          ldb_dn_get_linearized(conflict_dn)));
3360                 goto failed;
3361         }
3362
3363         rename_incoming_record = !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3364
3365         if (rename_incoming_record) {
3366                 struct GUID guid;
3367                 struct ldb_dn *new_dn;
3368                 struct ldb_message *new_msg;
3369
3370                 guid = samdb_result_guid(req->op.add.message, "objectGUID");
3371                 if (GUID_all_zero(&guid)) {
3372                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3373                                  ldb_dn_get_linearized(conflict_dn)));
3374                         goto failed;
3375                 }
3376                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3377                 if (new_dn == NULL) {
3378                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3379                                  ldb_dn_get_linearized(conflict_dn)));
3380                         goto failed;
3381                 }
3382
3383                 DEBUG(1,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3384                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3385
3386                 /* re-submit the request, but with a different
3387                    callback, so we don't loop forever. */
3388                 new_msg = ldb_msg_copy_shallow(req, req->op.add.message);
3389                 if (!new_msg) {
3390                         goto failed;
3391                         DEBUG(0,(__location__ ": Failed to copy conflict DN message for %s\n",
3392                                  ldb_dn_get_linearized(conflict_dn)));
3393                 }
3394                 new_msg->dn = new_dn;
3395                 req->op.add.message = new_msg;
3396                 req->callback = replmd_op_name_modify_callback;
3397
3398                 return ldb_next_request(ar->module, req);
3399         } else {
3400                 /* we are renaming the existing record */
3401                 struct GUID guid;
3402                 struct ldb_dn *new_dn;
3403
3404                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3405                 if (GUID_all_zero(&guid)) {
3406                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3407                                  ldb_dn_get_linearized(conflict_dn)));
3408                         goto failed;
3409                 }
3410
3411                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3412                 if (new_dn == NULL) {
3413                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3414                                  ldb_dn_get_linearized(conflict_dn)));
3415                         goto failed;
3416                 }
3417
3418                 DEBUG(1,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
3419                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3420
3421                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3422                                          DSDB_FLAG_OWN_MODULE, req);
3423                 if (ret != LDB_SUCCESS) {
3424                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3425                                  ldb_dn_get_linearized(conflict_dn),
3426                                  ldb_dn_get_linearized(new_dn),
3427                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3428                         goto failed;
3429                 }
3430
3431                 /*
3432                  * now we need to ensure that the rename is seen as an
3433                  * originating update. We do that with a modify.
3434                  */
3435                 ret = replmd_name_modify(ar, req, new_dn);
3436                 if (ret != LDB_SUCCESS) {
3437                         goto failed;
3438                 }
3439
3440                 req->callback = replmd_op_callback;
3441
3442                 return ldb_next_request(ar->module, req);
3443         }
3444
3445 failed:
3446         /* on failure do the original callback. This means replication
3447          * will stop with an error, but there is not much else we can
3448          * do
3449          */
3450         return replmd_op_callback(req, ares);
3451 }
3452
3453 /*
3454   this is called when a new object comes in over DRS
3455  */
3456 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3457 {
3458         struct ldb_context *ldb;
3459         struct ldb_request *change_req;
3460         enum ndr_err_code ndr_err;
3461         struct ldb_message *msg;
3462         struct replPropertyMetaDataBlob *md;
3463         struct ldb_val md_value;
3464         unsigned int i;
3465         int ret;
3466
3467         /*
3468          * TODO: check if the parent object exist
3469          */
3470
3471         /*
3472          * TODO: handle the conflict case where an object with the
3473          *       same name exist
3474          */
3475
3476         ldb = ldb_module_get_ctx(ar->module);
3477         msg = ar->objs->objects[ar->index_current].msg;
3478         md = ar->objs->objects[ar->index_current].meta_data;
3479
3480         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3481         if (ret != LDB_SUCCESS) {
3482                 return replmd_replicated_request_error(ar, ret);
3483         }
3484
3485         ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
3486         if (ret != LDB_SUCCESS) {
3487                 return replmd_replicated_request_error(ar, ret);
3488         }
3489
3490         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3491         if (ret != LDB_SUCCESS) {
3492                 return replmd_replicated_request_error(ar, ret);
3493         }
3494
3495         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
3496         if (ret != LDB_SUCCESS) {
3497                 return replmd_replicated_request_error(ar, ret);
3498         }
3499
3500         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3501         if (ret != LDB_SUCCESS) {
3502                 return replmd_replicated_request_error(ar, ret);
3503         }
3504
3505         /* remove any message elements that have zero values */
3506         for (i=0; i<msg->num_elements; i++) {
3507                 struct ldb_message_element *el = &msg->elements[i];
3508
3509                 if (el->num_values == 0) {
3510                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
3511                                  el->name));
3512                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
3513                         msg->num_elements--;
3514                         i--;
3515                         continue;
3516                 }
3517         }
3518
3519         /*
3520          * the meta data array is already sorted by the caller
3521          */
3522         for (i=0; i < md->ctr.ctr1.count; i++) {
3523                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3524         }
3525         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3526                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3527         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3528                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3529                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3530         }
3531         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3532         if (ret != LDB_SUCCESS) {
3533                 return replmd_replicated_request_error(ar, ret);
3534         }
3535
3536         replmd_ldb_message_sort(msg, ar->schema);
3537
3538         if (DEBUGLVL(4)) {
3539                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3540                 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3541                 talloc_free(s);
3542         }
3543
3544         ret = ldb_build_add_req(&change_req,
3545                                 ldb,
3546                                 ar,
3547                                 msg,
3548                                 ar->controls,
3549                                 ar,
3550                                 replmd_op_add_callback,
3551                                 ar->req);
3552         LDB_REQ_SET_LOCATION(change_req);
3553         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3554
3555         /* current partition control needed by "repmd_op_callback" */
3556         ret = ldb_request_add_control(change_req,
3557                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3558                                       false, NULL);
3559         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3560
3561         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
3562                 /* this tells the partition module to make it a
3563                    partial replica if creating an NC */
3564                 ret = ldb_request_add_control(change_req,
3565                                               DSDB_CONTROL_PARTIAL_REPLICA,
3566                                               false, NULL);
3567                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3568         }
3569
3570         return ldb_next_request(ar->module, change_req);
3571 }
3572
3573 /*
3574   handle renames that come in over DRS replication
3575  */
3576 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
3577                                            struct ldb_message *msg,
3578                                            struct replPropertyMetaDataBlob *rmd,
3579                                            struct replPropertyMetaDataBlob *omd,
3580                                            struct ldb_request *parent)
3581 {
3582         struct replPropertyMetaData1 *md_remote;
3583         struct replPropertyMetaData1 *md_local;
3584
3585         if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3586                 /* no rename */
3587                 return LDB_SUCCESS;
3588         }
3589
3590         /* now we need to check for double renames. We could have a
3591          * local rename pending which our replication partner hasn't
3592          * received yet. We choose which one wins by looking at the
3593          * attribute stamps on the two objects, the newer one wins
3594          */
3595         md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3596         md_local  = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3597         /* if there is no name attribute then we have to assume the
3598            object we've received is in fact newer */
3599         if (!md_remote || !md_local ||
3600             replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3601                 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3602                          ldb_dn_get_linearized(ar->search_msg->dn),
3603                          ldb_dn_get_linearized(msg->dn)));
3604                 /* pass rename to the next module
3605                  * so it doesn't appear as an originating update */
3606                 return dsdb_module_rename(ar->module,
3607                                           ar->search_msg->dn, msg->dn,
3608                                           DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX, parent);
3609         }
3610
3611         /* we're going to keep our old object */
3612         DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
3613                  ldb_dn_get_linearized(ar->search_msg->dn),
3614                  ldb_dn_get_linearized(msg->dn)));
3615         return LDB_SUCCESS;
3616 }
3617
3618
3619 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
3620 {
3621         struct ldb_context *ldb;
3622         struct ldb_request *change_req;
3623         enum ndr_err_code ndr_err;
3624         struct ldb_message *msg;
3625         struct replPropertyMetaDataBlob *rmd;
3626         struct replPropertyMetaDataBlob omd;
3627         const struct ldb_val *omd_value;
3628         struct replPropertyMetaDataBlob nmd;
3629         struct ldb_val nmd_value;
3630         unsigned int i;
3631         uint32_t j,ni=0;
3632         unsigned int removed_attrs = 0;
3633         int ret;
3634
3635         ldb = ldb_module_get_ctx(ar->module);
3636         msg = ar->objs->objects[ar->index_current].msg;
3637         rmd = ar->objs->objects[ar->index_current].meta_data;
3638         ZERO_STRUCT(omd);
3639         omd.version = 1;
3640
3641         /* find existing meta data */
3642         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
3643         if (omd_value) {
3644                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
3645                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3646                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3647                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3648                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3649                 }
3650
3651                 if (omd.version != 1) {
3652                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3653                 }
3654         }
3655
3656         /* handle renames that come in over DRS */
3657         ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
3658         if (ret != LDB_SUCCESS) {
3659                 ldb_debug(ldb, LDB_DEBUG_FATAL,
3660                           "replmd_replicated_request rename %s => %s failed - %s\n",
3661                           ldb_dn_get_linearized(ar->search_msg->dn),
3662                           ldb_dn_get_linearized(msg->dn),
3663                           ldb_errstring(ldb));
3664                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
3665         }
3666
3667         ZERO_STRUCT(nmd);
3668         nmd.version = 1;
3669         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
3670         nmd.ctr.ctr1.array = talloc_array(ar,
3671                                           struct replPropertyMetaData1,
3672                                           nmd.ctr.ctr1.count);
3673         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3674
3675         /* first copy the old meta data */
3676         for (i=0; i < omd.ctr.ctr1.count; i++) {
3677                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
3678                 ni++;
3679         }
3680
3681         ar->seq_num = 0;
3682         /* now merge in the new meta data */
3683         for (i=0; i < rmd->ctr.ctr1.count; i++) {
3684                 bool found = false;
3685
3686                 for (j=0; j < ni; j++) {
3687                         bool cmp;
3688
3689                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
3690                                 continue;
3691                         }
3692
3693                         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
3694                                 /* if we compare equal then do an
3695                                    update. This is used when a client
3696                                    asks for a FULL_SYNC, and can be
3697                                    used to recover a corrupt
3698                                    replica */
3699                                 cmp = !replmd_replPropertyMetaData1_is_newer(&rmd->ctr.ctr1.array[i],
3700                                                                              &nmd.ctr.ctr1.array[j]);
3701                         } else {
3702                                 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
3703                                                                             &rmd->ctr.ctr1.array[i]);
3704                         }
3705                         if (cmp) {
3706                                 /* replace the entry */
3707                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
3708                                 if (ar->seq_num == 0) {
3709                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3710                                         if (ret != LDB_SUCCESS) {
3711                                                 return replmd_replicated_request_error(ar, ret);
3712                                         }
3713                                 }
3714                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
3715                                 found = true;
3716                                 break;
3717                         }
3718
3719                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
3720                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
3721                                          msg->elements[i-removed_attrs].name,
3722                                          ldb_dn_get_linearized(msg->dn),
3723                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
3724                         }
3725
3726                         /* we don't want to apply this change so remove the attribute */
3727                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
3728                         removed_attrs++;
3729
3730                         found = true;
3731                         break;
3732                 }
3733
3734                 if (found) continue;
3735
3736                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
3737                 if (ar->seq_num == 0) {
3738                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3739                         if (ret != LDB_SUCCESS) {
3740                                 return replmd_replicated_request_error(ar, ret);
3741                         }
3742                 }
3743                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
3744                 ni++;
3745         }
3746
3747         /*
3748          * finally correct the size of the meta_data array
3749          */
3750         nmd.ctr.ctr1.count = ni;
3751
3752         /*
3753          * the rdn attribute (the alias for the name attribute),
3754          * 'cn' for most objects is the last entry in the meta data array
3755          * we have stored
3756          *
3757          * sort the new meta data array
3758          */
3759         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
3760         if (ret != LDB_SUCCESS) {
3761                 return ret;
3762         }
3763
3764         /*
3765          * check if some replicated attributes left, otherwise skip the ldb_modify() call
3766          */
3767         if (msg->num_elements == 0) {
3768                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
3769                           ar->index_current);
3770
3771                 ar->index_current++;
3772                 return replmd_replicated_apply_next(ar);
3773         }
3774
3775         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
3776                   ar->index_current, msg->num_elements);
3777
3778         /* create the meta data value */
3779         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
3780                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3781         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3782                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3783                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3784         }
3785
3786         /*
3787          * when we know that we'll modify the record, add the whenChanged, uSNChanged
3788          * and replPopertyMetaData attributes
3789          */
3790         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3791         if (ret != LDB_SUCCESS) {
3792                 return replmd_replicated_request_error(ar, ret);
3793         }
3794         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3795         if (ret != LDB_SUCCESS) {
3796                 return replmd_replicated_request_error(ar, ret);
3797         }
3798         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
3799         if (ret != LDB_SUCCESS) {
3800                 return replmd_replicated_request_error(ar, ret);
3801         }
3802
3803         replmd_ldb_message_sort(msg, ar->schema);
3804
3805         /* we want to replace the old values */
3806         for (i=0; i < msg->num_elements; i++) {
3807                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3808         }
3809
3810         if (DEBUGLVL(4)) {
3811                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3812                 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
3813                 talloc_free(s);
3814         }
3815
3816         ret = ldb_build_mod_req(&change_req,
3817                                 ldb,
3818                                 ar,
3819                                 msg,
3820                                 ar->controls,
3821                                 ar,
3822                                 replmd_op_callback,
3823                                 ar->req);
3824         LDB_REQ_SET_LOCATION(change_req);
3825         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3826
3827         /* current partition control needed by "repmd_op_callback" */
3828         ret = ldb_request_add_control(change_req,
3829                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3830                                       false, NULL);
3831         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3832
3833         return ldb_next_request(ar->module, change_req);
3834 }
3835
3836 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
3837                                                    struct ldb_reply *ares)
3838 {
3839         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3840                                                struct replmd_replicated_request);
3841         int ret;
3842
3843         if (!ares) {
3844                 return ldb_module_done(ar->req, NULL, NULL,
3845                                         LDB_ERR_OPERATIONS_ERROR);
3846         }
3847         if (ares->error != LDB_SUCCESS &&
3848             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3849                 return ldb_module_done(ar->req, ares->controls,
3850                                         ares->response, ares->error);
3851         }
3852
3853         switch (ares->type) {
3854         case LDB_REPLY_ENTRY:
3855                 ar->search_msg = talloc_steal(ar, ares->message);
3856                 break;
3857
3858         case LDB_REPLY_REFERRAL:
3859                 /* we ignore referrals */
3860                 break;
3861
3862         case LDB_REPLY_DONE:
3863                 if (ar->search_msg != NULL) {
3864                         ret = replmd_replicated_apply_merge(ar);
3865                 } else {
3866                         ret = replmd_replicated_apply_add(ar);
3867                 }
3868                 if (ret != LDB_SUCCESS) {
3869                         return ldb_module_done(ar->req, NULL, NULL, ret);
3870                 }
3871         }
3872
3873         talloc_free(ares);
3874         return LDB_SUCCESS;
3875 }
3876
3877 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3878
3879 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3880 {
3881         struct ldb_context *ldb;
3882         int ret;
3883         char *tmp_str;
3884         char *filter;
3885         struct ldb_request *search_req;
3886         struct ldb_search_options_control *options;
3887
3888         if (ar->index_current >= ar->objs->num_objects) {
3889                 /* done with it, go to next stage */
3890                 return replmd_replicated_uptodate_vector(ar);
3891         }
3892
3893         ldb = ldb_module_get_ctx(ar->module);
3894         ar->search_msg = NULL;
3895
3896         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3897         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3898
3899         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3900         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3901         talloc_free(tmp_str);
3902
3903         ret = ldb_build_search_req(&search_req,
3904                                    ldb,
3905                                    ar,
3906                                    NULL,
3907                                    LDB_SCOPE_SUBTREE,
3908                                    filter,
3909                                    NULL,
3910                                    NULL,
3911                                    ar,
3912                                    replmd_replicated_apply_search_callback,
3913                                    ar->req);
3914         LDB_REQ_SET_LOCATION(search_req);
3915
3916         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
3917                                       true, NULL);
3918         if (ret != LDB_SUCCESS) {
3919                 return ret;
3920         }
3921
3922         /* we need to cope with cross-partition links, so search for
3923            the GUID over all partitions */
3924         options = talloc(search_req, struct ldb_search_options_control);
3925         if (options == NULL) {
3926                 DEBUG(0, (__location__ ": out of memory\n"));
3927                 return LDB_ERR_OPERATIONS_ERROR;
3928         }
3929         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
3930
3931         ret = ldb_request_add_control(search_req,
3932                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
3933                                       true, options);
3934         if (ret != LDB_SUCCESS) {
3935                 return ret;
3936         }
3937
3938         return ldb_next_request(ar->module, search_req);
3939 }
3940
3941 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
3942                                                       struct ldb_reply *ares)
3943 {
3944         struct ldb_context *ldb;
3945         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3946                                                struct replmd_replicated_request);
3947         ldb = ldb_module_get_ctx(ar->module);
3948
3949         if (!ares) {
3950                 return ldb_module_done(ar->req, NULL, NULL,
3951                                         LDB_ERR_OPERATIONS_ERROR);
3952         }
3953         if (ares->error != LDB_SUCCESS) {
3954                 return ldb_module_done(ar->req, ares->controls,
3955                                         ares->response, ares->error);
3956         }
3957
3958         if (ares->type != LDB_REPLY_DONE) {
3959                 ldb_set_errstring(ldb, "Invalid reply type\n!");
3960                 return ldb_module_done(ar->req, NULL, NULL,
3961                                         LDB_ERR_OPERATIONS_ERROR);
3962         }
3963
3964         talloc_free(ares);
3965
3966         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
3967 }
3968
3969 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
3970 {
3971         struct ldb_context *ldb;
3972         struct ldb_request *change_req;
3973         enum ndr_err_code ndr_err;
3974         struct ldb_message *msg;
3975         struct replUpToDateVectorBlob ouv;
3976         const struct ldb_val *ouv_value;
3977         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
3978         struct replUpToDateVectorBlob nuv;
3979         struct ldb_val nuv_value;
3980         struct ldb_message_element *nuv_el = NULL;
3981         const struct GUID *our_invocation_id;
3982         struct ldb_message_element *orf_el = NULL;
3983         struct repsFromToBlob nrf;
3984         struct ldb_val *nrf_value = NULL;
3985         struct ldb_message_element *nrf_el = NULL;
3986         unsigned int i;
3987         uint32_t j,ni=0;
3988         bool found = false;
3989         time_t t = time(NULL);
3990         NTTIME now;
3991         int ret;
3992         uint32_t instanceType;
3993
3994         ldb = ldb_module_get_ctx(ar->module);
3995         ruv = ar->objs->uptodateness_vector;
3996         ZERO_STRUCT(ouv);
3997         ouv.version = 2;
3998         ZERO_STRUCT(nuv);
3999         nuv.version = 2;
4000
4001         unix_to_nt_time(&now, t);
4002
4003         if (ar->search_msg == NULL) {
4004                 /* this happens for a REPL_OBJ call where we are
4005                    creating the target object by replicating it. The
4006                    subdomain join code does this for the partition DN
4007                 */
4008                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
4009                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4010         }
4011
4012         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
4013         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
4014                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
4015                          ldb_dn_get_linearized(ar->search_msg->dn)));
4016                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4017         }
4018
4019         /*
4020          * first create the new replUpToDateVector
4021          */
4022         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
4023         if (ouv_value) {
4024                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
4025                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4026                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4027                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4028                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4029                 }
4030
4031                 if (ouv.version != 2) {
4032                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4033                 }
4034         }
4035
4036         /*
4037          * the new uptodateness vector will at least
4038          * contain 1 entry, one for the source_dsa
4039          *
4040          * plus optional values from our old vector and the one from the source_dsa
4041          */
4042         nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
4043         if (ruv) nuv.ctr.ctr2.count += ruv->count;
4044         nuv.ctr.ctr2.cursors = talloc_array(ar,
4045                                             struct drsuapi_DsReplicaCursor2,
4046                                             nuv.ctr.ctr2.count);
4047         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4048
4049         /* first copy the old vector */
4050         for (i=0; i < ouv.ctr.ctr2.count; i++) {
4051                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
4052                 ni++;
4053         }
4054
4055         /* get our invocation_id if we have one already attached to the ldb */
4056         our_invocation_id = samdb_ntds_invocation_id(ldb);
4057
4058         /* merge in the source_dsa vector is available */
4059         for (i=0; (ruv && i < ruv->count); i++) {
4060                 found = false;
4061
4062                 if (our_invocation_id &&
4063                     GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4064                                our_invocation_id)) {
4065                         continue;
4066                 }
4067
4068                 for (j=0; j < ni; j++) {
4069                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4070                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4071                                 continue;
4072                         }
4073
4074                         found = true;
4075
4076                         /*
4077                          * we update only the highest_usn and not the latest_sync_success time,
4078                          * because the last success stands for direct replication
4079                          */
4080                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
4081                                 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
4082                         }
4083                         break;
4084                 }
4085
4086                 if (found) continue;
4087
4088                 /* if it's not there yet, add it */
4089                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
4090                 ni++;
4091         }
4092
4093         /*
4094          * merge in the current highwatermark for the source_dsa
4095          */
4096         found = false;
4097         for (j=0; j < ni; j++) {
4098                 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
4099                                 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4100                         continue;
4101                 }
4102
4103                 found = true;
4104
4105                 /*
4106                  * here we update the highest_usn and last_sync_success time
4107                  * because we're directly replicating from the source_dsa
4108                  *
4109                  * and use the tmp_highest_usn because this is what we have just applied
4110                  * to our ldb
4111                  */
4112                 nuv.ctr.ctr2.cursors[j].highest_usn             = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4113                 nuv.ctr.ctr2.cursors[j].last_sync_success       = now;
4114                 break;
4115         }
4116         if (!found) {
4117                 /*
4118                  * here we update the highest_usn and last_sync_success time
4119                  * because we're directly replicating from the source_dsa
4120                  *
4121                  * and use the tmp_highest_usn because this is what we have just applied
4122                  * to our ldb
4123                  */
4124                 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
4125                 nuv.ctr.ctr2.cursors[ni].highest_usn            = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4126                 nuv.ctr.ctr2.cursors[ni].last_sync_success      = now;
4127                 ni++;
4128         }
4129
4130         /*
4131          * finally correct the size of the cursors array
4132          */
4133         nuv.ctr.ctr2.count = ni;
4134
4135         /*
4136          * sort the cursors
4137          */
4138         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
4139
4140         /*
4141          * create the change ldb_message
4142          */
4143         msg = ldb_msg_new(ar);
4144         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4145         msg->dn = ar->search_msg->dn;
4146
4147         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
4148                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
4149         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4150                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4151                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4152         }
4153         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
4154         if (ret != LDB_SUCCESS) {
4155                 return replmd_replicated_request_error(ar, ret);
4156         }
4157         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
4158
4159         /*
4160          * now create the new repsFrom value from the given repsFromTo1 structure
4161          */
4162         ZERO_STRUCT(nrf);
4163         nrf.version                                     = 1;
4164         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
4165         nrf.ctr.ctr1.highwatermark.highest_usn          = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
4166
4167         /*
4168          * first see if we already have a repsFrom value for the current source dsa
4169          * if so we'll later replace this value
4170          */
4171         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
4172         if (orf_el) {
4173                 for (i=0; i < orf_el->num_values; i++) {
4174                         struct repsFromToBlob *trf;
4175
4176                         trf = talloc(ar, struct repsFromToBlob);
4177                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4178
4179                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
4180                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
4181                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4182                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4183                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4184                         }
4185
4186                         if (trf->version != 1) {
4187                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4188                         }
4189
4190                         /*
4191                          * we compare the source dsa objectGUID not the invocation_id
4192                          * because we want only one repsFrom value per source dsa
4193                          * and when the invocation_id of the source dsa has changed we don't need
4194                          * the old repsFrom with the old invocation_id
4195                          */
4196                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
4197                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
4198                                 talloc_free(trf);
4199                                 continue;
4200                         }
4201
4202                         talloc_free(trf);
4203                         nrf_value = &orf_el->values[i];
4204                         break;
4205                 }
4206
4207                 /*
4208                  * copy over all old values to the new ldb_message
4209                  */
4210                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
4211                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4212                 *nrf_el = *orf_el;
4213         }
4214
4215         /*
4216          * if we haven't found an old repsFrom value for the current source dsa
4217          * we'll add a new value
4218          */
4219         if (!nrf_value) {
4220                 struct ldb_val zero_value;
4221                 ZERO_STRUCT(zero_value);
4222                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
4223                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4224
4225                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
4226         }
4227
4228         /* we now fill the value which is already attached to ldb_message */
4229         ndr_err = ndr_push_struct_blob(nrf_value, msg,
4230                                        &nrf,
4231                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
4232         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4233                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4234                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4235         }
4236
4237         /*
4238          * the ldb_message_element for the attribute, has all the old values and the new one
4239          * so we'll replace the whole attribute with all values
4240          */
4241         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
4242
4243         if (CHECK_DEBUGLVL(4)) {
4244                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4245                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
4246                 talloc_free(s);
4247         }
4248
4249         /* prepare the ldb_modify() request */
4250         ret = ldb_build_mod_req(&change_req,
4251                                 ldb,
4252                                 ar,
4253                                 msg,
4254                                 ar->controls,
4255                                 ar,
4256                                 replmd_replicated_uptodate_modify_callback,
4257                                 ar->req);
4258         LDB_REQ_SET_LOCATION(change_req);
4259         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4260
4261         return ldb_next_request(ar->module, change_req);
4262 }
4263
4264 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
4265                                                       struct ldb_reply *ares)
4266 {
4267         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4268                                                struct replmd_replicated_request);
4269         int ret;
4270
4271         if (!ares) {
4272                 return ldb_module_done(ar->req, NULL, NULL,
4273                                         LDB_ERR_OPERATIONS_ERROR);
4274         }
4275         if (ares->error != LDB_SUCCESS &&
4276             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4277                 return ldb_module_done(ar->req, ares->controls,
4278                                         ares->response, ares->error);
4279         }
4280
4281         switch (ares->type) {
4282         case LDB_REPLY_ENTRY:
4283                 ar->search_msg = talloc_steal(ar, ares->message);
4284                 break;
4285
4286         case LDB_REPLY_REFERRAL:
4287                 /* we ignore referrals */
4288                 break;
4289
4290         case LDB_REPLY_DONE:
4291                 ret = replmd_replicated_uptodate_modify(ar);
4292                 if (ret != LDB_SUCCESS) {
4293                         return ldb_module_done(ar->req, NULL, NULL, ret);
4294                 }
4295         }
4296
4297         talloc_free(ares);
4298         return LDB_SUCCESS;
4299 }
4300
4301
4302 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
4303 {
4304         struct ldb_context *ldb;
4305         int ret;
4306         static const char *attrs[] = {
4307                 "replUpToDateVector",
4308                 "repsFrom",
4309                 "instanceType",
4310                 NULL
4311         };
4312         struct ldb_request *search_req;
4313
4314         ldb = ldb_module_get_ctx(ar->module);
4315         ar->search_msg = NULL;
4316
4317         ret = ldb_build_search_req(&search_req,
4318                                    ldb,
4319                                    ar,
4320                                    ar->objs->partition_dn,
4321                                    LDB_SCOPE_BASE,
4322                                    "(objectClass=*)",
4323                                    attrs,
4324                                    NULL,
4325                                    ar,
4326                                    replmd_replicated_uptodate_search_callback,
4327                                    ar->req);
4328         LDB_REQ_SET_LOCATION(search_req);
4329         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4330
4331         return ldb_next_request(ar->module, search_req);
4332 }
4333
4334
4335
4336 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
4337 {
4338         struct ldb_context *ldb;
4339         struct dsdb_extended_replicated_objects *objs;
4340         struct replmd_replicated_request *ar;
4341         struct ldb_control **ctrls;
4342         int ret;
4343         uint32_t i;
4344         struct replmd_private *replmd_private =
4345                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4346         struct dsdb_control_replicated_update *rep_update;
4347
4348         ldb = ldb_module_get_ctx(module);
4349
4350         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
4351
4352         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
4353         if (!objs) {
4354                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
4355                 return LDB_ERR_PROTOCOL_ERROR;
4356         }
4357
4358         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
4359                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
4360                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
4361                 return LDB_ERR_PROTOCOL_ERROR;
4362         }
4363
4364         ar = replmd_ctx_init(module, req);
4365         if (!ar)
4366                 return LDB_ERR_OPERATIONS_ERROR;
4367
4368         /* Set the flags to have the replmd_op_callback run over the full set of objects */
4369         ar->apply_mode = true;
4370         ar->objs = objs;
4371         ar->schema = dsdb_get_schema(ldb, ar);
4372         if (!ar->schema) {
4373                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
4374                 talloc_free(ar);
4375                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4376                 return LDB_ERR_CONSTRAINT_VIOLATION;
4377         }
4378
4379         ctrls = req->controls;
4380
4381         if (req->controls) {
4382                 req->controls = talloc_memdup(ar, req->controls,
4383                                               talloc_get_size(req->controls));
4384                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4385         }
4386
4387         /* This allows layers further down to know if a change came in
4388            over replication and what the replication flags were */
4389         rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
4390         if (rep_update == NULL) {
4391                 return ldb_module_oom(module);
4392         }
4393         rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
4394
4395         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
4396         if (ret != LDB_SUCCESS) {
4397                 return ret;
4398         }
4399
4400         /* If this change contained linked attributes in the body
4401          * (rather than in the links section) we need to update
4402          * backlinks in linked_attributes */
4403         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
4404         if (ret != LDB_SUCCESS) {
4405                 return ret;
4406         }
4407
4408         ar->controls = req->controls;
4409         req->controls = ctrls;
4410
4411         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
4412
4413         /* save away the linked attributes for the end of the
4414            transaction */
4415         for (i=0; i<ar->objs->linked_attributes_count; i++) {
4416                 struct la_entry *la_entry;
4417
4418                 if (replmd_private->la_ctx == NULL) {
4419                         replmd_private->la_ctx = talloc_new(replmd_private);
4420                 }
4421                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
4422                 if (la_entry == NULL) {
4423                         ldb_oom(ldb);
4424                         return LDB_ERR_OPERATIONS_ERROR;
4425                 }
4426                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
4427                 if (la_entry->la == NULL) {
4428                         talloc_free(la_entry);
4429                         ldb_oom(ldb);
4430                         return LDB_ERR_OPERATIONS_ERROR;
4431                 }
4432                 *la_entry->la = ar->objs->linked_attributes[i];
4433
4434                 /* we need to steal the non-scalars so they stay
4435                    around until the end of the transaction */
4436                 talloc_steal(la_entry->la, la_entry->la->identifier);
4437                 talloc_steal(la_entry->la, la_entry->la->value.blob);
4438
4439                 DLIST_ADD(replmd_private->la_list, la_entry);
4440         }
4441
4442         return replmd_replicated_apply_next(ar);
4443 }
4444
4445 /*
4446   process one linked attribute structure
4447  */
4448 static int replmd_process_linked_attribute(struct ldb_module *module,
4449                                            struct la_entry *la_entry,
4450                                            struct ldb_request *parent)
4451 {
4452         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
4453         struct ldb_context *ldb = ldb_module_get_ctx(module);
4454         struct ldb_message *msg;
4455         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
4456         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
4457         int ret;
4458         const struct dsdb_attribute *attr;
4459         struct dsdb_dn *dsdb_dn;
4460         uint64_t seq_num = 0;
4461         struct ldb_message_element *old_el;
4462         WERROR status;
4463         time_t t = time(NULL);
4464         struct ldb_result *res;
4465         const char *attrs[2];
4466         struct parsed_dn *pdn_list, *pdn;
4467         struct GUID guid = GUID_zero();
4468         NTSTATUS ntstatus;
4469         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
4470         const struct GUID *our_invocation_id;
4471
4472 /*
4473 linked_attributes[0]:
4474      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
4475         identifier               : *
4476             identifier: struct drsuapi_DsReplicaObjectIdentifier
4477                 __ndr_size               : 0x0000003a (58)
4478                 __ndr_size_sid           : 0x00000000 (0)
4479                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
4480                 sid                      : S-0-0
4481                 __ndr_size_dn            : 0x00000000 (0)
4482                 dn                       : ''
4483         attid                    : DRSUAPI_ATTID_member (0x1F)
4484         value: struct drsuapi_DsAttributeValue
4485             __ndr_size               : 0x0000007e (126)
4486             blob                     : *
4487                 blob                     : DATA_BLOB length=126
4488         flags                    : 0x00000001 (1)
4489                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
4490         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
4491         meta_data: struct drsuapi_DsReplicaMetaData
4492             version                  : 0x00000015 (21)
4493             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
4494             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
4495             originating_usn          : 0x000000000001e19c (123292)
4496
4497 (for cases where the link is to a normal DN)
4498      &target: struct drsuapi_DsReplicaObjectIdentifier3
4499         __ndr_size               : 0x0000007e (126)
4500         __ndr_size_sid           : 0x0000001c (28)
4501         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
4502         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
4503         __ndr_size_dn            : 0x00000022 (34)
4504         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
4505  */
4506
4507         /* find the attribute being modified */
4508         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
4509         if (attr == NULL) {
4510                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
4511                 talloc_free(tmp_ctx);
4512                 return LDB_ERR_OPERATIONS_ERROR;
4513         }
4514
4515         attrs[0] = attr->lDAPDisplayName;
4516         attrs[1] = NULL;
4517
4518         /* get the existing message from the db for the object with
4519            this GUID, returning attribute being modified. We will then
4520            use this msg as the basis for a modify call */
4521         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
4522                                  DSDB_FLAG_NEXT_MODULE |
4523                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
4524                                  DSDB_SEARCH_SHOW_RECYCLED |
4525                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4526                                  DSDB_SEARCH_REVEAL_INTERNALS,
4527                                  parent,
4528                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
4529         if (ret != LDB_SUCCESS) {
4530                 talloc_free(tmp_ctx);
4531                 return ret;
4532         }
4533         if (res->count != 1) {
4534                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
4535                                        GUID_string(tmp_ctx, &la->identifier->guid));
4536                 talloc_free(tmp_ctx);
4537                 return LDB_ERR_NO_SUCH_OBJECT;
4538         }
4539         msg = res->msgs[0];
4540
4541         if (msg->num_elements == 0) {
4542                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
4543                 if (ret != LDB_SUCCESS) {
4544                         ldb_module_oom(module);
4545                         talloc_free(tmp_ctx);
4546                         return LDB_ERR_OPERATIONS_ERROR;
4547                 }
4548         } else {
4549                 old_el = &msg->elements[0];
4550                 old_el->flags = LDB_FLAG_MOD_REPLACE;
4551         }
4552
4553         /* parse the existing links */
4554         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
4555         if (ret != LDB_SUCCESS) {
4556                 talloc_free(tmp_ctx);
4557                 return ret;
4558         }
4559
4560         /* get our invocationId */
4561         our_invocation_id = samdb_ntds_invocation_id(ldb);
4562         if (!our_invocation_id) {
4563                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
4564                 talloc_free(tmp_ctx);
4565                 return LDB_ERR_OPERATIONS_ERROR;
4566         }
4567
4568         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
4569         if (ret != LDB_SUCCESS) {
4570                 talloc_free(tmp_ctx);
4571                 return ret;
4572         }
4573
4574         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
4575         if (!W_ERROR_IS_OK(status)) {
4576                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
4577                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
4578                 return LDB_ERR_OPERATIONS_ERROR;
4579         }
4580
4581         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
4582         if (!NT_STATUS_IS_OK(ntstatus) && active) {
4583                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
4584                                        old_el->name,
4585                                        ldb_dn_get_linearized(dsdb_dn->dn),
4586                                        ldb_dn_get_linearized(msg->dn));
4587                 return LDB_ERR_OPERATIONS_ERROR;
4588         }
4589
4590         /* re-resolve the DN by GUID, as the DRS server may give us an
4591            old DN value */
4592         ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
4593         if (ret != LDB_SUCCESS) {
4594                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
4595                          GUID_string(tmp_ctx, &guid),
4596                          ldb_dn_get_linearized(dsdb_dn->dn)));
4597         }
4598
4599         /* see if this link already exists */
4600         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
4601         if (pdn != NULL) {
4602                 /* see if this update is newer than what we have already */
4603                 struct GUID invocation_id = GUID_zero();
4604                 uint32_t version = 0;
4605                 uint32_t originating_usn = 0;
4606                 NTTIME change_time = 0;
4607                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
4608
4609                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
4610                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
4611                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
4612                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
4613
4614                 if (!replmd_update_is_newer(&invocation_id,
4615                                             &la->meta_data.originating_invocation_id,
4616                                             version,
4617                                             la->meta_data.version,
4618                                             change_time,
4619                                             la->meta_data.originating_change_time)) {
4620                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
4621                                  old_el->name, ldb_dn_get_linearized(msg->dn),
4622                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
4623                         talloc_free(tmp_ctx);
4624                         return LDB_SUCCESS;
4625                 }
4626
4627                 /* get a seq_num for this change */
4628                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4629                 if (ret != LDB_SUCCESS) {
4630                         talloc_free(tmp_ctx);
4631                         return ret;
4632                 }
4633
4634                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
4635                         /* remove the existing backlink */
4636                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
4637                         if (ret != LDB_SUCCESS) {
4638                                 talloc_free(tmp_ctx);
4639                                 return ret;
4640                         }
4641                 }
4642
4643                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
4644                                            &la->meta_data.originating_invocation_id,
4645                                            la->meta_data.originating_usn, seq_num,
4646                                            la->meta_data.originating_change_time,
4647                                            la->meta_data.version,
4648                                            !active);
4649                 if (ret != LDB_SUCCESS) {
4650                         talloc_free(tmp_ctx);
4651                         return ret;
4652                 }
4653
4654                 if (active) {
4655                         /* add the new backlink */
4656                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
4657                         if (ret != LDB_SUCCESS) {
4658                                 talloc_free(tmp_ctx);
4659                                 return ret;
4660                         }
4661                 }
4662         } else {
4663                 /* get a seq_num for this change */
4664                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4665                 if (ret != LDB_SUCCESS) {
4666                         talloc_free(tmp_ctx);
4667                         return ret;
4668                 }
4669
4670                 old_el->values = talloc_realloc(msg->elements, old_el->values,
4671                                                 struct ldb_val, old_el->num_values+1);
4672                 if (!old_el->values) {
4673                         ldb_module_oom(module);
4674                         return LDB_ERR_OPERATIONS_ERROR;
4675                 }
4676                 old_el->num_values++;
4677
4678                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
4679                                           &la->meta_data.originating_invocation_id,
4680                                           la->meta_data.originating_usn, seq_num,
4681                                           la->meta_data.originating_change_time,
4682                                           la->meta_data.version,
4683                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
4684                 if (ret != LDB_SUCCESS) {
4685                         talloc_free(tmp_ctx);
4686                         return ret;
4687                 }
4688
4689                 if (active) {
4690                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
4691                                                   true, attr, false);
4692                         if (ret != LDB_SUCCESS) {
4693                                 talloc_free(tmp_ctx);
4694                                 return ret;
4695                         }
4696                 }
4697         }
4698
4699         /* we only change whenChanged and uSNChanged if the seq_num
4700            has changed */
4701         if (add_time_element(msg, "whenChanged", t) != LDB_SUCCESS) {
4702                 talloc_free(tmp_ctx);
4703                 return ldb_operr(ldb);
4704         }
4705
4706         if (add_uint64_element(ldb, msg, "uSNChanged",
4707                                seq_num) != LDB_SUCCESS) {
4708                 talloc_free(tmp_ctx);
4709                 return ldb_operr(ldb);
4710         }
4711
4712         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
4713         if (old_el == NULL) {
4714                 talloc_free(tmp_ctx);
4715                 return ldb_operr(ldb);
4716         }
4717
4718         ret = dsdb_check_single_valued_link(attr, old_el);
4719         if (ret != LDB_SUCCESS) {
4720                 talloc_free(tmp_ctx);
4721                 return ret;
4722         }
4723
4724         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
4725
4726         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
4727         if (ret != LDB_SUCCESS) {
4728                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
4729                           ldb_errstring(ldb),
4730                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
4731                 talloc_free(tmp_ctx);
4732                 return ret;
4733         }
4734
4735         talloc_free(tmp_ctx);
4736
4737         return ret;
4738 }
4739
4740 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
4741 {
4742         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
4743                 return replmd_extended_replicated_objects(module, req);
4744         }
4745
4746         return ldb_next_request(module, req);
4747 }
4748
4749
4750 /*
4751   we hook into the transaction operations to allow us to
4752   perform the linked attribute updates at the end of the whole
4753   transaction. This allows a forward linked attribute to be created
4754   before the object is created. During a vampire, w2k8 sends us linked
4755   attributes before the objects they are part of.
4756  */
4757 static int replmd_start_transaction(struct ldb_module *module)
4758 {
4759         /* create our private structure for this transaction */
4760         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
4761                                                                 struct replmd_private);
4762         replmd_txn_cleanup(replmd_private);
4763
4764         /* free any leftover mod_usn records from cancelled
4765            transactions */
4766         while (replmd_private->ncs) {
4767                 struct nc_entry *e = replmd_private->ncs;
4768                 DLIST_REMOVE(replmd_private->ncs, e);
4769                 talloc_free(e);
4770         }
4771
4772         return ldb_next_start_trans(module);
4773 }
4774
4775 /*
4776   on prepare commit we loop over our queued la_context structures and
4777   apply each of them
4778  */
4779 static int replmd_prepare_commit(struct ldb_module *module)
4780 {
4781         struct replmd_private *replmd_private =
4782                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4783         struct la_entry *la, *prev;
4784         struct la_backlink *bl;
4785         int ret;
4786
4787         /* walk the list backwards, to do the first entry first, as we
4788          * added the entries with DLIST_ADD() which puts them at the
4789          * start of the list */
4790         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
4791                 prev = DLIST_PREV(la);
4792                 DLIST_REMOVE(replmd_private->la_list, la);
4793                 ret = replmd_process_linked_attribute(module, la, NULL);
4794                 if (ret != LDB_SUCCESS) {
4795                         replmd_txn_cleanup(replmd_private);
4796                         return ret;
4797                 }
4798         }
4799
4800         /* process our backlink list, creating and deleting backlinks
4801            as necessary */
4802         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
4803                 ret = replmd_process_backlink(module, bl, NULL);
4804                 if (ret != LDB_SUCCESS) {
4805                         replmd_txn_cleanup(replmd_private);
4806                         return ret;
4807                 }
4808         }
4809
4810         replmd_txn_cleanup(replmd_private);
4811
4812         /* possibly change @REPLCHANGED */
4813         ret = replmd_notify_store(module, NULL);
4814         if (ret != LDB_SUCCESS) {
4815                 return ret;
4816         }
4817
4818         return ldb_next_prepare_commit(module);
4819 }
4820
4821 static int replmd_del_transaction(struct ldb_module *module)
4822 {
4823         struct replmd_private *replmd_private =
4824                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4825         replmd_txn_cleanup(replmd_private);
4826
4827         return ldb_next_del_trans(module);
4828 }
4829
4830
4831 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
4832         .name          = "repl_meta_data",
4833         .init_context      = replmd_init,
4834         .add               = replmd_add,
4835         .modify            = replmd_modify,
4836         .rename            = replmd_rename,
4837         .del               = replmd_delete,
4838         .extended          = replmd_extended,
4839         .start_transaction = replmd_start_transaction,
4840         .prepare_commit    = replmd_prepare_commit,
4841         .del_transaction   = replmd_del_transaction,
4842 };
4843
4844 int ldb_repl_meta_data_module_init(const char *version)
4845 {
4846         LDB_MODULE_CHECK_VERSION(version);
4847         return ldb_register_module(&ldb_repl_meta_data_module_ops);
4848 }