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