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