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