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