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