dsdb: Remove 120 second delay and USN from schema refresh check
[kai/samba-autobuild/.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-2013
6    Copyright (C) Andrew Tridgell 2005-2009
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8    Copyright (C) Matthieu Patou <mat@samba.org> 2010-2011
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         struct ldb_dn *schema_dn;
71 };
72
73 struct la_entry {
74         struct la_entry *next, *prev;
75         struct drsuapi_DsReplicaLinkedAttribute *la;
76 };
77
78 struct replmd_replicated_request {
79         struct ldb_module *module;
80         struct ldb_request *req;
81
82         const struct dsdb_schema *schema;
83         struct GUID our_invocation_id;
84
85         /* the controls we pass down */
86         struct ldb_control **controls;
87
88         /* details for the mode where we apply a bunch of inbound replication meessages */
89         bool apply_mode;
90         uint32_t index_current;
91         struct dsdb_extended_replicated_objects *objs;
92
93         struct ldb_message *search_msg;
94         struct GUID local_parent_guid;
95
96         uint64_t seq_num;
97         bool is_urgent;
98
99         bool isDeleted;
100 };
101
102 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar);
103 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete);
104
105 enum urgent_situation {
106         REPL_URGENT_ON_CREATE = 1,
107         REPL_URGENT_ON_UPDATE = 2,
108         REPL_URGENT_ON_DELETE = 4
109 };
110
111 enum deletion_state {
112         OBJECT_NOT_DELETED=1,
113         OBJECT_DELETED=2,
114         OBJECT_RECYCLED=3,
115         OBJECT_TOMBSTONE=4,
116         OBJECT_REMOVED=5
117 };
118
119 static void replmd_deletion_state(struct ldb_module *module,
120                                   const struct ldb_message *msg,
121                                   enum deletion_state *current_state,
122                                   enum deletion_state *next_state)
123 {
124         int ret;
125         bool enabled = false;
126
127         if (msg == NULL) {
128                 *current_state = OBJECT_REMOVED;
129                 if (next_state != NULL) {
130                         *next_state = OBJECT_REMOVED;
131                 }
132                 return;
133         }
134
135         ret = dsdb_recyclebin_enabled(module, &enabled);
136         if (ret != LDB_SUCCESS) {
137                 enabled = false;
138         }
139
140         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
141                 if (!enabled) {
142                         *current_state = OBJECT_TOMBSTONE;
143                         if (next_state != NULL) {
144                                 *next_state = OBJECT_REMOVED;
145                         }
146                         return;
147                 }
148
149                 if (ldb_msg_check_string_attribute(msg, "isRecycled", "TRUE")) {
150                         *current_state = OBJECT_RECYCLED;
151                         if (next_state != NULL) {
152                                 *next_state = OBJECT_REMOVED;
153                         }
154                         return;
155                 }
156
157                 *current_state = OBJECT_DELETED;
158                 if (next_state != NULL) {
159                         *next_state = OBJECT_RECYCLED;
160                 }
161                 return;
162         }
163
164         *current_state = OBJECT_NOT_DELETED;
165         if (next_state == NULL) {
166                 return;
167         }
168
169         if (enabled) {
170                 *next_state = OBJECT_DELETED;
171         } else {
172                 *next_state = OBJECT_TOMBSTONE;
173         }
174 }
175
176 static const struct {
177         const char *update_name;
178         enum urgent_situation repl_situation;
179 } urgent_objects[] = {
180                 {"nTDSDSA", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
181                 {"crossRef", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE)},
182                 {"attributeSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
183                 {"classSchema", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
184                 {"secret", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
185                 {"rIDManager", (REPL_URGENT_ON_CREATE | REPL_URGENT_ON_UPDATE)},
186                 {NULL, 0}
187 };
188
189 /* Attributes looked for when updating or deleting, to check for a urgent replication needed */
190 static const char *urgent_attrs[] = {
191                 "lockoutTime",
192                 "pwdLastSet",
193                 "userAccountControl",
194                 NULL
195 };
196
197
198 static bool replmd_check_urgent_objectclass(const struct ldb_message_element *objectclass_el,
199                                         enum urgent_situation situation)
200 {
201         unsigned int i, j;
202         for (i=0; urgent_objects[i].update_name; i++) {
203
204                 if ((situation & urgent_objects[i].repl_situation) == 0) {
205                         continue;
206                 }
207
208                 for (j=0; j<objectclass_el->num_values; j++) {
209                         const struct ldb_val *v = &objectclass_el->values[j];
210                         if (ldb_attr_cmp((const char *)v->data, urgent_objects[i].update_name) == 0) {
211                                 return true;
212                         }
213                 }
214         }
215         return false;
216 }
217
218 static bool replmd_check_urgent_attribute(const struct ldb_message_element *el)
219 {
220         if (ldb_attr_in_list(urgent_attrs, el->name)) {
221                 return true;
222         }
223         return false;
224 }
225
226
227 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar);
228
229 /*
230   initialise the module
231   allocate the private structure and build the list
232   of partition DNs for use by replmd_notify()
233  */
234 static int replmd_init(struct ldb_module *module)
235 {
236         struct replmd_private *replmd_private;
237         struct ldb_context *ldb = ldb_module_get_ctx(module);
238
239         replmd_private = talloc_zero(module, struct replmd_private);
240         if (replmd_private == NULL) {
241                 ldb_oom(ldb);
242                 return LDB_ERR_OPERATIONS_ERROR;
243         }
244         ldb_module_set_private(module, replmd_private);
245
246         replmd_private->schema_dn = ldb_get_schema_basedn(ldb);
247
248         return ldb_next_init(module);
249 }
250
251 /*
252   cleanup our per-transaction contexts
253  */
254 static void replmd_txn_cleanup(struct replmd_private *replmd_private)
255 {
256         talloc_free(replmd_private->la_ctx);
257         replmd_private->la_list = NULL;
258         replmd_private->la_ctx = NULL;
259
260         talloc_free(replmd_private->bl_ctx);
261         replmd_private->la_backlinks = NULL;
262         replmd_private->bl_ctx = NULL;
263 }
264
265
266 struct la_backlink {
267         struct la_backlink *next, *prev;
268         const char *attr_name;
269         struct GUID forward_guid, target_guid;
270         bool active;
271 };
272
273 /*
274   process a backlinks we accumulated during a transaction, adding and
275   deleting the backlinks from the target objects
276  */
277 static int replmd_process_backlink(struct ldb_module *module, struct la_backlink *bl, struct ldb_request *parent)
278 {
279         struct ldb_dn *target_dn, *source_dn;
280         int ret;
281         struct ldb_context *ldb = ldb_module_get_ctx(module);
282         struct ldb_message *msg;
283         TALLOC_CTX *tmp_ctx = talloc_new(bl);
284         char *dn_string;
285
286         /*
287           - find DN of target
288           - find DN of source
289           - construct ldb_message
290               - either an add or a delete
291          */
292         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->target_guid, &target_dn, parent);
293         if (ret != LDB_SUCCESS) {
294                 DEBUG(2,(__location__ ": WARNING: Failed to find target DN for linked attribute with GUID %s\n",
295                          GUID_string(bl, &bl->target_guid)));
296                 return LDB_SUCCESS;
297         }
298
299         ret = dsdb_module_dn_by_guid(module, tmp_ctx, &bl->forward_guid, &source_dn, parent);
300         if (ret != LDB_SUCCESS) {
301                 ldb_asprintf_errstring(ldb, "Failed to find source DN for linked attribute with GUID %s\n",
302                                        GUID_string(bl, &bl->forward_guid));
303                 talloc_free(tmp_ctx);
304                 return ret;
305         }
306
307         msg = ldb_msg_new(tmp_ctx);
308         if (msg == NULL) {
309                 ldb_module_oom(module);
310                 talloc_free(tmp_ctx);
311                 return LDB_ERR_OPERATIONS_ERROR;
312         }
313
314         /* construct a ldb_message for adding/deleting the backlink */
315         msg->dn = target_dn;
316         dn_string = ldb_dn_get_extended_linearized(tmp_ctx, source_dn, 1);
317         if (!dn_string) {
318                 ldb_module_oom(module);
319                 talloc_free(tmp_ctx);
320                 return LDB_ERR_OPERATIONS_ERROR;
321         }
322         ret = ldb_msg_add_steal_string(msg, bl->attr_name, dn_string);
323         if (ret != LDB_SUCCESS) {
324                 talloc_free(tmp_ctx);
325                 return ret;
326         }
327         msg->elements[0].flags = bl->active?LDB_FLAG_MOD_ADD:LDB_FLAG_MOD_DELETE;
328
329         /* a backlink should never be single valued. Unfortunately the
330            exchange schema has a attribute
331            msExchBridgeheadedLocalConnectorsDNBL which is single
332            valued and a backlink. We need to cope with that by
333            ignoring the single value flag */
334         msg->elements[0].flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
335
336         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
337         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE && !bl->active) {
338                 /* we allow LDB_ERR_NO_SUCH_ATTRIBUTE as success to
339                    cope with possible corruption where the backlink has
340                    already been removed */
341                 DEBUG(3,("WARNING: backlink from %s already removed from %s - %s\n",
342                          ldb_dn_get_linearized(target_dn),
343                          ldb_dn_get_linearized(source_dn),
344                          ldb_errstring(ldb)));
345                 ret = LDB_SUCCESS;
346         } else if (ret != LDB_SUCCESS) {
347                 ldb_asprintf_errstring(ldb, "Failed to %s backlink from %s to %s - %s",
348                                        bl->active?"add":"remove",
349                                        ldb_dn_get_linearized(source_dn),
350                                        ldb_dn_get_linearized(target_dn),
351                                        ldb_errstring(ldb));
352                 talloc_free(tmp_ctx);
353                 return ret;
354         }
355         talloc_free(tmp_ctx);
356         return ret;
357 }
358
359 /*
360   add a backlink to the list of backlinks to add/delete in the prepare
361   commit
362  */
363 static int replmd_add_backlink(struct ldb_module *module, const struct dsdb_schema *schema,
364                                struct GUID *forward_guid, struct GUID *target_guid,
365                                bool active, const struct dsdb_attribute *schema_attr, bool immediate)
366 {
367         const struct dsdb_attribute *target_attr;
368         struct la_backlink *bl;
369         struct replmd_private *replmd_private =
370                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
371
372         target_attr = dsdb_attribute_by_linkID(schema, schema_attr->linkID ^ 1);
373         if (!target_attr) {
374                 /*
375                  * windows 2003 has a broken schema where the
376                  * definition of msDS-IsDomainFor is missing (which is
377                  * supposed to be the backlink of the
378                  * msDS-HasDomainNCs attribute
379                  */
380                 return LDB_SUCCESS;
381         }
382
383         /* see if its already in the list */
384         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
385                 if (GUID_equal(forward_guid, &bl->forward_guid) &&
386                     GUID_equal(target_guid, &bl->target_guid) &&
387                     (target_attr->lDAPDisplayName == bl->attr_name ||
388                      strcmp(target_attr->lDAPDisplayName, bl->attr_name) == 0)) {
389                         break;
390                 }
391         }
392
393         if (bl) {
394                 /* we found an existing one */
395                 if (bl->active == active) {
396                         return LDB_SUCCESS;
397                 }
398                 DLIST_REMOVE(replmd_private->la_backlinks, bl);
399                 talloc_free(bl);
400                 return LDB_SUCCESS;
401         }
402
403         if (replmd_private->bl_ctx == NULL) {
404                 replmd_private->bl_ctx = talloc_new(replmd_private);
405                 if (replmd_private->bl_ctx == NULL) {
406                         ldb_module_oom(module);
407                         return LDB_ERR_OPERATIONS_ERROR;
408                 }
409         }
410
411         /* its a new one */
412         bl = talloc(replmd_private->bl_ctx, struct la_backlink);
413         if (bl == NULL) {
414                 ldb_module_oom(module);
415                 return LDB_ERR_OPERATIONS_ERROR;
416         }
417
418         /* Ensure the schema does not go away before the bl->attr_name is used */
419         if (!talloc_reference(bl, schema)) {
420                 talloc_free(bl);
421                 ldb_module_oom(module);
422                 return LDB_ERR_OPERATIONS_ERROR;
423         }
424
425         bl->attr_name = target_attr->lDAPDisplayName;
426         bl->forward_guid = *forward_guid;
427         bl->target_guid = *target_guid;
428         bl->active = active;
429
430         /* the caller may ask for this backlink to be processed
431            immediately */
432         if (immediate) {
433                 int ret = replmd_process_backlink(module, bl, NULL);
434                 talloc_free(bl);
435                 return ret;
436         }
437
438         DLIST_ADD(replmd_private->la_backlinks, bl);
439
440         return LDB_SUCCESS;
441 }
442
443
444 /*
445  * Callback for most write operations in this module:
446  *
447  * notify the repl task that a object has changed. The notifies are
448  * gathered up in the replmd_private structure then written to the
449  * @REPLCHANGED object in each partition during the prepare_commit
450  */
451 static int replmd_op_callback(struct ldb_request *req, struct ldb_reply *ares)
452 {
453         int ret;
454         struct replmd_replicated_request *ac =
455                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
456         struct replmd_private *replmd_private =
457                 talloc_get_type_abort(ldb_module_get_private(ac->module), struct replmd_private);
458         struct nc_entry *modified_partition;
459         struct ldb_control *partition_ctrl;
460         const struct dsdb_control_current_partition *partition;
461
462         struct ldb_control **controls;
463
464         partition_ctrl = ldb_reply_get_control(ares, DSDB_CONTROL_CURRENT_PARTITION_OID);
465
466         controls = ares->controls;
467         if (ldb_request_get_control(ac->req,
468                                     DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
469                 /*
470                  * Remove the current partition control from what we pass up
471                  * the chain if it hasn't been requested manually.
472                  */
473                 controls = ldb_controls_except_specified(ares->controls, ares,
474                                                          partition_ctrl);
475         }
476
477         if (ares->error != LDB_SUCCESS) {
478                 DEBUG(5,("%s failure. Error is: %s\n", __FUNCTION__, ldb_strerror(ares->error)));
479                 return ldb_module_done(ac->req, controls,
480                                         ares->response, ares->error);
481         }
482
483         if (ares->type != LDB_REPLY_DONE) {
484                 ldb_set_errstring(ldb_module_get_ctx(ac->module), "Invalid reply type for notify\n!");
485                 return ldb_module_done(ac->req, NULL,
486                                        NULL, LDB_ERR_OPERATIONS_ERROR);
487         }
488
489         if (!partition_ctrl) {
490                 ldb_set_errstring(ldb_module_get_ctx(ac->module),"No partition control on reply");
491                 return ldb_module_done(ac->req, NULL,
492                                        NULL, LDB_ERR_OPERATIONS_ERROR);
493         }
494
495         partition = talloc_get_type_abort(partition_ctrl->data,
496                                     struct dsdb_control_current_partition);
497
498         if (ac->seq_num > 0) {
499                 for (modified_partition = replmd_private->ncs; modified_partition;
500                      modified_partition = modified_partition->next) {
501                         if (ldb_dn_compare(modified_partition->dn, partition->dn) == 0) {
502                                 break;
503                         }
504                 }
505
506                 if (modified_partition == NULL) {
507                         modified_partition = talloc_zero(replmd_private, struct nc_entry);
508                         if (!modified_partition) {
509                                 ldb_oom(ldb_module_get_ctx(ac->module));
510                                 return ldb_module_done(ac->req, NULL,
511                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
512                         }
513                         modified_partition->dn = ldb_dn_copy(modified_partition, partition->dn);
514                         if (!modified_partition->dn) {
515                                 ldb_oom(ldb_module_get_ctx(ac->module));
516                                 return ldb_module_done(ac->req, NULL,
517                                                        NULL, LDB_ERR_OPERATIONS_ERROR);
518                         }
519                         DLIST_ADD(replmd_private->ncs, modified_partition);
520                 }
521
522                 if (ac->seq_num > modified_partition->mod_usn) {
523                         modified_partition->mod_usn = ac->seq_num;
524                         if (ac->is_urgent) {
525                                 modified_partition->mod_usn_urgent = ac->seq_num;
526                         }
527                 }
528         }
529
530         if (ac->apply_mode) {
531                 ret = replmd_replicated_apply_isDeleted(ac);
532                 if (ret != LDB_SUCCESS) {
533                         return ldb_module_done(ac->req, NULL, NULL, ret);
534                 }
535                 return ret;
536         } else {
537                 /* free the partition control container here, for the
538                  * common path.  Other cases will have it cleaned up
539                  * eventually with the ares */
540                 talloc_free(partition_ctrl);
541                 return ldb_module_done(ac->req, controls,
542                                        ares->response, LDB_SUCCESS);
543         }
544 }
545
546
547 /*
548  * update a @REPLCHANGED record in each partition if there have been
549  * any writes of replicated data in the partition
550  */
551 static int replmd_notify_store(struct ldb_module *module, struct ldb_request *parent)
552 {
553         struct replmd_private *replmd_private =
554                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
555
556         while (replmd_private->ncs) {
557                 int ret;
558                 struct nc_entry *modified_partition = replmd_private->ncs;
559
560                 ret = dsdb_module_save_partition_usn(module, modified_partition->dn,
561                                                      modified_partition->mod_usn,
562                                                      modified_partition->mod_usn_urgent, parent);
563                 if (ret != LDB_SUCCESS) {
564                         DEBUG(0,(__location__ ": Failed to save partition uSN for %s\n",
565                                  ldb_dn_get_linearized(modified_partition->dn)));
566                         return ret;
567                 }
568
569                 if (ldb_dn_compare(modified_partition->dn,
570                                    replmd_private->schema_dn) == 0) {
571                         struct ldb_result *ext_res;
572                         ret = dsdb_module_extended(module,
573                                                    replmd_private->schema_dn,
574                                                    &ext_res,
575                                                    DSDB_EXTENDED_SCHEMA_UPDATE_NOW_OID,
576                                                    ext_res,
577                                                    DSDB_FLAG_NEXT_MODULE,
578                                                    parent);
579                         if (ret != LDB_SUCCESS) {
580                                 return ret;
581                         }
582                         talloc_free(ext_res);
583                 }
584
585                 DLIST_REMOVE(replmd_private->ncs, modified_partition);
586                 talloc_free(modified_partition);
587         }
588
589         return LDB_SUCCESS;
590 }
591
592
593 /*
594   created a replmd_replicated_request context
595  */
596 static struct replmd_replicated_request *replmd_ctx_init(struct ldb_module *module,
597                                                          struct ldb_request *req)
598 {
599         struct ldb_context *ldb;
600         struct replmd_replicated_request *ac;
601         const struct GUID *our_invocation_id;
602
603         ldb = ldb_module_get_ctx(module);
604
605         ac = talloc_zero(req, struct replmd_replicated_request);
606         if (ac == NULL) {
607                 ldb_oom(ldb);
608                 return NULL;
609         }
610
611         ac->module = module;
612         ac->req = req;
613
614         ac->schema = dsdb_get_schema(ldb, ac);
615         if (!ac->schema) {
616                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
617                               "replmd_modify: no dsdb_schema loaded");
618                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
619                 talloc_free(ac);
620                 return NULL;
621         }
622
623         /* get our invocationId */
624         our_invocation_id = samdb_ntds_invocation_id(ldb);
625         if (!our_invocation_id) {
626                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
627                               "replmd_add: unable to find invocationId\n");
628                 talloc_free(ac);
629                 return NULL;
630         }
631         ac->our_invocation_id = *our_invocation_id;
632
633         return ac;
634 }
635
636 /*
637   add a time element to a record
638 */
639 static int add_time_element(struct ldb_message *msg, const char *attr, time_t t)
640 {
641         struct ldb_message_element *el;
642         char *s;
643         int ret;
644
645         if (ldb_msg_find_element(msg, attr) != NULL) {
646                 return LDB_SUCCESS;
647         }
648
649         s = ldb_timestring(msg, t);
650         if (s == NULL) {
651                 return LDB_ERR_OPERATIONS_ERROR;
652         }
653
654         ret = ldb_msg_add_string(msg, attr, s);
655         if (ret != LDB_SUCCESS) {
656                 return ret;
657         }
658
659         el = ldb_msg_find_element(msg, attr);
660         /* always set as replace. This works because on add ops, the flag
661            is ignored */
662         el->flags = LDB_FLAG_MOD_REPLACE;
663
664         return LDB_SUCCESS;
665 }
666
667 /*
668   add a uint64_t element to a record
669 */
670 static int add_uint64_element(struct ldb_context *ldb, struct ldb_message *msg,
671                               const char *attr, uint64_t v)
672 {
673         struct ldb_message_element *el;
674         int ret;
675
676         if (ldb_msg_find_element(msg, attr) != NULL) {
677                 return LDB_SUCCESS;
678         }
679
680         ret = samdb_msg_add_uint64(ldb, msg, msg, attr, v);
681         if (ret != LDB_SUCCESS) {
682                 return ret;
683         }
684
685         el = ldb_msg_find_element(msg, attr);
686         /* always set as replace. This works because on add ops, the flag
687            is ignored */
688         el->flags = LDB_FLAG_MOD_REPLACE;
689
690         return LDB_SUCCESS;
691 }
692
693 static int replmd_replPropertyMetaData1_attid_sort(const struct replPropertyMetaData1 *m1,
694                                                    const struct replPropertyMetaData1 *m2,
695                                                    const uint32_t *rdn_attid)
696 {
697         /*
698          * This assignment seems inoccous, but it is critical for the
699          * system, as we need to do the comparisons as a unsigned
700          * quantity, not signed (enums are signed integers)
701          */
702         uint32_t attid_1 = m1->attid;
703         uint32_t attid_2 = m2->attid;
704
705         if (attid_1 == attid_2) {
706                 return 0;
707         }
708
709         /*
710          * See above regarding this being an unsigned comparison.
711          * Otherwise when the high bit is set on non-standard
712          * attributes, they would end up first, before objectClass
713          * (0).
714          */
715         return attid_1 > attid_2 ? 1 : -1;
716 }
717
718 static int replmd_replPropertyMetaDataCtr1_verify(struct ldb_context *ldb,
719                                                   struct replPropertyMetaDataCtr1 *ctr1,
720                                                   struct ldb_dn *dn)
721 {
722         if (ctr1->count == 0) {
723                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
724                               "No elements found in replPropertyMetaData for %s!\n",
725                               ldb_dn_get_linearized(dn));
726                 return LDB_ERR_CONSTRAINT_VIOLATION;
727         }
728
729         /* the objectClass attribute is value 0x00000000, so must be first */
730         if (ctr1->array[0].attid != DRSUAPI_ATTID_objectClass) {
731                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
732                               "No objectClass found in replPropertyMetaData for %s!\n",
733                               ldb_dn_get_linearized(dn));
734                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
735         }
736
737         return LDB_SUCCESS;
738 }
739
740 static int replmd_replPropertyMetaDataCtr1_sort_and_verify(struct ldb_context *ldb,
741                                                            struct replPropertyMetaDataCtr1 *ctr1,
742                                                            struct ldb_dn *dn)
743 {
744         /* Note this is O(n^2) for the almost-sorted case, which this is */
745         LDB_TYPESAFE_QSORT(ctr1->array, ctr1->count, NULL,
746                            replmd_replPropertyMetaData1_attid_sort);
747         return replmd_replPropertyMetaDataCtr1_verify(ldb, ctr1, dn);
748 }
749
750 static int replmd_ldb_message_element_attid_sort(const struct ldb_message_element *e1,
751                                                  const struct ldb_message_element *e2,
752                                                  const struct dsdb_schema *schema)
753 {
754         const struct dsdb_attribute *a1;
755         const struct dsdb_attribute *a2;
756
757         /*
758          * TODO: make this faster by caching the dsdb_attribute pointer
759          *       on the ldb_messag_element
760          */
761
762         a1 = dsdb_attribute_by_lDAPDisplayName(schema, e1->name);
763         a2 = dsdb_attribute_by_lDAPDisplayName(schema, e2->name);
764
765         /*
766          * TODO: remove this check, we should rely on e1 and e2 having valid attribute names
767          *       in the schema
768          */
769         if (!a1 || !a2) {
770                 return strcasecmp(e1->name, e2->name);
771         }
772         if (a1->attributeID_id == a2->attributeID_id) {
773                 return 0;
774         }
775         return a1->attributeID_id > a2->attributeID_id ? 1 : -1;
776 }
777
778 static void replmd_ldb_message_sort(struct ldb_message *msg,
779                                     const struct dsdb_schema *schema)
780 {
781         LDB_TYPESAFE_QSORT(msg->elements, msg->num_elements, schema, replmd_ldb_message_element_attid_sort);
782 }
783
784 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
785                                const struct GUID *invocation_id, uint64_t seq_num,
786                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted);
787
788
789 /*
790   fix up linked attributes in replmd_add.
791   This involves setting up the right meta-data in extended DN
792   components, and creating backlinks to the object
793  */
794 static int replmd_add_fix_la(struct ldb_module *module, struct ldb_message_element *el,
795                              uint64_t seq_num, const struct GUID *invocationId, NTTIME now,
796                              struct GUID *guid, const struct dsdb_attribute *sa, struct ldb_request *parent)
797 {
798         unsigned int i;
799         TALLOC_CTX *tmp_ctx = talloc_new(el->values);
800         struct ldb_context *ldb = ldb_module_get_ctx(module);
801
802         /* We will take a reference to the schema in replmd_add_backlink */
803         const struct dsdb_schema *schema = dsdb_get_schema(ldb, NULL);
804
805         for (i=0; i<el->num_values; i++) {
806                 struct ldb_val *v = &el->values[i];
807                 struct dsdb_dn *dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, v, sa->syntax->ldap_oid);
808                 struct GUID target_guid;
809                 NTSTATUS status;
810                 int ret;
811
812                 /* note that the DN already has the extended
813                    components from the extended_dn_store module */
814                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
815                 if (!NT_STATUS_IS_OK(status) || GUID_all_zero(&target_guid)) {
816                         ret = dsdb_module_guid_by_dn(module, dsdb_dn->dn, &target_guid, parent);
817                         if (ret != LDB_SUCCESS) {
818                                 talloc_free(tmp_ctx);
819                                 return ret;
820                         }
821                         ret = dsdb_set_extended_dn_guid(dsdb_dn->dn, &target_guid, "GUID");
822                         if (ret != LDB_SUCCESS) {
823                                 talloc_free(tmp_ctx);
824                                 return ret;
825                         }
826                 }
827
828                 ret = replmd_build_la_val(el->values, v, dsdb_dn, invocationId,
829                                           seq_num, seq_num, now, 0, false);
830                 if (ret != LDB_SUCCESS) {
831                         talloc_free(tmp_ctx);
832                         return ret;
833                 }
834
835                 ret = replmd_add_backlink(module, schema, guid, &target_guid, true, sa, false);
836                 if (ret != LDB_SUCCESS) {
837                         talloc_free(tmp_ctx);
838                         return ret;
839                 }
840         }
841
842         talloc_free(tmp_ctx);
843         return LDB_SUCCESS;
844 }
845
846
847 /*
848   intercept add requests
849  */
850 static int replmd_add(struct ldb_module *module, struct ldb_request *req)
851 {
852         struct ldb_context *ldb;
853         struct ldb_control *control;
854         struct replmd_replicated_request *ac;
855         enum ndr_err_code ndr_err;
856         struct ldb_request *down_req;
857         struct ldb_message *msg;
858         const DATA_BLOB *guid_blob;
859         struct GUID guid;
860         struct replPropertyMetaDataBlob nmd;
861         struct ldb_val nmd_value;
862
863         /*
864          * The use of a time_t here seems odd, but as the NTTIME
865          * elements are actually declared as NTTIME_1sec in the IDL,
866          * getting a higher resolution timestamp is not required.
867          */
868         time_t t = time(NULL);
869         NTTIME now;
870         char *time_str;
871         int ret;
872         unsigned int i;
873         unsigned int functional_level;
874         uint32_t ni=0;
875         bool allow_add_guid = false;
876         bool remove_current_guid = false;
877         bool is_urgent = false;
878         bool is_schema_nc = false;
879         struct ldb_message_element *objectclass_el;
880         struct replmd_private *replmd_private =
881                 talloc_get_type_abort(ldb_module_get_private(module), struct replmd_private);
882
883         /* check if there's a show relax control (used by provision to say 'I know what I'm doing') */
884         control = ldb_request_get_control(req, LDB_CONTROL_RELAX_OID);
885         if (control) {
886                 allow_add_guid = true;
887         }
888
889         /* do not manipulate our control entries */
890         if (ldb_dn_is_special(req->op.add.message->dn)) {
891                 return ldb_next_request(module, req);
892         }
893
894         ldb = ldb_module_get_ctx(module);
895
896         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_add\n");
897
898         guid_blob = ldb_msg_find_ldb_val(req->op.add.message, "objectGUID");
899         if (guid_blob != NULL) {
900                 if (!allow_add_guid) {
901                         ldb_set_errstring(ldb,
902                                           "replmd_add: it's not allowed to add an object with objectGUID!");
903                         return LDB_ERR_UNWILLING_TO_PERFORM;
904                 } else {
905                         NTSTATUS status = GUID_from_data_blob(guid_blob,&guid);
906                         if (!NT_STATUS_IS_OK(status)) {
907                                 ldb_set_errstring(ldb,
908                                                   "replmd_add: Unable to parse the 'objectGUID' as a GUID!");
909                                 return LDB_ERR_UNWILLING_TO_PERFORM;
910                         }
911                         /* we remove this attribute as it can be a string and
912                          * will not be treated correctly and then we will re-add
913                          * it later on in the good format */
914                         remove_current_guid = true;
915                 }
916         } else {
917                 /* a new GUID */
918                 guid = GUID_random();
919         }
920
921         ac = replmd_ctx_init(module, req);
922         if (ac == NULL) {
923                 return ldb_module_oom(module);
924         }
925
926         functional_level = dsdb_functional_level(ldb);
927
928         /* Get a sequence number from the backend */
929         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ac->seq_num);
930         if (ret != LDB_SUCCESS) {
931                 talloc_free(ac);
932                 return ret;
933         }
934
935         /* we have to copy the message as the caller might have it as a const */
936         msg = ldb_msg_copy_shallow(ac, req->op.add.message);
937         if (msg == NULL) {
938                 ldb_oom(ldb);
939                 talloc_free(ac);
940                 return LDB_ERR_OPERATIONS_ERROR;
941         }
942
943         /* generated times */
944         unix_to_nt_time(&now, t);
945         time_str = ldb_timestring(msg, t);
946         if (!time_str) {
947                 ldb_oom(ldb);
948                 talloc_free(ac);
949                 return LDB_ERR_OPERATIONS_ERROR;
950         }
951         if (remove_current_guid) {
952                 ldb_msg_remove_attr(msg,"objectGUID");
953         }
954
955         /*
956          * remove autogenerated attributes
957          */
958         ldb_msg_remove_attr(msg, "whenCreated");
959         ldb_msg_remove_attr(msg, "whenChanged");
960         ldb_msg_remove_attr(msg, "uSNCreated");
961         ldb_msg_remove_attr(msg, "uSNChanged");
962         ldb_msg_remove_attr(msg, "replPropertyMetaData");
963
964         /*
965          * readd replicated attributes
966          */
967         ret = ldb_msg_add_string(msg, "whenCreated", time_str);
968         if (ret != LDB_SUCCESS) {
969                 ldb_oom(ldb);
970                 talloc_free(ac);
971                 return ret;
972         }
973
974         /* build the replication meta_data */
975         ZERO_STRUCT(nmd);
976         nmd.version             = 1;
977         nmd.ctr.ctr1.count      = msg->num_elements;
978         nmd.ctr.ctr1.array      = talloc_array(msg,
979                                                struct replPropertyMetaData1,
980                                                nmd.ctr.ctr1.count);
981         if (!nmd.ctr.ctr1.array) {
982                 ldb_oom(ldb);
983                 talloc_free(ac);
984                 return LDB_ERR_OPERATIONS_ERROR;
985         }
986
987         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
988
989         for (i=0; i < msg->num_elements; i++) {
990                 struct ldb_message_element *e = &msg->elements[i];
991                 struct replPropertyMetaData1 *m = &nmd.ctr.ctr1.array[ni];
992                 const struct dsdb_attribute *sa;
993
994                 if (e->name[0] == '@') continue;
995
996                 sa = dsdb_attribute_by_lDAPDisplayName(ac->schema, e->name);
997                 if (!sa) {
998                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
999                                       "replmd_add: attribute '%s' not defined in schema\n",
1000                                       e->name);
1001                         talloc_free(ac);
1002                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
1003                 }
1004
1005                 if ((sa->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (sa->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1006                         /* if the attribute is not replicated (0x00000001)
1007                          * or constructed (0x00000004) it has no metadata
1008                          */
1009                         continue;
1010                 }
1011
1012                 if (sa->linkID != 0 && functional_level > DS_DOMAIN_FUNCTION_2000) {
1013                         ret = replmd_add_fix_la(module, e, ac->seq_num,
1014                                                 &ac->our_invocation_id, now,
1015                                                 &guid, sa, req);
1016                         if (ret != LDB_SUCCESS) {
1017                                 talloc_free(ac);
1018                                 return ret;
1019                         }
1020                         /* linked attributes are not stored in
1021                            replPropertyMetaData in FL above w2k */
1022                         continue;
1023                 }
1024
1025                 m->attid   = dsdb_attribute_get_attid(sa, is_schema_nc);
1026                 m->version = 1;
1027                 if (m->attid == DRSUAPI_ATTID_isDeleted) {
1028                         const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1029                         const char* rdn;
1030
1031                         if (rdn_val == NULL) {
1032                                 ldb_oom(ldb);
1033                                 talloc_free(ac);
1034                                 return LDB_ERR_OPERATIONS_ERROR;
1035                         }
1036
1037                         rdn = (const char*)rdn_val->data;
1038                         if (strcmp(rdn, "Deleted Objects") == 0) {
1039                                 /*
1040                                  * Set the originating_change_time to 29/12/9999 at 23:59:59
1041                                  * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1042                                  */
1043                                 m->originating_change_time      = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1044                         } else {
1045                                 m->originating_change_time      = now;
1046                         }
1047                 } else {
1048                         m->originating_change_time      = now;
1049                 }
1050                 m->originating_invocation_id    = ac->our_invocation_id;
1051                 m->originating_usn              = ac->seq_num;
1052                 m->local_usn                    = ac->seq_num;
1053                 ni++;
1054         }
1055
1056         /* fix meta data count */
1057         nmd.ctr.ctr1.count = ni;
1058
1059         /*
1060          * sort meta data array
1061          */
1062         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
1063         if (ret != LDB_SUCCESS) {
1064                 ldb_asprintf_errstring(ldb, "%s: error during direct ADD: %s", __func__, ldb_errstring(ldb));
1065                 talloc_free(ac);
1066                 return ret;
1067         }
1068
1069         /* generated NDR encoded values */
1070         ndr_err = ndr_push_struct_blob(&nmd_value, msg,
1071                                        &nmd,
1072                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1073         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1074                 ldb_oom(ldb);
1075                 talloc_free(ac);
1076                 return LDB_ERR_OPERATIONS_ERROR;
1077         }
1078
1079         /*
1080          * add the autogenerated values
1081          */
1082         ret = dsdb_msg_add_guid(msg, &guid, "objectGUID");
1083         if (ret != LDB_SUCCESS) {
1084                 ldb_oom(ldb);
1085                 talloc_free(ac);
1086                 return ret;
1087         }
1088         ret = ldb_msg_add_string(msg, "whenChanged", time_str);
1089         if (ret != LDB_SUCCESS) {
1090                 ldb_oom(ldb);
1091                 talloc_free(ac);
1092                 return ret;
1093         }
1094         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ac->seq_num);
1095         if (ret != LDB_SUCCESS) {
1096                 ldb_oom(ldb);
1097                 talloc_free(ac);
1098                 return ret;
1099         }
1100         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ac->seq_num);
1101         if (ret != LDB_SUCCESS) {
1102                 ldb_oom(ldb);
1103                 talloc_free(ac);
1104                 return ret;
1105         }
1106         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
1107         if (ret != LDB_SUCCESS) {
1108                 ldb_oom(ldb);
1109                 talloc_free(ac);
1110                 return ret;
1111         }
1112
1113         /*
1114          * sort the attributes by attid before storing the object
1115          */
1116         replmd_ldb_message_sort(msg, ac->schema);
1117
1118         /*
1119          * Assert that we do have an objectClass
1120          */
1121         objectclass_el = ldb_msg_find_element(msg, "objectClass");
1122         if (objectclass_el == NULL) {
1123                 ldb_asprintf_errstring(ldb, __location__
1124                                        ": objectClass missing on %s\n",
1125                                        ldb_dn_get_linearized(msg->dn));
1126                 talloc_free(ac);
1127                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1128         }
1129         is_urgent = replmd_check_urgent_objectclass(objectclass_el,
1130                                                         REPL_URGENT_ON_CREATE);
1131
1132         ac->is_urgent = is_urgent;
1133         ret = ldb_build_add_req(&down_req, ldb, ac,
1134                                 msg,
1135                                 req->controls,
1136                                 ac, replmd_op_callback,
1137                                 req);
1138
1139         LDB_REQ_SET_LOCATION(down_req);
1140         if (ret != LDB_SUCCESS) {
1141                 talloc_free(ac);
1142                 return ret;
1143         }
1144
1145         /* current partition control is needed by "replmd_op_callback" */
1146         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
1147                 ret = ldb_request_add_control(down_req,
1148                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
1149                                               false, NULL);
1150                 if (ret != LDB_SUCCESS) {
1151                         talloc_free(ac);
1152                         return ret;
1153                 }
1154         }
1155
1156         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
1157                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
1158                 if (ret != LDB_SUCCESS) {
1159                         talloc_free(ac);
1160                         return ret;
1161                 }
1162         }
1163
1164         /* mark the control done */
1165         if (control) {
1166                 control->critical = 0;
1167         }
1168         /* go on with the call chain */
1169         return ldb_next_request(module, down_req);
1170 }
1171
1172
1173 /*
1174  * update the replPropertyMetaData for one element
1175  */
1176 static int replmd_update_rpmd_element(struct ldb_context *ldb,
1177                                       struct ldb_message *msg,
1178                                       struct ldb_message_element *el,
1179                                       struct ldb_message_element *old_el,
1180                                       struct replPropertyMetaDataBlob *omd,
1181                                       const struct dsdb_schema *schema,
1182                                       uint64_t *seq_num,
1183                                       const struct GUID *our_invocation_id,
1184                                       NTTIME now,
1185                                       bool is_schema_nc,
1186                                       struct ldb_request *req)
1187 {
1188         uint32_t i;
1189         const struct dsdb_attribute *a;
1190         struct replPropertyMetaData1 *md1;
1191         bool may_skip = false;
1192         uint32_t attid;
1193
1194         a = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
1195         if (a == NULL) {
1196                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
1197                         /* allow this to make it possible for dbcheck
1198                            to remove bad attributes */
1199                         return LDB_SUCCESS;
1200                 }
1201
1202                 DEBUG(0,(__location__ ": Unable to find attribute %s in schema\n",
1203                          el->name));
1204                 return LDB_ERR_OPERATIONS_ERROR;
1205         }
1206
1207         attid = dsdb_attribute_get_attid(a, is_schema_nc);
1208
1209         if ((a->systemFlags & DS_FLAG_ATTR_NOT_REPLICATED) || (a->systemFlags & DS_FLAG_ATTR_IS_CONSTRUCTED)) {
1210                 return LDB_SUCCESS;
1211         }
1212
1213         /*
1214          * if the attribute's value haven't changed, and this isn't
1215          * just a delete of everything then return LDB_SUCCESS Unless
1216          * we have the provision control or if the attribute is
1217          * interSiteTopologyGenerator as this page explain:
1218          * http://support.microsoft.com/kb/224815 this attribute is
1219          * periodicaly written by the DC responsible for the intersite
1220          * generation in a given site
1221          *
1222          * Unchanged could be deleting or replacing an already-gone
1223          * thing with an unconstrained delete/empty replace or a
1224          * replace with the same value, but not an add with the same
1225          * value because that could be about adding a duplicate (which
1226          * is for someone else to error out on).
1227          */
1228         if (old_el != NULL && ldb_msg_element_equal_ordered(el, old_el)) {
1229                 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1230                         may_skip = true;
1231                 }
1232         } else if (old_el == NULL && el->num_values == 0) {
1233                 if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_REPLACE) {
1234                         may_skip = true;
1235                 } else if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
1236                         may_skip = true;
1237                 }
1238         }
1239
1240         if (may_skip) {
1241                 if (strcmp(el->name, "interSiteTopologyGenerator") != 0 &&
1242                     !ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID)) {
1243                         /*
1244                          * allow this to make it possible for dbcheck
1245                          * to rebuild broken metadata
1246                          */
1247                         return LDB_SUCCESS;
1248                 }
1249         }
1250
1251         for (i=0; i<omd->ctr.ctr1.count; i++) {
1252                 /*
1253                  * First check if we find it under the msDS-IntID,
1254                  * then check if we find it under the OID and
1255                  * prefixMap ID.
1256                  *
1257                  * This allows the administrator to simply re-write
1258                  * the attributes and so restore replication, which is
1259                  * likely what they will try to do.
1260                  */
1261                 if (attid == omd->ctr.ctr1.array[i].attid) {
1262                         break;
1263                 }
1264
1265                 if (a->attributeID_id == omd->ctr.ctr1.array[i].attid) {
1266                         break;
1267                 }
1268         }
1269
1270         if (a->linkID != 0 && dsdb_functional_level(ldb) > DS_DOMAIN_FUNCTION_2000) {
1271                 /* linked attributes are not stored in
1272                    replPropertyMetaData in FL above w2k, but we do
1273                    raise the seqnum for the object  */
1274                 if (*seq_num == 0 &&
1275                     ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num) != LDB_SUCCESS) {
1276                         return LDB_ERR_OPERATIONS_ERROR;
1277                 }
1278                 return LDB_SUCCESS;
1279         }
1280
1281         if (i == omd->ctr.ctr1.count) {
1282                 /* we need to add a new one */
1283                 omd->ctr.ctr1.array = talloc_realloc(msg, omd->ctr.ctr1.array,
1284                                                      struct replPropertyMetaData1, omd->ctr.ctr1.count+1);
1285                 if (omd->ctr.ctr1.array == NULL) {
1286                         ldb_oom(ldb);
1287                         return LDB_ERR_OPERATIONS_ERROR;
1288                 }
1289                 omd->ctr.ctr1.count++;
1290                 ZERO_STRUCT(omd->ctr.ctr1.array[i]);
1291         }
1292
1293         /* Get a new sequence number from the backend. We only do this
1294          * if we have a change that requires a new
1295          * replPropertyMetaData element
1296          */
1297         if (*seq_num == 0) {
1298                 int ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, seq_num);
1299                 if (ret != LDB_SUCCESS) {
1300                         return LDB_ERR_OPERATIONS_ERROR;
1301                 }
1302         }
1303
1304         md1 = &omd->ctr.ctr1.array[i];
1305         md1->version++;
1306         md1->attid = attid;
1307         if (md1->attid == DRSUAPI_ATTID_isDeleted) {
1308                 const struct ldb_val *rdn_val = ldb_dn_get_rdn_val(msg->dn);
1309                 const char* rdn;
1310
1311                 if (rdn_val == NULL) {
1312                         ldb_oom(ldb);
1313                         return LDB_ERR_OPERATIONS_ERROR;
1314                 }
1315
1316                 rdn = (const char*)rdn_val->data;
1317                 if (strcmp(rdn, "Deleted Objects") == 0) {
1318                         /*
1319                          * Set the originating_change_time to 29/12/9999 at 23:59:59
1320                          * as specified in MS-ADTS 7.1.1.4.2 Deleted Objects Container
1321                          */
1322                         md1->originating_change_time    = DELETED_OBJECT_CONTAINER_CHANGE_TIME;
1323                 } else {
1324                         md1->originating_change_time    = now;
1325                 }
1326         } else {
1327                 md1->originating_change_time    = now;
1328         }
1329         md1->originating_invocation_id = *our_invocation_id;
1330         md1->originating_usn           = *seq_num;
1331         md1->local_usn                 = *seq_num;
1332
1333         return LDB_SUCCESS;
1334 }
1335
1336 /*
1337  * Bump the replPropertyMetaData version on an attribute, and if it
1338  * has changed (or forced by leaving rdn_old NULL), update the value
1339  * in the entry.
1340  *
1341  * This is important, as calling a modify operation may not change the
1342  * version number if the values appear unchanged, but a rename between
1343  * parents bumps this value.
1344  *
1345  */
1346 static int replmd_update_rpmd_rdn_attr(struct ldb_context *ldb,
1347                                        struct ldb_message *msg,
1348                                        const struct ldb_val *rdn_new,
1349                                        const struct ldb_val *rdn_old,
1350                                        struct replPropertyMetaDataBlob *omd,
1351                                        struct replmd_replicated_request *ar,
1352                                        NTTIME now,
1353                                        bool is_schema_nc)
1354 {
1355         struct ldb_message_element new_el = {
1356                 .flags = LDB_FLAG_MOD_REPLACE,
1357                 .name = ldb_dn_get_rdn_name(msg->dn),
1358                 .num_values = 1,
1359                 .values = discard_const_p(struct ldb_val, rdn_new)
1360         };
1361         struct ldb_message_element old_el = {
1362                 .flags = LDB_FLAG_MOD_REPLACE,
1363                 .name = ldb_dn_get_rdn_name(msg->dn),
1364                 .num_values = rdn_old ? 1 : 0,
1365                 .values = discard_const_p(struct ldb_val, rdn_old)
1366         };
1367
1368         if (ldb_msg_element_equal_ordered(&new_el, &old_el) == false) {
1369                 int ret = ldb_msg_add(msg, &new_el, LDB_FLAG_MOD_REPLACE);
1370                 if (ret != LDB_SUCCESS) {
1371                         return ldb_oom(ldb);
1372                 }
1373         }
1374
1375         return replmd_update_rpmd_element(ldb, msg, &new_el, NULL,
1376                                           omd, ar->schema, &ar->seq_num,
1377                                           &ar->our_invocation_id,
1378                                           now, is_schema_nc, ar->req);
1379
1380 }
1381
1382 static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd)
1383 {
1384         uint32_t count = omd.ctr.ctr1.count;
1385         uint64_t max = 0;
1386         uint32_t i;
1387         for (i=0; i < count; i++) {
1388                 struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i];
1389                 if (max < m.local_usn) {
1390                         max = m.local_usn;
1391                 }
1392         }
1393         return max;
1394 }
1395
1396 /*
1397  * update the replPropertyMetaData object each time we modify an
1398  * object. This is needed for DRS replication, as the merge on the
1399  * client is based on this object
1400  */
1401 static int replmd_update_rpmd(struct ldb_module *module,
1402                               const struct dsdb_schema *schema,
1403                               struct ldb_request *req,
1404                               const char * const *rename_attrs,
1405                               struct ldb_message *msg, uint64_t *seq_num,
1406                               time_t t, bool is_schema_nc,
1407                               bool *is_urgent, bool *rodc)
1408 {
1409         const struct ldb_val *omd_value;
1410         enum ndr_err_code ndr_err;
1411         struct replPropertyMetaDataBlob omd;
1412         unsigned int i;
1413         NTTIME now;
1414         const struct GUID *our_invocation_id;
1415         int ret;
1416         const char * const *attrs = NULL;
1417         const char * const attrs2[] = { "uSNChanged", "objectClass", "instanceType", NULL };
1418         struct ldb_result *res;
1419         struct ldb_context *ldb;
1420         struct ldb_message_element *objectclass_el;
1421         enum urgent_situation situation;
1422         bool rmd_is_provided;
1423         bool rmd_is_just_resorted = false;
1424         const char *not_rename_attrs[4 + msg->num_elements];
1425         
1426         if (rename_attrs) {
1427                 attrs = rename_attrs;
1428         } else {
1429                 for (i = 0; i < msg->num_elements; i++) {
1430                         not_rename_attrs[i] = msg->elements[i].name;
1431                 }
1432                 not_rename_attrs[i] = "replPropertyMetaData";
1433                 not_rename_attrs[i+1] = "objectClass";
1434                 not_rename_attrs[i+2] = "instanceType";
1435                 not_rename_attrs[i+3] = NULL;
1436                 attrs = not_rename_attrs;
1437         }
1438
1439         ldb = ldb_module_get_ctx(module);
1440
1441         our_invocation_id = samdb_ntds_invocation_id(ldb);
1442         if (!our_invocation_id) {
1443                 /* this happens during an initial vampire while
1444                    updating the schema */
1445                 DEBUG(5,("No invocationID - skipping replPropertyMetaData update\n"));
1446                 return LDB_SUCCESS;
1447         }
1448
1449         unix_to_nt_time(&now, t);
1450
1451         if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) {
1452                 rmd_is_provided = true;
1453                 if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_RESORT_OID)) {
1454                         rmd_is_just_resorted = true;
1455                 }
1456         } else {
1457                 rmd_is_provided = false;
1458         }
1459
1460         /* if isDeleted is present and is TRUE, then we consider we are deleting,
1461          * otherwise we consider we are updating */
1462         if (ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")) {
1463                 situation = REPL_URGENT_ON_DELETE;
1464         } else if (rename_attrs) {
1465                 situation = REPL_URGENT_ON_CREATE | REPL_URGENT_ON_DELETE;
1466         } else {
1467                 situation = REPL_URGENT_ON_UPDATE;
1468         }
1469
1470         if (rmd_is_provided) {
1471                 /* In this case the change_replmetadata control was supplied */
1472                 /* We check that it's the only attribute that is provided
1473                  * (it's a rare case so it's better to keep the code simplier)
1474                  * We also check that the highest local_usn is bigger or the same as
1475                  * uSNChanged. */
1476                 uint64_t db_seq;
1477                 if( msg->num_elements != 1 ||
1478                         strncmp(msg->elements[0].name,
1479                                 "replPropertyMetaData", 20) ) {
1480                         DEBUG(0,(__location__ ": changereplmetada control called without "\
1481                                 "a specified replPropertyMetaData attribute or with others\n"));
1482                         return LDB_ERR_OPERATIONS_ERROR;
1483                 }
1484                 if (situation != REPL_URGENT_ON_UPDATE) {
1485                         DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n"));
1486                         return LDB_ERR_OPERATIONS_ERROR;
1487                 }
1488                 omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData");
1489                 if (!omd_value) {
1490                         DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n",
1491                                  ldb_dn_get_linearized(msg->dn)));
1492                         return LDB_ERR_OPERATIONS_ERROR;
1493                 }
1494                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1495                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1496                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1497                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1498                                  ldb_dn_get_linearized(msg->dn)));
1499                         return LDB_ERR_OPERATIONS_ERROR;
1500                 }
1501
1502                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2,
1503                                             DSDB_FLAG_NEXT_MODULE |
1504                                             DSDB_SEARCH_SHOW_RECYCLED |
1505                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1506                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1507                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1508
1509                 if (ret != LDB_SUCCESS) {
1510                         return ret;
1511                 }
1512
1513                 if (rmd_is_just_resorted == false) {
1514                         *seq_num = find_max_local_usn(omd);
1515
1516                         db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0);
1517
1518                         /*
1519                          * The test here now allows for a new
1520                          * replPropertyMetaData with no change, if was
1521                          * just dbcheck re-sorting the values.
1522                          */
1523                         if (*seq_num <= db_seq) {
1524                                 DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)" \
1525                                          " is less than uSNChanged (max = %lld uSNChanged = %lld)\n",
1526                                          (long long)*seq_num, (long long)db_seq));
1527                                 return LDB_ERR_OPERATIONS_ERROR;
1528                         }
1529                 }
1530
1531         } else {
1532                 /* search for the existing replPropertyMetaDataBlob. We need
1533                  * to use REVEAL and ask for DNs in storage format to support
1534                  * the check for values being the same in
1535                  * replmd_update_rpmd_element()
1536                  */
1537                 ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
1538                                             DSDB_FLAG_NEXT_MODULE |
1539                                             DSDB_SEARCH_SHOW_RECYCLED |
1540                                             DSDB_SEARCH_SHOW_EXTENDED_DN |
1541                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
1542                                             DSDB_SEARCH_REVEAL_INTERNALS, req);
1543                 if (ret != LDB_SUCCESS) {
1544                         return ret;
1545                 }
1546
1547                 omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
1548                 if (!omd_value) {
1549                         DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n",
1550                                  ldb_dn_get_linearized(msg->dn)));
1551                         return LDB_ERR_OPERATIONS_ERROR;
1552                 }
1553
1554                 ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd,
1555                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
1556                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1557                         DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n",
1558                                  ldb_dn_get_linearized(msg->dn)));
1559                         return LDB_ERR_OPERATIONS_ERROR;
1560                 }
1561
1562                 if (omd.version != 1) {
1563                         DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n",
1564                                  omd.version, ldb_dn_get_linearized(msg->dn)));
1565                         return LDB_ERR_OPERATIONS_ERROR;
1566                 }
1567
1568                 for (i=0; i<msg->num_elements; i++) {
1569                         struct ldb_message_element *old_el;
1570                         old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name);
1571                         ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num,
1572                                                          our_invocation_id,
1573                                                          now, is_schema_nc,
1574                                                          req);
1575                         if (ret != LDB_SUCCESS) {
1576                                 return ret;
1577                         }
1578
1579                         if (!*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) {
1580                                 *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]);
1581                         }
1582
1583                 }
1584         }
1585
1586         /*
1587          * Assert that we have an objectClass attribute - this is major
1588          * corruption if we don't have this!
1589          */
1590         objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass");
1591         if (objectclass_el != NULL) {
1592                 /*
1593                  * Now check if this objectClass means we need to do urgent replication
1594                  */
1595                 if (!*is_urgent && replmd_check_urgent_objectclass(objectclass_el,
1596                                                                    situation)) {
1597                         *is_urgent = true;
1598                 }
1599         } else if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
1600                 ldb_asprintf_errstring(ldb, __location__
1601                                        ": objectClass missing on %s\n",
1602                                        ldb_dn_get_linearized(msg->dn));
1603                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
1604         }
1605
1606         /*
1607          * replmd_update_rpmd_element has done an update if the
1608          * seq_num is set
1609          */
1610         if (*seq_num != 0 || rmd_is_just_resorted == true) {
1611                 struct ldb_val *md_value;
1612                 struct ldb_message_element *el;
1613
1614                 /*if we are RODC and this is a DRSR update then its ok*/
1615                 if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
1616                     && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
1617                         unsigned instanceType;
1618
1619                         ret = samdb_rodc(ldb, rodc);
1620                         if (ret != LDB_SUCCESS) {
1621                                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
1622                         } else if (*rodc) {
1623                                 ldb_set_errstring(ldb, "RODC modify is forbidden!");
1624                                 return LDB_ERR_REFERRAL;
1625                         }
1626
1627                         instanceType = ldb_msg_find_attr_as_uint(res->msgs[0], "instanceType", INSTANCE_TYPE_WRITE);
1628                         if (!(instanceType & INSTANCE_TYPE_WRITE)) {
1629                                 return ldb_error(ldb, LDB_ERR_UNWILLING_TO_PERFORM,
1630                                                  "cannot change replicated attribute on partial replica");
1631                         }
1632                 }
1633
1634                 md_value = talloc(msg, struct ldb_val);
1635                 if (md_value == NULL) {
1636                         ldb_oom(ldb);
1637                         return LDB_ERR_OPERATIONS_ERROR;
1638                 }
1639
1640                 ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &omd.ctr.ctr1, msg->dn);
1641                 if (ret != LDB_SUCCESS) {
1642                         ldb_asprintf_errstring(ldb, "%s: %s", __func__, ldb_errstring(ldb));
1643                         return ret;
1644                 }
1645
1646                 ndr_err = ndr_push_struct_blob(md_value, msg, &omd,
1647                                                (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
1648                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1649                         DEBUG(0,(__location__ ": Failed to marshall replPropertyMetaData for %s\n",
1650                                  ldb_dn_get_linearized(msg->dn)));
1651                         return LDB_ERR_OPERATIONS_ERROR;
1652                 }
1653
1654                 ret = ldb_msg_add_empty(msg, "replPropertyMetaData", LDB_FLAG_MOD_REPLACE, &el);
1655                 if (ret != LDB_SUCCESS) {
1656                         DEBUG(0,(__location__ ": Failed to add updated replPropertyMetaData %s\n",
1657                                  ldb_dn_get_linearized(msg->dn)));
1658                         return ret;
1659                 }
1660
1661                 el->num_values = 1;
1662                 el->values = md_value;
1663         }
1664
1665         return LDB_SUCCESS;
1666 }
1667
1668 struct parsed_dn {
1669         struct dsdb_dn *dsdb_dn;
1670         struct GUID guid;
1671         struct ldb_val *v;
1672 };
1673
1674 static int parsed_dn_compare(struct parsed_dn *pdn1, struct parsed_dn *pdn2)
1675 {
1676         return GUID_compare(&pdn1->guid, &pdn2->guid);
1677 }
1678
1679 static int GUID_compare_struct(struct GUID *g1, struct GUID g2)
1680 {
1681         return GUID_compare(g1, &g2);
1682 }
1683
1684 static struct parsed_dn *parsed_dn_find(struct parsed_dn *pdn,
1685                                         unsigned int count, struct GUID *guid,
1686                                         struct ldb_dn *dn)
1687 {
1688         struct parsed_dn *ret;
1689         unsigned int i;
1690         if (dn && GUID_all_zero(guid)) {
1691                 /* when updating a link using DRS, we sometimes get a
1692                    NULL GUID. We then need to try and match by DN */
1693                 for (i=0; i<count; i++) {
1694                         if (ldb_dn_compare(pdn[i].dsdb_dn->dn, dn) == 0) {
1695                                 dsdb_get_extended_dn_guid(pdn[i].dsdb_dn->dn, guid, "GUID");
1696                                 return &pdn[i];
1697                         }
1698                 }
1699                 return NULL;
1700         }
1701         BINARY_ARRAY_SEARCH(pdn, count, guid, guid, GUID_compare_struct, ret);
1702         return ret;
1703 }
1704
1705 /*
1706   get a series of message element values as an array of DNs and GUIDs
1707   the result is sorted by GUID
1708  */
1709 static int get_parsed_dns(struct ldb_module *module, TALLOC_CTX *mem_ctx,
1710                           struct ldb_message_element *el, struct parsed_dn **pdn,
1711                           const char *ldap_oid, struct ldb_request *parent)
1712 {
1713         unsigned int i;
1714         struct ldb_context *ldb = ldb_module_get_ctx(module);
1715
1716         if (el == NULL) {
1717                 *pdn = NULL;
1718                 return LDB_SUCCESS;
1719         }
1720
1721         (*pdn) = talloc_array(mem_ctx, struct parsed_dn, el->num_values);
1722         if (!*pdn) {
1723                 ldb_module_oom(module);
1724                 return LDB_ERR_OPERATIONS_ERROR;
1725         }
1726
1727         for (i=0; i<el->num_values; i++) {
1728                 struct ldb_val *v = &el->values[i];
1729                 NTSTATUS status;
1730                 struct ldb_dn *dn;
1731                 struct parsed_dn *p;
1732
1733                 p = &(*pdn)[i];
1734
1735                 p->dsdb_dn = dsdb_dn_parse(*pdn, ldb, v, ldap_oid);
1736                 if (p->dsdb_dn == NULL) {
1737                         return LDB_ERR_INVALID_DN_SYNTAX;
1738                 }
1739
1740                 dn = p->dsdb_dn->dn;
1741
1742                 status = dsdb_get_extended_dn_guid(dn, &p->guid, "GUID");
1743                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1744                         /* we got a DN without a GUID - go find the GUID */
1745                         int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
1746                         if (ret != LDB_SUCCESS) {
1747                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
1748                                                        ldb_dn_get_linearized(dn));
1749                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
1750                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
1751                                     ldb_attr_cmp(el->name, "member") == 0) {
1752                                         return LDB_ERR_UNWILLING_TO_PERFORM;
1753                                 }
1754                                 return ret;
1755                         }
1756                         ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
1757                         if (ret != LDB_SUCCESS) {
1758                                 return ret;
1759                         }
1760                 } else if (!NT_STATUS_IS_OK(status)) {
1761                         return LDB_ERR_OPERATIONS_ERROR;
1762                 }
1763
1764                 /* keep a pointer to the original ldb_val */
1765                 p->v = v;
1766         }
1767
1768         TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
1769
1770         return LDB_SUCCESS;
1771 }
1772
1773 /*
1774   build a new extended DN, including all meta data fields
1775
1776   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
1777   RMD_ADDTIME         = originating_add_time
1778   RMD_INVOCID         = originating_invocation_id
1779   RMD_CHANGETIME      = originating_change_time
1780   RMD_ORIGINATING_USN = originating_usn
1781   RMD_LOCAL_USN       = local_usn
1782   RMD_VERSION         = version
1783  */
1784 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1785                                const struct GUID *invocation_id, uint64_t seq_num,
1786                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
1787 {
1788         struct ldb_dn *dn = dsdb_dn->dn;
1789         const char *tstring, *usn_string, *flags_string;
1790         struct ldb_val tval;
1791         struct ldb_val iid;
1792         struct ldb_val usnv, local_usnv;
1793         struct ldb_val vers, flagsv;
1794         NTSTATUS status;
1795         int ret;
1796         const char *dnstring;
1797         char *vstring;
1798         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1799
1800         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1801         if (!tstring) {
1802                 return LDB_ERR_OPERATIONS_ERROR;
1803         }
1804         tval = data_blob_string_const(tstring);
1805
1806         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
1807         if (!usn_string) {
1808                 return LDB_ERR_OPERATIONS_ERROR;
1809         }
1810         usnv = data_blob_string_const(usn_string);
1811
1812         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1813         if (!usn_string) {
1814                 return LDB_ERR_OPERATIONS_ERROR;
1815         }
1816         local_usnv = data_blob_string_const(usn_string);
1817
1818         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
1819         if (!vstring) {
1820                 return LDB_ERR_OPERATIONS_ERROR;
1821         }
1822         vers = data_blob_string_const(vstring);
1823
1824         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1825         if (!NT_STATUS_IS_OK(status)) {
1826                 return LDB_ERR_OPERATIONS_ERROR;
1827         }
1828
1829         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1830         if (!flags_string) {
1831                 return LDB_ERR_OPERATIONS_ERROR;
1832         }
1833         flagsv = data_blob_string_const(flags_string);
1834
1835         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1836         if (ret != LDB_SUCCESS) return ret;
1837         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
1838         if (ret != LDB_SUCCESS) return ret;
1839         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1840         if (ret != LDB_SUCCESS) return ret;
1841         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1842         if (ret != LDB_SUCCESS) return ret;
1843         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1844         if (ret != LDB_SUCCESS) return ret;
1845         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1846         if (ret != LDB_SUCCESS) return ret;
1847         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1848         if (ret != LDB_SUCCESS) return ret;
1849
1850         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1851         if (dnstring == NULL) {
1852                 return LDB_ERR_OPERATIONS_ERROR;
1853         }
1854         *v = data_blob_string_const(dnstring);
1855
1856         return LDB_SUCCESS;
1857 }
1858
1859 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1860                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1861                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
1862                                 uint32_t version, bool deleted);
1863
1864 /*
1865   check if any links need upgrading from w2k format
1866
1867   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.
1868  */
1869 static int replmd_check_upgrade_links(struct parsed_dn *dns, uint32_t count, struct ldb_message_element *parent_ctx, const struct GUID *invocation_id)
1870 {
1871         uint32_t i;
1872         for (i=0; i<count; i++) {
1873                 NTSTATUS status;
1874                 uint32_t version;
1875                 int ret;
1876
1877                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn, &version, "RMD_VERSION");
1878                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1879                         continue;
1880                 }
1881
1882                 /* it's an old one that needs upgrading */
1883                 ret = replmd_update_la_val(parent_ctx->values, dns[i].v, dns[i].dsdb_dn, dns[i].dsdb_dn, invocation_id,
1884                                            1, 1, 0, 0, false);
1885                 if (ret != LDB_SUCCESS) {
1886                         return ret;
1887                 }
1888         }
1889         return LDB_SUCCESS;
1890 }
1891
1892 /*
1893   update an extended DN, including all meta data fields
1894
1895   see replmd_build_la_val for value names
1896  */
1897 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
1898                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
1899                                 uint64_t usn, uint64_t local_usn, NTTIME nttime,
1900                                 uint32_t version, bool deleted)
1901 {
1902         struct ldb_dn *dn = dsdb_dn->dn;
1903         const char *tstring, *usn_string, *flags_string;
1904         struct ldb_val tval;
1905         struct ldb_val iid;
1906         struct ldb_val usnv, local_usnv;
1907         struct ldb_val vers, flagsv;
1908         const struct ldb_val *old_addtime;
1909         uint32_t old_version;
1910         NTSTATUS status;
1911         int ret;
1912         const char *dnstring;
1913         char *vstring;
1914         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
1915
1916         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
1917         if (!tstring) {
1918                 return LDB_ERR_OPERATIONS_ERROR;
1919         }
1920         tval = data_blob_string_const(tstring);
1921
1922         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
1923         if (!usn_string) {
1924                 return LDB_ERR_OPERATIONS_ERROR;
1925         }
1926         usnv = data_blob_string_const(usn_string);
1927
1928         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
1929         if (!usn_string) {
1930                 return LDB_ERR_OPERATIONS_ERROR;
1931         }
1932         local_usnv = data_blob_string_const(usn_string);
1933
1934         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
1935         if (!NT_STATUS_IS_OK(status)) {
1936                 return LDB_ERR_OPERATIONS_ERROR;
1937         }
1938
1939         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
1940         if (!flags_string) {
1941                 return LDB_ERR_OPERATIONS_ERROR;
1942         }
1943         flagsv = data_blob_string_const(flags_string);
1944
1945         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
1946         if (ret != LDB_SUCCESS) return ret;
1947
1948         /* get the ADDTIME from the original */
1949         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
1950         if (old_addtime == NULL) {
1951                 old_addtime = &tval;
1952         }
1953         if (dsdb_dn != old_dsdb_dn ||
1954             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
1955                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
1956                 if (ret != LDB_SUCCESS) return ret;
1957         }
1958
1959         /* use our invocation id */
1960         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
1961         if (ret != LDB_SUCCESS) return ret;
1962
1963         /* changetime is the current time */
1964         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
1965         if (ret != LDB_SUCCESS) return ret;
1966
1967         /* update the USN */
1968         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
1969         if (ret != LDB_SUCCESS) return ret;
1970
1971         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
1972         if (ret != LDB_SUCCESS) return ret;
1973
1974         /* increase the version by 1 */
1975         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
1976         if (NT_STATUS_IS_OK(status) && old_version >= version) {
1977                 version = old_version+1;
1978         }
1979         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
1980         vers = data_blob_string_const(vstring);
1981         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
1982         if (ret != LDB_SUCCESS) return ret;
1983
1984         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
1985         if (dnstring == NULL) {
1986                 return LDB_ERR_OPERATIONS_ERROR;
1987         }
1988         *v = data_blob_string_const(dnstring);
1989
1990         return LDB_SUCCESS;
1991 }
1992
1993 /*
1994   handle adding a linked attribute
1995  */
1996 static int replmd_modify_la_add(struct ldb_module *module,
1997                                 const struct dsdb_schema *schema,
1998                                 struct ldb_message *msg,
1999                                 struct ldb_message_element *el,
2000                                 struct ldb_message_element *old_el,
2001                                 const struct dsdb_attribute *schema_attr,
2002                                 uint64_t seq_num,
2003                                 time_t t,
2004                                 struct GUID *msg_guid,
2005                                 struct ldb_request *parent)
2006 {
2007         unsigned int i;
2008         struct parsed_dn *dns, *old_dns;
2009         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2010         int ret;
2011         struct ldb_val *new_values = NULL;
2012         unsigned int num_new_values = 0;
2013         unsigned old_num_values = old_el?old_el->num_values:0;
2014         const struct GUID *invocation_id;
2015         struct ldb_context *ldb = ldb_module_get_ctx(module);
2016         NTTIME now;
2017
2018         unix_to_nt_time(&now, t);
2019
2020         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2021         if (ret != LDB_SUCCESS) {
2022                 talloc_free(tmp_ctx);
2023                 return ret;
2024         }
2025
2026         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2027         if (ret != LDB_SUCCESS) {
2028                 talloc_free(tmp_ctx);
2029                 return ret;
2030         }
2031
2032         invocation_id = samdb_ntds_invocation_id(ldb);
2033         if (!invocation_id) {
2034                 talloc_free(tmp_ctx);
2035                 return LDB_ERR_OPERATIONS_ERROR;
2036         }
2037
2038         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2039         if (ret != LDB_SUCCESS) {
2040                 talloc_free(tmp_ctx);
2041                 return ret;
2042         }
2043
2044         /* for each new value, see if it exists already with the same GUID */
2045         for (i=0; i<el->num_values; i++) {
2046                 struct parsed_dn *p = parsed_dn_find(old_dns, old_num_values, &dns[i].guid, NULL);
2047                 if (p == NULL) {
2048                         /* this is a new linked attribute value */
2049                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val, num_new_values+1);
2050                         if (new_values == NULL) {
2051                                 ldb_module_oom(module);
2052                                 talloc_free(tmp_ctx);
2053                                 return LDB_ERR_OPERATIONS_ERROR;
2054                         }
2055                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2056                                                   invocation_id, seq_num, seq_num, now, 0, false);
2057                         if (ret != LDB_SUCCESS) {
2058                                 talloc_free(tmp_ctx);
2059                                 return ret;
2060                         }
2061                         num_new_values++;
2062                 } else {
2063                         /* this is only allowed if the GUID was
2064                            previously deleted. */
2065                         uint32_t rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2066
2067                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2068                                 struct GUID_txt_buf guid_str;
2069                                 ldb_asprintf_errstring(ldb, "Attribute %s already exists for target GUID %s",
2070                                                        el->name, GUID_buf_string(&p->guid, &guid_str));
2071                                 talloc_free(tmp_ctx);
2072                                 /* error codes for 'member' need to be
2073                                    special cased */
2074                                 if (ldb_attr_cmp(el->name, "member") == 0) {
2075                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
2076                                 } else {
2077                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2078                                 }
2079                         }
2080                         ret = replmd_update_la_val(old_el->values, p->v, dns[i].dsdb_dn, p->dsdb_dn,
2081                                                    invocation_id, seq_num, seq_num, now, 0, false);
2082                         if (ret != LDB_SUCCESS) {
2083                                 talloc_free(tmp_ctx);
2084                                 return ret;
2085                         }
2086                 }
2087
2088                 ret = replmd_add_backlink(module, schema, msg_guid, &dns[i].guid, true, schema_attr, true);
2089                 if (ret != LDB_SUCCESS) {
2090                         talloc_free(tmp_ctx);
2091                         return ret;
2092                 }
2093         }
2094
2095         /* add the new ones on to the end of the old values, constructing a new el->values */
2096         el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2097                                     struct ldb_val,
2098                                     old_num_values+num_new_values);
2099         if (el->values == NULL) {
2100                 ldb_module_oom(module);
2101                 return LDB_ERR_OPERATIONS_ERROR;
2102         }
2103
2104         memcpy(&el->values[old_num_values], new_values, num_new_values*sizeof(struct ldb_val));
2105         el->num_values = old_num_values + num_new_values;
2106
2107         talloc_steal(msg->elements, el->values);
2108         talloc_steal(el->values, new_values);
2109
2110         talloc_free(tmp_ctx);
2111
2112         /* we now tell the backend to replace all existing values
2113            with the one we have constructed */
2114         el->flags = LDB_FLAG_MOD_REPLACE;
2115
2116         return LDB_SUCCESS;
2117 }
2118
2119
2120 /*
2121   handle deleting all active linked attributes
2122  */
2123 static int replmd_modify_la_delete(struct ldb_module *module,
2124                                    const struct dsdb_schema *schema,
2125                                    struct ldb_message *msg,
2126                                    struct ldb_message_element *el,
2127                                    struct ldb_message_element *old_el,
2128                                    const struct dsdb_attribute *schema_attr,
2129                                    uint64_t seq_num,
2130                                    time_t t,
2131                                    struct GUID *msg_guid,
2132                                    struct ldb_request *parent)
2133 {
2134         unsigned int i;
2135         struct parsed_dn *dns, *old_dns;
2136         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2137         int ret;
2138         const struct GUID *invocation_id;
2139         struct ldb_context *ldb = ldb_module_get_ctx(module);
2140         NTTIME now;
2141
2142         unix_to_nt_time(&now, t);
2143
2144         /* check if there is nothing to delete */
2145         if ((!old_el || old_el->num_values == 0) &&
2146             el->num_values == 0) {
2147                 return LDB_SUCCESS;
2148         }
2149
2150         if (!old_el || old_el->num_values == 0) {
2151                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2152         }
2153
2154         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2155         if (ret != LDB_SUCCESS) {
2156                 talloc_free(tmp_ctx);
2157                 return ret;
2158         }
2159
2160         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2161         if (ret != LDB_SUCCESS) {
2162                 talloc_free(tmp_ctx);
2163                 return ret;
2164         }
2165
2166         invocation_id = samdb_ntds_invocation_id(ldb);
2167         if (!invocation_id) {
2168                 return LDB_ERR_OPERATIONS_ERROR;
2169         }
2170
2171         ret = replmd_check_upgrade_links(old_dns, old_el->num_values, old_el, invocation_id);
2172         if (ret != LDB_SUCCESS) {
2173                 talloc_free(tmp_ctx);
2174                 return ret;
2175         }
2176
2177         el->values = NULL;
2178
2179         /* see if we are being asked to delete any links that
2180            don't exist or are already deleted */
2181         for (i=0; i<el->num_values; i++) {
2182                 struct parsed_dn *p = &dns[i];
2183                 struct parsed_dn *p2;
2184                 uint32_t rmd_flags;
2185
2186                 p2 = parsed_dn_find(old_dns, old_el->num_values, &p->guid, NULL);
2187                 if (!p2) {
2188                         struct GUID_txt_buf buf;
2189                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't exist for target GUID %s",
2190                                                el->name, GUID_buf_string(&p->guid, &buf));
2191                         if (ldb_attr_cmp(el->name, "member") == 0) {
2192                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2193                         } else {
2194                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2195                         }
2196                 }
2197                 rmd_flags = dsdb_dn_rmd_flags(p2->dsdb_dn->dn);
2198                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2199                         struct GUID_txt_buf buf;
2200                         ldb_asprintf_errstring(ldb, "Attribute %s already deleted for target GUID %s",
2201                                                el->name, GUID_buf_string(&p->guid, &buf));
2202                         if (ldb_attr_cmp(el->name, "member") == 0) {
2203                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2204                         } else {
2205                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2206                         }
2207                 }
2208         }
2209
2210         /* for each new value, see if it exists already with the same GUID
2211            if it is not already deleted and matches the delete list then delete it
2212         */
2213         for (i=0; i<old_el->num_values; i++) {
2214                 struct parsed_dn *p = &old_dns[i];
2215                 uint32_t rmd_flags;
2216
2217                 if (el->num_values && parsed_dn_find(dns, el->num_values, &p->guid, NULL) == NULL) {
2218                         continue;
2219                 }
2220
2221                 rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2222                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2223
2224                 ret = replmd_update_la_val(old_el->values, p->v, p->dsdb_dn, p->dsdb_dn,
2225                                            invocation_id, seq_num, seq_num, now, 0, true);
2226                 if (ret != LDB_SUCCESS) {
2227                         talloc_free(tmp_ctx);
2228                         return ret;
2229                 }
2230
2231                 ret = replmd_add_backlink(module, schema, msg_guid, &old_dns[i].guid, false, schema_attr, true);
2232                 if (ret != LDB_SUCCESS) {
2233                         talloc_free(tmp_ctx);
2234                         return ret;
2235                 }
2236         }
2237
2238         el->values = talloc_steal(msg->elements, old_el->values);
2239         el->num_values = old_el->num_values;
2240
2241         talloc_free(tmp_ctx);
2242
2243         /* we now tell the backend to replace all existing values
2244            with the one we have constructed */
2245         el->flags = LDB_FLAG_MOD_REPLACE;
2246
2247         return LDB_SUCCESS;
2248 }
2249
2250 /*
2251   handle replacing a linked attribute
2252  */
2253 static int replmd_modify_la_replace(struct ldb_module *module,
2254                                     const struct dsdb_schema *schema,
2255                                     struct ldb_message *msg,
2256                                     struct ldb_message_element *el,
2257                                     struct ldb_message_element *old_el,
2258                                     const struct dsdb_attribute *schema_attr,
2259                                     uint64_t seq_num,
2260                                     time_t t,
2261                                     struct GUID *msg_guid,
2262                                     struct ldb_request *parent)
2263 {
2264         unsigned int i;
2265         struct parsed_dn *dns, *old_dns;
2266         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2267         int ret;
2268         const struct GUID *invocation_id;
2269         struct ldb_context *ldb = ldb_module_get_ctx(module);
2270         struct ldb_val *new_values = NULL;
2271         unsigned int num_new_values = 0;
2272         unsigned int old_num_values = old_el?old_el->num_values:0;
2273         NTTIME now;
2274
2275         unix_to_nt_time(&now, t);
2276
2277         /* check if there is nothing to replace */
2278         if ((!old_el || old_el->num_values == 0) &&
2279             el->num_values == 0) {
2280                 return LDB_SUCCESS;
2281         }
2282
2283         ret = get_parsed_dns(module, tmp_ctx, el, &dns, schema_attr->syntax->ldap_oid, parent);
2284         if (ret != LDB_SUCCESS) {
2285                 talloc_free(tmp_ctx);
2286                 return ret;
2287         }
2288
2289         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns, schema_attr->syntax->ldap_oid, parent);
2290         if (ret != LDB_SUCCESS) {
2291                 talloc_free(tmp_ctx);
2292                 return ret;
2293         }
2294
2295         invocation_id = samdb_ntds_invocation_id(ldb);
2296         if (!invocation_id) {
2297                 return LDB_ERR_OPERATIONS_ERROR;
2298         }
2299
2300         ret = replmd_check_upgrade_links(old_dns, old_num_values, old_el, invocation_id);
2301         if (ret != LDB_SUCCESS) {
2302                 talloc_free(tmp_ctx);
2303                 return ret;
2304         }
2305
2306         /* mark all the old ones as deleted */
2307         for (i=0; i<old_num_values; i++) {
2308                 struct parsed_dn *old_p = &old_dns[i];
2309                 struct parsed_dn *p;
2310                 uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2311
2312                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) continue;
2313
2314                 ret = replmd_add_backlink(module, schema, msg_guid, &old_dns[i].guid, false, schema_attr, false);
2315                 if (ret != LDB_SUCCESS) {
2316                         talloc_free(tmp_ctx);
2317                         return ret;
2318                 }
2319
2320                 p = parsed_dn_find(dns, el->num_values, &old_p->guid, NULL);
2321                 if (p) {
2322                         /* we don't delete it if we are re-adding it */
2323                         continue;
2324                 }
2325
2326                 ret = replmd_update_la_val(old_el->values, old_p->v, old_p->dsdb_dn, old_p->dsdb_dn,
2327                                            invocation_id, seq_num, seq_num, now, 0, true);
2328                 if (ret != LDB_SUCCESS) {
2329                         talloc_free(tmp_ctx);
2330                         return ret;
2331                 }
2332         }
2333
2334         /* for each new value, either update its meta-data, or add it
2335          * to old_el
2336         */
2337         for (i=0; i<el->num_values; i++) {
2338                 struct parsed_dn *p = &dns[i], *old_p;
2339
2340                 if (old_dns &&
2341                     (old_p = parsed_dn_find(old_dns,
2342                                             old_num_values, &p->guid, NULL)) != NULL) {
2343                         /* update in place */
2344                         ret = replmd_update_la_val(old_el->values, old_p->v, p->dsdb_dn,
2345                                                    old_p->dsdb_dn, invocation_id,
2346                                                    seq_num, seq_num, now, 0, false);
2347                         if (ret != LDB_SUCCESS) {
2348                                 talloc_free(tmp_ctx);
2349                                 return ret;
2350                         }
2351                 } else {
2352                         /* add a new one */
2353                         new_values = talloc_realloc(tmp_ctx, new_values, struct ldb_val,
2354                                                     num_new_values+1);
2355                         if (new_values == NULL) {
2356                                 ldb_module_oom(module);
2357                                 talloc_free(tmp_ctx);
2358                                 return LDB_ERR_OPERATIONS_ERROR;
2359                         }
2360                         ret = replmd_build_la_val(new_values, &new_values[num_new_values], dns[i].dsdb_dn,
2361                                                   invocation_id, seq_num, seq_num, now, 0, false);
2362                         if (ret != LDB_SUCCESS) {
2363                                 talloc_free(tmp_ctx);
2364                                 return ret;
2365                         }
2366                         num_new_values++;
2367                 }
2368
2369                 ret = replmd_add_backlink(module, schema, msg_guid, &dns[i].guid, true, schema_attr, false);
2370                 if (ret != LDB_SUCCESS) {
2371                         talloc_free(tmp_ctx);
2372                         return ret;
2373                 }
2374         }
2375
2376         /* add the new values to the end of old_el */
2377         if (num_new_values != 0) {
2378                 el->values = talloc_realloc(msg->elements, old_el?old_el->values:NULL,
2379                                             struct ldb_val, old_num_values+num_new_values);
2380                 if (el->values == NULL) {
2381                         ldb_module_oom(module);
2382                         return LDB_ERR_OPERATIONS_ERROR;
2383                 }
2384                 memcpy(&el->values[old_num_values], &new_values[0],
2385                        sizeof(struct ldb_val)*num_new_values);
2386                 el->num_values = old_num_values + num_new_values;
2387                 talloc_steal(msg->elements, new_values);
2388         } else {
2389                 el->values = old_el->values;
2390                 el->num_values = old_el->num_values;
2391                 talloc_steal(msg->elements, el->values);
2392         }
2393
2394         talloc_free(tmp_ctx);
2395
2396         /* we now tell the backend to replace all existing values
2397            with the one we have constructed */
2398         el->flags = LDB_FLAG_MOD_REPLACE;
2399
2400         return LDB_SUCCESS;
2401 }
2402
2403
2404 /*
2405   handle linked attributes in modify requests
2406  */
2407 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
2408                                                struct ldb_message *msg,
2409                                                uint64_t seq_num, time_t t,
2410                                                struct ldb_request *parent)
2411 {
2412         struct ldb_result *res;
2413         unsigned int i;
2414         int ret;
2415         struct ldb_context *ldb = ldb_module_get_ctx(module);
2416         struct ldb_message *old_msg;
2417
2418         const struct dsdb_schema *schema;
2419         struct GUID old_guid;
2420
2421         if (seq_num == 0) {
2422                 /* there the replmd_update_rpmd code has already
2423                  * checked and saw that there are no linked
2424                  * attributes */
2425                 return LDB_SUCCESS;
2426         }
2427
2428         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
2429                 /* don't do anything special for linked attributes */
2430                 return LDB_SUCCESS;
2431         }
2432
2433         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
2434                                     DSDB_FLAG_NEXT_MODULE |
2435                                     DSDB_SEARCH_SHOW_RECYCLED |
2436                                     DSDB_SEARCH_REVEAL_INTERNALS |
2437                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
2438                                     parent);
2439         if (ret != LDB_SUCCESS) {
2440                 return ret;
2441         }
2442         schema = dsdb_get_schema(ldb, res);
2443         if (!schema) {
2444                 return LDB_ERR_OPERATIONS_ERROR;
2445         }
2446
2447         old_msg = res->msgs[0];
2448
2449         old_guid = samdb_result_guid(old_msg, "objectGUID");
2450
2451         for (i=0; i<msg->num_elements; i++) {
2452                 struct ldb_message_element *el = &msg->elements[i];
2453                 struct ldb_message_element *old_el, *new_el;
2454                 const struct dsdb_attribute *schema_attr
2455                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
2456                 if (!schema_attr) {
2457                         ldb_asprintf_errstring(ldb,
2458                                                "%s: attribute %s is not a valid attribute in schema",
2459                                                __FUNCTION__, el->name);
2460                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
2461                 }
2462                 if (schema_attr->linkID == 0) {
2463                         continue;
2464                 }
2465                 if ((schema_attr->linkID & 1) == 1) {
2466                         if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
2467                                 continue;
2468                         }
2469                         /* Odd is for the target.  Illegal to modify */
2470                         ldb_asprintf_errstring(ldb,
2471                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
2472                         return LDB_ERR_UNWILLING_TO_PERFORM;
2473                 }
2474                 old_el = ldb_msg_find_element(old_msg, el->name);
2475                 switch (el->flags & LDB_FLAG_MOD_MASK) {
2476                 case LDB_FLAG_MOD_REPLACE:
2477                         ret = replmd_modify_la_replace(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2478                         break;
2479                 case LDB_FLAG_MOD_DELETE:
2480                         ret = replmd_modify_la_delete(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2481                         break;
2482                 case LDB_FLAG_MOD_ADD:
2483                         ret = replmd_modify_la_add(module, schema, msg, el, old_el, schema_attr, seq_num, t, &old_guid, parent);
2484                         break;
2485                 default:
2486                         ldb_asprintf_errstring(ldb,
2487                                                "invalid flags 0x%x for %s linked attribute",
2488                                                el->flags, el->name);
2489                         return LDB_ERR_UNWILLING_TO_PERFORM;
2490                 }
2491                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
2492                         ldb_asprintf_errstring(ldb,
2493                                                "Attribute %s is single valued but more than one value has been supplied",
2494                                                el->name);
2495                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2496                 } else {
2497                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
2498                 }
2499
2500
2501
2502                 if (ret != LDB_SUCCESS) {
2503                         return ret;
2504                 }
2505                 if (old_el) {
2506                         ldb_msg_remove_attr(old_msg, el->name);
2507                 }
2508                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
2509                 new_el->num_values = el->num_values;
2510                 new_el->values = talloc_steal(msg->elements, el->values);
2511
2512                 /* TODO: this relises a bit too heavily on the exact
2513                    behaviour of ldb_msg_find_element and
2514                    ldb_msg_remove_element */
2515                 old_el = ldb_msg_find_element(msg, el->name);
2516                 if (old_el != el) {
2517                         ldb_msg_remove_element(msg, old_el);
2518                         i--;
2519                 }
2520         }
2521
2522         talloc_free(res);
2523         return ret;
2524 }
2525
2526
2527
2528 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
2529 {
2530         struct ldb_context *ldb;
2531         struct replmd_replicated_request *ac;
2532         struct ldb_request *down_req;
2533         struct ldb_message *msg;
2534         time_t t = time(NULL);
2535         int ret;
2536         bool is_urgent = false, rodc = false;
2537         bool is_schema_nc = false;
2538         unsigned int functional_level;
2539         const struct ldb_message_element *guid_el = NULL;
2540         struct ldb_control *sd_propagation_control;
2541         struct replmd_private *replmd_private =
2542                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
2543
2544         /* do not manipulate our control entries */
2545         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2546                 return ldb_next_request(module, req);
2547         }
2548
2549         sd_propagation_control = ldb_request_get_control(req,
2550                                         DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
2551         if (sd_propagation_control != NULL) {
2552                 if (req->op.mod.message->num_elements != 1) {
2553                         return ldb_module_operr(module);
2554                 }
2555                 ret = strcmp(req->op.mod.message->elements[0].name,
2556                              "nTSecurityDescriptor");
2557                 if (ret != 0) {
2558                         return ldb_module_operr(module);
2559                 }
2560
2561                 return ldb_next_request(module, req);
2562         }
2563
2564         ldb = ldb_module_get_ctx(module);
2565
2566         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
2567
2568         guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
2569         if (guid_el != NULL) {
2570                 ldb_set_errstring(ldb,
2571                                   "replmd_modify: it's not allowed to change the objectGUID!");
2572                 return LDB_ERR_CONSTRAINT_VIOLATION;
2573         }
2574
2575         ac = replmd_ctx_init(module, req);
2576         if (ac == NULL) {
2577                 return ldb_module_oom(module);
2578         }
2579
2580         functional_level = dsdb_functional_level(ldb);
2581
2582         /* we have to copy the message as the caller might have it as a const */
2583         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
2584         if (msg == NULL) {
2585                 ldb_oom(ldb);
2586                 talloc_free(ac);
2587                 return LDB_ERR_OPERATIONS_ERROR;
2588         }
2589
2590         ldb_msg_remove_attr(msg, "whenChanged");
2591         ldb_msg_remove_attr(msg, "uSNChanged");
2592
2593         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2594
2595         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
2596                                  msg, &ac->seq_num, t, is_schema_nc,
2597                                  &is_urgent, &rodc);
2598         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2599                 struct loadparm_context *lp_ctx;
2600                 char *referral;
2601
2602                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2603                                          struct loadparm_context);
2604
2605                 referral = talloc_asprintf(req,
2606                                            "ldap://%s/%s",
2607                                            lpcfg_dnsdomain(lp_ctx),
2608                                            ldb_dn_get_linearized(msg->dn));
2609                 ret = ldb_module_send_referral(req, referral);
2610                 talloc_free(ac);
2611                 return ret;
2612         }
2613
2614         if (ret != LDB_SUCCESS) {
2615                 talloc_free(ac);
2616                 return ret;
2617         }
2618
2619         ret = replmd_modify_handle_linked_attribs(module, msg, ac->seq_num, t, req);
2620         if (ret != LDB_SUCCESS) {
2621                 talloc_free(ac);
2622                 return ret;
2623         }
2624
2625         /* TODO:
2626          * - replace the old object with the newly constructed one
2627          */
2628
2629         ac->is_urgent = is_urgent;
2630
2631         ret = ldb_build_mod_req(&down_req, ldb, ac,
2632                                 msg,
2633                                 req->controls,
2634                                 ac, replmd_op_callback,
2635                                 req);
2636         LDB_REQ_SET_LOCATION(down_req);
2637         if (ret != LDB_SUCCESS) {
2638                 talloc_free(ac);
2639                 return ret;
2640         }
2641
2642         /* current partition control is needed by "replmd_op_callback" */
2643         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2644                 ret = ldb_request_add_control(down_req,
2645                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2646                                               false, NULL);
2647                 if (ret != LDB_SUCCESS) {
2648                         talloc_free(ac);
2649                         return ret;
2650                 }
2651         }
2652
2653         /* If we are in functional level 2000, then
2654          * replmd_modify_handle_linked_attribs will have done
2655          * nothing */
2656         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
2657                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
2658                 if (ret != LDB_SUCCESS) {
2659                         talloc_free(ac);
2660                         return ret;
2661                 }
2662         }
2663
2664         talloc_steal(down_req, msg);
2665
2666         /* we only change whenChanged and uSNChanged if the seq_num
2667            has changed */
2668         if (ac->seq_num != 0) {
2669                 ret = add_time_element(msg, "whenChanged", t);
2670                 if (ret != LDB_SUCCESS) {
2671                         talloc_free(ac);
2672                         ldb_operr(ldb);
2673                         return ret;
2674                 }
2675
2676                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2677                 if (ret != LDB_SUCCESS) {
2678                         talloc_free(ac);
2679                         ldb_operr(ldb);
2680                         return ret;
2681                 }
2682         }
2683
2684         /* go on with the call chain */
2685         return ldb_next_request(module, down_req);
2686 }
2687
2688 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
2689
2690 /*
2691   handle a rename request
2692
2693   On a rename we need to do an extra ldb_modify which sets the
2694   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
2695  */
2696 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
2697 {
2698         struct ldb_context *ldb;
2699         struct replmd_replicated_request *ac;
2700         int ret;
2701         struct ldb_request *down_req;
2702
2703         /* do not manipulate our control entries */
2704         if (ldb_dn_is_special(req->op.mod.message->dn)) {
2705                 return ldb_next_request(module, req);
2706         }
2707
2708         ldb = ldb_module_get_ctx(module);
2709
2710         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
2711
2712         ac = replmd_ctx_init(module, req);
2713         if (ac == NULL) {
2714                 return ldb_module_oom(module);
2715         }
2716
2717         ret = ldb_build_rename_req(&down_req, ldb, ac,
2718                                    ac->req->op.rename.olddn,
2719                                    ac->req->op.rename.newdn,
2720                                    ac->req->controls,
2721                                    ac, replmd_rename_callback,
2722                                    ac->req);
2723         LDB_REQ_SET_LOCATION(down_req);
2724         if (ret != LDB_SUCCESS) {
2725                 talloc_free(ac);
2726                 return ret;
2727         }
2728
2729         /* go on with the call chain */
2730         return ldb_next_request(module, down_req);
2731 }
2732
2733 /* After the rename is compleated, update the whenchanged etc */
2734 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
2735 {
2736         struct ldb_context *ldb;
2737         struct ldb_request *down_req;
2738         struct ldb_message *msg;
2739         const struct dsdb_attribute *rdn_attr;
2740         const char *rdn_name;
2741         const struct ldb_val *rdn_val;
2742         const char *attrs[5] = { NULL, };
2743         time_t t = time(NULL);
2744         int ret;
2745         bool is_urgent = false, rodc = false;
2746         bool is_schema_nc;
2747         struct replmd_replicated_request *ac =
2748                 talloc_get_type(req->context, struct replmd_replicated_request);
2749         struct replmd_private *replmd_private =
2750                 talloc_get_type(ldb_module_get_private(ac->module),
2751                                 struct replmd_private);
2752
2753         ldb = ldb_module_get_ctx(ac->module);
2754
2755         if (ares->error != LDB_SUCCESS) {
2756                 return ldb_module_done(ac->req, ares->controls,
2757                                         ares->response, ares->error);
2758         }
2759
2760         if (ares->type != LDB_REPLY_DONE) {
2761                 ldb_set_errstring(ldb,
2762                                   "invalid ldb_reply_type in callback");
2763                 talloc_free(ares);
2764                 return ldb_module_done(ac->req, NULL, NULL,
2765                                         LDB_ERR_OPERATIONS_ERROR);
2766         }
2767
2768         /* TODO:
2769          * - replace the old object with the newly constructed one
2770          */
2771
2772         msg = ldb_msg_new(ac);
2773         if (msg == NULL) {
2774                 ldb_oom(ldb);
2775                 return LDB_ERR_OPERATIONS_ERROR;
2776         }
2777
2778         msg->dn = ac->req->op.rename.newdn;
2779
2780         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
2781
2782         rdn_name = ldb_dn_get_rdn_name(msg->dn);
2783         if (rdn_name == NULL) {
2784                 talloc_free(ares);
2785                 return ldb_module_done(ac->req, NULL, NULL,
2786                                        ldb_operr(ldb));
2787         }
2788
2789         /* normalize the rdn attribute name */
2790         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
2791         if (rdn_attr == NULL) {
2792                 talloc_free(ares);
2793                 return ldb_module_done(ac->req, NULL, NULL,
2794                                        ldb_operr(ldb));
2795         }
2796         rdn_name = rdn_attr->lDAPDisplayName;
2797
2798         rdn_val = ldb_dn_get_rdn_val(msg->dn);
2799         if (rdn_val == NULL) {
2800                 talloc_free(ares);
2801                 return ldb_module_done(ac->req, NULL, NULL,
2802                                        ldb_operr(ldb));
2803         }
2804
2805         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2806                 talloc_free(ares);
2807                 return ldb_module_done(ac->req, NULL, NULL,
2808                                        ldb_oom(ldb));
2809         }
2810         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
2811                 talloc_free(ares);
2812                 return ldb_module_done(ac->req, NULL, NULL,
2813                                        ldb_oom(ldb));
2814         }
2815         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
2816                 talloc_free(ares);
2817                 return ldb_module_done(ac->req, NULL, NULL,
2818                                        ldb_oom(ldb));
2819         }
2820         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
2821                 talloc_free(ares);
2822                 return ldb_module_done(ac->req, NULL, NULL,
2823                                        ldb_oom(ldb));
2824         }
2825
2826         /*
2827          * here we let replmd_update_rpmd() only search for
2828          * the existing "replPropertyMetaData" and rdn_name attributes.
2829          *
2830          * We do not want the existing "name" attribute as
2831          * the "name" attribute needs to get the version
2832          * updated on rename even if the rdn value hasn't changed.
2833          *
2834          * This is the diff of the meta data, for a moved user
2835          * on a w2k8r2 server:
2836          *
2837          * # record 1
2838          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
2839          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
2840          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
2841          *         version                  : 0x00000001 (1)
2842          *         reserved                 : 0x00000000 (0)
2843          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
2844          *                      local_usn                : 0x00000000000037a5 (14245)
2845          *                 array: struct replPropertyMetaData1
2846          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
2847          * -                    version                  : 0x00000001 (1)
2848          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
2849          * +                    version                  : 0x00000002 (2)
2850          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
2851          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
2852          * -                    originating_usn          : 0x00000000000037a5 (14245)
2853          * -                    local_usn                : 0x00000000000037a5 (14245)
2854          * +                    originating_usn          : 0x0000000000003834 (14388)
2855          * +                    local_usn                : 0x0000000000003834 (14388)
2856          *                 array: struct replPropertyMetaData1
2857          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
2858          *                      version                  : 0x00000004 (4)
2859          */
2860         attrs[0] = "replPropertyMetaData";
2861         attrs[1] = "objectClass";
2862         attrs[2] = "instanceType";
2863         attrs[3] = rdn_name;
2864         attrs[4] = NULL;
2865
2866         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
2867                                  msg, &ac->seq_num, t,
2868                                  is_schema_nc, &is_urgent, &rodc);
2869         if (rodc && (ret == LDB_ERR_REFERRAL)) {
2870                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
2871                 struct loadparm_context *lp_ctx;
2872                 char *referral;
2873
2874                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2875                                          struct loadparm_context);
2876
2877                 referral = talloc_asprintf(req,
2878                                            "ldap://%s/%s",
2879                                            lpcfg_dnsdomain(lp_ctx),
2880                                            ldb_dn_get_linearized(olddn));
2881                 ret = ldb_module_send_referral(req, referral);
2882                 talloc_free(ares);
2883                 return ldb_module_done(req, NULL, NULL, ret);
2884         }
2885
2886         if (ret != LDB_SUCCESS) {
2887                 talloc_free(ares);
2888                 return ldb_module_done(ac->req, NULL, NULL, ret);
2889         }
2890
2891         if (ac->seq_num == 0) {
2892                 talloc_free(ares);
2893                 return ldb_module_done(ac->req, NULL, NULL,
2894                                        ldb_error(ldb, ret,
2895                                         "internal error seq_num == 0"));
2896         }
2897         ac->is_urgent = is_urgent;
2898
2899         ret = ldb_build_mod_req(&down_req, ldb, ac,
2900                                 msg,
2901                                 req->controls,
2902                                 ac, replmd_op_callback,
2903                                 req);
2904         LDB_REQ_SET_LOCATION(down_req);
2905         if (ret != LDB_SUCCESS) {
2906                 talloc_free(ac);
2907                 return ret;
2908         }
2909
2910         /* current partition control is needed by "replmd_op_callback" */
2911         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
2912                 ret = ldb_request_add_control(down_req,
2913                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
2914                                               false, NULL);
2915                 if (ret != LDB_SUCCESS) {
2916                         talloc_free(ac);
2917                         return ret;
2918                 }
2919         }
2920
2921         talloc_steal(down_req, msg);
2922
2923         ret = add_time_element(msg, "whenChanged", t);
2924         if (ret != LDB_SUCCESS) {
2925                 talloc_free(ac);
2926                 ldb_operr(ldb);
2927                 return ret;
2928         }
2929
2930         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
2931         if (ret != LDB_SUCCESS) {
2932                 talloc_free(ac);
2933                 ldb_operr(ldb);
2934                 return ret;
2935         }
2936
2937         /* go on with the call chain - do the modify after the rename */
2938         return ldb_next_request(ac->module, down_req);
2939 }
2940
2941 /*
2942  * remove links from objects that point at this object when an object
2943  * is deleted.  We remove it from the NEXT module per MS-DRSR 5.160
2944  * RemoveObj which states that link removal due to the object being
2945  * deleted is NOT an originating update - they just go away!
2946  *
2947  */
2948 static int replmd_delete_remove_link(struct ldb_module *module,
2949                                      const struct dsdb_schema *schema,
2950                                      struct ldb_dn *dn,
2951                                      struct ldb_message_element *el,
2952                                      const struct dsdb_attribute *sa,
2953                                      struct ldb_request *parent)
2954 {
2955         unsigned int i;
2956         TALLOC_CTX *tmp_ctx = talloc_new(module);
2957         struct ldb_context *ldb = ldb_module_get_ctx(module);
2958
2959         for (i=0; i<el->num_values; i++) {
2960                 struct dsdb_dn *dsdb_dn;
2961                 NTSTATUS status;
2962                 int ret;
2963                 struct GUID guid2;
2964                 struct ldb_message *msg;
2965                 const struct dsdb_attribute *target_attr;
2966                 struct ldb_message_element *el2;
2967                 struct ldb_val dn_val;
2968
2969                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
2970                         continue;
2971                 }
2972
2973                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
2974                 if (!dsdb_dn) {
2975                         talloc_free(tmp_ctx);
2976                         return LDB_ERR_OPERATIONS_ERROR;
2977                 }
2978
2979                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
2980                 if (!NT_STATUS_IS_OK(status)) {
2981                         talloc_free(tmp_ctx);
2982                         return LDB_ERR_OPERATIONS_ERROR;
2983                 }
2984
2985                 /* remove the link */
2986                 msg = ldb_msg_new(tmp_ctx);
2987                 if (!msg) {
2988                         ldb_module_oom(module);
2989                         talloc_free(tmp_ctx);
2990                         return LDB_ERR_OPERATIONS_ERROR;
2991                 }
2992
2993
2994                 msg->dn = dsdb_dn->dn;
2995
2996                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
2997                 if (target_attr == NULL) {
2998                         continue;
2999                 }
3000
3001                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3002                 if (ret != LDB_SUCCESS) {
3003                         ldb_module_oom(module);
3004                         talloc_free(tmp_ctx);
3005                         return LDB_ERR_OPERATIONS_ERROR;
3006                 }
3007                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3008                 el2->values = &dn_val;
3009                 el2->num_values = 1;
3010
3011                 ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, parent);
3012                 if (ret != LDB_SUCCESS) {
3013                         talloc_free(tmp_ctx);
3014                         return ret;
3015                 }
3016         }
3017         talloc_free(tmp_ctx);
3018         return LDB_SUCCESS;
3019 }
3020
3021
3022 /*
3023   handle update of replication meta data for deletion of objects
3024
3025   This also handles the mapping of delete to a rename operation
3026   to allow deletes to be replicated.
3027
3028   It also handles the incoming deleted objects, to ensure they are
3029   fully deleted here.  In that case re_delete is true, and we do not
3030   use this as a signal to change the deleted state, just reinforce it.
3031
3032  */
3033 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3034 {
3035         int ret = LDB_ERR_OTHER;
3036         bool retb, disallow_move_on_delete;
3037         struct ldb_dn *old_dn, *new_dn;
3038         const char *rdn_name;
3039         const struct ldb_val *rdn_value, *new_rdn_value;
3040         struct GUID guid;
3041         struct ldb_context *ldb = ldb_module_get_ctx(module);
3042         const struct dsdb_schema *schema;
3043         struct ldb_message *msg, *old_msg;
3044         struct ldb_message_element *el;
3045         TALLOC_CTX *tmp_ctx;
3046         struct ldb_result *res, *parent_res;
3047         const char *preserved_attrs[] = {
3048                 /* yes, this really is a hard coded list. See MS-ADTS
3049                    section 3.1.1.5.5.1.1 */
3050                 "nTSecurityDescriptor", "attributeID", "attributeSyntax", "dNReferenceUpdate", "dNSHostName",
3051                 "flatName", "governsID", "groupType", "instanceType", "lDAPDisplayName", "legacyExchangeDN",
3052                 "isDeleted", "isRecycled", "lastKnownParent", "msDS-LastKnownRDN", "mS-DS-CreatorSID",
3053                 "mSMQOwnerID", "nCName", "objectClass", "distinguishedName", "objectGUID", "objectSid",
3054                 "oMSyntax", "proxiedObjectName", "name", "replPropertyMetaData", "sAMAccountName",
3055                 "securityIdentifier", "sIDHistory", "subClassOf", "systemFlags", "trustPartner", "trustDirection",
3056                 "trustType", "trustAttributes", "userAccountControl", "uSNChanged", "uSNCreated", "whenCreated",
3057                 "whenChanged", NULL};
3058         unsigned int i, el_count = 0;
3059         enum deletion_state deletion_state, next_deletion_state;
3060
3061         if (ldb_dn_is_special(req->op.del.dn)) {
3062                 return ldb_next_request(module, req);
3063         }
3064
3065         /*
3066          * We have to allow dbcheck to remove an object that
3067          * is beyond repair, and to do so totally.  This could
3068          * mean we we can get a partial object from the other
3069          * DC, causing havoc, so dbcheck suggests
3070          * re-replication first.  dbcheck sets both DBCHECK
3071          * and RELAX in this situation.
3072          */
3073         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3074             && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3075                 /* really, really remove it */
3076                 return ldb_next_request(module, req);
3077         }
3078
3079         tmp_ctx = talloc_new(ldb);
3080         if (!tmp_ctx) {
3081                 ldb_oom(ldb);
3082                 return LDB_ERR_OPERATIONS_ERROR;
3083         }
3084
3085         schema = dsdb_get_schema(ldb, tmp_ctx);
3086         if (!schema) {
3087                 talloc_free(tmp_ctx);
3088                 return LDB_ERR_OPERATIONS_ERROR;
3089         }
3090
3091         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3092
3093         /* we need the complete msg off disk, so we can work out which
3094            attributes need to be removed */
3095         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, NULL,
3096                                     DSDB_FLAG_NEXT_MODULE |
3097                                     DSDB_SEARCH_SHOW_RECYCLED |
3098                                     DSDB_SEARCH_REVEAL_INTERNALS |
3099                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3100         if (ret != LDB_SUCCESS) {
3101                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3102                                        "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3103                                        re_delete ? "re-delete" : "delete",
3104                                        ldb_dn_get_linearized(old_dn),
3105                                        ldb_errstring(ldb_module_get_ctx(module)));
3106                 talloc_free(tmp_ctx);
3107                 return ret;
3108         }
3109         old_msg = res->msgs[0];
3110
3111         replmd_deletion_state(module, old_msg,
3112                               &deletion_state,
3113                               &next_deletion_state);
3114
3115         /* This supports us noticing an incoming isDeleted and acting on it */
3116         if (re_delete) {
3117                 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3118                 next_deletion_state = deletion_state;
3119         }
3120
3121         if (next_deletion_state == OBJECT_REMOVED) {
3122                 /*
3123                  * We have to prevent objects being deleted, even if
3124                  * the administrator really wants them gone, as
3125                  * without the tombstone, we can get a partial object
3126                  * from the other DC, causing havoc.
3127                  *
3128                  * The only other valid case is when the 180 day
3129                  * timeout has expired, when relax is specified.
3130                  */
3131                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3132                         /* it is already deleted - really remove it this time */
3133                         talloc_free(tmp_ctx);
3134                         return ldb_next_request(module, req);
3135                 }
3136
3137                 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s.  "
3138                                        "This check is to prevent corruption of the replicated state.",
3139                                        ldb_dn_get_linearized(old_msg->dn));
3140                 return LDB_ERR_UNWILLING_TO_PERFORM;
3141         }
3142
3143         rdn_name = ldb_dn_get_rdn_name(old_dn);
3144         rdn_value = ldb_dn_get_rdn_val(old_dn);
3145         if ((rdn_name == NULL) || (rdn_value == NULL)) {
3146                 talloc_free(tmp_ctx);
3147                 return ldb_operr(ldb);
3148         }
3149
3150         msg = ldb_msg_new(tmp_ctx);
3151         if (msg == NULL) {
3152                 ldb_module_oom(module);
3153                 talloc_free(tmp_ctx);
3154                 return LDB_ERR_OPERATIONS_ERROR;
3155         }
3156
3157         msg->dn = old_dn;
3158
3159         /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3160         disallow_move_on_delete =
3161                 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3162                  & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3163
3164         /* work out where we will be renaming this object to */
3165         if (!disallow_move_on_delete) {
3166                 struct ldb_dn *deleted_objects_dn;
3167                 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3168                                                   &deleted_objects_dn);
3169
3170                 /*
3171                  * We should not move objects if we can't find the
3172                  * deleted objects DN.  Not moving (or otherwise
3173                  * harming) the Deleted Objects DN itself is handled
3174                  * in the caller.
3175                  */
3176                 if (re_delete && (ret != LDB_SUCCESS)) {
3177                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3178                         if (new_dn == NULL) {
3179                                 ldb_module_oom(module);
3180                                 talloc_free(tmp_ctx);
3181                                 return LDB_ERR_OPERATIONS_ERROR;
3182                         }
3183                 } else if (ret != LDB_SUCCESS) {
3184                         /* this is probably an attempted delete on a partition
3185                          * that doesn't allow delete operations, such as the
3186                          * schema partition */
3187                         ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3188                                                ldb_dn_get_linearized(old_dn));
3189                         talloc_free(tmp_ctx);
3190                         return LDB_ERR_UNWILLING_TO_PERFORM;
3191                 } else {
3192                         new_dn = deleted_objects_dn;
3193                 }
3194         } else {
3195                 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3196                 if (new_dn == NULL) {
3197                         ldb_module_oom(module);
3198                         talloc_free(tmp_ctx);
3199                         return LDB_ERR_OPERATIONS_ERROR;
3200                 }
3201         }
3202
3203         if (deletion_state == OBJECT_NOT_DELETED) {
3204                 /* get the objects GUID from the search we just did */
3205                 guid = samdb_result_guid(old_msg, "objectGUID");
3206
3207                 /* Add a formatted child */
3208                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3209                                             rdn_name,
3210                                             ldb_dn_escape_value(tmp_ctx, *rdn_value),
3211                                             GUID_string(tmp_ctx, &guid));
3212                 if (!retb) {
3213                         ldb_asprintf_errstring(ldb, __location__
3214                                                ": Unable to add a formatted child to dn: %s",
3215                                                ldb_dn_get_linearized(new_dn));
3216                         talloc_free(tmp_ctx);
3217                         return LDB_ERR_OPERATIONS_ERROR;
3218                 }
3219
3220                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3221                 if (ret != LDB_SUCCESS) {
3222                         ldb_asprintf_errstring(ldb, __location__
3223                                                ": Failed to add isDeleted string to the msg");
3224                         talloc_free(tmp_ctx);
3225                         return ret;
3226                 }
3227                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3228         } else {
3229                 /*
3230                  * No matter what has happened with other renames etc, try again to
3231                  * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3232                  */
3233
3234                 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3235                 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3236                 if (!retb) {
3237                         ldb_asprintf_errstring(ldb, __location__
3238                                                ": Unable to add a prepare rdn of %s",
3239                                                ldb_dn_get_linearized(rdn));
3240                         talloc_free(tmp_ctx);
3241                         return LDB_ERR_OPERATIONS_ERROR;
3242                 }
3243                 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3244
3245                 retb = ldb_dn_add_child(new_dn, rdn);
3246                 if (!retb) {
3247                         ldb_asprintf_errstring(ldb, __location__
3248                                                ": Unable to add rdn %s to base dn: %s",
3249                                                ldb_dn_get_linearized(rdn),
3250                                                ldb_dn_get_linearized(new_dn));
3251                         talloc_free(tmp_ctx);
3252                         return LDB_ERR_OPERATIONS_ERROR;
3253                 }
3254         }
3255
3256         /*
3257           now we need to modify the object in the following ways:
3258
3259           - add isDeleted=TRUE
3260           - update rDN and name, with new rDN
3261           - remove linked attributes
3262           - remove objectCategory and sAMAccountType
3263           - remove attribs not on the preserved list
3264              - preserved if in above list, or is rDN
3265           - remove all linked attribs from this object
3266           - remove all links from other objects to this object
3267           - add lastKnownParent
3268           - update replPropertyMetaData?
3269
3270           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3271          */
3272
3273         if (deletion_state == OBJECT_NOT_DELETED) {
3274                 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3275                 char *parent_dn_str = NULL;
3276
3277                 /* we need the storage form of the parent GUID */
3278                 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3279                                             parent_dn, NULL,
3280                                             DSDB_FLAG_NEXT_MODULE |
3281                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3282                                             DSDB_SEARCH_REVEAL_INTERNALS|
3283                                             DSDB_SEARCH_SHOW_RECYCLED, req);
3284                 if (ret != LDB_SUCCESS) {
3285                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
3286                                                "repmd_delete: Failed to %s %s, "
3287                                                "because we failed to find it's parent (%s): %s",
3288                                                re_delete ? "re-delete" : "delete",
3289                                                ldb_dn_get_linearized(old_dn),
3290                                                ldb_dn_get_linearized(parent_dn),
3291                                                ldb_errstring(ldb_module_get_ctx(module)));
3292                         talloc_free(tmp_ctx);
3293                         return ret;
3294                 }
3295
3296                 /*
3297                  * Now we can use the DB version,
3298                  * it will have the extended DN info in it
3299                  */
3300                 parent_dn = parent_res->msgs[0]->dn;
3301                 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
3302                                                                parent_dn,
3303                                                                1);
3304                 if (parent_dn_str == NULL) {
3305                         talloc_free(tmp_ctx);
3306                         return ldb_module_oom(module);
3307                 }
3308
3309                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3310                                                parent_dn_str);
3311                 if (ret != LDB_SUCCESS) {
3312                         ldb_asprintf_errstring(ldb, __location__
3313                                                ": Failed to add lastKnownParent "
3314                                                "string when deleting %s",
3315                                                ldb_dn_get_linearized(old_dn));
3316                         talloc_free(tmp_ctx);
3317                         return ret;
3318                 }
3319                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3320
3321                 if (next_deletion_state == OBJECT_DELETED) {
3322                         ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
3323                         if (ret != LDB_SUCCESS) {
3324                                 ldb_asprintf_errstring(ldb, __location__
3325                                                        ": Failed to add msDS-LastKnownRDN "
3326                                                        "string when deleting %s",
3327                                                        ldb_dn_get_linearized(old_dn));
3328                                 talloc_free(tmp_ctx);
3329                                 return ret;
3330                         }
3331                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
3332                 }
3333         }
3334
3335         switch (next_deletion_state) {
3336
3337         case OBJECT_RECYCLED:
3338         case OBJECT_TOMBSTONE:
3339
3340                 /*
3341                  * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
3342                  * describes what must be removed from a tombstone
3343                  * object
3344                  *
3345                  * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
3346                  * describes what must be removed from a recycled
3347                  * object
3348                  *
3349                  */
3350
3351                 /*
3352                  * we also mark it as recycled, meaning this object can't be
3353                  * recovered (we are stripping its attributes).
3354                  * This is done only if we have this schema object of course ...
3355                  * This behavior is identical to the one of Windows 2008R2 which
3356                  * always set the isRecycled attribute, even if the recycle-bin is
3357                  * not activated and what ever the forest level is.
3358                  */
3359                 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
3360                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
3361                         if (ret != LDB_SUCCESS) {
3362                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
3363                                 ldb_module_oom(module);
3364                                 talloc_free(tmp_ctx);
3365                                 return ret;
3366                         }
3367                         msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3368                 }
3369
3370                 /* work out which of the old attributes we will be removing */
3371                 for (i=0; i<old_msg->num_elements; i++) {
3372                         const struct dsdb_attribute *sa;
3373                         el = &old_msg->elements[i];
3374                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3375                         if (!sa) {
3376                                 talloc_free(tmp_ctx);
3377                                 return LDB_ERR_OPERATIONS_ERROR;
3378                         }
3379                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
3380                                 /* don't remove the rDN */
3381                                 continue;
3382                         }
3383                         if (sa->linkID && (sa->linkID & 1)) {
3384                                 /*
3385                                   we have a backlink in this object
3386                                   that needs to be removed. We're not
3387                                   allowed to remove it directly
3388                                   however, so we instead setup a
3389                                   modify to delete the corresponding
3390                                   forward link
3391                                  */
3392                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
3393                                 if (ret != LDB_SUCCESS) {
3394                                         const char *old_dn_str
3395                                                 = ldb_dn_get_linearized(old_dn);
3396                                         ldb_asprintf_errstring(ldb,
3397                                                                __location__
3398                                                                ": Failed to remove backlink of "
3399                                                                "%s when deleting %s",
3400                                                                el->name,
3401                                                                old_dn_str);
3402                                         talloc_free(tmp_ctx);
3403                                         return LDB_ERR_OPERATIONS_ERROR;
3404                                 }
3405                                 /* now we continue, which means we
3406                                    won't remove this backlink
3407                                    directly
3408                                 */
3409                                 continue;
3410                         }
3411                         if (!sa->linkID) {
3412                                 if (ldb_attr_in_list(preserved_attrs, el->name)) {
3413                                         continue;
3414                                 }
3415                                 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
3416                                         continue;
3417                                 }
3418                         }
3419                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
3420                         if (ret != LDB_SUCCESS) {
3421                                 talloc_free(tmp_ctx);
3422                                 ldb_module_oom(module);
3423                                 return ret;
3424                         }
3425                 }
3426
3427                 break;
3428
3429         case OBJECT_DELETED:
3430                 /*
3431                  * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
3432                  * describes what must be removed from a deleted
3433                  * object
3434                  */
3435
3436                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
3437                 if (ret != LDB_SUCCESS) {
3438                         talloc_free(tmp_ctx);
3439                         ldb_module_oom(module);
3440                         return ret;
3441                 }
3442
3443                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
3444                 if (ret != LDB_SUCCESS) {
3445                         talloc_free(tmp_ctx);
3446                         ldb_module_oom(module);
3447                         return ret;
3448                 }
3449
3450                 break;
3451
3452         default:
3453                 break;
3454         }
3455
3456         if (deletion_state == OBJECT_NOT_DELETED) {
3457                 const struct dsdb_attribute *sa;
3458
3459                 /* work out what the new rdn value is, for updating the
3460                    rDN and name fields */
3461                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
3462                 if (new_rdn_value == NULL) {
3463                         talloc_free(tmp_ctx);
3464                         return ldb_operr(ldb);
3465                 }
3466
3467                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
3468                 if (!sa) {
3469                         talloc_free(tmp_ctx);
3470                         return LDB_ERR_OPERATIONS_ERROR;
3471                 }
3472
3473                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
3474                                         &el);
3475                 if (ret != LDB_SUCCESS) {
3476                         talloc_free(tmp_ctx);
3477                         return ret;
3478                 }
3479                 el->flags = LDB_FLAG_MOD_REPLACE;
3480
3481                 el = ldb_msg_find_element(old_msg, "name");
3482                 if (el) {
3483                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
3484                         if (ret != LDB_SUCCESS) {
3485                                 talloc_free(tmp_ctx);
3486                                 return ret;
3487                         }
3488                         el->flags = LDB_FLAG_MOD_REPLACE;
3489                 }
3490         }
3491
3492         /*
3493          * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
3494          *
3495          */
3496
3497         /*
3498          * No matter what has happned with other renames, try again to
3499          * get this to be under the deleted DN.
3500          */
3501         if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
3502                 /* now rename onto the new DN */
3503                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
3504                 if (ret != LDB_SUCCESS){
3505                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
3506                                  ldb_dn_get_linearized(old_dn),
3507                                  ldb_dn_get_linearized(new_dn),
3508                                  ldb_errstring(ldb)));
3509                         talloc_free(tmp_ctx);
3510                         return ret;
3511                 }
3512                 msg->dn = new_dn;
3513         }
3514
3515         ret = dsdb_module_modify(module, msg, DSDB_FLAG_OWN_MODULE, req);
3516         if (ret != LDB_SUCCESS) {
3517                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
3518                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
3519                 talloc_free(tmp_ctx);
3520                 return ret;
3521         }
3522
3523         talloc_free(tmp_ctx);
3524
3525         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
3526 }
3527
3528 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
3529 {
3530         return replmd_delete_internals(module, req, false);
3531 }
3532
3533
3534 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
3535 {
3536         return ret;
3537 }
3538
3539 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
3540 {
3541         int ret = LDB_ERR_OTHER;
3542         /* TODO: do some error mapping */
3543
3544         /* Let the caller know the full WERROR */
3545         ar->objs->error = status;
3546
3547         return ret;
3548 }
3549
3550
3551 static struct replPropertyMetaData1 *
3552 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
3553                                         enum drsuapi_DsAttributeId attid)
3554 {
3555         uint32_t i;
3556         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
3557
3558         for (i = 0; i < rpmd_ctr->count; i++) {
3559                 if (rpmd_ctr->array[i].attid == attid) {
3560                         return &rpmd_ctr->array[i];
3561                 }
3562         }
3563         return NULL;
3564 }
3565
3566
3567 /*
3568    return true if an update is newer than an existing entry
3569    see section 5.11 of MS-ADTS
3570 */
3571 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
3572                                    const struct GUID *update_invocation_id,
3573                                    uint32_t current_version,
3574                                    uint32_t update_version,
3575                                    NTTIME current_change_time,
3576                                    NTTIME update_change_time)
3577 {
3578         if (update_version != current_version) {
3579                 return update_version > current_version;
3580         }
3581         if (update_change_time != current_change_time) {
3582                 return update_change_time > current_change_time;
3583         }
3584         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
3585 }
3586
3587 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
3588                                                   struct replPropertyMetaData1 *new_m)
3589 {
3590         return replmd_update_is_newer(&cur_m->originating_invocation_id,
3591                                       &new_m->originating_invocation_id,
3592                                       cur_m->version,
3593                                       new_m->version,
3594                                       cur_m->originating_change_time,
3595                                       new_m->originating_change_time);
3596 }
3597
3598 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
3599                                                              struct replPropertyMetaData1 *cur_m,
3600                                                              struct replPropertyMetaData1 *new_m)
3601 {
3602         bool cmp;
3603
3604         /*
3605          * If the new replPropertyMetaData entry for this attribute is
3606          * not provided (this happens in the case where we look for
3607          * ATTID_name, but the name was not changed), then the local
3608          * state is clearly still current, as the remote
3609          * server didn't send it due to being older the high watermark
3610          * USN we sent.
3611          */
3612         if (new_m == NULL) {
3613                 return false;
3614         }
3615
3616         if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
3617                 /*
3618                  * if we compare equal then do an
3619                  * update. This is used when a client
3620                  * asks for a FULL_SYNC, and can be
3621                  * used to recover a corrupt
3622                  * replica.
3623                  *
3624                  * This call is a bit tricky, what we
3625                  * are doing it turning the 'is_newer'
3626                  * call into a 'not is older' by
3627                  * swapping cur_m and new_m, and negating the
3628                  * outcome.
3629                  */
3630                 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
3631                                                              cur_m);
3632         } else {
3633                 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
3634                                                             new_m);
3635         }
3636         return cmp;
3637 }
3638
3639
3640 /*
3641   form a conflict DN
3642  */
3643 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
3644 {
3645         const struct ldb_val *rdn_val;
3646         const char *rdn_name;
3647         struct ldb_dn *new_dn;
3648
3649         rdn_val = ldb_dn_get_rdn_val(dn);
3650         rdn_name = ldb_dn_get_rdn_name(dn);
3651         if (!rdn_val || !rdn_name) {
3652                 return NULL;
3653         }
3654
3655         new_dn = ldb_dn_copy(mem_ctx, dn);
3656         if (!new_dn) {
3657                 return NULL;
3658         }
3659
3660         if (!ldb_dn_remove_child_components(new_dn, 1)) {
3661                 return NULL;
3662         }
3663
3664         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
3665                                   rdn_name,
3666                                   ldb_dn_escape_value(new_dn, *rdn_val),
3667                                   GUID_string(new_dn, guid))) {
3668                 return NULL;
3669         }
3670
3671         return new_dn;
3672 }
3673
3674
3675 /*
3676   perform a modify operation which sets the rDN and name attributes to
3677   their current values. This has the effect of changing these
3678   attributes to have been last updated by the current DC. This is
3679   needed to ensure that renames performed as part of conflict
3680   resolution are propogated to other DCs
3681  */
3682 static int replmd_name_modify(struct replmd_replicated_request *ar,
3683                               struct ldb_request *req, struct ldb_dn *dn)
3684 {
3685         struct ldb_message *msg;
3686         const char *rdn_name;
3687         const struct ldb_val *rdn_val;
3688         const struct dsdb_attribute *rdn_attr;
3689         int ret;
3690
3691         msg = ldb_msg_new(req);
3692         if (msg == NULL) {
3693                 goto failed;
3694         }
3695         msg->dn = dn;
3696
3697         rdn_name = ldb_dn_get_rdn_name(dn);
3698         if (rdn_name == NULL) {
3699                 goto failed;
3700         }
3701
3702         /* normalize the rdn attribute name */
3703         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
3704         if (rdn_attr == NULL) {
3705                 goto failed;
3706         }
3707         rdn_name = rdn_attr->lDAPDisplayName;
3708
3709         rdn_val = ldb_dn_get_rdn_val(dn);
3710         if (rdn_val == NULL) {
3711                 goto failed;
3712         }
3713
3714         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3715                 goto failed;
3716         }
3717         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3718                 goto failed;
3719         }
3720         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3721                 goto failed;
3722         }
3723         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3724                 goto failed;
3725         }
3726
3727         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3728         if (ret != LDB_SUCCESS) {
3729                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
3730                          ldb_dn_get_linearized(dn),
3731                          ldb_errstring(ldb_module_get_ctx(ar->module))));
3732                 return ret;
3733         }
3734
3735         talloc_free(msg);
3736
3737         return LDB_SUCCESS;
3738
3739 failed:
3740         talloc_free(msg);
3741         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
3742                  ldb_dn_get_linearized(dn)));
3743         return LDB_ERR_OPERATIONS_ERROR;
3744 }
3745
3746
3747 /*
3748   callback for conflict DN handling where we have renamed the incoming
3749   record. After renaming it, we need to ensure the change of name and
3750   rDN for the incoming record is seen as an originating update by this DC.
3751
3752   This also handles updating lastKnownParent for entries sent to lostAndFound
3753  */
3754 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
3755 {
3756         struct replmd_replicated_request *ar =
3757                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3758         struct ldb_dn *conflict_dn = NULL;
3759         int ret;
3760
3761         if (ares->error != LDB_SUCCESS) {
3762                 /* call the normal callback for everything except success */
3763                 return replmd_op_callback(req, ares);
3764         }
3765
3766         switch (req->operation) {
3767         case LDB_ADD:
3768                 conflict_dn = req->op.add.message->dn;
3769                 break;
3770         case LDB_MODIFY:
3771                 conflict_dn = req->op.mod.message->dn;
3772                 break;
3773         default:
3774                 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
3775         }
3776
3777         /* perform a modify of the rDN and name of the record */
3778         ret = replmd_name_modify(ar, req, conflict_dn);
3779         if (ret != LDB_SUCCESS) {
3780                 ares->error = ret;
3781                 return replmd_op_callback(req, ares);
3782         }
3783
3784         if (ar->objs->objects[ar->index_current].last_known_parent) {
3785                 struct ldb_message *msg = ldb_msg_new(req);
3786                 if (msg == NULL) {
3787                         ldb_module_oom(ar->module);
3788                         return LDB_ERR_OPERATIONS_ERROR;
3789                 }
3790
3791                 msg->dn = req->op.add.message->dn;
3792
3793                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
3794                                                ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
3795                 if (ret != LDB_SUCCESS) {
3796                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
3797                         ldb_module_oom(ar->module);
3798                         return ret;
3799                 }
3800                 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
3801
3802                 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
3803                 if (ret != LDB_SUCCESS) {
3804                         DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
3805                                  ldb_dn_get_linearized(msg->dn),
3806                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3807                         return ret;
3808                 }
3809                 TALLOC_FREE(msg);
3810         }
3811
3812         return replmd_op_callback(req, ares);
3813 }
3814
3815 /*
3816   callback for replmd_replicated_apply_add()
3817   This copes with the creation of conflict records in the case where
3818   the DN exists, but with a different objectGUID
3819  */
3820 static int replmd_op_possible_conflict_callback(struct ldb_request *req, struct ldb_reply *ares, int (*callback)(struct ldb_request *req, struct ldb_reply *ares))
3821 {
3822         struct ldb_dn *conflict_dn;
3823         struct replmd_replicated_request *ar =
3824                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
3825         struct ldb_result *res;
3826         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
3827         int ret;
3828         const struct ldb_val *omd_value;
3829         struct replPropertyMetaDataBlob omd, *rmd;
3830         enum ndr_err_code ndr_err;
3831         bool rename_incoming_record, rodc;
3832         struct replPropertyMetaData1 *rmd_name, *omd_name;
3833         struct ldb_message *msg;
3834         struct ldb_request *down_req = NULL;
3835
3836         /* call the normal callback for success */
3837         if (ares->error == LDB_SUCCESS) {
3838                 return callback(req, ares);
3839         }
3840
3841         /*
3842          * we have a conflict, and need to decide if we will keep the
3843          * new record or the old record
3844          */
3845
3846         msg = ar->objs->objects[ar->index_current].msg;
3847         conflict_dn = msg->dn;
3848
3849         /* For failures other than conflicts, fail the whole operation here */
3850         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
3851                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
3852                                        ldb_dn_get_linearized(conflict_dn),
3853                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
3854
3855                 return ldb_module_done(ar->req, NULL, NULL,
3856                                        LDB_ERR_OPERATIONS_ERROR);
3857         }
3858
3859         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
3860         if (ret != LDB_SUCCESS) {
3861                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to determine if we are an RODC when attempting to form conflict DN: %s", ldb_errstring(ldb_module_get_ctx(ar->module)));
3862                 return ldb_module_done(ar->req, NULL, NULL,
3863                                        LDB_ERR_OPERATIONS_ERROR);
3864
3865         }
3866
3867         if (rodc) {
3868                 /*
3869                  * We are on an RODC, or were a GC for this
3870                  * partition, so we have to fail this until
3871                  * someone who owns the partition sorts it
3872                  * out 
3873                  */
3874                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), 
3875                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
3876                                        " - We must fail the operation until a master for this partition resolves the conflict",
3877                                        ldb_dn_get_linearized(conflict_dn));
3878                 goto failed;
3879         }
3880
3881         /*
3882          * first we need the replPropertyMetaData attribute from the
3883          * local, conflicting record
3884          */
3885         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
3886                                     attrs,
3887                                     DSDB_FLAG_NEXT_MODULE |
3888                                     DSDB_SEARCH_SHOW_DELETED |
3889                                     DSDB_SEARCH_SHOW_RECYCLED, req);
3890         if (ret != LDB_SUCCESS) {
3891                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
3892                          ldb_dn_get_linearized(conflict_dn)));
3893                 goto failed;
3894         }
3895
3896         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
3897         if (omd_value == NULL) {
3898                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
3899                          ldb_dn_get_linearized(conflict_dn)));
3900                 goto failed;
3901         }
3902
3903         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
3904                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
3905         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3906                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
3907                          ldb_dn_get_linearized(conflict_dn)));
3908                 goto failed;
3909         }
3910
3911         rmd = ar->objs->objects[ar->index_current].meta_data;
3912
3913         /*
3914          * we decide which is newer based on the RPMD on the name
3915          * attribute.  See [MS-DRSR] ResolveNameConflict.
3916          *
3917          * We expect omd_name to be present, as this is from a local
3918          * search, but while rmd_name should have been given to us by
3919          * the remote server, if it is missing we just prefer the
3920          * local name in
3921          * replmd_replPropertyMetaData1_new_should_be_taken()
3922          */
3923         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
3924         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
3925         if (!omd_name) {
3926                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
3927                          ldb_dn_get_linearized(conflict_dn)));
3928                 goto failed;
3929         }
3930
3931         /*
3932          * Should we preserve the current record, and so rename the
3933          * incoming record to be a conflict?
3934          */
3935         rename_incoming_record
3936                 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
3937                                                                     omd_name, rmd_name);
3938
3939         if (rename_incoming_record) {
3940                 struct GUID guid;
3941                 struct ldb_dn *new_dn;
3942
3943                 guid = samdb_result_guid(msg, "objectGUID");
3944                 if (GUID_all_zero(&guid)) {
3945                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
3946                                  ldb_dn_get_linearized(conflict_dn)));
3947                         goto failed;
3948                 }
3949                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3950                 if (new_dn == NULL) {
3951                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3952                                  ldb_dn_get_linearized(conflict_dn)));
3953                         goto failed;
3954                 }
3955
3956                 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
3957                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3958
3959                 /* re-submit the request, but with the new DN */
3960                 callback = replmd_op_name_modify_callback;
3961                 msg->dn = new_dn;
3962         } else {
3963                 /* we are renaming the existing record */
3964                 struct GUID guid;
3965                 struct ldb_dn *new_dn;
3966
3967                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
3968                 if (GUID_all_zero(&guid)) {
3969                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
3970                                  ldb_dn_get_linearized(conflict_dn)));
3971                         goto failed;
3972                 }
3973
3974                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
3975                 if (new_dn == NULL) {
3976                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
3977                                  ldb_dn_get_linearized(conflict_dn)));
3978                         goto failed;
3979                 }
3980
3981                 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
3982                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
3983
3984                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
3985                                          DSDB_FLAG_OWN_MODULE, req);
3986                 if (ret != LDB_SUCCESS) {
3987                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
3988                                  ldb_dn_get_linearized(conflict_dn),
3989                                  ldb_dn_get_linearized(new_dn),
3990                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
3991                         goto failed;
3992                 }
3993
3994                 /*
3995                  * now we need to ensure that the rename is seen as an
3996                  * originating update. We do that with a modify.
3997                  */
3998                 ret = replmd_name_modify(ar, req, new_dn);
3999                 if (ret != LDB_SUCCESS) {
4000                         goto failed;
4001                 }
4002
4003                 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4004                          ldb_dn_get_linearized(req->op.add.message->dn)));
4005         }
4006
4007         ret = ldb_build_add_req(&down_req,
4008                                 ldb_module_get_ctx(ar->module),
4009                                 req,
4010                                 msg,
4011                                 ar->controls,
4012                                 ar,
4013                                 callback,
4014                                 req);
4015         if (ret != LDB_SUCCESS) {
4016                 goto failed;
4017         }
4018         LDB_REQ_SET_LOCATION(down_req);
4019
4020         /* current partition control needed by "repmd_op_callback" */
4021         ret = ldb_request_add_control(down_req,
4022                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4023                                       false, NULL);
4024         if (ret != LDB_SUCCESS) {
4025                 return replmd_replicated_request_error(ar, ret);
4026         }
4027
4028         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4029                 /* this tells the partition module to make it a
4030                    partial replica if creating an NC */
4031                 ret = ldb_request_add_control(down_req,
4032                                               DSDB_CONTROL_PARTIAL_REPLICA,
4033                                               false, NULL);
4034                 if (ret != LDB_SUCCESS) {
4035                         return replmd_replicated_request_error(ar, ret);
4036                 }
4037         }
4038
4039         /*
4040          * Finally we re-run the add, otherwise the new record won't
4041          * exist, as we are here because of that exact failure!
4042          */
4043         return ldb_next_request(ar->module, down_req);
4044 failed:
4045
4046         /* on failure make the caller get the error. This means
4047          * replication will stop with an error, but there is not much
4048          * else we can do.
4049          */
4050         return ldb_module_done(ar->req, NULL, NULL,
4051                                ret);
4052 }
4053
4054 /*
4055   callback for replmd_replicated_apply_add()
4056   This copes with the creation of conflict records in the case where
4057   the DN exists, but with a different objectGUID
4058  */
4059 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4060 {
4061         struct replmd_replicated_request *ar =
4062                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4063
4064         if (ar->objs->objects[ar->index_current].last_known_parent) {
4065                 /* This is like a conflict DN, where we put the object in LostAndFound
4066                    see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4067                 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4068         }
4069
4070         return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4071 }
4072
4073 /*
4074   this is called when a new object comes in over DRS
4075  */
4076 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4077 {
4078         struct ldb_context *ldb;
4079         struct ldb_request *change_req;
4080         enum ndr_err_code ndr_err;
4081         struct ldb_message *msg;
4082         struct replPropertyMetaDataBlob *md;
4083         struct ldb_val md_value;
4084         unsigned int i;
4085         int ret;
4086         bool remote_isDeleted = false;
4087         bool is_schema_nc;
4088         NTTIME now;
4089         time_t t = time(NULL);
4090         const struct ldb_val *rdn_val;
4091         struct replmd_private *replmd_private =
4092                 talloc_get_type(ldb_module_get_private(ar->module),
4093                                 struct replmd_private);
4094         unix_to_nt_time(&now, t);
4095
4096         ldb = ldb_module_get_ctx(ar->module);
4097         msg = ar->objs->objects[ar->index_current].msg;
4098         md = ar->objs->objects[ar->index_current].meta_data;
4099         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4100
4101         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4102         if (ret != LDB_SUCCESS) {
4103                 return replmd_replicated_request_error(ar, ret);
4104         }
4105
4106         ret = dsdb_msg_add_guid(msg,
4107                                 &ar->objs->objects[ar->index_current].object_guid,
4108                                 "objectGUID");
4109         if (ret != LDB_SUCCESS) {
4110                 return replmd_replicated_request_error(ar, ret);
4111         }
4112
4113         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4114         if (ret != LDB_SUCCESS) {
4115                 return replmd_replicated_request_error(ar, ret);
4116         }
4117
4118         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4119         if (ret != LDB_SUCCESS) {
4120                 return replmd_replicated_request_error(ar, ret);
4121         }
4122
4123         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4124         if (ret != LDB_SUCCESS) {
4125                 return replmd_replicated_request_error(ar, ret);
4126         }
4127
4128         /* remove any message elements that have zero values */
4129         for (i=0; i<msg->num_elements; i++) {
4130                 struct ldb_message_element *el = &msg->elements[i];
4131
4132                 if (el->num_values == 0) {
4133                         if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4134                                 ldb_asprintf_errstring(ldb, __location__
4135                                                        ": empty objectClass sent on %s, aborting replication\n",
4136                                                        ldb_dn_get_linearized(msg->dn));
4137                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4138                         }
4139
4140                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4141                                  el->name));
4142                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4143                         msg->num_elements--;
4144                         i--;
4145                         continue;
4146                 }
4147         }
4148
4149         if (DEBUGLVL(4)) {
4150                 struct GUID_txt_buf guid_txt;
4151
4152                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4153                 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4154                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4155                           s));
4156                 talloc_free(s);
4157         }
4158
4159         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4160                                                      "isDeleted", false);
4161
4162         /*
4163          * the meta data array is already sorted by the caller, except
4164          * for the RDN, which needs to be added.
4165          */
4166
4167
4168         rdn_val = ldb_dn_get_rdn_val(msg->dn);
4169         ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4170                                      md, ar, now, is_schema_nc);
4171         if (ret != LDB_SUCCESS) {
4172                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4173                 return replmd_replicated_request_error(ar, ret);
4174         }
4175
4176         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4177         if (ret != LDB_SUCCESS) {
4178                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4179                 return replmd_replicated_request_error(ar, ret);
4180         }
4181
4182         for (i=0; i < md->ctr.ctr1.count; i++) {
4183                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4184         }
4185         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4186                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4187         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4188                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4189                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4190         }
4191         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4192         if (ret != LDB_SUCCESS) {
4193                 return replmd_replicated_request_error(ar, ret);
4194         }
4195
4196         replmd_ldb_message_sort(msg, ar->schema);
4197
4198         if (!remote_isDeleted) {
4199                 ret = dsdb_module_schedule_sd_propagation(ar->module,
4200                                                           ar->objs->partition_dn,
4201                                                           msg->dn, true);
4202                 if (ret != LDB_SUCCESS) {
4203                         return replmd_replicated_request_error(ar, ret);
4204                 }
4205         }
4206
4207         ar->isDeleted = remote_isDeleted;
4208
4209         ret = ldb_build_add_req(&change_req,
4210                                 ldb,
4211                                 ar,
4212                                 msg,
4213                                 ar->controls,
4214                                 ar,
4215                                 replmd_op_add_callback,
4216                                 ar->req);
4217         LDB_REQ_SET_LOCATION(change_req);
4218         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4219
4220         /* current partition control needed by "repmd_op_callback" */
4221         ret = ldb_request_add_control(change_req,
4222                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4223                                       false, NULL);
4224         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4225
4226         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4227                 /* this tells the partition module to make it a
4228                    partial replica if creating an NC */
4229                 ret = ldb_request_add_control(change_req,
4230                                               DSDB_CONTROL_PARTIAL_REPLICA,
4231                                               false, NULL);
4232                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4233         }
4234
4235         return ldb_next_request(ar->module, change_req);
4236 }
4237
4238 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4239                                                               struct ldb_reply *ares)
4240 {
4241         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4242                                                struct replmd_replicated_request);
4243         int ret;
4244
4245         if (!ares) {
4246                 return ldb_module_done(ar->req, NULL, NULL,
4247                                         LDB_ERR_OPERATIONS_ERROR);
4248         }
4249
4250         /*
4251          * The error NO_SUCH_OBJECT is not expected, unless the search
4252          * base is the partition DN, and that case doesn't happen here
4253          * because then we wouldn't get a parent_guid_value in any
4254          * case.
4255          */
4256         if (ares->error != LDB_SUCCESS) {
4257                 return ldb_module_done(ar->req, ares->controls,
4258                                         ares->response, ares->error);
4259         }
4260
4261         switch (ares->type) {
4262         case LDB_REPLY_ENTRY:
4263         {
4264                 struct ldb_message *parent_msg = ares->message;
4265                 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4266                 struct ldb_dn *parent_dn;
4267                 int comp_num;
4268
4269                 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4270                     && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4271                         /* Per MS-DRSR 4.1.10.6.10
4272                          * FindBestParentObject we need to move this
4273                          * new object under a deleted object to
4274                          * lost-and-found */
4275                         struct ldb_dn *nc_root;
4276
4277                         ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4278                         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4279                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4280                                                        "No suitable NC root found for %s.  "
4281                                                        "We need to move this object because parent object %s "
4282                                                        "is deleted, but this object is not.",
4283                                                        ldb_dn_get_linearized(msg->dn),
4284                                                        ldb_dn_get_linearized(parent_msg->dn));
4285                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4286                         } else if (ret != LDB_SUCCESS) {
4287                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4288                                                        "Unable to find NC root for %s: %s. "
4289                                                        "We need to move this object because parent object %s "
4290                                                        "is deleted, but this object is not.",
4291                                                        ldb_dn_get_linearized(msg->dn),
4292                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
4293                                                        ldb_dn_get_linearized(parent_msg->dn));
4294                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4295                         }
4296                         
4297                         ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
4298                                                 nc_root,
4299                                                 DS_GUID_LOSTANDFOUND_CONTAINER,
4300                                                 &parent_dn);
4301                         if (ret != LDB_SUCCESS) {
4302                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4303                                                        "Unable to find LostAndFound Container for %s "
4304                                                        "in partition %s: %s. "
4305                                                        "We need to move this object because parent object %s "
4306                                                        "is deleted, but this object is not.",
4307                                                        ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
4308                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
4309                                                        ldb_dn_get_linearized(parent_msg->dn));
4310                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4311                         }
4312                         ar->objs->objects[ar->index_current].last_known_parent
4313                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4314
4315                 } else {
4316                         parent_dn
4317                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
4318
4319                 }
4320                 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
4321
4322                 comp_num = ldb_dn_get_comp_num(msg->dn);
4323                 if (comp_num > 1) {
4324                         if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
4325                                 talloc_free(ares);
4326                                 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4327                         }
4328                 }
4329                 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
4330                         talloc_free(ares);
4331                         return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
4332                 }
4333                 break;
4334         }
4335         case LDB_REPLY_REFERRAL:
4336                 /* we ignore referrals */
4337                 break;
4338
4339         case LDB_REPLY_DONE:
4340
4341                 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
4342                         struct GUID_txt_buf str_buf;
4343                         if (ar->search_msg != NULL) {
4344                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4345                                                        "No parent with GUID %s found for object locally known as %s",
4346                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4347                                                        ldb_dn_get_linearized(ar->search_msg->dn));
4348                         } else {
4349                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4350                                                        "No parent with GUID %s found for object remotely known as %s",
4351                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
4352                                                        ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
4353                         }
4354
4355                         /*
4356                          * This error code is really important, as it
4357                          * is the flag back to the callers to retry
4358                          * this with DRSUAPI_DRS_GET_ANC, and so get
4359                          * the parent objects before the child
4360                          * objects
4361                          */
4362                         return ldb_module_done(ar->req, NULL, NULL,
4363                                                replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
4364                 }
4365
4366                 if (ar->search_msg != NULL) {
4367                         ret = replmd_replicated_apply_merge(ar);
4368                 } else {
4369                         ret = replmd_replicated_apply_add(ar);
4370                 }
4371                 if (ret != LDB_SUCCESS) {
4372                         return ldb_module_done(ar->req, NULL, NULL, ret);
4373                 }
4374         }
4375
4376         talloc_free(ares);
4377         return LDB_SUCCESS;
4378 }
4379
4380 /*
4381  * Look for the parent object, so we put the new object in the right
4382  * place This is akin to NameObject in MS-DRSR - this routine and the
4383  * callbacks find the right parent name, and correct name for this
4384  * object
4385  */
4386
4387 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
4388 {
4389         struct ldb_context *ldb;
4390         int ret;
4391         char *tmp_str;
4392         char *filter;
4393         struct ldb_request *search_req;
4394         static const char *attrs[] = {"isDeleted", NULL};
4395         struct GUID_txt_buf guid_str_buf;
4396
4397         ldb = ldb_module_get_ctx(ar->module);
4398
4399         if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
4400                 if (ar->search_msg != NULL) {
4401                         return replmd_replicated_apply_merge(ar);
4402                 } else {
4403                         return replmd_replicated_apply_add(ar);
4404                 }
4405         }
4406
4407         tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
4408                                   &guid_str_buf);
4409
4410         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
4411         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4412
4413         ret = ldb_build_search_req(&search_req,
4414                                    ldb,
4415                                    ar,
4416                                    ar->objs->partition_dn,
4417                                    LDB_SCOPE_SUBTREE,
4418                                    filter,
4419                                    attrs,
4420                                    NULL,
4421                                    ar,
4422                                    replmd_replicated_apply_search_for_parent_callback,
4423                                    ar->req);
4424         LDB_REQ_SET_LOCATION(search_req);
4425
4426         ret = dsdb_request_add_controls(search_req, 
4427                                         DSDB_SEARCH_SHOW_RECYCLED|
4428                                         DSDB_SEARCH_SHOW_DELETED|
4429                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
4430         if (ret != LDB_SUCCESS) {
4431                 return ret;
4432         }
4433
4434         return ldb_next_request(ar->module, search_req);
4435 }
4436
4437 /*
4438   handle renames that come in over DRS replication
4439  */
4440 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
4441                                            struct ldb_message *msg,
4442                                            struct ldb_request *parent,
4443                                            bool *renamed)
4444 {
4445         int ret;
4446         TALLOC_CTX *tmp_ctx = talloc_new(msg);
4447         struct ldb_result *res;
4448         struct ldb_dn *conflict_dn;
4449         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4450         const struct ldb_val *omd_value;
4451         struct replPropertyMetaDataBlob omd, *rmd;
4452         enum ndr_err_code ndr_err;
4453         bool rename_incoming_record, rodc;
4454         struct replPropertyMetaData1 *rmd_name, *omd_name;
4455         struct ldb_dn *new_dn;
4456         struct GUID guid;
4457
4458         DEBUG(4,("replmd_replicated_request rename %s => %s\n",
4459                  ldb_dn_get_linearized(ar->search_msg->dn),
4460                  ldb_dn_get_linearized(msg->dn)));
4461
4462
4463         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4464                                  DSDB_FLAG_NEXT_MODULE, ar->req);
4465         if (ret == LDB_SUCCESS) {
4466                 talloc_free(tmp_ctx);
4467                 *renamed = true;
4468                 return ret;
4469         }
4470
4471         if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4472                 talloc_free(tmp_ctx);
4473                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
4474                                        ldb_dn_get_linearized(ar->search_msg->dn),
4475                                        ldb_dn_get_linearized(msg->dn),
4476                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
4477                 return ret;
4478         }
4479
4480         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4481         if (ret != LDB_SUCCESS) {
4482                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4483                                        "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
4484                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
4485                 return LDB_ERR_OPERATIONS_ERROR;
4486         }
4487         /*
4488          * we have a conflict, and need to decide if we will keep the
4489          * new record or the old record
4490          */
4491
4492         conflict_dn = msg->dn;
4493
4494         if (rodc) {
4495                 /*
4496                  * We are on an RODC, or were a GC for this
4497                  * partition, so we have to fail this until
4498                  * someone who owns the partition sorts it
4499                  * out
4500                  */
4501                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4502                                        "Conflict adding object '%s' from incoming replication but we are read only for the partition.  \n"
4503                                        " - We must fail the operation until a master for this partition resolves the conflict",
4504                                        ldb_dn_get_linearized(conflict_dn));
4505                 goto failed;
4506         }
4507
4508         /*
4509          * first we need the replPropertyMetaData attribute from the
4510          * old record
4511          */
4512         ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
4513                                     attrs,
4514                                     DSDB_FLAG_NEXT_MODULE |
4515                                     DSDB_SEARCH_SHOW_DELETED |
4516                                     DSDB_SEARCH_SHOW_RECYCLED, ar->req);
4517         if (ret != LDB_SUCCESS) {
4518                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4519                          ldb_dn_get_linearized(conflict_dn)));
4520                 goto failed;
4521         }
4522
4523         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4524         if (omd_value == NULL) {
4525                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4526                          ldb_dn_get_linearized(conflict_dn)));
4527                 goto failed;
4528         }
4529
4530         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4531                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4532         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4533                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4534                          ldb_dn_get_linearized(conflict_dn)));
4535                 goto failed;
4536         }
4537
4538         rmd = ar->objs->objects[ar->index_current].meta_data;
4539
4540         /*
4541          * we decide which is newer based on the RPMD on the name
4542          * attribute.  See [MS-DRSR] ResolveNameConflict.
4543          *
4544          * We expect omd_name to be present, as this is from a local
4545          * search, but while rmd_name should have been given to us by
4546          * the remote server, if it is missing we just prefer the
4547          * local name in
4548          * replmd_replPropertyMetaData1_new_should_be_taken()
4549          */
4550         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4551         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4552         if (!omd_name) {
4553                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4554                          ldb_dn_get_linearized(conflict_dn)));
4555                 goto failed;
4556         }
4557
4558         /*
4559          * Should we preserve the current record, and so rename the
4560          * incoming record to be a conflict?
4561          */
4562         rename_incoming_record =
4563                 !replmd_replPropertyMetaData1_new_should_be_taken(
4564                         ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4565                         omd_name, rmd_name);
4566
4567         if (rename_incoming_record) {
4568
4569                 new_dn = replmd_conflict_dn(msg, msg->dn,
4570                                             &ar->objs->objects[ar->index_current].object_guid);
4571                 if (new_dn == NULL) {
4572                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4573                                                                   "Failed to form conflict DN for %s\n",
4574                                                                   ldb_dn_get_linearized(msg->dn));
4575
4576                         return replmd_replicated_request_werror(ar, WERR_NOMEM);
4577                 }
4578
4579                 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
4580                                          DSDB_FLAG_NEXT_MODULE, ar->req);
4581                 if (ret != LDB_SUCCESS) {
4582                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4583                                                "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
4584                                                ldb_dn_get_linearized(conflict_dn),
4585                                                ldb_dn_get_linearized(ar->search_msg->dn),
4586                                                ldb_dn_get_linearized(new_dn),
4587                                                ldb_errstring(ldb_module_get_ctx(ar->module)));
4588                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4589                 }
4590
4591                 msg->dn = new_dn;
4592                 *renamed = true;
4593                 return LDB_SUCCESS;
4594         }
4595
4596         /* we are renaming the existing record */
4597
4598         guid = samdb_result_guid(res->msgs[0], "objectGUID");
4599         if (GUID_all_zero(&guid)) {
4600                 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4601                          ldb_dn_get_linearized(conflict_dn)));
4602                 goto failed;
4603         }
4604
4605         new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
4606         if (new_dn == NULL) {
4607                 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4608                          ldb_dn_get_linearized(conflict_dn)));
4609                 goto failed;
4610         }
4611
4612         DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4613                  ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4614
4615         ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4616                                  DSDB_FLAG_OWN_MODULE, ar->req);
4617         if (ret != LDB_SUCCESS) {
4618                 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4619                          ldb_dn_get_linearized(conflict_dn),
4620                          ldb_dn_get_linearized(new_dn),
4621                          ldb_errstring(ldb_module_get_ctx(ar->module))));
4622                 goto failed;
4623         }
4624
4625         /*
4626          * now we need to ensure that the rename is seen as an
4627          * originating update. We do that with a modify.
4628          */
4629         ret = replmd_name_modify(ar, ar->req, new_dn);
4630         if (ret != LDB_SUCCESS) {
4631                 goto failed;
4632         }
4633
4634         DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
4635                  ldb_dn_get_linearized(ar->search_msg->dn),
4636                  ldb_dn_get_linearized(msg->dn)));
4637
4638
4639         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
4640                                  DSDB_FLAG_NEXT_MODULE, ar->req);
4641         if (ret != LDB_SUCCESS) {
4642                 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
4643                          ldb_dn_get_linearized(ar->search_msg->dn),
4644                          ldb_dn_get_linearized(msg->dn),
4645                          ldb_errstring(ldb_module_get_ctx(ar->module))));
4646                         goto failed;
4647         }
4648 failed:
4649
4650         /*
4651          * On failure make the caller get the error
4652          * This means replication will stop with an error,
4653          * but there is not much else we can do.  In the
4654          * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
4655          * needed.
4656          */
4657
4658         talloc_free(tmp_ctx);
4659         return ret;
4660 }
4661
4662
4663 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
4664 {
4665         struct ldb_context *ldb;
4666         struct ldb_request *change_req;
4667         enum ndr_err_code ndr_err;
4668         struct ldb_message *msg;
4669         struct replPropertyMetaDataBlob *rmd;
4670         struct replPropertyMetaDataBlob omd;
4671         const struct ldb_val *omd_value;
4672         struct replPropertyMetaDataBlob nmd;
4673         struct ldb_val nmd_value;
4674         struct GUID remote_parent_guid;
4675         unsigned int i;
4676         uint32_t j,ni=0;
4677         unsigned int removed_attrs = 0;
4678         int ret;
4679         int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
4680         bool isDeleted = false;
4681         bool local_isDeleted = false;
4682         bool remote_isDeleted = false;
4683         bool take_remote_isDeleted = false;
4684         bool sd_updated = false;
4685         bool renamed = false;
4686         bool is_schema_nc = false;
4687         NTSTATUS nt_status;
4688         const struct ldb_val *old_rdn, *new_rdn;
4689         struct replmd_private *replmd_private =
4690                 talloc_get_type(ldb_module_get_private(ar->module),
4691                                 struct replmd_private);
4692         NTTIME now;
4693         time_t t = time(NULL);
4694         unix_to_nt_time(&now, t);
4695
4696         ldb = ldb_module_get_ctx(ar->module);
4697         msg = ar->objs->objects[ar->index_current].msg;
4698
4699         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4700
4701         rmd = ar->objs->objects[ar->index_current].meta_data;
4702         ZERO_STRUCT(omd);
4703         omd.version = 1;
4704
4705         /* find existing meta data */
4706         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
4707         if (omd_value) {
4708                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
4709                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4710                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4711                         nt_status = ndr_map_error2ntstatus(ndr_err);
4712                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4713                 }
4714
4715                 if (omd.version != 1) {
4716                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
4717                 }
4718         }
4719
4720         if (DEBUGLVL(5)) {
4721                 struct GUID_txt_buf guid_txt;
4722
4723                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4724                 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
4725                           "%s\n"
4726                           "%s\n",
4727                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4728                           s,
4729                           ndr_print_struct_string(s,
4730                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
4731                                                   "existing replPropertyMetaData",
4732                                                   &omd),
4733                           ndr_print_struct_string(s,
4734                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
4735                                                   "incoming replPropertyMetaData",
4736                                                   rmd)));
4737                 talloc_free(s);
4738         }
4739
4740         local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
4741                                                     "isDeleted", false);
4742         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4743                                                      "isDeleted", false);
4744
4745         /*
4746          * Fill in the remote_parent_guid with the GUID or an all-zero
4747          * GUID.
4748          */
4749         if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
4750                 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
4751         } else {
4752                 remote_parent_guid = GUID_zero();
4753         }
4754
4755         /*
4756          * To ensure we follow a complex rename chain around, we have
4757          * to confirm that the DN is the same (mostly to confirm the
4758          * RDN) and the parentGUID is the same.
4759          *
4760          * This ensures we keep things under the correct parent, which
4761          * replmd_replicated_handle_rename() will do.
4762          */
4763
4764         if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
4765             && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
4766                 ret = LDB_SUCCESS;
4767         } else {
4768                 /*
4769                  * handle renames, even just by case that come in over
4770                  * DRS.  Changes in the parent DN don't hit us here,
4771                  * because the search for a parent will clean up those
4772                  * components.
4773                  *
4774                  * We also have already filtered out the case where
4775                  * the peer has an older name to what we have (see
4776                  * replmd_replicated_apply_search_callback())
4777                  */
4778                 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
4779         }
4780
4781         if (ret != LDB_SUCCESS) {
4782                 ldb_debug(ldb, LDB_DEBUG_FATAL,
4783                           "replmd_replicated_request rename %s => %s failed - %s\n",
4784                           ldb_dn_get_linearized(ar->search_msg->dn),
4785                           ldb_dn_get_linearized(msg->dn),
4786                           ldb_errstring(ldb));
4787                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
4788         }
4789
4790         if (renamed == true) {
4791                 /*
4792                  * Set the callback to one that will fix up the name
4793                  * metadata on the new conflict DN
4794                  */
4795                 callback = replmd_op_name_modify_callback;
4796         }
4797
4798         ZERO_STRUCT(nmd);
4799         nmd.version = 1;
4800         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
4801         nmd.ctr.ctr1.array = talloc_array(ar,
4802                                           struct replPropertyMetaData1,
4803                                           nmd.ctr.ctr1.count);
4804         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOMEM);
4805
4806         /* first copy the old meta data */
4807         for (i=0; i < omd.ctr.ctr1.count; i++) {
4808                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
4809                 ni++;
4810         }
4811
4812         ar->seq_num = 0;
4813         /* now merge in the new meta data */
4814         for (i=0; i < rmd->ctr.ctr1.count; i++) {
4815                 bool found = false;
4816
4817                 for (j=0; j < ni; j++) {
4818                         bool cmp;
4819
4820                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
4821                                 continue;
4822                         }
4823
4824                         cmp = replmd_replPropertyMetaData1_new_should_be_taken(
4825                                 ar->objs->dsdb_repl_flags,
4826                                 &nmd.ctr.ctr1.array[j],
4827                                 &rmd->ctr.ctr1.array[i]);
4828                         if (cmp) {
4829                                 /* replace the entry */
4830                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
4831                                 if (ar->seq_num == 0) {
4832                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4833                                         if (ret != LDB_SUCCESS) {
4834                                                 return replmd_replicated_request_error(ar, ret);
4835                                         }
4836                                 }
4837                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
4838                                 switch (nmd.ctr.ctr1.array[j].attid) {
4839                                 case DRSUAPI_ATTID_ntSecurityDescriptor:
4840                                         sd_updated = true;
4841                                         break;
4842                                 case DRSUAPI_ATTID_isDeleted:
4843                                         take_remote_isDeleted = true;
4844                                         break;
4845                                 default:
4846                                         break;
4847                                 }
4848                                 found = true;
4849                                 break;
4850                         }
4851
4852                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
4853                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
4854                                          msg->elements[i-removed_attrs].name,
4855                                          ldb_dn_get_linearized(msg->dn),
4856                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
4857                         }
4858
4859                         /* we don't want to apply this change so remove the attribute */
4860                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
4861                         removed_attrs++;
4862
4863                         found = true;
4864                         break;
4865                 }
4866
4867                 if (found) continue;
4868
4869                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
4870                 if (ar->seq_num == 0) {
4871                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4872                         if (ret != LDB_SUCCESS) {
4873                                 return replmd_replicated_request_error(ar, ret);
4874                         }
4875                 }
4876                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
4877                 switch (nmd.ctr.ctr1.array[ni].attid) {
4878                 case DRSUAPI_ATTID_ntSecurityDescriptor:
4879                         sd_updated = true;
4880                         break;
4881                 case DRSUAPI_ATTID_isDeleted:
4882                         take_remote_isDeleted = true;
4883                         break;
4884                 default:
4885                         break;
4886                 }
4887                 ni++;
4888         }
4889
4890         /*
4891          * finally correct the size of the meta_data array
4892          */
4893         nmd.ctr.ctr1.count = ni;
4894
4895         new_rdn = ldb_dn_get_rdn_val(msg->dn);
4896         old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
4897
4898         if (renamed) {
4899                 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
4900                                                   &nmd, ar, now, is_schema_nc);
4901                 if (ret != LDB_SUCCESS) {
4902                         ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
4903                         return replmd_replicated_request_error(ar, ret);
4904                 }
4905         }
4906         /*
4907          * sort the new meta data array
4908          */
4909         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
4910         if (ret != LDB_SUCCESS) {
4911                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
4912                 return ret;
4913         }
4914
4915         /*
4916          * Work out if this object is deleted, so we can prune any extra attributes.  See MS-DRSR 4.1.10.6.9
4917          * UpdateObject.
4918          *
4919          * This also controls SD propagation below
4920          */
4921         if (take_remote_isDeleted) {
4922                 isDeleted = remote_isDeleted;
4923         } else {
4924                 isDeleted = local_isDeleted;
4925         }
4926
4927         ar->isDeleted = isDeleted;
4928
4929         /*
4930          * check if some replicated attributes left, otherwise skip the ldb_modify() call
4931          */
4932         if (msg->num_elements == 0) {
4933                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
4934                           ar->index_current);
4935
4936                 return replmd_replicated_apply_isDeleted(ar);
4937         }
4938
4939         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
4940                   ar->index_current, msg->num_elements);
4941
4942         if (renamed) {
4943                 sd_updated = true;
4944         }
4945
4946         if (sd_updated && !isDeleted) {
4947                 ret = dsdb_module_schedule_sd_propagation(ar->module,
4948                                                           ar->objs->partition_dn,
4949                                                           msg->dn, true);
4950                 if (ret != LDB_SUCCESS) {
4951                         return ldb_operr(ldb);
4952                 }
4953         }
4954
4955         /* create the meta data value */
4956         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
4957                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4958         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4959                 nt_status = ndr_map_error2ntstatus(ndr_err);
4960                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4961         }
4962
4963         /*
4964          * when we know that we'll modify the record, add the whenChanged, uSNChanged
4965          * and replPopertyMetaData attributes
4966          */
4967         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4968         if (ret != LDB_SUCCESS) {
4969                 return replmd_replicated_request_error(ar, ret);
4970         }
4971         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4972         if (ret != LDB_SUCCESS) {
4973                 return replmd_replicated_request_error(ar, ret);
4974         }
4975         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
4976         if (ret != LDB_SUCCESS) {
4977                 return replmd_replicated_request_error(ar, ret);
4978         }
4979
4980         replmd_ldb_message_sort(msg, ar->schema);
4981
4982         /* we want to replace the old values */
4983         for (i=0; i < msg->num_elements; i++) {
4984                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
4985                 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4986                         if (msg->elements[i].num_values == 0) {
4987                                 ldb_asprintf_errstring(ldb, __location__
4988                                                        ": objectClass removed on %s, aborting replication\n",
4989                                                        ldb_dn_get_linearized(msg->dn));
4990                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4991                         }
4992                 }
4993         }
4994
4995         if (DEBUGLVL(4)) {
4996                 struct GUID_txt_buf guid_txt;
4997
4998                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
4999                 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5000                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5001                           s));
5002                 talloc_free(s);
5003         }
5004
5005         ret = ldb_build_mod_req(&change_req,
5006                                 ldb,
5007                                 ar,
5008                                 msg,
5009                                 ar->controls,
5010                                 ar,
5011                                 callback,
5012                                 ar->req);
5013         LDB_REQ_SET_LOCATION(change_req);
5014         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5015
5016         /* current partition control needed by "repmd_op_callback" */
5017         ret = ldb_request_add_control(change_req,
5018                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
5019                                       false, NULL);
5020         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5021
5022         return ldb_next_request(ar->module, change_req);
5023 }
5024
5025 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5026                                                    struct ldb_reply *ares)
5027 {
5028         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5029                                                struct replmd_replicated_request);
5030         int ret;
5031
5032         if (!ares) {
5033                 return ldb_module_done(ar->req, NULL, NULL,
5034                                         LDB_ERR_OPERATIONS_ERROR);
5035         }
5036         if (ares->error != LDB_SUCCESS &&
5037             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5038                 return ldb_module_done(ar->req, ares->controls,
5039                                         ares->response, ares->error);
5040         }
5041
5042         switch (ares->type) {
5043         case LDB_REPLY_ENTRY:
5044                 ar->search_msg = talloc_steal(ar, ares->message);
5045                 break;
5046
5047         case LDB_REPLY_REFERRAL:
5048                 /* we ignore referrals */
5049                 break;
5050
5051         case LDB_REPLY_DONE:
5052         {
5053                 struct replPropertyMetaData1 *md_remote;
5054                 struct replPropertyMetaData1 *md_local;
5055
5056                 struct replPropertyMetaDataBlob omd;
5057                 const struct ldb_val *omd_value;
5058                 struct replPropertyMetaDataBlob *rmd;
5059                 struct ldb_message *msg;
5060                 int instanceType;
5061                 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5062                 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5063
5064                 /*
5065                  * This is the ADD case, find the appropriate parent,
5066                  * as this object doesn't exist locally:
5067                  */
5068                 if (ar->search_msg == NULL) {
5069                         ret = replmd_replicated_apply_search_for_parent(ar);
5070                         if (ret != LDB_SUCCESS) {
5071                                 return ldb_module_done(ar->req, NULL, NULL, ret);
5072                         }
5073                         talloc_free(ares);
5074                         return LDB_SUCCESS;
5075                 }
5076
5077                 /*
5078                  * Otherwise, in the MERGE case, work out if we are
5079                  * attempting a rename, and if so find the parent the
5080                  * newly renamed object wants to belong under (which
5081                  * may not be the parent in it's attached string DN
5082                  */
5083                 rmd = ar->objs->objects[ar->index_current].meta_data;
5084                 ZERO_STRUCT(omd);
5085                 omd.version = 1;
5086
5087                 /* find existing meta data */
5088                 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5089                 if (omd_value) {
5090                         enum ndr_err_code ndr_err;
5091                         ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5092                                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5093                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5094                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5095                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5096                         }
5097
5098                         if (omd.version != 1) {
5099                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5100                         }
5101                 }
5102
5103                 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5104
5105                 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5106                 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5107                     && GUID_all_zero(&ar->local_parent_guid)) {
5108                         DEBUG(0, ("Refusing to replicate new version of %s "
5109                                   "as local object has an all-zero parentGUID attribute, "
5110                                   "despite not being an NC root\n",
5111                                   ldb_dn_get_linearized(ar->search_msg->dn)));
5112                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5113                 }
5114
5115                 /*
5116                  * now we need to check for double renames. We could have a
5117                  * local rename pending which our replication partner hasn't
5118                  * received yet. We choose which one wins by looking at the
5119                  * attribute stamps on the two objects, the newer one wins.
5120                  *
5121                  * This also simply applies the correct algorithms for
5122                  * determining if a change was made to name at all, or
5123                  * if the object has just been renamed under the same
5124                  * parent.
5125                  */
5126                 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5127                 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5128                 if (!md_local) {
5129                         DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5130                                  ldb_dn_get_linearized(ar->search_msg->dn)));
5131                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5132                 }
5133
5134                 /*
5135                  * if there is no name attribute given then we have to assume the
5136                  *  object we've received has the older name
5137                  */
5138                 if (replmd_replPropertyMetaData1_new_should_be_taken(
5139                             ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5140                             md_local, md_remote)) {
5141                         struct GUID_txt_buf p_guid_local;
5142                         struct GUID_txt_buf p_guid_remote;
5143                         msg = ar->objs->objects[ar->index_current].msg;
5144
5145                         /* Merge on the existing object, with rename */
5146
5147                         DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5148                                  "as incoming object changing to %s under %s\n",
5149                                  ldb_dn_get_linearized(ar->search_msg->dn),
5150                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5151                                  ldb_dn_get_linearized(msg->dn),
5152                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5153                                                  &p_guid_remote)));
5154                         ret = replmd_replicated_apply_search_for_parent(ar);
5155                 } else {
5156                         struct GUID_txt_buf p_guid_local;
5157                         struct GUID_txt_buf p_guid_remote;
5158                         msg = ar->objs->objects[ar->index_current].msg;
5159
5160                         /*
5161                          * Merge on the existing object, force no
5162                          * rename (code below just to explain why in
5163                          * the DEBUG() logs)
5164                          */
5165
5166                         if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5167                                    ldb_dn_get_linearized(msg->dn)) == 0) {
5168                                 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5169                                     GUID_equal(&ar->local_parent_guid,
5170                                                ar->objs->objects[ar->index_current].parent_guid)
5171                                     == false) {
5172                                         DEBUG(4,(__location__ ": Keeping object %s at under %s "
5173                                                  "despite incoming object changing parent to %s\n",
5174                                                  ldb_dn_get_linearized(ar->search_msg->dn),
5175                                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5176                                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5177                                                                  &p_guid_remote)));
5178                                 }
5179                         } else {
5180                                 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5181                                          " and rejecting older rename to %s under %s\n",
5182                                          ldb_dn_get_linearized(ar->search_msg->dn),
5183                                          GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5184                                          ldb_dn_get_linearized(msg->dn),
5185                                          GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5186                                                          &p_guid_remote)));
5187                         }
5188                         /*
5189                          * This assignment ensures that the strcmp()
5190                          * and GUID_equal() calls in
5191                          * replmd_replicated_apply_merge() avoids the
5192                          * rename call
5193                          */
5194                         ar->objs->objects[ar->index_current].parent_guid =
5195                                 &ar->local_parent_guid;
5196
5197                         msg->dn = ar->search_msg->dn;
5198                         ret = replmd_replicated_apply_merge(ar);
5199                 }
5200                 if (ret != LDB_SUCCESS) {
5201                         return ldb_module_done(ar->req, NULL, NULL, ret);
5202                 }
5203         }
5204         }
5205
5206         talloc_free(ares);
5207         return LDB_SUCCESS;
5208 }
5209
5210 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5211
5212 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5213 {
5214         struct ldb_context *ldb;
5215         int ret;
5216         char *tmp_str;
5217         char *filter;
5218         struct ldb_request *search_req;
5219         static const char *attrs[] = { "*", "parentGUID", "instanceType",
5220                                        "replPropertyMetaData", "nTSecurityDescriptor",
5221                                        NULL };
5222         struct GUID_txt_buf guid_str_buf;
5223
5224         if (ar->index_current >= ar->objs->num_objects) {
5225                 /* done with it, go to next stage */
5226                 return replmd_replicated_uptodate_vector(ar);
5227         }
5228
5229         ldb = ldb_module_get_ctx(ar->module);
5230         ar->search_msg = NULL;
5231         ar->isDeleted = false;
5232
5233         tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5234                                   &guid_str_buf);
5235
5236         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5237         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5238
5239         ret = ldb_build_search_req(&search_req,
5240                                    ldb,
5241                                    ar,
5242                                    ar->objs->partition_dn,
5243                                    LDB_SCOPE_SUBTREE,
5244                                    filter,
5245                                    attrs,
5246                                    NULL,
5247                                    ar,
5248                                    replmd_replicated_apply_search_callback,
5249                                    ar->req);
5250         LDB_REQ_SET_LOCATION(search_req);
5251
5252         ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5253
5254         if (ret != LDB_SUCCESS) {
5255                 return ret;
5256         }
5257
5258         return ldb_next_request(ar->module, search_req);
5259 }
5260
5261 /*
5262  * This is essentially a wrapper for replmd_replicated_apply_next()
5263  *
5264  * This is needed to ensure that both codepaths call this handler.
5265  */
5266 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5267 {
5268         struct ldb_dn *deleted_objects_dn;
5269         struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5270         int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5271                                               &deleted_objects_dn);
5272         if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5273                 /*
5274                  * Do a delete here again, so that if there is
5275                  * anything local that conflicts with this
5276                  * object being deleted, it is removed.  This
5277                  * includes links.  See MS-DRSR 4.1.10.6.9
5278                  * UpdateObject.
5279                  *
5280                  * If the object is already deleted, and there
5281                  * is no more work required, it doesn't do
5282                  * anything.
5283                  */
5284
5285                 /* This has been updated to point to the DN we eventually did the modify on */
5286
5287                 struct ldb_request *del_req;
5288                 struct ldb_result *res;
5289
5290                 TALLOC_CTX *tmp_ctx = talloc_new(ar);
5291                 if (!tmp_ctx) {
5292                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
5293                         return ret;
5294                 }
5295
5296                 res = talloc_zero(tmp_ctx, struct ldb_result);
5297                 if (!res) {
5298                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
5299                         talloc_free(tmp_ctx);
5300                         return ret;
5301                 }
5302
5303                 /* Build a delete request, which hopefully will artually turn into nothing */
5304                 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
5305                                         msg->dn,
5306                                         NULL,
5307                                         res,
5308                                         ldb_modify_default_callback,
5309                                         ar->req);
5310                 LDB_REQ_SET_LOCATION(del_req);
5311                 if (ret != LDB_SUCCESS) {
5312                         talloc_free(tmp_ctx);
5313                         return ret;
5314                 }
5315
5316                 /*
5317                  * This is the guts of the call, call back
5318                  * into our delete code, but setting the
5319                  * re_delete flag so we delete anything that
5320                  * shouldn't be there on a deleted or recycled
5321                  * object
5322                  */
5323                 ret = replmd_delete_internals(ar->module, del_req, true);
5324                 if (ret == LDB_SUCCESS) {
5325                         ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
5326                 }
5327
5328                 talloc_free(tmp_ctx);
5329                 if (ret != LDB_SUCCESS) {
5330                         return ret;
5331                 }
5332         }
5333
5334         ar->index_current++;
5335         return replmd_replicated_apply_next(ar);
5336 }
5337
5338 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
5339                                                       struct ldb_reply *ares)
5340 {
5341         struct ldb_context *ldb;
5342         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5343                                                struct replmd_replicated_request);
5344         ldb = ldb_module_get_ctx(ar->module);
5345
5346         if (!ares) {
5347                 return ldb_module_done(ar->req, NULL, NULL,
5348                                         LDB_ERR_OPERATIONS_ERROR);
5349         }
5350         if (ares->error != LDB_SUCCESS) {
5351                 return ldb_module_done(ar->req, ares->controls,
5352                                         ares->response, ares->error);
5353         }
5354
5355         if (ares->type != LDB_REPLY_DONE) {
5356                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
5357                 return ldb_module_done(ar->req, NULL, NULL,
5358                                         LDB_ERR_OPERATIONS_ERROR);
5359         }
5360
5361         talloc_free(ares);
5362
5363         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5364 }
5365
5366 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
5367 {
5368         struct ldb_context *ldb;
5369         struct ldb_request *change_req;
5370         enum ndr_err_code ndr_err;
5371         struct ldb_message *msg;
5372         struct replUpToDateVectorBlob ouv;
5373         const struct ldb_val *ouv_value;
5374         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
5375         struct replUpToDateVectorBlob nuv;
5376         struct ldb_val nuv_value;
5377         struct ldb_message_element *nuv_el = NULL;
5378         struct ldb_message_element *orf_el = NULL;
5379         struct repsFromToBlob nrf;
5380         struct ldb_val *nrf_value = NULL;
5381         struct ldb_message_element *nrf_el = NULL;
5382         unsigned int i;
5383         uint32_t j,ni=0;
5384         bool found = false;
5385         time_t t = time(NULL);
5386         NTTIME now;
5387         int ret;
5388         uint32_t instanceType;
5389
5390         ldb = ldb_module_get_ctx(ar->module);
5391         ruv = ar->objs->uptodateness_vector;
5392         ZERO_STRUCT(ouv);
5393         ouv.version = 2;
5394         ZERO_STRUCT(nuv);
5395         nuv.version = 2;
5396
5397         unix_to_nt_time(&now, t);
5398
5399         if (ar->search_msg == NULL) {
5400                 /* this happens for a REPL_OBJ call where we are
5401                    creating the target object by replicating it. The
5402                    subdomain join code does this for the partition DN
5403                 */
5404                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
5405                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5406         }
5407
5408         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
5409         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
5410                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
5411                          ldb_dn_get_linearized(ar->search_msg->dn)));
5412                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
5413         }
5414
5415         /*
5416          * first create the new replUpToDateVector
5417          */
5418         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
5419         if (ouv_value) {
5420                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
5421                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
5422                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5423                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5424                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5425                 }
5426
5427                 if (ouv.version != 2) {
5428                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5429                 }
5430         }
5431
5432         /*
5433          * the new uptodateness vector will at least
5434          * contain 1 entry, one for the source_dsa
5435          *
5436          * plus optional values from our old vector and the one from the source_dsa
5437          */
5438         nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
5439         if (ruv) nuv.ctr.ctr2.count += ruv->count;
5440         nuv.ctr.ctr2.cursors = talloc_array(ar,
5441                                             struct drsuapi_DsReplicaCursor2,
5442                                             nuv.ctr.ctr2.count);
5443         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5444
5445         /* first copy the old vector */
5446         for (i=0; i < ouv.ctr.ctr2.count; i++) {
5447                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
5448                 ni++;
5449         }
5450
5451         /* merge in the source_dsa vector is available */
5452         for (i=0; (ruv && i < ruv->count); i++) {
5453                 found = false;
5454
5455                 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5456                                &ar->our_invocation_id)) {
5457                         continue;
5458                 }
5459
5460                 for (j=0; j < ni; j++) {
5461                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
5462                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
5463                                 continue;
5464                         }
5465
5466                         found = true;
5467
5468                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
5469                                 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
5470                         }
5471                         break;
5472                 }
5473
5474                 if (found) continue;
5475
5476                 /* if it's not there yet, add it */
5477                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
5478                 ni++;
5479         }
5480
5481         /*
5482          * finally correct the size of the cursors array
5483          */
5484         nuv.ctr.ctr2.count = ni;
5485
5486         /*
5487          * sort the cursors
5488          */
5489         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
5490
5491         /*
5492          * create the change ldb_message
5493          */
5494         msg = ldb_msg_new(ar);
5495         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5496         msg->dn = ar->search_msg->dn;
5497
5498         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
5499                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
5500         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5501                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5502                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5503         }
5504         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
5505         if (ret != LDB_SUCCESS) {
5506                 return replmd_replicated_request_error(ar, ret);
5507         }
5508         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
5509
5510         /*
5511          * now create the new repsFrom value from the given repsFromTo1 structure
5512          */
5513         ZERO_STRUCT(nrf);
5514         nrf.version                                     = 1;
5515         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
5516         nrf.ctr.ctr1.last_attempt                       = now;
5517         nrf.ctr.ctr1.last_success                       = now;
5518         nrf.ctr.ctr1.result_last_attempt                = WERR_OK;
5519
5520         /*
5521          * first see if we already have a repsFrom value for the current source dsa
5522          * if so we'll later replace this value
5523          */
5524         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
5525         if (orf_el) {
5526                 for (i=0; i < orf_el->num_values; i++) {
5527                         struct repsFromToBlob *trf;
5528
5529                         trf = talloc(ar, struct repsFromToBlob);
5530                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5531
5532                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
5533                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
5534                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5535                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5536                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5537                         }
5538
5539                         if (trf->version != 1) {
5540                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5541                         }
5542
5543                         /*
5544                          * we compare the source dsa objectGUID not the invocation_id
5545                          * because we want only one repsFrom value per source dsa
5546                          * and when the invocation_id of the source dsa has changed we don't need
5547                          * the old repsFrom with the old invocation_id
5548                          */
5549                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
5550                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
5551                                 talloc_free(trf);
5552                                 continue;
5553                         }
5554
5555                         talloc_free(trf);
5556                         nrf_value = &orf_el->values[i];
5557                         break;
5558                 }
5559
5560                 /*
5561                  * copy over all old values to the new ldb_message
5562                  */
5563                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
5564                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5565                 *nrf_el = *orf_el;
5566         }
5567
5568         /*
5569          * if we haven't found an old repsFrom value for the current source dsa
5570          * we'll add a new value
5571          */
5572         if (!nrf_value) {
5573                 struct ldb_val zero_value;
5574                 ZERO_STRUCT(zero_value);
5575                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
5576                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5577
5578                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
5579         }
5580
5581         /* we now fill the value which is already attached to ldb_message */
5582         ndr_err = ndr_push_struct_blob(nrf_value, msg,
5583                                        &nrf,
5584                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
5585         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5586                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5587                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5588         }
5589
5590         /*
5591          * the ldb_message_element for the attribute, has all the old values and the new one
5592          * so we'll replace the whole attribute with all values
5593          */
5594         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
5595
5596         if (CHECK_DEBUGLVL(4)) {
5597                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5598                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
5599                 talloc_free(s);
5600         }
5601
5602         /* prepare the ldb_modify() request */
5603         ret = ldb_build_mod_req(&change_req,
5604                                 ldb,
5605                                 ar,
5606                                 msg,
5607                                 ar->controls,
5608                                 ar,
5609                                 replmd_replicated_uptodate_modify_callback,
5610                                 ar->req);
5611         LDB_REQ_SET_LOCATION(change_req);
5612         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5613
5614         return ldb_next_request(ar->module, change_req);
5615 }
5616
5617 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
5618                                                       struct ldb_reply *ares)
5619 {
5620         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5621                                                struct replmd_replicated_request);
5622         int ret;
5623
5624         if (!ares) {
5625                 return ldb_module_done(ar->req, NULL, NULL,
5626                                         LDB_ERR_OPERATIONS_ERROR);
5627         }
5628         if (ares->error != LDB_SUCCESS &&
5629             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5630                 return ldb_module_done(ar->req, ares->controls,
5631                                         ares->response, ares->error);
5632         }
5633
5634         switch (ares->type) {
5635         case LDB_REPLY_ENTRY:
5636                 ar->search_msg = talloc_steal(ar, ares->message);
5637                 break;
5638
5639         case LDB_REPLY_REFERRAL:
5640                 /* we ignore referrals */
5641                 break;
5642
5643         case LDB_REPLY_DONE:
5644                 ret = replmd_replicated_uptodate_modify(ar);
5645                 if (ret != LDB_SUCCESS) {
5646                         return ldb_module_done(ar->req, NULL, NULL, ret);
5647                 }
5648         }
5649
5650         talloc_free(ares);
5651         return LDB_SUCCESS;
5652 }
5653
5654
5655 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
5656 {
5657         struct ldb_context *ldb;
5658         int ret;
5659         static const char *attrs[] = {
5660                 "replUpToDateVector",
5661                 "repsFrom",
5662                 "instanceType",
5663                 NULL
5664         };
5665         struct ldb_request *search_req;
5666
5667         ldb = ldb_module_get_ctx(ar->module);
5668         ar->search_msg = NULL;
5669
5670         ret = ldb_build_search_req(&search_req,
5671                                    ldb,
5672                                    ar,
5673                                    ar->objs->partition_dn,
5674                                    LDB_SCOPE_BASE,
5675                                    "(objectClass=*)",
5676                                    attrs,
5677                                    NULL,
5678                                    ar,
5679                                    replmd_replicated_uptodate_search_callback,
5680                                    ar->req);
5681         LDB_REQ_SET_LOCATION(search_req);
5682         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5683
5684         return ldb_next_request(ar->module, search_req);
5685 }
5686
5687
5688
5689 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
5690 {
5691         struct ldb_context *ldb;
5692         struct dsdb_extended_replicated_objects *objs;
5693         struct replmd_replicated_request *ar;
5694         struct ldb_control **ctrls;
5695         int ret;
5696         uint32_t i;
5697         struct replmd_private *replmd_private =
5698                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
5699         struct dsdb_control_replicated_update *rep_update;
5700
5701         ldb = ldb_module_get_ctx(module);
5702
5703         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
5704
5705         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
5706         if (!objs) {
5707                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
5708                 return LDB_ERR_PROTOCOL_ERROR;
5709         }
5710
5711         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
5712                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
5713                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
5714                 return LDB_ERR_PROTOCOL_ERROR;
5715         }
5716
5717         ar = replmd_ctx_init(module, req);
5718         if (!ar)
5719                 return LDB_ERR_OPERATIONS_ERROR;
5720
5721         /* Set the flags to have the replmd_op_callback run over the full set of objects */
5722         ar->apply_mode = true;
5723         ar->objs = objs;
5724         ar->schema = dsdb_get_schema(ldb, ar);
5725         if (!ar->schema) {
5726                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
5727                 talloc_free(ar);
5728                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
5729                 return LDB_ERR_CONSTRAINT_VIOLATION;
5730         }
5731
5732         ctrls = req->controls;
5733
5734         if (req->controls) {
5735                 req->controls = talloc_memdup(ar, req->controls,
5736                                               talloc_get_size(req->controls));
5737                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOMEM);
5738         }
5739
5740         /* This allows layers further down to know if a change came in
5741            over replication and what the replication flags were */
5742         rep_update = talloc_zero(ar, struct dsdb_control_replicated_update);
5743         if (rep_update == NULL) {
5744                 return ldb_module_oom(module);
5745         }
5746         rep_update->dsdb_repl_flags = objs->dsdb_repl_flags;
5747
5748         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, rep_update);
5749         if (ret != LDB_SUCCESS) {
5750                 return ret;
5751         }
5752
5753         /* If this change contained linked attributes in the body
5754          * (rather than in the links section) we need to update
5755          * backlinks in linked_attributes */
5756         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
5757         if (ret != LDB_SUCCESS) {
5758                 return ret;
5759         }
5760
5761         ar->controls = req->controls;
5762         req->controls = ctrls;
5763
5764         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
5765
5766         /* save away the linked attributes for the end of the
5767            transaction */
5768         for (i=0; i<ar->objs->linked_attributes_count; i++) {
5769                 struct la_entry *la_entry;
5770
5771                 if (replmd_private->la_ctx == NULL) {
5772                         replmd_private->la_ctx = talloc_new(replmd_private);
5773                 }
5774                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
5775                 if (la_entry == NULL) {
5776                         ldb_oom(ldb);
5777                         return LDB_ERR_OPERATIONS_ERROR;
5778                 }
5779                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
5780                 if (la_entry->la == NULL) {
5781                         talloc_free(la_entry);
5782                         ldb_oom(ldb);
5783                         return LDB_ERR_OPERATIONS_ERROR;
5784                 }
5785                 *la_entry->la = ar->objs->linked_attributes[i];
5786
5787                 /* we need to steal the non-scalars so they stay
5788                    around until the end of the transaction */
5789                 talloc_steal(la_entry->la, la_entry->la->identifier);
5790                 talloc_steal(la_entry->la, la_entry->la->value.blob);
5791
5792                 DLIST_ADD(replmd_private->la_list, la_entry);
5793         }
5794
5795         return replmd_replicated_apply_next(ar);
5796 }
5797
5798 /*
5799   process one linked attribute structure
5800  */
5801 static int replmd_process_linked_attribute(struct ldb_module *module,
5802                                            struct la_entry *la_entry,
5803                                            struct ldb_request *parent)
5804 {
5805         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
5806         struct ldb_context *ldb = ldb_module_get_ctx(module);
5807         struct ldb_message *msg;
5808         struct ldb_message *target_msg = NULL;
5809         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
5810         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
5811         int ret;
5812         const struct dsdb_attribute *attr;
5813         struct dsdb_dn *dsdb_dn;
5814         uint64_t seq_num = 0;
5815         struct ldb_message_element *old_el;
5816         WERROR status;
5817         time_t t = time(NULL);
5818         struct ldb_result *res;
5819         struct ldb_result *target_res;
5820         const char *attrs[4];
5821         const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
5822         struct parsed_dn *pdn_list, *pdn;
5823         struct GUID guid = GUID_zero();
5824         NTSTATUS ntstatus;
5825         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
5826         const struct GUID *our_invocation_id;
5827
5828         enum deletion_state deletion_state = OBJECT_NOT_DELETED;
5829         enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
5830
5831 /*
5832 linked_attributes[0]:
5833      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
5834         identifier               : *
5835             identifier: struct drsuapi_DsReplicaObjectIdentifier
5836                 __ndr_size               : 0x0000003a (58)
5837                 __ndr_size_sid           : 0x00000000 (0)
5838                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
5839                 sid                      : S-0-0
5840                 __ndr_size_dn            : 0x00000000 (0)
5841                 dn                       : ''
5842         attid                    : DRSUAPI_ATTID_member (0x1F)
5843         value: struct drsuapi_DsAttributeValue
5844             __ndr_size               : 0x0000007e (126)
5845             blob                     : *
5846                 blob                     : DATA_BLOB length=126
5847         flags                    : 0x00000001 (1)
5848                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
5849         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
5850         meta_data: struct drsuapi_DsReplicaMetaData
5851             version                  : 0x00000015 (21)
5852             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
5853             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
5854             originating_usn          : 0x000000000001e19c (123292)
5855
5856 (for cases where the link is to a normal DN)
5857      &target: struct drsuapi_DsReplicaObjectIdentifier3
5858         __ndr_size               : 0x0000007e (126)
5859         __ndr_size_sid           : 0x0000001c (28)
5860         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
5861         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
5862         __ndr_size_dn            : 0x00000022 (34)
5863         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
5864  */
5865
5866         /* find the attribute being modified */
5867         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
5868         if (attr == NULL) {
5869                 DEBUG(0, (__location__ ": Unable to find attributeID 0x%x\n", la->attid));
5870                 talloc_free(tmp_ctx);
5871                 return LDB_ERR_OPERATIONS_ERROR;
5872         }
5873
5874         attrs[0] = attr->lDAPDisplayName;
5875         attrs[1] = "isDeleted";
5876         attrs[2] = "isRecycled";
5877         attrs[3] = NULL;
5878
5879         /* get the existing message from the db for the object with
5880            this GUID, returning attribute being modified. We will then
5881            use this msg as the basis for a modify call */
5882         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
5883                                  DSDB_FLAG_NEXT_MODULE |
5884                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5885                                  DSDB_SEARCH_SHOW_RECYCLED |
5886                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
5887                                  DSDB_SEARCH_REVEAL_INTERNALS,
5888                                  parent,
5889                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
5890         if (ret != LDB_SUCCESS) {
5891                 talloc_free(tmp_ctx);
5892                 return ret;
5893         }
5894         if (res->count != 1) {
5895                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
5896                                        GUID_string(tmp_ctx, &la->identifier->guid));
5897                 talloc_free(tmp_ctx);
5898                 return LDB_ERR_NO_SUCH_OBJECT;
5899         }
5900         msg = res->msgs[0];
5901
5902         /*
5903          * Check for deleted objects per MS-DRSR 4.1.10.6.13
5904          * ProcessLinkValue, because link updates are not applied to
5905          * recycled and tombstone objects.  We don't have to delete
5906          * any existing link, that should have happened when the
5907          * object deletion was replicated or initiated.
5908          */
5909
5910         replmd_deletion_state(module, msg, &deletion_state, NULL);
5911
5912         if (deletion_state >= OBJECT_RECYCLED) {
5913                 talloc_free(tmp_ctx);
5914                 return LDB_SUCCESS;
5915         }
5916
5917         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
5918         if (old_el == NULL) {
5919                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
5920                 if (ret != LDB_SUCCESS) {
5921                         ldb_module_oom(module);
5922                         talloc_free(tmp_ctx);
5923                         return LDB_ERR_OPERATIONS_ERROR;
5924                 }
5925         } else {
5926                 old_el->flags = LDB_FLAG_MOD_REPLACE;
5927         }
5928
5929         /* parse the existing links */
5930         ret = get_parsed_dns(module, tmp_ctx, old_el, &pdn_list, attr->syntax->ldap_oid, parent);
5931         if (ret != LDB_SUCCESS) {
5932                 talloc_free(tmp_ctx);
5933                 return ret;
5934         }
5935
5936         /* get our invocationId */
5937         our_invocation_id = samdb_ntds_invocation_id(ldb);
5938         if (!our_invocation_id) {
5939                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
5940                 talloc_free(tmp_ctx);
5941                 return LDB_ERR_OPERATIONS_ERROR;
5942         }
5943
5944         ret = replmd_check_upgrade_links(pdn_list, old_el->num_values, old_el, our_invocation_id);
5945         if (ret != LDB_SUCCESS) {
5946                 talloc_free(tmp_ctx);
5947                 return ret;
5948         }
5949
5950         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
5951         if (!W_ERROR_IS_OK(status)) {
5952                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
5953                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
5954                 talloc_free(tmp_ctx);
5955                 return LDB_ERR_OPERATIONS_ERROR;
5956         }
5957
5958         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
5959         if (!NT_STATUS_IS_OK(ntstatus) && !active) {
5960                 /*
5961                  * This strange behaviour (allowing a NULL/missing
5962                  * GUID) originally comes from:
5963                  *
5964                  * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
5965                  * Author: Andrew Tridgell <tridge@samba.org>
5966                  * Date:   Mon Dec 21 21:21:55 2009 +1100
5967                  *
5968                  *  s4-drs: cope better with NULL GUIDS from DRS
5969                  *
5970                  *  It is valid to get a NULL GUID over DRS for a deleted forward link. We
5971                  *  need to match by DN if possible when seeing if we should update an
5972                  *  existing link.
5973                  *
5974                  *  Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
5975                  */
5976
5977                 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
5978                                             dsdb_dn->dn, attrs2,
5979                                             DSDB_FLAG_NEXT_MODULE |
5980                                             DSDB_SEARCH_SHOW_RECYCLED |
5981                                             DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5982                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
5983                                             parent);
5984         } else if (!NT_STATUS_IS_OK(ntstatus)) {
5985                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
5986                                        old_el->name,
5987                                        ldb_dn_get_linearized(dsdb_dn->dn),
5988                                        ldb_dn_get_linearized(msg->dn));
5989                 talloc_free(tmp_ctx);
5990                 return LDB_ERR_OPERATIONS_ERROR;
5991         } else {
5992                 ret = dsdb_module_search(module, tmp_ctx, &target_res,
5993                                          NULL, LDB_SCOPE_SUBTREE,
5994                                          attrs2,
5995                                          DSDB_FLAG_NEXT_MODULE |
5996                                          DSDB_SEARCH_SHOW_RECYCLED |
5997                                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
5998                                          DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
5999                                          parent,
6000                                          "objectGUID=%s",
6001                                          GUID_string(tmp_ctx, &guid));
6002         }
6003
6004         if (ret != LDB_SUCCESS) {
6005                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6006                                        GUID_string(tmp_ctx, &guid),
6007                                        ldb_errstring(ldb_module_get_ctx(module)));
6008                 talloc_free(tmp_ctx);
6009                 return ret;
6010         }
6011
6012         if (target_res->count == 0) {
6013                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6014                          GUID_string(tmp_ctx, &guid),
6015                          ldb_dn_get_linearized(dsdb_dn->dn)));
6016         } else if (target_res->count != 1) {
6017                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6018                                        GUID_string(tmp_ctx, &guid));
6019                 talloc_free(tmp_ctx);
6020                 return LDB_ERR_OPERATIONS_ERROR;
6021         } else {
6022                 target_msg = target_res->msgs[0];
6023                 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6024         }
6025
6026         /*
6027          * Check for deleted objects per MS-DRSR 4.1.10.6.13
6028          * ProcessLinkValue, because link updates are not applied to
6029          * recycled and tombstone objects.  We don't have to delete
6030          * any existing link, that should have happened when the
6031          * object deletion was replicated or initiated.
6032          */
6033         replmd_deletion_state(module, target_msg,
6034                               &target_deletion_state, NULL);
6035
6036         if (target_deletion_state >= OBJECT_RECYCLED) {
6037                 talloc_free(tmp_ctx);
6038                 return LDB_SUCCESS;
6039         }
6040
6041         /* see if this link already exists */
6042         pdn = parsed_dn_find(pdn_list, old_el->num_values, &guid, dsdb_dn->dn);
6043         if (pdn != NULL) {
6044                 /* see if this update is newer than what we have already */
6045                 struct GUID invocation_id = GUID_zero();
6046                 uint32_t version = 0;
6047                 uint32_t originating_usn = 0;
6048                 NTTIME change_time = 0;
6049                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6050
6051                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6052                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6053                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6054                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6055
6056                 if (!replmd_update_is_newer(&invocation_id,
6057                                             &la->meta_data.originating_invocation_id,
6058                                             version,
6059                                             la->meta_data.version,
6060                                             change_time,
6061                                             la->meta_data.originating_change_time)) {
6062                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6063                                  old_el->name, ldb_dn_get_linearized(msg->dn),
6064                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6065                         talloc_free(tmp_ctx);
6066                         return LDB_SUCCESS;
6067                 }
6068
6069                 /* get a seq_num for this change */
6070                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6071                 if (ret != LDB_SUCCESS) {
6072                         talloc_free(tmp_ctx);
6073                         return ret;
6074                 }
6075
6076                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6077                         /* remove the existing backlink */
6078                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, false, attr, true);
6079                         if (ret != LDB_SUCCESS) {
6080                                 talloc_free(tmp_ctx);
6081                                 return ret;
6082                         }
6083                 }
6084
6085                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6086                                            &la->meta_data.originating_invocation_id,
6087                                            la->meta_data.originating_usn, seq_num,
6088                                            la->meta_data.originating_change_time,
6089                                            la->meta_data.version,
6090                                            !active);
6091                 if (ret != LDB_SUCCESS) {
6092                         talloc_free(tmp_ctx);
6093                         return ret;
6094                 }
6095
6096                 if (active) {
6097                         /* add the new backlink */
6098                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid, true, attr, true);
6099                         if (ret != LDB_SUCCESS) {
6100                                 talloc_free(tmp_ctx);
6101                                 return ret;
6102                         }
6103                 }
6104         } else {
6105                 /* get a seq_num for this change */
6106                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6107                 if (ret != LDB_SUCCESS) {
6108                         talloc_free(tmp_ctx);
6109                         return ret;
6110                 }
6111
6112                 old_el->values = talloc_realloc(msg->elements, old_el->values,
6113                                                 struct ldb_val, old_el->num_values+1);
6114                 if (!old_el->values) {
6115                         ldb_module_oom(module);
6116                         return LDB_ERR_OPERATIONS_ERROR;
6117                 }
6118                 old_el->num_values++;
6119
6120                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[old_el->num_values-1], dsdb_dn,
6121                                           &la->meta_data.originating_invocation_id,
6122                                           la->meta_data.originating_usn, seq_num,
6123                                           la->meta_data.originating_change_time,
6124                                           la->meta_data.version,
6125                                           (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?false:true);
6126                 if (ret != LDB_SUCCESS) {
6127                         talloc_free(tmp_ctx);
6128                         return ret;
6129                 }
6130
6131                 if (active) {
6132                         ret = replmd_add_backlink(module, schema, &la->identifier->guid, &guid,
6133                                                   true, attr, true);
6134                         if (ret != LDB_SUCCESS) {
6135                                 talloc_free(tmp_ctx);
6136                                 return ret;
6137                         }
6138                 }
6139         }
6140
6141         /* we only change whenChanged and uSNChanged if the seq_num
6142            has changed */
6143         ret = add_time_element(msg, "whenChanged", t);
6144         if (ret != LDB_SUCCESS) {
6145                 talloc_free(tmp_ctx);
6146                 ldb_operr(ldb);
6147                 return ret;
6148         }
6149
6150         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6151         if (ret != LDB_SUCCESS) {
6152                 talloc_free(tmp_ctx);
6153                 ldb_operr(ldb);
6154                 return ret;
6155         }
6156
6157         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6158         if (old_el == NULL) {
6159                 talloc_free(tmp_ctx);
6160                 return ldb_operr(ldb);
6161         }
6162
6163         ret = dsdb_check_single_valued_link(attr, old_el);
6164         if (ret != LDB_SUCCESS) {
6165                 talloc_free(tmp_ctx);
6166                 return ret;
6167         }
6168
6169         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6170
6171         ret = dsdb_module_modify(module, msg, DSDB_FLAG_NEXT_MODULE, parent);
6172         if (ret != LDB_SUCCESS) {
6173                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6174                           ldb_errstring(ldb),
6175                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6176                 talloc_free(tmp_ctx);
6177                 return ret;
6178         }
6179
6180         talloc_free(tmp_ctx);
6181
6182         return ret;
6183 }
6184
6185 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6186 {
6187         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6188                 return replmd_extended_replicated_objects(module, req);
6189         }
6190
6191         return ldb_next_request(module, req);
6192 }
6193
6194
6195 /*
6196   we hook into the transaction operations to allow us to
6197   perform the linked attribute updates at the end of the whole
6198   transaction. This allows a forward linked attribute to be created
6199   before the object is created. During a vampire, w2k8 sends us linked
6200   attributes before the objects they are part of.
6201  */
6202 static int replmd_start_transaction(struct ldb_module *module)
6203 {
6204         /* create our private structure for this transaction */
6205         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6206                                                                 struct replmd_private);
6207         replmd_txn_cleanup(replmd_private);
6208
6209         /* free any leftover mod_usn records from cancelled
6210            transactions */
6211         while (replmd_private->ncs) {
6212                 struct nc_entry *e = replmd_private->ncs;
6213                 DLIST_REMOVE(replmd_private->ncs, e);
6214                 talloc_free(e);
6215         }
6216
6217         return ldb_next_start_trans(module);
6218 }
6219
6220 /*
6221   on prepare commit we loop over our queued la_context structures and
6222   apply each of them
6223  */
6224 static int replmd_prepare_commit(struct ldb_module *module)
6225 {
6226         struct replmd_private *replmd_private =
6227                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6228         struct la_entry *la, *prev;
6229         struct la_backlink *bl;
6230         int ret;
6231
6232         /* walk the list backwards, to do the first entry first, as we
6233          * added the entries with DLIST_ADD() which puts them at the
6234          * start of the list */
6235         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
6236                 prev = DLIST_PREV(la);
6237                 DLIST_REMOVE(replmd_private->la_list, la);
6238                 ret = replmd_process_linked_attribute(module, la, NULL);
6239                 if (ret != LDB_SUCCESS) {
6240                         replmd_txn_cleanup(replmd_private);
6241                         return ret;
6242                 }
6243         }
6244
6245         /* process our backlink list, creating and deleting backlinks
6246            as necessary */
6247         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
6248                 ret = replmd_process_backlink(module, bl, NULL);
6249                 if (ret != LDB_SUCCESS) {
6250                         replmd_txn_cleanup(replmd_private);
6251                         return ret;
6252                 }
6253         }
6254
6255         replmd_txn_cleanup(replmd_private);
6256
6257         /* possibly change @REPLCHANGED */
6258         ret = replmd_notify_store(module, NULL);
6259         if (ret != LDB_SUCCESS) {
6260                 return ret;
6261         }
6262
6263         return ldb_next_prepare_commit(module);
6264 }
6265
6266 static int replmd_del_transaction(struct ldb_module *module)
6267 {
6268         struct replmd_private *replmd_private =
6269                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6270         replmd_txn_cleanup(replmd_private);
6271
6272         return ldb_next_del_trans(module);
6273 }
6274
6275
6276 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
6277         .name          = "repl_meta_data",
6278         .init_context      = replmd_init,
6279         .add               = replmd_add,
6280         .modify            = replmd_modify,
6281         .rename            = replmd_rename,
6282         .del               = replmd_delete,
6283         .extended          = replmd_extended,
6284         .start_transaction = replmd_start_transaction,
6285         .prepare_commit    = replmd_prepare_commit,
6286         .del_transaction   = replmd_del_transaction,
6287 };
6288
6289 int ldb_repl_meta_data_module_init(const char *version)
6290 {
6291         LDB_MODULE_CHECK_VERSION(version);
6292         return ldb_register_module(&ldb_repl_meta_data_module_ops);
6293 }