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