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