7a642426b48464cfdcd818c830360eb96db6ff4f
[amitay/samba.git] / source4 / dsdb / samdb / ldb_modules / repl_meta_data.c
1 /*
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8    Copyright (C) Matthieu Patou <mat@samba.org> 2010
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb repl_meta_data module
28  *
29  *  Description: - add a unique objectGUID onto every new record,
30  *               - handle whenCreated, whenChanged timestamps
31  *               - handle uSNCreated, uSNChanged numbers
32  *               - handle replPropertyMetaData attribute
33  *
34  *  Author: Simo Sorce
35  *  Author: Stefan Metzmacher
36  */
37
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "../libds/common/flags.h"
43 #include "librpc/gen_ndr/ndr_misc.h"
44 #include "librpc/gen_ndr/ndr_drsuapi.h"
45 #include "librpc/gen_ndr/ndr_drsblobs.h"
46 #include "param/param.h"
47 #include "libcli/security/security.h"
48 #include "lib/util/dlinklist.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
50 #include "lib/util/binsearch.h"
51 #include "lib/util/tsort.h"
52
53 struct replmd_private {
54         TALLOC_CTX *la_ctx;
55         struct la_entry *la_list;
56         TALLOC_CTX *bl_ctx;
57         struct la_backlink *la_backlinks;
58         struct nc_entry {
59                 struct nc_entry *prev, *next;
60                 struct ldb_dn *dn;
61                 uint64_t mod_usn;
62                 uint64_t mod_usn_urgent;
63         } *ncs;
64 };
65
66 struct la_entry {
67         struct la_entry *next, *prev;
68         struct drsuapi_DsReplicaLinkedAttribute *la;
69 };
70
71 struct replmd_replicated_request {
72         struct ldb_module *module;
73         struct ldb_request *req;
74
75         const struct dsdb_schema *schema;
76
77         /* the controls we pass down */
78         struct ldb_control **controls;
79
80         /* details for the mode where we apply a bunch of inbound replication meessages */
81         bool apply_mode;
82         uint32_t index_current;
83         struct dsdb_extended_replicated_objects *objs;
84
85         struct ldb_message *search_msg;
86
87         uint64_t seq_num;
88         bool is_urgent;
89 };
90
91 enum urgent_situation {
92         REPL_URGENT_ON_CREATE = 1,
93         REPL_URGENT_ON_UPDATE = 2,
94         REPL_URGENT_ON_DELETE = 4
95 };
96
97
98 static const struct {
99         const char *update_name;
100         enum urgent_situation repl_situation;
101 } urgent_objects[] = {
102                 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
103                 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
104                 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
105                 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
106                 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
107                 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
108                 {NULL, 0}
109 };
110
111 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
112 static const char *urgent_attrs[] = {
113                 "lockoutTime",
114                 "pwdLastSet",
115                 "userAccountControl",
116                 NULL
117 };
118
119
120 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
121                                         enum urgent_situation situation)
122 {
123         unsigned int i, j;
124         for (i=0; urgent_objects[i].update_name; i++) {
125
126                 if ((situation & urgent_objects[i].repl_situation) == 0) {
127                         continue;
128                 }
129
130                 for (j=0; j<objectclass_el->num_values; j++) {
131                         const struct ldb_val *v = &objectclass_el->values[j];
132                         if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
133                                 return true;
134                         }
135                 }
136         }
137         return false;
138 }
139
140 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
141 {
142         if (ldb_attr_in_list(urgent_attrs, el->name)) {
143                 return true;
144         }
145         return false;
146 }
147
148
149 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
150
151 /*
152   initialise the module
153   allocate the private structure and build the list
154   of partition DNs for use by replmd_notify()
155  */
156 static int replmd_init(struct ldb_module *module)
157 {
158         struct replmd_private *replmd_private;
159         struct ldb_context *ldb = ldb_module_get_ctx(module);
160
161         replmd_private = talloc_zero(module, struct replmd_private);
162         if (replmd_private == NULL) {
163                 ldb_oom(ldb);
164                 return LDB_ERR_OPERATIONS_ERROR;
165         }
166         ldb_module_set_private(module, replmd_private);
167
168         return ldb_next_init(module);
169 }
170
171 /*
172   cleanup our per-transaction contexts
173  */
174 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
175 {
176         talloc_free(replmd_private->la_ctx);
177         replmd_private->la_list = NULL;
178         replmd_private->la_ctx = NULL;
179
180         talloc_free(replmd_private->bl_ctx);
181         replmd_private->la_backlinks = NULL;
182         replmd_private->bl_ctx = NULL;
183 }
184
185
186 struct la_backlink {
187         struct la_backlink *next, *prev;
188         const char *attr_name;
189         struct GUID forward_guid, target_guid;
190         bool active;
191 };
192
193 /*
194   process a backlinks we accumulated during a transaction, adding and
195   deleting the backlinks from the target objects
196  */
197 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
198 {
199         struct ldb_dn *target_dn, *source_dn;
200         int ret;
201         struct ldb_context *ldb = ldb_module_get_ctx(module);
202         struct ldb_message *msg;
203         TALLOC_CTX *tmp_ctx = talloc_new(bl);
204         char *dn_string;
205
206         /*
207           - find DN of target
208           - find DN of source
209           - construct ldb_message
210               - either an add or a delete
211          */
212         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
213         if (ret != LDB_SUCCESS) {
214                 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
215                          GUID_string(bl, &bl->target_guid)));
216                 return LDB_SUCCESS;
217         }
218
219         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
220         if (ret != LDB_SUCCESS) {
221                 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
222                                        GUID_string(bl, &bl->forward_guid));
223                 talloc_free(tmp_ctx);
224                 return ret;
225         }
226
227         msg = ldb_msg_new(tmp_ctx);
228         if (msg == NULL) {
229                 ldb_module_oom(module);
230                 talloc_free(tmp_ctx);
231                 return LDB_ERR_OPERATIONS_ERROR;
232         }
233
234         /* construct a ldb_message for adding/deleting the backlink */
235         msg->dn = target_dn;
236         dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
237         if (!dn_string) {
238                 ldb_module_oom(module);
239                 talloc_free(tmp_ctx);
240                 return LDB_ERR_OPERATIONS_ERROR;
241         }
242         ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
243         if (ret != LDB_SUCCESS) {
244                 talloc_free(tmp_ctx);
245                 return ret;
246         }
247         msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
248
249         /* a backlink should never be single valued. Unfortunately the
250            exchange schema has a attribute
251            msExchBridgeheadedLocalConnectorsDNBL which is single
252            valued and a backlink. We need to cope with that by
253            ignoring the single value flag */
254         msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
255
256         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
257         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
258                 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
259                    cope with possible corruption where the backlink has
260                    already been removed */
261                 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
262                          ldb_dn_get_linearized(target_dn),
263                          ldb_dn_get_linearized(source_dn),
264                          ldb_errstring(ldb)));
265                 ret = LDB_SUCCESS;
266         } else if (ret != LDB_SUCCESS) {
267                 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
268                                        bl->active?"add":"remove",
269                                        ldb_dn_get_linearized(source_dn),
270                                        ldb_dn_get_linearized(target_dn),
271                                        ldb_errstring(ldb));
272                 talloc_free(tmp_ctx);
273                 return ret;
274         }
275         talloc_free(tmp_ctx);
276         return ret;
277 }
278
279 /*
280   add a backlink to the list of backlinks to add/delete in the prepare
281   commit
282  */
283 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
284                                struct GUID *forward_guid, struct GUID *target_guid,
285                                bool active, const struct dsdb_attribute *schema_attr, bool immediate)
286 {
287         const struct dsdb_attribute *target_attr;
288         struct la_backlink *bl;
289         struct replmd_private *replmd_private =
290                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
291
292         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
293         if (!target_attr) {
294                 /*
295                  * windows 2003 has a broken schema where the
296                  * definition of msDS-IsDomainFor is missing (which is
297                  * supposed to be the backlink of the
298                  * msDS-HasDomainNCs attribute
299                  */
300                 return LDB_SUCCESS;
301         }
302
303         /* see if its already in the list */
304         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
305                 if (GUID_equal(forward_guid, &bl->forward_guid) &&
306                     GUID_equal(target_guid, &bl->target_guid) &&
307                     (target_attr->lDAPDisplayName == bl->attr_name ||
308                      strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
309                         break;
310                 }
311         }
312
313         if (bl) {
314                 /* we found an existing one */
315                 if (bl->active == active) {
316                         return LDB_SUCCESS;
317                 }
318                 DLIST_REMOVE(replmd_private->la_backlinks, bl);
319                 talloc_free(bl);
320                 return LDB_SUCCESS;
321         }
322
323         if (replmd_private->bl_ctx == NULL) {
324                 replmd_private->bl_ctx = talloc_new(replmd_private);
325                 if (replmd_private->bl_ctx == NULL) {
326                         ldb_module_oom(module);
327                         return LDB_ERR_OPERATIONS_ERROR;
328                 }
329         }
330
331         /* its a new one */
332         bl = talloc(replmd_private->bl_ctx, struct la_backlink);
333         if (bl == NULL) {
334                 ldb_module_oom(module);
335                 return LDB_ERR_OPERATIONS_ERROR;
336         }
337
338         /* Ensure the schema does not go away before the bl->attr_name is used */
339         if (!talloc_reference(bl, schema)) {
340                 talloc_free(bl);
341                 ldb_module_oom(module);
342                 return LDB_ERR_OPERATIONS_ERROR;
343         }
344
345         bl->attr_name = target_attr->lDAPDisplayName;
346         bl->forward_guid = *forward_guid;
347         bl->target_guid = *target_guid;
348         bl->active = active;
349
350         /* the caller may ask for this backlink to be processed
351            immediately */
352         if (immediate) {
353                 int ret = replmd_process_backlink(module, bl, NULL);
354                 talloc_free(bl);
355                 return ret;
356         }
357
358         DLIST_ADD(replmd_private->la_backlinks, bl);
359
360         return LDB_SUCCESS;
361 }
362
363
364 /*
365  * Callback for most write operations in this module:
366  *
367  * notify the repl task that a object has changed. The notifies are
368  * gathered up in the replmd_private structure then written to the
369  * @REPLCHANGED object in each partition during the prepare_commit
370  */
371 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
372 {
373         int ret;
374         struct replmd_replicated_request *ac =
375                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
376         struct replmd_private *replmd_private =
377                 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
378         struct nc_entry *modified_partition;
379         struct ldb_control *partition_ctrl;
380         const struct dsdb_control_current_partition *partition;
381
382         struct ldb_control **controls;
383
384         partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
385
386         controls = ares->controls;
387         if (ldb_request_get_control(ac->req,
388                                     DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
389                 /*
390                  * Remove the current partition control from what we pass up
391                  * the chain if it hasn't been requested manually.
392                  */
393                 controls = ldb_controls_except_specified(ares->controls, ares,
394                                                          partition_ctrl);
395         }
396
397         if (ares->error != LDB_SUCCESS) {
398                 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
399                 return ldb_module_done(ac->req, controls,
400                                         ares->response, ares->error);
401         }
402
403         if (ares->type != LDB_REPLY_DONE) {
404                 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
405                 return ldb_module_done(ac->req, NULL,
406                                        NULL, LDB_ERR_OPERATIONS_ERROR);
407         }
408
409         if (!partition_ctrl) {
410                 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
411                 return ldb_module_done(ac->req, NULL,
412                                        NULL, LDB_ERR_OPERATIONS_ERROR);
413         }
414
415         partition = talloc_get_type_abort(partition_ctrl->data,
416                                     struct dsdb_control_current_partition);
417
418         if (ac->seq_num > 0) {
419                 for (modified_partition = replmd_private->ncs; modified_partition;
420                      modified_partition = modified_partition->next) {
421                         if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
422                                 break;
423                         }
424                 }
425
426                 if (modified_partition == NULL) {
427                         modified_partition = talloc_zero(replmd_private, struct nc_entry);
428                         if (!modified_partition) {
429                                 ldb_oom(ldb_module_get_ctx(ac->module));
430                                 return ldb_module_done(ac->req, NULL,
431                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
432                         }
433                         modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
434                         if (!modified_partition->dn) {
435                                 ldb_oom(ldb_module_get_ctx(ac->module));
436                                 return ldb_module_done(ac->req, NULL,
437                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
438                         }
439                         DLIST_ADD(replmd_private->ncs, modified_partition);
440                 }
441
442                 if (ac->seq_num > modified_partition->mod_usn) {
443                         modified_partition->mod_usn = ac->seq_num;
444                         if (ac->is_urgent) {
445                                 modified_partition->mod_usn_urgent = ac->seq_num;
446                         }
447                 }
448         }
449
450         if (ac->apply_mode) {
451                 talloc_free(ares);
452                 ac->index_current++;
453
454                 ret = replmd_replicated_apply_next(ac);
455                 if (ret != LDB_SUCCESS) {
456                         return ldb_module_done(ac->req, NULL, NULL, ret);
457                 }
458                 return ret;
459         } else {
460                 /* free the partition control container here, for the
461                  * common path.  Other cases will have it cleaned up
462                  * eventually with the ares */
463                 talloc_free(partition_ctrl);
464                 return ldb_module_done(ac->req, controls,
465                                        ares->response, LDB_SUCCESS);
466         }
467 }
468
469
470 /*
471  * update a @REPLCHANGED record in each partition if there have been
472  * any writes of replicated data in the partition
473  */
474 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
475 {
476         struct replmd_private *replmd_private =
477                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
478
479         while (replmd_private->ncs) {
480                 int ret;
481                 struct nc_entry *modified_partition = replmd_private->ncs;
482
483                 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
484                                                      modified_partition->mod_usn,
485                                                      modified_partition->mod_usn_urgent, parent);
486                 if (ret != LDB_SUCCESS) {
487                         DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
488                                  ldb_dn_get_linearized(modified_partition->dn)));
489                         return ret;
490                 }
491                 DLIST_REMOVE(replmd_private->ncs, modified_partition);
492                 talloc_free(modified_partition);
493         }
494
495         return LDB_SUCCESS;
496 }
497
498
499 /*
500   created a replmd_replicated_request context
501  */
502 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
503                                                          struct ldb_request *req)
504 {
505         struct ldb_context *ldb;
506         struct replmd_replicated_request *ac;
507
508         ldb = ldb_module_get_ctx(module);
509
510         ac = talloc_zero(req, struct replmd_replicated_request);
511         if (ac == NULL) {
512                 ldb_oom(ldb);
513                 return NULL;
514         }
515
516         ac->module = module;
517         ac->req = req;
518
519         ac->schema = dsdb_get_schema(ldb, ac);
520         if (!ac->schema) {
521                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
522                               "replmd_modify: no dsdb_schema loaded");
523                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
524                 return NULL;
525         }
526
527         return ac;
528 }
529
530 /*
531   add a time element to a record
532 */
533 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
534 {
535         struct ldb_message_element *el;
536         char *s;
537         int ret;
538
539         if (ldb_msg_find_element(msg, attr) != NULL) {
540                 return LDB_SUCCESS;
541         }
542
543         s = ldb_timestring(msg, t);
544         if (s == NULL) {
545                 return LDB_ERR_OPERATIONS_ERROR;
546         }
547
548         ret = ldb_msg_add_string(msg, attr, s);
549         if (ret != LDB_SUCCESS) {
550                 return ret;
551         }
552
553         el = ldb_msg_find_element(msg, attr);
554         /* always set as replace. This works because on add ops, the flag
555            is ignored */
556         el->flags = LDB_FLAG_MOD_REPLACE;
557
558         return LDB_SUCCESS;
559 }
560
561 /*
562   add a uint64_t element to a record
563 */
564 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
565                               const char *attr, uint64_t v)
566 {
567         struct ldb_message_element *el;
568         int ret;
569
570         if (ldb_msg_find_element(msg, attr) != NULL) {
571                 return LDB_SUCCESS;
572         }
573
574         ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
575         if (ret != LDB_SUCCESS) {
576                 return ret;
577         }
578
579         el = ldb_msg_find_element(msg, attr);
580         /* always set as replace. This works because on add ops, the flag
581            is ignored */
582         el->flags = LDB_FLAG_MOD_REPLACE;
583
584         return LDB_SUCCESS;
585 }
586
587 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
588                                                    const struct replPropertyMetaData1 *m2,
589                                                    const uint32_t *rdn_attid)
590 {
591         if (m1->attid == m2->attid) {
592                 return 0;
593         }
594
595         /*
596          * the rdn attribute should be at the end!
597          * so we need to return a value greater than zero
598          * which means m1 is greater than m2
599          */
600         if (m1->attid == *rdn_attid) {
601                 return 1;
602         }
603
604         /*
605          * the rdn attribute should be at the end!
606          * so we need to return a value less than zero
607          * which means m2 is greater than m1
608          */
609         if (m2->attid == *rdn_attid) {
610                 return -1;
611         }
612
613         return m1->attid > m2->attid ? 1 : -1;
614 }
615
616 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
617                                                 const struct dsdb_schema *schema,
618                                                 struct ldb_dn *dn)
619 {
620         const char *rdn_name;
621         const struct dsdb_attribute *rdn_sa;
622
623         rdn_name = ldb_dn_get_rdn_name(dn);
624         if (!rdn_name) {
625                 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
626                 return LDB_ERR_OPERATIONS_ERROR;
627         }
628
629         rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
630         if (rdn_sa == NULL) {
631                 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
632                 return LDB_ERR_OPERATIONS_ERROR;
633         }
634
635         DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
636                  rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
637
638         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
639
640         return LDB_SUCCESS;
641 }
642
643 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
644                                                  const struct ldb_message_element *e2,
645                                                  const struct dsdb_schema *schema)
646 {
647         const struct dsdb_attribute *a1;
648         const struct dsdb_attribute *a2;
649
650         /*
651          * TODO: make this faster by caching the dsdb_attribute pointer
652          *       on the ldb_messag_element
653          */
654
655         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
656         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
657
658         /*
659          * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
660          *       in the schema
661          */
662         if (!a1 || !a2) {
663                 return strcasecmp(e1->name, e2->name);
664         }
665         if (a1->attributeID_id == a2->attributeID_id) {
666                 return 0;
667         }
668         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
669 }
670
671 static void replmd_ldb_message_sort(struct ldb_message *msg,
672                                     const struct dsdb_schema *schema)
673 {
674         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
675 }
676
677 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
678                                const struct GUID *invocation_id, uint64_t seq_num,
679                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
680
681
682 /*
683   fix up linked attributes in replmd_add.
684   This involves setting up the right meta-data in extended DN
685   components, and creating backlinks to the object
686  */
687 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
688                              uint64_t seq_num, const struct GUID *invocationId, time_t t,
689                              struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
690 {
691         unsigned int i;
692         TALLOC_CTX *tmp_ctx = talloc_new(el->values);
693         struct ldb_context *ldb = ldb_module_get_ctx(module);
694
695         /* We will take a reference to the schema in replmd_add_backlink */
696         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
697         NTTIME now;
698
699         unix_to_nt_time(&now, t);
700
701         for (i=0; i<el->num_values; i++) {
702                 struct ldb_val *v = &el->values[i];
703                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
704                 struct GUID target_guid;
705                 NTSTATUS status;
706                 int ret;
707
708                 /* note that the DN already has the extended
709                    components from the extended_dn_store module */
710                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
711                 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
712                         ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
713                         if (ret != LDB_SUCCESS) {
714                                 talloc_free(tmp_ctx);
715                                 return ret;
716                         }
717                         ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
718                         if (ret != LDB_SUCCESS) {
719                                 talloc_free(tmp_ctx);
720                                 return ret;
721                         }
722                 }
723
724                 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
725                                           seq_num, seq_num, now, 0, false);
726                 if (ret != LDB_SUCCESS) {
727                         talloc_free(tmp_ctx);
728                         return ret;
729                 }
730
731                 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
732                 if (ret != LDB_SUCCESS) {
733                         talloc_free(tmp_ctx);
734                         return ret;
735                 }
736         }
737
738         talloc_free(tmp_ctx);
739         return LDB_SUCCESS;
740 }
741
742
743 /*
744   intercept add requests
745  */
746 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
747 {
748         struct ldb_context *ldb;
749         struct ldb_control *control;
750         struct replmd_replicated_request *ac;
751         enum ndr_err_code ndr_err;
752         struct ldb_request *down_req;
753         struct ldb_message *msg;
754         const DATA_BLOB *guid_blob;
755         struct GUID guid;
756         struct replPropertyMetaDataBlob nmd;
757         struct ldb_val nmd_value;
758         const struct GUID *our_invocation_id;
759         time_t t = time(NULL);
760         NTTIME now;
761         char *time_str;
762         int ret;
763         unsigned int i;
764         unsigned int functional_level;
765         uint32_t ni=0;
766         bool allow_add_guid = false;
767         bool remove_current_guid = false;
768         bool is_urgent = false;
769         struct ldb_message_element *objectclass_el;
770
771         /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
772         control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
773         if (control) {
774                 allow_add_guid = true;
775         }
776
777         /* do not manipulate our control entries */
778         if (ldb_dn_is_special(req->op.add.message->dn)) {
779                 return ldb_next_request(module, req);
780         }
781
782         ldb = ldb_module_get_ctx(module);
783
784         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
785
786         guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
787         if (guid_blob != NULL) {
788                 if (!allow_add_guid) {
789                         ldb_set_errstring(ldb,
790                                           "replmd_add: it's not allowed to add an object with objectGUID!");
791                         return LDB_ERR_UNWILLING_TO_PERFORM;
792                 } else {
793                         NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
794                         if (!NT_STATUS_IS_OK(status)) {
795                                 ldb_set_errstring(ldb,
796                                                   "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
797                                 return LDB_ERR_UNWILLING_TO_PERFORM;
798                         }
799                         /* we remove this attribute as it can be a string and
800                          * will not be treated correctly and then we will re-add
801                          * it later on in the good format */
802                         remove_current_guid = true;
803                 }
804         } else {
805                 /* a new GUID */
806                 guid = GUID_random();
807         }
808
809         ac = replmd_ctx_init(module, req);
810         if (ac == NULL) {
811                 return ldb_module_oom(module);
812         }
813
814         functional_level = dsdb_functional_level(ldb);
815
816         /* Get a sequence number from the backend */
817         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
818         if (ret != LDB_SUCCESS) {
819                 talloc_free(ac);
820                 return ret;
821         }
822
823         /* get our invocationId */
824         our_invocation_id = samdb_ntds_invocation_id(ldb);
825         if (!our_invocation_id) {
826                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
827                               "replmd_add: unable to find invocationId\n");
828                 talloc_free(ac);
829                 return LDB_ERR_OPERATIONS_ERROR;
830         }
831
832         /* we have to copy the message as the caller might have it as a const */
833         msg = ldb_msg_copy_shallow(ac, req->op.add.message);
834         if (msg == NULL) {
835                 ldb_oom(ldb);
836                 talloc_free(ac);
837                 return LDB_ERR_OPERATIONS_ERROR;
838         }
839
840         /* generated times */
841         unix_to_nt_time(&now, t);
842         time_str = ldb_timestring(msg, t);
843         if (!time_str) {
844                 ldb_oom(ldb);
845                 talloc_free(ac);
846                 return LDB_ERR_OPERATIONS_ERROR;
847         }
848         if (remove_current_guid) {
849                 ldb_msg_remove_attr(msg,"objectGUID");
850         }
851
852         /*
853          * remove autogenerated attributes
854          */
855         ldb_msg_remove_attr(msg, "whenCreated");
856         ldb_msg_remove_attr(msg, "whenChanged");
857         ldb_msg_remove_attr(msg, "uSNCreated");
858         ldb_msg_remove_attr(msg, "uSNChanged");
859         ldb_msg_remove_attr(msg, "replPropertyMetaData");
860
861         /*
862          * readd replicated attributes
863          */
864         ret = ldb_msg_add_string(msg, "whenCreated", time_str);
865         if (ret != LDB_SUCCESS) {
866                 ldb_oom(ldb);
867                 talloc_free(ac);
868                 return ret;
869         }
870
871         /* build the replication meta_data */
872         ZERO_STRUCT(nmd);
873         nmd.version             = 1;
874         nmd.ctr.ctr1.count      = msg->num_elements;
875         nmd.ctr.ctr1.array      = talloc_array(msg,
876                                                struct replPropertyMetaData1,
877                                                nmd.ctr.ctr1.count);
878         if (!nmd.ctr.ctr1.array) {
879                 ldb_oom(ldb);
880                 talloc_free(ac);
881                 return LDB_ERR_OPERATIONS_ERROR;
882         }
883
884         for (i=0; i < msg->num_elements; i++) {
885                 struct ldb_message_element *e = &msg->elements[i];
886                 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
887                 const struct dsdb_attribute *sa;
888
889                 if (e->name[0] == '@') continue;
890
891                 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
892                 if (!sa) {
893                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
894                                       "replmd_add: attribute '%s' not defined in schema\n",
895                                       e->name);
896                         talloc_free(ac);
897                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
898                 }
899
900                 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
901                         /* if the attribute is not replicated (0x00000001)
902                          * or constructed (0x00000004) it has no metadata
903                          */
904                         continue;
905                 }
906
907                 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
908                         ret = replmd_add_fix_la(module, e, ac->seq_num, our_invocation_id, t, &guid, sa, req);
909                         if (ret != LDB_SUCCESS) {
910                                 talloc_free(ac);
911                                 return ret;
912                         }
913                         /* linked attributes are not stored in
914                            replPropertyMetaData in FL above w2k */
915                         continue;
916                 }
917
918                 m->attid                        = sa->attributeID_id;
919                 m->version                      = 1;
920                 m->originating_change_time      = now;
921                 m->originating_invocation_id    = *our_invocation_id;
922                 m->originating_usn              = ac->seq_num;
923                 m->local_usn                    = ac->seq_num;
924                 ni++;
925         }
926
927         /* fix meta data count */
928         nmd.ctr.ctr1.count = ni;
929
930         /*
931          * sort meta data array, and move the rdn attribute entry to the end
932          */
933         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ac->schema, msg->dn);
934         if (ret != LDB_SUCCESS) {
935                 talloc_free(ac);
936                 return ret;
937         }
938
939         /* generated NDR encoded values */
940         ndr_err = ndr_push_struct_blob(&nmd_value, msg,
941                                        &nmd,
942                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
943         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
944                 ldb_oom(ldb);
945                 talloc_free(ac);
946                 return LDB_ERR_OPERATIONS_ERROR;
947         }
948
949         /*
950          * add the autogenerated values
951          */
952         ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
953         if (ret != LDB_SUCCESS) {
954                 ldb_oom(ldb);
955                 talloc_free(ac);
956                 return ret;
957         }
958         ret = ldb_msg_add_string(msg, "whenChanged", time_str);
959         if (ret != LDB_SUCCESS) {
960                 ldb_oom(ldb);
961                 talloc_free(ac);
962                 return ret;
963         }
964         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
965         if (ret != LDB_SUCCESS) {
966                 ldb_oom(ldb);
967                 talloc_free(ac);
968                 return ret;
969         }
970         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
971         if (ret != LDB_SUCCESS) {
972                 ldb_oom(ldb);
973                 talloc_free(ac);
974                 return ret;
975         }
976         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
977         if (ret != LDB_SUCCESS) {
978                 ldb_oom(ldb);
979                 talloc_free(ac);
980                 return ret;
981         }
982
983         /*
984          * sort the attributes by attid before storing the object
985          */
986         replmd_ldb_message_sort(msg, ac->schema);
987
988         objectclass_el = ldb_msg_find_element(msg, "objectClass");
989         is_urgent = replmd_check_urgent_objectclass(objectclass_el,
990                                                         REPL_URGENT_ON_CREATE);
991
992         ac->is_urgent = is_urgent;
993         ret = ldb_build_add_req(&down_req, ldb, ac,
994                                 msg,
995                                 req->controls,
996                                 ac, replmd_op_callback,
997                                 req);
998
999         LDB_REQ_SET_LOCATION(down_req);
1000         if (ret != LDB_SUCCESS) {
1001                 talloc_free(ac);
1002                 return ret;
1003         }
1004
1005         /* current partition control is needed by "replmd_op_callback" */
1006         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1007                 ret = ldb_request_add_control(down_req,
1008                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
1009                                               false, NULL);
1010                 if (ret != LDB_SUCCESS) {
1011                         talloc_free(ac);
1012                         return ret;
1013                 }
1014         }
1015
1016         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1017                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1018                 if (ret != LDB_SUCCESS) {
1019                         talloc_free(ac);
1020                         return ret;
1021                 }
1022         }
1023
1024         /* mark the control done */
1025         if (control) {
1026                 control->critical = 0;
1027         }
1028
1029         /* go on with the call chain */
1030         return ldb_next_request(module, down_req);
1031 }
1032
1033
1034 /*
1035  * update the replPropertyMetaData for one element
1036  */
1037 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1038                                       struct ldb_message *msg,
1039                                       struct ldb_message_element *el,
1040                                       struct ldb_message_element *old_el,
1041                                       struct replPropertyMetaDataBlob *omd,
1042                                       const struct dsdb_schema *schema,
1043                                       uint64_t *seq_num,
1044                                       const struct GUID *our_invocation_id,
1045                                       NTTIME now,
1046                                       struct ldb_request *req)
1047 {
1048         uint32_t i;
1049         const struct dsdb_attribute *a;
1050         struct replPropertyMetaData1 *md1;
1051
1052         a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1053         if (a == NULL) {
1054                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1055                         /* allow this to make it possible for dbcheck
1056                            to remove bad attributes */
1057                         return LDB_SUCCESS;
1058                 }
1059
1060                 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1061                          el->name));
1062                 return LDB_ERR_OPERATIONS_ERROR;
1063         }
1064
1065         if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1066                 return LDB_SUCCESS;
1067         }
1068
1069         /* if the attribute's value haven't changed then return LDB_SUCCESS     */
1070         if (old_el != NULL && ldb_msg_element_compare(el, old_el) == 0) {
1071                 if (!ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1072                         /*
1073                          * allow this to make it possible for dbcheck
1074                          * to rebuild broken metadata
1075                          */
1076                         return LDB_SUCCESS;
1077                 }
1078         }
1079
1080         for (i=0; i<omd->ctr.ctr1.count; i++) {
1081                 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) break;
1082         }
1083
1084         if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1085                 /* linked attributes are not stored in
1086                    replPropertyMetaData in FL above w2k, but we do
1087                    raise the seqnum for the object  */
1088                 if (*seq_num == 0 &&
1089                     ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1090                         return LDB_ERR_OPERATIONS_ERROR;
1091                 }
1092                 return LDB_SUCCESS;
1093         }
1094
1095         if (i == omd->ctr.ctr1.count) {
1096                 /* we need to add a new one */
1097                 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1098                                                      struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1099                 if (omd->ctr.ctr1.array == NULL) {
1100                         ldb_oom(ldb);
1101                         return LDB_ERR_OPERATIONS_ERROR;
1102                 }
1103                 omd->ctr.ctr1.count++;
1104                 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1105         }
1106
1107         /* Get a new sequence number from the backend. We only do this
1108          * if we have a change that requires a new
1109          * replPropertyMetaData element
1110          */
1111         if (*seq_num == 0) {
1112                 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1113                 if (ret != LDB_SUCCESS) {
1114                         return LDB_ERR_OPERATIONS_ERROR;
1115                 }
1116         }
1117
1118         md1 = &omd->ctr.ctr1.array[i];
1119         md1->version++;
1120         md1->attid                     = a->attributeID_id;
1121         md1->originating_change_time   = now;
1122         md1->originating_invocation_id = *our_invocation_id;
1123         md1->originating_usn           = *seq_num;
1124         md1->local_usn                 = *seq_num;
1125
1126         return LDB_SUCCESS;
1127 }
1128
1129 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1130 {
1131         uint32_t count = omd.ctr.ctr1.count;
1132         uint64_t max = 0;
1133         uint32_t i;
1134         for (i=0; i < count; i++) {
1135                 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1136                 if (max < m.local_usn) {
1137                         max = m.local_usn;
1138                 }
1139         }
1140         return max;
1141 }
1142
1143 /*
1144  * update the replPropertyMetaData object each time we modify an
1145  * object. This is needed for DRS replication, as the merge on the
1146  * client is based on this object
1147  */
1148 static int replmd_update_rpmd(struct ldb_module *module,
1149                               const struct dsdb_schema *schema,
1150                               struct ldb_request *req,
1151                               const char * const *rename_attrs,
1152                               struct ldb_message *msg, uint64_t *seq_num,
1153                               time_t t,
1154                               bool *is_urgent)
1155 {
1156         const struct ldb_val *omd_value;
1157         enum ndr_err_code ndr_err;
1158         struct replPropertyMetaDataBlob omd;
1159         unsigned int i;
1160         NTTIME now;
1161         const struct GUID *our_invocation_id;
1162         int ret;
1163         const char * const *attrs = NULL;
1164         const char * const attrs1[] = { "replPropertyMetaData", "*", NULL };
1165         const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1166         struct ldb_result *res;
1167         struct ldb_context *ldb;
1168         struct ldb_message_element *objectclass_el;
1169         enum urgent_situation situation;
1170         bool rodc, rmd_is_provided;
1171
1172         if (rename_attrs) {
1173                 attrs = rename_attrs;
1174         } else {
1175                 attrs = attrs1;
1176         }
1177
1178         ldb = ldb_module_get_ctx(module);
1179
1180         our_invocation_id = samdb_ntds_invocation_id(ldb);
1181         if (!our_invocation_id) {
1182                 /* this happens during an initial vampire while
1183                    updating the schema */
1184                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1185                 return LDB_SUCCESS;
1186         }
1187
1188         unix_to_nt_time(&now, t);
1189
1190         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1191                 rmd_is_provided = true;
1192         } else {
1193                 rmd_is_provided = false;
1194         }
1195
1196         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1197          * otherwise we consider we are updating */
1198         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1199                 situation = REPL_URGENT_ON_DELETE;
1200         } else if (rename_attrs) {
1201                 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1202         } else {
1203                 situation = REPL_URGENT_ON_UPDATE;
1204         }
1205
1206         if (rmd_is_provided) {
1207                 /* In this case the change_replmetadata control was supplied */
1208                 /* We check that it's the only attribute that is provided
1209                  * (it's a rare case so it's better to keep the code simplier)
1210                  * We also check that the highest local_usn is bigger than
1211                  * uSNChanged. */
1212                 uint64_t db_seq;
1213                 if( msg->num_elements != 1 ||
1214                         strncmp(msg->elements[0].name,
1215                                 "replPropertyMetaData", 20) ) {
1216                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1217                                 "a specified replPropertyMetaData attribute or with others\n"));
1218                         return LDB_ERR_OPERATIONS_ERROR;
1219                 }
1220                 if (situation != REPL_URGENT_ON_UPDATE) {
1221                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1222                         return LDB_ERR_OPERATIONS_ERROR;
1223                 }
1224                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1225                 if (!omd_value) {
1226                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1227                                  ldb_dn_get_linearized(msg->dn)));
1228                         return LDB_ERR_OPERATIONS_ERROR;
1229                 }
1230                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1231                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1232                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1233                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1234                                  ldb_dn_get_linearized(msg->dn)));
1235                         return LDB_ERR_OPERATIONS_ERROR;
1236                 }
1237                 *seq_num = find_max_local_usn(omd);
1238
1239                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1240                                             DSDB_FLAG_NEXT_MODULE |
1241                                             DSDB_SEARCH_SHOW_RECYCLED |
1242                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1243                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1244                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1245
1246                 if (ret != LDB_SUCCESS || res->count != 1) {
1247                         DEBUG(0,(__location__ ": Object %s failed to find uSNChanged\n",
1248                                  ldb_dn_get_linearized(msg->dn)));
1249                         return LDB_ERR_OPERATIONS_ERROR;
1250                 }
1251
1252                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1253                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1254                                                                 situation)) {
1255                         *is_urgent = true;
1256                 }
1257
1258                 db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1259                 if (*seq_num <= db_seq) {
1260                         DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\
1261                                               " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n",
1262                                  (long long)*seq_num, (long long)db_seq));
1263                         return LDB_ERR_OPERATIONS_ERROR;
1264                 }
1265
1266         } else {
1267                 /* search for the existing replPropertyMetaDataBlob. We need
1268                  * to use REVEAL and ask for DNs in storage format to support
1269                  * the check for values being the same in
1270                  * replmd_update_rpmd_element()
1271                  */
1272                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1273                                             DSDB_FLAG_NEXT_MODULE |
1274                                             DSDB_SEARCH_SHOW_RECYCLED |
1275                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1276                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1277                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1278                 if (ret != LDB_SUCCESS || res->count != 1) {
1279                         DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n",
1280                                  ldb_dn_get_linearized(msg->dn)));
1281                         return LDB_ERR_OPERATIONS_ERROR;
1282                 }
1283
1284                 objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1285                 if (is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1286                                                                 situation)) {
1287                         *is_urgent = true;
1288                 }
1289
1290                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1291                 if (!omd_value) {
1292                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1293                                  ldb_dn_get_linearized(msg->dn)));
1294                         return LDB_ERR_OPERATIONS_ERROR;
1295                 }
1296
1297                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1298                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1299                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1300                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1301                                  ldb_dn_get_linearized(msg->dn)));
1302                         return LDB_ERR_OPERATIONS_ERROR;
1303                 }
1304
1305                 if (omd.version != 1) {
1306                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1307                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1308                         return LDB_ERR_OPERATIONS_ERROR;
1309                 }
1310
1311                 for (i=0; i<msg->num_elements; i++) {
1312                         struct ldb_message_element *old_el;
1313                         old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1314                         ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1315                                                          our_invocation_id, now, req);
1316                         if (ret != LDB_SUCCESS) {
1317                                 return ret;
1318                         }
1319
1320                         if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1321                                 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1322                         }
1323
1324                 }
1325         }
1326         /*
1327          * replmd_update_rpmd_element has done an update if the
1328          * seq_num is set
1329          */
1330         if (*seq_num != 0) {
1331                 struct ldb_val *md_value;
1332                 struct ldb_message_element *el;
1333
1334                 /*if we are RODC and this is a DRSR update then its ok*/
1335                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
1336                         unsigned instanceType;
1337
1338                         ret = samdb_rodc(ldb, &rodc);
1339                         if (ret != LDB_SUCCESS) {
1340                                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1341                         } else if (rodc) {
1342                                 ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n");
1343                                 return LDB_ERR_REFERRAL;
1344                         }
1345
1346                         instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1347                         if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1348                                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1349                                                  "cannot change replicated attribute on partial replica");
1350                         }
1351                 }
1352
1353                 md_value = talloc(msg, struct ldb_val);
1354                 if (md_value == NULL) {
1355                         ldb_oom(ldb);
1356                         return LDB_ERR_OPERATIONS_ERROR;
1357                 }
1358
1359                 ret = replmd_replPropertyMetaDataCtr1_sort(&omd.ctr.ctr1, schema, msg->dn);
1360                 if (ret != LDB_SUCCESS) {
1361                         return ret;
1362                 }
1363
1364                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1365                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1366                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1367                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1368                                  ldb_dn_get_linearized(msg->dn)));
1369                         return LDB_ERR_OPERATIONS_ERROR;
1370                 }
1371
1372                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1373                 if (ret != LDB_SUCCESS) {
1374                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1375                                  ldb_dn_get_linearized(msg->dn)));
1376                         return ret;
1377                 }
1378
1379                 el->num_values = 1;
1380                 el->values = md_value;
1381         }
1382
1383         return LDB_SUCCESS;
1384 }
1385
1386 struct parsed_dn {
1387         struct dsdb_dn *dsdb_dn;
1388         struct GUID *guid;
1389         struct ldb_val *v;
1390 };
1391
1392 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1393 {
1394         return GUID_compare(pdn1->guid, pdn2->guid);
1395 }
1396
1397 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1398                                         unsigned int count, struct GUID *guid,
1399                                         struct ldb_dn *dn)
1400 {
1401         struct parsed_dn *ret;
1402         unsigned int i;
1403         if (dn && GUID_all_zero(guid)) {
1404                 /* when updating a link using DRS, we sometimes get a
1405                    NULL GUID. We then need to try and match by DN */
1406                 for (i=0; i<count; i++) {
1407                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1408                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1409                                 return &pdn[i];
1410                         }
1411                 }
1412                 return NULL;
1413         }
1414         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare, ret);
1415         return ret;
1416 }
1417
1418 /*
1419   get a series of message element values as an array of DNs and GUIDs
1420   the result is sorted by GUID
1421  */
1422 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1423                           struct ldb_message_element *el, struct parsed_dn **pdn,
1424                           const char *ldap_oid, struct ldb_request *parent)
1425 {
1426         unsigned int i;
1427         struct ldb_context *ldb = ldb_module_get_ctx(module);
1428
1429         if (el == NULL) {
1430                 *pdn = NULL;
1431                 return LDB_SUCCESS;
1432         }
1433
1434         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1435         if (!*pdn) {
1436                 ldb_module_oom(module);
1437                 return LDB_ERR_OPERATIONS_ERROR;
1438         }
1439
1440         for (i=0; i<el->num_values; i++) {
1441                 struct ldb_val *v = &el->values[i];
1442                 NTSTATUS status;
1443                 struct ldb_dn *dn;
1444                 struct parsed_dn *p;
1445
1446                 p = &(*pdn)[i];
1447
1448                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1449                 if (p->dsdb_dn == NULL) {
1450                         return LDB_ERR_INVALID_DN_SYNTAX;
1451                 }
1452
1453                 dn = p->dsdb_dn->dn;
1454
1455                 p->guid = talloc(*pdn, struct GUID);
1456                 if (p->guid == NULL) {
1457                         ldb_module_oom(module);
1458                         return LDB_ERR_OPERATIONS_ERROR;
1459                 }
1460
1461                 status = dsdb_get_extended_dn_guid(dn, p->guid, "GUID");
1462                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1463                         /* we got a DN without a GUID - go find the GUID */
1464                         int ret = dsdb_module_guid_by_dn(module, dn, p->guid, parent);
1465                         if (ret != LDB_SUCCESS) {
1466                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1467                                                        ldb_dn_get_linearized(dn));
1468                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1469                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1470                                     ldb_attr_cmp(el->name, "member") == 0) {
1471                                         return LDB_ERR_UNWILLING_TO_PERFORM;
1472                                 }
1473                                 return ret;
1474                         }
1475                         ret = dsdb_set_extended_dn_guid(dn, p->guid, "GUID");
1476                         if (ret != LDB_SUCCESS) {
1477                                 return ret;
1478                         }
1479                 } else if (!NT_STATUS_IS_OK(status)) {
1480                         return LDB_ERR_OPERATIONS_ERROR;
1481                 }
1482
1483                 /* keep a pointer to the original ldb_val */
1484                 p->v = v;
1485         }
1486
1487         TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1488
1489         return LDB_SUCCESS;
1490 }
1491
1492 /*
1493   build a new extended DN, including all meta data fields
1494
1495   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1496   RMD_ADDTIME         = originating_add_time
1497   RMD_INVOCID         = originating_invocation_id
1498   RMD_CHANGETIME      = originating_change_time
1499   RMD_ORIGINATING_USN = originating_usn
1500   RMD_LOCAL_USN       = local_usn
1501   RMD_VERSION         = version
1502  */
1503 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1504                                const struct GUID *invocation_id, uint64_t seq_num,
1505                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1506 {
1507         struct ldb_dn *dn = dsdb_dn->dn;
1508         const char *tstring, *usn_string, *flags_string;
1509         struct ldb_val tval;
1510         struct ldb_val iid;
1511         struct ldb_val usnv, local_usnv;
1512         struct ldb_val vers, flagsv;
1513         NTSTATUS status;
1514         int ret;
1515         const char *dnstring;
1516         char *vstring;
1517         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1518
1519         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1520         if (!tstring) {
1521                 return LDB_ERR_OPERATIONS_ERROR;
1522         }
1523         tval = data_blob_string_const(tstring);
1524
1525         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1526         if (!usn_string) {
1527                 return LDB_ERR_OPERATIONS_ERROR;
1528         }
1529         usnv = data_blob_string_const(usn_string);
1530
1531         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1532         if (!usn_string) {
1533                 return LDB_ERR_OPERATIONS_ERROR;
1534         }
1535         local_usnv = data_blob_string_const(usn_string);
1536
1537         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1538         if (!vstring) {
1539                 return LDB_ERR_OPERATIONS_ERROR;
1540         }
1541         vers = data_blob_string_const(vstring);
1542
1543         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1544         if (!NT_STATUS_IS_OK(status)) {
1545                 return LDB_ERR_OPERATIONS_ERROR;
1546         }
1547
1548         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1549         if (!flags_string) {
1550                 return LDB_ERR_OPERATIONS_ERROR;
1551         }
1552         flagsv = data_blob_string_const(flags_string);
1553
1554         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1555         if (ret != LDB_SUCCESS) return ret;
1556         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1557         if (ret != LDB_SUCCESS) return ret;
1558         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1559         if (ret != LDB_SUCCESS) return ret;
1560         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1561         if (ret != LDB_SUCCESS) return ret;
1562         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1563         if (ret != LDB_SUCCESS) return ret;
1564         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1565         if (ret != LDB_SUCCESS) return ret;
1566         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1567         if (ret != LDB_SUCCESS) return ret;
1568
1569         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1570         if (dnstring == NULL) {
1571                 return LDB_ERR_OPERATIONS_ERROR;
1572         }
1573         *v = data_blob_string_const(dnstring);
1574
1575         return LDB_SUCCESS;
1576 }
1577
1578 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1579                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1580                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1581                                 uint32_t version, bool deleted);
1582
1583 /*
1584   check if any links need upgrading from w2k format
1585
1586   The parent_ctx is the ldb_message_element which contains the values array that dns[i].v points at, and which should be used for allocating any new value.
1587  */
1588 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1589 {
1590         uint32_t i;
1591         for (i=0; i<count; i++) {
1592                 NTSTATUS status;
1593                 uint32_t version;
1594                 int ret;
1595
1596                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1597                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1598                         continue;
1599                 }
1600
1601                 /* it's an old one that needs upgrading */
1602                 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1603                                            1, 1, 0, 0, false);
1604                 if (ret != LDB_SUCCESS) {
1605                         return ret;
1606                 }
1607         }
1608         return LDB_SUCCESS;
1609 }
1610
1611 /*
1612   update an extended DN, including all meta data fields
1613
1614   see replmd_build_la_val for value names
1615  */
1616 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1617                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1618                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1619                                 uint32_t version, bool deleted)
1620 {
1621         struct ldb_dn *dn = dsdb_dn->dn;
1622         const char *tstring, *usn_string, *flags_string;
1623         struct ldb_val tval;
1624         struct ldb_val iid;
1625         struct ldb_val usnv, local_usnv;
1626         struct ldb_val vers, flagsv;
1627         const struct ldb_val *old_addtime;
1628         uint32_t old_version;
1629         NTSTATUS status;
1630         int ret;
1631         const char *dnstring;
1632         char *vstring;
1633         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1634
1635         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1636         if (!tstring) {
1637                 return LDB_ERR_OPERATIONS_ERROR;
1638         }
1639         tval = data_blob_string_const(tstring);
1640
1641         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1642         if (!usn_string) {
1643                 return LDB_ERR_OPERATIONS_ERROR;
1644         }
1645         usnv = data_blob_string_const(usn_string);
1646
1647         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1648         if (!usn_string) {
1649                 return LDB_ERR_OPERATIONS_ERROR;
1650         }
1651         local_usnv = data_blob_string_const(usn_string);
1652
1653         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1654         if (!NT_STATUS_IS_OK(status)) {
1655                 return LDB_ERR_OPERATIONS_ERROR;
1656         }
1657
1658         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1659         if (!flags_string) {
1660                 return LDB_ERR_OPERATIONS_ERROR;
1661         }
1662         flagsv = data_blob_string_const(flags_string);
1663
1664         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1665         if (ret != LDB_SUCCESS) return ret;
1666
1667         /* get the ADDTIME from the original */
1668         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1669         if (old_addtime == NULL) {
1670                 old_addtime = &tval;
1671         }
1672         if (dsdb_dn != old_dsdb_dn ||
1673             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1674                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1675                 if (ret != LDB_SUCCESS) return ret;
1676         }
1677
1678         /* use our invocation id */
1679         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1680         if (ret != LDB_SUCCESS) return ret;
1681
1682         /* changetime is the current time */
1683         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1684         if (ret != LDB_SUCCESS) return ret;
1685
1686         /* update the USN */
1687         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1688         if (ret != LDB_SUCCESS) return ret;
1689
1690         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1691         if (ret != LDB_SUCCESS) return ret;
1692
1693         /* increase the version by 1 */
1694         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1695         if (NT_STATUS_IS_OK(status) && old_version >= version) {
1696                 version = old_version+1;
1697         }
1698         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1699         vers = data_blob_string_const(vstring);
1700         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1701         if (ret != LDB_SUCCESS) return ret;
1702
1703         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1704         if (dnstring == NULL) {
1705                 return LDB_ERR_OPERATIONS_ERROR;
1706         }
1707         *v = data_blob_string_const(dnstring);
1708
1709         return LDB_SUCCESS;
1710 }
1711
1712 /*
1713   handle adding a linked attribute
1714  */
1715 static int replmd_modify_la_add(struct ldb_module *module,
1716                                 const struct dsdb_schema *schema,
1717                                 struct ldb_message *msg,
1718                                 struct ldb_message_element *el,
1719                                 struct ldb_message_element *old_el,
1720                                 const struct dsdb_attribute *schema_attr,
1721                                 uint64_t seq_num,
1722                                 time_t t,
1723                                 struct GUID *msg_guid,
1724                                 struct ldb_request *parent)
1725 {
1726         unsigned int i;
1727         struct parsed_dn *dns, *old_dns;
1728         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1729         int ret;
1730         struct ldb_val *new_values = NULL;
1731         unsigned int num_new_values = 0;
1732         unsigned old_num_values = old_el?old_el->num_values:0;
1733         const struct GUID *invocation_id;
1734         struct ldb_context *ldb = ldb_module_get_ctx(module);
1735         NTTIME now;
1736
1737         unix_to_nt_time(&now, t);
1738
1739         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1740         if (ret != LDB_SUCCESS) {
1741                 talloc_free(tmp_ctx);
1742                 return ret;
1743         }
1744
1745         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1746         if (ret != LDB_SUCCESS) {
1747                 talloc_free(tmp_ctx);
1748                 return ret;
1749         }
1750
1751         invocation_id = samdb_ntds_invocation_id(ldb);
1752         if (!invocation_id) {
1753                 talloc_free(tmp_ctx);
1754                 return LDB_ERR_OPERATIONS_ERROR;
1755         }
1756
1757         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
1758         if (ret != LDB_SUCCESS) {
1759                 talloc_free(tmp_ctx);
1760                 return ret;
1761         }
1762
1763         /* for each new value, see if it exists already with the same GUID */
1764         for (i=0; i<el->num_values; i++) {
1765                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, dns[i].guid, NULL);
1766                 if (p == NULL) {
1767                         /* this is a new linked attribute value */
1768                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
1769                         if (new_values == NULL) {
1770                                 ldb_module_oom(module);
1771                                 talloc_free(tmp_ctx);
1772                                 return LDB_ERR_OPERATIONS_ERROR;
1773                         }
1774                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
1775                                                   invocation_id, seq_num, seq_num, now, 0, false);
1776                         if (ret != LDB_SUCCESS) {
1777                                 talloc_free(tmp_ctx);
1778                                 return ret;
1779                         }
1780                         num_new_values++;
1781                 } else {
1782                         /* this is only allowed if the GUID was
1783                            previously deleted. */
1784                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1785
1786                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
1787                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
1788                                                        el->name, GUID_string(tmp_ctx, p->guid));
1789                                 talloc_free(tmp_ctx);
1790                                 /* error codes for 'member' need to be
1791                                    special cased */
1792                                 if (ldb_attr_cmp(el->name, "member") == 0) {
1793                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
1794                                 } else {
1795                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
1796                                 }
1797                         }
1798                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
1799                                                    invocation_id, seq_num, seq_num, now, 0, false);
1800                         if (ret != LDB_SUCCESS) {
1801                                 talloc_free(tmp_ctx);
1802                                 return ret;
1803                         }
1804                 }
1805
1806                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, true);
1807                 if (ret != LDB_SUCCESS) {
1808                         talloc_free(tmp_ctx);
1809                         return ret;
1810                 }
1811         }
1812
1813         /* add the new ones on to the end of the old values, constructing a new el->values */
1814         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
1815                                     struct ldb_val,
1816                                     old_num_values+num_new_values);
1817         if (el->values == NULL) {
1818                 ldb_module_oom(module);
1819                 return LDB_ERR_OPERATIONS_ERROR;
1820         }
1821
1822         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
1823         el->num_values = old_num_values + num_new_values;
1824
1825         talloc_steal(msg->elements, el->values);
1826         talloc_steal(el->values, new_values);
1827
1828         talloc_free(tmp_ctx);
1829
1830         /* we now tell the backend to replace all existing values
1831            with the one we have constructed */
1832         el->flags = LDB_FLAG_MOD_REPLACE;
1833
1834         return LDB_SUCCESS;
1835 }
1836
1837
1838 /*
1839   handle deleting all active linked attributes
1840  */
1841 static int replmd_modify_la_delete(struct ldb_module *module,
1842                                    const struct dsdb_schema *schema,
1843                                    struct ldb_message *msg,
1844                                    struct ldb_message_element *el,
1845                                    struct ldb_message_element *old_el,
1846                                    const struct dsdb_attribute *schema_attr,
1847                                    uint64_t seq_num,
1848                                    time_t t,
1849                                    struct GUID *msg_guid,
1850                                    struct ldb_request *parent)
1851 {
1852         unsigned int i;
1853         struct parsed_dn *dns, *old_dns;
1854         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1855         int ret;
1856         const struct GUID *invocation_id;
1857         struct ldb_context *ldb = ldb_module_get_ctx(module);
1858         NTTIME now;
1859
1860         unix_to_nt_time(&now, t);
1861
1862         /* check if there is nothing to delete */
1863         if ((!old_el || old_el->num_values == 0) &&
1864             el->num_values == 0) {
1865                 return LDB_SUCCESS;
1866         }
1867
1868         if (!old_el || old_el->num_values == 0) {
1869                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1870         }
1871
1872         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
1873         if (ret != LDB_SUCCESS) {
1874                 talloc_free(tmp_ctx);
1875                 return ret;
1876         }
1877
1878         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
1879         if (ret != LDB_SUCCESS) {
1880                 talloc_free(tmp_ctx);
1881                 return ret;
1882         }
1883
1884         invocation_id = samdb_ntds_invocation_id(ldb);
1885         if (!invocation_id) {
1886                 return LDB_ERR_OPERATIONS_ERROR;
1887         }
1888
1889         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
1890         if (ret != LDB_SUCCESS) {
1891                 talloc_free(tmp_ctx);
1892                 return ret;
1893         }
1894
1895         el->values = NULL;
1896
1897         /* see if we are being asked to delete any links that
1898            don't exist or are already deleted */
1899         for (i=0; i<el->num_values; i++) {
1900                 struct parsed_dn *p = &dns[i];
1901                 struct parsed_dn *p2;
1902                 uint32_t rmd_flags;
1903
1904                 p2 = parsed_dn_find(old_dns, old_el->num_values, p->guid, NULL);
1905                 if (!p2) {
1906                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
1907                                                el->name, GUID_string(tmp_ctx, p->guid));
1908                         if (ldb_attr_cmp(el->name, "member") == 0) {
1909                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1910                         } else {
1911                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1912                         }
1913                 }
1914                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
1915                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
1916                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
1917                                                el->name, GUID_string(tmp_ctx, p->guid));
1918                         if (ldb_attr_cmp(el->name, "member") == 0) {
1919                                 return LDB_ERR_UNWILLING_TO_PERFORM;
1920                         } else {
1921                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
1922                         }
1923                 }
1924         }
1925
1926         /* for each new value, see if it exists already with the same GUID
1927            if it is not already deleted and matches the delete list then delete it
1928         */
1929         for (i=0; i<old_el->num_values; i++) {
1930                 struct parsed_dn *p = &old_dns[i];
1931                 uint32_t rmd_flags;
1932
1933                 if (el->num_values && parsed_dn_find(dns, el->num_values, p->guid, NULL) == NULL) {
1934                         continue;
1935                 }
1936
1937                 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
1938                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
1939
1940                 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
1941                                            invocation_id, seq_num, seq_num, now, 0, true);
1942                 if (ret != LDB_SUCCESS) {
1943                         talloc_free(tmp_ctx);
1944                         return ret;
1945                 }
1946
1947                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, true);
1948                 if (ret != LDB_SUCCESS) {
1949                         talloc_free(tmp_ctx);
1950                         return ret;
1951                 }
1952         }
1953
1954         el->values = talloc_steal(msg->elements, old_el->values);
1955         el->num_values = old_el->num_values;
1956
1957         talloc_free(tmp_ctx);
1958
1959         /* we now tell the backend to replace all existing values
1960            with the one we have constructed */
1961         el->flags = LDB_FLAG_MOD_REPLACE;
1962
1963         return LDB_SUCCESS;
1964 }
1965
1966 /*
1967   handle replacing a linked attribute
1968  */
1969 static int replmd_modify_la_replace(struct ldb_module *module,
1970                                     const struct dsdb_schema *schema,
1971                                     struct ldb_message *msg,
1972                                     struct ldb_message_element *el,
1973                                     struct ldb_message_element *old_el,
1974                                     const struct dsdb_attribute *schema_attr,
1975                                     uint64_t seq_num,
1976                                     time_t t,
1977                                     struct GUID *msg_guid,
1978                                     struct ldb_request *parent)
1979 {
1980         unsigned int i;
1981         struct parsed_dn *dns, *old_dns;
1982         TALLOC_CTX *tmp_ctx = talloc_new(msg);
1983         int ret;
1984         const struct GUID *invocation_id;
1985         struct ldb_context *ldb = ldb_module_get_ctx(module);
1986         struct ldb_val *new_values = NULL;
1987         unsigned int num_new_values = 0;
1988         unsigned int old_num_values = old_el?old_el->num_values:0;
1989         NTTIME now;
1990
1991         unix_to_nt_time(&now, t);
1992
1993         /* check if there is nothing to replace */
1994         if ((!old_el || old_el->num_values == 0) &&
1995             el->num_values == 0) {
1996                 return LDB_SUCCESS;
1997         }
1998
1999         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2000         if (ret != LDB_SUCCESS) {
2001                 talloc_free(tmp_ctx);
2002                 return ret;
2003         }
2004
2005         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2006         if (ret != LDB_SUCCESS) {
2007                 talloc_free(tmp_ctx);
2008                 return ret;
2009         }
2010
2011         invocation_id = samdb_ntds_invocation_id(ldb);
2012         if (!invocation_id) {
2013                 return LDB_ERR_OPERATIONS_ERROR;
2014         }
2015
2016         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2017         if (ret != LDB_SUCCESS) {
2018                 talloc_free(tmp_ctx);
2019                 return ret;
2020         }
2021
2022         /* mark all the old ones as deleted */
2023         for (i=0; i<old_num_values; i++) {
2024                 struct parsed_dn *old_p = &old_dns[i];
2025                 struct parsed_dn *p;
2026                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2027
2028                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2029
2030                 ret = replmd_add_backlink(module, schema, msg_guid, old_dns[i].guid, false, schema_attr, false);
2031                 if (ret != LDB_SUCCESS) {
2032                         talloc_free(tmp_ctx);
2033                         return ret;
2034                 }
2035
2036                 p = parsed_dn_find(dns, el->num_values, old_p->guid, NULL);
2037                 if (p) {
2038                         /* we don't delete it if we are re-adding it */
2039                         continue;
2040                 }
2041
2042                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2043                                            invocation_id, seq_num, seq_num, now, 0, true);
2044                 if (ret != LDB_SUCCESS) {
2045                         talloc_free(tmp_ctx);
2046                         return ret;
2047                 }
2048         }
2049
2050         /* for each new value, either update its meta-data, or add it
2051          * to old_el
2052         */
2053         for (i=0; i<el->num_values; i++) {
2054                 struct parsed_dn *p = &dns[i], *old_p;
2055
2056                 if (old_dns &&
2057                     (old_p = parsed_dn_find(old_dns,
2058                                             old_num_values, p->guid, NULL)) != NULL) {
2059                         /* update in place */
2060                         ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2061                                                    old_p->dsdb_dn, invocation_id,
2062                                                    seq_num, seq_num, now, 0, false);
2063                         if (ret != LDB_SUCCESS) {
2064                                 talloc_free(tmp_ctx);
2065                                 return ret;
2066                         }
2067                 } else {
2068                         /* add a new one */
2069                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2070                                                     num_new_values+1);
2071                         if (new_values == NULL) {
2072                                 ldb_module_oom(module);
2073                                 talloc_free(tmp_ctx);
2074                                 return LDB_ERR_OPERATIONS_ERROR;
2075                         }
2076                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2077                                                   invocation_id, seq_num, seq_num, now, 0, false);
2078                         if (ret != LDB_SUCCESS) {
2079                                 talloc_free(tmp_ctx);
2080                                 return ret;
2081                         }
2082                         num_new_values++;
2083                 }
2084
2085                 ret = replmd_add_backlink(module, schema, msg_guid, dns[i].guid, true, schema_attr, false);
2086                 if (ret != LDB_SUCCESS) {
2087                         talloc_free(tmp_ctx);
2088                         return ret;
2089                 }
2090         }
2091
2092         /* add the new values to the end of old_el */
2093         if (num_new_values != 0) {
2094                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2095                                             struct ldb_val, old_num_values+num_new_values);
2096                 if (el->values == NULL) {
2097                         ldb_module_oom(module);
2098                         return LDB_ERR_OPERATIONS_ERROR;
2099                 }
2100                 memcpy(&el->values[old_num_values], &new_values[0],
2101                        sizeof(struct ldb_val)*num_new_values);
2102                 el->num_values = old_num_values + num_new_values;
2103                 talloc_steal(msg->elements, new_values);
2104         } else {
2105                 el->values = old_el->values;
2106                 el->num_values = old_el->num_values;
2107                 talloc_steal(msg->elements, el->values);
2108         }
2109
2110         talloc_free(tmp_ctx);
2111
2112         /* we now tell the backend to replace all existing values
2113            with the one we have constructed */
2114         el->flags = LDB_FLAG_MOD_REPLACE;
2115
2116         return LDB_SUCCESS;
2117 }
2118
2119
2120 /*
2121   handle linked attributes in modify requests
2122  */
2123 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2124                                                struct ldb_message *msg,
2125                                                uint64_t seq_num, time_t t,
2126                                                struct ldb_request *parent)
2127 {
2128         struct ldb_result *res;
2129         unsigned int i;
2130         int ret;
2131         struct ldb_context *ldb = ldb_module_get_ctx(module);
2132         struct ldb_message *old_msg;
2133
2134         const struct dsdb_schema *schema;
2135         struct GUID old_guid;
2136
2137         if (seq_num == 0) {
2138                 /* there the replmd_update_rpmd code has already
2139                  * checked and saw that there are no linked
2140                  * attributes */
2141                 return LDB_SUCCESS;
2142         }
2143
2144         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2145                 /* don't do anything special for linked attributes */
2146                 return LDB_SUCCESS;
2147         }
2148
2149         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2150                                     DSDB_FLAG_NEXT_MODULE |
2151                                     DSDB_SEARCH_SHOW_RECYCLED |
2152                                     DSDB_SEARCH_REVEAL_INTERNALS |
2153                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2154                                     parent);
2155         if (ret != LDB_SUCCESS) {
2156                 return ret;
2157         }
2158         schema = dsdb_get_schema(ldb, res);
2159         if (!schema) {
2160                 return LDB_ERR_OPERATIONS_ERROR;
2161         }
2162
2163         old_msg = res->msgs[0];
2164
2165         old_guid = samdb_result_guid(old_msg, "objectGUID");
2166
2167         for (i=0; i<msg->num_elements; i++) {
2168                 struct ldb_message_element *el = &msg->elements[i];
2169                 struct ldb_message_element *old_el, *new_el;
2170                 const struct dsdb_attribute *schema_attr
2171                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2172                 if (!schema_attr) {
2173                         ldb_asprintf_errstring(ldb,
2174                                                "%s: attribute %s is not a valid attribute in schema",
2175                                                __FUNCTION__, el->name);
2176                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2177                 }
2178                 if (schema_attr->linkID == 0) {
2179                         continue;
2180                 }
2181                 if ((schema_attr->linkID & 1) == 1) {
2182                         /* Odd is for the target.  Illegal to modify */
2183                         ldb_asprintf_errstring(ldb,
2184                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2185                         return LDB_ERR_UNWILLING_TO_PERFORM;
2186                 }
2187                 old_el = ldb_msg_find_element(old_msg, el->name);
2188                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2189                 case LDB_FLAG_MOD_REPLACE:
2190                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2191                         break;
2192                 case LDB_FLAG_MOD_DELETE:
2193                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2194                         break;
2195                 case LDB_FLAG_MOD_ADD:
2196                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2197                         break;
2198                 default:
2199                         ldb_asprintf_errstring(ldb,
2200                                                "invalid flags 0x%x for %s linked attribute",
2201                                                el->flags, el->name);
2202                         return LDB_ERR_UNWILLING_TO_PERFORM;
2203                 }
2204                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2205                         ldb_asprintf_errstring(ldb,
2206                                                "Attribute %s is single valued but more than one value has been supplied",
2207                                                el->name);
2208                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2209                 } else {
2210                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2211                 }
2212
2213
2214
2215                 if (ret != LDB_SUCCESS) {
2216                         return ret;
2217                 }
2218                 if (old_el) {
2219                         ldb_msg_remove_attr(old_msg, el->name);
2220                 }
2221                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2222                 new_el->num_values = el->num_values;
2223                 new_el->values = talloc_steal(msg->elements, el->values);
2224
2225                 /* TODO: this relises a bit too heavily on the exact
2226                    behaviour of ldb_msg_find_element and
2227                    ldb_msg_remove_element */
2228                 old_el = ldb_msg_find_element(msg, el->name);
2229                 if (old_el != el) {
2230                         ldb_msg_remove_element(msg, old_el);
2231                         i--;
2232                 }
2233         }
2234
2235         talloc_free(res);
2236         return ret;
2237 }
2238
2239
2240
2241 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2242 {
2243         struct ldb_context *ldb;
2244         struct replmd_replicated_request *ac;
2245         struct ldb_request *down_req;
2246         struct ldb_message *msg;
2247         time_t t = time(NULL);
2248         int ret;
2249         bool is_urgent = false;
2250         struct loadparm_context *lp_ctx;
2251         char *referral;
2252         unsigned int functional_level;
2253         const DATA_BLOB *guid_blob;
2254
2255         /* do not manipulate our control entries */
2256         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2257                 return ldb_next_request(module, req);
2258         }
2259
2260         ldb = ldb_module_get_ctx(module);
2261
2262         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2263
2264         guid_blob = ldb_msg_find_ldb_val(req->op.mod.message, "objectGUID");
2265         if ( guid_blob != NULL ) {
2266                 ldb_set_errstring(ldb,
2267                                   "replmd_modify: it's not allowed to change the objectGUID!");
2268                 return LDB_ERR_CONSTRAINT_VIOLATION;
2269         }
2270
2271         ac = replmd_ctx_init(module, req);
2272         if (ac == NULL) {
2273                 return ldb_module_oom(module);
2274         }
2275
2276         functional_level = dsdb_functional_level(ldb);
2277
2278         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2279                                  struct loadparm_context);
2280
2281         /* we have to copy the message as the caller might have it as a const */
2282         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2283         if (msg == NULL) {
2284                 ldb_oom(ldb);
2285                 talloc_free(ac);
2286                 return LDB_ERR_OPERATIONS_ERROR;
2287         }
2288
2289         ldb_msg_remove_attr(msg, "whenChanged");
2290         ldb_msg_remove_attr(msg, "uSNChanged");
2291
2292         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2293                                  msg, &ac->seq_num, t, &is_urgent);
2294         if (ret == LDB_ERR_REFERRAL) {
2295                 referral = talloc_asprintf(req,
2296                                            "ldap://%s/%s",
2297                                            lpcfg_dnsdomain(lp_ctx),
2298                                            ldb_dn_get_linearized(msg->dn));
2299                 ret = ldb_module_send_referral(req, referral);
2300                 talloc_free(ac);
2301                 return ldb_module_done(req, NULL, NULL, ret);
2302         }
2303
2304         if (ret != LDB_SUCCESS) {
2305                 talloc_free(ac);
2306                 return ret;
2307         }
2308
2309         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2310         if (ret != LDB_SUCCESS) {
2311                 talloc_free(ac);
2312                 return ret;
2313         }
2314
2315         /* TODO:
2316          * - replace the old object with the newly constructed one
2317          */
2318
2319         ac->is_urgent = is_urgent;
2320
2321         ret = ldb_build_mod_req(&down_req, ldb, ac,
2322                                 msg,
2323                                 req->controls,
2324                                 ac, replmd_op_callback,
2325                                 req);
2326         LDB_REQ_SET_LOCATION(down_req);
2327         if (ret != LDB_SUCCESS) {
2328                 talloc_free(ac);
2329                 return ret;
2330         }
2331
2332         /* current partition control is needed by "replmd_op_callback" */
2333         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2334                 ret = ldb_request_add_control(down_req,
2335                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2336                                               false, NULL);
2337                 if (ret != LDB_SUCCESS) {
2338                         talloc_free(ac);
2339                         return ret;
2340                 }
2341         }
2342
2343         /* If we are in functional level 2000, then
2344          * replmd_modify_handle_linked_attribs will have done
2345          * nothing */
2346         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2347                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2348                 if (ret != LDB_SUCCESS) {
2349                         talloc_free(ac);
2350                         return ret;
2351                 }
2352         }
2353
2354         talloc_steal(down_req, msg);
2355
2356         /* we only change whenChanged and uSNChanged if the seq_num
2357            has changed */
2358         if (ac->seq_num != 0) {
2359                 ret = add_time_element(msg, "whenChanged", t);
2360                 if (ret != LDB_SUCCESS) {
2361                         talloc_free(ac);
2362                         return ret;
2363                 }
2364
2365                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2366                 if (ret != LDB_SUCCESS) {
2367                         talloc_free(ac);
2368                         return ret;
2369                 }
2370         }
2371
2372         /* go on with the call chain */
2373         return ldb_next_request(module, down_req);
2374 }
2375
2376 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2377
2378 /*
2379   handle a rename request
2380
2381   On a rename we need to do an extra ldb_modify which sets the
2382   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2383  */
2384 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2385 {
2386         struct ldb_context *ldb;
2387         struct replmd_replicated_request *ac;
2388         int ret;
2389         struct ldb_request *down_req;
2390
2391         /* do not manipulate our control entries */
2392         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2393                 return ldb_next_request(module, req);
2394         }
2395
2396         ldb = ldb_module_get_ctx(module);
2397
2398         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2399
2400         ac = replmd_ctx_init(module, req);
2401         if (ac == NULL) {
2402                 return ldb_module_oom(module);
2403         }
2404
2405         ret = ldb_build_rename_req(&down_req, ldb, ac,
2406                                    ac->req->op.rename.olddn,
2407                                    ac->req->op.rename.newdn,
2408                                    ac->req->controls,
2409                                    ac, replmd_rename_callback,
2410                                    ac->req);
2411         LDB_REQ_SET_LOCATION(down_req);
2412         if (ret != LDB_SUCCESS) {
2413                 talloc_free(ac);
2414                 return ret;
2415         }
2416
2417         /* go on with the call chain */
2418         return ldb_next_request(module, down_req);
2419 }
2420
2421 /* After the rename is compleated, update the whenchanged etc */
2422 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2423 {
2424         struct ldb_context *ldb;
2425         struct replmd_replicated_request *ac;
2426         struct ldb_request *down_req;
2427         struct ldb_message *msg;
2428         const struct dsdb_attribute *rdn_attr;
2429         const char *rdn_name;
2430         const struct ldb_val *rdn_val;
2431         const char *attrs[5] = { NULL, };
2432         time_t t = time(NULL);
2433         int ret;
2434         bool is_urgent = false;
2435
2436         ac = talloc_get_type(req->context, struct replmd_replicated_request);
2437         ldb = ldb_module_get_ctx(ac->module);
2438
2439         if (ares->error != LDB_SUCCESS) {
2440                 return ldb_module_done(ac->req, ares->controls,
2441                                         ares->response, ares->error);
2442         }
2443
2444         if (ares->type != LDB_REPLY_DONE) {
2445                 ldb_set_errstring(ldb,
2446                                   "invalid ldb_reply_type in callback");
2447                 talloc_free(ares);
2448                 return ldb_module_done(ac->req, NULL, NULL,
2449                                         LDB_ERR_OPERATIONS_ERROR);
2450         }
2451
2452         /* TODO:
2453          * - replace the old object with the newly constructed one
2454          */
2455
2456         msg = ldb_msg_new(ac);
2457         if (msg == NULL) {
2458                 ldb_oom(ldb);
2459                 return LDB_ERR_OPERATIONS_ERROR;
2460         }
2461
2462         msg->dn = ac->req->op.rename.newdn;
2463
2464         rdn_name = ldb_dn_get_rdn_name(msg->dn);
2465         if (rdn_name == NULL) {
2466                 talloc_free(ares);
2467                 return ldb_module_done(ac->req, NULL, NULL,
2468                                        ldb_operr(ldb));
2469         }
2470
2471         /* normalize the rdn attribute name */
2472         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2473         if (rdn_attr == NULL) {
2474                 talloc_free(ares);
2475                 return ldb_module_done(ac->req, NULL, NULL,
2476                                        ldb_operr(ldb));
2477         }
2478         rdn_name = rdn_attr->lDAPDisplayName;
2479
2480         rdn_val = ldb_dn_get_rdn_val(msg->dn);
2481         if (rdn_val == NULL) {
2482                 talloc_free(ares);
2483                 return ldb_module_done(ac->req, NULL, NULL,
2484                                        ldb_operr(ldb));
2485         }
2486
2487         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2488                 talloc_free(ares);
2489                 return ldb_module_done(ac->req, NULL, NULL,
2490                                        ldb_oom(ldb));
2491         }
2492         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2493                 talloc_free(ares);
2494                 return ldb_module_done(ac->req, NULL, NULL,
2495                                        ldb_oom(ldb));
2496         }
2497         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2498                 talloc_free(ares);
2499                 return ldb_module_done(ac->req, NULL, NULL,
2500                                        ldb_oom(ldb));
2501         }
2502         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2503                 talloc_free(ares);
2504                 return ldb_module_done(ac->req, NULL, NULL,
2505                                        ldb_oom(ldb));
2506         }
2507
2508         /*
2509          * here we let replmd_update_rpmd() only search for
2510          * the existing "replPropertyMetaData" and rdn_name attributes.
2511          *
2512          * We do not want the existing "name" attribute as
2513          * the "name" attribute needs to get the version
2514          * updated on rename even if the rdn value hasn't changed.
2515          *
2516          * This is the diff of the meta data, for a moved user
2517          * on a w2k8r2 server:
2518          *
2519          * # record 1
2520          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2521          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2522          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
2523          *         version                  : 0x00000001 (1)
2524          *         reserved                 : 0x00000000 (0)
2525          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
2526          *                      local_usn                : 0x00000000000037a5 (14245)
2527          *                 array: struct replPropertyMetaData1
2528          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
2529          * -                    version                  : 0x00000001 (1)
2530          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
2531          * +                    version                  : 0x00000002 (2)
2532          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
2533          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2534          * -                    originating_usn          : 0x00000000000037a5 (14245)
2535          * -                    local_usn                : 0x00000000000037a5 (14245)
2536          * +                    originating_usn          : 0x0000000000003834 (14388)
2537          * +                    local_usn                : 0x0000000000003834 (14388)
2538          *                 array: struct replPropertyMetaData1
2539          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
2540          *                      version                  : 0x00000004 (4)
2541          */
2542         attrs[0] = "replPropertyMetaData";
2543         attrs[1] = "objectClass";
2544         attrs[2] = "instanceType";
2545         attrs[3] = rdn_name;
2546         attrs[4] = NULL;
2547
2548         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2549                                  msg, &ac->seq_num, t, &is_urgent);
2550         if (ret == LDB_ERR_REFERRAL) {
2551                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2552                 struct loadparm_context *lp_ctx;
2553                 char *referral;
2554
2555                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2556                                          struct loadparm_context);
2557
2558                 referral = talloc_asprintf(req,
2559                                            "ldap://%s/%s",
2560                                            lpcfg_dnsdomain(lp_ctx),
2561                                            ldb_dn_get_linearized(olddn));
2562                 ret = ldb_module_send_referral(req, referral);
2563                 talloc_free(ac);
2564                 return ldb_module_done(req, NULL, NULL, ret);
2565         }
2566
2567         if (ret != LDB_SUCCESS) {
2568                 talloc_free(ares);
2569                 return ldb_module_done(ac->req, NULL, NULL,
2570                                        ldb_error(ldb, ret,
2571                                         "failed to call replmd_update_rpmd()"));
2572         }
2573
2574         if (ac->seq_num == 0) {
2575                 talloc_free(ares);
2576                 return ldb_module_done(ac->req, NULL, NULL,
2577                                        ldb_error(ldb, ret,
2578                                         "internal error seq_num == 0"));
2579         }
2580         ac->is_urgent = is_urgent;
2581
2582         ret = ldb_build_mod_req(&down_req, ldb, ac,
2583                                 msg,
2584                                 req->controls,
2585                                 ac, replmd_op_callback,
2586                                 req);
2587         LDB_REQ_SET_LOCATION(down_req);
2588         if (ret != LDB_SUCCESS) {
2589                 talloc_free(ac);
2590                 return ret;
2591         }
2592
2593         /* current partition control is needed by "replmd_op_callback" */
2594         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2595                 ret = ldb_request_add_control(down_req,
2596                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2597                                               false, NULL);
2598                 if (ret != LDB_SUCCESS) {
2599                         talloc_free(ac);
2600                         return ret;
2601                 }
2602         }
2603
2604         talloc_steal(down_req, msg);
2605
2606         ret = add_time_element(msg, "whenChanged", t);
2607         if (ret != LDB_SUCCESS) {
2608                 talloc_free(ac);
2609                 return ret;
2610         }
2611
2612         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2613         if (ret != LDB_SUCCESS) {
2614                 talloc_free(ac);
2615                 return ret;
2616         }
2617
2618         /* go on with the call chain - do the modify after the rename */
2619         return ldb_next_request(ac->module, down_req);
2620 }
2621
2622 /*
2623    remove links from objects that point at this object when an object
2624    is deleted
2625  */
2626 static int replmd_delete_remove_link(struct ldb_module *module,
2627                                      const struct dsdb_schema *schema,
2628                                      struct ldb_dn *dn,
2629                                      struct ldb_message_element *el,
2630                                      const struct dsdb_attribute *sa,
2631                                      struct ldb_request *parent)
2632 {
2633         unsigned int i;
2634         TALLOC_CTX *tmp_ctx = talloc_new(module);
2635         struct ldb_context *ldb = ldb_module_get_ctx(module);
2636
2637         for (i=0; i<el->num_values; i++) {
2638                 struct dsdb_dn *dsdb_dn;
2639                 NTSTATUS status;
2640                 int ret;
2641                 struct GUID guid2;
2642                 struct ldb_message *msg;
2643                 const struct dsdb_attribute *target_attr;
2644                 struct ldb_message_element *el2;
2645                 struct ldb_val dn_val;
2646
2647                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2648                         continue;
2649                 }
2650
2651                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2652                 if (!dsdb_dn) {
2653                         talloc_free(tmp_ctx);
2654                         return LDB_ERR_OPERATIONS_ERROR;
2655                 }
2656
2657                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2658                 if (!NT_STATUS_IS_OK(status)) {
2659                         talloc_free(tmp_ctx);
2660                         return LDB_ERR_OPERATIONS_ERROR;
2661                 }
2662
2663                 /* remove the link */
2664                 msg = ldb_msg_new(tmp_ctx);
2665                 if (!msg) {
2666                         ldb_module_oom(module);
2667                         talloc_free(tmp_ctx);
2668                         return LDB_ERR_OPERATIONS_ERROR;
2669                 }
2670
2671
2672                 msg->dn = dsdb_dn->dn;
2673
2674                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2675                 if (target_attr == NULL) {
2676                         continue;
2677                 }
2678
2679                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
2680                 if (ret != LDB_SUCCESS) {
2681                         ldb_module_oom(module);
2682                         talloc_free(tmp_ctx);
2683                         return LDB_ERR_OPERATIONS_ERROR;
2684                 }
2685                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
2686                 el2->values = &dn_val;
2687                 el2->num_values = 1;
2688
2689                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
2690                 if (ret != LDB_SUCCESS) {
2691                         talloc_free(tmp_ctx);
2692                         return ret;
2693                 }
2694         }
2695         talloc_free(tmp_ctx);
2696         return LDB_SUCCESS;
2697 }
2698
2699
2700 /*
2701   handle update of replication meta data for deletion of objects
2702
2703   This also handles the mapping of delete to a rename operation
2704   to allow deletes to be replicated.
2705  */
2706 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
2707 {
2708         int ret = LDB_ERR_OTHER;
2709         bool retb, disallow_move_on_delete;
2710         struct ldb_dn *old_dn, *new_dn;
2711         const char *rdn_name;
2712         const struct ldb_val *rdn_value, *new_rdn_value;
2713         struct GUID guid;
2714         struct ldb_context *ldb = ldb_module_get_ctx(module);
2715         const struct dsdb_schema *schema;
2716         struct ldb_message *msg, *old_msg;
2717         struct ldb_message_element *el;
2718         TALLOC_CTX *tmp_ctx;
2719         struct ldb_result *res, *parent_res;
2720         const char *preserved_attrs[] = {
2721                 /* yes, this really is a hard coded list. See MS-ADTS
2722                    section 3.1.1.5.5.1.1 */
2723                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
2724                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
2725                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
2726                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
2727                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
2728                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
2729                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
2730                 "whenChanged", NULL};
2731         unsigned int i, el_count = 0;
2732         enum deletion_state { OBJECT_NOT_DELETED=1, OBJECT_DELETED=2, OBJECT_RECYCLED=3,
2733                                                 OBJECT_TOMBSTONE=4, OBJECT_REMOVED=5 };
2734         enum deletion_state deletion_state, next_deletion_state;
2735         bool enabled;
2736         int functional_level;
2737
2738         if (ldb_dn_is_special(req->op.del.dn)) {
2739                 return ldb_next_request(module, req);
2740         }
2741
2742         tmp_ctx = talloc_new(ldb);
2743         if (!tmp_ctx) {
2744                 ldb_oom(ldb);
2745                 return LDB_ERR_OPERATIONS_ERROR;
2746         }
2747
2748         schema = dsdb_get_schema(ldb, tmp_ctx);
2749         if (!schema) {
2750                 return LDB_ERR_OPERATIONS_ERROR;
2751         }
2752
2753         functional_level = dsdb_functional_level(ldb);
2754
2755         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2756
2757         /* we need the complete msg off disk, so we can work out which
2758            attributes need to be removed */
2759         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2760                                     DSDB_FLAG_NEXT_MODULE |
2761                                     DSDB_SEARCH_SHOW_RECYCLED |
2762                                     DSDB_SEARCH_REVEAL_INTERNALS |
2763                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2764         if (ret != LDB_SUCCESS) {
2765                 talloc_free(tmp_ctx);
2766                 return ret;
2767         }
2768         old_msg = res->msgs[0];
2769
2770
2771         ret = dsdb_recyclebin_enabled(module, &enabled);
2772         if (ret != LDB_SUCCESS) {
2773                 talloc_free(tmp_ctx);
2774                 return ret;
2775         }
2776
2777         if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2778                 if (!enabled) {
2779                         deletion_state = OBJECT_TOMBSTONE;
2780                         next_deletion_state = OBJECT_REMOVED;
2781                 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2782                         deletion_state = OBJECT_RECYCLED;
2783                         next_deletion_state = OBJECT_REMOVED;
2784                 } else {
2785                         deletion_state = OBJECT_DELETED;
2786                         next_deletion_state = OBJECT_RECYCLED;
2787                 }
2788         } else {
2789                 deletion_state = OBJECT_NOT_DELETED;
2790                 if (enabled) {
2791                         next_deletion_state = OBJECT_DELETED;
2792                 } else {
2793                         next_deletion_state = OBJECT_TOMBSTONE;
2794                 }
2795         }
2796
2797         if (next_deletion_state == OBJECT_REMOVED) {
2798                 struct auth_session_info *session_info =
2799                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2800                 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2801                         ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2802                                         ldb_dn_get_linearized(old_msg->dn));
2803                         return LDB_ERR_UNWILLING_TO_PERFORM;
2804                 }
2805
2806                 /* it is already deleted - really remove it this time */
2807                 talloc_free(tmp_ctx);
2808                 return ldb_next_request(module, req);
2809         }
2810
2811         rdn_name = ldb_dn_get_rdn_name(old_dn);
2812         rdn_value = ldb_dn_get_rdn_val(old_dn);
2813         if ((rdn_name == NULL) || (rdn_value == NULL)) {
2814                 talloc_free(tmp_ctx);
2815                 return ldb_operr(ldb);
2816         }
2817
2818         msg = ldb_msg_new(tmp_ctx);
2819         if (msg == NULL) {
2820                 ldb_module_oom(module);
2821                 talloc_free(tmp_ctx);
2822                 return LDB_ERR_OPERATIONS_ERROR;
2823         }
2824
2825         msg->dn = old_dn;
2826
2827         if (deletion_state == OBJECT_NOT_DELETED){
2828                 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2829                 disallow_move_on_delete =
2830                         (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2831                                 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2832
2833                 /* work out where we will be renaming this object to */
2834                 if (!disallow_move_on_delete) {
2835                         ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2836                                                           &new_dn);
2837                         if (ret != LDB_SUCCESS) {
2838                                 /* this is probably an attempted delete on a partition
2839                                  * that doesn't allow delete operations, such as the
2840                                  * schema partition */
2841                                 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2842                                                            ldb_dn_get_linearized(old_dn));
2843                                 talloc_free(tmp_ctx);
2844                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2845                         }
2846                 } else {
2847                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2848                         if (new_dn == NULL) {
2849                                 ldb_module_oom(module);
2850                                 talloc_free(tmp_ctx);
2851                                 return LDB_ERR_OPERATIONS_ERROR;
2852                         }
2853                 }
2854
2855                 /* get the objects GUID from the search we just did */
2856                 guid = samdb_result_guid(old_msg, "objectGUID");
2857
2858                 /* Add a formatted child */
2859                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2860                                                 rdn_name,
2861                                                 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2862                                                 GUID_string(tmp_ctx, &guid));
2863                 if (!retb) {
2864                         DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2865                                         ldb_dn_get_linearized(new_dn)));
2866                         talloc_free(tmp_ctx);
2867                         return LDB_ERR_OPERATIONS_ERROR;
2868                 }
2869
2870                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2871                 if (ret != LDB_SUCCESS) {
2872                         DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2873                         ldb_module_oom(module);
2874                         talloc_free(tmp_ctx);
2875                         return ret;
2876                 }
2877                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2878         }
2879
2880         /*
2881           now we need to modify the object in the following ways:
2882
2883           - add isDeleted=TRUE
2884           - update rDN and name, with new rDN
2885           - remove linked attributes
2886           - remove objectCategory and sAMAccountType
2887           - remove attribs not on the preserved list
2888              - preserved if in above list, or is rDN
2889           - remove all linked attribs from this object
2890           - remove all links from other objects to this object
2891           - add lastKnownParent
2892           - update replPropertyMetaData?
2893
2894           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2895          */
2896
2897         /* we need the storage form of the parent GUID */
2898         ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2899                                     ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2900                                     DSDB_FLAG_NEXT_MODULE |
2901                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2902                                     DSDB_SEARCH_REVEAL_INTERNALS|
2903                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2904         if (ret != LDB_SUCCESS) {
2905                 talloc_free(tmp_ctx);
2906                 return ret;
2907         }
2908
2909         if (deletion_state == OBJECT_NOT_DELETED){
2910                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2911                                                    ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2912                 if (ret != LDB_SUCCESS) {
2913                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2914                         ldb_module_oom(module);
2915                         talloc_free(tmp_ctx);
2916                         return ret;
2917                 }
2918                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2919         }
2920
2921         switch (next_deletion_state){
2922
2923         case OBJECT_DELETED:
2924
2925                 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2926                 if (ret != LDB_SUCCESS) {
2927                         DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2928                         ldb_module_oom(module);
2929                         talloc_free(tmp_ctx);
2930                         return ret;
2931                 }
2932                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2933
2934                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_DELETE, NULL);
2935                 if (ret != LDB_SUCCESS) {
2936                         talloc_free(tmp_ctx);
2937                         ldb_module_oom(module);
2938                         return ret;
2939                 }
2940
2941                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_DELETE, NULL);
2942                 if (ret != LDB_SUCCESS) {
2943                         talloc_free(tmp_ctx);
2944                         ldb_module_oom(module);
2945                         return ret;
2946                 }
2947
2948                 break;
2949
2950         case OBJECT_RECYCLED:
2951         case OBJECT_TOMBSTONE:
2952
2953                 /* we also mark it as recycled, meaning this object can't be
2954                    recovered (we are stripping its attributes) */
2955                 if (functional_level >= DS_DOMAIN_FUNCTION_2008_R2) {
2956                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
2957                         if (ret != LDB_SUCCESS) {
2958                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
2959                                 ldb_module_oom(module);
2960                                 talloc_free(tmp_ctx);
2961                                 return ret;
2962                         }
2963                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2964                 }
2965
2966                 /* work out which of the old attributes we will be removing */
2967                 for (i=0; i<old_msg->num_elements; i++) {
2968                         const struct dsdb_attribute *sa;
2969                         el = &old_msg->elements[i];
2970                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2971                         if (!sa) {
2972                                 talloc_free(tmp_ctx);
2973                                 return LDB_ERR_OPERATIONS_ERROR;
2974                         }
2975                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
2976                                 /* don't remove the rDN */
2977                                 continue;
2978                         }
2979                         if (sa->linkID && (sa->linkID & 1)) {
2980                                 /*
2981                                   we have a backlink in this object
2982                                   that needs to be removed. We're not
2983                                   allowed to remove it directly
2984                                   however, so we instead setup a
2985                                   modify to delete the corresponding
2986                                   forward link
2987                                  */
2988                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
2989                                 if (ret != LDB_SUCCESS) {
2990                                         talloc_free(tmp_ctx);
2991                                         return LDB_ERR_OPERATIONS_ERROR;
2992                                 }
2993                                 /* now we continue, which means we
2994                                    won't remove this backlink
2995                                    directly
2996                                 */
2997                                 continue;
2998                         }
2999                         if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
3000                                 continue;
3001                         }
3002                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3003                         if (ret != LDB_SUCCESS) {
3004                                 talloc_free(tmp_ctx);
3005                                 ldb_module_oom(module);
3006                                 return ret;
3007                         }
3008                 }
3009                 break;
3010
3011         default:
3012                 break;
3013         }
3014
3015         if (deletion_state == OBJECT_NOT_DELETED) {
3016                 const struct dsdb_attribute *sa;
3017
3018                 /* work out what the new rdn value is, for updating the
3019                    rDN and name fields */
3020                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3021                 if (new_rdn_value == NULL) {
3022                         talloc_free(tmp_ctx);
3023                         return ldb_operr(ldb);
3024                 }
3025
3026                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3027                 if (!sa) {
3028                         talloc_free(tmp_ctx);
3029                         return LDB_ERR_OPERATIONS_ERROR;
3030                 }
3031
3032                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3033                                         &el);
3034                 if (ret != LDB_SUCCESS) {
3035                         talloc_free(tmp_ctx);
3036                         return ret;
3037                 }
3038                 el->flags = LDB_FLAG_MOD_REPLACE;
3039
3040                 el = ldb_msg_find_element(old_msg, "name");
3041                 if (el) {
3042                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3043                         if (ret != LDB_SUCCESS) {
3044                                 talloc_free(tmp_ctx);
3045                                 return ret;
3046                         }
3047                         el->flags = LDB_FLAG_MOD_REPLACE;
3048                 }
3049         }
3050
3051         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3052         if (ret != LDB_SUCCESS) {
3053                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3054                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3055                 talloc_free(tmp_ctx);
3056                 return ret;
3057         }
3058
3059         if (deletion_state == OBJECT_NOT_DELETED) {
3060                 /* now rename onto the new DN */
3061                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3062                 if (ret != LDB_SUCCESS){
3063                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3064                                  ldb_dn_get_linearized(old_dn),
3065                                  ldb_dn_get_linearized(new_dn),
3066                                  ldb_errstring(ldb)));
3067                         talloc_free(tmp_ctx);
3068                         return ret;
3069                 }
3070         }
3071
3072         talloc_free(tmp_ctx);
3073
3074         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3075 }
3076
3077
3078
3079 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3080 {
3081         return ret;
3082 }
3083
3084 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3085 {
3086         int ret = LDB_ERR_OTHER;
3087         /* TODO: do some error mapping */
3088         return ret;
3089 }
3090
3091
3092 static struct replPropertyMetaData1 *
3093 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3094                                         enum drsuapi_DsAttributeId attid)
3095 {
3096         uint32_t i;
3097         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3098
3099         for (i = 0; i < rpmd_ctr->count; i++) {
3100                 if (rpmd_ctr->array[i].attid == attid) {
3101                         return &rpmd_ctr->array[i];
3102                 }
3103         }
3104         return NULL;
3105 }
3106
3107
3108 /*
3109    return true if an update is newer than an existing entry
3110    see section 5.11 of MS-ADTS
3111 */
3112 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3113                                    const struct GUID *update_invocation_id,
3114                                    uint32_t current_version,
3115                                    uint32_t update_version,
3116                                    NTTIME current_change_time,
3117                                    NTTIME update_change_time)
3118 {
3119         if (update_version != current_version) {
3120                 return update_version > current_version;
3121         }
3122         if (update_change_time != current_change_time) {
3123                 return update_change_time > current_change_time;
3124         }
3125         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3126 }
3127
3128 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3129                                                   struct replPropertyMetaData1 *new_m)
3130 {
3131         return replmd_update_is_newer(&cur_m->originating_invocation_id,
3132                                       &new_m->originating_invocation_id,
3133                                       cur_m->version,
3134                                       new_m->version,
3135                                       cur_m->originating_change_time,
3136                                       new_m->originating_change_time);
3137 }
3138
3139
3140 /*
3141   form a conflict DN
3142  */
3143 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3144 {
3145         const struct ldb_val *rdn_val;
3146         const char *rdn_name;
3147         struct ldb_dn *new_dn;
3148
3149         rdn_val = ldb_dn_get_rdn_val(dn);
3150         rdn_name = ldb_dn_get_rdn_name(dn);
3151         if (!rdn_val || !rdn_name) {
3152                 return NULL;
3153         }
3154
3155         new_dn = ldb_dn_copy(mem_ctx, dn);
3156         if (!new_dn) {
3157                 return NULL;
3158         }
3159
3160         if (!ldb_dn_remove_child_components(new_dn, 1)) {
3161                 return NULL;
3162         }
3163
3164         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3165                                   rdn_name,
3166                                   ldb_dn_escape_value(new_dn, *rdn_val),
3167                                   GUID_string(new_dn, guid))) {
3168                 return NULL;
3169         }
3170
3171         return new_dn;
3172 }
3173
3174
3175 /*
3176   perform a modify operation which sets the rDN and name attributes to
3177   their current values. This has the effect of changing these
3178   attributes to have been last updated by the current DC. This is
3179   needed to ensure that renames performed as part of conflict
3180   resolution are propogated to other DCs
3181  */
3182 static int replmd_name_modify(struct replmd_replicated_request *ar,
3183                               struct ldb_request *req, struct ldb_dn *dn)
3184 {
3185         struct ldb_message *msg;
3186         const char *rdn_name;
3187         const struct ldb_val *rdn_val;
3188         const struct dsdb_attribute *rdn_attr;
3189         int ret;
3190
3191         msg = ldb_msg_new(req);
3192         if (msg == NULL) {
3193                 goto failed;
3194         }
3195         msg->dn = dn;
3196
3197         rdn_name = ldb_dn_get_rdn_name(dn);
3198         if (rdn_name == NULL) {
3199                 goto failed;
3200         }
3201
3202         /* normalize the rdn attribute name */
3203         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3204         if (rdn_attr == NULL) {
3205                 goto failed;
3206         }
3207         rdn_name = rdn_attr->lDAPDisplayName;
3208
3209         rdn_val = ldb_dn_get_rdn_val(dn);
3210         if (rdn_val == NULL) {
3211                 goto failed;
3212         }
3213
3214         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3215                 goto failed;
3216         }
3217         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3218                 goto failed;
3219         }
3220         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3221                 goto failed;
3222         }
3223         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3224                 goto failed;
3225         }
3226
3227         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3228         if (ret != LDB_SUCCESS) {
3229                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3230                          ldb_dn_get_linearized(dn),
3231                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3232                 return ret;
3233         }
3234
3235         talloc_free(msg);
3236
3237         return LDB_SUCCESS;
3238
3239 failed:
3240         talloc_free(msg);
3241         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3242                  ldb_dn_get_linearized(dn)));
3243         return LDB_ERR_OPERATIONS_ERROR;
3244 }
3245
3246
3247 /*
3248   callback for conflict DN handling where we have renamed the incoming
3249   record. After renaming it, we need to ensure the change of name and
3250   rDN for the incoming record is seen as an originating update by this DC.
3251  */
3252 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3253 {
3254         struct replmd_replicated_request *ar =
3255                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3256         int ret;
3257
3258         if (ares->error != LDB_SUCCESS) {
3259                 /* call the normal callback for everything except success */
3260                 return replmd_op_callback(req, ares);
3261         }
3262
3263         /* perform a modify of the rDN and name of the record */
3264         ret = replmd_name_modify(ar, req, req->op.add.message->dn);
3265         if (ret != LDB_SUCCESS) {
3266                 ares->error = ret;
3267                 return replmd_op_callback(req, ares);
3268         }
3269
3270         return replmd_op_callback(req, ares);
3271 }
3272
3273 /*
3274   callback for replmd_replicated_apply_add()
3275   This copes with the creation of conflict records in the case where
3276   the DN exists, but with a different objectGUID
3277  */
3278 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3279 {
3280         struct ldb_dn *conflict_dn;
3281         struct replmd_replicated_request *ar =
3282                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3283         struct ldb_result *res;
3284         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3285         int ret;
3286         const struct ldb_val *rmd_value, *omd_value;
3287         struct replPropertyMetaDataBlob omd, rmd;
3288         enum ndr_err_code ndr_err;
3289         bool rename_incoming_record;
3290         struct replPropertyMetaData1 *rmd_name, *omd_name;
3291
3292         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3293                 /* call the normal callback for everything except
3294                    conflicts */
3295                 return replmd_op_callback(req, ares);
3296         }
3297
3298         /*
3299          * we have a conflict, and need to decide if we will keep the
3300          * new record or the old record
3301          */
3302         conflict_dn = req->op.add.message->dn;
3303
3304         /*
3305          * first we need the replPropertyMetaData attribute from the
3306          * old record
3307          */
3308         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3309                                     attrs,
3310                                     DSDB_FLAG_NEXT_MODULE |
3311                                     DSDB_SEARCH_SHOW_DELETED |
3312                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3313         if (ret != LDB_SUCCESS) {
3314                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3315                          ldb_dn_get_linearized(conflict_dn)));
3316                 goto failed;
3317         }
3318
3319         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3320         if (omd_value == NULL) {
3321                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3322                          ldb_dn_get_linearized(conflict_dn)));
3323                 goto failed;
3324         }
3325
3326         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3327                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3328         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3329                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3330                          ldb_dn_get_linearized(conflict_dn)));
3331                 goto failed;
3332         }
3333
3334         /*
3335          * and the replPropertyMetaData attribute from the
3336          * new record
3337          */
3338         rmd_value = ldb_msg_find_ldb_val(req->op.add.message, "replPropertyMetaData");
3339         if (rmd_value == NULL) {
3340                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for new record '%s'\n",
3341                          ldb_dn_get_linearized(conflict_dn)));
3342                 goto failed;
3343         }
3344
3345         ndr_err = ndr_pull_struct_blob(rmd_value, req, &rmd,
3346                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3347         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3348                 DEBUG(0,(__location__ ": Failed to parse new replPropertyMetaData for %s\n",
3349                          ldb_dn_get_linearized(conflict_dn)));
3350                 goto failed;
3351         }
3352
3353         /* we decide which is newer based on the RPMD on the name
3354            attribute.  See [MS-DRSR] ResolveNameConflict */
3355         rmd_name = replmd_replPropertyMetaData1_find_attid(&rmd, DRSUAPI_ATTID_name);