replmd: keep links sorted in replmd_process_linked_attribute
[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                         /* we got a DN without a GUID - go find the GUID */
2017                         int ret = dsdb_module_guid_by_dn(module, dn, &p->guid, parent);
2018                         if (ret != LDB_SUCCESS) {
2019                                 ldb_asprintf_errstring(ldb, "Unable to find GUID for DN %s\n",
2020                                                        ldb_dn_get_linearized(dn));
2021                                 if (ret == LDB_ERR_NO_SUCH_OBJECT &&
2022                                     LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE &&
2023                                     ldb_attr_cmp(el->name, "member") == 0) {
2024                                         return LDB_ERR_UNWILLING_TO_PERFORM;
2025                                 }
2026                                 return ret;
2027                         }
2028                         ret = dsdb_set_extended_dn_guid(dn, &p->guid, "GUID");
2029                         if (ret != LDB_SUCCESS) {
2030                                 return ret;
2031                         }
2032                 } else if (!NT_STATUS_IS_OK(status)) {
2033                         return LDB_ERR_OPERATIONS_ERROR;
2034                 }
2035                 if (i > 0 && values_are_sorted) {
2036                         int cmp = parsed_dn_compare(p, &(*pdn)[i - 1]);
2037                         if (cmp < 0) {
2038                                 values_are_sorted = false;
2039                         }
2040                 }
2041                 /* keep a pointer to the original ldb_val */
2042                 p->v = v;
2043         }
2044         if (! values_are_sorted) {
2045                 TYPESAFE_QSORT(*pdn, el->num_values, parsed_dn_compare);
2046         }
2047         return LDB_SUCCESS;
2048 }
2049
2050 /*
2051  * Get a series of trusted message element values. The result is sorted by
2052  * GUID, even though the GUIDs might not be known. That works because we trust
2053  * the database to give us the elements like that if the
2054  * replmd_private->sorted_links flag is set.
2055  */
2056 static int get_parsed_dns_trusted(struct ldb_module *module,
2057                                   struct replmd_private *replmd_private,
2058                                   TALLOC_CTX *mem_ctx,
2059                                   struct ldb_message_element *el,
2060                                   struct parsed_dn **pdn,
2061                                   const char *ldap_oid,
2062                                   struct ldb_request *parent)
2063 {
2064         unsigned int i;
2065
2066         if (el == NULL) {
2067                 *pdn = NULL;
2068                 return LDB_SUCCESS;
2069         }
2070
2071         if (!replmd_private->sorted_links) {
2072                 /* We need to sort the list. This is the slow old path we want
2073                    to avoid.
2074                  */
2075                 return get_parsed_dns(module, mem_ctx, el, pdn, ldap_oid,
2076                                       parent);
2077         }
2078         /* Here we get a list of 'struct parsed_dns' without the parsing */
2079         *pdn = talloc_zero_array(mem_ctx, struct parsed_dn,
2080                                  el->num_values);
2081         if (!*pdn) {
2082                 ldb_module_oom(module);
2083                 return LDB_ERR_OPERATIONS_ERROR;
2084         }
2085
2086         for (i = 0; i < el->num_values; i++) {
2087                 (*pdn)[i].v = &el->values[i];
2088         }
2089
2090         return LDB_SUCCESS;
2091 }
2092
2093 /*
2094   build a new extended DN, including all meta data fields
2095
2096   RMD_FLAGS           = DSDB_RMD_FLAG_* bits
2097   RMD_ADDTIME         = originating_add_time
2098   RMD_INVOCID         = originating_invocation_id
2099   RMD_CHANGETIME      = originating_change_time
2100   RMD_ORIGINATING_USN = originating_usn
2101   RMD_LOCAL_USN       = local_usn
2102   RMD_VERSION         = version
2103  */
2104 static int replmd_build_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2105                                const struct GUID *invocation_id, uint64_t seq_num,
2106                                uint64_t local_usn, NTTIME nttime, uint32_t version, bool deleted)
2107 {
2108         struct ldb_dn *dn = dsdb_dn->dn;
2109         const char *tstring, *usn_string, *flags_string;
2110         struct ldb_val tval;
2111         struct ldb_val iid;
2112         struct ldb_val usnv, local_usnv;
2113         struct ldb_val vers, flagsv;
2114         NTSTATUS status;
2115         int ret;
2116         const char *dnstring;
2117         char *vstring;
2118         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2119
2120         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2121         if (!tstring) {
2122                 return LDB_ERR_OPERATIONS_ERROR;
2123         }
2124         tval = data_blob_string_const(tstring);
2125
2126         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)seq_num);
2127         if (!usn_string) {
2128                 return LDB_ERR_OPERATIONS_ERROR;
2129         }
2130         usnv = data_blob_string_const(usn_string);
2131
2132         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2133         if (!usn_string) {
2134                 return LDB_ERR_OPERATIONS_ERROR;
2135         }
2136         local_usnv = data_blob_string_const(usn_string);
2137
2138         vstring = talloc_asprintf(mem_ctx, "%lu", (unsigned long)version);
2139         if (!vstring) {
2140                 return LDB_ERR_OPERATIONS_ERROR;
2141         }
2142         vers = data_blob_string_const(vstring);
2143
2144         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2145         if (!NT_STATUS_IS_OK(status)) {
2146                 return LDB_ERR_OPERATIONS_ERROR;
2147         }
2148
2149         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2150         if (!flags_string) {
2151                 return LDB_ERR_OPERATIONS_ERROR;
2152         }
2153         flagsv = data_blob_string_const(flags_string);
2154
2155         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2156         if (ret != LDB_SUCCESS) return ret;
2157         ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", &tval);
2158         if (ret != LDB_SUCCESS) return ret;
2159         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2160         if (ret != LDB_SUCCESS) return ret;
2161         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2162         if (ret != LDB_SUCCESS) return ret;
2163         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2164         if (ret != LDB_SUCCESS) return ret;
2165         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2166         if (ret != LDB_SUCCESS) return ret;
2167         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2168         if (ret != LDB_SUCCESS) return ret;
2169
2170         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2171         if (dnstring == NULL) {
2172                 return LDB_ERR_OPERATIONS_ERROR;
2173         }
2174         *v = data_blob_string_const(dnstring);
2175
2176         return LDB_SUCCESS;
2177 }
2178
2179 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2180                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2181                                 uint64_t seq_num, uint64_t local_usn, NTTIME nttime,
2182                                 uint32_t version, bool deleted);
2183
2184 /*
2185   check if any links need upgrading from w2k format
2186  */
2187 static int replmd_check_upgrade_links(struct ldb_context *ldb,
2188                                       struct parsed_dn *dns, uint32_t count,
2189                                       struct ldb_message_element *el,
2190                                       const struct GUID *invocation_id,
2191                                       const char *ldap_oid)
2192 {
2193         uint32_t i;
2194         for (i=0; i<count; i++) {
2195                 NTSTATUS status;
2196                 uint32_t version;
2197                 int ret;
2198                 if (dns[i].dsdb_dn == NULL) {
2199                         ret = really_parse_trusted_dn(dns, ldb, &dns[i],
2200                                                       ldap_oid);
2201                         if (ret != LDB_SUCCESS) {
2202                                 return LDB_ERR_INVALID_DN_SYNTAX;
2203                         }
2204                 }
2205
2206                 status = dsdb_get_extended_dn_uint32(dns[i].dsdb_dn->dn,
2207                                                      &version, "RMD_VERSION");
2208                 if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2209                         /*
2210                          *  We optimistically assume they are all the same; if
2211                          *  the first one is fixed, they are all fixed.
2212                          *
2213                          *  If the first one was *not* fixed and we find a
2214                          *  later one that is, that is an occasion to shout
2215                          *  with DEBUG(0).
2216                          */
2217                         if (i == 0) {
2218                                 return LDB_SUCCESS;
2219                         }
2220                         DEBUG(0, ("Mixed w2k and fixed format "
2221                                   "linked attributes\n"));
2222                         continue;
2223                 }
2224
2225                 /* it's an old one that needs upgrading */
2226                 ret = replmd_update_la_val(el->values, dns[i].v,
2227                                            dns[i].dsdb_dn, dns[i].dsdb_dn,
2228                                            invocation_id, 1, 1, 0, 0, false);
2229                 if (ret != LDB_SUCCESS) {
2230                         return ret;
2231                 }
2232         }
2233         return LDB_SUCCESS;
2234 }
2235
2236 /*
2237   update an extended DN, including all meta data fields
2238
2239   see replmd_build_la_val for value names
2240  */
2241 static int replmd_update_la_val(TALLOC_CTX *mem_ctx, struct ldb_val *v, struct dsdb_dn *dsdb_dn,
2242                                 struct dsdb_dn *old_dsdb_dn, const struct GUID *invocation_id,
2243                                 uint64_t usn, uint64_t local_usn, NTTIME nttime,
2244                                 uint32_t version, bool deleted)
2245 {
2246         struct ldb_dn *dn = dsdb_dn->dn;
2247         const char *tstring, *usn_string, *flags_string;
2248         struct ldb_val tval;
2249         struct ldb_val iid;
2250         struct ldb_val usnv, local_usnv;
2251         struct ldb_val vers, flagsv;
2252         const struct ldb_val *old_addtime;
2253         uint32_t old_version;
2254         NTSTATUS status;
2255         int ret;
2256         const char *dnstring;
2257         char *vstring;
2258         uint32_t rmd_flags = deleted?DSDB_RMD_FLAG_DELETED:0;
2259
2260         tstring = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)nttime);
2261         if (!tstring) {
2262                 return LDB_ERR_OPERATIONS_ERROR;
2263         }
2264         tval = data_blob_string_const(tstring);
2265
2266         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)usn);
2267         if (!usn_string) {
2268                 return LDB_ERR_OPERATIONS_ERROR;
2269         }
2270         usnv = data_blob_string_const(usn_string);
2271
2272         usn_string = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)local_usn);
2273         if (!usn_string) {
2274                 return LDB_ERR_OPERATIONS_ERROR;
2275         }
2276         local_usnv = data_blob_string_const(usn_string);
2277
2278         status = GUID_to_ndr_blob(invocation_id, dn, &iid);
2279         if (!NT_STATUS_IS_OK(status)) {
2280                 return LDB_ERR_OPERATIONS_ERROR;
2281         }
2282
2283         flags_string = talloc_asprintf(mem_ctx, "%u", rmd_flags);
2284         if (!flags_string) {
2285                 return LDB_ERR_OPERATIONS_ERROR;
2286         }
2287         flagsv = data_blob_string_const(flags_string);
2288
2289         ret = ldb_dn_set_extended_component(dn, "RMD_FLAGS", &flagsv);
2290         if (ret != LDB_SUCCESS) return ret;
2291
2292         /* get the ADDTIME from the original */
2293         old_addtime = ldb_dn_get_extended_component(old_dsdb_dn->dn, "RMD_ADDTIME");
2294         if (old_addtime == NULL) {
2295                 old_addtime = &tval;
2296         }
2297         if (dsdb_dn != old_dsdb_dn ||
2298             ldb_dn_get_extended_component(dn, "RMD_ADDTIME") == NULL) {
2299                 ret = ldb_dn_set_extended_component(dn, "RMD_ADDTIME", old_addtime);
2300                 if (ret != LDB_SUCCESS) return ret;
2301         }
2302
2303         /* use our invocation id */
2304         ret = ldb_dn_set_extended_component(dn, "RMD_INVOCID", &iid);
2305         if (ret != LDB_SUCCESS) return ret;
2306
2307         /* changetime is the current time */
2308         ret = ldb_dn_set_extended_component(dn, "RMD_CHANGETIME", &tval);
2309         if (ret != LDB_SUCCESS) return ret;
2310
2311         /* update the USN */
2312         ret = ldb_dn_set_extended_component(dn, "RMD_ORIGINATING_USN", &usnv);
2313         if (ret != LDB_SUCCESS) return ret;
2314
2315         ret = ldb_dn_set_extended_component(dn, "RMD_LOCAL_USN", &local_usnv);
2316         if (ret != LDB_SUCCESS) return ret;
2317
2318         /* increase the version by 1 */
2319         status = dsdb_get_extended_dn_uint32(old_dsdb_dn->dn, &old_version, "RMD_VERSION");
2320         if (NT_STATUS_IS_OK(status) && old_version >= version) {
2321                 version = old_version+1;
2322         }
2323         vstring = talloc_asprintf(dn, "%lu", (unsigned long)version);
2324         vers = data_blob_string_const(vstring);
2325         ret = ldb_dn_set_extended_component(dn, "RMD_VERSION", &vers);
2326         if (ret != LDB_SUCCESS) return ret;
2327
2328         dnstring = dsdb_dn_get_extended_linearized(mem_ctx, dsdb_dn, 1);
2329         if (dnstring == NULL) {
2330                 return LDB_ERR_OPERATIONS_ERROR;
2331         }
2332         *v = data_blob_string_const(dnstring);
2333
2334         return LDB_SUCCESS;
2335 }
2336
2337 /*
2338   handle adding a linked attribute
2339  */
2340 static int replmd_modify_la_add(struct ldb_module *module,
2341                                 struct replmd_private *replmd_private,
2342                                 const struct dsdb_schema *schema,
2343                                 struct ldb_message *msg,
2344                                 struct ldb_message_element *el,
2345                                 struct ldb_message_element *old_el,
2346                                 const struct dsdb_attribute *schema_attr,
2347                                 uint64_t seq_num,
2348                                 time_t t,
2349                                 struct GUID *msg_guid,
2350                                 struct ldb_request *parent)
2351 {
2352         unsigned int i, j;
2353         struct parsed_dn *dns, *old_dns;
2354         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2355         int ret;
2356         struct ldb_val *new_values = NULL;
2357         unsigned old_num_values = old_el ? old_el->num_values : 0;
2358         unsigned num_values = 0;
2359         unsigned max_num_values;
2360         const struct GUID *invocation_id;
2361         struct ldb_context *ldb = ldb_module_get_ctx(module);
2362         NTTIME now;
2363
2364         unix_to_nt_time(&now, t);
2365
2366         /* get the DNs to be added, fully parsed.
2367          *
2368          * We need full parsing because they came off the wire and we don't
2369          * trust them, besides which we need their details to know where to put
2370          * them.
2371          */
2372         ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2373                              schema_attr->syntax->ldap_oid, parent);
2374         if (ret != LDB_SUCCESS) {
2375                 talloc_free(tmp_ctx);
2376                 return ret;
2377         }
2378
2379         /* get the existing DNs, lazily parsed */
2380         ret = get_parsed_dns_trusted(module, replmd_private,
2381                                      tmp_ctx, old_el, &old_dns,
2382                                      schema_attr->syntax->ldap_oid, parent);
2383
2384         if (ret != LDB_SUCCESS) {
2385                 talloc_free(tmp_ctx);
2386                 return ret;
2387         }
2388
2389         invocation_id = samdb_ntds_invocation_id(ldb);
2390         if (!invocation_id) {
2391                 talloc_free(tmp_ctx);
2392                 return LDB_ERR_OPERATIONS_ERROR;
2393         }
2394
2395         ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2396                                          old_el, invocation_id,
2397                                          schema_attr->syntax->ldap_oid);
2398         if (ret != LDB_SUCCESS) {
2399                 talloc_free(tmp_ctx);
2400                 return ret;
2401         }
2402
2403         max_num_values = old_num_values + el->num_values;
2404         if (max_num_values < old_num_values) {
2405                 DEBUG(0, ("we seem to have overflow in replmd_modify_la_add. "
2406                           "old values: %u, new values: %u, sum: %u",
2407                           old_num_values, el->num_values, max_num_values));
2408                 talloc_free(tmp_ctx);
2409                 return LDB_ERR_OPERATIONS_ERROR;
2410         }
2411
2412         new_values = talloc_zero_array(tmp_ctx, struct ldb_val, max_num_values);
2413
2414         if (new_values == NULL) {
2415                 ldb_module_oom(module);
2416                 talloc_free(tmp_ctx);
2417                 return LDB_ERR_OPERATIONS_ERROR;
2418         }
2419
2420         /*
2421          * For each new value, find where it would go in the list. If there is
2422          * a matching GUID there, we update the existing value; otherwise we
2423          * put it in place.
2424          */
2425         j = 0;
2426         for (i = 0; i < el->num_values; i++) {
2427                 struct parsed_dn *exact;
2428                 struct parsed_dn *next;
2429                 unsigned offset;
2430                 int err = parsed_dn_find(ldb, old_dns, old_num_values,
2431                                          &dns[i].guid,
2432                                          dns[i].dsdb_dn->dn,
2433                                          &exact, &next,
2434                                          schema_attr->syntax->ldap_oid);
2435                 if (err != LDB_SUCCESS) {
2436                         talloc_free(tmp_ctx);
2437                         return err;
2438                 }
2439
2440                 if (exact != NULL) {
2441                         /*
2442                          * We are trying to add one that exists, which is only
2443                          * allowed if it was previously deleted.
2444                          *
2445                          * When we do undelete a link we change it in place.
2446                          * It will be copied across into the right spot in due
2447                          * course.
2448                          */
2449                         uint32_t rmd_flags;
2450                         rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2451
2452                         if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2453                                 struct GUID_txt_buf guid_str;
2454                                 ldb_asprintf_errstring(ldb,
2455                                                        "Attribute %s already "
2456                                                        "exists for target GUID %s",
2457                                                        el->name,
2458                                                        GUID_buf_string(&exact->guid,
2459                                                                        &guid_str));
2460                                 talloc_free(tmp_ctx);
2461                                 /* error codes for 'member' need to be
2462                                    special cased */
2463                                 if (ldb_attr_cmp(el->name, "member") == 0) {
2464                                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
2465                                 } else {
2466                                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
2467                                 }
2468                         }
2469
2470                         ret = replmd_update_la_val(new_values, exact->v,
2471                                                    dns[i].dsdb_dn,
2472                                                    exact->dsdb_dn,
2473                                                    invocation_id, seq_num,
2474                                                    seq_num, now, 0, false);
2475                         if (ret != LDB_SUCCESS) {
2476                                 talloc_free(tmp_ctx);
2477                                 return ret;
2478                         }
2479
2480                         ret = replmd_add_backlink(module, replmd_private,
2481                                                   schema, msg_guid,
2482                                                   &dns[i].guid, true,
2483                                                   schema_attr, true);
2484                         if (ret != LDB_SUCCESS) {
2485                                 talloc_free(tmp_ctx);
2486                                 return ret;
2487                                 }
2488                         continue;
2489                 }
2490                 /*
2491                  * Here we don't have an exact match.
2492                  *
2493                  * If next is NULL, this one goes beyond the end of the
2494                  * existing list, so we need to add all of those ones first.
2495                  *
2496                  * If next is not NULL, we need to add all the ones before
2497                  * next.
2498                  */
2499                 if (next == NULL) {
2500                         offset = old_num_values;
2501                 } else {
2502                         /* next should have been parsed, but let's make sure */
2503                         if (next->dsdb_dn == NULL) {
2504                                 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
2505                                                               schema_attr->syntax->ldap_oid);
2506                                 if (ret != LDB_SUCCESS) {
2507                                         return ret;
2508                                 }
2509                         }
2510                         offset = MIN(next - old_dns, old_num_values);
2511                 }
2512
2513                 /* put all the old ones before next on the list */
2514                 for (; j < offset; j++) {
2515                         new_values[num_values] = *old_dns[j].v;
2516                         num_values++;
2517                 }
2518
2519                 ret = replmd_add_backlink(module, replmd_private,
2520                                           schema, msg_guid, &dns[i].guid,
2521                                           true, schema_attr, true);
2522                 /* Make the new linked attribute ldb_val. */
2523                 ret = replmd_build_la_val(new_values, &new_values[num_values],
2524                                           dns[i].dsdb_dn, invocation_id,
2525                                           seq_num, seq_num,
2526                                           now, 0, false);
2527                 if (ret != LDB_SUCCESS) {
2528                         talloc_free(tmp_ctx);
2529                         return ret;
2530                 }
2531                 num_values++;
2532                 if (ret != LDB_SUCCESS) {
2533                         talloc_free(tmp_ctx);
2534                         return ret;
2535                 }
2536         }
2537         /* copy the rest of the old ones (if any) */
2538         for (; j < old_num_values; j++) {
2539                 new_values[num_values] = *old_dns[j].v;
2540                 num_values++;
2541         }
2542
2543         talloc_steal(msg->elements, new_values);
2544         if (old_el != NULL) {
2545                 talloc_steal(msg->elements, old_el->values);
2546         }
2547         el->values = new_values;
2548         el->num_values = num_values;
2549
2550         talloc_free(tmp_ctx);
2551
2552         /* we now tell the backend to replace all existing values
2553            with the one we have constructed */
2554         el->flags = LDB_FLAG_MOD_REPLACE;
2555
2556         return LDB_SUCCESS;
2557 }
2558
2559
2560 /*
2561   handle deleting all active linked attributes
2562  */
2563 static int replmd_modify_la_delete(struct ldb_module *module,
2564                                    struct replmd_private *replmd_private,
2565                                    const struct dsdb_schema *schema,
2566                                    struct ldb_message *msg,
2567                                    struct ldb_message_element *el,
2568                                    struct ldb_message_element *old_el,
2569                                    const struct dsdb_attribute *schema_attr,
2570                                    uint64_t seq_num,
2571                                    time_t t,
2572                                    struct GUID *msg_guid,
2573                                    struct ldb_request *parent)
2574 {
2575         unsigned int i;
2576         struct parsed_dn *dns, *old_dns;
2577         TALLOC_CTX *tmp_ctx = NULL;
2578         int ret;
2579         const struct GUID *invocation_id;
2580         struct ldb_context *ldb = ldb_module_get_ctx(module);
2581         struct ldb_control *vanish_links_ctrl = NULL;
2582         bool vanish_links = false;
2583         unsigned int num_to_delete = el->num_values;
2584         uint32_t rmd_flags;
2585         NTTIME now;
2586
2587         unix_to_nt_time(&now, t);
2588
2589         if (old_el == NULL || old_el->num_values == 0) {
2590                 /* there is nothing to delete... */
2591                 if (num_to_delete == 0) {
2592                         /* and we're deleting nothing, so that's OK */
2593                         return LDB_SUCCESS;
2594                 }
2595                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2596         }
2597
2598         tmp_ctx = talloc_new(msg);
2599         if (tmp_ctx == NULL) {
2600                 return LDB_ERR_OPERATIONS_ERROR;
2601         }
2602
2603         ret = get_parsed_dns(module, tmp_ctx, el, &dns,
2604                              schema_attr->syntax->ldap_oid, parent);
2605         if (ret != LDB_SUCCESS) {
2606                 talloc_free(tmp_ctx);
2607                 return ret;
2608         }
2609
2610         ret = get_parsed_dns_trusted(module, replmd_private,
2611                                      tmp_ctx, old_el, &old_dns,
2612                                      schema_attr->syntax->ldap_oid, parent);
2613
2614         if (ret != LDB_SUCCESS) {
2615                 talloc_free(tmp_ctx);
2616                 return ret;
2617         }
2618
2619         invocation_id = samdb_ntds_invocation_id(ldb);
2620         if (!invocation_id) {
2621                 talloc_free(tmp_ctx);
2622                 return LDB_ERR_OPERATIONS_ERROR;
2623         }
2624
2625         ret = replmd_check_upgrade_links(ldb, old_dns, old_el->num_values,
2626                                          old_el, invocation_id,
2627                                          schema_attr->syntax->ldap_oid);
2628         if (ret != LDB_SUCCESS) {
2629                 talloc_free(tmp_ctx);
2630                 return ret;
2631         }
2632
2633         if (parent) {
2634                 vanish_links_ctrl = ldb_request_get_control(parent, DSDB_CONTROL_REPLMD_VANISH_LINKS);
2635                 if (vanish_links_ctrl) {
2636                         vanish_links = true;
2637                         vanish_links_ctrl->critical = false;
2638                 }
2639         }
2640
2641         /* we empty out el->values here to avoid damage if we return early. */
2642         el->num_values = 0;
2643         el->values = NULL;
2644
2645         /*
2646          * If vanish links is set, we are actually removing members of
2647          *  old_el->values; otherwise we are just marking them deleted.
2648          *
2649          * There is a special case when no values are given: we remove them
2650          * all. When we have the vanish_links control we just have to remove
2651          * the backlinks and change our element to replace the existing values
2652          * with the empty list.
2653          */
2654
2655         if (num_to_delete == 0) {
2656                 for (i = 0; i < old_el->num_values; i++) {
2657                         struct parsed_dn *p = &old_dns[i];
2658                         if (p->dsdb_dn == NULL) {
2659                                 ret = really_parse_trusted_dn(tmp_ctx, ldb, p,
2660                                                               schema_attr->syntax->ldap_oid);
2661                                 if (ret != LDB_SUCCESS) {
2662                                         return ret;
2663                                 }
2664                         }
2665                         ret = replmd_add_backlink(module, replmd_private,
2666                                                   schema, msg_guid, &p->guid,
2667                                                   false, schema_attr, true);
2668                         if (ret != LDB_SUCCESS) {
2669                                 talloc_free(tmp_ctx);
2670                                 return ret;
2671                         }
2672                         if (vanish_links) {
2673                                 continue;
2674                         }
2675
2676                         rmd_flags = dsdb_dn_rmd_flags(p->dsdb_dn->dn);
2677                         if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2678                                 continue;
2679                         }
2680
2681                         ret = replmd_update_la_val(old_el->values, p->v,
2682                                                    p->dsdb_dn, p->dsdb_dn,
2683                                                    invocation_id, seq_num,
2684                                                    seq_num, now, 0, true);
2685                         if (ret != LDB_SUCCESS) {
2686                                 talloc_free(tmp_ctx);
2687                                 return ret;
2688                         }
2689                 }
2690
2691                 if (vanish_links) {
2692                         el->flags = LDB_FLAG_MOD_REPLACE;
2693                         talloc_free(tmp_ctx);
2694                         return LDB_SUCCESS;
2695                 }
2696         }
2697
2698
2699         for (i = 0; i < num_to_delete; i++) {
2700                 struct parsed_dn *p = &dns[i];
2701                 struct parsed_dn *exact = NULL;
2702                 struct parsed_dn *next = NULL;
2703                 ret = parsed_dn_find(ldb, old_dns, old_el->num_values,
2704                                      &p->guid,
2705                                      NULL,
2706                                      &exact, &next,
2707                                      schema_attr->syntax->ldap_oid);
2708                 if (ret != LDB_SUCCESS) {
2709                         talloc_free(tmp_ctx);
2710                         return ret;
2711                 }
2712                 if (exact == NULL) {
2713                         struct GUID_txt_buf buf;
2714                         ldb_asprintf_errstring(ldb, "Attribute %s doesn't "
2715                                                "exist for target GUID %s",
2716                                                el->name,
2717                                                GUID_buf_string(&p->guid, &buf));
2718                         if (ldb_attr_cmp(el->name, "member") == 0) {
2719                                 talloc_free(tmp_ctx);
2720                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2721                         } else {
2722                                 talloc_free(tmp_ctx);
2723                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2724                         }
2725                 }
2726
2727                 if (vanish_links) {
2728                         if (CHECK_DEBUGLVL(5)) {
2729                                 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2730                                 if ((rmd_flags & DSDB_RMD_FLAG_DELETED)) {
2731                                         struct GUID_txt_buf buf;
2732                                         const char *guid_str = \
2733                                                 GUID_buf_string(&p->guid, &buf);
2734                                         DEBUG(5, ("Deleting deleted linked "
2735                                                   "attribute %s to %s, because "
2736                                                   "vanish_links control is set\n",
2737                                                   el->name, guid_str));
2738                                 }
2739                         }
2740
2741                         /* remove the backlink */
2742                         ret = replmd_add_backlink(module,
2743                                                   replmd_private,
2744                                                   schema, msg_guid,
2745                                                   &p->guid,
2746                                                   false, schema_attr,
2747                                                   true);
2748                         if (ret != LDB_SUCCESS) {
2749                                 talloc_free(tmp_ctx);
2750                                 return ret;
2751                         }
2752
2753                         /* We flag the deletion and tidy it up later. */
2754                         exact->v = NULL;
2755                         continue;
2756                 }
2757
2758                 rmd_flags = dsdb_dn_rmd_flags(exact->dsdb_dn->dn);
2759
2760                 if (rmd_flags & DSDB_RMD_FLAG_DELETED) {
2761                         struct GUID_txt_buf buf;
2762                         const char *guid_str = GUID_buf_string(&p->guid, &buf);
2763                         ldb_asprintf_errstring(ldb, "Attribute %s already "
2764                                                "deleted for target GUID %s",
2765                                                el->name, guid_str);
2766                         if (ldb_attr_cmp(el->name, "member") == 0) {
2767                                 talloc_free(tmp_ctx);
2768                                 return LDB_ERR_UNWILLING_TO_PERFORM;
2769                         } else {
2770                                 talloc_free(tmp_ctx);
2771                                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
2772                         }
2773                 }
2774
2775                 ret = replmd_update_la_val(old_el->values, exact->v,
2776                                            exact->dsdb_dn, exact->dsdb_dn,
2777                                            invocation_id, seq_num, seq_num,
2778                                            now, 0, true);
2779                 if (ret != LDB_SUCCESS) {
2780                         talloc_free(tmp_ctx);
2781                         return ret;
2782                 }
2783                 ret = replmd_add_backlink(module, replmd_private,
2784                                           schema, msg_guid, &p->guid,
2785                                           false, schema_attr, true);
2786                 if (ret != LDB_SUCCESS) {
2787                         talloc_free(tmp_ctx);
2788                         return ret;
2789                 }
2790         }
2791
2792         if (vanish_links) {
2793                 unsigned j = 0;
2794                 for (i = 0; i < old_el->num_values; i++) {
2795                         if (old_dns[i].v != NULL) {
2796                                 old_el->values[j] = *old_dns[i].v;
2797                                 j++;
2798                         }
2799                 }
2800                 old_el->num_values = j;
2801         }
2802
2803         el->values = talloc_steal(msg->elements, old_el->values);
2804         el->num_values = old_el->num_values;
2805
2806         talloc_free(tmp_ctx);
2807
2808         /* we now tell the backend to replace all existing values
2809            with the one we have constructed */
2810         el->flags = LDB_FLAG_MOD_REPLACE;
2811
2812         return LDB_SUCCESS;
2813 }
2814
2815 /*
2816   handle replacing a linked attribute
2817  */
2818 static int replmd_modify_la_replace(struct ldb_module *module,
2819                                     struct replmd_private *replmd_private,
2820                                     const struct dsdb_schema *schema,
2821                                     struct ldb_message *msg,
2822                                     struct ldb_message_element *el,
2823                                     struct ldb_message_element *old_el,
2824                                     const struct dsdb_attribute *schema_attr,
2825                                     uint64_t seq_num,
2826                                     time_t t,
2827                                     struct GUID *msg_guid,
2828                                     struct ldb_request *parent)
2829 {
2830         unsigned int i, old_i, new_i;
2831         struct parsed_dn *dns, *old_dns;
2832         TALLOC_CTX *tmp_ctx = talloc_new(msg);
2833         int ret;
2834         const struct GUID *invocation_id;
2835         struct ldb_context *ldb = ldb_module_get_ctx(module);
2836         struct ldb_val *new_values = NULL;
2837         const char *ldap_oid = schema_attr->syntax->ldap_oid;
2838         unsigned int old_num_values;
2839         unsigned int repl_num_values;
2840         unsigned int max_num_values;
2841         NTTIME now;
2842
2843         unix_to_nt_time(&now, t);
2844
2845         /*
2846          * The replace operation is unlike the replace and delete cases in that
2847          * we need to look at every existing link to see whether it is being
2848          * retained or deleted. In other words, we can't avoid parsing the GUIDs.
2849          *
2850          * As we are trying to combine two sorted lists, the algorithm we use
2851          * is akin to the merge phase of a merge sort. We interleave the two
2852          * lists, doing different things depending on which side the current
2853          * item came from.
2854          *
2855          * There are three main cases, with some sub-cases.
2856          *
2857          *  - a DN is in the old list but not the new one. It needs to be
2858          *    marked as deleted (but left in the list).
2859          *     - maybe it is already deleted, and we have less to do.
2860          *
2861          *  - a DN is in both lists. The old data gets replaced by the new,
2862          *    and the list doesn't grow. The old link may have been marked as
2863          *    deleted, in which case we undelete it.
2864          *
2865          *  - a DN is in the new list only. We add it in the right place.
2866          */
2867
2868         old_num_values = old_el ? old_el->num_values : 0;
2869         repl_num_values = el->num_values;
2870         max_num_values = old_num_values + repl_num_values;
2871
2872         if (max_num_values == 0) {
2873                 /* There is nothing to do! */
2874                 return LDB_SUCCESS;
2875         }
2876
2877         ret = get_parsed_dns(module, tmp_ctx, el, &dns, ldap_oid, parent);
2878         if (ret != LDB_SUCCESS) {
2879                 talloc_free(tmp_ctx);
2880                 return ret;
2881         }
2882
2883         ret = get_parsed_dns(module, tmp_ctx, old_el, &old_dns,
2884                              ldap_oid, parent);
2885         if (ret != LDB_SUCCESS) {
2886                 talloc_free(tmp_ctx);
2887                 return ret;
2888         }
2889
2890         invocation_id = samdb_ntds_invocation_id(ldb);
2891         if (!invocation_id) {
2892                 return LDB_ERR_OPERATIONS_ERROR;
2893         }
2894
2895         ret = replmd_check_upgrade_links(ldb, old_dns, old_num_values,
2896                                          old_el, invocation_id, ldap_oid);
2897         if (ret != LDB_SUCCESS) {
2898                 talloc_free(tmp_ctx);
2899                 return ret;
2900         }
2901
2902         new_values = talloc_array(tmp_ctx, struct ldb_val, max_num_values);
2903         if (new_values == NULL) {
2904                 ldb_module_oom(module);
2905                 talloc_free(tmp_ctx);
2906                 return LDB_ERR_OPERATIONS_ERROR;
2907         }
2908
2909         old_i = 0;
2910         new_i = 0;
2911         for (i = 0; i < max_num_values; i++) {
2912                 int cmp;
2913                 struct parsed_dn *old_p, *new_p;
2914                 if (old_i < old_num_values && new_i < repl_num_values) {
2915                         old_p = &old_dns[old_i];
2916                         new_p = &dns[new_i];
2917                         cmp = parsed_dn_compare(old_p, new_p);
2918                 } else if (old_i < old_num_values) {
2919                         /* the new list is empty, read the old list */
2920                         old_p = &old_dns[old_i];
2921                         new_p = NULL;
2922                         cmp = -1;
2923                 } else if (new_i < repl_num_values) {
2924                         /* the old list is empty, read new list */
2925                         old_p = NULL;
2926                         new_p = &dns[new_i];
2927                         cmp = 1;
2928                 } else {
2929                         break;
2930                 }
2931
2932                 if (cmp < 0) {
2933                         /*
2934                          * An old ones that come before the next replacement
2935                          * (if any). We mark it as deleted and add it to the
2936                          * final list.
2937                          */
2938                         uint32_t rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2939                         if ((rmd_flags & DSDB_RMD_FLAG_DELETED) == 0) {
2940                                 ret = replmd_update_la_val(new_values, old_p->v,
2941                                                            old_p->dsdb_dn,
2942                                                            old_p->dsdb_dn,
2943                                                            invocation_id,
2944                                                            seq_num, seq_num,
2945                                                            now, 0, true);
2946                                 if (ret != LDB_SUCCESS) {
2947                                         talloc_free(tmp_ctx);
2948                                         return ret;
2949                                 }
2950
2951                                 ret = replmd_add_backlink(module, replmd_private,
2952                                                           schema, msg_guid,
2953                                                           &old_p->guid, false,
2954                                                           schema_attr, true);
2955                                 if (ret != LDB_SUCCESS) {
2956                                         talloc_free(tmp_ctx);
2957                                         return ret;
2958                                 }
2959                         }
2960                         new_values[i] = *old_p->v;
2961                         old_i++;
2962                 } else if (cmp == 0) {
2963                         /*
2964                          * We are overwriting one. If it was previously
2965                          * deleted, we need to add a backlink.
2966                          *
2967                          * Note that if any RMD_FLAGs in an extended new DN
2968                          * will be ignored.
2969                          */
2970                         uint32_t rmd_flags;
2971
2972                         ret = replmd_update_la_val(new_values, old_p->v,
2973                                                    new_p->dsdb_dn,
2974                                                    old_p->dsdb_dn,
2975                                                    invocation_id,
2976                                                    seq_num, seq_num,
2977                                                    now, 0, false);
2978                         if (ret != LDB_SUCCESS) {
2979                                 talloc_free(tmp_ctx);
2980                                 return ret;
2981                         }
2982
2983                         rmd_flags = dsdb_dn_rmd_flags(old_p->dsdb_dn->dn);
2984                         if ((rmd_flags & DSDB_RMD_FLAG_DELETED) != 0) {
2985                                 ret = replmd_add_backlink(module, replmd_private,
2986                                                           schema, msg_guid,
2987                                                           &new_p->guid, true,
2988                                                           schema_attr, true);
2989                                 if (ret != LDB_SUCCESS) {
2990                                         talloc_free(tmp_ctx);
2991                                         return ret;
2992                                 }
2993                         }
2994
2995                         new_values[i] = *old_p->v;
2996                         old_i++;
2997                         new_i++;
2998                 } else {
2999                         /*
3000                          * Replacements that don't match an existing one. We
3001                          * just add them to the final list.
3002                          */
3003                         ret = replmd_build_la_val(new_values,
3004                                                   new_p->v,
3005                                                   new_p->dsdb_dn,
3006                                                   invocation_id,
3007                                                   seq_num, seq_num,
3008                                                   now, 0, false);
3009                         if (ret != LDB_SUCCESS) {
3010                                 talloc_free(tmp_ctx);
3011                                 return ret;
3012                         }
3013                         ret = replmd_add_backlink(module, replmd_private,
3014                                                   schema, msg_guid,
3015                                                   &new_p->guid, true,
3016                                                   schema_attr, true);
3017                         if (ret != LDB_SUCCESS) {
3018                                 talloc_free(tmp_ctx);
3019                                 return ret;
3020                         }
3021                         new_values[i] = *new_p->v;
3022                         new_i++;
3023                 }
3024         }
3025         if (old_el != NULL) {
3026                 talloc_steal(msg->elements, old_el->values);
3027         }
3028         el->values = talloc_steal(msg->elements, new_values);
3029         el->num_values = i;
3030         talloc_free(tmp_ctx);
3031
3032         el->flags = LDB_FLAG_MOD_REPLACE;
3033
3034         return LDB_SUCCESS;
3035 }
3036
3037
3038 /*
3039   handle linked attributes in modify requests
3040  */
3041 static int replmd_modify_handle_linked_attribs(struct ldb_module *module,
3042                                                struct replmd_private *replmd_private,
3043                                                struct ldb_message *msg,
3044                                                uint64_t seq_num, time_t t,
3045                                                struct ldb_request *parent)
3046 {
3047         struct ldb_result *res;
3048         unsigned int i;
3049         int ret;
3050         struct ldb_context *ldb = ldb_module_get_ctx(module);
3051         struct ldb_message *old_msg;
3052
3053         const struct dsdb_schema *schema;
3054         struct GUID old_guid;
3055
3056         if (dsdb_functional_level(ldb) == DS_DOMAIN_FUNCTION_2000) {
3057                 /*
3058                  * Nothing special is required for modifying or vanishing links
3059                  * in fl2000 since they are just strings in a multi-valued
3060                  * attribute.
3061                  */
3062                 struct ldb_control *ctrl = ldb_request_get_control(parent,
3063                                                                    DSDB_CONTROL_REPLMD_VANISH_LINKS);
3064                 if (ctrl) {
3065                         ctrl->critical = false;
3066                 }
3067                 return LDB_SUCCESS;
3068         }
3069
3070         /*
3071          * TODO:
3072          *
3073          * We should restrict this to the intersection of the list of
3074          * linked attributes in the schema and the list of attributes
3075          * being modified.
3076          *
3077          * This will help performance a little, as otherwise we have
3078          * to allocate the entire object value-by-value.
3079          */
3080         ret = dsdb_module_search_dn(module, msg, &res, msg->dn, NULL,
3081                                     DSDB_FLAG_NEXT_MODULE |
3082                                     DSDB_SEARCH_SHOW_RECYCLED |
3083                                     DSDB_SEARCH_REVEAL_INTERNALS |
3084                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
3085                                     parent);
3086         if (ret != LDB_SUCCESS) {
3087                 return ret;
3088         }
3089         schema = dsdb_get_schema(ldb, res);
3090         if (!schema) {
3091                 return LDB_ERR_OPERATIONS_ERROR;
3092         }
3093
3094         old_msg = res->msgs[0];
3095
3096         old_guid = samdb_result_guid(old_msg, "objectGUID");
3097
3098         for (i=0; i<msg->num_elements; i++) {
3099                 struct ldb_message_element *el = &msg->elements[i];
3100                 struct ldb_message_element *old_el, *new_el;
3101                 const struct dsdb_attribute *schema_attr
3102                         = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
3103                 if (!schema_attr) {
3104                         ldb_asprintf_errstring(ldb,
3105                                                "%s: attribute %s is not a valid attribute in schema",
3106                                                __FUNCTION__, el->name);
3107                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
3108                 }
3109                 if (schema_attr->linkID == 0) {
3110                         continue;
3111                 }
3112                 if ((schema_attr->linkID & 1) == 1) {
3113                         if (parent && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3114                                 continue;
3115                         }
3116                         /* Odd is for the target.  Illegal to modify */
3117                         ldb_asprintf_errstring(ldb,
3118                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
3119                         return LDB_ERR_UNWILLING_TO_PERFORM;
3120                 }
3121                 old_el = ldb_msg_find_element(old_msg, el->name);
3122                 switch (el->flags & LDB_FLAG_MOD_MASK) {
3123                 case LDB_FLAG_MOD_REPLACE:
3124                         ret = replmd_modify_la_replace(module, replmd_private,
3125                                                        schema, msg, el, old_el,
3126                                                        schema_attr, seq_num, t,
3127                                                        &old_guid, parent);
3128                         break;
3129                 case LDB_FLAG_MOD_DELETE:
3130                         ret = replmd_modify_la_delete(module, replmd_private,
3131                                                       schema, msg, el, old_el,
3132                                                       schema_attr, seq_num, t,
3133                                                       &old_guid, parent);
3134                         break;
3135                 case LDB_FLAG_MOD_ADD:
3136                         ret = replmd_modify_la_add(module, replmd_private,
3137                                                    schema, msg, el, old_el,
3138                                                    schema_attr, seq_num, t,
3139                                                    &old_guid, parent);
3140                         break;
3141                 default:
3142                         ldb_asprintf_errstring(ldb,
3143                                                "invalid flags 0x%x for %s linked attribute",
3144                                                el->flags, el->name);
3145                         return LDB_ERR_UNWILLING_TO_PERFORM;
3146                 }
3147                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3148                         ldb_asprintf_errstring(ldb,
3149                                                "Attribute %s is single valued but more than one value has been supplied",
3150                                                el->name);
3151                         return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3152                 } else {
3153                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3154                 }
3155
3156
3157
3158                 if (ret != LDB_SUCCESS) {
3159                         return ret;
3160                 }
3161                 if (old_el) {
3162                         ldb_msg_remove_attr(old_msg, el->name);
3163                 }
3164                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3165                 new_el->num_values = el->num_values;
3166                 new_el->values = talloc_steal(msg->elements, el->values);
3167
3168                 /* TODO: this relises a bit too heavily on the exact
3169                    behaviour of ldb_msg_find_element and
3170                    ldb_msg_remove_element */
3171                 old_el = ldb_msg_find_element(msg, el->name);
3172                 if (old_el != el) {
3173                         ldb_msg_remove_element(msg, old_el);
3174                         i--;
3175                 }
3176         }
3177
3178         talloc_free(res);
3179         return ret;
3180 }
3181
3182
3183
3184 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3185 {
3186         struct ldb_context *ldb;
3187         struct replmd_replicated_request *ac;
3188         struct ldb_request *down_req;
3189         struct ldb_message *msg;
3190         time_t t = time(NULL);
3191         int ret;
3192         bool is_urgent = false, rodc = false;
3193         bool is_schema_nc = false;
3194         unsigned int functional_level;
3195         const struct ldb_message_element *guid_el = NULL;
3196         struct ldb_control *sd_propagation_control;
3197         struct replmd_private *replmd_private =
3198                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3199
3200         /* do not manipulate our control entries */
3201         if (ldb_dn_is_special(req->op.mod.message->dn)) {
3202                 return ldb_next_request(module, req);
3203         }
3204
3205         sd_propagation_control = ldb_request_get_control(req,
3206                                         DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3207         if (sd_propagation_control != NULL) {
3208                 if (req->op.mod.message->num_elements != 1) {
3209                         return ldb_module_operr(module);
3210                 }
3211                 ret = strcmp(req->op.mod.message->elements[0].name,
3212                              "nTSecurityDescriptor");
3213                 if (ret != 0) {
3214                         return ldb_module_operr(module);
3215                 }
3216
3217                 return ldb_next_request(module, req);
3218         }
3219
3220         ldb = ldb_module_get_ctx(module);
3221
3222         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3223
3224         guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3225         if (guid_el != NULL) {
3226                 ldb_set_errstring(ldb,
3227                                   "replmd_modify: it's not allowed to change the objectGUID!");
3228                 return LDB_ERR_CONSTRAINT_VIOLATION;
3229         }
3230
3231         ac = replmd_ctx_init(module, req);
3232         if (ac == NULL) {
3233                 return ldb_module_oom(module);
3234         }
3235
3236         functional_level = dsdb_functional_level(ldb);
3237
3238         /* we have to copy the message as the caller might have it as a const */
3239         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3240         if (msg == NULL) {
3241                 ldb_oom(ldb);
3242                 talloc_free(ac);
3243                 return LDB_ERR_OPERATIONS_ERROR;
3244         }
3245
3246         ldb_msg_remove_attr(msg, "whenChanged");
3247         ldb_msg_remove_attr(msg, "uSNChanged");
3248
3249         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3250
3251         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3252                                  msg, &ac->seq_num, t, is_schema_nc,
3253                                  &is_urgent, &rodc);
3254         if (rodc && (ret == LDB_ERR_REFERRAL)) {
3255                 struct loadparm_context *lp_ctx;
3256                 char *referral;
3257
3258                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3259                                          struct loadparm_context);
3260
3261                 referral = talloc_asprintf(req,
3262                                            "ldap://%s/%s",
3263                                            lpcfg_dnsdomain(lp_ctx),
3264                                            ldb_dn_get_linearized(msg->dn));
3265                 ret = ldb_module_send_referral(req, referral);
3266                 talloc_free(ac);
3267                 return ret;
3268         }
3269
3270         if (ret != LDB_SUCCESS) {
3271                 talloc_free(ac);
3272                 return ret;
3273         }
3274
3275         ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3276                                                   msg, ac->seq_num, t, req);
3277         if (ret != LDB_SUCCESS) {
3278                 talloc_free(ac);
3279                 return ret;
3280         }
3281
3282         /* TODO:
3283          * - replace the old object with the newly constructed one
3284          */
3285
3286         ac->is_urgent = is_urgent;
3287
3288         ret = ldb_build_mod_req(&down_req, ldb, ac,
3289                                 msg,
3290                                 req->controls,
3291                                 ac, replmd_op_callback,
3292                                 req);
3293         LDB_REQ_SET_LOCATION(down_req);
3294         if (ret != LDB_SUCCESS) {
3295                 talloc_free(ac);
3296                 return ret;
3297         }
3298
3299         /* current partition control is needed by "replmd_op_callback" */
3300         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3301                 ret = ldb_request_add_control(down_req,
3302                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
3303                                               false, NULL);
3304                 if (ret != LDB_SUCCESS) {
3305                         talloc_free(ac);
3306                         return ret;
3307                 }
3308         }
3309
3310         /* If we are in functional level 2000, then
3311          * replmd_modify_handle_linked_attribs will have done
3312          * nothing */
3313         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3314                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3315                 if (ret != LDB_SUCCESS) {
3316                         talloc_free(ac);
3317                         return ret;
3318                 }
3319         }
3320
3321         talloc_steal(down_req, msg);
3322
3323         /* we only change whenChanged and uSNChanged if the seq_num
3324            has changed */
3325         if (ac->seq_num != 0) {
3326                 ret = add_time_element(msg, "whenChanged", t);
3327                 if (ret != LDB_SUCCESS) {
3328                         talloc_free(ac);
3329                         ldb_operr(ldb);
3330                         return ret;
3331                 }
3332
3333                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3334                 if (ret != LDB_SUCCESS) {
3335                         talloc_free(ac);
3336                         ldb_operr(ldb);
3337                         return ret;
3338                 }
3339         }
3340
3341         /* go on with the call chain */
3342         return ldb_next_request(module, down_req);
3343 }
3344
3345 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3346
3347 /*
3348   handle a rename request
3349
3350   On a rename we need to do an extra ldb_modify which sets the
3351   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
3352  */
3353 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3354 {
3355         struct ldb_context *ldb;
3356         struct replmd_replicated_request *ac;
3357         int ret;
3358         struct ldb_request *down_req;
3359
3360         /* do not manipulate our control entries */
3361         if (ldb_dn_is_special(req->op.mod.message->dn)) {
3362                 return ldb_next_request(module, req);
3363         }
3364
3365         ldb = ldb_module_get_ctx(module);
3366
3367         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3368
3369         ac = replmd_ctx_init(module, req);
3370         if (ac == NULL) {
3371                 return ldb_module_oom(module);
3372         }
3373
3374         ret = ldb_build_rename_req(&down_req, ldb, ac,
3375                                    ac->req->op.rename.olddn,
3376                                    ac->req->op.rename.newdn,
3377                                    ac->req->controls,
3378                                    ac, replmd_rename_callback,
3379                                    ac->req);
3380         LDB_REQ_SET_LOCATION(down_req);
3381         if (ret != LDB_SUCCESS) {
3382                 talloc_free(ac);
3383                 return ret;
3384         }
3385
3386         /* go on with the call chain */
3387         return ldb_next_request(module, down_req);
3388 }
3389
3390 /* After the rename is compleated, update the whenchanged etc */
3391 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3392 {
3393         struct ldb_context *ldb;
3394         struct ldb_request *down_req;
3395         struct ldb_message *msg;
3396         const struct dsdb_attribute *rdn_attr;
3397         const char *rdn_name;
3398         const struct ldb_val *rdn_val;
3399         const char *attrs[5] = { NULL, };
3400         time_t t = time(NULL);
3401         int ret;
3402         bool is_urgent = false, rodc = false;
3403         bool is_schema_nc;
3404         struct replmd_replicated_request *ac =
3405                 talloc_get_type(req->context, struct replmd_replicated_request);
3406         struct replmd_private *replmd_private =
3407                 talloc_get_type(ldb_module_get_private(ac->module),
3408                                 struct replmd_private);
3409
3410         ldb = ldb_module_get_ctx(ac->module);
3411
3412         if (ares->error != LDB_SUCCESS) {
3413                 return ldb_module_done(ac->req, ares->controls,
3414                                         ares->response, ares->error);
3415         }
3416
3417         if (ares->type != LDB_REPLY_DONE) {
3418                 ldb_set_errstring(ldb,
3419                                   "invalid ldb_reply_type in callback");
3420                 talloc_free(ares);
3421                 return ldb_module_done(ac->req, NULL, NULL,
3422                                         LDB_ERR_OPERATIONS_ERROR);
3423         }
3424
3425         /* TODO:
3426          * - replace the old object with the newly constructed one
3427          */
3428
3429         msg = ldb_msg_new(ac);
3430         if (msg == NULL) {
3431                 ldb_oom(ldb);
3432                 return LDB_ERR_OPERATIONS_ERROR;
3433         }
3434
3435         msg->dn = ac->req->op.rename.newdn;
3436
3437         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3438
3439         rdn_name = ldb_dn_get_rdn_name(msg->dn);
3440         if (rdn_name == NULL) {
3441                 talloc_free(ares);
3442                 return ldb_module_done(ac->req, NULL, NULL,
3443                                        ldb_operr(ldb));
3444         }
3445
3446         /* normalize the rdn attribute name */
3447         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3448         if (rdn_attr == NULL) {
3449                 talloc_free(ares);
3450                 return ldb_module_done(ac->req, NULL, NULL,
3451                                        ldb_operr(ldb));
3452         }
3453         rdn_name = rdn_attr->lDAPDisplayName;
3454
3455         rdn_val = ldb_dn_get_rdn_val(msg->dn);
3456         if (rdn_val == NULL) {
3457                 talloc_free(ares);
3458                 return ldb_module_done(ac->req, NULL, NULL,
3459                                        ldb_operr(ldb));
3460         }
3461
3462         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3463                 talloc_free(ares);
3464                 return ldb_module_done(ac->req, NULL, NULL,
3465                                        ldb_oom(ldb));
3466         }
3467         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3468                 talloc_free(ares);
3469                 return ldb_module_done(ac->req, NULL, NULL,
3470                                        ldb_oom(ldb));
3471         }
3472         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3473                 talloc_free(ares);
3474                 return ldb_module_done(ac->req, NULL, NULL,
3475                                        ldb_oom(ldb));
3476         }
3477         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3478                 talloc_free(ares);
3479                 return ldb_module_done(ac->req, NULL, NULL,
3480                                        ldb_oom(ldb));
3481         }
3482
3483         /*
3484          * here we let replmd_update_rpmd() only search for
3485          * the existing "replPropertyMetaData" and rdn_name attributes.
3486          *
3487          * We do not want the existing "name" attribute as
3488          * the "name" attribute needs to get the version
3489          * updated on rename even if the rdn value hasn't changed.
3490          *
3491          * This is the diff of the meta data, for a moved user
3492          * on a w2k8r2 server:
3493          *
3494          * # record 1
3495          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3496          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3497          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
3498          *         version                  : 0x00000001 (1)
3499          *         reserved                 : 0x00000000 (0)
3500          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
3501          *                      local_usn                : 0x00000000000037a5 (14245)
3502          *                 array: struct replPropertyMetaData1
3503          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
3504          * -                    version                  : 0x00000001 (1)
3505          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
3506          * +                    version                  : 0x00000002 (2)
3507          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
3508          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3509          * -                    originating_usn          : 0x00000000000037a5 (14245)
3510          * -                    local_usn                : 0x00000000000037a5 (14245)
3511          * +                    originating_usn          : 0x0000000000003834 (14388)
3512          * +                    local_usn                : 0x0000000000003834 (14388)
3513          *                 array: struct replPropertyMetaData1
3514          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
3515          *                      version                  : 0x00000004 (4)
3516          */
3517         attrs[0] = "replPropertyMetaData";
3518         attrs[1] = "objectClass";
3519         attrs[2] = "instanceType";
3520         attrs[3] = rdn_name;
3521         attrs[4] = NULL;
3522
3523         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3524                                  msg, &ac->seq_num, t,
3525                                  is_schema_nc, &is_urgent, &rodc);
3526         if (rodc && (ret == LDB_ERR_REFERRAL)) {
3527                 struct ldb_dn *olddn = ac->req->op.rename.olddn;
3528                 struct loadparm_context *lp_ctx;
3529                 char *referral;
3530
3531                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3532                                          struct loadparm_context);
3533
3534                 referral = talloc_asprintf(req,
3535                                            "ldap://%s/%s",
3536                                            lpcfg_dnsdomain(lp_ctx),
3537                                            ldb_dn_get_linearized(olddn));
3538                 ret = ldb_module_send_referral(req, referral);
3539                 talloc_free(ares);
3540                 return ldb_module_done(req, NULL, NULL, ret);
3541         }
3542
3543         if (ret != LDB_SUCCESS) {
3544                 talloc_free(ares);
3545                 return ldb_module_done(ac->req, NULL, NULL, ret);
3546         }
3547
3548         if (ac->seq_num == 0) {
3549                 talloc_free(ares);
3550                 return ldb_module_done(ac->req, NULL, NULL,
3551                                        ldb_error(ldb, ret,
3552                                         "internal error seq_num == 0"));
3553         }
3554         ac->is_urgent = is_urgent;
3555
3556         ret = ldb_build_mod_req(&down_req, ldb, ac,
3557                                 msg,
3558                                 req->controls,
3559                                 ac, replmd_op_callback,
3560                                 req);
3561         LDB_REQ_SET_LOCATION(down_req);
3562         if (ret != LDB_SUCCESS) {
3563                 talloc_free(ac);
3564                 return ret;
3565         }
3566
3567         /* current partition control is needed by "replmd_op_callback" */
3568         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3569                 ret = ldb_request_add_control(down_req,
3570                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
3571                                               false, NULL);
3572                 if (ret != LDB_SUCCESS) {
3573                         talloc_free(ac);
3574                         return ret;
3575                 }
3576         }
3577
3578         talloc_steal(down_req, msg);
3579
3580         ret = add_time_element(msg, "whenChanged", t);
3581         if (ret != LDB_SUCCESS) {
3582                 talloc_free(ac);
3583                 ldb_operr(ldb);
3584                 return ret;
3585         }
3586
3587         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3588         if (ret != LDB_SUCCESS) {
3589                 talloc_free(ac);
3590                 ldb_operr(ldb);
3591                 return ret;
3592         }
3593
3594         /* go on with the call chain - do the modify after the rename */
3595         return ldb_next_request(ac->module, down_req);
3596 }
3597
3598 /*
3599  * remove links from objects that point at this object when an object
3600  * is deleted.  We remove it from the NEXT module per MS-DRSR 5.160
3601  * RemoveObj which states that link removal due to the object being
3602  * deleted is NOT an originating update - they just go away!
3603  *
3604  */
3605 static int replmd_delete_remove_link(struct ldb_module *module,
3606                                      const struct dsdb_schema *schema,
3607                                      struct ldb_dn *dn,
3608                                      struct ldb_message_element *el,
3609                                      const struct dsdb_attribute *sa,
3610                                      struct ldb_request *parent)
3611 {
3612         unsigned int i;
3613         TALLOC_CTX *tmp_ctx = talloc_new(module);
3614         struct ldb_context *ldb = ldb_module_get_ctx(module);
3615
3616         for (i=0; i<el->num_values; i++) {
3617                 struct dsdb_dn *dsdb_dn;
3618                 NTSTATUS status;
3619                 int ret;
3620                 struct GUID guid2;
3621                 struct ldb_message *msg;
3622                 const struct dsdb_attribute *target_attr;
3623                 struct ldb_message_element *el2;
3624                 struct ldb_val dn_val;
3625                 uint32_t dsdb_flags = 0;
3626
3627                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3628                         continue;
3629                 }
3630
3631                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3632                 if (!dsdb_dn) {
3633                         talloc_free(tmp_ctx);
3634                         return LDB_ERR_OPERATIONS_ERROR;
3635                 }
3636
3637                 status = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid2, "GUID");
3638                 if (!NT_STATUS_IS_OK(status)) {
3639                         talloc_free(tmp_ctx);
3640                         return LDB_ERR_OPERATIONS_ERROR;
3641                 }
3642
3643                 /* remove the link */
3644                 msg = ldb_msg_new(tmp_ctx);
3645                 if (!msg) {
3646                         ldb_module_oom(module);
3647                         talloc_free(tmp_ctx);
3648                         return LDB_ERR_OPERATIONS_ERROR;
3649                 }
3650
3651
3652                 msg->dn = dsdb_dn->dn;
3653
3654                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3655                 if (target_attr == NULL) {
3656                         continue;
3657                 }
3658
3659                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName, LDB_FLAG_MOD_DELETE, &el2);
3660                 if (ret != LDB_SUCCESS) {
3661                         ldb_module_oom(module);
3662                         talloc_free(tmp_ctx);
3663                         return LDB_ERR_OPERATIONS_ERROR;
3664                 }
3665                 dn_val = data_blob_string_const(ldb_dn_get_linearized(dn));
3666                 el2->values = &dn_val;
3667                 el2->num_values = 1;
3668
3669                 /*
3670                  * Ensure that we tell the modification to vanish any linked
3671                  * attributes (not simply mark them as isDeleted = TRUE)
3672                  */
3673                 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3674
3675                 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3676                 if (ret != LDB_SUCCESS) {
3677                         talloc_free(tmp_ctx);
3678                         return ret;
3679                 }
3680         }
3681         talloc_free(tmp_ctx);
3682         return LDB_SUCCESS;
3683 }
3684
3685
3686 /*
3687   handle update of replication meta data for deletion of objects
3688
3689   This also handles the mapping of delete to a rename operation
3690   to allow deletes to be replicated.
3691
3692   It also handles the incoming deleted objects, to ensure they are
3693   fully deleted here.  In that case re_delete is true, and we do not
3694   use this as a signal to change the deleted state, just reinforce it.
3695
3696  */
3697 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3698 {
3699         int ret = LDB_ERR_OTHER;
3700         bool retb, disallow_move_on_delete;
3701         struct ldb_dn *old_dn, *new_dn;
3702         const char *rdn_name;
3703         const struct ldb_val *rdn_value, *new_rdn_value;
3704         struct GUID guid;
3705         struct ldb_context *ldb = ldb_module_get_ctx(module);
3706         const struct dsdb_schema *schema;
3707         struct ldb_message *msg, *old_msg;
3708         struct ldb_message_element *el;
3709         TALLOC_CTX *tmp_ctx;
3710         struct ldb_result *res, *parent_res;
3711         static const char * const preserved_attrs[] = {
3712                 /* yes, this really is a hard coded list. See MS-ADTS
3713                    section 3.1.1.5.5.1.1 */
3714                 "attributeID",
3715                 "attributeSyntax",
3716                 "dNReferenceUpdate",
3717                 "dNSHostName",
3718                 "flatName",
3719                 "governsID",
3720                 "groupType",
3721                 "instanceType",
3722                 "lDAPDisplayName",
3723                 "legacyExchangeDN",
3724                 "isDeleted",
3725                 "isRecycled",
3726                 "lastKnownParent",
3727                 "msDS-LastKnownRDN",
3728                 "msDS-PortLDAP",
3729                 "mS-DS-CreatorSID",
3730                 "mSMQOwnerID",
3731                 "nCName",
3732                 "objectClass",
3733                 "distinguishedName",
3734                 "objectGUID",
3735                 "objectSid",
3736                 "oMSyntax",
3737                 "proxiedObjectName",
3738                 "name",
3739                 "nTSecurityDescriptor",
3740                 "replPropertyMetaData",
3741                 "sAMAccountName",
3742                 "securityIdentifier",
3743                 "sIDHistory",
3744                 "subClassOf",
3745                 "systemFlags",
3746                 "trustPartner",
3747                 "trustDirection",
3748                 "trustType",
3749                 "trustAttributes",
3750                 "userAccountControl",
3751                 "uSNChanged",
3752                 "uSNCreated",
3753                 "whenCreated",
3754                 "whenChanged",
3755                 NULL
3756         };
3757         static const char * const all_attrs[] = {
3758                 DSDB_SECRET_ATTRIBUTES,
3759                 "*",
3760                 NULL
3761         };
3762         unsigned int i, el_count = 0;
3763         uint32_t dsdb_flags = 0;
3764         enum deletion_state deletion_state, next_deletion_state;
3765
3766         if (ldb_dn_is_special(req->op.del.dn)) {
3767                 return ldb_next_request(module, req);
3768         }
3769
3770         /*
3771          * We have to allow dbcheck to remove an object that
3772          * is beyond repair, and to do so totally.  This could
3773          * mean we we can get a partial object from the other
3774          * DC, causing havoc, so dbcheck suggests
3775          * re-replication first.  dbcheck sets both DBCHECK
3776          * and RELAX in this situation.
3777          */
3778         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3779             && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3780                 /* really, really remove it */
3781                 return ldb_next_request(module, req);
3782         }
3783
3784         tmp_ctx = talloc_new(ldb);
3785         if (!tmp_ctx) {
3786                 ldb_oom(ldb);
3787                 return LDB_ERR_OPERATIONS_ERROR;
3788         }
3789
3790         schema = dsdb_get_schema(ldb, tmp_ctx);
3791         if (!schema) {
3792                 talloc_free(tmp_ctx);
3793                 return LDB_ERR_OPERATIONS_ERROR;
3794         }
3795
3796         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3797
3798         /* we need the complete msg off disk, so we can work out which
3799            attributes need to be removed */
3800         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3801                                     DSDB_FLAG_NEXT_MODULE |
3802                                     DSDB_SEARCH_SHOW_RECYCLED |
3803                                     DSDB_SEARCH_REVEAL_INTERNALS |
3804                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3805         if (ret != LDB_SUCCESS) {
3806                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3807                                        "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3808                                        re_delete ? "re-delete" : "delete",
3809                                        ldb_dn_get_linearized(old_dn),
3810                                        ldb_errstring(ldb_module_get_ctx(module)));
3811                 talloc_free(tmp_ctx);
3812                 return ret;
3813         }
3814         old_msg = res->msgs[0];
3815
3816         replmd_deletion_state(module, old_msg,
3817                               &deletion_state,
3818                               &next_deletion_state);
3819
3820         /* This supports us noticing an incoming isDeleted and acting on it */
3821         if (re_delete) {
3822                 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3823                 next_deletion_state = deletion_state;
3824         }
3825
3826         if (next_deletion_state == OBJECT_REMOVED) {
3827                 /*
3828                  * We have to prevent objects being deleted, even if
3829                  * the administrator really wants them gone, as
3830                  * without the tombstone, we can get a partial object
3831                  * from the other DC, causing havoc.
3832                  *
3833                  * The only other valid case is when the 180 day
3834                  * timeout has expired, when relax is specified.
3835                  */
3836                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3837                         /* it is already deleted - really remove it this time */
3838                         talloc_free(tmp_ctx);
3839                         return ldb_next_request(module, req);
3840                 }
3841
3842                 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s.  "
3843                                        "This check is to prevent corruption of the replicated state.",
3844                                        ldb_dn_get_linearized(old_msg->dn));
3845                 return LDB_ERR_UNWILLING_TO_PERFORM;
3846         }
3847
3848         rdn_name = ldb_dn_get_rdn_name(old_dn);
3849         rdn_value = ldb_dn_get_rdn_val(old_dn);
3850         if ((rdn_name == NULL) || (rdn_value == NULL)) {
3851                 talloc_free(tmp_ctx);
3852                 return ldb_operr(ldb);
3853         }
3854
3855         msg = ldb_msg_new(tmp_ctx);
3856         if (msg == NULL) {
3857                 ldb_module_oom(module);
3858                 talloc_free(tmp_ctx);
3859                 return LDB_ERR_OPERATIONS_ERROR;
3860         }
3861
3862         msg->dn = old_dn;
3863
3864         /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
3865         disallow_move_on_delete =
3866                 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
3867                  & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
3868
3869         /* work out where we will be renaming this object to */
3870         if (!disallow_move_on_delete) {
3871                 struct ldb_dn *deleted_objects_dn;
3872                 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
3873                                                   &deleted_objects_dn);
3874
3875                 /*
3876                  * We should not move objects if we can't find the
3877                  * deleted objects DN.  Not moving (or otherwise
3878                  * harming) the Deleted Objects DN itself is handled
3879                  * in the caller.
3880                  */
3881                 if (re_delete && (ret != LDB_SUCCESS)) {
3882                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3883                         if (new_dn == NULL) {
3884                                 ldb_module_oom(module);
3885                                 talloc_free(tmp_ctx);
3886                                 return LDB_ERR_OPERATIONS_ERROR;
3887                         }
3888                 } else if (ret != LDB_SUCCESS) {
3889                         /* this is probably an attempted delete on a partition
3890                          * that doesn't allow delete operations, such as the
3891                          * schema partition */
3892                         ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
3893                                                ldb_dn_get_linearized(old_dn));
3894                         talloc_free(tmp_ctx);
3895                         return LDB_ERR_UNWILLING_TO_PERFORM;
3896                 } else {
3897                         new_dn = deleted_objects_dn;
3898                 }
3899         } else {
3900                 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3901                 if (new_dn == NULL) {
3902                         ldb_module_oom(module);
3903                         talloc_free(tmp_ctx);
3904                         return LDB_ERR_OPERATIONS_ERROR;
3905                 }
3906         }
3907
3908         if (deletion_state == OBJECT_NOT_DELETED) {
3909                 /* get the objects GUID from the search we just did */
3910                 guid = samdb_result_guid(old_msg, "objectGUID");
3911
3912                 /* Add a formatted child */
3913                 retb = ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ADEL:%s",
3914                                             rdn_name,
3915                                             ldb_dn_escape_value(tmp_ctx, *rdn_value),
3916                                             GUID_string(tmp_ctx, &guid));
3917                 if (!retb) {
3918                         ldb_asprintf_errstring(ldb, __location__
3919                                                ": Unable to add a formatted child to dn: %s",
3920                                                ldb_dn_get_linearized(new_dn));
3921                         talloc_free(tmp_ctx);
3922                         return LDB_ERR_OPERATIONS_ERROR;
3923                 }
3924
3925                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
3926                 if (ret != LDB_SUCCESS) {
3927                         ldb_asprintf_errstring(ldb, __location__
3928                                                ": Failed to add isDeleted string to the msg");
3929                         talloc_free(tmp_ctx);
3930                         return ret;
3931                 }
3932                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
3933         } else {
3934                 /*
3935                  * No matter what has happened with other renames etc, try again to
3936                  * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
3937                  */
3938
3939                 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
3940                 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
3941                 if (!retb) {
3942                         ldb_asprintf_errstring(ldb, __location__
3943                                                ": Unable to add a prepare rdn of %s",
3944                                                ldb_dn_get_linearized(rdn));
3945                         talloc_free(tmp_ctx);
3946                         return LDB_ERR_OPERATIONS_ERROR;
3947                 }
3948                 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
3949
3950                 retb = ldb_dn_add_child(new_dn, rdn);
3951                 if (!retb) {
3952                         ldb_asprintf_errstring(ldb, __location__
3953                                                ": Unable to add rdn %s to base dn: %s",
3954                                                ldb_dn_get_linearized(rdn),
3955                                                ldb_dn_get_linearized(new_dn));
3956                         talloc_free(tmp_ctx);
3957                         return LDB_ERR_OPERATIONS_ERROR;
3958                 }
3959         }
3960
3961         /*
3962           now we need to modify the object in the following ways:
3963
3964           - add isDeleted=TRUE
3965           - update rDN and name, with new rDN
3966           - remove linked attributes
3967           - remove objectCategory and sAMAccountType
3968           - remove attribs not on the preserved list
3969              - preserved if in above list, or is rDN
3970           - remove all linked attribs from this object
3971           - remove all links from other objects to this object
3972           - add lastKnownParent
3973           - update replPropertyMetaData?
3974
3975           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
3976          */
3977
3978         if (deletion_state == OBJECT_NOT_DELETED) {
3979                 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
3980                 char *parent_dn_str = NULL;
3981
3982                 /* we need the storage form of the parent GUID */
3983                 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
3984                                             parent_dn, NULL,
3985                                             DSDB_FLAG_NEXT_MODULE |
3986                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
3987                                             DSDB_SEARCH_REVEAL_INTERNALS|
3988                                             DSDB_SEARCH_SHOW_RECYCLED, req);
3989                 if (ret != LDB_SUCCESS) {
3990                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
3991                                                "repmd_delete: Failed to %s %s, "
3992                                                "because we failed to find it's parent (%s): %s",
3993                                                re_delete ? "re-delete" : "delete",
3994                                                ldb_dn_get_linearized(old_dn),
3995                                                ldb_dn_get_linearized(parent_dn),
3996                                                ldb_errstring(ldb_module_get_ctx(module)));
3997                         talloc_free(tmp_ctx);
3998                         return ret;
3999                 }
4000
4001                 /*
4002                  * Now we can use the DB version,
4003                  * it will have the extended DN info in it
4004                  */
4005                 parent_dn = parent_res->msgs[0]->dn;
4006                 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4007                                                                parent_dn,
4008                                                                1);
4009                 if (parent_dn_str == NULL) {
4010                         talloc_free(tmp_ctx);
4011                         return ldb_module_oom(module);
4012                 }
4013
4014                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4015                                                parent_dn_str);
4016                 if (ret != LDB_SUCCESS) {
4017                         ldb_asprintf_errstring(ldb, __location__
4018                                                ": Failed to add lastKnownParent "
4019                                                "string when deleting %s",
4020                                                ldb_dn_get_linearized(old_dn));
4021                         talloc_free(tmp_ctx);
4022                         return ret;
4023                 }
4024                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4025
4026                 if (next_deletion_state == OBJECT_DELETED) {
4027                         ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4028                         if (ret != LDB_SUCCESS) {
4029                                 ldb_asprintf_errstring(ldb, __location__
4030                                                        ": Failed to add msDS-LastKnownRDN "
4031                                                        "string when deleting %s",
4032                                                        ldb_dn_get_linearized(old_dn));
4033                                 talloc_free(tmp_ctx);
4034                                 return ret;
4035                         }
4036                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4037                 }
4038         }
4039
4040         switch (next_deletion_state) {
4041
4042         case OBJECT_RECYCLED:
4043         case OBJECT_TOMBSTONE:
4044
4045                 /*
4046                  * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4047                  * describes what must be removed from a tombstone
4048                  * object
4049                  *
4050                  * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4051                  * describes what must be removed from a recycled
4052                  * object
4053                  *
4054                  */
4055
4056                 /*
4057                  * we also mark it as recycled, meaning this object can't be
4058                  * recovered (we are stripping its attributes).
4059                  * This is done only if we have this schema object of course ...
4060                  * This behavior is identical to the one of Windows 2008R2 which
4061                  * always set the isRecycled attribute, even if the recycle-bin is
4062                  * not activated and what ever the forest level is.
4063                  */
4064                 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4065                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4066                         if (ret != LDB_SUCCESS) {
4067                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4068                                 ldb_module_oom(module);
4069                                 talloc_free(tmp_ctx);
4070                                 return ret;
4071                         }
4072                         msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4073                 }
4074
4075                 /* work out which of the old attributes we will be removing */
4076                 for (i=0; i<old_msg->num_elements; i++) {
4077                         const struct dsdb_attribute *sa;
4078                         el = &old_msg->elements[i];
4079                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4080                         if (!sa) {
4081                                 talloc_free(tmp_ctx);
4082                                 return LDB_ERR_OPERATIONS_ERROR;
4083                         }
4084                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4085                                 /* don't remove the rDN */
4086                                 continue;
4087                         }
4088                         if (sa->linkID && (sa->linkID & 1)) {
4089                                 /*
4090                                   we have a backlink in this object
4091                                   that needs to be removed. We're not
4092                                   allowed to remove it directly
4093                                   however, so we instead setup a
4094                                   modify to delete the corresponding
4095                                   forward link
4096                                  */
4097                                 ret = replmd_delete_remove_link(module, schema, old_dn, el, sa, req);
4098                                 if (ret != LDB_SUCCESS) {
4099                                         const char *old_dn_str
4100                                                 = ldb_dn_get_linearized(old_dn);
4101                                         ldb_asprintf_errstring(ldb,
4102                                                                __location__
4103                                                                ": Failed to remove backlink of "
4104                                                                "%s when deleting %s: %s",
4105                                                                el->name,
4106                                                                old_dn_str,
4107                                                                ldb_errstring(ldb));
4108                                         talloc_free(tmp_ctx);
4109                                         return LDB_ERR_OPERATIONS_ERROR;
4110                                 }
4111                                 /* now we continue, which means we
4112                                    won't remove this backlink
4113                                    directly
4114                                 */
4115                                 continue;
4116                         }
4117                         if (!sa->linkID) {
4118                                 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4119                                         continue;
4120                                 }
4121                                 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4122                                         continue;
4123                                 }
4124                         } else {
4125                                 /*
4126                                  * Ensure that we tell the modification to vanish any linked
4127                                  * attributes (not simply mark them as isDeleted = TRUE)
4128                                  */
4129                                 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4130                         }
4131                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4132                         if (ret != LDB_SUCCESS) {
4133                                 talloc_free(tmp_ctx);
4134                                 ldb_module_oom(module);
4135                                 return ret;
4136                         }
4137                 }
4138
4139                 break;
4140
4141         case OBJECT_DELETED:
4142                 /*
4143                  * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4144                  * describes what must be removed from a deleted
4145                  * object
4146                  */
4147
4148                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4149                 if (ret != LDB_SUCCESS) {
4150                         talloc_free(tmp_ctx);
4151                         ldb_module_oom(module);
4152                         return ret;
4153                 }
4154
4155                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4156                 if (ret != LDB_SUCCESS) {
4157                         talloc_free(tmp_ctx);
4158                         ldb_module_oom(module);
4159                         return ret;
4160                 }
4161
4162                 break;
4163
4164         default:
4165                 break;
4166         }
4167
4168         if (deletion_state == OBJECT_NOT_DELETED) {
4169                 const struct dsdb_attribute *sa;
4170
4171                 /* work out what the new rdn value is, for updating the
4172                    rDN and name fields */
4173                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4174                 if (new_rdn_value == NULL) {
4175                         talloc_free(tmp_ctx);
4176                         return ldb_operr(ldb);
4177                 }
4178
4179                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4180                 if (!sa) {
4181                         talloc_free(tmp_ctx);
4182                         return LDB_ERR_OPERATIONS_ERROR;
4183                 }
4184
4185                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4186                                         &el);
4187                 if (ret != LDB_SUCCESS) {
4188                         talloc_free(tmp_ctx);
4189                         return ret;
4190                 }
4191                 el->flags = LDB_FLAG_MOD_REPLACE;
4192
4193                 el = ldb_msg_find_element(old_msg, "name");
4194                 if (el) {
4195                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4196                         if (ret != LDB_SUCCESS) {
4197                                 talloc_free(tmp_ctx);
4198                                 return ret;
4199                         }
4200                         el->flags = LDB_FLAG_MOD_REPLACE;
4201                 }
4202         }
4203
4204         /*
4205          * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4206          *
4207          */
4208
4209         /*
4210          * No matter what has happned with other renames, try again to
4211          * get this to be under the deleted DN.
4212          */
4213         if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4214                 /* now rename onto the new DN */
4215                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4216                 if (ret != LDB_SUCCESS){
4217                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4218                                  ldb_dn_get_linearized(old_dn),
4219                                  ldb_dn_get_linearized(new_dn),
4220                                  ldb_errstring(ldb)));
4221                         talloc_free(tmp_ctx);
4222                         return ret;
4223                 }
4224                 msg->dn = new_dn;
4225         }
4226
4227         ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4228         if (ret != LDB_SUCCESS) {
4229                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4230                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4231                 talloc_free(tmp_ctx);
4232                 return ret;
4233         }
4234
4235         talloc_free(tmp_ctx);
4236
4237         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4238 }
4239
4240 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4241 {
4242         return replmd_delete_internals(module, req, false);
4243 }
4244
4245
4246 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4247 {
4248         return ret;
4249 }
4250
4251 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4252 {
4253         int ret = LDB_ERR_OTHER;
4254         /* TODO: do some error mapping */
4255
4256         /* Let the caller know the full WERROR */
4257         ar->objs->error = status;
4258
4259         return ret;
4260 }
4261
4262
4263 static struct replPropertyMetaData1 *
4264 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4265                                         enum drsuapi_DsAttributeId attid)
4266 {
4267         uint32_t i;
4268         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4269
4270         for (i = 0; i < rpmd_ctr->count; i++) {
4271                 if (rpmd_ctr->array[i].attid == attid) {
4272                         return &rpmd_ctr->array[i];
4273                 }
4274         }
4275         return NULL;
4276 }
4277
4278
4279 /*
4280    return true if an update is newer than an existing entry
4281    see section 5.11 of MS-ADTS
4282 */
4283 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4284                                    const struct GUID *update_invocation_id,
4285                                    uint32_t current_version,
4286                                    uint32_t update_version,
4287                                    NTTIME current_change_time,
4288                                    NTTIME update_change_time)
4289 {
4290         if (update_version != current_version) {
4291                 return update_version > current_version;
4292         }
4293         if (update_change_time != current_change_time) {
4294                 return update_change_time > current_change_time;
4295         }
4296         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4297 }
4298
4299 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4300                                                   struct replPropertyMetaData1 *new_m)
4301 {
4302         return replmd_update_is_newer(&cur_m->originating_invocation_id,
4303                                       &new_m->originating_invocation_id,
4304                                       cur_m->version,
4305                                       new_m->version,
4306                                       cur_m->originating_change_time,
4307                                       new_m->originating_change_time);
4308 }
4309
4310 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4311                                                              struct replPropertyMetaData1 *cur_m,
4312                                                              struct replPropertyMetaData1 *new_m)
4313 {
4314         bool cmp;
4315
4316         /*
4317          * If the new replPropertyMetaData entry for this attribute is
4318          * not provided (this happens in the case where we look for
4319          * ATTID_name, but the name was not changed), then the local
4320          * state is clearly still current, as the remote
4321          * server didn't send it due to being older the high watermark
4322          * USN we sent.
4323          */
4324         if (new_m == NULL) {
4325                 return false;
4326         }
4327
4328         if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4329                 /*
4330                  * if we compare equal then do an
4331                  * update. This is used when a client
4332                  * asks for a FULL_SYNC, and can be
4333                  * used to recover a corrupt
4334                  * replica.
4335                  *
4336                  * This call is a bit tricky, what we
4337                  * are doing it turning the 'is_newer'
4338                  * call into a 'not is older' by
4339                  * swapping cur_m and new_m, and negating the
4340                  * outcome.
4341                  */
4342                 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4343                                                              cur_m);
4344         } else {
4345                 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4346                                                             new_m);
4347         }
4348         return cmp;
4349 }
4350
4351
4352 /*
4353   form a conflict DN
4354  */
4355 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4356 {
4357         const struct ldb_val *rdn_val;
4358         const char *rdn_name;
4359         struct ldb_dn *new_dn;
4360
4361         rdn_val = ldb_dn_get_rdn_val(dn);
4362         rdn_name = ldb_dn_get_rdn_name(dn);
4363         if (!rdn_val || !rdn_name) {
4364                 return NULL;
4365         }
4366
4367         new_dn = ldb_dn_copy(mem_ctx, dn);
4368         if (!new_dn) {
4369                 return NULL;
4370         }
4371
4372         if (!ldb_dn_remove_child_components(new_dn, 1)) {
4373                 return NULL;
4374         }
4375
4376         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4377                                   rdn_name,
4378                                   ldb_dn_escape_value(new_dn, *rdn_val),
4379                                   GUID_string(new_dn, guid))) {
4380                 return NULL;
4381         }
4382
4383         return new_dn;
4384 }
4385
4386
4387 /*
4388   perform a modify operation which sets the rDN and name attributes to
4389   their current values. This has the effect of changing these
4390   attributes to have been last updated by the current DC. This is
4391   needed to ensure that renames performed as part of conflict
4392   resolution are propogated to other DCs
4393  */
4394 static int replmd_name_modify(struct replmd_replicated_request *ar,
4395                               struct ldb_request *req, struct ldb_dn *dn)
4396 {
4397         struct ldb_message *msg;
4398         const char *rdn_name;
4399         const struct ldb_val *rdn_val;
4400         const struct dsdb_attribute *rdn_attr;
4401         int ret;
4402
4403         msg = ldb_msg_new(req);
4404         if (msg == NULL) {
4405                 goto failed;
4406         }
4407         msg->dn = dn;
4408
4409         rdn_name = ldb_dn_get_rdn_name(dn);
4410         if (rdn_name == NULL) {
4411                 goto failed;
4412         }
4413
4414         /* normalize the rdn attribute name */
4415         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4416         if (rdn_attr == NULL) {
4417                 goto failed;
4418         }
4419         rdn_name = rdn_attr->lDAPDisplayName;
4420
4421         rdn_val = ldb_dn_get_rdn_val(dn);
4422         if (rdn_val == NULL) {
4423                 goto failed;
4424         }
4425
4426         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4427                 goto failed;
4428         }
4429         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4430                 goto failed;
4431         }
4432         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4433                 goto failed;
4434         }
4435         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4436                 goto failed;
4437         }
4438
4439         ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4440         if (ret != LDB_SUCCESS) {
4441                 DEBUG(0,(__location__ ": Failed to modify rDN/name of conflict DN '%s' - %s",
4442                          ldb_dn_get_linearized(dn),
4443                          ldb_errstring(ldb_module_get_ctx(ar->module))));
4444                 return ret;
4445         }
4446
4447         talloc_free(msg);
4448
4449         return LDB_SUCCESS;
4450
4451 failed:
4452         talloc_free(msg);
4453         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of conflict DN '%s'",
4454                  ldb_dn_get_linearized(dn)));
4455         return LDB_ERR_OPERATIONS_ERROR;
4456 }
4457
4458
4459 /*
4460   callback for conflict DN handling where we have renamed the incoming
4461   record. After renaming it, we need to ensure the change of name and
4462   rDN for the incoming record is seen as an originating update by this DC.
4463
4464   This also handles updating lastKnownParent for entries sent to lostAndFound
4465  */
4466 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4467 {
4468         struct replmd_replicated_request *ar =
4469                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4470         struct ldb_dn *conflict_dn = NULL;
4471         int ret;
4472
4473         if (ares->error != LDB_SUCCESS) {
4474                 /* call the normal callback for everything except success */
4475                 return replmd_op_callback(req, ares);
4476         }
4477
4478         switch (req->operation) {
4479         case LDB_ADD:
4480                 conflict_dn = req->op.add.message->dn;
4481                 break;
4482         case LDB_MODIFY:
4483                 conflict_dn = req->op.mod.message->dn;
4484                 break;
4485         default:
4486                 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4487         }
4488
4489         /* perform a modify of the rDN and name of the record */
4490         ret = replmd_name_modify(ar, req, conflict_dn);
4491         if (ret != LDB_SUCCESS) {
4492                 ares->error = ret;
4493                 return replmd_op_callback(req, ares);
4494         }
4495
4496         if (ar->objs->objects[ar->index_current].last_known_parent) {
4497                 struct ldb_message *msg = ldb_msg_new(req);
4498                 if (msg == NULL) {
4499                         ldb_module_oom(ar->module);
4500                         return LDB_ERR_OPERATIONS_ERROR;
4501                 }
4502
4503                 msg->dn = req->op.add.message->dn;
4504
4505                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4506                                                ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4507                 if (ret != LDB_SUCCESS) {
4508                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4509                         ldb_module_oom(ar->module);
4510                         return ret;
4511                 }
4512                 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4513
4514                 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4515                 if (ret != LDB_SUCCESS) {
4516                         DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4517                                  ldb_dn_get_linearized(msg->dn),
4518                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
4519                         return ret;
4520                 }
4521                 TALLOC_FREE(msg);
4522         }
4523
4524         return replmd_op_callback(req, ares);
4525 }
4526
4527 /*
4528   callback for replmd_replicated_apply_add()
4529   This copes with the creation of conflict records in the case where
4530   the DN exists, but with a different objectGUID
4531  */
4532 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))
4533 {
4534         struct ldb_dn *conflict_dn;
4535         struct replmd_replicated_request *ar =
4536                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4537         struct ldb_result *res;
4538         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4539         int ret;
4540         const struct ldb_val *omd_value;
4541         struct replPropertyMetaDataBlob omd, *rmd;
4542         enum ndr_err_code ndr_err;
4543         bool rename_incoming_record, rodc;
4544         struct replPropertyMetaData1 *rmd_name, *omd_name;
4545         struct ldb_message *msg;
4546         struct ldb_request *down_req = NULL;
4547
4548         /* call the normal callback for success */
4549         if (ares->error == LDB_SUCCESS) {
4550                 return callback(req, ares);
4551         }
4552
4553         /*
4554          * we have a conflict, and need to decide if we will keep the
4555          * new record or the old record
4556          */
4557
4558         msg = ar->objs->objects[ar->index_current].msg;
4559         conflict_dn = msg->dn;
4560
4561         /* For failures other than conflicts, fail the whole operation here */
4562         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4563                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4564                                        ldb_dn_get_linearized(conflict_dn),
4565                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
4566
4567                 return ldb_module_done(ar->req, NULL, NULL,
4568                                        LDB_ERR_OPERATIONS_ERROR);
4569         }
4570
4571         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4572         if (ret != LDB_SUCCESS) {
4573                 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)));
4574                 return ldb_module_done(ar->req, NULL, NULL,
4575                                        LDB_ERR_OPERATIONS_ERROR);
4576
4577         }
4578
4579         if (rodc) {
4580                 /*
4581                  * We are on an RODC, or were a GC for this
4582                  * partition, so we have to fail this until
4583                  * someone who owns the partition sorts it
4584                  * out
4585                  */
4586                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4587                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
4588                                        " - We must fail the operation until a master for this partition resolves the conflict",
4589                                        ldb_dn_get_linearized(conflict_dn));
4590                 goto failed;
4591         }
4592
4593         /*
4594          * first we need the replPropertyMetaData attribute from the
4595          * local, conflicting record
4596          */
4597         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4598                                     attrs,
4599                                     DSDB_FLAG_NEXT_MODULE |
4600                                     DSDB_SEARCH_SHOW_DELETED |
4601                                     DSDB_SEARCH_SHOW_RECYCLED, req);
4602         if (ret != LDB_SUCCESS) {
4603                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4604                          ldb_dn_get_linearized(conflict_dn)));
4605                 goto failed;
4606         }
4607
4608         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4609         if (omd_value == NULL) {
4610                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4611                          ldb_dn_get_linearized(conflict_dn)));
4612                 goto failed;
4613         }
4614
4615         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4616                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4617         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4618                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4619                          ldb_dn_get_linearized(conflict_dn)));
4620                 goto failed;
4621         }
4622
4623         rmd = ar->objs->objects[ar->index_current].meta_data;
4624
4625         /*
4626          * we decide which is newer based on the RPMD on the name
4627          * attribute.  See [MS-DRSR] ResolveNameConflict.
4628          *
4629          * We expect omd_name to be present, as this is from a local
4630          * search, but while rmd_name should have been given to us by
4631          * the remote server, if it is missing we just prefer the
4632          * local name in
4633          * replmd_replPropertyMetaData1_new_should_be_taken()
4634          */
4635         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4636         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4637         if (!omd_name) {
4638                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4639                          ldb_dn_get_linearized(conflict_dn)));
4640                 goto failed;
4641         }
4642
4643         /*
4644          * Should we preserve the current record, and so rename the
4645          * incoming record to be a conflict?
4646          */
4647         rename_incoming_record
4648                 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4649                                                                     omd_name, rmd_name);
4650
4651         if (rename_incoming_record) {
4652                 struct GUID guid;
4653                 struct ldb_dn *new_dn;
4654
4655                 guid = samdb_result_guid(msg, "objectGUID");
4656                 if (GUID_all_zero(&guid)) {
4657                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4658                                  ldb_dn_get_linearized(conflict_dn)));
4659                         goto failed;
4660                 }
4661                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4662                 if (new_dn == NULL) {
4663                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4664                                  ldb_dn_get_linearized(conflict_dn)));
4665                         goto failed;
4666                 }
4667
4668                 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4669                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4670
4671                 /* re-submit the request, but with the new DN */
4672                 callback = replmd_op_name_modify_callback;
4673                 msg->dn = new_dn;
4674         } else {
4675                 /* we are renaming the existing record */
4676                 struct GUID guid;
4677                 struct ldb_dn *new_dn;
4678
4679                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4680                 if (GUID_all_zero(&guid)) {
4681                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4682                                  ldb_dn_get_linearized(conflict_dn)));
4683                         goto failed;
4684                 }
4685
4686                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4687                 if (new_dn == NULL) {
4688                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4689                                  ldb_dn_get_linearized(conflict_dn)));
4690                         goto failed;
4691                 }
4692
4693                 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4694                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4695
4696                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4697                                          DSDB_FLAG_OWN_MODULE, req);
4698                 if (ret != LDB_SUCCESS) {
4699                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4700                                  ldb_dn_get_linearized(conflict_dn),
4701                                  ldb_dn_get_linearized(new_dn),
4702                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
4703                         goto failed;
4704                 }
4705
4706                 /*
4707                  * now we need to ensure that the rename is seen as an
4708                  * originating update. We do that with a modify.
4709                  */
4710                 ret = replmd_name_modify(ar, req, new_dn);
4711                 if (ret != LDB_SUCCESS) {
4712                         goto failed;
4713                 }
4714
4715                 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
4716                          ldb_dn_get_linearized(req->op.add.message->dn)));
4717         }
4718
4719         ret = ldb_build_add_req(&down_req,
4720                                 ldb_module_get_ctx(ar->module),
4721                                 req,
4722                                 msg,
4723                                 ar->controls,
4724                                 ar,
4725                                 callback,
4726                                 req);
4727         if (ret != LDB_SUCCESS) {
4728                 goto failed;
4729         }
4730         LDB_REQ_SET_LOCATION(down_req);
4731
4732         /* current partition control needed by "repmd_op_callback" */
4733         ret = ldb_request_add_control(down_req,
4734                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4735                                       false, NULL);
4736         if (ret != LDB_SUCCESS) {
4737                 return replmd_replicated_request_error(ar, ret);
4738         }
4739
4740         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4741                 /* this tells the partition module to make it a
4742                    partial replica if creating an NC */
4743                 ret = ldb_request_add_control(down_req,
4744                                               DSDB_CONTROL_PARTIAL_REPLICA,
4745                                               false, NULL);
4746                 if (ret != LDB_SUCCESS) {
4747                         return replmd_replicated_request_error(ar, ret);
4748                 }
4749         }
4750
4751         /*
4752          * Finally we re-run the add, otherwise the new record won't
4753          * exist, as we are here because of that exact failure!
4754          */
4755         return ldb_next_request(ar->module, down_req);
4756 failed:
4757
4758         /* on failure make the caller get the error. This means
4759          * replication will stop with an error, but there is not much
4760          * else we can do.
4761          */
4762         return ldb_module_done(ar->req, NULL, NULL,
4763                                ret);
4764 }
4765
4766 /*
4767   callback for replmd_replicated_apply_add()
4768   This copes with the creation of conflict records in the case where
4769   the DN exists, but with a different objectGUID
4770  */
4771 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
4772 {
4773         struct replmd_replicated_request *ar =
4774                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4775
4776         if (ar->objs->objects[ar->index_current].last_known_parent) {
4777                 /* This is like a conflict DN, where we put the object in LostAndFound
4778                    see MS-DRSR 4.1.10.6.10 FindBestParentObject */
4779                 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
4780         }
4781
4782         return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
4783 }
4784
4785 /*
4786   this is called when a new object comes in over DRS
4787  */
4788 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
4789 {
4790         struct ldb_context *ldb;
4791         struct ldb_request *change_req;
4792         enum ndr_err_code ndr_err;
4793         struct ldb_message *msg;
4794         struct replPropertyMetaDataBlob *md;
4795         struct ldb_val md_value;
4796         unsigned int i;
4797         int ret;
4798         bool remote_isDeleted = false;
4799         bool is_schema_nc;
4800         NTTIME now;
4801         time_t t = time(NULL);
4802         const struct ldb_val *rdn_val;
4803         struct replmd_private *replmd_private =
4804                 talloc_get_type(ldb_module_get_private(ar->module),
4805                                 struct replmd_private);
4806         unix_to_nt_time(&now, t);
4807
4808         ldb = ldb_module_get_ctx(ar->module);
4809         msg = ar->objs->objects[ar->index_current].msg;
4810         md = ar->objs->objects[ar->index_current].meta_data;
4811         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
4812
4813         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
4814         if (ret != LDB_SUCCESS) {
4815                 return replmd_replicated_request_error(ar, ret);
4816         }
4817
4818         ret = dsdb_msg_add_guid(msg,
4819                                 &ar->objs->objects[ar->index_current].object_guid,
4820                                 "objectGUID");
4821         if (ret != LDB_SUCCESS) {
4822                 return replmd_replicated_request_error(ar, ret);
4823         }
4824
4825         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
4826         if (ret != LDB_SUCCESS) {
4827                 return replmd_replicated_request_error(ar, ret);
4828         }
4829
4830         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
4831         if (ret != LDB_SUCCESS) {
4832                 return replmd_replicated_request_error(ar, ret);
4833         }
4834
4835         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
4836         if (ret != LDB_SUCCESS) {
4837                 return replmd_replicated_request_error(ar, ret);
4838         }
4839
4840         /* remove any message elements that have zero values */
4841         for (i=0; i<msg->num_elements; i++) {
4842                 struct ldb_message_element *el = &msg->elements[i];
4843
4844                 if (el->num_values == 0) {
4845                         if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
4846                                 ldb_asprintf_errstring(ldb, __location__
4847                                                        ": empty objectClass sent on %s, aborting replication\n",
4848                                                        ldb_dn_get_linearized(msg->dn));
4849                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
4850                         }
4851
4852                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
4853                                  el->name));
4854                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
4855                         msg->num_elements--;
4856                         i--;
4857                         continue;
4858                 }
4859         }
4860
4861         if (DEBUGLVL(4)) {
4862                 struct GUID_txt_buf guid_txt;
4863
4864                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_ADD, msg);
4865                 DEBUG(4, ("DRS replication add message of %s:\n%s\n",
4866                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
4867                           s));
4868                 talloc_free(s);
4869         }
4870
4871         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
4872                                                      "isDeleted", false);
4873
4874         /*
4875          * the meta data array is already sorted by the caller, except
4876          * for the RDN, which needs to be added.
4877          */
4878
4879
4880         rdn_val = ldb_dn_get_rdn_val(msg->dn);
4881         ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
4882                                      md, ar, now, is_schema_nc);
4883         if (ret != LDB_SUCCESS) {
4884                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4885                 return replmd_replicated_request_error(ar, ret);
4886         }
4887
4888         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
4889         if (ret != LDB_SUCCESS) {
4890                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
4891                 return replmd_replicated_request_error(ar, ret);
4892         }
4893
4894         for (i=0; i < md->ctr.ctr1.count; i++) {
4895                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
4896         }
4897         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
4898                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
4899         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4900                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
4901                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
4902         }
4903         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
4904         if (ret != LDB_SUCCESS) {
4905                 return replmd_replicated_request_error(ar, ret);
4906         }
4907
4908         replmd_ldb_message_sort(msg, ar->schema);
4909
4910         if (!remote_isDeleted) {
4911                 ret = dsdb_module_schedule_sd_propagation(ar->module,
4912                                                           ar->objs->partition_dn,
4913                                                           msg->dn, true);
4914                 if (ret != LDB_SUCCESS) {
4915                         return replmd_replicated_request_error(ar, ret);
4916                 }
4917         }
4918
4919         ar->isDeleted = remote_isDeleted;
4920
4921         ret = ldb_build_add_req(&change_req,
4922                                 ldb,
4923                                 ar,
4924                                 msg,
4925                                 ar->controls,
4926                                 ar,
4927                                 replmd_op_add_callback,
4928                                 ar->req);
4929         LDB_REQ_SET_LOCATION(change_req);
4930         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4931
4932         /* current partition control needed by "repmd_op_callback" */
4933         ret = ldb_request_add_control(change_req,
4934                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
4935                                       false, NULL);
4936         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4937
4938         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
4939                 /* this tells the partition module to make it a
4940                    partial replica if creating an NC */
4941                 ret = ldb_request_add_control(change_req,
4942                                               DSDB_CONTROL_PARTIAL_REPLICA,
4943                                               false, NULL);
4944                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
4945         }
4946
4947         return ldb_next_request(ar->module, change_req);
4948 }
4949
4950 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
4951                                                               struct ldb_reply *ares)
4952 {
4953         struct replmd_replicated_request *ar = talloc_get_type(req->context,
4954                                                struct replmd_replicated_request);
4955         int ret;
4956
4957         if (!ares) {
4958                 return ldb_module_done(ar->req, NULL, NULL,
4959                                         LDB_ERR_OPERATIONS_ERROR);
4960         }
4961
4962         /*
4963          * The error NO_SUCH_OBJECT is not expected, unless the search
4964          * base is the partition DN, and that case doesn't happen here
4965          * because then we wouldn't get a parent_guid_value in any
4966          * case.
4967          */
4968         if (ares->error != LDB_SUCCESS) {
4969                 return ldb_module_done(ar->req, ares->controls,
4970                                         ares->response, ares->error);
4971         }
4972
4973         switch (ares->type) {
4974         case LDB_REPLY_ENTRY:
4975         {
4976                 struct ldb_message *parent_msg = ares->message;
4977                 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
4978                 struct ldb_dn *parent_dn;
4979                 int comp_num;
4980
4981                 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
4982                     && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
4983                         /* Per MS-DRSR 4.1.10.6.10
4984                          * FindBestParentObject we need to move this
4985                          * new object under a deleted object to
4986                          * lost-and-found */
4987                         struct ldb_dn *nc_root;
4988
4989                         ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
4990                         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
4991                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4992                                                        "No suitable NC root found for %s.  "
4993                                                        "We need to move this object because parent object %s "
4994                                                        "is deleted, but this object is not.",
4995                                                        ldb_dn_get_linearized(msg->dn),
4996                                                        ldb_dn_get_linearized(parent_msg->dn));
4997                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
4998                         } else if (ret != LDB_SUCCESS) {
4999                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5000                                                        "Unable to find NC root for %s: %s. "
5001                                                        "We need to move this object because parent object %s "
5002                                                        "is deleted, but this object is not.",
5003                                                        ldb_dn_get_linearized(msg->dn),
5004                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
5005                                                        ldb_dn_get_linearized(parent_msg->dn));
5006                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5007                         }
5008
5009                         ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5010                                                 nc_root,
5011                                                 DS_GUID_LOSTANDFOUND_CONTAINER,
5012                                                 &parent_dn);
5013                         if (ret != LDB_SUCCESS) {
5014                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5015                                                        "Unable to find LostAndFound Container for %s "
5016                                                        "in partition %s: %s. "
5017                                                        "We need to move this object because parent object %s "
5018                                                        "is deleted, but this object is not.",
5019                                                        ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5020                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
5021                                                        ldb_dn_get_linearized(parent_msg->dn));
5022                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5023                         }
5024                         ar->objs->objects[ar->index_current].last_known_parent
5025                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5026
5027                 } else {
5028                         parent_dn
5029                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5030
5031                 }
5032                 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5033
5034                 comp_num = ldb_dn_get_comp_num(msg->dn);
5035                 if (comp_num > 1) {
5036                         if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5037                                 talloc_free(ares);
5038                                 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5039                         }
5040                 }
5041                 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5042                         talloc_free(ares);
5043                         return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5044                 }
5045                 break;
5046         }
5047         case LDB_REPLY_REFERRAL:
5048                 /* we ignore referrals */
5049                 break;
5050
5051         case LDB_REPLY_DONE:
5052
5053                 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5054                         struct GUID_txt_buf str_buf;
5055                         if (ar->search_msg != NULL) {
5056                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5057                                                        "No parent with GUID %s found for object locally known as %s",
5058                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5059                                                        ldb_dn_get_linearized(ar->search_msg->dn));
5060                         } else {
5061                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5062                                                        "No parent with GUID %s found for object remotely known as %s",
5063                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5064                                                        ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5065                         }
5066
5067                         /*
5068                          * This error code is really important, as it
5069                          * is the flag back to the callers to retry
5070                          * this with DRSUAPI_DRS_GET_ANC, and so get
5071                          * the parent objects before the child
5072                          * objects
5073                          */
5074                         return ldb_module_done(ar->req, NULL, NULL,
5075                                                replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5076                 }
5077
5078                 if (ar->search_msg != NULL) {
5079                         ret = replmd_replicated_apply_merge(ar);
5080                 } else {
5081                         ret = replmd_replicated_apply_add(ar);
5082                 }
5083                 if (ret != LDB_SUCCESS) {
5084                         return ldb_module_done(ar->req, NULL, NULL, ret);
5085                 }
5086         }
5087
5088         talloc_free(ares);
5089         return LDB_SUCCESS;
5090 }
5091
5092 /*
5093  * Look for the parent object, so we put the new object in the right
5094  * place This is akin to NameObject in MS-DRSR - this routine and the
5095  * callbacks find the right parent name, and correct name for this
5096  * object
5097  */
5098
5099 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5100 {
5101         struct ldb_context *ldb;
5102         int ret;
5103         char *tmp_str;
5104         char *filter;
5105         struct ldb_request *search_req;
5106         static const char *attrs[] = {"isDeleted", NULL};
5107         struct GUID_txt_buf guid_str_buf;
5108
5109         ldb = ldb_module_get_ctx(ar->module);
5110
5111         if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5112                 if (ar->search_msg != NULL) {
5113                         return replmd_replicated_apply_merge(ar);
5114                 } else {
5115                         return replmd_replicated_apply_add(ar);
5116                 }
5117         }
5118
5119         tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5120                                   &guid_str_buf);
5121
5122         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5123         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5124
5125         ret = ldb_build_search_req(&search_req,
5126                                    ldb,
5127                                    ar,
5128                                    ar->objs->partition_dn,
5129                                    LDB_SCOPE_SUBTREE,
5130                                    filter,
5131                                    attrs,
5132                                    NULL,
5133                                    ar,
5134                                    replmd_replicated_apply_search_for_parent_callback,
5135                                    ar->req);
5136         LDB_REQ_SET_LOCATION(search_req);
5137
5138         ret = dsdb_request_add_controls(search_req,
5139                                         DSDB_SEARCH_SHOW_RECYCLED|
5140                                         DSDB_SEARCH_SHOW_DELETED|
5141                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
5142         if (ret != LDB_SUCCESS) {
5143                 return ret;
5144         }
5145
5146         return ldb_next_request(ar->module, search_req);
5147 }
5148
5149 /*
5150   handle renames that come in over DRS replication
5151  */
5152 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5153                                            struct ldb_message *msg,
5154                                            struct ldb_request *parent,
5155                                            bool *renamed)
5156 {
5157         int ret;
5158         TALLOC_CTX *tmp_ctx = talloc_new(msg);
5159         struct ldb_result *res;
5160         struct ldb_dn *conflict_dn;
5161         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5162         const struct ldb_val *omd_value;
5163         struct replPropertyMetaDataBlob omd, *rmd;
5164         enum ndr_err_code ndr_err;
5165         bool rename_incoming_record, rodc;
5166         struct replPropertyMetaData1 *rmd_name, *omd_name;
5167         struct ldb_dn *new_dn;
5168         struct GUID guid;
5169
5170         DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5171                  ldb_dn_get_linearized(ar->search_msg->dn),
5172                  ldb_dn_get_linearized(msg->dn)));
5173
5174
5175         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5176                                  DSDB_FLAG_NEXT_MODULE, ar->req);
5177         if (ret == LDB_SUCCESS) {
5178                 talloc_free(tmp_ctx);
5179                 *renamed = true;
5180                 return ret;
5181         }
5182
5183         if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5184                 talloc_free(tmp_ctx);
5185                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5186                                        ldb_dn_get_linearized(ar->search_msg->dn),
5187                                        ldb_dn_get_linearized(msg->dn),
5188                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
5189                 return ret;
5190         }
5191
5192         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5193         if (ret != LDB_SUCCESS) {
5194                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5195                                        "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5196                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
5197                 return LDB_ERR_OPERATIONS_ERROR;
5198         }
5199         /*
5200          * we have a conflict, and need to decide if we will keep the
5201          * new record or the old record
5202          */
5203
5204         conflict_dn = msg->dn;
5205
5206         if (rodc) {
5207                 /*
5208                  * We are on an RODC, or were a GC for this
5209                  * partition, so we have to fail this until
5210                  * someone who owns the partition sorts it
5211                  * out
5212                  */
5213                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5214                                        "Conflict adding object '%s' from incoming replication but we are read only for the partition.  \n"
5215                                        " - We must fail the operation until a master for this partition resolves the conflict",
5216                                        ldb_dn_get_linearized(conflict_dn));
5217                 goto failed;
5218         }
5219
5220         /*
5221          * first we need the replPropertyMetaData attribute from the
5222          * old record
5223          */
5224         ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5225                                     attrs,
5226                                     DSDB_FLAG_NEXT_MODULE |
5227                                     DSDB_SEARCH_SHOW_DELETED |
5228                                     DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5229         if (ret != LDB_SUCCESS) {
5230                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5231                          ldb_dn_get_linearized(conflict_dn)));
5232                 goto failed;
5233         }
5234
5235         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5236         if (omd_value == NULL) {
5237                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5238                          ldb_dn_get_linearized(conflict_dn)));
5239                 goto failed;
5240         }
5241
5242         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5243                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5244         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5245                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5246                          ldb_dn_get_linearized(conflict_dn)));
5247                 goto failed;
5248         }
5249
5250         rmd = ar->objs->objects[ar->index_current].meta_data;
5251
5252         /*
5253          * we decide which is newer based on the RPMD on the name
5254          * attribute.  See [MS-DRSR] ResolveNameConflict.
5255          *
5256          * We expect omd_name to be present, as this is from a local
5257          * search, but while rmd_name should have been given to us by
5258          * the remote server, if it is missing we just prefer the
5259          * local name in
5260          * replmd_replPropertyMetaData1_new_should_be_taken()
5261          */
5262         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5263         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5264         if (!omd_name) {
5265                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5266                          ldb_dn_get_linearized(conflict_dn)));
5267                 goto failed;
5268         }
5269
5270         /*
5271          * Should we preserve the current record, and so rename the
5272          * incoming record to be a conflict?
5273          */
5274         rename_incoming_record =
5275                 !replmd_replPropertyMetaData1_new_should_be_taken(
5276                         ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5277                         omd_name, rmd_name);
5278
5279         if (rename_incoming_record) {
5280
5281                 new_dn = replmd_conflict_dn(msg, msg->dn,
5282                                             &ar->objs->objects[ar->index_current].object_guid);
5283                 if (new_dn == NULL) {
5284                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5285                                                                   "Failed to form conflict DN for %s\n",
5286                                                                   ldb_dn_get_linearized(msg->dn));
5287
5288                         return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5289                 }
5290
5291                 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5292                                          DSDB_FLAG_NEXT_MODULE, ar->req);
5293                 if (ret != LDB_SUCCESS) {
5294                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5295                                                "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5296                                                ldb_dn_get_linearized(conflict_dn),
5297                                                ldb_dn_get_linearized(ar->search_msg->dn),
5298                                                ldb_dn_get_linearized(new_dn),
5299                                                ldb_errstring(ldb_module_get_ctx(ar->module)));
5300                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5301                 }
5302
5303                 msg->dn = new_dn;
5304                 *renamed = true;
5305                 return LDB_SUCCESS;
5306         }
5307
5308         /* we are renaming the existing record */
5309
5310         guid = samdb_result_guid(res->msgs[0], "objectGUID");
5311         if (GUID_all_zero(&guid)) {
5312                 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5313                          ldb_dn_get_linearized(conflict_dn)));
5314                 goto failed;
5315         }
5316
5317         new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5318         if (new_dn == NULL) {
5319                 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5320                          ldb_dn_get_linearized(conflict_dn)));
5321                 goto failed;
5322         }
5323
5324         DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5325                  ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5326
5327         ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5328                                  DSDB_FLAG_OWN_MODULE, ar->req);
5329         if (ret != LDB_SUCCESS) {
5330                 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5331                          ldb_dn_get_linearized(conflict_dn),
5332                          ldb_dn_get_linearized(new_dn),
5333                          ldb_errstring(ldb_module_get_ctx(ar->module))));
5334                 goto failed;
5335         }
5336
5337         /*
5338          * now we need to ensure that the rename is seen as an
5339          * originating update. We do that with a modify.
5340          */
5341         ret = replmd_name_modify(ar, ar->req, new_dn);
5342         if (ret != LDB_SUCCESS) {
5343                 goto failed;
5344         }
5345
5346         DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5347                  ldb_dn_get_linearized(ar->search_msg->dn),
5348                  ldb_dn_get_linearized(msg->dn)));
5349
5350
5351         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5352                                  DSDB_FLAG_NEXT_MODULE, ar->req);
5353         if (ret != LDB_SUCCESS) {
5354                 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5355                          ldb_dn_get_linearized(ar->search_msg->dn),
5356                          ldb_dn_get_linearized(msg->dn),
5357                          ldb_errstring(ldb_module_get_ctx(ar->module))));
5358                         goto failed;
5359         }
5360 failed:
5361
5362         /*
5363          * On failure make the caller get the error
5364          * This means replication will stop with an error,
5365          * but there is not much else we can do.  In the
5366          * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5367          * needed.
5368          */
5369
5370         talloc_free(tmp_ctx);
5371         return ret;
5372 }
5373
5374
5375 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5376 {
5377         struct ldb_context *ldb;
5378         struct ldb_request *change_req;
5379         enum ndr_err_code ndr_err;
5380         struct ldb_message *msg;
5381         struct replPropertyMetaDataBlob *rmd;
5382         struct replPropertyMetaDataBlob omd;
5383         const struct ldb_val *omd_value;
5384         struct replPropertyMetaDataBlob nmd;
5385         struct ldb_val nmd_value;
5386         struct GUID remote_parent_guid;
5387         unsigned int i;
5388         uint32_t j,ni=0;
5389         unsigned int removed_attrs = 0;
5390         int ret;
5391         int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5392         bool isDeleted = false;
5393         bool local_isDeleted = false;
5394         bool remote_isDeleted = false;
5395         bool take_remote_isDeleted = false;
5396         bool sd_updated = false;
5397         bool renamed = false;
5398         bool is_schema_nc = false;
5399         NTSTATUS nt_status;
5400         const struct ldb_val *old_rdn, *new_rdn;
5401         struct replmd_private *replmd_private =
5402                 talloc_get_type(ldb_module_get_private(ar->module),
5403                                 struct replmd_private);
5404         NTTIME now;
5405         time_t t = time(NULL);
5406         unix_to_nt_time(&now, t);
5407
5408         ldb = ldb_module_get_ctx(ar->module);
5409         msg = ar->objs->objects[ar->index_current].msg;
5410
5411         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5412
5413         rmd = ar->objs->objects[ar->index_current].meta_data;
5414         ZERO_STRUCT(omd);
5415         omd.version = 1;
5416
5417         /* find existing meta data */
5418         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5419         if (omd_value) {
5420                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5421                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5422                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5423                         nt_status = ndr_map_error2ntstatus(ndr_err);
5424                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5425                 }
5426
5427                 if (omd.version != 1) {
5428                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5429                 }
5430         }
5431
5432         if (DEBUGLVL(5)) {
5433                 struct GUID_txt_buf guid_txt;
5434
5435                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5436                 DEBUG(5, ("Initial DRS replication modify message of %s is:\n%s\n"
5437                           "%s\n"
5438                           "%s\n",
5439                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5440                           s,
5441                           ndr_print_struct_string(s,
5442                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5443                                                   "existing replPropertyMetaData",
5444                                                   &omd),
5445                           ndr_print_struct_string(s,
5446                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5447                                                   "incoming replPropertyMetaData",
5448                                                   rmd)));
5449                 talloc_free(s);
5450         }
5451
5452         local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5453                                                     "isDeleted", false);
5454         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5455                                                      "isDeleted", false);
5456
5457         /*
5458          * Fill in the remote_parent_guid with the GUID or an all-zero
5459          * GUID.
5460          */
5461         if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5462                 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5463         } else {
5464                 remote_parent_guid = GUID_zero();
5465         }
5466
5467         /*
5468          * To ensure we follow a complex rename chain around, we have
5469          * to confirm that the DN is the same (mostly to confirm the
5470          * RDN) and the parentGUID is the same.
5471          *
5472          * This ensures we keep things under the correct parent, which
5473          * replmd_replicated_handle_rename() will do.
5474          */
5475
5476         if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5477             && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5478                 ret = LDB_SUCCESS;
5479         } else {
5480                 /*
5481                  * handle renames, even just by case that come in over
5482                  * DRS.  Changes in the parent DN don't hit us here,
5483                  * because the search for a parent will clean up those
5484                  * components.
5485                  *
5486                  * We also have already filtered out the case where
5487                  * the peer has an older name to what we have (see
5488                  * replmd_replicated_apply_search_callback())
5489                  */
5490                 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5491         }
5492
5493         if (ret != LDB_SUCCESS) {
5494                 ldb_debug(ldb, LDB_DEBUG_FATAL,
5495                           "replmd_replicated_request rename %s => %s failed - %s\n",
5496                           ldb_dn_get_linearized(ar->search_msg->dn),
5497                           ldb_dn_get_linearized(msg->dn),
5498                           ldb_errstring(ldb));
5499                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5500         }
5501
5502         if (renamed == true) {
5503                 /*
5504                  * Set the callback to one that will fix up the name
5505                  * metadata on the new conflict DN
5506                  */
5507                 callback = replmd_op_name_modify_callback;
5508         }
5509
5510         ZERO_STRUCT(nmd);
5511         nmd.version = 1;
5512         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5513         nmd.ctr.ctr1.array = talloc_array(ar,
5514                                           struct replPropertyMetaData1,
5515                                           nmd.ctr.ctr1.count);
5516         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5517
5518         /* first copy the old meta data */
5519         for (i=0; i < omd.ctr.ctr1.count; i++) {
5520                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
5521                 ni++;
5522         }
5523
5524         ar->seq_num = 0;
5525         /* now merge in the new meta data */
5526         for (i=0; i < rmd->ctr.ctr1.count; i++) {
5527                 bool found = false;
5528
5529                 for (j=0; j < ni; j++) {
5530                         bool cmp;
5531
5532                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5533                                 continue;
5534                         }
5535
5536                         cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5537                                 ar->objs->dsdb_repl_flags,
5538                                 &nmd.ctr.ctr1.array[j],
5539                                 &rmd->ctr.ctr1.array[i]);
5540                         if (cmp) {
5541                                 /* replace the entry */
5542                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5543                                 if (ar->seq_num == 0) {
5544                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5545                                         if (ret != LDB_SUCCESS) {
5546                                                 return replmd_replicated_request_error(ar, ret);
5547                                         }
5548                                 }
5549                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5550                                 switch (nmd.ctr.ctr1.array[j].attid) {
5551                                 case DRSUAPI_ATTID_ntSecurityDescriptor:
5552                                         sd_updated = true;
5553                                         break;
5554                                 case DRSUAPI_ATTID_isDeleted:
5555                                         take_remote_isDeleted = true;
5556                                         break;
5557                                 default:
5558                                         break;
5559                                 }
5560                                 found = true;
5561                                 break;
5562                         }
5563
5564                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5565                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5566                                          msg->elements[i-removed_attrs].name,
5567                                          ldb_dn_get_linearized(msg->dn),
5568                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5569                         }
5570
5571                         /* we don't want to apply this change so remove the attribute */
5572                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5573                         removed_attrs++;
5574
5575                         found = true;
5576                         break;
5577                 }
5578
5579                 if (found) continue;
5580
5581                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5582                 if (ar->seq_num == 0) {
5583                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5584                         if (ret != LDB_SUCCESS) {
5585                                 return replmd_replicated_request_error(ar, ret);
5586                         }
5587                 }
5588                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5589                 switch (nmd.ctr.ctr1.array[ni].attid) {
5590                 case DRSUAPI_ATTID_ntSecurityDescriptor:
5591                         sd_updated = true;
5592                         break;
5593                 case DRSUAPI_ATTID_isDeleted:
5594                         take_remote_isDeleted = true;
5595                         break;
5596                 default:
5597                         break;
5598                 }
5599                 ni++;
5600         }
5601
5602         /*
5603          * finally correct the size of the meta_data array
5604          */
5605         nmd.ctr.ctr1.count = ni;
5606
5607         new_rdn = ldb_dn_get_rdn_val(msg->dn);
5608         old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5609
5610         if (renamed) {
5611                 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5612                                                   &nmd, ar, now, is_schema_nc);
5613                 if (ret != LDB_SUCCESS) {
5614                         ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5615                         return replmd_replicated_request_error(ar, ret);
5616                 }
5617         }
5618         /*
5619          * sort the new meta data array
5620          */
5621         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5622         if (ret != LDB_SUCCESS) {
5623                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5624                 return ret;
5625         }
5626
5627         /*
5628          * Work out if this object is deleted, so we can prune any extra attributes.  See MS-DRSR 4.1.10.6.9
5629          * UpdateObject.
5630          *
5631          * This also controls SD propagation below
5632          */
5633         if (take_remote_isDeleted) {
5634                 isDeleted = remote_isDeleted;
5635         } else {
5636                 isDeleted = local_isDeleted;
5637         }
5638
5639         ar->isDeleted = isDeleted;
5640
5641         /*
5642          * check if some replicated attributes left, otherwise skip the ldb_modify() call
5643          */
5644         if (msg->num_elements == 0) {
5645                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5646                           ar->index_current);
5647
5648                 return replmd_replicated_apply_isDeleted(ar);
5649         }
5650
5651         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5652                   ar->index_current, msg->num_elements);
5653
5654         if (renamed) {
5655                 sd_updated = true;
5656         }
5657
5658         if (sd_updated && !isDeleted) {
5659                 ret = dsdb_module_schedule_sd_propagation(ar->module,
5660                                                           ar->objs->partition_dn,
5661                                                           msg->dn, true);
5662                 if (ret != LDB_SUCCESS) {
5663                         return ldb_operr(ldb);
5664                 }
5665         }
5666
5667         /* create the meta data value */
5668         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5669                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5670         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5671                 nt_status = ndr_map_error2ntstatus(ndr_err);
5672                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5673         }
5674
5675         /*
5676          * when we know that we'll modify the record, add the whenChanged, uSNChanged
5677          * and replPopertyMetaData attributes
5678          */
5679         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5680         if (ret != LDB_SUCCESS) {
5681                 return replmd_replicated_request_error(ar, ret);
5682         }
5683         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5684         if (ret != LDB_SUCCESS) {
5685                 return replmd_replicated_request_error(ar, ret);
5686         }
5687         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5688         if (ret != LDB_SUCCESS) {
5689                 return replmd_replicated_request_error(ar, ret);
5690         }
5691
5692         replmd_ldb_message_sort(msg, ar->schema);
5693
5694         /* we want to replace the old values */
5695         for (i=0; i < msg->num_elements; i++) {
5696                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
5697                 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5698                         if (msg->elements[i].num_values == 0) {
5699                                 ldb_asprintf_errstring(ldb, __location__
5700                                                        ": objectClass removed on %s, aborting replication\n",
5701                                                        ldb_dn_get_linearized(msg->dn));
5702                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5703                         }
5704                 }
5705         }
5706
5707         if (DEBUGLVL(4)) {
5708                 struct GUID_txt_buf guid_txt;
5709
5710                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
5711                 DEBUG(4, ("Final DRS replication modify message of %s:\n%s\n",
5712                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5713                           s));
5714                 talloc_free(s);
5715         }
5716
5717         ret = ldb_build_mod_req(&change_req,
5718                                 ldb,
5719                                 ar,
5720                                 msg,
5721                                 ar->controls,
5722                                 ar,
5723                                 callback,
5724                                 ar->req);
5725         LDB_REQ_SET_LOCATION(change_req);
5726         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5727
5728         /* current partition control needed by "repmd_op_callback" */
5729         ret = ldb_request_add_control(change_req,
5730                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
5731                                       false, NULL);
5732         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5733
5734         return ldb_next_request(ar->module, change_req);
5735 }
5736
5737 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
5738                                                    struct ldb_reply *ares)
5739 {
5740         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5741                                                struct replmd_replicated_request);
5742         int ret;
5743
5744         if (!ares) {
5745                 return ldb_module_done(ar->req, NULL, NULL,
5746                                         LDB_ERR_OPERATIONS_ERROR);
5747         }
5748         if (ares->error != LDB_SUCCESS &&
5749             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
5750                 return ldb_module_done(ar->req, ares->controls,
5751                                         ares->response, ares->error);
5752         }
5753
5754         switch (ares->type) {
5755         case LDB_REPLY_ENTRY:
5756                 ar->search_msg = talloc_steal(ar, ares->message);
5757                 break;
5758
5759         case LDB_REPLY_REFERRAL:
5760                 /* we ignore referrals */
5761                 break;
5762
5763         case LDB_REPLY_DONE:
5764         {
5765                 struct replPropertyMetaData1 *md_remote;
5766                 struct replPropertyMetaData1 *md_local;
5767
5768                 struct replPropertyMetaDataBlob omd;
5769                 const struct ldb_val *omd_value;
5770                 struct replPropertyMetaDataBlob *rmd;
5771                 struct ldb_message *msg;
5772                 int instanceType;
5773                 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
5774                 ar->objs->objects[ar->index_current].last_known_parent = NULL;
5775
5776                 /*
5777                  * This is the ADD case, find the appropriate parent,
5778                  * as this object doesn't exist locally:
5779                  */
5780                 if (ar->search_msg == NULL) {
5781                         ret = replmd_replicated_apply_search_for_parent(ar);
5782                         if (ret != LDB_SUCCESS) {
5783                                 return ldb_module_done(ar->req, NULL, NULL, ret);
5784                         }
5785                         talloc_free(ares);
5786                         return LDB_SUCCESS;
5787                 }
5788
5789                 /*
5790                  * Otherwise, in the MERGE case, work out if we are
5791                  * attempting a rename, and if so find the parent the
5792                  * newly renamed object wants to belong under (which
5793                  * may not be the parent in it's attached string DN
5794                  */
5795                 rmd = ar->objs->objects[ar->index_current].meta_data;
5796                 ZERO_STRUCT(omd);
5797                 omd.version = 1;
5798
5799                 /* find existing meta data */
5800                 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5801                 if (omd_value) {
5802                         enum ndr_err_code ndr_err;
5803                         ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5804                                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5805                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5806                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5807                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5808                         }
5809
5810                         if (omd.version != 1) {
5811                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5812                         }
5813                 }
5814
5815                 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
5816
5817                 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
5818                 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
5819                     && GUID_all_zero(&ar->local_parent_guid)) {
5820                         DEBUG(0, ("Refusing to replicate new version of %s "
5821                                   "as local object has an all-zero parentGUID attribute, "
5822                                   "despite not being an NC root\n",
5823                                   ldb_dn_get_linearized(ar->search_msg->dn)));
5824                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5825                 }
5826
5827                 /*
5828                  * now we need to check for double renames. We could have a
5829                  * local rename pending which our replication partner hasn't
5830                  * received yet. We choose which one wins by looking at the
5831                  * attribute stamps on the two objects, the newer one wins.
5832                  *
5833                  * This also simply applies the correct algorithms for
5834                  * determining if a change was made to name at all, or
5835                  * if the object has just been renamed under the same
5836                  * parent.
5837                  */
5838                 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5839                 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5840                 if (!md_local) {
5841                         DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5842                                  ldb_dn_get_linearized(ar->search_msg->dn)));
5843                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5844                 }
5845
5846                 /*
5847                  * if there is no name attribute given then we have to assume the
5848                  *  object we've received has the older name
5849                  */
5850                 if (replmd_replPropertyMetaData1_new_should_be_taken(
5851                             ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5852                             md_local, md_remote)) {
5853                         struct GUID_txt_buf p_guid_local;
5854                         struct GUID_txt_buf p_guid_remote;
5855                         msg = ar->objs->objects[ar->index_current].msg;
5856
5857                         /* Merge on the existing object, with rename */
5858
5859                         DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
5860                                  "as incoming object changing to %s under %s\n",
5861                                  ldb_dn_get_linearized(ar->search_msg->dn),
5862                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5863                                  ldb_dn_get_linearized(msg->dn),
5864                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5865                                                  &p_guid_remote)));
5866                         ret = replmd_replicated_apply_search_for_parent(ar);
5867                 } else {
5868                         struct GUID_txt_buf p_guid_local;
5869                         struct GUID_txt_buf p_guid_remote;
5870                         msg = ar->objs->objects[ar->index_current].msg;
5871
5872                         /*
5873                          * Merge on the existing object, force no
5874                          * rename (code below just to explain why in
5875                          * the DEBUG() logs)
5876                          */
5877
5878                         if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
5879                                    ldb_dn_get_linearized(msg->dn)) == 0) {
5880                                 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
5881                                     GUID_equal(&ar->local_parent_guid,
5882                                                ar->objs->objects[ar->index_current].parent_guid)
5883                                     == false) {
5884                                         DEBUG(4,(__location__ ": Keeping object %s at under %s "
5885                                                  "despite incoming object changing parent to %s\n",
5886                                                  ldb_dn_get_linearized(ar->search_msg->dn),
5887                                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5888                                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5889                                                                  &p_guid_remote)));
5890                                 }
5891                         } else {
5892                                 DEBUG(4,(__location__ ": Keeping object %s at under %s "
5893                                          " and rejecting older rename to %s under %s\n",
5894                                          ldb_dn_get_linearized(ar->search_msg->dn),
5895                                          GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
5896                                          ldb_dn_get_linearized(msg->dn),
5897                                          GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5898                                                          &p_guid_remote)));
5899                         }
5900                         /*
5901                          * This assignment ensures that the strcmp()
5902                          * and GUID_equal() calls in
5903                          * replmd_replicated_apply_merge() avoids the
5904                          * rename call
5905                          */
5906                         ar->objs->objects[ar->index_current].parent_guid =
5907                                 &ar->local_parent_guid;
5908
5909                         msg->dn = ar->search_msg->dn;
5910                         ret = replmd_replicated_apply_merge(ar);
5911                 }
5912                 if (ret != LDB_SUCCESS) {
5913                         return ldb_module_done(ar->req, NULL, NULL, ret);
5914                 }
5915         }
5916         }
5917
5918         talloc_free(ares);
5919         return LDB_SUCCESS;
5920 }
5921
5922 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
5923
5924 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
5925 {
5926         struct ldb_context *ldb;
5927         int ret;
5928         char *tmp_str;
5929         char *filter;
5930         struct ldb_request *search_req;
5931         static const char *attrs[] = { "repsFrom", "replUpToDateVector",
5932                                        "parentGUID", "instanceType",
5933                                        "replPropertyMetaData", "nTSecurityDescriptor",
5934                                        "isDeleted", NULL };
5935         struct GUID_txt_buf guid_str_buf;
5936
5937         if (ar->index_current >= ar->objs->num_objects) {
5938                 /* done with it, go to next stage */
5939                 return replmd_replicated_uptodate_vector(ar);
5940         }
5941
5942         ldb = ldb_module_get_ctx(ar->module);
5943         ar->search_msg = NULL;
5944         ar->isDeleted = false;
5945
5946         tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5947                                   &guid_str_buf);
5948
5949         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5950         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5951
5952         ret = ldb_build_search_req(&search_req,
5953                                    ldb,
5954                                    ar,
5955                                    ar->objs->partition_dn,
5956                                    LDB_SCOPE_SUBTREE,
5957                                    filter,
5958                                    attrs,
5959                                    NULL,
5960                                    ar,
5961                                    replmd_replicated_apply_search_callback,
5962                                    ar->req);
5963         LDB_REQ_SET_LOCATION(search_req);
5964
5965         ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
5966
5967         if (ret != LDB_SUCCESS) {
5968                 return ret;
5969         }
5970
5971         return ldb_next_request(ar->module, search_req);
5972 }
5973
5974 /*
5975  * This is essentially a wrapper for replmd_replicated_apply_next()
5976  *
5977  * This is needed to ensure that both codepaths call this handler.
5978  */
5979 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
5980 {
5981         struct ldb_dn *deleted_objects_dn;
5982         struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5983         int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
5984                                               &deleted_objects_dn);
5985         if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
5986                 /*
5987                  * Do a delete here again, so that if there is
5988                  * anything local that conflicts with this
5989                  * object being deleted, it is removed.  This
5990                  * includes links.  See MS-DRSR 4.1.10.6.9
5991                  * UpdateObject.
5992                  *
5993                  * If the object is already deleted, and there
5994                  * is no more work required, it doesn't do
5995                  * anything.
5996                  */
5997
5998                 /* This has been updated to point to the DN we eventually did the modify on */
5999
6000                 struct ldb_request *del_req;
6001                 struct ldb_result *res;
6002
6003                 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6004                 if (!tmp_ctx) {
6005                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
6006                         return ret;
6007                 }
6008
6009                 res = talloc_zero(tmp_ctx, struct ldb_result);
6010                 if (!res) {
6011                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
6012                         talloc_free(tmp_ctx);
6013                         return ret;
6014                 }
6015
6016                 /* Build a delete request, which hopefully will artually turn into nothing */
6017                 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6018                                         msg->dn,
6019                                         NULL,
6020                                         res,
6021                                         ldb_modify_default_callback,
6022                                         ar->req);
6023                 LDB_REQ_SET_LOCATION(del_req);
6024                 if (ret != LDB_SUCCESS) {
6025                         talloc_free(tmp_ctx);
6026                         return ret;
6027                 }
6028
6029                 /*
6030                  * This is the guts of the call, call back
6031                  * into our delete code, but setting the
6032                  * re_delete flag so we delete anything that
6033                  * shouldn't be there on a deleted or recycled
6034                  * object
6035                  */
6036                 ret = replmd_delete_internals(ar->module, del_req, true);
6037                 if (ret == LDB_SUCCESS) {
6038                         ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6039                 }
6040
6041                 talloc_free(tmp_ctx);
6042                 if (ret != LDB_SUCCESS) {
6043                         return ret;
6044                 }
6045         }
6046
6047         ar->index_current++;
6048         return replmd_replicated_apply_next(ar);
6049 }
6050
6051 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6052                                                       struct ldb_reply *ares)
6053 {
6054         struct ldb_context *ldb;
6055         struct replmd_replicated_request *ar = talloc_get_type(req->context,
6056                                                struct replmd_replicated_request);
6057         ldb = ldb_module_get_ctx(ar->module);
6058
6059         if (!ares) {
6060                 return ldb_module_done(ar->req, NULL, NULL,
6061                                         LDB_ERR_OPERATIONS_ERROR);
6062         }
6063         if (ares->error != LDB_SUCCESS) {
6064                 return ldb_module_done(ar->req, ares->controls,
6065                                         ares->response, ares->error);
6066         }
6067
6068         if (ares->type != LDB_REPLY_DONE) {
6069                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6070                 return ldb_module_done(ar->req, NULL, NULL,
6071                                         LDB_ERR_OPERATIONS_ERROR);
6072         }
6073
6074         talloc_free(ares);
6075
6076         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6077 }
6078
6079 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6080 {
6081         struct ldb_context *ldb;
6082         struct ldb_request *change_req;
6083         enum ndr_err_code ndr_err;
6084         struct ldb_message *msg;
6085         struct replUpToDateVectorBlob ouv;
6086         const struct ldb_val *ouv_value;
6087         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6088         struct replUpToDateVectorBlob nuv;
6089         struct ldb_val nuv_value;
6090         struct ldb_message_element *nuv_el = NULL;
6091         struct ldb_message_element *orf_el = NULL;
6092         struct repsFromToBlob nrf;
6093         struct ldb_val *nrf_value = NULL;
6094         struct ldb_message_element *nrf_el = NULL;
6095         unsigned int i;
6096         uint32_t j,ni=0;
6097         bool found = false;
6098         time_t t = time(NULL);
6099         NTTIME now;
6100         int ret;
6101         uint32_t instanceType;
6102
6103         ldb = ldb_module_get_ctx(ar->module);
6104         ruv = ar->objs->uptodateness_vector;
6105         ZERO_STRUCT(ouv);
6106         ouv.version = 2;
6107         ZERO_STRUCT(nuv);
6108         nuv.version = 2;
6109
6110         unix_to_nt_time(&now, t);
6111
6112         if (ar->search_msg == NULL) {
6113                 /* this happens for a REPL_OBJ call where we are
6114                    creating the target object by replicating it. The
6115                    subdomain join code does this for the partition DN
6116                 */
6117                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6118                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6119         }
6120
6121         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6122         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6123                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6124                          ldb_dn_get_linearized(ar->search_msg->dn)));
6125                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6126         }
6127
6128         /*
6129          * first create the new replUpToDateVector
6130          */
6131         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6132         if (ouv_value) {
6133                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6134                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6135                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6136                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6137                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6138                 }
6139
6140                 if (ouv.version != 2) {
6141                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6142                 }
6143         }
6144
6145         /*
6146          * the new uptodateness vector will at least
6147          * contain 1 entry, one for the source_dsa
6148          *
6149          * plus optional values from our old vector and the one from the source_dsa
6150          */
6151         nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6152         if (ruv) nuv.ctr.ctr2.count += ruv->count;
6153         nuv.ctr.ctr2.cursors = talloc_array(ar,
6154                                             struct drsuapi_DsReplicaCursor2,
6155                                             nuv.ctr.ctr2.count);
6156         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6157
6158         /* first copy the old vector */
6159         for (i=0; i < ouv.ctr.ctr2.count; i++) {
6160                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6161                 ni++;
6162         }
6163
6164         /* merge in the source_dsa vector is available */
6165         for (i=0; (ruv && i < ruv->count); i++) {
6166                 found = false;
6167
6168                 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6169                                &ar->our_invocation_id)) {
6170                         continue;
6171                 }
6172
6173                 for (j=0; j < ni; j++) {
6174                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6175                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6176                                 continue;
6177                         }
6178
6179                         found = true;
6180
6181                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6182                                 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6183                         }
6184                         break;
6185                 }
6186
6187                 if (found) continue;
6188
6189                 /* if it's not there yet, add it */
6190                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6191                 ni++;
6192         }
6193
6194         /*
6195          * finally correct the size of the cursors array
6196          */
6197         nuv.ctr.ctr2.count = ni;
6198
6199         /*
6200          * sort the cursors
6201          */
6202         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6203
6204         /*
6205          * create the change ldb_message
6206          */
6207         msg = ldb_msg_new(ar);
6208         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6209         msg->dn = ar->search_msg->dn;
6210
6211         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6212                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6213         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6214                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6215                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6216         }
6217         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6218         if (ret != LDB_SUCCESS) {
6219                 return replmd_replicated_request_error(ar, ret);
6220         }
6221         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6222
6223         /*
6224          * now create the new repsFrom value from the given repsFromTo1 structure
6225          */
6226         ZERO_STRUCT(nrf);
6227         nrf.version                                     = 1;
6228         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
6229         nrf.ctr.ctr1.last_attempt                       = now;
6230         nrf.ctr.ctr1.last_success                       = now;
6231         nrf.ctr.ctr1.result_last_attempt                = WERR_OK;
6232
6233         /*
6234          * first see if we already have a repsFrom value for the current source dsa
6235          * if so we'll later replace this value
6236          */
6237         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6238         if (orf_el) {
6239                 for (i=0; i < orf_el->num_values; i++) {
6240                         struct repsFromToBlob *trf;
6241
6242                         trf = talloc(ar, struct repsFromToBlob);
6243                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6244
6245                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6246                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6247                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6248                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6249                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6250                         }
6251
6252                         if (trf->version != 1) {
6253                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6254                         }
6255
6256                         /*
6257                          * we compare the source dsa objectGUID not the invocation_id
6258                          * because we want only one repsFrom value per source dsa
6259                          * and when the invocation_id of the source dsa has changed we don't need
6260                          * the old repsFrom with the old invocation_id
6261                          */
6262                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6263                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
6264                                 talloc_free(trf);
6265                                 continue;
6266                         }
6267
6268                         talloc_free(trf);
6269                         nrf_value = &orf_el->values[i];
6270                         break;
6271                 }
6272
6273                 /*
6274                  * copy over all old values to the new ldb_message
6275                  */
6276                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6277                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6278                 *nrf_el = *orf_el;
6279         }
6280
6281         /*
6282          * if we haven't found an old repsFrom value for the current source dsa
6283          * we'll add a new value
6284          */
6285         if (!nrf_value) {
6286                 struct ldb_val zero_value;
6287                 ZERO_STRUCT(zero_value);
6288                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6289                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6290
6291                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6292         }
6293
6294         /* we now fill the value which is already attached to ldb_message */
6295         ndr_err = ndr_push_struct_blob(nrf_value, msg,
6296                                        &nrf,
6297                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6298         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6299                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6300                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6301         }
6302
6303         /*
6304          * the ldb_message_element for the attribute, has all the old values and the new one
6305          * so we'll replace the whole attribute with all values
6306          */
6307         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6308
6309         if (CHECK_DEBUGLVL(4)) {
6310                 char *s = ldb_ldif_message_string(ldb, ar, LDB_CHANGETYPE_MODIFY, msg);
6311                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6312                 talloc_free(s);
6313         }
6314
6315         /* prepare the ldb_modify() request */
6316         ret = ldb_build_mod_req(&change_req,
6317                                 ldb,
6318                                 ar,
6319                                 msg,
6320                                 ar->controls,
6321                                 ar,
6322                                 replmd_replicated_uptodate_modify_callback,
6323                                 ar->req);
6324         LDB_REQ_SET_LOCATION(change_req);
6325         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6326
6327         return ldb_next_request(ar->module, change_req);
6328 }
6329
6330 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6331                                                       struct ldb_reply *ares)
6332 {
6333         struct replmd_replicated_request *ar = talloc_get_type(req->context,
6334                                                struct replmd_replicated_request);
6335         int ret;
6336
6337         if (!ares) {
6338                 return ldb_module_done(ar->req, NULL, NULL,
6339                                         LDB_ERR_OPERATIONS_ERROR);
6340         }
6341         if (ares->error != LDB_SUCCESS &&
6342             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6343                 return ldb_module_done(ar->req, ares->controls,
6344                                         ares->response, ares->error);
6345         }
6346
6347         switch (ares->type) {
6348         case LDB_REPLY_ENTRY:
6349                 ar->search_msg = talloc_steal(ar, ares->message);
6350                 break;
6351
6352         case LDB_REPLY_REFERRAL:
6353                 /* we ignore referrals */
6354                 break;
6355
6356         case LDB_REPLY_DONE:
6357                 ret = replmd_replicated_uptodate_modify(ar);
6358                 if (ret != LDB_SUCCESS) {
6359                         return ldb_module_done(ar->req, NULL, NULL, ret);
6360                 }
6361         }
6362
6363         talloc_free(ares);
6364         return LDB_SUCCESS;
6365 }
6366
6367
6368 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6369 {
6370         struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6371         struct replmd_private *replmd_private =
6372                 talloc_get_type_abort(ldb_module_get_private(ar->module),
6373                 struct replmd_private);
6374         int ret;
6375         static const char *attrs[] = {
6376                 "replUpToDateVector",
6377                 "repsFrom",
6378                 "instanceType",
6379                 NULL
6380         };
6381         struct ldb_request *search_req;
6382
6383         ar->search_msg = NULL;
6384
6385         /*
6386          * Let the caller know that we did an originating updates
6387          */
6388         ar->objs->originating_updates = replmd_private->originating_updates;
6389
6390         ret = ldb_build_search_req(&search_req,
6391                                    ldb,
6392                                    ar,
6393                                    ar->objs->partition_dn,
6394                                    LDB_SCOPE_BASE,
6395                                    "(objectClass=*)",
6396                                    attrs,
6397                                    NULL,
6398                                    ar,
6399                                    replmd_replicated_uptodate_search_callback,
6400                                    ar->req);
6401         LDB_REQ_SET_LOCATION(search_req);
6402         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6403
6404         return ldb_next_request(ar->module, search_req);
6405 }
6406
6407
6408
6409 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6410 {
6411         struct ldb_context *ldb;
6412         struct dsdb_extended_replicated_objects *objs;
6413         struct replmd_replicated_request *ar;
6414         struct ldb_control **ctrls;
6415         int ret;
6416         uint32_t i;
6417         struct replmd_private *replmd_private =
6418                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6419
6420         ldb = ldb_module_get_ctx(module);
6421
6422         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6423
6424         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6425         if (!objs) {
6426                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6427                 return LDB_ERR_PROTOCOL_ERROR;
6428         }
6429
6430         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6431                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6432                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6433                 return LDB_ERR_PROTOCOL_ERROR;
6434         }
6435
6436         ar = replmd_ctx_init(module, req);
6437         if (!ar)
6438                 return LDB_ERR_OPERATIONS_ERROR;
6439
6440         /* Set the flags to have the replmd_op_callback run over the full set of objects */
6441         ar->apply_mode = true;
6442         ar->objs = objs;
6443         ar->schema = dsdb_get_schema(ldb, ar);
6444         if (!ar->schema) {
6445                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6446                 talloc_free(ar);
6447                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6448                 return LDB_ERR_CONSTRAINT_VIOLATION;
6449         }
6450
6451         ctrls = req->controls;
6452
6453         if (req->controls) {
6454                 req->controls = talloc_memdup(ar, req->controls,
6455                                               talloc_get_size(req->controls));
6456                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6457         }
6458
6459         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6460         if (ret != LDB_SUCCESS) {
6461                 return ret;
6462         }
6463
6464         /* If this change contained linked attributes in the body
6465          * (rather than in the links section) we need to update
6466          * backlinks in linked_attributes */
6467         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6468         if (ret != LDB_SUCCESS) {
6469                 return ret;
6470         }
6471
6472         ar->controls = req->controls;
6473         req->controls = ctrls;
6474
6475         DEBUG(4,("linked_attributes_count=%u\n", objs->linked_attributes_count));
6476
6477         /* save away the linked attributes for the end of the
6478            transaction */
6479         for (i=0; i<ar->objs->linked_attributes_count; i++) {
6480                 struct la_entry *la_entry;
6481
6482                 if (replmd_private->la_ctx == NULL) {
6483                         replmd_private->la_ctx = talloc_new(replmd_private);
6484                 }
6485                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6486                 if (la_entry == NULL) {
6487                         ldb_oom(ldb);
6488                         return LDB_ERR_OPERATIONS_ERROR;
6489                 }
6490                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6491                 if (la_entry->la == NULL) {
6492                         talloc_free(la_entry);
6493                         ldb_oom(ldb);
6494                         return LDB_ERR_OPERATIONS_ERROR;
6495                 }
6496                 *la_entry->la = ar->objs->linked_attributes[i];
6497
6498                 /* we need to steal the non-scalars so they stay
6499                    around until the end of the transaction */
6500                 talloc_steal(la_entry->la, la_entry->la->identifier);
6501                 talloc_steal(la_entry->la, la_entry->la->value.blob);
6502
6503                 DLIST_ADD(replmd_private->la_list, la_entry);
6504         }
6505
6506         return replmd_replicated_apply_next(ar);
6507 }
6508
6509 /*
6510   process one linked attribute structure
6511  */
6512 static int replmd_process_linked_attribute(struct ldb_module *module,
6513                                            struct replmd_private *replmd_private,
6514                                            struct la_entry *la_entry,
6515                                            struct ldb_request *parent)
6516 {
6517         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6518         struct ldb_context *ldb = ldb_module_get_ctx(module);
6519         struct ldb_message *msg;
6520         struct ldb_message *target_msg = NULL;
6521         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6522         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
6523         int ret;
6524         const struct dsdb_attribute *attr;
6525         struct dsdb_dn *dsdb_dn;
6526         uint64_t seq_num = 0;
6527         struct ldb_message_element *old_el;
6528         WERROR status;
6529         time_t t = time(NULL);
6530         struct ldb_result *res;
6531         struct ldb_result *target_res;
6532         const char *attrs[4];
6533         const char *attrs2[] = { "isDeleted", "isRecycled", NULL };
6534         struct parsed_dn *pdn_list, *pdn, *next;
6535         struct GUID guid = GUID_zero();
6536         NTSTATUS ntstatus;
6537         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
6538         const struct GUID *our_invocation_id;
6539
6540         enum deletion_state deletion_state = OBJECT_NOT_DELETED;
6541         enum deletion_state target_deletion_state = OBJECT_NOT_DELETED;
6542
6543 /*
6544 linked_attributes[0]:
6545      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
6546         identifier               : *
6547             identifier: struct drsuapi_DsReplicaObjectIdentifier
6548                 __ndr_size               : 0x0000003a (58)
6549                 __ndr_size_sid           : 0x00000000 (0)
6550                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
6551                 sid                      : S-0-0
6552                 __ndr_size_dn            : 0x00000000 (0)
6553                 dn                       : ''
6554         attid                    : DRSUAPI_ATTID_member (0x1F)
6555         value: struct drsuapi_DsAttributeValue
6556             __ndr_size               : 0x0000007e (126)
6557             blob                     : *
6558                 blob                     : DATA_BLOB length=126
6559         flags                    : 0x00000001 (1)
6560                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
6561         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
6562         meta_data: struct drsuapi_DsReplicaMetaData
6563             version                  : 0x00000015 (21)
6564             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
6565             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
6566             originating_usn          : 0x000000000001e19c (123292)
6567
6568 (for cases where the link is to a normal DN)
6569      &target: struct drsuapi_DsReplicaObjectIdentifier3
6570         __ndr_size               : 0x0000007e (126)
6571         __ndr_size_sid           : 0x0000001c (28)
6572         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
6573         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
6574         __ndr_size_dn            : 0x00000022 (34)
6575         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
6576  */
6577
6578         /* find the attribute being modified */
6579         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
6580         if (attr == NULL) {
6581                 struct GUID_txt_buf guid_str;
6582                 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
6583                                        la->attid,
6584                                        GUID_buf_string(&la->identifier->guid,
6585                                                        &guid_str));
6586                 talloc_free(tmp_ctx);
6587                 return LDB_ERR_OPERATIONS_ERROR;
6588         }
6589
6590         attrs[0] = attr->lDAPDisplayName;
6591         attrs[1] = "isDeleted";
6592         attrs[2] = "isRecycled";
6593         attrs[3] = NULL;
6594
6595         /* get the existing message from the db for the object with
6596            this GUID, returning attribute being modified. We will then
6597            use this msg as the basis for a modify call */
6598         ret = dsdb_module_search(module, tmp_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
6599                                  DSDB_FLAG_NEXT_MODULE |
6600                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6601                                  DSDB_SEARCH_SHOW_RECYCLED |
6602                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
6603                                  DSDB_SEARCH_REVEAL_INTERNALS,
6604                                  parent,
6605                                  "objectGUID=%s", GUID_string(tmp_ctx, &la->identifier->guid));
6606         if (ret != LDB_SUCCESS) {
6607                 talloc_free(tmp_ctx);
6608                 return ret;
6609         }
6610         if (res->count != 1) {
6611                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
6612                                        GUID_string(tmp_ctx, &la->identifier->guid));
6613                 talloc_free(tmp_ctx);
6614                 return LDB_ERR_NO_SUCH_OBJECT;
6615         }
6616         msg = res->msgs[0];
6617
6618         /*
6619          * Check for deleted objects per MS-DRSR 4.1.10.6.13
6620          * ProcessLinkValue, because link updates are not applied to
6621          * recycled and tombstone objects.  We don't have to delete
6622          * any existing link, that should have happened when the
6623          * object deletion was replicated or initiated.
6624          */
6625
6626         replmd_deletion_state(module, msg, &deletion_state, NULL);
6627
6628         if (deletion_state >= OBJECT_RECYCLED) {
6629                 talloc_free(tmp_ctx);
6630                 return LDB_SUCCESS;
6631         }
6632
6633         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6634         if (old_el == NULL) {
6635                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
6636                 if (ret != LDB_SUCCESS) {
6637                         ldb_module_oom(module);
6638                         talloc_free(tmp_ctx);
6639                         return LDB_ERR_OPERATIONS_ERROR;
6640                 }
6641         } else {
6642                 old_el->flags = LDB_FLAG_MOD_REPLACE;
6643         }
6644
6645         /* parse the existing links */
6646         ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
6647                                      attr->syntax->ldap_oid, parent);
6648
6649         if (ret != LDB_SUCCESS) {
6650                 talloc_free(tmp_ctx);
6651                 return ret;
6652         }
6653
6654         /* get our invocationId */
6655         our_invocation_id = samdb_ntds_invocation_id(ldb);
6656         if (!our_invocation_id) {
6657                 ldb_debug_set(ldb, LDB_DEBUG_ERROR, __location__ ": unable to find invocationId\n");
6658                 talloc_free(tmp_ctx);
6659                 return LDB_ERR_OPERATIONS_ERROR;
6660         }
6661
6662         ret = replmd_check_upgrade_links(ldb, pdn_list, old_el->num_values,
6663                                          old_el, our_invocation_id,
6664                                          attr->syntax->ldap_oid);
6665         if (ret != LDB_SUCCESS) {
6666                 talloc_free(tmp_ctx);
6667                 return ret;
6668         }
6669
6670         status = dsdb_dn_la_from_blob(ldb, attr, schema, tmp_ctx, la->value.blob, &dsdb_dn);
6671         if (!W_ERROR_IS_OK(status)) {
6672                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
6673                                        old_el->name, ldb_dn_get_linearized(msg->dn), win_errstr(status));
6674                 talloc_free(tmp_ctx);
6675                 return LDB_ERR_OPERATIONS_ERROR;
6676         }
6677
6678         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, &guid, "GUID");
6679         if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6680                 /*
6681                  * This strange behaviour (allowing a NULL/missing
6682                  * GUID) originally comes from:
6683                  *
6684                  * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6685                  * Author: Andrew Tridgell <tridge@samba.org>
6686                  * Date:   Mon Dec 21 21:21:55 2009 +1100
6687                  *
6688                  *  s4-drs: cope better with NULL GUIDS from DRS
6689                  *
6690                  *  It is valid to get a NULL GUID over DRS for a deleted forward link. We
6691                  *  need to match by DN if possible when seeing if we should update an
6692                  *  existing link.
6693                  *
6694                  *  Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
6695                  */
6696
6697                 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
6698                                             dsdb_dn->dn, attrs2,
6699                                             DSDB_FLAG_NEXT_MODULE |
6700                                             DSDB_SEARCH_SHOW_RECYCLED |
6701                                             DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6702                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6703                                             parent);
6704         } else if (!NT_STATUS_IS_OK(ntstatus)) {
6705                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute blob for %s on %s from %s",
6706                                        old_el->name,
6707                                        ldb_dn_get_linearized(dsdb_dn->dn),
6708                                        ldb_dn_get_linearized(msg->dn));
6709                 talloc_free(tmp_ctx);
6710                 return LDB_ERR_OPERATIONS_ERROR;
6711         } else {
6712                 ret = dsdb_module_search(module, tmp_ctx, &target_res,
6713                                          NULL, LDB_SCOPE_SUBTREE,
6714                                          attrs2,
6715                                          DSDB_FLAG_NEXT_MODULE |
6716                                          DSDB_SEARCH_SHOW_RECYCLED |
6717                                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
6718                                          DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
6719                                          parent,
6720                                          "objectGUID=%s",
6721                                          GUID_string(tmp_ctx, &guid));
6722         }
6723
6724         if (ret != LDB_SUCCESS) {
6725                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "Failed to re-resolve GUID %s: %s\n",
6726                                        GUID_string(tmp_ctx, &guid),
6727                                        ldb_errstring(ldb_module_get_ctx(module)));
6728                 talloc_free(tmp_ctx);
6729                 return ret;
6730         }
6731
6732         if (target_res->count == 0) {
6733                 DEBUG(2,(__location__ ": WARNING: Failed to re-resolve GUID %s - using %s\n",
6734                          GUID_string(tmp_ctx, &guid),
6735                          ldb_dn_get_linearized(dsdb_dn->dn)));
6736         } else if (target_res->count != 1) {
6737                 ldb_asprintf_errstring(ldb_module_get_ctx(module), "More than one object found matching objectGUID %s\n",
6738                                        GUID_string(tmp_ctx, &guid));
6739                 talloc_free(tmp_ctx);
6740                 return LDB_ERR_OPERATIONS_ERROR;
6741         } else {
6742                 target_msg = target_res->msgs[0];
6743                 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
6744         }
6745
6746         /*
6747          * Check for deleted objects per MS-DRSR 4.1.10.6.13
6748          * ProcessLinkValue, because link updates are not applied to
6749          * recycled and tombstone objects.  We don't have to delete
6750          * any existing link, that should have happened when the
6751          * object deletion was replicated or initiated.
6752          */
6753         replmd_deletion_state(module, target_msg,
6754                               &target_deletion_state, NULL);
6755
6756         if (target_deletion_state >= OBJECT_RECYCLED) {
6757                 talloc_free(tmp_ctx);
6758                 return LDB_SUCCESS;
6759         }
6760
6761         /* see if this link already exists */
6762         ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
6763                              &guid,
6764                              dsdb_dn->dn,
6765                              &pdn, &next,
6766                              attr->syntax->ldap_oid);
6767         if (ret != LDB_SUCCESS) {
6768                 talloc_free(tmp_ctx);
6769                 return ret;
6770         }
6771
6772
6773         if (pdn != NULL) {
6774                 /* see if this update is newer than what we have already */
6775                 struct GUID invocation_id = GUID_zero();
6776                 uint32_t version = 0;
6777                 uint32_t originating_usn = 0;
6778                 NTTIME change_time = 0;
6779                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
6780
6781                 dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
6782                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
6783                 dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &originating_usn, "RMD_ORIGINATING_USN");
6784                 dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
6785
6786                 if (!replmd_update_is_newer(&invocation_id,
6787                                             &la->meta_data.originating_invocation_id,
6788                                             version,
6789                                             la->meta_data.version,
6790                                             change_time,
6791                                             la->meta_data.originating_change_time)) {
6792                         DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
6793                                  old_el->name, ldb_dn_get_linearized(msg->dn),
6794                                  GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
6795                         talloc_free(tmp_ctx);
6796                         return LDB_SUCCESS;
6797                 }
6798
6799                 /* get a seq_num for this change */
6800                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6801                 if (ret != LDB_SUCCESS) {
6802                         talloc_free(tmp_ctx);
6803                         return ret;
6804                 }
6805
6806                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
6807                         /* remove the existing backlink */
6808                         ret = replmd_add_backlink(module, replmd_private,
6809                                                   schema, &la->identifier->guid,
6810                                                   &guid, false, attr, true);
6811                         if (ret != LDB_SUCCESS) {
6812                                 talloc_free(tmp_ctx);
6813                                 return ret;
6814                         }
6815                 }
6816
6817                 ret = replmd_update_la_val(tmp_ctx, pdn->v, dsdb_dn, pdn->dsdb_dn,
6818                                            &la->meta_data.originating_invocation_id,
6819                                            la->meta_data.originating_usn, seq_num,
6820                                            la->meta_data.originating_change_time,
6821                                            la->meta_data.version,
6822                                            !active);
6823                 if (ret != LDB_SUCCESS) {
6824                         talloc_free(tmp_ctx);
6825                         return ret;
6826                 }
6827
6828                 if (active) {
6829                         /* add the new backlink */
6830                         ret = replmd_add_backlink(module, replmd_private,
6831                                                   schema, &la->identifier->guid,
6832                                                   &guid, true, attr, true);
6833                         if (ret != LDB_SUCCESS) {
6834                                 talloc_free(tmp_ctx);
6835                                 return ret;
6836                         }
6837                 }
6838         } else {
6839                 unsigned offset;
6840                 /* get a seq_num for this change */
6841                 ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
6842                 if (ret != LDB_SUCCESS) {
6843                         talloc_free(tmp_ctx);
6844                         return ret;
6845                 }
6846                 /*
6847                  * We know where the new one needs to be, from the *next
6848                  * pointer into pdn_list.
6849                  */
6850                 if (next == NULL) {
6851                         offset = old_el->num_values;
6852                 } else {
6853                         if (next->dsdb_dn == NULL) {
6854                                 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
6855                                                               attr->syntax->ldap_oid);
6856                                 if (ret != LDB_SUCCESS) {
6857                                         return ret;
6858                                 }
6859                         }
6860                         offset = next - pdn_list;
6861                         if (offset > old_el->num_values) {
6862                                 talloc_free(tmp_ctx);
6863                                 return LDB_ERR_OPERATIONS_ERROR;
6864                         }
6865                 }
6866
6867                 old_el->values = talloc_realloc(msg->elements, old_el->values,
6868                                                 struct ldb_val, old_el->num_values+1);
6869                 if (!old_el->values) {
6870                         ldb_module_oom(module);
6871                         return LDB_ERR_OPERATIONS_ERROR;
6872                 }
6873
6874                 if (offset != old_el->num_values) {
6875                         memmove(&old_el->values[offset + 1], &old_el->values[offset],
6876                                 (old_el->num_values - offset) * sizeof(old_el->values[0]));
6877                 }
6878
6879                 old_el->num_values++;
6880
6881                 ret = replmd_build_la_val(tmp_ctx, &old_el->values[offset], dsdb_dn,
6882                                           &la->meta_data.originating_invocation_id,
6883                                           la->meta_data.originating_usn, seq_num,
6884                                           la->meta_data.originating_change_time,
6885                                           la->meta_data.version,
6886                                           !active);
6887                 if (ret != LDB_SUCCESS) {
6888                         talloc_free(tmp_ctx);
6889                         return ret;
6890                 }
6891
6892                 if (active) {
6893                         ret = replmd_add_backlink(module, replmd_private,
6894                                                   schema, &la->identifier->guid,
6895                                                   &guid, true, attr, true);
6896                         if (ret != LDB_SUCCESS) {
6897                                 talloc_free(tmp_ctx);
6898                                 return ret;
6899                         }
6900                 }
6901         }
6902
6903         /* we only change whenChanged and uSNChanged if the seq_num
6904            has changed */
6905         ret = add_time_element(msg, "whenChanged", t);
6906         if (ret != LDB_SUCCESS) {
6907                 talloc_free(tmp_ctx);
6908                 ldb_operr(ldb);
6909                 return ret;
6910         }
6911
6912         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
6913         if (ret != LDB_SUCCESS) {
6914                 talloc_free(tmp_ctx);
6915                 ldb_operr(ldb);
6916                 return ret;
6917         }
6918
6919         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
6920         if (old_el == NULL) {
6921                 talloc_free(tmp_ctx);
6922                 return ldb_operr(ldb);
6923         }
6924
6925         ret = dsdb_check_single_valued_link(attr, old_el);
6926         if (ret != LDB_SUCCESS) {
6927                 talloc_free(tmp_ctx);
6928                 return ret;
6929         }
6930
6931         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
6932
6933         ret = linked_attr_modify(module, msg, parent);
6934         if (ret != LDB_SUCCESS) {
6935                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
6936                           ldb_errstring(ldb),
6937                           ldb_ldif_message_string(ldb, tmp_ctx, LDB_CHANGETYPE_MODIFY, msg));
6938                 talloc_free(tmp_ctx);
6939                 return ret;
6940         }
6941
6942         talloc_free(tmp_ctx);
6943
6944         return ret;
6945 }
6946
6947 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
6948 {
6949         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
6950                 return replmd_extended_replicated_objects(module, req);
6951         }
6952
6953         return ldb_next_request(module, req);
6954 }
6955
6956
6957 /*
6958   we hook into the transaction operations to allow us to
6959   perform the linked attribute updates at the end of the whole
6960   transaction. This allows a forward linked attribute to be created
6961   before the object is created. During a vampire, w2k8 sends us linked
6962   attributes before the objects they are part of.
6963  */
6964 static int replmd_start_transaction(struct ldb_module *module)
6965 {
6966         /* create our private structure for this transaction */
6967         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
6968                                                                 struct replmd_private);
6969         replmd_txn_cleanup(replmd_private);
6970
6971         /* free any leftover mod_usn records from cancelled
6972            transactions */
6973         while (replmd_private->ncs) {
6974                 struct nc_entry *e = replmd_private->ncs;
6975                 DLIST_REMOVE(replmd_private->ncs, e);
6976                 talloc_free(e);
6977         }
6978
6979         replmd_private->originating_updates = false;
6980
6981         return ldb_next_start_trans(module);
6982 }
6983
6984 /*
6985   on prepare commit we loop over our queued la_context structures and
6986   apply each of them
6987  */
6988 static int replmd_prepare_commit(struct ldb_module *module)
6989 {
6990         struct replmd_private *replmd_private =
6991                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6992         struct la_entry *la, *prev;
6993         struct la_backlink *bl;
6994         int ret;
6995
6996         /* walk the list backwards, to do the first entry first, as we
6997          * added the entries with DLIST_ADD() which puts them at the
6998          * start of the list */
6999         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7000                 prev = DLIST_PREV(la);
7001                 DLIST_REMOVE(replmd_private->la_list, la);
7002                 ret = replmd_process_linked_attribute(module, replmd_private,
7003                                                       la, NULL);
7004                 if (ret != LDB_SUCCESS) {
7005                         replmd_txn_cleanup(replmd_private);
7006                         return ret;
7007                 }
7008         }
7009
7010         /* process our backlink list, creating and deleting backlinks
7011            as necessary */
7012         for (bl=replmd_private->la_backlinks; bl; bl=bl->next) {
7013                 ret = replmd_process_backlink(module, bl, NULL);
7014                 if (ret != LDB_SUCCESS) {
7015                         replmd_txn_cleanup(replmd_private);
7016                         return ret;
7017                 }
7018         }
7019
7020         replmd_txn_cleanup(replmd_private);
7021
7022         /* possibly change @REPLCHANGED */
7023         ret = replmd_notify_store(module, NULL);
7024         if (ret != LDB_SUCCESS) {
7025                 return ret;
7026         }
7027
7028         return ldb_next_prepare_commit(module);
7029 }
7030
7031 static int replmd_del_transaction(struct ldb_module *module)
7032 {
7033         struct replmd_private *replmd_private =
7034                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7035         replmd_txn_cleanup(replmd_private);
7036
7037         return ldb_next_del_trans(module);
7038 }
7039
7040
7041 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7042         .name          = "repl_meta_data",
7043         .init_context      = replmd_init,
7044         .add               = replmd_add,
7045         .modify            = replmd_modify,
7046         .rename            = replmd_rename,
7047         .del               = replmd_delete,
7048         .extended          = replmd_extended,
7049         .start_transaction = replmd_start_transaction,
7050         .prepare_commit    = replmd_prepare_commit,
7051         .del_transaction   = replmd_del_transaction,
7052 };
7053
7054 int ldb_repl_meta_data_module_init(const char *version)
7055 {
7056         LDB_MODULE_CHECK_VERSION(version);
7057         return ldb_register_module(&ldb_repl_meta_data_module_ops);
7058 }