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