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