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