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