s4-dsdb: fix a warning about unused variable
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / repl_meta_data.c
1 /*
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
6    Copyright (C) Andrew Tridgell 2005
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8    Copyright (C) Matthieu Patou <mat@samba.org> 2010
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb repl_meta_data module
28  *
29  *  Description: - add a unique objectGUID onto every new record,
30  *               - handle whenCreated, whenChanged timestamps
31  *               - handle uSNCreated, uSNChanged numbers
32  *               - handle replPropertyMetaData attribute
33  *
34  *  Author: Simo Sorce
35  *  Author: Stefan Metzmacher
36  */
37
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "../libds/common/flags.h"
43 #include "librpc/gen_ndr/ndr_misc.h"
44 #include "librpc/gen_ndr/ndr_drsuapi.h"
45 #include "librpc/gen_ndr/ndr_drsblobs.h"
46 #include "param/param.h"
47 #include "libcli/security/security.h"
48 #include "lib/util/dlinklist.h"
49 #include "dsdb/samdb/ldb_modules/util.h"
50 #include "lib/util/binsearch.h"
51 #include "lib/util/tsort.h"
52
53 /*
54  * It's 29/12/9999 at 23:59:59 UTC as specified in MS-ADTS 7.1.1.4.2
55  * Deleted Objects Container
56  */
57 static const NTTIME DELETED_OBJECT_CONTAINER_CHANGE_TIME = 2650466015990000000ULL;
58
59 struct replmd_private {
60         TALLOC_CTX *la_ctx;
61         struct la_entry *la_list;
62         TALLOC_CTX *bl_ctx;
63         struct la_backlink *la_backlinks;
64         struct nc_entry {
65                 struct nc_entry *prev, *next;
66                 struct ldb_dn *dn;
67                 uint64_t mod_usn;
68                 uint64_t mod_usn_urgent;
69         } *ncs;
70 };
71
72 struct la_entry {
73         struct la_entry *next, *prev;
74         struct drsuapi_DsReplicaLinkedAttribute *la;
75 };
76
77 struct replmd_replicated_request {
78         struct ldb_module *module;
79         struct ldb_request *req;
80
81         const struct dsdb_schema *schema;
82
83         /* the controls we pass down */
84         struct ldb_control **controls;
85
86         /* details for the mode where we apply a bunch of inbound replication meessages */
87         bool apply_mode;
88         uint32_t index_current;
89         struct dsdb_extended_replicated_objects *objs;
90
91         struct ldb_message *search_msg;
92
93         uint64_t seq_num;
94         bool is_urgent;
95 };
96
97 enum urgent_situation {
98         REPL_URGENT_ON_CREATE = 1,
99         REPL_URGENT_ON_UPDATE = 2,
100         REPL_URGENT_ON_DELETE = 4
101 };
102
103
104 static const struct {
105         const char *update_name;
106         enum urgent_situation repl_situation;
107 } urgent_objects[] = {
108                 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
109                 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
110                 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
111                 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
112                 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
113                 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
114                 {NULL, 0}
115 };
116
117 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
118 static const char *urgent_attrs[] = {
119                 "lockoutTime",
120                 "pwdLastSet",
121                 "userAccountControl",
122                 NULL
123 };
124
125
126 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
127                                         enum urgent_situation situation)
128 {
129         unsigned int i, j;
130         for (i=0; urgent_objects[i].update_name; i++) {
131
132                 if ((situation & urgent_objects[i].repl_situation) == 0) {
133                         continue;
134                 }
135
136                 for (j=0; j<objectclass_el->num_values; j++) {
137                         const struct ldb_val *v = &objectclass_el->values[j];
138                         if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
139                                 return true;
140                         }
141                 }
142         }
143         return false;
144 }
145
146 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
147 {
148         if (ldb_attr_in_list(urgent_attrs, el->name)) {
149                 return true;
150         }
151         return false;
152 }
153
154
155 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar);
156
157 /*
158   initialise the module
159   allocate the private structure and build the list
160   of partition DNs for use by replmd_notify()
161  */
162 static int replmd_init(struct ldb_module *module)
163 {
164         struct replmd_private *replmd_private;
165         struct ldb_context *ldb = ldb_module_get_ctx(module);
166
167         replmd_private = talloc_zero(module, struct replmd_private);
168         if (replmd_private == NULL) {
169                 ldb_oom(ldb);
170                 return LDB_ERR_OPERATIONS_ERROR;
171         }
172         ldb_module_set_private(module, replmd_private);
173
174         return ldb_next_init(module);
175 }
176
177 /*
178   cleanup our per-transaction contexts
179  */
180 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
181 {
182         talloc_free(replmd_private->la_ctx);
183         replmd_private->la_list = NULL;
184         replmd_private->la_ctx = NULL;
185
186         talloc_free(replmd_private->bl_ctx);
187         replmd_private->la_backlinks = NULL;
188         replmd_private->bl_ctx = NULL;
189 }
190
191
192 struct la_backlink {
193         struct la_backlink *next, *prev;
194         const char *attr_name;
195         struct GUID forward_guid, target_guid;
196         bool active;
197 };
198
199 /*
200   process a backlinks we accumulated during a transaction, adding and
201   deleting the backlinks from the target objects
202  */
203 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
204 {
205         struct ldb_dn *target_dn, *source_dn;
206         int ret;
207         struct ldb_context *ldb = ldb_module_get_ctx(module);
208         struct ldb_message *msg;
209         TALLOC_CTX *tmp_ctx = talloc_new(bl);
210         char *dn_string;
211
212         /*
213           - find DN of target
214           - find DN of source
215           - construct ldb_message
216               - either an add or a delete
217          */
218         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
219         if (ret != LDB_SUCCESS) {
220                 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
221                          GUID_string(bl, &bl->target_guid)));
222                 return LDB_SUCCESS;
223         }
224
225         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
226         if (ret != LDB_SUCCESS) {
227                 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
228                                        GUID_string(bl, &bl->forward_guid));
229                 talloc_free(tmp_ctx);
230                 return ret;
231         }
232
233         msg = ldb_msg_new(tmp_ctx);
234         if (msg == NULL) {
235                 ldb_module_oom(module);
236                 talloc_free(tmp_ctx);
237                 return LDB_ERR_OPERATIONS_ERROR;
238         }
239
240         /* construct a ldb_message for adding/deleting the backlink */
241         msg->dn = target_dn;
242         dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
243         if (!dn_string) {
244                 ldb_module_oom(module);
245                 talloc_free(tmp_ctx);
246                 return LDB_ERR_OPERATIONS_ERROR;
247         }
248         ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
249         if (ret != LDB_SUCCESS) {
250                 talloc_free(tmp_ctx);
251                 return ret;
252         }
253         msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
254
255         /* a backlink should never be single valued. Unfortunately the
256            exchange schema has a attribute
257            msExchBridgeheadedLocalConnectorsDNBL which is single
258            valued and a backlink. We need to cope with that by
259            ignoring the single value flag */
260         msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
261
262         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
263         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
264                 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
265                    cope with possible corruption where the backlink has
266                    already been removed */
267                 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
268                          ldb_dn_get_linearized(target_dn),
269                          ldb_dn_get_linearized(source_dn),
270                          ldb_errstring(ldb)));
271                 ret = LDB_SUCCESS;
272         } else if (ret != LDB_SUCCESS) {
273                 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
274                                        bl->active?"add":"remove",
275                                        ldb_dn_get_linearized(source_dn),
276                                        ldb_dn_get_linearized(target_dn),
277                                        ldb_errstring(ldb));
278                 talloc_free(tmp_ctx);
279                 return ret;
280         }
281         talloc_free(tmp_ctx);
282         return ret;
283 }
284
285 /*
286   add a backlink to the list of backlinks to add/delete in the prepare
287   commit
288  */
289 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
290                                struct GUID *forward_guid, struct GUID *target_guid,
291                                bool active, const struct dsdb_attribute *schema_attr, bool immediate)
292 {
293         const struct dsdb_attribute *target_attr;
294         struct la_backlink *bl;
295         struct replmd_private *replmd_private =
296                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
297
298         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
299         if (!target_attr) {
300                 /*
301                  * windows 2003 has a broken schema where the
302                  * definition of msDS-IsDomainFor is missing (which is
303                  * supposed to be the backlink of the
304                  * msDS-HasDomainNCs attribute
305                  */
306                 return LDB_SUCCESS;
307         }
308
309         /* see if its already in the list */
310         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
311                 if (GUID_equal(forward_guid, &bl->forward_guid) &&
312                     GUID_equal(target_guid, &bl->target_guid) &&
313                     (target_attr->lDAPDisplayName == bl->attr_name ||
314                      strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
315                         break;
316                 }
317         }
318
319         if (bl) {
320                 /* we found an existing one */
321                 if (bl->active == active) {
322                         return LDB_SUCCESS;
323                 }
324                 DLIST_REMOVE(replmd_private->la_backlinks, bl);
325                 talloc_free(bl);
326                 return LDB_SUCCESS;
327         }
328
329         if (replmd_private->bl_ctx == NULL) {
330                 replmd_private->bl_ctx = talloc_new(replmd_private);
331                 if (replmd_private->bl_ctx == NULL) {
332                         ldb_module_oom(module);
333                         return LDB_ERR_OPERATIONS_ERROR;
334                 }
335         }
336
337         /* its a new one */
338         bl = talloc(replmd_private->bl_ctx, struct la_backlink);
339         if (bl == NULL) {
340                 ldb_module_oom(module);
341                 return LDB_ERR_OPERATIONS_ERROR;
342         }
343
344         /* Ensure the schema does not go away before the bl->attr_name is used */
345         if (!talloc_reference(bl, schema)) {
346                 talloc_free(bl);
347                 ldb_module_oom(module);
348                 return LDB_ERR_OPERATIONS_ERROR;
349         }
350
351         bl->attr_name = target_attr->lDAPDisplayName;
352         bl->forward_guid = *forward_guid;
353         bl->target_guid = *target_guid;
354         bl->active = active;
355
356         /* the caller may ask for this backlink to be processed
357            immediately */
358         if (immediate) {
359                 int ret = replmd_process_backlink(module, bl, NULL);
360                 talloc_free(bl);
361                 return ret;
362         }
363
364         DLIST_ADD(replmd_private->la_backlinks, bl);
365
366         return LDB_SUCCESS;
367 }
368
369
370 /*
371  * Callback for most write operations in this module:
372  *
373  * notify the repl task that a object has changed. The notifies are
374  * gathered up in the replmd_private structure then written to the
375  * @REPLCHANGED object in each partition during the prepare_commit
376  */
377 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
378 {
379         int ret;
380         struct replmd_replicated_request *ac =
381                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
382         struct replmd_private *replmd_private =
383                 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
384         struct nc_entry *modified_partition;
385         struct ldb_control *partition_ctrl;
386         const struct dsdb_control_current_partition *partition;
387
388         struct ldb_control **controls;
389
390         partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
391
392         controls = ares->controls;
393         if (ldb_request_get_control(ac->req,
394                                     DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
395                 /*
396                  * Remove the current partition control from what we pass up
397                  * the chain if it hasn't been requested manually.
398                  */
399                 controls = ldb_controls_except_specified(ares->controls, ares,
400                                                          partition_ctrl);
401         }
402
403         if (ares->error != LDB_SUCCESS) {
404                 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
405                 return ldb_module_done(ac->req, controls,
406                                         ares->response, ares->error);
407         }
408
409         if (ares->type != LDB_REPLY_DONE) {
410                 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
411                 return ldb_module_done(ac->req, NULL,
412                                        NULL, LDB_ERR_OPERATIONS_ERROR);
413         }
414
415         if (!partition_ctrl) {
416                 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
417                 return ldb_module_done(ac->req, NULL,
418                                        NULL, LDB_ERR_OPERATIONS_ERROR);
419         }
420
421         partition = talloc_get_type_abort(partition_ctrl->data,
422                                     struct dsdb_control_current_partition);
423
424         if (ac->seq_num > 0) {
425                 for (modified_partition = replmd_private->ncs; modified_partition;
426                      modified_partition = modified_partition->next) {
427                         if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
428                                 break;
429                         }
430                 }
431
432                 if (modified_partition == NULL) {
433                         modified_partition = talloc_zero(replmd_private, struct nc_entry);
434                         if (!modified_partition) {
435                                 ldb_oom(ldb_module_get_ctx(ac->module));
436                                 return ldb_module_done(ac->req, NULL,
437                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
438                         }
439                         modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
440                         if (!modified_partition->dn) {
441                                 ldb_oom(ldb_module_get_ctx(ac->module));
442                                 return ldb_module_done(ac->req, NULL,
443                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
444                         }
445                         DLIST_ADD(replmd_private->ncs, modified_partition);
446                 }
447
448                 if (ac->seq_num > modified_partition->mod_usn) {
449                         modified_partition->mod_usn = ac->seq_num;
450                         if (ac->is_urgent) {
451                                 modified_partition->mod_usn_urgent = ac->seq_num;
452                         }
453                 }
454         }
455
456         if (ac->apply_mode) {
457                 talloc_free(ares);
458                 ac->index_current++;
459
460                 ret = replmd_replicated_apply_next(ac);
461                 if (ret != LDB_SUCCESS) {
462                         return ldb_module_done(ac->req, NULL, NULL, ret);
463                 }
464                 return ret;
465         } else {
466                 /* free the partition control container here, for the
467                  * common path.  Other cases will have it cleaned up
468                  * eventually with the ares */
469                 talloc_free(partition_ctrl);
470                 return ldb_module_done(ac->req, controls,
471                                        ares->response, LDB_SUCCESS);
472         }
473 }
474
475
476 /*
477  * update a @REPLCHANGED record in each partition if there have been
478  * any writes of replicated data in the partition
479  */
480 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
481 {
482         struct replmd_private *replmd_private =
483                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
484
485         while (replmd_private->ncs) {
486                 int ret;
487                 struct nc_entry *modified_partition = replmd_private->ncs;
488
489                 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
490                                                      modified_partition->mod_usn,
491                                                      modified_partition->mod_usn_urgent, parent);
492                 if (ret != LDB_SUCCESS) {
493                         DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
494                                  ldb_dn_get_linearized(modified_partition->dn)));
495                         return ret;
496                 }
497                 DLIST_REMOVE(replmd_private->ncs, modified_partition);
498                 talloc_free(modified_partition);
499         }
500
501         return LDB_SUCCESS;
502 }
503
504
505 /*
506   created a replmd_replicated_request context
507  */
508 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
509                                                          struct ldb_request *req)
510 {
511         struct ldb_context *ldb;
512         struct replmd_replicated_request *ac;
513
514         ldb = ldb_module_get_ctx(module);
515
516         ac = talloc_zero(req, struct replmd_replicated_request);
517         if (ac == NULL) {
518                 ldb_oom(ldb);
519                 return NULL;
520         }
521
522         ac->module = module;
523         ac->req = req;
524
525         ac->schema = dsdb_get_schema(ldb, ac);
526         if (!ac->schema) {
527                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
528                               "replmd_modify: no dsdb_schema loaded");
529                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
530                 return NULL;
531         }
532
533         return ac;
534 }
535
536 /*
537   add a time element to a record
538 */
539 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
540 {
541         struct ldb_message_element *el;
542         char *s;
543         int ret;
544
545         if (ldb_msg_find_element(msg, attr) != NULL) {
546                 return LDB_SUCCESS;
547         }
548
549         s = ldb_timestring(msg, t);
550         if (s == NULL) {
551                 return LDB_ERR_OPERATIONS_ERROR;
552         }
553
554         ret = ldb_msg_add_string(msg, attr, s);
555         if (ret != LDB_SUCCESS) {
556                 return ret;
557         }
558
559         el = ldb_msg_find_element(msg, attr);
560         /* always set as replace. This works because on add ops, the flag
561            is ignored */
562         el->flags = LDB_FLAG_MOD_REPLACE;
563
564         return LDB_SUCCESS;
565 }
566
567 /*
568   add a uint64_t element to a record
569 */
570 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
571                               const char *attr, uint64_t v)
572 {
573         struct ldb_message_element *el;
574         int ret;
575
576         if (ldb_msg_find_element(msg, attr) != NULL) {
577                 return LDB_SUCCESS;
578         }
579
580         ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
581         if (ret != LDB_SUCCESS) {
582                 return ret;
583         }
584
585         el = ldb_msg_find_element(msg, attr);
586         /* always set as replace. This works because on add ops, the flag
587            is ignored */
588         el->flags = LDB_FLAG_MOD_REPLACE;
589
590         return LDB_SUCCESS;
591 }
592
593 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
594                                                    const struct replPropertyMetaData1 *m2,
595                                                    const uint32_t *rdn_attid)
596 {
597         if (m1->attid == m2->attid) {
598                 return 0;
599         }
600
601         /*
602          * the rdn attribute should be at the end!
603          * so we need to return a value greater than zero
604          * which means m1 is greater than m2
605          */
606         if (m1->attid == *rdn_attid) {
607                 return 1;
608         }
609
610         /*
611          * the rdn attribute should be at the end!
612          * so we need to return a value less than zero
613          * which means m2 is greater than m1
614          */
615         if (m2->attid == *rdn_attid) {
616                 return -1;
617         }
618
619         return m1->attid > m2->attid ? 1 : -1;
620 }
621
622 static int replmd_replPropertyMetaDataCtr1_sort(struct replPropertyMetaDataCtr1 *ctr1,
623                                                 const struct dsdb_schema *schema,
624                                                 struct ldb_dn *dn)
625 {
626         const char *rdn_name;
627         const struct dsdb_attribute *rdn_sa;
628
629         rdn_name = ldb_dn_get_rdn_name(dn);
630         if (!rdn_name) {
631                 DEBUG(0,(__location__ ": No rDN for %s?\n", ldb_dn_get_linearized(dn)));
632                 return LDB_ERR_OPERATIONS_ERROR;
633         }
634
635         rdn_sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
636         if (rdn_sa == NULL) {
637                 DEBUG(0,(__location__ ": No sa found for rDN %s for %s\n", rdn_name, ldb_dn_get_linearized(dn)));
638                 return LDB_ERR_OPERATIONS_ERROR;
639         }
640
641         DEBUG(6,("Sorting rpmd with attid exception %u rDN=%s DN=%s\n",
642                  rdn_sa->attributeID_id, rdn_name, ldb_dn_get_linearized(dn)));
643
644         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, &rdn_sa->attributeID_id, replmd_replPropertyMetaData1_attid_sort);
645
646         return LDB_SUCCESS;
647 }
648
649 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
650                                                  const struct ldb_message_element *e2,
651                                                  const struct dsdb_schema *schema)
652 {
653         const struct dsdb_attribute *a1;
654         const struct dsdb_attribute *a2;
655
656         /*
657          * TODO: make this faster by caching the dsdb_attribute pointer
658          *       on the ldb_messag_element
659          */
660
661         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
662         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
663
664         /*
665          * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
666          *       in the schema
667          */
668         if (!a1 || !a2) {
669                 return strcasecmp(e1->name, e2->name);
670         }
671         if (a1->attributeID_id == a2->attributeID_id) {
672                 return 0;
673         }
674         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
675 }
676
677 static void replmd_ldb_message_sort(struct ldb_message *msg,
678                                     const struct dsdb_schema *schema)
679 {
680         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
681 }
682
683 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
684                                const struct GUID *invocation_id, uint64_t seq_num,
685                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
686
687
688 /*
689   fix up linked attributes in replmd_add.
690   This involves setting up the right meta-data in extended DN
691   components, and creating backlinks to the object
692  */
693 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
694                              uint64_t seq_num, const struct GUID *invocationId, time_t t,
695                              struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
696 {
697         unsigned int i;
698         TALLOC_CTX *tmp_ctx = talloc_new(el->values);
699         struct ldb_context *ldb = ldb_module_get_ctx(module);
700
701         /* We will take a reference to the schema in replmd_add_backlink */
702         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
703         NTTIME now;
704
705         unix_to_nt_time(&now, t);
706
707         for (i=0; i<el->num_values; i++) {
708                 struct ldb_val *v = &el->values[i];
709                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
710                 struct GUID target_guid;
711                 NTSTATUS status;
712                 int ret;
713
714                 /* note that the DN already has the extended
715                    components from the extended_dn_store module */
716                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
717                 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
718                         ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
719                         if (ret != LDB_SUCCESS) {
720                                 talloc_free(tmp_ctx);
721                                 return ret;
722                         }
723                         ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
724                         if (ret != LDB_SUCCESS) {
725                                 talloc_free(tmp_ctx);
726                                 return ret;
727                         }
728                 }
729
730                 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
731                                           seq_num, seq_num, now, 0, false);
732                 if (ret != LDB_SUCCESS) {
733                         talloc_free(tmp_ctx);
734                         return ret;
735                 }
736
737                 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
738                 if (ret != LDB_SUCCESS) {
739                         talloc_free(tmp_ctx);
740                         return ret;
741                 }
742         }
743
744         talloc_free(tmp_ctx);
745         return LDB_SUCCESS;
746 }
747
748
749 /*
750   intercept add requests
751  */
752 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
753 {
754         struct 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
2794         if (ldb_dn_is_special(req->op.del.dn)) {
2795                 return ldb_next_request(module, req);
2796         }
2797
2798         tmp_ctx = talloc_new(ldb);
2799         if (!tmp_ctx) {
2800                 ldb_oom(ldb);
2801                 return LDB_ERR_OPERATIONS_ERROR;
2802         }
2803
2804         schema = dsdb_get_schema(ldb, tmp_ctx);
2805         if (!schema) {
2806                 return LDB_ERR_OPERATIONS_ERROR;
2807         }
2808
2809         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
2810
2811         /* we need the complete msg off disk, so we can work out which
2812            attributes need to be removed */
2813         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
2814                                     DSDB_FLAG_NEXT_MODULE |
2815                                     DSDB_SEARCH_SHOW_RECYCLED |
2816                                     DSDB_SEARCH_REVEAL_INTERNALS |
2817                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
2818         if (ret != LDB_SUCCESS) {
2819                 talloc_free(tmp_ctx);
2820                 return ret;
2821         }
2822         old_msg = res->msgs[0];
2823
2824
2825         ret = dsdb_recyclebin_enabled(module, &enabled);
2826         if (ret != LDB_SUCCESS) {
2827                 talloc_free(tmp_ctx);
2828                 return ret;
2829         }
2830
2831         if (ldb_msg_check_string_attribute(old_msg, "isDeleted", "TRUE")) {
2832                 if (!enabled) {
2833                         deletion_state = OBJECT_TOMBSTONE;
2834                         next_deletion_state = OBJECT_REMOVED;
2835                 } else if (ldb_msg_check_string_attribute(old_msg, "isRecycled", "TRUE")) {
2836                         deletion_state = OBJECT_RECYCLED;
2837                         next_deletion_state = OBJECT_REMOVED;
2838                 } else {
2839                         deletion_state = OBJECT_DELETED;
2840                         next_deletion_state = OBJECT_RECYCLED;
2841                 }
2842         } else {
2843                 deletion_state = OBJECT_NOT_DELETED;
2844                 if (enabled) {
2845                         next_deletion_state = OBJECT_DELETED;
2846                 } else {
2847                         next_deletion_state = OBJECT_TOMBSTONE;
2848                 }
2849         }
2850
2851         if (next_deletion_state == OBJECT_REMOVED) {
2852                 struct auth_session_info *session_info =
2853                                 (struct auth_session_info *)ldb_get_opaque(ldb, "sessionInfo");
2854                 if (security_session_user_level(session_info, NULL) != SECURITY_SYSTEM) {
2855                         ldb_asprintf_errstring(ldb, "Refusing to delete deleted object %s",
2856                                         ldb_dn_get_linearized(old_msg->dn));
2857                         return LDB_ERR_UNWILLING_TO_PERFORM;
2858                 }
2859
2860                 /* it is already deleted - really remove it this time */
2861                 talloc_free(tmp_ctx);
2862                 return ldb_next_request(module, req);
2863         }
2864
2865         rdn_name = ldb_dn_get_rdn_name(old_dn);
2866         rdn_value = ldb_dn_get_rdn_val(old_dn);
2867         if ((rdn_name == NULL) || (rdn_value == NULL)) {
2868                 talloc_free(tmp_ctx);
2869                 return ldb_operr(ldb);
2870         }
2871
2872         msg = ldb_msg_new(tmp_ctx);
2873         if (msg == NULL) {
2874                 ldb_module_oom(module);
2875                 talloc_free(tmp_ctx);
2876                 return LDB_ERR_OPERATIONS_ERROR;
2877         }
2878
2879         msg->dn = old_dn;
2880
2881         if (deletion_state == OBJECT_NOT_DELETED){
2882                 /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
2883                 disallow_move_on_delete =
2884                         (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
2885                                 & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
2886
2887                 /* work out where we will be renaming this object to */
2888                 if (!disallow_move_on_delete) {
2889                         ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
2890                                                           &new_dn);
2891                         if (ret != LDB_SUCCESS) {
2892                                 /* this is probably an attempted delete on a partition
2893                                  * that doesn't allow delete operations, such as the
2894                                  * schema partition */
2895                                 ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
2896                                                            ldb_dn_get_linearized(old_dn));
2897                                 talloc_free(tmp_ctx);
2898                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2899                         }
2900                 } else {
2901                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
2902                         if (new_dn == NULL) {
2903                                 ldb_module_oom(module);
2904                                 talloc_free(tmp_ctx);
2905                                 return LDB_ERR_OPERATIONS_ERROR;
2906                         }
2907                 }
2908
2909                 /* get the objects GUID from the search we just did */
2910                 guid = samdb_result_guid(old_msg, "objectGUID");
2911
2912                 /* Add a formatted child */
2913                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
2914                                                 rdn_name,
2915                                                 ldb_dn_escape_value(tmp_ctx, *rdn_value),
2916                                                 GUID_string(tmp_ctx, &guid));
2917                 if (!retb) {
2918                         DEBUG(0,(__location__ ": Unable to add a formatted child to dn: %s",
2919                                         ldb_dn_get_linearized(new_dn)));
2920                         talloc_free(tmp_ctx);
2921                         return LDB_ERR_OPERATIONS_ERROR;
2922                 }
2923
2924                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
2925                 if (ret != LDB_SUCCESS) {
2926                         DEBUG(0,(__location__ ": Failed to add isDeleted string to the msg\n"));
2927                         ldb_module_oom(module);
2928                         talloc_free(tmp_ctx);
2929                         return ret;
2930                 }
2931                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
2932         }
2933
2934         /*
2935           now we need to modify the object in the following ways:
2936
2937           - add isDeleted=TRUE
2938           - update rDN and name, with new rDN
2939           - remove linked attributes
2940           - remove objectCategory and sAMAccountType
2941           - remove attribs not on the preserved list
2942              - preserved if in above list, or is rDN
2943           - remove all linked attribs from this object
2944           - remove all links from other objects to this object
2945           - add lastKnownParent
2946           - update replPropertyMetaData?
2947
2948           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
2949          */
2950
2951         /* we need the storage form of the parent GUID */
2952         ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
2953                                     ldb_dn_get_parent(tmp_ctx, old_dn), NULL,
2954                                     DSDB_FLAG_NEXT_MODULE |
2955                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
2956                                     DSDB_SEARCH_REVEAL_INTERNALS|
2957                                     DSDB_SEARCH_SHOW_RECYCLED, req);
2958         if (ret != LDB_SUCCESS) {
2959                 talloc_free(tmp_ctx);
2960                 return ret;
2961         }
2962
2963         if (deletion_state == OBJECT_NOT_DELETED){
2964                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
2965                                                    ldb_dn_get_extended_linearized(tmp_ctx, parent_res->msgs[0]->dn, 1));
2966                 if (ret != LDB_SUCCESS) {
2967                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
2968                         ldb_module_oom(module);
2969                         talloc_free(tmp_ctx);
2970                         return ret;
2971                 }
2972                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2973         }
2974
2975         switch (next_deletion_state){
2976
2977         case OBJECT_DELETED:
2978
2979                 ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
2980                 if (ret != LDB_SUCCESS) {
2981                         DEBUG(0,(__location__ ": Failed to add msDS-LastKnownRDN string to the msg\n"));
2982                         ldb_module_oom(module);
2983                         talloc_free(tmp_ctx);
2984                         return ret;
2985                 }
2986                 msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
2987
2988                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
2989                 if (ret != LDB_SUCCESS) {
2990                         talloc_free(tmp_ctx);
2991                         ldb_module_oom(module);
2992                         return ret;
2993                 }
2994
2995                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
2996                 if (ret != LDB_SUCCESS) {
2997                         talloc_free(tmp_ctx);
2998                         ldb_module_oom(module);
2999                         return ret;
3000                 }
3001
3002                 break;
3003
3004         case OBJECT_RECYCLED:
3005         case OBJECT_TOMBSTONE:
3006
3007                 /*
3008                  * we also mark it as recycled, meaning this object can't be
3009                  * recovered (we are stripping its attributes).
3010                  * This is done only if we have this schema object of course ...
3011                  * This behavior is identical to the one of Windows 2008R2 which
3012                  * always set the isRecycled attribute, even if the recycle-bin is
3013                  * not activated and what ever the forest level is.
3014                  */
3015                 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3016                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3017                         if (ret != LDB_SUCCESS) {
3018                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3019                                 ldb_module_oom(module);
3020                                 talloc_free(tmp_ctx);
3021                                 return ret;
3022                         }
3023                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3024                 }
3025
3026                 /* work out which of the old attributes we will be removing */
3027                 for (i=0; i<old_msg->num_elements; i++) {
3028                         const struct dsdb_attribute *sa;
3029                         el = &old_msg->elements[i];
3030                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3031                         if (!sa) {
3032                                 talloc_free(tmp_ctx);
3033                                 return LDB_ERR_OPERATIONS_ERROR;
3034                         }
3035                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3036                                 /* don't remove the rDN */
3037                                 continue;
3038                         }
3039                         if (sa->linkID && (sa->linkID & 1)) {
3040                                 /*
3041                                   we have a backlink in this object
3042                                   that needs to be removed. We're not
3043                                   allowed to remove it directly
3044                                   however, so we instead setup a
3045                                   modify to delete the corresponding
3046                                   forward link
3047                                  */
3048                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3049                                 if (ret != LDB_SUCCESS) {
3050                                         talloc_free(tmp_ctx);
3051                                         return LDB_ERR_OPERATIONS_ERROR;
3052                                 }
3053                                 /* now we continue, which means we
3054                                    won't remove this backlink
3055                                    directly
3056                                 */
3057                                 continue;
3058                         }
3059                         if (!sa->linkID && ldb_attr_in_list(preserved_attrs, el->name)) {
3060                                 continue;
3061                         }
3062                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3063                         if (ret != LDB_SUCCESS) {
3064                                 talloc_free(tmp_ctx);
3065                                 ldb_module_oom(module);
3066                                 return ret;
3067                         }
3068                 }
3069                 break;
3070
3071         default:
3072                 break;
3073         }
3074
3075         if (deletion_state == OBJECT_NOT_DELETED) {
3076                 const struct dsdb_attribute *sa;
3077
3078                 /* work out what the new rdn value is, for updating the
3079                    rDN and name fields */
3080                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3081                 if (new_rdn_value == NULL) {
3082                         talloc_free(tmp_ctx);
3083                         return ldb_operr(ldb);
3084                 }
3085
3086                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3087                 if (!sa) {
3088                         talloc_free(tmp_ctx);
3089                         return LDB_ERR_OPERATIONS_ERROR;
3090                 }
3091
3092                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3093                                         &el);
3094                 if (ret != LDB_SUCCESS) {
3095                         talloc_free(tmp_ctx);
3096                         return ret;
3097                 }
3098                 el->flags = LDB_FLAG_MOD_REPLACE;
3099
3100                 el = ldb_msg_find_element(old_msg, "name");
3101                 if (el) {
3102                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3103                         if (ret != LDB_SUCCESS) {
3104                                 talloc_free(tmp_ctx);
3105                                 return ret;
3106                         }
3107                         el->flags = LDB_FLAG_MOD_REPLACE;
3108                 }
3109         }
3110
3111         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3112         if (ret != LDB_SUCCESS) {
3113                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3114                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3115                 talloc_free(tmp_ctx);
3116                 return ret;
3117         }
3118
3119         if (deletion_state == OBJECT_NOT_DELETED) {
3120                 /* now rename onto the new DN */
3121                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3122                 if (ret != LDB_SUCCESS){
3123                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3124                                  ldb_dn_get_linearized(old_dn),
3125                                  ldb_dn_get_linearized(new_dn),
3126                                  ldb_errstring(ldb)));
3127                         talloc_free(tmp_ctx);
3128                         return ret;
3129                 }
3130         }
3131
3132         talloc_free(tmp_ctx);
3133
3134         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3135 }
3136
3137
3138
3139 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3140 {
3141         return ret;
3142 }
3143
3144 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3145 {
3146         int ret = LDB_ERR_OTHER;
3147         /* TODO: do some error mapping */
3148         return ret;
3149 }
3150
3151
3152 static struct replPropertyMetaData1 *
3153 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3154                                         enum drsuapi_DsAttributeId attid)
3155 {
3156         uint32_t i;
3157         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3158
3159         for (i = 0; i < rpmd_ctr->count; i++) {
3160                 if (rpmd_ctr->array[i].attid == attid) {
3161                         return &rpmd_ctr->array[i];
3162                 }
3163         }
3164         return NULL;
3165 }
3166
3167
3168 /*
3169    return true if an update is newer than an existing entry
3170    see section 5.11 of MS-ADTS
3171 */
3172 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3173                                    const struct GUID *update_invocation_id,
3174                                    uint32_t current_version,
3175                                    uint32_t update_version,
3176                                    NTTIME current_change_time,
3177                                    NTTIME update_change_time)
3178 {
3179         if (update_version != current_version) {
3180                 return update_version > current_version;
3181         }
3182         if (update_change_time != current_change_time) {
3183                 return update_change_time > current_change_time;
3184         }
3185         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3186 }
3187
3188 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3189                                                   struct replPropertyMetaData1 *new_m)
3190 {
3191         return replmd_update_is_newer(&cur_m->originating_invocation_id,
3192                                       &new_m->originating_invocation_id,
3193                                       cur_m->version,
3194                                       new_m->version,
3195                                       cur_m->originating_change_time,
3196                                       new_m->originating_change_time);
3197 }
3198
3199
3200 /*
3201   form a conflict DN
3202  */
3203 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3204 {
3205         const struct ldb_val *rdn_val;
3206         const char *rdn_name;
3207         struct ldb_dn *new_dn;
3208
3209         rdn_val = ldb_dn_get_rdn_val(dn);
3210         rdn_name = ldb_dn_get_rdn_name(dn);
3211         if (!rdn_val || !rdn_name) {
3212                 return NULL;
3213         }
3214
3215         new_dn = ldb_dn_copy(mem_ctx, dn);
3216         if (!new_dn) {
3217                 return NULL;
3218         }
3219
3220         if (!ldb_dn_remove_child_components(new_dn, 1)) {
3221                 return NULL;
3222         }
3223
3224         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3225                                   rdn_name,
3226                                   ldb_dn_escape_value(new_dn, *rdn_val),
3227                                   GUID_string(new_dn, guid))) {
3228                 return NULL;
3229         }
3230
3231         return new_dn;
3232 }
3233
3234
3235 /*
3236   perform a modify operation which sets the rDN and name attributes to
3237   their current values. This has the effect of changing these
3238   attributes to have been last updated by the current DC. This is
3239   needed to ensure that renames performed as part of conflict
3240   resolution are propogated to other DCs
3241  */
3242 static int replmd_name_modify(struct replmd_replicated_request *ar,
3243                               struct ldb_request *req, struct ldb_dn *dn)
3244 {
3245         struct ldb_message *msg;
3246         const char *rdn_name;
3247         const struct ldb_val *rdn_val;
3248         const struct dsdb_attribute *rdn_attr;
3249         int ret;
3250
3251         msg = ldb_msg_new(req);
3252         if (msg == NULL) {
3253                 goto failed;
3254         }
3255         msg->dn = dn;
3256
3257         rdn_name = ldb_dn_get_rdn_name(dn);
3258         if (rdn_name == NULL) {
3259                 goto failed;
3260         }
3261
3262         /* normalize the rdn attribute name */
3263         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3264         if (rdn_attr == NULL) {
3265                 goto failed;
3266         }
3267         rdn_name = rdn_attr->lDAPDisplayName;
3268
3269         rdn_val = ldb_dn_get_rdn_val(dn);
3270         if (rdn_val == NULL) {
3271                 goto failed;
3272         }
3273
3274         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3275                 goto failed;
3276         }
3277         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3278                 goto failed;
3279         }
3280         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3281                 goto failed;
3282         }
3283         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3284                 goto failed;
3285         }
3286
3287         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3288         if (ret != LDB_SUCCESS) {
3289                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3290                          ldb_dn_get_linearized(dn),
3291                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3292                 return ret;
3293         }
3294
3295         talloc_free(msg);
3296
3297         return LDB_SUCCESS;
3298
3299 failed:
3300         talloc_free(msg);
3301         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3302                  ldb_dn_get_linearized(dn)));
3303         return LDB_ERR_OPERATIONS_ERROR;
3304 }
3305
3306
3307 /*
3308   callback for conflict DN handling where we have renamed the incoming
3309   record. After renaming it, we need to ensure the change of name and
3310   rDN for the incoming record is seen as an originating update by this DC.
3311  */
3312 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3313 {
3314         struct replmd_replicated_request *ar =
3315                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3316         int ret;
3317
3318         if (ares->error != LDB_SUCCESS) {
3319                 /* call the normal callback for everything except success */
3320                 return replmd_op_callback(req, ares);
3321         }
3322
3323         /* perform a modify of the rDN and name of the record */
3324         ret = replmd_name_modify(ar, req, req->op.add.message->dn);
3325         if (ret != LDB_SUCCESS) {
3326                 ares->error = ret;
3327                 return replmd_op_callback(req, ares);
3328         }
3329
3330         return replmd_op_callback(req, ares);
3331 }
3332
3333 /*
3334   callback for replmd_replicated_apply_add()
3335   This copes with the creation of conflict records in the case where
3336   the DN exists, but with a different objectGUID
3337  */
3338 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
3339 {
3340         struct ldb_dn *conflict_dn;
3341         struct replmd_replicated_request *ar =
3342                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3343         struct ldb_result *res;
3344         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3345         int ret;
3346         const struct ldb_val *rmd_value, *omd_value;
3347         struct replPropertyMetaDataBlob omd, rmd;
3348         enum ndr_err_code ndr_err;
3349         bool rename_incoming_record, rodc;
3350         struct replPropertyMetaData1 *rmd_name, *omd_name;
3351
3352         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3353                 /* call the normal callback for everything except
3354                    conflicts */
3355                 return replmd_op_callback(req, ares);
3356         }
3357
3358         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
3359         if (ret != LDB_SUCCESS) {
3360                 return ret;
3361         }
3362         /*
3363          * we have a conflict, and need to decide if we will keep the
3364          * new record or the old record
3365          */
3366         conflict_dn = req->op.add.message->dn;
3367
3368         if (rodc) {
3369                 /*
3370                  * We are on an RODC, or were a GC for this
3371                  * partition, so we have to fail this until
3372                  * someone who owns the partition sorts it
3373                  * out 
3374                  */
3375                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), 
3376                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
3377                                        " - We must fail the operation until a master for this partition resolves the conflict",
3378                                        ldb_dn_get_linearized(conflict_dn));
3379                 goto failed;
3380         }
3381
3382         /*
3383          * we have a conflict, and need to decide if we will keep the
3384          * new record or the old record
3385          */
3386         conflict_dn = req->op.add.message->dn;
3387
3388         /*
3389          * first we need the replPropertyMetaData attribute from the
3390          * old record
3391          */
3392         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3393                                     attrs,
3394                                     DSDB_FLAG_NEXT_MODULE |
3395                                     DSDB_SEARCH_SHOW_DELETED |
3396                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3397         if (ret != LDB_SUCCESS) {
3398                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3399                          ldb_dn_get_linearized(conflict_dn)));
3400                 goto failed;
3401         }
3402
3403         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3404         if (omd_value == NULL) {
3405                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3406                          ldb_dn_get_linearized(conflict_dn)));
3407                 goto failed;
3408         }
3409
3410         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3411                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3412         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3413                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3414                          ldb_dn_get_linearized(conflict_dn)));
3415                 goto failed;
3416         }
3417
3418         /*
3419          * and the replPropertyMetaData attribute from the
3420          * new record
3421          */
3422         rmd_value = ldb_msg_find_ldb_val(req->op.add.message, "replPropertyMetaData");
3423         if (rmd_value == NULL) {
3424                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for new record '%s'\n",
3425                          ldb_dn_get_linearized(conflict_dn)));
3426                 goto failed;
3427         }
3428
3429         ndr_err = ndr_pull_struct_blob(rmd_value, req, &rmd,
3430                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3431         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3432                 DEBUG(0,(__location__ ": Failed to parse new replPropertyMetaData for %s\n",
3433                          ldb_dn_get_linearized(conflict_dn)));
3434                 goto failed;
3435         }
3436
3437         /* we decide which is newer based on the RPMD on the name
3438            attribute.  See [MS-DRSR] ResolveNameConflict */
3439         rmd_name = replmd_replPropertyMetaData1_find_attid(&rmd, DRSUAPI_ATTID_name);
3440         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3441         if (!rmd_name || !omd_name) {
3442                 DEBUG(0,(__location__ ": Failed to find name attribute in replPropertyMetaData for %s\n",
3443                          ldb_dn_get_linearized(conflict_dn)));
3444                 goto failed;
3445         }
3446
3447         rename_incoming_record = !replmd_replPropertyMetaData1_is_newer(omd_name, rmd_name);
3448
3449         if (rename_incoming_record) {
3450                 struct GUID guid;
3451                 struct ldb_dn *new_dn;
3452                 struct ldb_message *new_msg;
3453
3454                 guid = samdb_result_guid(req->op.add.message, "objectGUID");
3455                 if (GUID_all_zero(&guid)) {
3456                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3457                                  ldb_dn_get_linearized(conflict_dn)));
3458                         goto failed;
3459                 }
3460                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3461                 if (new_dn == NULL) {
3462                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3463                                  ldb_dn_get_linearized(conflict_dn)));
3464                         goto failed;
3465                 }
3466
3467                 DEBUG(1,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3468                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3469
3470                 /* re-submit the request, but with a different
3471                    callback, so we don't loop forever. */
3472                 new_msg = ldb_msg_copy_shallow(req, req->op.add.message);
3473                 if (!new_msg) {
3474                         goto failed;
3475                         DEBUG(0,(__location__ ": Failed to copy conflict DN message for %s\n",
3476                                  ldb_dn_get_linearized(conflict_dn)));
3477                 }
3478                 new_msg->dn = new_dn;
3479                 req->op.add.message = new_msg;
3480                 req->callback = replmd_op_name_modify_callback;
3481
3482                 return ldb_next_request(ar->module, req);
3483         } else {
3484                 /* we are renaming the existing record */
3485                 struct GUID guid;
3486                 struct ldb_dn *new_dn;
3487
3488                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3489                 if (GUID_all_zero(&guid)) {
3490                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3491                                  ldb_dn_get_linearized(conflict_dn)));
3492                         goto failed;
3493                 }
3494
3495                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3496                 if (new_dn == NULL) {
3497                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3498                                  ldb_dn_get_linearized(conflict_dn)));
3499                         goto failed;
3500                 }
3501
3502                 DEBUG(1,(__location__ ": Resolving conflict record via existing rename '%s' -> '%s'\n",
3503                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3504
3505                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3506                                          DSDB_FLAG_OWN_MODULE, req);
3507                 if (ret != LDB_SUCCESS) {
3508                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3509                                  ldb_dn_get_linearized(conflict_dn),
3510                                  ldb_dn_get_linearized(new_dn),
3511                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3512                         goto failed;
3513                 }
3514
3515                 /*
3516                  * now we need to ensure that the rename is seen as an
3517                  * originating update. We do that with a modify.
3518                  */
3519                 ret = replmd_name_modify(ar, req, new_dn);
3520                 if (ret != LDB_SUCCESS) {
3521                         goto failed;
3522                 }
3523
3524                 req->callback = replmd_op_callback;
3525
3526                 return ldb_next_request(ar->module, req);
3527         }
3528
3529 failed:
3530         /* on failure do the original callback. This means replication
3531          * will stop with an error, but there is not much else we can
3532          * do
3533          */
3534         return replmd_op_callback(req, ares);
3535 }
3536
3537 /*
3538   this is called when a new object comes in over DRS
3539  */
3540 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
3541 {
3542         struct ldb_context *ldb;
3543         struct ldb_request *change_req;
3544         enum ndr_err_code ndr_err;
3545         struct ldb_message *msg;
3546         struct replPropertyMetaDataBlob *md;
3547         struct ldb_val md_value;
3548         unsigned int i;
3549         int ret;
3550
3551         /*
3552          * TODO: check if the parent object exist
3553          */
3554
3555         /*
3556          * TODO: handle the conflict case where an object with the
3557          *       same name exist
3558          */
3559
3560         ldb = ldb_module_get_ctx(ar->module);
3561         msg = ar->objs->objects[ar->index_current].msg;
3562         md = ar->objs->objects[ar->index_current].meta_data;
3563
3564         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3565         if (ret != LDB_SUCCESS) {
3566                 return replmd_replicated_request_error(ar, ret);
3567         }
3568
3569         ret = ldb_msg_add_value(msg, "objectGUID", &ar->objs->objects[ar->index_current].guid_value, NULL);
3570         if (ret != LDB_SUCCESS) {
3571                 return replmd_replicated_request_error(ar, ret);
3572         }
3573
3574         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3575         if (ret != LDB_SUCCESS) {
3576                 return replmd_replicated_request_error(ar, ret);
3577         }
3578
3579         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
3580         if (ret != LDB_SUCCESS) {
3581                 return replmd_replicated_request_error(ar, ret);
3582         }
3583
3584         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3585         if (ret != LDB_SUCCESS) {
3586                 return replmd_replicated_request_error(ar, ret);
3587         }
3588
3589         /* remove any message elements that have zero values */
3590         for (i=0; i<msg->num_elements; i++) {
3591                 struct ldb_message_element *el = &msg->elements[i];
3592
3593                 if (el->num_values == 0) {
3594                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
3595                                  el->name));
3596                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
3597                         msg->num_elements--;
3598                         i--;
3599                         continue;
3600                 }
3601         }
3602
3603         /*
3604          * the meta data array is already sorted by the caller
3605          */
3606         for (i=0; i < md->ctr.ctr1.count; i++) {
3607                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
3608         }
3609         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
3610                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3611         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3612                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3613                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3614         }
3615         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
3616         if (ret != LDB_SUCCESS) {
3617                 return replmd_replicated_request_error(ar, ret);
3618         }
3619
3620         replmd_ldb_message_sort(msg, ar->schema);
3621
3622         if (DEBUGLVL(4)) {
3623                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
3624                 DEBUG(4, ("DRS replication add message:\n%s\n", s));
3625                 talloc_free(s);
3626         }
3627
3628         ret = ldb_build_add_req(&change_req,
3629                                 ldb,
3630                                 ar,
3631                                 msg,
3632                                 ar->controls,
3633                                 ar,
3634                                 replmd_op_add_callback,
3635                                 ar->req);
3636         LDB_REQ_SET_LOCATION(change_req);
3637         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3638
3639         /* current partition control needed by "repmd_op_callback" */
3640         ret = ldb_request_add_control(change_req,
3641                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3642                                       false, NULL);
3643         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3644
3645         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
3646                 /* this tells the partition module to make it a
3647                    partial replica if creating an NC */
3648                 ret = ldb_request_add_control(change_req,
3649                                               DSDB_CONTROL_PARTIAL_REPLICA,
3650                                               false, NULL);
3651                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3652         }
3653
3654         return ldb_next_request(ar->module, change_req);
3655 }
3656
3657 /*
3658   handle renames that come in over DRS replication
3659  */
3660 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
3661                                            struct ldb_message *msg,
3662                                            struct replPropertyMetaDataBlob *rmd,
3663                                            struct replPropertyMetaDataBlob *omd,
3664                                            struct ldb_request *parent)
3665 {
3666         struct replPropertyMetaData1 *md_remote;
3667         struct replPropertyMetaData1 *md_local;
3668
3669         if (ldb_dn_compare(msg->dn, ar->search_msg->dn) == 0) {
3670                 /* no rename */
3671                 return LDB_SUCCESS;
3672         }
3673
3674         /* now we need to check for double renames. We could have a
3675          * local rename pending which our replication partner hasn't
3676          * received yet. We choose which one wins by looking at the
3677          * attribute stamps on the two objects, the newer one wins
3678          */
3679         md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3680         md_local  = replmd_replPropertyMetaData1_find_attid(omd, DRSUAPI_ATTID_name);
3681         /* if there is no name attribute then we have to assume the
3682            object we've received is in fact newer */
3683         if (!md_remote || !md_local ||
3684             replmd_replPropertyMetaData1_is_newer(md_local, md_remote)) {
3685                 DEBUG(4,("replmd_replicated_request rename %s => %s\n",
3686                          ldb_dn_get_linearized(ar->search_msg->dn),
3687                          ldb_dn_get_linearized(msg->dn)));
3688                 /* pass rename to the next module
3689                  * so it doesn't appear as an originating update */
3690                 return dsdb_module_rename(ar->module,
3691                                           ar->search_msg->dn, msg->dn,
3692                                           DSDB_FLAG_NEXT_MODULE | DSDB_MODIFY_RELAX, parent);
3693         }
3694
3695         /* we're going to keep our old object */
3696         DEBUG(4,(__location__ ": Keeping object %s and rejecting older rename to %s\n",
3697                  ldb_dn_get_linearized(ar->search_msg->dn),
3698                  ldb_dn_get_linearized(msg->dn)));
3699         return LDB_SUCCESS;
3700 }
3701
3702
3703 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
3704 {
3705         struct ldb_context *ldb;
3706         struct ldb_request *change_req;
3707         enum ndr_err_code ndr_err;
3708         struct ldb_message *msg;
3709         struct replPropertyMetaDataBlob *rmd;
3710         struct replPropertyMetaDataBlob omd;
3711         const struct ldb_val *omd_value;
3712         struct replPropertyMetaDataBlob nmd;
3713         struct ldb_val nmd_value;
3714         unsigned int i;
3715         uint32_t j,ni=0;
3716         unsigned int removed_attrs = 0;
3717         int ret;
3718
3719         ldb = ldb_module_get_ctx(ar->module);
3720         msg = ar->objs->objects[ar->index_current].msg;
3721         rmd = ar->objs->objects[ar->index_current].meta_data;
3722         ZERO_STRUCT(omd);
3723         omd.version = 1;
3724
3725         /* find existing meta data */
3726         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
3727         if (omd_value) {
3728                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
3729                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3730                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3731                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3732                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3733                 }
3734
3735                 if (omd.version != 1) {
3736                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
3737                 }
3738         }
3739
3740         /* handle renames that come in over DRS */
3741         ret = replmd_replicated_handle_rename(ar, msg, rmd, &omd, ar->req);
3742         if (ret != LDB_SUCCESS) {
3743                 ldb_debug(ldb, LDB_DEBUG_FATAL,
3744                           "replmd_replicated_request rename %s => %s failed - %s\n",
3745                           ldb_dn_get_linearized(ar->search_msg->dn),
3746                           ldb_dn_get_linearized(msg->dn),
3747                           ldb_errstring(ldb));
3748                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
3749         }
3750
3751         ZERO_STRUCT(nmd);
3752         nmd.version = 1;
3753         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
3754         nmd.ctr.ctr1.array = talloc_array(ar,
3755                                           struct replPropertyMetaData1,
3756                                           nmd.ctr.ctr1.count);
3757         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3758
3759         /* first copy the old meta data */
3760         for (i=0; i < omd.ctr.ctr1.count; i++) {
3761                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
3762                 ni++;
3763         }
3764
3765         ar->seq_num = 0;
3766         /* now merge in the new meta data */
3767         for (i=0; i < rmd->ctr.ctr1.count; i++) {
3768                 bool found = false;
3769
3770                 for (j=0; j < ni; j++) {
3771                         bool cmp;
3772
3773                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
3774                                 continue;
3775                         }
3776
3777                         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
3778                                 /* if we compare equal then do an
3779                                    update. This is used when a client
3780                                    asks for a FULL_SYNC, and can be
3781                                    used to recover a corrupt
3782                                    replica */
3783                                 cmp = !replmd_replPropertyMetaData1_is_newer(&rmd->ctr.ctr1.array[i],
3784                                                                              &nmd.ctr.ctr1.array[j]);
3785                         } else {
3786                                 cmp = replmd_replPropertyMetaData1_is_newer(&nmd.ctr.ctr1.array[j],
3787                                                                             &rmd->ctr.ctr1.array[i]);
3788                         }
3789                         if (cmp) {
3790                                 /* replace the entry */
3791                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
3792                                 if (ar->seq_num == 0) {
3793                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3794                                         if (ret != LDB_SUCCESS) {
3795                                                 return replmd_replicated_request_error(ar, ret);
3796                                         }
3797                                 }
3798                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
3799                                 found = true;
3800                                 break;
3801                         }
3802
3803                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
3804                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
3805                                          msg->elements[i-removed_attrs].name,
3806                                          ldb_dn_get_linearized(msg->dn),
3807                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
3808                         }
3809
3810                         /* we don't want to apply this change so remove the attribute */
3811                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
3812                         removed_attrs++;
3813
3814                         found = true;
3815                         break;
3816                 }
3817
3818                 if (found) continue;
3819
3820                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
3821                 if (ar->seq_num == 0) {
3822                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
3823                         if (ret != LDB_SUCCESS) {
3824                                 return replmd_replicated_request_error(ar, ret);
3825                         }
3826                 }
3827                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
3828                 ni++;
3829         }
3830
3831         /*
3832          * finally correct the size of the meta_data array
3833          */
3834         nmd.ctr.ctr1.count = ni;
3835
3836         /*
3837          * the rdn attribute (the alias for the name attribute),
3838          * 'cn' for most objects is the last entry in the meta data array
3839          * we have stored
3840          *
3841          * sort the new meta data array
3842          */
3843         ret = replmd_replPropertyMetaDataCtr1_sort(&nmd.ctr.ctr1, ar->schema, msg->dn);
3844         if (ret != LDB_SUCCESS) {
3845                 return ret;
3846         }
3847
3848         /*
3849          * check if some replicated attributes left, otherwise skip the ldb_modify() call
3850          */
3851         if (msg->num_elements == 0) {
3852                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
3853                           ar->index_current);
3854
3855                 ar->index_current++;
3856                 return replmd_replicated_apply_next(ar);
3857         }
3858
3859         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
3860                   ar->index_current, msg->num_elements);
3861
3862         /* create the meta data value */
3863         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
3864                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
3865         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3866                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
3867                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
3868         }
3869
3870         /*
3871          * when we know that we'll modify the record, add the whenChanged, uSNChanged
3872          * and replPopertyMetaData attributes
3873          */
3874         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
3875         if (ret != LDB_SUCCESS) {
3876                 return replmd_replicated_request_error(ar, ret);
3877         }
3878         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
3879         if (ret != LDB_SUCCESS) {
3880                 return replmd_replicated_request_error(ar, ret);
3881         }
3882         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
3883         if (ret != LDB_SUCCESS) {
3884                 return replmd_replicated_request_error(ar, ret);
3885         }
3886
3887         replmd_ldb_message_sort(msg, ar->schema);
3888
3889         /* we want to replace the old values */
3890         for (i=0; i < msg->num_elements; i++) {
3891                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
3892         }
3893
3894         if (DEBUGLVL(4)) {
3895                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
3896                 DEBUG(4, ("DRS replication modify message:\n%s\n", s));
3897                 talloc_free(s);
3898         }
3899
3900         ret = ldb_build_mod_req(&change_req,
3901                                 ldb,
3902                                 ar,
3903                                 msg,
3904                                 ar->controls,
3905                                 ar,
3906                                 replmd_op_callback,
3907                                 ar->req);
3908         LDB_REQ_SET_LOCATION(change_req);
3909         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3910
3911         /* current partition control needed by "repmd_op_callback" */
3912         ret = ldb_request_add_control(change_req,
3913                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
3914                                       false, NULL);
3915         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
3916
3917         return ldb_next_request(ar->module, change_req);
3918 }
3919
3920 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
3921                                                    struct ldb_reply *ares)
3922 {
3923         struct replmd_replicated_request *ar = talloc_get_type(req->context,
3924                                                struct replmd_replicated_request);
3925         int ret;
3926
3927         if (!ares) {
3928                 return ldb_module_done(ar->req, NULL, NULL,
3929                                         LDB_ERR_OPERATIONS_ERROR);
3930         }
3931         if (ares->error != LDB_SUCCESS &&
3932             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
3933                 return ldb_module_done(ar->req, ares->controls,
3934                                         ares->response, ares->error);
3935         }
3936
3937         switch (ares->type) {
3938         case LDB_REPLY_ENTRY:
3939                 ar->search_msg = talloc_steal(ar, ares->message);
3940                 break;
3941
3942         case LDB_REPLY_REFERRAL:
3943                 /* we ignore referrals */
3944                 break;
3945
3946         case LDB_REPLY_DONE:
3947                 if (ar->search_msg != NULL) {
3948                         ret = replmd_replicated_apply_merge(ar);
3949                 } else {
3950                         ret = replmd_replicated_apply_add(ar);
3951                 }
3952                 if (ret != LDB_SUCCESS) {
3953                         return ldb_module_done(ar->req, NULL, NULL, ret);
3954                 }
3955         }
3956
3957         talloc_free(ares);
3958         return LDB_SUCCESS;
3959 }
3960
3961 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
3962
3963 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
3964 {
3965         struct ldb_context *ldb;
3966         int ret;
3967         char *tmp_str;
3968         char *filter;
3969         struct ldb_request *search_req;
3970         struct ldb_search_options_control *options;
3971
3972         if (ar->index_current >= ar->objs->num_objects) {
3973                 /* done with it, go to next stage */
3974                 return replmd_replicated_uptodate_vector(ar);
3975         }
3976
3977         ldb = ldb_module_get_ctx(ar->module);
3978         ar->search_msg = NULL;
3979
3980         tmp_str = ldb_binary_encode(ar, ar->objs->objects[ar->index_current].guid_value);
3981         if (!tmp_str) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3982
3983         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
3984         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
3985         talloc_free(tmp_str);
3986
3987         ret = ldb_build_search_req(&search_req,
3988                                    ldb,
3989                                    ar,
3990                                    NULL,
3991                                    LDB_SCOPE_SUBTREE,
3992                                    filter,
3993                                    NULL,
3994                                    NULL,
3995                                    ar,
3996                                    replmd_replicated_apply_search_callback,
3997                                    ar->req);
3998         LDB_REQ_SET_LOCATION(search_req);
3999
4000         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
4001                                       true, NULL);
4002         if (ret != LDB_SUCCESS) {
4003                 return ret;
4004         }
4005
4006         /* we need to cope with cross-partition links, so search for
4007            the GUID over all partitions */
4008         options = talloc(search_req, struct ldb_search_options_control);
4009         if (options == NULL) {
4010                 DEBUG(0, (__location__ ": out of memory\n"));
4011                 return LDB_ERR_OPERATIONS_ERROR;
4012         }
4013         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
4014
4015         ret = ldb_request_add_control(search_req,
4016                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
4017                                       true, options);
4018         if (ret != LDB_SUCCESS) {
4019                 return ret;
4020         }
4021
4022         return ldb_next_request(ar->module, search_req);
4023 }
4024
4025 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
4026                                                       struct ldb_reply *ares)
4027 {
4028         struct ldb_context *ldb;
4029         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4030                                                struct replmd_replicated_request);
4031         ldb = ldb_module_get_ctx(ar->module);
4032
4033         if (!ares) {
4034                 return ldb_module_done(ar->req, NULL, NULL,
4035                                         LDB_ERR_OPERATIONS_ERROR);
4036         }
4037         if (ares->error != LDB_SUCCESS) {
4038                 return ldb_module_done(ar->req, ares->controls,
4039                                         ares->response, ares->error);
4040         }
4041
4042         if (ares->type != LDB_REPLY_DONE) {
4043                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
4044                 return ldb_module_done(ar->req, NULL, NULL,
4045                                         LDB_ERR_OPERATIONS_ERROR);
4046         }
4047
4048         talloc_free(ares);
4049
4050         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4051 }
4052
4053 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
4054 {
4055         struct ldb_context *ldb;
4056         struct ldb_request *change_req;
4057         enum ndr_err_code ndr_err;
4058         struct ldb_message *msg;
4059         struct replUpToDateVectorBlob ouv;
4060         const struct ldb_val *ouv_value;
4061         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
4062         struct replUpToDateVectorBlob nuv;
4063         struct ldb_val nuv_value;
4064         struct ldb_message_element *nuv_el = NULL;
4065         const struct GUID *our_invocation_id;
4066         struct ldb_message_element *orf_el = NULL;
4067         struct repsFromToBlob nrf;
4068         struct ldb_val *nrf_value = NULL;
4069         struct ldb_message_element *nrf_el = NULL;
4070         unsigned int i;
4071         uint32_t j,ni=0;
4072         bool found = false;
4073         time_t t = time(NULL);
4074         NTTIME now;
4075         int ret;
4076         uint32_t instanceType;
4077
4078         ldb = ldb_module_get_ctx(ar->module);
4079         ruv = ar->objs->uptodateness_vector;
4080         ZERO_STRUCT(ouv);
4081         ouv.version = 2;
4082         ZERO_STRUCT(nuv);
4083         nuv.version = 2;
4084
4085         unix_to_nt_time(&now, t);
4086
4087         if (ar->search_msg == NULL) {
4088                 /* this happens for a REPL_OBJ call where we are
4089                    creating the target object by replicating it. The
4090                    subdomain join code does this for the partition DN
4091                 */
4092                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
4093                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4094         }
4095
4096         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
4097         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
4098                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
4099                          ldb_dn_get_linearized(ar->search_msg->dn)));
4100                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
4101         }
4102
4103         /*
4104          * first create the new replUpToDateVector
4105          */
4106         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
4107         if (ouv_value) {
4108                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
4109                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
4110                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4111                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4112                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4113                 }
4114
4115                 if (ouv.version != 2) {
4116                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4117                 }
4118         }
4119
4120         /*
4121          * the new uptodateness vector will at least
4122          * contain 1 entry, one for the source_dsa
4123          *
4124          * plus optional values from our old vector and the one from the source_dsa
4125          */
4126         nuv.ctr.ctr2.count = 1 + ouv.ctr.ctr2.count;
4127         if (ruv) nuv.ctr.ctr2.count += ruv->count;
4128         nuv.ctr.ctr2.cursors = talloc_array(ar,
4129                                             struct drsuapi_DsReplicaCursor2,
4130                                             nuv.ctr.ctr2.count);
4131         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4132
4133         /* first copy the old vector */
4134         for (i=0; i < ouv.ctr.ctr2.count; i++) {
4135                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
4136                 ni++;
4137         }
4138
4139         /* get our invocation_id if we have one already attached to the ldb */
4140         our_invocation_id = samdb_ntds_invocation_id(ldb);
4141
4142         /* merge in the source_dsa vector is available */
4143         for (i=0; (ruv && i < ruv->count); i++) {
4144                 found = false;
4145
4146                 if (our_invocation_id &&
4147                     GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4148                                our_invocation_id)) {
4149                         continue;
4150                 }
4151
4152                 for (j=0; j < ni; j++) {
4153                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
4154                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4155                                 continue;
4156                         }
4157
4158                         found = true;
4159
4160                         /*
4161                          * we update only the highest_usn and not the latest_sync_success time,
4162                          * because the last success stands for direct replication
4163                          */
4164                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
4165                                 nuv.ctr.ctr2.cursors[j].highest_usn = ruv->cursors[i].highest_usn;
4166                         }
4167                         break;
4168                 }
4169
4170                 if (found) continue;
4171
4172                 /* if it's not there yet, add it */
4173                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
4174                 ni++;
4175         }
4176
4177         /*
4178          * merge in the current highwatermark for the source_dsa
4179          */
4180         found = false;
4181         for (j=0; j < ni; j++) {
4182                 if (!GUID_equal(&ar->objs->source_dsa->source_dsa_invocation_id,
4183                                 &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
4184                         continue;
4185                 }
4186
4187                 found = true;
4188
4189                 /*
4190                  * here we update the highest_usn and last_sync_success time
4191                  * because we're directly replicating from the source_dsa
4192                  *
4193                  * and use the tmp_highest_usn because this is what we have just applied
4194                  * to our ldb
4195                  */
4196                 nuv.ctr.ctr2.cursors[j].highest_usn             = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4197                 nuv.ctr.ctr2.cursors[j].last_sync_success       = now;
4198                 break;
4199         }
4200         if (!found) {
4201                 /*
4202                  * here we update the highest_usn and last_sync_success time
4203                  * because we're directly replicating from the source_dsa
4204                  *
4205                  * and use the tmp_highest_usn because this is what we have just applied
4206                  * to our ldb
4207                  */
4208                 nuv.ctr.ctr2.cursors[ni].source_dsa_invocation_id= ar->objs->source_dsa->source_dsa_invocation_id;
4209                 nuv.ctr.ctr2.cursors[ni].highest_usn            = ar->objs->source_dsa->highwatermark.tmp_highest_usn;
4210                 nuv.ctr.ctr2.cursors[ni].last_sync_success      = now;
4211                 ni++;
4212         }
4213
4214         /*
4215          * finally correct the size of the cursors array
4216          */
4217         nuv.ctr.ctr2.count = ni;
4218
4219         /*
4220          * sort the cursors
4221          */
4222         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
4223
4224         /*
4225          * create the change ldb_message
4226          */
4227         msg = ldb_msg_new(ar);
4228         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4229         msg->dn = ar->search_msg->dn;
4230
4231         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
4232                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
4233         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4234                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4235                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4236         }
4237         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
4238         if (ret != LDB_SUCCESS) {
4239                 return replmd_replicated_request_error(ar, ret);
4240         }
4241         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
4242
4243         /*
4244          * now create the new repsFrom value from the given repsFromTo1 structure
4245          */
4246         ZERO_STRUCT(nrf);
4247         nrf.version                                     = 1;
4248         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
4249         nrf.ctr.ctr1.highwatermark.highest_usn          = nrf.ctr.ctr1.highwatermark.tmp_highest_usn;
4250
4251         /*
4252          * first see if we already have a repsFrom value for the current source dsa
4253          * if so we'll later replace this value
4254          */
4255         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
4256         if (orf_el) {
4257                 for (i=0; i < orf_el->num_values; i++) {
4258                         struct repsFromToBlob *trf;
4259
4260                         trf = talloc(ar, struct repsFromToBlob);
4261                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4262
4263                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
4264                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
4265                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4266                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4267                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4268                         }
4269
4270                         if (trf->version != 1) {
4271                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4272                         }
4273
4274                         /*
4275                          * we compare the source dsa objectGUID not the invocation_id
4276                          * because we want only one repsFrom value per source dsa
4277                          * and when the invocation_id of the source dsa has changed we don't need
4278                          * the old repsFrom with the old invocation_id
4279                          */
4280                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
4281                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
4282                                 talloc_free(trf);
4283                                 continue;
4284                         }
4285
4286                         talloc_free(trf);
4287                         nrf_value = &orf_el->values[i];
4288                         break;
4289                 }
4290
4291                 /*
4292                  * copy over all old values to the new ldb_message
4293                  */
4294                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
4295                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4296                 *nrf_el = *orf_el;
4297         }
4298
4299         /*
4300          * if we haven't found an old repsFrom value for the current source dsa
4301          * we'll add a new value
4302          */
4303         if (!nrf_value) {
4304                 struct ldb_val zero_value;
4305                 ZERO_STRUCT(zero_value);
4306                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
4307                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4308
4309                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
4310         }
4311
4312         /* we now fill the value which is already attached to ldb_message */
4313         ndr_err = ndr_push_struct_blob(nrf_value, msg,
4314                                        &nrf,
4315                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
4316         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4317                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4318                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4319         }
4320
4321         /*
4322          * the ldb_message_element for the attribute, has all the old values and the new one
4323          * so we'll replace the whole attribute with all values
4324          */
4325         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
4326
4327         if (CHECK_DEBUGLVL(4)) {
4328                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4329                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
4330                 talloc_free(s);
4331         }
4332
4333         /* prepare the ldb_modify() request */
4334         ret = ldb_build_mod_req(&change_req,
4335                                 ldb,
4336                                 ar,
4337                                 msg,
4338                                 ar->controls,
4339                                 ar,
4340                                 replmd_replicated_uptodate_modify_callback,
4341                                 ar->req);
4342         LDB_REQ_SET_LOCATION(change_req);
4343         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4344
4345         return ldb_next_request(ar->module, change_req);
4346 }
4347
4348 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
4349                                                       struct ldb_reply *ares)
4350 {
4351         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4352                                                struct replmd_replicated_request);
4353         int ret;
4354
4355         if (!ares) {
4356                 return ldb_module_done(ar->req, NULL, NULL,
4357                                         LDB_ERR_OPERATIONS_ERROR);
4358         }
4359         if (ares->error != LDB_SUCCESS &&
4360             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
4361                 return ldb_module_done(ar->req, ares->controls,
4362                                         ares->response, ares->error);
4363         }
4364
4365         switch (ares->type) {
4366         case LDB_REPLY_ENTRY:
4367                 ar->search_msg = talloc_steal(ar, ares->message);
4368                 break;
4369
4370         case LDB_REPLY_REFERRAL:
4371                 /* we ignore referrals */
4372                 break;
4373
4374         case LDB_REPLY_DONE:
4375                 ret = replmd_replicated_uptodate_modify(ar);
4376                 if (ret != LDB_SUCCESS) {
4377                         return ldb_module_done(ar->req, NULL, NULL, ret);
4378                 }
4379         }
4380
4381         talloc_free(ares);
4382         return LDB_SUCCESS;
4383 }
4384
4385
4386 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
4387 {
4388         struct ldb_context *ldb;
4389         int ret;
4390         static const char *attrs[] = {
4391                 "replUpToDateVector",
4392                 "repsFrom",
4393                 "instanceType",
4394                 NULL
4395         };
4396         struct ldb_request *search_req;
4397
4398         ldb = ldb_module_get_ctx(ar->module);
4399         ar->search_msg = NULL;
4400
4401         ret = ldb_build_search_req(&search_req,
4402                                    ldb,
4403                                    ar,
4404                                    ar->objs->partition_dn,
4405                                    LDB_SCOPE_BASE,
4406                                    "(objectClass=*)",
4407                                    attrs,
4408                                    NULL,
4409                                    ar,
4410                                    replmd_replicated_uptodate_search_callback,
4411                                    ar->req);
4412         LDB_REQ_SET_LOCATION(search_req);
4413         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4414
4415         return ldb_next_request(ar->module, search_req);
4416 }
4417
4418
4419
4420 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
4421 {
4422         struct ldb_context *ldb;
4423         struct dsdb_extended_replicated_objects *objs;
4424         struct replmd_replicated_request *ar;
4425         struct ldb_control **ctrls;
4426         int ret;
4427         uint32_t i;
4428         struct replmd_private *replmd_private =
4429                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4430         struct dsdb_control_replicated_update *rep_update;
4431
4432         ldb = ldb_module_get_ctx(module);
4433
4434         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
4435
4436         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
4437         if (!objs) {
4438                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
4439                 return LDB_ERR_PROTOCOL_ERROR;
4440         }
4441
4442         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
4443                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
4444                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
4445                 return LDB_ERR_PROTOCOL_ERROR;
4446         }
4447
4448         ar = replmd_ctx_init(module, req);
4449         if (!ar)
4450                 return LDB_ERR_OPERATIONS_ERROR;
4451
4452         /* Set the flags to have the replmd_op_callback run over the full set of objects */
4453         ar->apply_mode = true;
4454         ar->objs = objs;
4455         ar->schema = dsdb_get_schema(ldb, ar);
4456         if (!ar->schema) {
4457                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
4458                 talloc_free(ar);
4459                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4460                 return LDB_ERR_CONSTRAINT_VIOLATION;
4461         }
4462
4463         ctrls = req->controls;
4464
4465         if (req->controls) {
4466                 req->controls = talloc_memdup(ar, req->controls,
4467                                               talloc_get_size(req->controls));
4468                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4469         }
4470
4471         /* This allows layers further down to know if a change came in
4472            over replication and what the replication flags were */
4473         rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
4474         if (rep_update == NULL) {
4475                 return ldb_module_oom(module);
4476         }
4477         rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
4478
4479         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
4480         if (ret != LDB_SUCCESS) {
4481                 return ret;
4482         }
4483
4484         /* If this change contained linked attributes in the body
4485          * (rather than in the links section) we need to update
4486          * backlinks in linked_attributes */
4487         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
4488         if (ret != LDB_SUCCESS) {
4489                 return ret;
4490         }
4491
4492         ar->controls = req->controls;
4493         req->controls = ctrls;
4494
4495         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
4496
4497         /* save away the linked attributes for the end of the
4498            transaction */
4499         for (i=0; i<ar->objs->linked_attributes_count; i++) {
4500                 struct la_entry *la_entry;
4501
4502                 if (replmd_private->la_ctx == NULL) {
4503                         replmd_private->la_ctx = talloc_new(replmd_private);
4504                 }
4505                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
4506                 if (la_entry == NULL) {
4507                         ldb_oom(ldb);
4508                         return LDB_ERR_OPERATIONS_ERROR;
4509                 }
4510                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
4511                 if (la_entry->la == NULL) {
4512                         talloc_free(la_entry);
4513                         ldb_oom(ldb);
4514                         return LDB_ERR_OPERATIONS_ERROR;
4515                 }
4516                 *la_entry->la = ar->objs->linked_attributes[i];
4517
4518                 /* we need to steal the non-scalars so they stay
4519                    around until the end of the transaction */
4520                 talloc_steal(la_entry->la, la_entry->la->identifier);
4521                 talloc_steal(la_entry->la, la_entry->la->value.blob);
4522
4523                 DLIST_ADD(replmd_private->la_list, la_entry);
4524         }
4525
4526         return replmd_replicated_apply_next(ar);
4527 }
4528
4529 /*
4530   process one linked attribute structure
4531  */
4532 static int replmd_process_linked_attribute(struct ldb_module *module,
4533                                            struct la_entry *la_entry,
4534                                            struct ldb_request *parent)
4535 {
4536         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
4537         struct ldb_context *ldb = ldb_module_get_ctx(module);
4538         struct ldb_message *msg;
4539         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
4540         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
4541         int ret;
4542         const struct dsdb_attribute *attr;
4543         struct dsdb_dn *dsdb_dn;
4544         uint64_t seq_num = 0;
4545         struct ldb_message_element *old_el;
4546         WERROR status;
4547         time_t t = time(NULL);
4548         struct ldb_result *res;
4549         const char *attrs[2];
4550         struct parsed_dn *pdn_list, *pdn;
4551         struct GUID guid = GUID_zero();
4552         NTSTATUS ntstatus;
4553         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
4554         const struct GUID *our_invocation_id;
4555
4556 /*
4557 linked_attributes[0]:
4558      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
4559         identifier               : *
4560             identifier: struct drsuapi_DsReplicaObjectIdentifier
4561                 __ndr_size               : 0x0000003a (58)
4562                 __ndr_size_sid           : 0x00000000 (0)
4563                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
4564                 sid                      : S-0-0
4565                 __ndr_size_dn            : 0x00000000 (0)
4566                 dn                       : ''
4567         attid                    : DRSUAPI_ATTID_member (0x1F)
4568         value: struct drsuapi_DsAttributeValue
4569             __ndr_size               : 0x0000007e (126)
4570             blob                     : *
4571                 blob                     : DATA_BLOB length=126
4572         flags                    : 0x00000001 (1)
4573                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
4574         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
4575         meta_data: struct drsuapi_DsReplicaMetaData
4576             version                  : 0x00000015 (21)
4577             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
4578             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
4579             originating_usn          : 0x000000000001e19c (123292)
4580
4581 (for cases where the link is to a normal DN)
4582      &target: struct drsuapi_DsReplicaObjectIdentifier3
4583         __ndr_size               : 0x0000007e (126)
4584         __ndr_size_sid           : 0x0000001c (28)
4585         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
4586         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
4587         __ndr_size_dn            : 0x00000022 (34)
4588         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
4589  */
4590
4591         /* find the attribute being modified */
4592         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
4593         if (attr == NULL) {
4594                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
4595                 talloc_free(tmp_ctx);
4596                 return LDB_ERR_OPERATIONS_ERROR;
4597         }
4598
4599         attrs[0] = attr->lDAPDisplayName;
4600         attrs[1] = NULL;
4601
4602         /* get the existing message from the db for the object with
4603            this GUID, returning attribute being modified. We will then
4604            use this msg as the basis for a modify call */
4605         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
4606                                  DSDB_FLAG_NEXT_MODULE |
4607                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
4608                                  DSDB_SEARCH_SHOW_RECYCLED |
4609                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4610                                  DSDB_SEARCH_REVEAL_INTERNALS,
4611                                  parent,
4612                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
4613         if (ret != LDB_SUCCESS) {
4614                 talloc_free(tmp_ctx);
4615                 return ret;
4616         }
4617         if (res->count != 1) {
4618                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
4619                                        GUID_string(tmp_ctx, &la->identifier->guid));
4620                 talloc_free(tmp_ctx);
4621                 return LDB_ERR_NO_SUCH_OBJECT;
4622         }
4623         msg = res->msgs[0];
4624
4625         if (msg->num_elements == 0) {
4626                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
4627                 if (ret != LDB_SUCCESS) {
4628                         ldb_module_oom(module);
4629                         talloc_free(tmp_ctx);
4630                         return LDB_ERR_OPERATIONS_ERROR;
4631                 }
4632         } else {
4633                 old_el = &msg->elements[0];
4634                 old_el->flags = LDB_FLAG_MOD_REPLACE;
4635         }
4636
4637         /* parse the existing links */
4638         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
4639         if (ret != LDB_SUCCESS) {
4640                 talloc_free(tmp_ctx);
4641                 return ret;
4642         }
4643
4644         /* get our invocationId */
4645         our_invocation_id = samdb_ntds_invocation_id(ldb);
4646         if (!our_invocation_id) {
4647                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
4648                 talloc_free(tmp_ctx);
4649                 return LDB_ERR_OPERATIONS_ERROR;
4650         }
4651
4652         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
4653         if (ret != LDB_SUCCESS) {
4654                 talloc_free(tmp_ctx);
4655                 return ret;
4656         }
4657
4658         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
4659         if (!W_ERROR_IS_OK(status)) {
4660                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
4661                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
4662                 return LDB_ERR_OPERATIONS_ERROR;
4663         }
4664
4665         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
4666         if (!NT_STATUS_IS_OK(ntstatus) && active) {
4667                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
4668                                        old_el->name,
4669                                        ldb_dn_get_linearized(dsdb_dn->dn),
4670                                        ldb_dn_get_linearized(msg->dn));
4671                 return LDB_ERR_OPERATIONS_ERROR;
4672         }
4673
4674         /* re-resolve the DN by GUID, as the DRS server may give us an
4675            old DN value */
4676         ret = dsdb_module_dn_by_guid(module, dsdb_dn, &guid, &dsdb_dn->dn, parent);
4677         if (ret != LDB_SUCCESS) {
4678                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
4679                          GUID_string(tmp_ctx, &guid),
4680                          ldb_dn_get_linearized(dsdb_dn->dn)));
4681         }
4682
4683         /* see if this link already exists */
4684         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
4685         if (pdn != NULL) {
4686                 /* see if this update is newer than what we have already */
4687                 struct GUID invocation_id = GUID_zero();
4688                 uint32_t version = 0;
4689                 uint32_t originating_usn = 0;
4690                 NTTIME change_time = 0;
4691                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
4692
4693                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
4694                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
4695                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
4696                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
4697
4698                 if (!replmd_update_is_newer(&invocation_id,
4699                                             &la->meta_data.originating_invocation_id,
4700                                             version,
4701                                             la->meta_data.version,
4702                                             change_time,
4703                                             la->meta_data.originating_change_time)) {
4704                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
4705                                  old_el->name, ldb_dn_get_linearized(msg->dn),
4706                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
4707                         talloc_free(tmp_ctx);
4708                         return LDB_SUCCESS;
4709                 }
4710
4711                 /* get a seq_num for this change */
4712                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4713                 if (ret != LDB_SUCCESS) {
4714                         talloc_free(tmp_ctx);
4715                         return ret;
4716                 }
4717
4718                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
4719                         /* remove the existing backlink */
4720                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, false);
4721                         if (ret != LDB_SUCCESS) {
4722                                 talloc_free(tmp_ctx);
4723                                 return ret;
4724                         }
4725                 }
4726
4727                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
4728                                            &la->meta_data.originating_invocation_id,
4729                                            la->meta_data.originating_usn, seq_num,
4730                                            la->meta_data.originating_change_time,
4731                                            la->meta_data.version,
4732                                            !active);
4733                 if (ret != LDB_SUCCESS) {
4734                         talloc_free(tmp_ctx);
4735                         return ret;
4736                 }
4737
4738                 if (active) {
4739                         /* add the new backlink */
4740                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, false);
4741                         if (ret != LDB_SUCCESS) {
4742                                 talloc_free(tmp_ctx);
4743                                 return ret;
4744                         }
4745                 }
4746         } else {
4747                 /* get a seq_num for this change */
4748                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
4749                 if (ret != LDB_SUCCESS) {
4750                         talloc_free(tmp_ctx);
4751                         return ret;
4752                 }
4753
4754                 old_el->values = talloc_realloc(msg->elements, old_el->values,
4755                                                 struct ldb_val, old_el->num_values+1);
4756                 if (!old_el->values) {
4757                         ldb_module_oom(module);
4758                         return LDB_ERR_OPERATIONS_ERROR;
4759                 }
4760                 old_el->num_values++;
4761
4762                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
4763                                           &la->meta_data.originating_invocation_id,
4764                                           la->meta_data.originating_usn, seq_num,
4765                                           la->meta_data.originating_change_time,
4766                                           la->meta_data.version,
4767                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
4768                 if (ret != LDB_SUCCESS) {
4769                         talloc_free(tmp_ctx);
4770                         return ret;
4771                 }
4772
4773                 if (active) {
4774                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
4775                                                   true, attr, false);
4776                         if (ret != LDB_SUCCESS) {
4777                                 talloc_free(tmp_ctx);
4778                                 return ret;
4779                         }
4780                 }
4781         }
4782
4783         /* we only change whenChanged and uSNChanged if the seq_num
4784            has changed */
4785         ret = add_time_element(msg, "whenChanged", t);
4786         if (ret != LDB_SUCCESS) {
4787                 talloc_free(tmp_ctx);
4788                 ldb_operr(ldb);
4789                 return ret;
4790         }
4791
4792         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
4793         if (ret != LDB_SUCCESS) {
4794                 talloc_free(tmp_ctx);
4795                 ldb_operr(ldb);
4796                 return ret;
4797         }
4798
4799         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
4800         if (old_el == NULL) {
4801                 talloc_free(tmp_ctx);
4802                 return ldb_operr(ldb);
4803         }
4804
4805         ret = dsdb_check_single_valued_link(attr, old_el);
4806         if (ret != LDB_SUCCESS) {
4807                 talloc_free(tmp_ctx);
4808                 return ret;
4809         }
4810
4811         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
4812
4813         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
4814         if (ret != LDB_SUCCESS) {
4815                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
4816                           ldb_errstring(ldb),
4817                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
4818                 talloc_free(tmp_ctx);
4819                 return ret;
4820         }
4821
4822         talloc_free(tmp_ctx);
4823
4824         return ret;
4825 }
4826
4827 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
4828 {
4829         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
4830                 return replmd_extended_replicated_objects(module, req);
4831         }
4832
4833         return ldb_next_request(module, req);
4834 }
4835
4836
4837 /*
4838   we hook into the transaction operations to allow us to
4839   perform the linked attribute updates at the end of the whole
4840   transaction. This allows a forward linked attribute to be created
4841   before the object is created. During a vampire, w2k8 sends us linked
4842   attributes before the objects they are part of.
4843  */
4844 static int replmd_start_transaction(struct ldb_module *module)
4845 {
4846         /* create our private structure for this transaction */
4847         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
4848                                                                 struct replmd_private);
4849         replmd_txn_cleanup(replmd_private);
4850
4851         /* free any leftover mod_usn records from cancelled
4852            transactions */
4853         while (replmd_private->ncs) {
4854                 struct nc_entry *e = replmd_private->ncs;
4855                 DLIST_REMOVE(replmd_private->ncs, e);
4856                 talloc_free(e);
4857         }
4858
4859         return ldb_next_start_trans(module);
4860 }
4861
4862 /*
4863   on prepare commit we loop over our queued la_context structures and
4864   apply each of them
4865  */
4866 static int replmd_prepare_commit(struct ldb_module *module)
4867 {
4868         struct replmd_private *replmd_private =
4869                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4870         struct la_entry *la, *prev;
4871         struct la_backlink *bl;
4872         int ret;
4873
4874         /* walk the list backwards, to do the first entry first, as we
4875          * added the entries with DLIST_ADD() which puts them at the
4876          * start of the list */
4877         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
4878                 prev = DLIST_PREV(la);
4879                 DLIST_REMOVE(replmd_private->la_list, la);
4880                 ret = replmd_process_linked_attribute(module, la, NULL);
4881                 if (ret != LDB_SUCCESS) {
4882                         replmd_txn_cleanup(replmd_private);
4883                         return ret;
4884                 }
4885         }
4886
4887         /* process our backlink list, creating and deleting backlinks
4888            as necessary */
4889         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
4890                 ret = replmd_process_backlink(module, bl, NULL);
4891                 if (ret != LDB_SUCCESS) {
4892                         replmd_txn_cleanup(replmd_private);
4893                         return ret;
4894                 }
4895         }
4896
4897         replmd_txn_cleanup(replmd_private);
4898
4899         /* possibly change @REPLCHANGED */
4900         ret = replmd_notify_store(module, NULL);
4901         if (ret != LDB_SUCCESS) {
4902                 return ret;
4903         }
4904
4905         return ldb_next_prepare_commit(module);
4906 }
4907
4908 static int replmd_del_transaction(struct ldb_module *module)
4909 {
4910         struct replmd_private *replmd_private =
4911                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
4912         replmd_txn_cleanup(replmd_private);
4913
4914         return ldb_next_del_trans(module);
4915 }
4916
4917
4918 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
4919         .name          = "repl_meta_data",
4920         .init_context      = replmd_init,
4921         .add               = replmd_add,
4922         .modify            = replmd_modify,
4923         .rename            = replmd_rename,
4924         .del               = replmd_delete,
4925         .extended          = replmd_extended,
4926         .start_transaction = replmd_start_transaction,
4927         .prepare_commit    = replmd_prepare_commit,
4928         .del_transaction   = replmd_del_transaction,
4929 };
4930
4931 int ldb_repl_meta_data_module_init(const char *version)
4932 {
4933         LDB_MODULE_CHECK_VERSION(version);
4934         return ldb_register_module(&ldb_repl_meta_data_module_ops);
4935 }