8bb47b330ab7c7559e43e79a05e5d35f1bd714cf
[metze/samba/wip.git] / source4 / dsdb / samdb / ldb_modules / repl_meta_data.c
1 /*
2    ldb database library
3
4    Copyright (C) Simo Sorce  2004-2008
5    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2013
6    Copyright (C) Andrew Tridgell 2005-2009
7    Copyright (C) Stefan Metzmacher <metze@samba.org> 2007
8    Copyright (C) Matthieu Patou <mat@samba.org> 2010-2011
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 /*
25  *  Name: ldb
26  *
27  *  Component: ldb repl_meta_data module
28  *
29  *  Description: - add a unique objectGUID onto every new record,
30  *               - handle whenCreated, whenChanged timestamps
31  *               - handle uSNCreated, uSNChanged numbers
32  *               - handle replPropertyMetaData attribute
33  *
34  *  Author: Simo Sorce
35  *  Author: Stefan Metzmacher
36  */
37
38 #include "includes.h"
39 #include "ldb_module.h"
40 #include "dsdb/samdb/samdb.h"
41 #include "dsdb/common/proto.h"
42 #include "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 && ldb_request_get_control(parent, DSDB_CONTROL_DBCHECK)) {
3176                                 continue;
3177                         }
3178                         /* Odd is for the target.  Illegal to modify */
3179                         ldb_asprintf_errstring(ldb,
3180                                                "attribute %s must not be modified directly, it is a linked attribute", el->name);
3181                         return LDB_ERR_UNWILLING_TO_PERFORM;
3182                 }
3183                 old_el = ldb_msg_find_element(old_msg, el->name);
3184                 switch (mod_type) {
3185                 case LDB_FLAG_MOD_REPLACE:
3186                         ret = replmd_modify_la_replace(module, replmd_private,
3187                                                        schema, msg, el, old_el,
3188                                                        schema_attr, seq_num, t,
3189                                                        old_msg->dn,
3190                                                        parent);
3191                         break;
3192                 case LDB_FLAG_MOD_DELETE:
3193                         ret = replmd_modify_la_delete(module, replmd_private,
3194                                                       schema, msg, el, old_el,
3195                                                       schema_attr, seq_num, t,
3196                                                       old_msg->dn,
3197                                                       parent);
3198                         break;
3199                 case LDB_FLAG_MOD_ADD:
3200                         ret = replmd_modify_la_add(module, replmd_private,
3201                                                    schema, msg, el, old_el,
3202                                                    schema_attr, seq_num, t,
3203                                                    old_msg->dn,
3204                                                    parent);
3205                         break;
3206                 default:
3207                         ldb_asprintf_errstring(ldb,
3208                                                "invalid flags 0x%x for %s linked attribute",
3209                                                el->flags, el->name);
3210                         return LDB_ERR_UNWILLING_TO_PERFORM;
3211                 }
3212                 if (dsdb_check_single_valued_link(schema_attr, el) != LDB_SUCCESS) {
3213                         ldb_asprintf_errstring(ldb,
3214                                                "Attribute %s is single valued but more than one value has been supplied",
3215                                                el->name);
3216                         /* Return codes as found on Windows 2012r2 */
3217                         if (mod_type == LDB_FLAG_MOD_REPLACE) {
3218                                 return LDB_ERR_CONSTRAINT_VIOLATION;
3219                         } else {
3220                                 return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
3221                         }
3222                 } else {
3223                         el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
3224                 }
3225
3226                 if (ret != LDB_SUCCESS) {
3227                         return ret;
3228                 }
3229                 if (old_el) {
3230                         ldb_msg_remove_attr(old_msg, el->name);
3231                 }
3232                 ldb_msg_add_empty(old_msg, el->name, 0, &new_el);
3233                 new_el->num_values = el->num_values;
3234                 new_el->values = talloc_steal(msg->elements, el->values);
3235
3236                 /* TODO: this relises a bit too heavily on the exact
3237                    behaviour of ldb_msg_find_element and
3238                    ldb_msg_remove_element */
3239                 old_el = ldb_msg_find_element(msg, el->name);
3240                 if (old_el != el) {
3241                         ldb_msg_remove_element(msg, old_el);
3242                         i--;
3243                 }
3244         }
3245
3246         talloc_free(res);
3247         return ret;
3248 }
3249
3250
3251 static int send_rodc_referral(struct ldb_request *req,
3252                               struct ldb_context *ldb,
3253                               struct ldb_dn *dn)
3254 {
3255         char *referral = NULL;
3256         struct loadparm_context *lp_ctx = NULL;
3257         struct ldb_dn *fsmo_role_dn = NULL;
3258         struct ldb_dn *role_owner_dn = NULL;
3259         const char *domain = NULL;
3260         WERROR werr;
3261
3262         lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
3263                                  struct loadparm_context);
3264
3265         werr = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
3266                                        &fsmo_role_dn, &role_owner_dn);
3267
3268         if (W_ERROR_IS_OK(werr)) {
3269                 struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
3270                 if (server_dn != NULL) {
3271                         ldb_dn_remove_child_components(server_dn, 1);
3272                         domain = samdb_dn_to_dnshostname(ldb, req,
3273                                                          server_dn);
3274                 }
3275         }
3276
3277         if (domain == NULL) {
3278                 domain = lpcfg_dnsdomain(lp_ctx);
3279         }
3280
3281         referral = talloc_asprintf(req, "ldap://%s/%s",
3282                                    domain,
3283                                    ldb_dn_get_linearized(dn));
3284         if (referral == NULL) {
3285                 ldb_oom(ldb);
3286                 return LDB_ERR_OPERATIONS_ERROR;
3287         }
3288
3289         return ldb_module_send_referral(req, referral);
3290 }
3291
3292
3293 static int replmd_modify(struct ldb_module *module, struct ldb_request *req)
3294 {
3295         struct ldb_context *ldb;
3296         struct replmd_replicated_request *ac;
3297         struct ldb_request *down_req;
3298         struct ldb_message *msg;
3299         time_t t = time(NULL);
3300         int ret;
3301         bool is_urgent = false, rodc = false;
3302         bool is_schema_nc = false;
3303         unsigned int functional_level;
3304         const struct ldb_message_element *guid_el = NULL;
3305         struct ldb_control *sd_propagation_control;
3306         struct replmd_private *replmd_private =
3307                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
3308
3309         /* do not manipulate our control entries */
3310         if (ldb_dn_is_special(req->op.mod.message->dn)) {
3311                 return ldb_next_request(module, req);
3312         }
3313
3314         sd_propagation_control = ldb_request_get_control(req,
3315                                         DSDB_CONTROL_SEC_DESC_PROPAGATION_OID);
3316         if (sd_propagation_control != NULL) {
3317                 if (req->op.mod.message->num_elements != 1) {
3318                         return ldb_module_operr(module);
3319                 }
3320                 ret = strcmp(req->op.mod.message->elements[0].name,
3321                              "nTSecurityDescriptor");
3322                 if (ret != 0) {
3323                         return ldb_module_operr(module);
3324                 }
3325
3326                 return ldb_next_request(module, req);
3327         }
3328
3329         ldb = ldb_module_get_ctx(module);
3330
3331         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_modify\n");
3332
3333         guid_el = ldb_msg_find_element(req->op.mod.message, "objectGUID");
3334         if (guid_el != NULL) {
3335                 ldb_set_errstring(ldb,
3336                                   "replmd_modify: it's not allowed to change the objectGUID!");
3337                 return LDB_ERR_CONSTRAINT_VIOLATION;
3338         }
3339
3340         ac = replmd_ctx_init(module, req);
3341         if (ac == NULL) {
3342                 return ldb_module_oom(module);
3343         }
3344
3345         functional_level = dsdb_functional_level(ldb);
3346
3347         /* we have to copy the message as the caller might have it as a const */
3348         msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
3349         if (msg == NULL) {
3350                 ldb_oom(ldb);
3351                 talloc_free(ac);
3352                 return LDB_ERR_OPERATIONS_ERROR;
3353         }
3354
3355         ldb_msg_remove_attr(msg, "whenChanged");
3356         ldb_msg_remove_attr(msg, "uSNChanged");
3357
3358         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3359
3360         ret = replmd_update_rpmd(module, ac->schema, req, NULL,
3361                                  msg, &ac->seq_num, t, is_schema_nc,
3362                                  &is_urgent, &rodc);
3363         if (rodc && (ret == LDB_ERR_REFERRAL)) {
3364                 ret = send_rodc_referral(req, ldb, msg->dn);
3365                 talloc_free(ac);
3366                 return ret;
3367
3368         }
3369
3370         if (ret != LDB_SUCCESS) {
3371                 talloc_free(ac);
3372                 return ret;
3373         }
3374
3375         ret = replmd_modify_handle_linked_attribs(module, replmd_private,
3376                                                   msg, ac->seq_num, t, req);
3377         if (ret != LDB_SUCCESS) {
3378                 talloc_free(ac);
3379                 return ret;
3380         }
3381
3382         /* TODO:
3383          * - replace the old object with the newly constructed one
3384          */
3385
3386         ac->is_urgent = is_urgent;
3387
3388         ret = ldb_build_mod_req(&down_req, ldb, ac,
3389                                 msg,
3390                                 req->controls,
3391                                 ac, replmd_op_callback,
3392                                 req);
3393         LDB_REQ_SET_LOCATION(down_req);
3394         if (ret != LDB_SUCCESS) {
3395                 talloc_free(ac);
3396                 return ret;
3397         }
3398
3399         /* current partition control is needed by "replmd_op_callback" */
3400         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3401                 ret = ldb_request_add_control(down_req,
3402                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
3403                                               false, NULL);
3404                 if (ret != LDB_SUCCESS) {
3405                         talloc_free(ac);
3406                         return ret;
3407                 }
3408         }
3409
3410         /* If we are in functional level 2000, then
3411          * replmd_modify_handle_linked_attribs will have done
3412          * nothing */
3413         if (functional_level == DS_DOMAIN_FUNCTION_2000) {
3414                 ret = ldb_request_add_control(down_req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
3415                 if (ret != LDB_SUCCESS) {
3416                         talloc_free(ac);
3417                         return ret;
3418                 }
3419         }
3420
3421         talloc_steal(down_req, msg);
3422
3423         /* we only change whenChanged and uSNChanged if the seq_num
3424            has changed */
3425         if (ac->seq_num != 0) {
3426                 ret = add_time_element(msg, "whenChanged", t);
3427                 if (ret != LDB_SUCCESS) {
3428                         talloc_free(ac);
3429                         ldb_operr(ldb);
3430                         return ret;
3431                 }
3432
3433                 ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3434                 if (ret != LDB_SUCCESS) {
3435                         talloc_free(ac);
3436                         ldb_operr(ldb);
3437                         return ret;
3438                 }
3439         }
3440
3441         /* go on with the call chain */
3442         return ldb_next_request(module, down_req);
3443 }
3444
3445 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares);
3446
3447 /*
3448   handle a rename request
3449
3450   On a rename we need to do an extra ldb_modify which sets the
3451   whenChanged and uSNChanged attributes.  We do this in a callback after the success.
3452  */
3453 static int replmd_rename(struct ldb_module *module, struct ldb_request *req)
3454 {
3455         struct ldb_context *ldb;
3456         struct replmd_replicated_request *ac;
3457         int ret;
3458         struct ldb_request *down_req;
3459
3460         /* do not manipulate our control entries */
3461         if (ldb_dn_is_special(req->op.mod.message->dn)) {
3462                 return ldb_next_request(module, req);
3463         }
3464
3465         ldb = ldb_module_get_ctx(module);
3466
3467         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_rename\n");
3468
3469         ac = replmd_ctx_init(module, req);
3470         if (ac == NULL) {
3471                 return ldb_module_oom(module);
3472         }
3473
3474         ret = ldb_build_rename_req(&down_req, ldb, ac,
3475                                    ac->req->op.rename.olddn,
3476                                    ac->req->op.rename.newdn,
3477                                    ac->req->controls,
3478                                    ac, replmd_rename_callback,
3479                                    ac->req);
3480         LDB_REQ_SET_LOCATION(down_req);
3481         if (ret != LDB_SUCCESS) {
3482                 talloc_free(ac);
3483                 return ret;
3484         }
3485
3486         /* go on with the call chain */
3487         return ldb_next_request(module, down_req);
3488 }
3489
3490 /* After the rename is compleated, update the whenchanged etc */
3491 static int replmd_rename_callback(struct ldb_request *req, struct ldb_reply *ares)
3492 {
3493         struct ldb_context *ldb;
3494         struct ldb_request *down_req;
3495         struct ldb_message *msg;
3496         const struct dsdb_attribute *rdn_attr;
3497         const char *rdn_name;
3498         const struct ldb_val *rdn_val;
3499         const char *attrs[5] = { NULL, };
3500         time_t t = time(NULL);
3501         int ret;
3502         bool is_urgent = false, rodc = false;
3503         bool is_schema_nc;
3504         struct replmd_replicated_request *ac =
3505                 talloc_get_type(req->context, struct replmd_replicated_request);
3506         struct replmd_private *replmd_private =
3507                 talloc_get_type(ldb_module_get_private(ac->module),
3508                                 struct replmd_private);
3509
3510         ldb = ldb_module_get_ctx(ac->module);
3511
3512         if (ares->error != LDB_SUCCESS) {
3513                 return ldb_module_done(ac->req, ares->controls,
3514                                         ares->response, ares->error);
3515         }
3516
3517         if (ares->type != LDB_REPLY_DONE) {
3518                 ldb_set_errstring(ldb,
3519                                   "invalid ldb_reply_type in callback");
3520                 talloc_free(ares);
3521                 return ldb_module_done(ac->req, NULL, NULL,
3522                                         LDB_ERR_OPERATIONS_ERROR);
3523         }
3524
3525         /* TODO:
3526          * - replace the old object with the newly constructed one
3527          */
3528
3529         msg = ldb_msg_new(ac);
3530         if (msg == NULL) {
3531                 ldb_oom(ldb);
3532                 return LDB_ERR_OPERATIONS_ERROR;
3533         }
3534
3535         msg->dn = ac->req->op.rename.newdn;
3536
3537         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
3538
3539         rdn_name = ldb_dn_get_rdn_name(msg->dn);
3540         if (rdn_name == NULL) {
3541                 talloc_free(ares);
3542                 return ldb_module_done(ac->req, NULL, NULL,
3543                                        ldb_operr(ldb));
3544         }
3545
3546         /* normalize the rdn attribute name */
3547         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ac->schema, rdn_name);
3548         if (rdn_attr == NULL) {
3549                 talloc_free(ares);
3550                 return ldb_module_done(ac->req, NULL, NULL,
3551                                        ldb_operr(ldb));
3552         }
3553         rdn_name = rdn_attr->lDAPDisplayName;
3554
3555         rdn_val = ldb_dn_get_rdn_val(msg->dn);
3556         if (rdn_val == NULL) {
3557                 talloc_free(ares);
3558                 return ldb_module_done(ac->req, NULL, NULL,
3559                                        ldb_operr(ldb));
3560         }
3561
3562         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3563                 talloc_free(ares);
3564                 return ldb_module_done(ac->req, NULL, NULL,
3565                                        ldb_oom(ldb));
3566         }
3567         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
3568                 talloc_free(ares);
3569                 return ldb_module_done(ac->req, NULL, NULL,
3570                                        ldb_oom(ldb));
3571         }
3572         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
3573                 talloc_free(ares);
3574                 return ldb_module_done(ac->req, NULL, NULL,
3575                                        ldb_oom(ldb));
3576         }
3577         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
3578                 talloc_free(ares);
3579                 return ldb_module_done(ac->req, NULL, NULL,
3580                                        ldb_oom(ldb));
3581         }
3582
3583         /*
3584          * here we let replmd_update_rpmd() only search for
3585          * the existing "replPropertyMetaData" and rdn_name attributes.
3586          *
3587          * We do not want the existing "name" attribute as
3588          * the "name" attribute needs to get the version
3589          * updated on rename even if the rdn value hasn't changed.
3590          *
3591          * This is the diff of the meta data, for a moved user
3592          * on a w2k8r2 server:
3593          *
3594          * # record 1
3595          * -dn: CN=sdf df,CN=Users,DC=bla,DC=base
3596          * +dn: CN=sdf df,OU=TestOU,DC=bla,DC=base
3597          *  replPropertyMetaData:     NDR: struct replPropertyMetaDataBlob
3598          *         version                  : 0x00000001 (1)
3599          *         reserved                 : 0x00000000 (0)
3600          * @@ -66,11 +66,11 @@ replPropertyMetaData:     NDR: struct re
3601          *                      local_usn                : 0x00000000000037a5 (14245)
3602          *                 array: struct replPropertyMetaData1
3603          *                      attid                    : DRSUAPI_ATTID_name (0x90001)
3604          * -                    version                  : 0x00000001 (1)
3605          * -                    originating_change_time  : Wed Feb  9 17:20:49 2011 CET
3606          * +                    version                  : 0x00000002 (2)
3607          * +                    originating_change_time  : Wed Apr  6 15:21:01 2011 CEST
3608          *                      originating_invocation_id: 0d36ca05-5507-4e62-aca3-354bab0d39e1
3609          * -                    originating_usn          : 0x00000000000037a5 (14245)
3610          * -                    local_usn                : 0x00000000000037a5 (14245)
3611          * +                    originating_usn          : 0x0000000000003834 (14388)
3612          * +                    local_usn                : 0x0000000000003834 (14388)
3613          *                 array: struct replPropertyMetaData1
3614          *                      attid                    : DRSUAPI_ATTID_userAccountControl (0x90008)
3615          *                      version                  : 0x00000004 (4)
3616          */
3617         attrs[0] = "replPropertyMetaData";
3618         attrs[1] = "objectClass";
3619         attrs[2] = "instanceType";
3620         attrs[3] = rdn_name;
3621         attrs[4] = NULL;
3622
3623         ret = replmd_update_rpmd(ac->module, ac->schema, req, attrs,
3624                                  msg, &ac->seq_num, t,
3625                                  is_schema_nc, &is_urgent, &rodc);
3626         if (rodc && (ret == LDB_ERR_REFERRAL)) {
3627                 ret = send_rodc_referral(req, ldb, ac->req->op.rename.olddn);
3628                 talloc_free(ares);
3629                 return ldb_module_done(req, NULL, NULL, ret);
3630         }
3631
3632         if (ret != LDB_SUCCESS) {
3633                 talloc_free(ares);
3634                 return ldb_module_done(ac->req, NULL, NULL, ret);
3635         }
3636
3637         if (ac->seq_num == 0) {
3638                 talloc_free(ares);
3639                 return ldb_module_done(ac->req, NULL, NULL,
3640                                        ldb_error(ldb, ret,
3641                                         "internal error seq_num == 0"));
3642         }
3643         ac->is_urgent = is_urgent;
3644
3645         ret = ldb_build_mod_req(&down_req, ldb, ac,
3646                                 msg,
3647                                 req->controls,
3648                                 ac, replmd_op_callback,
3649                                 req);
3650         LDB_REQ_SET_LOCATION(down_req);
3651         if (ret != LDB_SUCCESS) {
3652                 talloc_free(ac);
3653                 return ret;
3654         }
3655
3656         /* current partition control is needed by "replmd_op_callback" */
3657         if (ldb_request_get_control(req, DSDB_CONTROL_CURRENT_PARTITION_OID) == NULL) {
3658                 ret = ldb_request_add_control(down_req,
3659                                               DSDB_CONTROL_CURRENT_PARTITION_OID,
3660                                               false, NULL);
3661                 if (ret != LDB_SUCCESS) {
3662                         talloc_free(ac);
3663                         return ret;
3664                 }
3665         }
3666
3667         talloc_steal(down_req, msg);
3668
3669         ret = add_time_element(msg, "whenChanged", t);
3670         if (ret != LDB_SUCCESS) {
3671                 talloc_free(ac);
3672                 ldb_operr(ldb);
3673                 return ret;
3674         }
3675
3676         ret = add_uint64_element(ldb, msg, "uSNChanged", ac->seq_num);
3677         if (ret != LDB_SUCCESS) {
3678                 talloc_free(ac);
3679                 ldb_operr(ldb);
3680                 return ret;
3681         }
3682
3683         /* go on with the call chain - do the modify after the rename */
3684         return ldb_next_request(ac->module, down_req);
3685 }
3686
3687 /*
3688  * remove links from objects that point at this object when an object
3689  * is deleted.  We remove it from the NEXT module per MS-DRSR 5.160
3690  * RemoveObj which states that link removal due to the object being
3691  * deleted is NOT an originating update - they just go away!
3692  *
3693  */
3694 static int replmd_delete_remove_link(struct ldb_module *module,
3695                                      const struct dsdb_schema *schema,
3696                                      struct replmd_private *replmd_private,
3697                                      struct ldb_dn *dn,
3698                                      struct GUID *guid,
3699                                      struct ldb_message_element *el,
3700                                      const struct dsdb_attribute *sa,
3701                                      struct ldb_request *parent)
3702 {
3703         unsigned int i;
3704         TALLOC_CTX *tmp_ctx = talloc_new(module);
3705         struct ldb_context *ldb = ldb_module_get_ctx(module);
3706
3707         for (i=0; i<el->num_values; i++) {
3708                 struct dsdb_dn *dsdb_dn;
3709                 int ret;
3710                 struct ldb_message *msg;
3711                 const struct dsdb_attribute *target_attr;
3712                 struct ldb_message_element *el2;
3713                 const char *dn_str;
3714                 struct ldb_val dn_val;
3715                 uint32_t dsdb_flags = 0;
3716                 const char *attrs[] = { NULL, NULL };
3717                 struct ldb_result *link_res;
3718                 struct ldb_message *link_msg;
3719                 struct ldb_message_element *link_el;
3720                 struct parsed_dn *link_dns;
3721                 struct parsed_dn *p = NULL, *unused = NULL;
3722
3723                 if (dsdb_dn_is_deleted_val(&el->values[i])) {
3724                         continue;
3725                 }
3726
3727                 dsdb_dn = dsdb_dn_parse(tmp_ctx, ldb, &el->values[i], sa->syntax->ldap_oid);
3728                 if (!dsdb_dn) {
3729                         talloc_free(tmp_ctx);
3730                         return LDB_ERR_OPERATIONS_ERROR;
3731                 }
3732
3733                 /* remove the link */
3734                 msg = ldb_msg_new(tmp_ctx);
3735                 if (!msg) {
3736                         ldb_module_oom(module);
3737                         talloc_free(tmp_ctx);
3738                         return LDB_ERR_OPERATIONS_ERROR;
3739                 }
3740
3741
3742                 msg->dn = dsdb_dn->dn;
3743
3744                 target_attr = dsdb_attribute_by_linkID(schema, sa->linkID ^ 1);
3745                 if (target_attr == NULL) {
3746                         continue;
3747                 }
3748                 attrs[0] = target_attr->lDAPDisplayName;
3749
3750                 ret = ldb_msg_add_empty(msg, target_attr->lDAPDisplayName,
3751                                         LDB_FLAG_MOD_DELETE, &el2);
3752                 if (ret != LDB_SUCCESS) {
3753                         ldb_module_oom(module);
3754                         talloc_free(tmp_ctx);
3755                         return LDB_ERR_OPERATIONS_ERROR;
3756                 }
3757
3758                 ret = dsdb_module_search_dn(module, tmp_ctx, &link_res,
3759                                             msg->dn, attrs,
3760                                             DSDB_FLAG_NEXT_MODULE |
3761                                             DSDB_SEARCH_SHOW_EXTENDED_DN,
3762                                             parent);
3763
3764                 if (ret != LDB_SUCCESS) {
3765                         talloc_free(tmp_ctx);
3766                         return ret;
3767                 }
3768
3769                 link_msg = link_res->msgs[0];
3770                 link_el = ldb_msg_find_element(link_msg,
3771                                                target_attr->lDAPDisplayName);
3772                 if (link_el == NULL) {
3773                         talloc_free(tmp_ctx);
3774                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
3775                 }
3776
3777                 /*
3778                  * This call 'upgrades' the links in link_dns, but we
3779                  * do not commit the result back into the database, so
3780                  * this is safe to call in FL2000 or on databases that
3781                  * have been run at that level in the past.
3782                  */
3783                 ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx,
3784                                              link_el, &link_dns,
3785                                              target_attr->syntax->ldap_oid, parent);
3786                 if (ret != LDB_SUCCESS) {
3787                         talloc_free(tmp_ctx);
3788                         return ret;
3789                 }
3790
3791                 ret = parsed_dn_find(ldb, link_dns, link_el->num_values,
3792                                      guid, dn,
3793                                      data_blob_null, 0,
3794                                      &p, &unused,
3795                                      target_attr->syntax->ldap_oid, false);
3796                 if (ret != LDB_SUCCESS) {
3797                         talloc_free(tmp_ctx);
3798                         return ret;
3799                 }
3800
3801                 if (p == NULL) {
3802                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
3803                                                "Failed to find forward link on %s "
3804                                                "as %s to remove backlink %s on %s",
3805                                                ldb_dn_get_linearized(msg->dn),
3806                                                target_attr->lDAPDisplayName,
3807                                                sa->lDAPDisplayName,
3808                                                ldb_dn_get_linearized(dn));
3809                         talloc_free(tmp_ctx);
3810                         return LDB_ERR_NO_SUCH_ATTRIBUTE;
3811                 }
3812
3813
3814                 /* This needs to get the Binary DN, by first searching */
3815                 dn_str = dsdb_dn_get_linearized(tmp_ctx,
3816                                                 p->dsdb_dn);
3817
3818                 dn_val = data_blob_string_const(dn_str);
3819                 el2->values = &dn_val;
3820                 el2->num_values = 1;
3821
3822                 /*
3823                  * Ensure that we tell the modification to vanish any linked
3824                  * attributes (not simply mark them as isDeleted = TRUE)
3825                  */
3826                 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
3827
3828                 ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, parent);
3829                 if (ret != LDB_SUCCESS) {
3830                         talloc_free(tmp_ctx);
3831                         return ret;
3832                 }
3833         }
3834         talloc_free(tmp_ctx);
3835         return LDB_SUCCESS;
3836 }
3837
3838
3839 /*
3840   handle update of replication meta data for deletion of objects
3841
3842   This also handles the mapping of delete to a rename operation
3843   to allow deletes to be replicated.
3844
3845   It also handles the incoming deleted objects, to ensure they are
3846   fully deleted here.  In that case re_delete is true, and we do not
3847   use this as a signal to change the deleted state, just reinforce it.
3848
3849  */
3850 static int replmd_delete_internals(struct ldb_module *module, struct ldb_request *req, bool re_delete)
3851 {
3852         int ret = LDB_ERR_OTHER;
3853         bool retb, disallow_move_on_delete;
3854         struct ldb_dn *old_dn = NULL, *new_dn = NULL;
3855         const char *rdn_name;
3856         const struct ldb_val *rdn_value, *new_rdn_value;
3857         struct GUID guid;
3858         struct ldb_context *ldb = ldb_module_get_ctx(module);
3859         const struct dsdb_schema *schema;
3860         struct ldb_message *msg, *old_msg;
3861         struct ldb_message_element *el;
3862         TALLOC_CTX *tmp_ctx;
3863         struct ldb_result *res, *parent_res;
3864         static const char * const preserved_attrs[] = {
3865                 /* yes, this really is a hard coded list. See MS-ADTS
3866                    section 3.1.1.5.5.1.1 */
3867                 "attributeID",
3868                 "attributeSyntax",
3869                 "dNReferenceUpdate",
3870                 "dNSHostName",
3871                 "flatName",
3872                 "governsID",
3873                 "groupType",
3874                 "instanceType",
3875                 "lDAPDisplayName",
3876                 "legacyExchangeDN",
3877                 "isDeleted",
3878                 "isRecycled",
3879                 "lastKnownParent",
3880                 "msDS-LastKnownRDN",
3881                 "msDS-PortLDAP",
3882                 "mS-DS-CreatorSID",
3883                 "mSMQOwnerID",
3884                 "nCName",
3885                 "objectClass",
3886                 "distinguishedName",
3887                 "objectGUID",
3888                 "objectSid",
3889                 "oMSyntax",
3890                 "proxiedObjectName",
3891                 "name",
3892                 "nTSecurityDescriptor",
3893                 "replPropertyMetaData",
3894                 "sAMAccountName",
3895                 "securityIdentifier",
3896                 "sIDHistory",
3897                 "subClassOf",
3898                 "systemFlags",
3899                 "trustPartner",
3900                 "trustDirection",
3901                 "trustType",
3902                 "trustAttributes",
3903                 "userAccountControl",
3904                 "uSNChanged",
3905                 "uSNCreated",
3906                 "whenCreated",
3907                 "whenChanged",
3908                 NULL
3909         };
3910         static const char * const all_attrs[] = {
3911                 DSDB_SECRET_ATTRIBUTES,
3912                 "*",
3913                 NULL
3914         };
3915         unsigned int i, el_count = 0;
3916         uint32_t dsdb_flags = 0;
3917         struct replmd_private *replmd_private;
3918         enum deletion_state deletion_state, next_deletion_state;
3919
3920         if (ldb_dn_is_special(req->op.del.dn)) {
3921                 return ldb_next_request(module, req);
3922         }
3923
3924         /*
3925          * We have to allow dbcheck to remove an object that
3926          * is beyond repair, and to do so totally.  This could
3927          * mean we we can get a partial object from the other
3928          * DC, causing havoc, so dbcheck suggests
3929          * re-replication first.  dbcheck sets both DBCHECK
3930          * and RELAX in this situation.
3931          */
3932         if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)
3933             && ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
3934                 /* really, really remove it */
3935                 return ldb_next_request(module, req);
3936         }
3937
3938         tmp_ctx = talloc_new(ldb);
3939         if (!tmp_ctx) {
3940                 ldb_oom(ldb);
3941                 return LDB_ERR_OPERATIONS_ERROR;
3942         }
3943
3944         schema = dsdb_get_schema(ldb, tmp_ctx);
3945         if (!schema) {
3946                 talloc_free(tmp_ctx);
3947                 return LDB_ERR_OPERATIONS_ERROR;
3948         }
3949
3950         old_dn = ldb_dn_copy(tmp_ctx, req->op.del.dn);
3951
3952         /* we need the complete msg off disk, so we can work out which
3953            attributes need to be removed */
3954         ret = dsdb_module_search_dn(module, tmp_ctx, &res, old_dn, all_attrs,
3955                                     DSDB_FLAG_NEXT_MODULE |
3956                                     DSDB_SEARCH_SHOW_RECYCLED |
3957                                     DSDB_SEARCH_REVEAL_INTERNALS |
3958                                     DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT, req);
3959         if (ret != LDB_SUCCESS) {
3960                 ldb_asprintf_errstring(ldb_module_get_ctx(module),
3961                                        "repmd_delete: Failed to %s %s, because we failed to find it: %s",
3962                                        re_delete ? "re-delete" : "delete",
3963                                        ldb_dn_get_linearized(old_dn),
3964                                        ldb_errstring(ldb_module_get_ctx(module)));
3965                 talloc_free(tmp_ctx);
3966                 return ret;
3967         }
3968         old_msg = res->msgs[0];
3969
3970         replmd_deletion_state(module, old_msg,
3971                               &deletion_state,
3972                               &next_deletion_state);
3973
3974         /* This supports us noticing an incoming isDeleted and acting on it */
3975         if (re_delete) {
3976                 SMB_ASSERT(deletion_state > OBJECT_NOT_DELETED);
3977                 next_deletion_state = deletion_state;
3978         }
3979
3980         if (next_deletion_state == OBJECT_REMOVED) {
3981                 /*
3982                  * We have to prevent objects being deleted, even if
3983                  * the administrator really wants them gone, as
3984                  * without the tombstone, we can get a partial object
3985                  * from the other DC, causing havoc.
3986                  *
3987                  * The only other valid case is when the 180 day
3988                  * timeout has expired, when relax is specified.
3989                  */
3990                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID)) {
3991                         /* it is already deleted - really remove it this time */
3992                         talloc_free(tmp_ctx);
3993                         return ldb_next_request(module, req);
3994                 }
3995
3996                 ldb_asprintf_errstring(ldb, "Refusing to delete tombstone object %s.  "
3997                                        "This check is to prevent corruption of the replicated state.",
3998                                        ldb_dn_get_linearized(old_msg->dn));
3999                 return LDB_ERR_UNWILLING_TO_PERFORM;
4000         }
4001
4002         rdn_name = ldb_dn_get_rdn_name(old_dn);
4003         rdn_value = ldb_dn_get_rdn_val(old_dn);
4004         if ((rdn_name == NULL) || (rdn_value == NULL)) {
4005                 talloc_free(tmp_ctx);
4006                 return ldb_operr(ldb);
4007         }
4008
4009         msg = ldb_msg_new(tmp_ctx);
4010         if (msg == NULL) {
4011                 ldb_module_oom(module);
4012                 talloc_free(tmp_ctx);
4013                 return LDB_ERR_OPERATIONS_ERROR;
4014         }
4015
4016         msg->dn = old_dn;
4017
4018         /* consider the SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE flag */
4019         disallow_move_on_delete =
4020                 (ldb_msg_find_attr_as_int(old_msg, "systemFlags", 0)
4021                  & SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE);
4022
4023         /* work out where we will be renaming this object to */
4024         if (!disallow_move_on_delete) {
4025                 struct ldb_dn *deleted_objects_dn;
4026                 ret = dsdb_get_deleted_objects_dn(ldb, tmp_ctx, old_dn,
4027                                                   &deleted_objects_dn);
4028
4029                 /*
4030                  * We should not move objects if we can't find the
4031                  * deleted objects DN.  Not moving (or otherwise
4032                  * harming) the Deleted Objects DN itself is handled
4033                  * in the caller.
4034                  */
4035                 if (re_delete && (ret != LDB_SUCCESS)) {
4036                         new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4037                         if (new_dn == NULL) {
4038                                 ldb_module_oom(module);
4039                                 talloc_free(tmp_ctx);
4040                                 return LDB_ERR_OPERATIONS_ERROR;
4041                         }
4042                 } else if (ret != LDB_SUCCESS) {
4043                         /* this is probably an attempted delete on a partition
4044                          * that doesn't allow delete operations, such as the
4045                          * schema partition */
4046                         ldb_asprintf_errstring(ldb, "No Deleted Objects container for DN %s",
4047                                                ldb_dn_get_linearized(old_dn));
4048                         talloc_free(tmp_ctx);
4049                         return LDB_ERR_UNWILLING_TO_PERFORM;
4050                 } else {
4051                         new_dn = deleted_objects_dn;
4052                 }
4053         } else {
4054                 new_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4055                 if (new_dn == NULL) {
4056                         ldb_module_oom(module);
4057                         talloc_free(tmp_ctx);
4058                         return LDB_ERR_OPERATIONS_ERROR;
4059                 }
4060         }
4061
4062         /* get the objects GUID from the search we just did */
4063         guid = samdb_result_guid(old_msg, "objectGUID");
4064
4065         if (deletion_state == OBJECT_NOT_DELETED) {
4066
4067                 ret = replmd_make_deleted_child_dn(tmp_ctx,
4068                                                    ldb,
4069                                                    new_dn,
4070                                                    rdn_name, rdn_value,
4071                                                    guid);
4072
4073                 if (ret != LDB_SUCCESS) {
4074                         talloc_free(tmp_ctx);
4075                         return ret;
4076                 }
4077
4078                 ret = ldb_msg_add_string(msg, "isDeleted", "TRUE");
4079                 if (ret != LDB_SUCCESS) {
4080                         ldb_asprintf_errstring(ldb, __location__
4081                                                ": Failed to add isDeleted string to the msg");
4082                         talloc_free(tmp_ctx);
4083                         return ret;
4084                 }
4085                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4086         } else {
4087                 /*
4088                  * No matter what has happened with other renames etc, try again to
4089                  * get this to be under the deleted DN. See MS-DRSR 5.160 RemoveObj
4090                  */
4091
4092                 struct ldb_dn *rdn = ldb_dn_copy(tmp_ctx, old_dn);
4093                 retb = ldb_dn_remove_base_components(rdn, ldb_dn_get_comp_num(rdn) - 1);
4094                 if (!retb) {
4095                         ldb_asprintf_errstring(ldb, __location__
4096                                                ": Unable to add a prepare rdn of %s",
4097                                                ldb_dn_get_linearized(rdn));
4098                         talloc_free(tmp_ctx);
4099                         return LDB_ERR_OPERATIONS_ERROR;
4100                 }
4101                 SMB_ASSERT(ldb_dn_get_comp_num(rdn) == 1);
4102
4103                 retb = ldb_dn_add_child(new_dn, rdn);
4104                 if (!retb) {
4105                         ldb_asprintf_errstring(ldb, __location__
4106                                                ": Unable to add rdn %s to base dn: %s",
4107                                                ldb_dn_get_linearized(rdn),
4108                                                ldb_dn_get_linearized(new_dn));
4109                         talloc_free(tmp_ctx);
4110                         return LDB_ERR_OPERATIONS_ERROR;
4111                 }
4112         }
4113
4114         /*
4115           now we need to modify the object in the following ways:
4116
4117           - add isDeleted=TRUE
4118           - update rDN and name, with new rDN
4119           - remove linked attributes
4120           - remove objectCategory and sAMAccountType
4121           - remove attribs not on the preserved list
4122              - preserved if in above list, or is rDN
4123           - remove all linked attribs from this object
4124           - remove all links from other objects to this object
4125           - add lastKnownParent
4126           - update replPropertyMetaData?
4127
4128           see MS-ADTS "Tombstone Requirements" section 3.1.1.5.5.1.1
4129          */
4130
4131         if (deletion_state == OBJECT_NOT_DELETED) {
4132                 struct ldb_dn *parent_dn = ldb_dn_get_parent(tmp_ctx, old_dn);
4133                 char *parent_dn_str = NULL;
4134
4135                 /* we need the storage form of the parent GUID */
4136                 ret = dsdb_module_search_dn(module, tmp_ctx, &parent_res,
4137                                             parent_dn, NULL,
4138                                             DSDB_FLAG_NEXT_MODULE |
4139                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
4140                                             DSDB_SEARCH_REVEAL_INTERNALS|
4141                                             DSDB_SEARCH_SHOW_RECYCLED, req);
4142                 if (ret != LDB_SUCCESS) {
4143                         ldb_asprintf_errstring(ldb_module_get_ctx(module),
4144                                                "repmd_delete: Failed to %s %s, "
4145                                                "because we failed to find it's parent (%s): %s",
4146                                                re_delete ? "re-delete" : "delete",
4147                                                ldb_dn_get_linearized(old_dn),
4148                                                ldb_dn_get_linearized(parent_dn),
4149                                                ldb_errstring(ldb_module_get_ctx(module)));
4150                         talloc_free(tmp_ctx);
4151                         return ret;
4152                 }
4153
4154                 /*
4155                  * Now we can use the DB version,
4156                  * it will have the extended DN info in it
4157                  */
4158                 parent_dn = parent_res->msgs[0]->dn;
4159                 parent_dn_str = ldb_dn_get_extended_linearized(tmp_ctx,
4160                                                                parent_dn,
4161                                                                1);
4162                 if (parent_dn_str == NULL) {
4163                         talloc_free(tmp_ctx);
4164                         return ldb_module_oom(module);
4165                 }
4166
4167                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4168                                                parent_dn_str);
4169                 if (ret != LDB_SUCCESS) {
4170                         ldb_asprintf_errstring(ldb, __location__
4171                                                ": Failed to add lastKnownParent "
4172                                                "string when deleting %s",
4173                                                ldb_dn_get_linearized(old_dn));
4174                         talloc_free(tmp_ctx);
4175                         return ret;
4176                 }
4177                 msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4178
4179                 if (next_deletion_state == OBJECT_DELETED) {
4180                         ret = ldb_msg_add_value(msg, "msDS-LastKnownRDN", rdn_value, NULL);
4181                         if (ret != LDB_SUCCESS) {
4182                                 ldb_asprintf_errstring(ldb, __location__
4183                                                        ": Failed to add msDS-LastKnownRDN "
4184                                                        "string when deleting %s",
4185                                                        ldb_dn_get_linearized(old_dn));
4186                                 talloc_free(tmp_ctx);
4187                                 return ret;
4188                         }
4189                         msg->elements[el_count++].flags = LDB_FLAG_MOD_ADD;
4190                 }
4191         }
4192
4193         switch (next_deletion_state) {
4194
4195         case OBJECT_RECYCLED:
4196         case OBJECT_TOMBSTONE:
4197
4198                 /*
4199                  * MS-ADTS 3.1.1.5.5.1.1 Tombstone Requirements
4200                  * describes what must be removed from a tombstone
4201                  * object
4202                  *
4203                  * MS-ADTS 3.1.1.5.5.1.3 Recycled-Object Requirements
4204                  * describes what must be removed from a recycled
4205                  * object
4206                  *
4207                  */
4208
4209                 /*
4210                  * we also mark it as recycled, meaning this object can't be
4211                  * recovered (we are stripping its attributes).
4212                  * This is done only if we have this schema object of course ...
4213                  * This behavior is identical to the one of Windows 2008R2 which
4214                  * always set the isRecycled attribute, even if the recycle-bin is
4215                  * not activated and what ever the forest level is.
4216                  */
4217                 if (dsdb_attribute_by_lDAPDisplayName(schema, "isRecycled") != NULL) {
4218                         ret = ldb_msg_add_string(msg, "isRecycled", "TRUE");
4219                         if (ret != LDB_SUCCESS) {
4220                                 DEBUG(0,(__location__ ": Failed to add isRecycled string to the msg\n"));
4221                                 ldb_module_oom(module);
4222                                 talloc_free(tmp_ctx);
4223                                 return ret;
4224                         }
4225                         msg->elements[el_count++].flags = LDB_FLAG_MOD_REPLACE;
4226                 }
4227
4228                 replmd_private = talloc_get_type(ldb_module_get_private(module),
4229                                                  struct replmd_private);
4230                 /* work out which of the old attributes we will be removing */
4231                 for (i=0; i<old_msg->num_elements; i++) {
4232                         const struct dsdb_attribute *sa;
4233                         el = &old_msg->elements[i];
4234                         sa = dsdb_attribute_by_lDAPDisplayName(schema, el->name);
4235                         if (!sa) {
4236                                 talloc_free(tmp_ctx);
4237                                 return LDB_ERR_OPERATIONS_ERROR;
4238                         }
4239                         if (ldb_attr_cmp(el->name, rdn_name) == 0) {
4240                                 /* don't remove the rDN */
4241                                 continue;
4242                         }
4243                         if (sa->linkID & 1) {
4244                                 /*
4245                                   we have a backlink in this object
4246                                   that needs to be removed. We're not
4247                                   allowed to remove it directly
4248                                   however, so we instead setup a
4249                                   modify to delete the corresponding
4250                                   forward link
4251                                  */
4252                                 ret = replmd_delete_remove_link(module, schema,
4253                                                                 replmd_private,
4254                                                                 old_dn, &guid,
4255                                                                 el, sa, req);
4256                                 if (ret != LDB_SUCCESS) {
4257                                         const char *old_dn_str
4258                                                 = ldb_dn_get_linearized(old_dn);
4259                                         ldb_asprintf_errstring(ldb,
4260                                                                __location__
4261                                                                ": Failed to remove backlink of "
4262                                                                "%s when deleting %s: %s",
4263                                                                el->name,
4264                                                                old_dn_str,
4265                                                                ldb_errstring(ldb));
4266                                         talloc_free(tmp_ctx);
4267                                         return LDB_ERR_OPERATIONS_ERROR;
4268                                 }
4269                                 /* now we continue, which means we
4270                                    won't remove this backlink
4271                                    directly
4272                                 */
4273                                 continue;
4274                         } else if (sa->linkID == 0) {
4275                                 if (ldb_attr_in_list(preserved_attrs, el->name)) {
4276                                         continue;
4277                                 }
4278                                 if (sa->searchFlags & SEARCH_FLAG_PRESERVEONDELETE) {
4279                                         continue;
4280                                 }
4281                         } else {
4282                                 /*
4283                                  * Ensure that we tell the modification to vanish any linked
4284                                  * attributes (not simply mark them as isDeleted = TRUE)
4285                                  */
4286                                 dsdb_flags |= DSDB_REPLMD_VANISH_LINKS;
4287                         }
4288                         ret = ldb_msg_add_empty(msg, el->name, LDB_FLAG_MOD_DELETE, &el);
4289                         if (ret != LDB_SUCCESS) {
4290                                 talloc_free(tmp_ctx);
4291                                 ldb_module_oom(module);
4292                                 return ret;
4293                         }
4294                 }
4295
4296                 break;
4297
4298         case OBJECT_DELETED:
4299                 /*
4300                  * MS-ADTS 3.1.1.5.5.1.2 Deleted-Object Requirements
4301                  * describes what must be removed from a deleted
4302                  * object
4303                  */
4304
4305                 ret = ldb_msg_add_empty(msg, "objectCategory", LDB_FLAG_MOD_REPLACE, NULL);
4306                 if (ret != LDB_SUCCESS) {
4307                         talloc_free(tmp_ctx);
4308                         ldb_module_oom(module);
4309                         return ret;
4310                 }
4311
4312                 ret = ldb_msg_add_empty(msg, "sAMAccountType", LDB_FLAG_MOD_REPLACE, NULL);
4313                 if (ret != LDB_SUCCESS) {
4314                         talloc_free(tmp_ctx);
4315                         ldb_module_oom(module);
4316                         return ret;
4317                 }
4318
4319                 break;
4320
4321         default:
4322                 break;
4323         }
4324
4325         if (deletion_state == OBJECT_NOT_DELETED) {
4326                 const struct dsdb_attribute *sa;
4327
4328                 /* work out what the new rdn value is, for updating the
4329                    rDN and name fields */
4330                 new_rdn_value = ldb_dn_get_rdn_val(new_dn);
4331                 if (new_rdn_value == NULL) {
4332                         talloc_free(tmp_ctx);
4333                         return ldb_operr(ldb);
4334                 }
4335
4336                 sa = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
4337                 if (!sa) {
4338                         talloc_free(tmp_ctx);
4339                         return LDB_ERR_OPERATIONS_ERROR;
4340                 }
4341
4342                 ret = ldb_msg_add_value(msg, sa->lDAPDisplayName, new_rdn_value,
4343                                         &el);
4344                 if (ret != LDB_SUCCESS) {
4345                         talloc_free(tmp_ctx);
4346                         return ret;
4347                 }
4348                 el->flags = LDB_FLAG_MOD_REPLACE;
4349
4350                 el = ldb_msg_find_element(old_msg, "name");
4351                 if (el) {
4352                         ret = ldb_msg_add_value(msg, "name", new_rdn_value, &el);
4353                         if (ret != LDB_SUCCESS) {
4354                                 talloc_free(tmp_ctx);
4355                                 return ret;
4356                         }
4357                         el->flags = LDB_FLAG_MOD_REPLACE;
4358                 }
4359         }
4360
4361         /*
4362          * TODO: Per MS-DRSR 5.160 RemoveObj we should remove links directly, not as an originating update!
4363          *
4364          */
4365
4366         /*
4367          * No matter what has happned with other renames, try again to
4368          * get this to be under the deleted DN.
4369          */
4370         if (strcmp(ldb_dn_get_linearized(old_dn), ldb_dn_get_linearized(new_dn)) != 0) {
4371                 /* now rename onto the new DN */
4372                 ret = dsdb_module_rename(module, old_dn, new_dn, DSDB_FLAG_NEXT_MODULE, req);
4373                 if (ret != LDB_SUCCESS){
4374                         DEBUG(0,(__location__ ": Failed to rename object from '%s' to '%s' - %s\n",
4375                                  ldb_dn_get_linearized(old_dn),
4376                                  ldb_dn_get_linearized(new_dn),
4377                                  ldb_errstring(ldb)));
4378                         talloc_free(tmp_ctx);
4379                         return ret;
4380                 }
4381                 msg->dn = new_dn;
4382         }
4383
4384         ret = dsdb_module_modify(module, msg, dsdb_flags|DSDB_FLAG_OWN_MODULE, req);
4385         if (ret != LDB_SUCCESS) {
4386                 ldb_asprintf_errstring(ldb, "replmd_delete: Failed to modify object %s in delete - %s",
4387                                        ldb_dn_get_linearized(old_dn), ldb_errstring(ldb));
4388                 talloc_free(tmp_ctx);
4389                 return ret;
4390         }
4391
4392         talloc_free(tmp_ctx);
4393
4394         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
4395 }
4396
4397 static int replmd_delete(struct ldb_module *module, struct ldb_request *req)
4398 {
4399         return replmd_delete_internals(module, req, false);
4400 }
4401
4402
4403 static int replmd_replicated_request_error(struct replmd_replicated_request *ar, int ret)
4404 {
4405         return ret;
4406 }
4407
4408 static int replmd_replicated_request_werror(struct replmd_replicated_request *ar, WERROR status)
4409 {
4410         int ret = LDB_ERR_OTHER;
4411         /* TODO: do some error mapping */
4412
4413         /* Let the caller know the full WERROR */
4414         ar->objs->error = status;
4415
4416         return ret;
4417 }
4418
4419
4420 static struct replPropertyMetaData1 *
4421 replmd_replPropertyMetaData1_find_attid(struct replPropertyMetaDataBlob *md_blob,
4422                                         enum drsuapi_DsAttributeId attid)
4423 {
4424         uint32_t i;
4425         struct replPropertyMetaDataCtr1 *rpmd_ctr = &md_blob->ctr.ctr1;
4426
4427         for (i = 0; i < rpmd_ctr->count; i++) {
4428                 if (rpmd_ctr->array[i].attid == attid) {
4429                         return &rpmd_ctr->array[i];
4430                 }
4431         }
4432         return NULL;
4433 }
4434
4435
4436 /*
4437    return true if an update is newer than an existing entry
4438    see section 5.11 of MS-ADTS
4439 */
4440 static bool replmd_update_is_newer(const struct GUID *current_invocation_id,
4441                                    const struct GUID *update_invocation_id,
4442                                    uint32_t current_version,
4443                                    uint32_t update_version,
4444                                    NTTIME current_change_time,
4445                                    NTTIME update_change_time)
4446 {
4447         if (update_version != current_version) {
4448                 return update_version > current_version;
4449         }
4450         if (update_change_time != current_change_time) {
4451                 return update_change_time > current_change_time;
4452         }
4453         return GUID_compare(update_invocation_id, current_invocation_id) > 0;
4454 }
4455
4456 static bool replmd_replPropertyMetaData1_is_newer(struct replPropertyMetaData1 *cur_m,
4457                                                   struct replPropertyMetaData1 *new_m)
4458 {
4459         return replmd_update_is_newer(&cur_m->originating_invocation_id,
4460                                       &new_m->originating_invocation_id,
4461                                       cur_m->version,
4462                                       new_m->version,
4463                                       cur_m->originating_change_time,
4464                                       new_m->originating_change_time);
4465 }
4466
4467 static bool replmd_replPropertyMetaData1_new_should_be_taken(uint32_t dsdb_repl_flags,
4468                                                              struct replPropertyMetaData1 *cur_m,
4469                                                              struct replPropertyMetaData1 *new_m)
4470 {
4471         bool cmp;
4472
4473         /*
4474          * If the new replPropertyMetaData entry for this attribute is
4475          * not provided (this happens in the case where we look for
4476          * ATTID_name, but the name was not changed), then the local
4477          * state is clearly still current, as the remote
4478          * server didn't send it due to being older the high watermark
4479          * USN we sent.
4480          */
4481         if (new_m == NULL) {
4482                 return false;
4483         }
4484
4485         if (dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING) {
4486                 /*
4487                  * if we compare equal then do an
4488                  * update. This is used when a client
4489                  * asks for a FULL_SYNC, and can be
4490                  * used to recover a corrupt
4491                  * replica.
4492                  *
4493                  * This call is a bit tricky, what we
4494                  * are doing it turning the 'is_newer'
4495                  * call into a 'not is older' by
4496                  * swapping cur_m and new_m, and negating the
4497                  * outcome.
4498                  */
4499                 cmp = !replmd_replPropertyMetaData1_is_newer(new_m,
4500                                                              cur_m);
4501         } else {
4502                 cmp = replmd_replPropertyMetaData1_is_newer(cur_m,
4503                                                             new_m);
4504         }
4505         return cmp;
4506 }
4507
4508
4509 /*
4510   form a conflict DN
4511  */
4512 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx, struct ldb_dn *dn, struct GUID *guid)
4513 {
4514         const struct ldb_val *rdn_val;
4515         const char *rdn_name;
4516         struct ldb_dn *new_dn;
4517
4518         rdn_val = ldb_dn_get_rdn_val(dn);
4519         rdn_name = ldb_dn_get_rdn_name(dn);
4520         if (!rdn_val || !rdn_name) {
4521                 return NULL;
4522         }
4523
4524         new_dn = ldb_dn_copy(mem_ctx, dn);
4525         if (!new_dn) {
4526                 return NULL;
4527         }
4528
4529         if (!ldb_dn_remove_child_components(new_dn, 1)) {
4530                 return NULL;
4531         }
4532
4533         if (!ldb_dn_add_child_fmt(new_dn, "%s=%s\\0ACNF:%s",
4534                                   rdn_name,
4535                                   ldb_dn_escape_value(new_dn, *rdn_val),
4536                                   GUID_string(new_dn, guid))) {
4537                 return NULL;
4538         }
4539
4540         return new_dn;
4541 }
4542
4543 /*
4544   form a deleted DN
4545  */
4546 static int replmd_make_prefix_child_dn(TALLOC_CTX *tmp_ctx,
4547                                        struct ldb_context *ldb,
4548                                        struct ldb_dn *dn,
4549                                        const char *four_char_prefix,
4550                                        const char *rdn_name,
4551                                        const struct ldb_val *rdn_value,
4552                                        struct GUID guid)
4553 {
4554         struct ldb_val deleted_child_rdn_val;
4555         struct GUID_txt_buf guid_str;
4556         bool retb;
4557
4558         GUID_buf_string(&guid, &guid_str);
4559
4560         retb = ldb_dn_add_child_fmt(dn, "X=Y");
4561         if (!retb) {
4562                 ldb_asprintf_errstring(ldb, __location__
4563                                        ": Unable to add a formatted child to dn: %s",
4564                                        ldb_dn_get_linearized(dn));
4565                 return LDB_ERR_OPERATIONS_ERROR;
4566         }
4567
4568
4569         deleted_child_rdn_val = ldb_val_dup(tmp_ctx, rdn_value);
4570
4571         /*
4572          * sizeof(guid_str.buf) will always be longer than
4573          * strlen(guid_str.buf) but we allocate using this and
4574          * waste the trailing bytes to avoid scaring folks
4575          * with memcpy() using strlen() below
4576          */
4577
4578         deleted_child_rdn_val.data
4579                 = talloc_realloc(tmp_ctx, deleted_child_rdn_val.data,
4580                                  uint8_t,
4581                                  rdn_value->length + 5
4582                                  + sizeof(guid_str.buf));
4583         if (!deleted_child_rdn_val.data) {
4584                 ldb_asprintf_errstring(ldb, __location__
4585                                        ": Unable to add a formatted child to dn: %s",
4586                                        ldb_dn_get_linearized(dn));
4587                 return LDB_ERR_OPERATIONS_ERROR;
4588         }
4589
4590         deleted_child_rdn_val.length =
4591                 rdn_value->length + 5
4592                 + strlen(guid_str.buf);
4593
4594         SMB_ASSERT(deleted_child_rdn_val.length <
4595                    talloc_get_size(deleted_child_rdn_val.data));
4596
4597         /*
4598          * talloc won't allocate more than 256MB so we can't
4599          * overflow but just to be sure
4600          */
4601         if (deleted_child_rdn_val.length < rdn_value->length) {
4602                 return LDB_ERR_OPERATIONS_ERROR;
4603         }
4604
4605         deleted_child_rdn_val.data[rdn_value->length] = 0x0a;
4606         memcpy(&deleted_child_rdn_val.data[rdn_value->length + 1],
4607                four_char_prefix, 4);
4608         memcpy(&deleted_child_rdn_val.data[rdn_value->length + 5],
4609                guid_str.buf,
4610                sizeof(guid_str.buf));
4611
4612         /* Now set the value into the RDN, without parsing it */
4613         ldb_dn_set_component(dn, 0, rdn_name,
4614                              deleted_child_rdn_val);
4615
4616         return LDB_SUCCESS;
4617 }
4618
4619
4620 /*
4621   form a conflict DN
4622  */
4623 static struct ldb_dn *replmd_conflict_dn(TALLOC_CTX *mem_ctx,
4624                                          struct ldb_context *ldb,
4625                                          struct ldb_dn *dn,
4626                                          struct GUID *guid)
4627 {
4628         const struct ldb_val *rdn_val;
4629         const char *rdn_name;
4630         struct ldb_dn *new_dn;
4631         int ret;
4632
4633         rdn_val = ldb_dn_get_rdn_val(dn);
4634         rdn_name = ldb_dn_get_rdn_name(dn);
4635         if (!rdn_val || !rdn_name) {
4636                 return NULL;
4637         }
4638
4639         new_dn = ldb_dn_get_parent(mem_ctx, dn);
4640         if (!new_dn) {
4641                 return NULL;
4642         }
4643
4644         ret = replmd_make_prefix_child_dn(mem_ctx,
4645                                           ldb, new_dn,
4646                                           "CNF:",
4647                                           rdn_name,
4648                                           rdn_val,
4649                                           *guid);
4650         if (ret != LDB_SUCCESS) {
4651                 return NULL;
4652         }
4653         return new_dn;
4654 }
4655
4656 /*
4657   form a deleted DN
4658  */
4659 static int replmd_make_deleted_child_dn(TALLOC_CTX *tmp_ctx,
4660                                         struct ldb_context *ldb,
4661                                         struct ldb_dn *dn,
4662                                         const char *rdn_name,
4663                                         const struct ldb_val *rdn_value,
4664                                         struct GUID guid)
4665 {
4666         return replmd_make_prefix_child_dn(tmp_ctx,
4667                                            ldb, dn,
4668                                            "DEL:",
4669                                            rdn_name,
4670                                            rdn_value,
4671                                            guid);
4672 }
4673
4674
4675 /*
4676   perform a modify operation which sets the rDN and name attributes to
4677   their current values. This has the effect of changing these
4678   attributes to have been last updated by the current DC. This is
4679   needed to ensure that renames performed as part of conflict
4680   resolution are propogated to other DCs
4681  */
4682 static int replmd_name_modify(struct replmd_replicated_request *ar,
4683                               struct ldb_request *req, struct ldb_dn *dn)
4684 {
4685         struct ldb_message *msg;
4686         const char *rdn_name;
4687         const struct ldb_val *rdn_val;
4688         const struct dsdb_attribute *rdn_attr;
4689         int ret;
4690
4691         msg = ldb_msg_new(req);
4692         if (msg == NULL) {
4693                 goto failed;
4694         }
4695         msg->dn = dn;
4696
4697         rdn_name = ldb_dn_get_rdn_name(dn);
4698         if (rdn_name == NULL) {
4699                 goto failed;
4700         }
4701
4702         /* normalize the rdn attribute name */
4703         rdn_attr = dsdb_attribute_by_lDAPDisplayName(ar->schema, rdn_name);
4704         if (rdn_attr == NULL) {
4705                 goto failed;
4706         }
4707         rdn_name = rdn_attr->lDAPDisplayName;
4708
4709         rdn_val = ldb_dn_get_rdn_val(dn);
4710         if (rdn_val == NULL) {
4711                 goto failed;
4712         }
4713
4714         if (ldb_msg_add_empty(msg, rdn_name, LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4715                 goto failed;
4716         }
4717         if (ldb_msg_add_value(msg, rdn_name, rdn_val, NULL) != 0) {
4718                 goto failed;
4719         }
4720         if (ldb_msg_add_empty(msg, "name", LDB_FLAG_MOD_REPLACE, NULL) != 0) {
4721                 goto failed;
4722         }
4723         if (ldb_msg_add_value(msg, "name", rdn_val, NULL) != 0) {
4724                 goto failed;
4725         }
4726
4727         /*
4728          * We have to mark this as a replicated update otherwise
4729          * schema_data may reject a rename in the schema partition
4730          */
4731
4732         ret = dsdb_module_modify(ar->module, msg,
4733                                  DSDB_FLAG_OWN_MODULE|DSDB_FLAG_REPLICATED_UPDATE,
4734                                  req);
4735         if (ret != LDB_SUCCESS) {
4736                 DEBUG(0,(__location__ ": Failed to modify rDN/name of DN being DRS renamed '%s' - %s",
4737                          ldb_dn_get_linearized(dn),
4738                          ldb_errstring(ldb_module_get_ctx(ar->module))));
4739                 return ret;
4740         }
4741
4742         talloc_free(msg);
4743
4744         return LDB_SUCCESS;
4745
4746 failed:
4747         talloc_free(msg);
4748         DEBUG(0,(__location__ ": Failed to setup modify rDN/name of DN being DRS renamed '%s'",
4749                  ldb_dn_get_linearized(dn)));
4750         return LDB_ERR_OPERATIONS_ERROR;
4751 }
4752
4753
4754 /*
4755   callback for conflict DN handling where we have renamed the incoming
4756   record. After renaming it, we need to ensure the change of name and
4757   rDN for the incoming record is seen as an originating update by this DC.
4758
4759   This also handles updating lastKnownParent for entries sent to lostAndFound
4760  */
4761 static int replmd_op_name_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4762 {
4763         struct replmd_replicated_request *ar =
4764                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4765         struct ldb_dn *conflict_dn = NULL;
4766         int ret;
4767
4768         if (ares->error != LDB_SUCCESS) {
4769                 /* call the normal callback for everything except success */
4770                 return replmd_op_callback(req, ares);
4771         }
4772
4773         switch (req->operation) {
4774         case LDB_ADD:
4775                 conflict_dn = req->op.add.message->dn;
4776                 break;
4777         case LDB_MODIFY:
4778                 conflict_dn = req->op.mod.message->dn;
4779                 break;
4780         default:
4781                 smb_panic("replmd_op_name_modify_callback called in unknown circumstances");
4782         }
4783
4784         /* perform a modify of the rDN and name of the record */
4785         ret = replmd_name_modify(ar, req, conflict_dn);
4786         if (ret != LDB_SUCCESS) {
4787                 ares->error = ret;
4788                 return replmd_op_callback(req, ares);
4789         }
4790
4791         if (ar->objs->objects[ar->index_current].last_known_parent) {
4792                 struct ldb_message *msg = ldb_msg_new(req);
4793                 if (msg == NULL) {
4794                         ldb_module_oom(ar->module);
4795                         return LDB_ERR_OPERATIONS_ERROR;
4796                 }
4797
4798                 msg->dn = req->op.add.message->dn;
4799
4800                 ret = ldb_msg_add_steal_string(msg, "lastKnownParent",
4801                                                ldb_dn_get_extended_linearized(msg, ar->objs->objects[ar->index_current].last_known_parent, 1));
4802                 if (ret != LDB_SUCCESS) {
4803                         DEBUG(0,(__location__ ": Failed to add lastKnownParent string to the msg\n"));
4804                         ldb_module_oom(ar->module);
4805                         return ret;
4806                 }
4807                 msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
4808
4809                 ret = dsdb_module_modify(ar->module, msg, DSDB_FLAG_OWN_MODULE, req);
4810                 if (ret != LDB_SUCCESS) {
4811                         DEBUG(0,(__location__ ": Failed to modify lastKnownParent of lostAndFound DN '%s' - %s",
4812                                  ldb_dn_get_linearized(msg->dn),
4813                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
4814                         return ret;
4815                 }
4816                 TALLOC_FREE(msg);
4817         }
4818
4819         return replmd_op_callback(req, ares);
4820 }
4821
4822 /*
4823   callback for replmd_replicated_apply_add()
4824   This copes with the creation of conflict records in the case where
4825   the DN exists, but with a different objectGUID
4826  */
4827 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))
4828 {
4829         struct ldb_dn *conflict_dn;
4830         struct replmd_replicated_request *ar =
4831                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
4832         struct ldb_result *res;
4833         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
4834         int ret;
4835         const struct ldb_val *omd_value;
4836         struct replPropertyMetaDataBlob omd, *rmd;
4837         enum ndr_err_code ndr_err;
4838         bool rename_incoming_record, rodc;
4839         struct replPropertyMetaData1 *rmd_name, *omd_name;
4840         struct ldb_message *msg;
4841         struct ldb_request *down_req = NULL;
4842
4843         /* call the normal callback for success */
4844         if (ares->error == LDB_SUCCESS) {
4845                 return callback(req, ares);
4846         }
4847
4848         /*
4849          * we have a conflict, and need to decide if we will keep the
4850          * new record or the old record
4851          */
4852
4853         msg = ar->objs->objects[ar->index_current].msg;
4854         conflict_dn = msg->dn;
4855
4856         /* For failures other than conflicts, fail the whole operation here */
4857         if (ares->error != LDB_ERR_ENTRY_ALREADY_EXISTS) {
4858                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote add of %s: %s",
4859                                        ldb_dn_get_linearized(conflict_dn),
4860                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
4861
4862                 return ldb_module_done(ar->req, NULL, NULL,
4863                                        LDB_ERR_OPERATIONS_ERROR);
4864         }
4865
4866         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
4867         if (ret != LDB_SUCCESS) {
4868                 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)));
4869                 return ldb_module_done(ar->req, NULL, NULL,
4870                                        LDB_ERR_OPERATIONS_ERROR);
4871
4872         }
4873
4874         if (rodc) {
4875                 /*
4876                  * We are on an RODC, or were a GC for this
4877                  * partition, so we have to fail this until
4878                  * someone who owns the partition sorts it
4879                  * out
4880                  */
4881                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
4882                                        "Conflict adding object '%s' from incoming replication as we are read only for the partition.  \n"
4883                                        " - We must fail the operation until a master for this partition resolves the conflict",
4884                                        ldb_dn_get_linearized(conflict_dn));
4885                 goto failed;
4886         }
4887
4888         /*
4889          * first we need the replPropertyMetaData attribute from the
4890          * local, conflicting record
4891          */
4892         ret = dsdb_module_search_dn(ar->module, req, &res, conflict_dn,
4893                                     attrs,
4894                                     DSDB_FLAG_NEXT_MODULE |
4895                                     DSDB_SEARCH_SHOW_DELETED |
4896                                     DSDB_SEARCH_SHOW_RECYCLED, req);
4897         if (ret != LDB_SUCCESS) {
4898                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
4899                          ldb_dn_get_linearized(conflict_dn)));
4900                 goto failed;
4901         }
4902
4903         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
4904         if (omd_value == NULL) {
4905                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
4906                          ldb_dn_get_linearized(conflict_dn)));
4907                 goto failed;
4908         }
4909
4910         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
4911                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
4912         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4913                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
4914                          ldb_dn_get_linearized(conflict_dn)));
4915                 goto failed;
4916         }
4917
4918         rmd = ar->objs->objects[ar->index_current].meta_data;
4919
4920         /*
4921          * we decide which is newer based on the RPMD on the name
4922          * attribute.  See [MS-DRSR] ResolveNameConflict.
4923          *
4924          * We expect omd_name to be present, as this is from a local
4925          * search, but while rmd_name should have been given to us by
4926          * the remote server, if it is missing we just prefer the
4927          * local name in
4928          * replmd_replPropertyMetaData1_new_should_be_taken()
4929          */
4930         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
4931         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
4932         if (!omd_name) {
4933                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
4934                          ldb_dn_get_linearized(conflict_dn)));
4935                 goto failed;
4936         }
4937
4938         /*
4939          * Should we preserve the current record, and so rename the
4940          * incoming record to be a conflict?
4941          */
4942         rename_incoming_record
4943                 = !replmd_replPropertyMetaData1_new_should_be_taken(ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
4944                                                                     omd_name, rmd_name);
4945
4946         if (rename_incoming_record) {
4947                 struct GUID guid;
4948                 struct ldb_dn *new_dn;
4949
4950                 guid = samdb_result_guid(msg, "objectGUID");
4951                 if (GUID_all_zero(&guid)) {
4952                         DEBUG(0,(__location__ ": Failed to find objectGUID for conflicting incoming record %s\n",
4953                                  ldb_dn_get_linearized(conflict_dn)));
4954                         goto failed;
4955                 }
4956                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4957                 if (new_dn == NULL) {
4958                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4959                                  ldb_dn_get_linearized(conflict_dn)));
4960                         goto failed;
4961                 }
4962
4963                 DEBUG(2,(__location__ ": Resolving conflict record via incoming rename '%s' -> '%s'\n",
4964                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4965
4966                 /* re-submit the request, but with the new DN */
4967                 callback = replmd_op_name_modify_callback;
4968                 msg->dn = new_dn;
4969         } else {
4970                 /* we are renaming the existing record */
4971                 struct GUID guid;
4972                 struct ldb_dn *new_dn;
4973
4974                 guid = samdb_result_guid(res->msgs[0], "objectGUID");
4975                 if (GUID_all_zero(&guid)) {
4976                         DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
4977                                  ldb_dn_get_linearized(conflict_dn)));
4978                         goto failed;
4979                 }
4980
4981                 new_dn = replmd_conflict_dn(req, conflict_dn, &guid);
4982                 if (new_dn == NULL) {
4983                         DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
4984                                  ldb_dn_get_linearized(conflict_dn)));
4985                         goto failed;
4986                 }
4987
4988                 DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
4989                          ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
4990
4991                 ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
4992                                          DSDB_FLAG_OWN_MODULE, req);
4993                 if (ret != LDB_SUCCESS) {
4994                         DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
4995                                  ldb_dn_get_linearized(conflict_dn),
4996                                  ldb_dn_get_linearized(new_dn),
4997                                  ldb_errstring(ldb_module_get_ctx(ar->module))));
4998                         goto failed;
4999                 }
5000
5001                 /*
5002                  * now we need to ensure that the rename is seen as an
5003                  * originating update. We do that with a modify.
5004                  */
5005                 ret = replmd_name_modify(ar, req, new_dn);
5006                 if (ret != LDB_SUCCESS) {
5007                         goto failed;
5008                 }
5009
5010                 DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated creation of '%s'\n",
5011                          ldb_dn_get_linearized(req->op.add.message->dn)));
5012         }
5013
5014         ret = ldb_build_add_req(&down_req,
5015                                 ldb_module_get_ctx(ar->module),
5016                                 req,
5017                                 msg,
5018                                 ar->controls,
5019                                 ar,
5020                                 callback,
5021                                 req);
5022         if (ret != LDB_SUCCESS) {
5023                 goto failed;
5024         }
5025         LDB_REQ_SET_LOCATION(down_req);
5026
5027         /* current partition control needed by "repmd_op_callback" */
5028         ret = ldb_request_add_control(down_req,
5029                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
5030                                       false, NULL);
5031         if (ret != LDB_SUCCESS) {
5032                 return replmd_replicated_request_error(ar, ret);
5033         }
5034
5035         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5036                 /* this tells the partition module to make it a
5037                    partial replica if creating an NC */
5038                 ret = ldb_request_add_control(down_req,
5039                                               DSDB_CONTROL_PARTIAL_REPLICA,
5040                                               false, NULL);
5041                 if (ret != LDB_SUCCESS) {
5042                         return replmd_replicated_request_error(ar, ret);
5043                 }
5044         }
5045
5046         /*
5047          * Finally we re-run the add, otherwise the new record won't
5048          * exist, as we are here because of that exact failure!
5049          */
5050         return ldb_next_request(ar->module, down_req);
5051 failed:
5052
5053         /* on failure make the caller get the error. This means
5054          * replication will stop with an error, but there is not much
5055          * else we can do.
5056          */
5057         return ldb_module_done(ar->req, NULL, NULL,
5058                                ret);
5059 }
5060
5061 /*
5062   callback for replmd_replicated_apply_add()
5063   This copes with the creation of conflict records in the case where
5064   the DN exists, but with a different objectGUID
5065  */
5066 static int replmd_op_add_callback(struct ldb_request *req, struct ldb_reply *ares)
5067 {
5068         struct replmd_replicated_request *ar =
5069                 talloc_get_type_abort(req->context, struct replmd_replicated_request);
5070
5071         if (ar->objs->objects[ar->index_current].last_known_parent) {
5072                 /* This is like a conflict DN, where we put the object in LostAndFound
5073                    see MS-DRSR 4.1.10.6.10 FindBestParentObject */
5074                 return replmd_op_possible_conflict_callback(req, ares, replmd_op_name_modify_callback);
5075         }
5076
5077         return replmd_op_possible_conflict_callback(req, ares, replmd_op_callback);
5078 }
5079
5080 /*
5081   this is called when a new object comes in over DRS
5082  */
5083 static int replmd_replicated_apply_add(struct replmd_replicated_request *ar)
5084 {
5085         struct ldb_context *ldb;
5086         struct ldb_request *change_req;
5087         enum ndr_err_code ndr_err;
5088         struct ldb_message *msg;
5089         struct replPropertyMetaDataBlob *md;
5090         struct ldb_val md_value;
5091         unsigned int i;
5092         int ret;
5093         bool remote_isDeleted = false;
5094         bool is_schema_nc;
5095         NTTIME now;
5096         time_t t = time(NULL);
5097         const struct ldb_val *rdn_val;
5098         struct replmd_private *replmd_private =
5099                 talloc_get_type(ldb_module_get_private(ar->module),
5100                                 struct replmd_private);
5101         unix_to_nt_time(&now, t);
5102
5103         ldb = ldb_module_get_ctx(ar->module);
5104         msg = ar->objs->objects[ar->index_current].msg;
5105         md = ar->objs->objects[ar->index_current].meta_data;
5106         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5107
5108         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5109         if (ret != LDB_SUCCESS) {
5110                 return replmd_replicated_request_error(ar, ret);
5111         }
5112
5113         ret = dsdb_msg_add_guid(msg,
5114                                 &ar->objs->objects[ar->index_current].object_guid,
5115                                 "objectGUID");
5116         if (ret != LDB_SUCCESS) {
5117                 return replmd_replicated_request_error(ar, ret);
5118         }
5119
5120         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5121         if (ret != LDB_SUCCESS) {
5122                 return replmd_replicated_request_error(ar, ret);
5123         }
5124
5125         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNCreated", ar->seq_num);
5126         if (ret != LDB_SUCCESS) {
5127                 return replmd_replicated_request_error(ar, ret);
5128         }
5129
5130         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5131         if (ret != LDB_SUCCESS) {
5132                 return replmd_replicated_request_error(ar, ret);
5133         }
5134
5135         /* remove any message elements that have zero values */
5136         for (i=0; i<msg->num_elements; i++) {
5137                 struct ldb_message_element *el = &msg->elements[i];
5138
5139                 if (el->num_values == 0) {
5140                         if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
5141                                 ldb_asprintf_errstring(ldb, __location__
5142                                                        ": empty objectClass sent on %s, aborting replication\n",
5143                                                        ldb_dn_get_linearized(msg->dn));
5144                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
5145                         }
5146
5147                         DEBUG(4,(__location__ ": Removing attribute %s with num_values==0\n",
5148                                  el->name));
5149                         memmove(el, el+1, sizeof(*el)*(msg->num_elements - (i+1)));
5150                         msg->num_elements--;
5151                         i--;
5152                         continue;
5153                 }
5154         }
5155
5156         if (DEBUGLVL(8)) {
5157                 struct GUID_txt_buf guid_txt;
5158
5159                 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5160                                                            LDB_CHANGETYPE_ADD,
5161                                                            msg);
5162                 DEBUG(8, ("DRS replication add message of %s:\n%s\n",
5163                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5164                           s));
5165                 talloc_free(s);
5166         } else if (DEBUGLVL(4)) {
5167                 struct GUID_txt_buf guid_txt;
5168                 DEBUG(4, ("DRS replication add DN of %s is %s\n",
5169                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5170                           ldb_dn_get_linearized(msg->dn)));
5171         }
5172         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5173                                                      "isDeleted", false);
5174
5175         /*
5176          * the meta data array is already sorted by the caller, except
5177          * for the RDN, which needs to be added.
5178          */
5179
5180
5181         rdn_val = ldb_dn_get_rdn_val(msg->dn);
5182         ret = replmd_update_rpmd_rdn_attr(ldb, msg, rdn_val, NULL,
5183                                           md, ar, now, is_schema_nc,
5184                                           false);
5185         if (ret != LDB_SUCCESS) {
5186                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5187                 return replmd_replicated_request_error(ar, ret);
5188         }
5189
5190         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &md->ctr.ctr1, msg->dn);
5191         if (ret != LDB_SUCCESS) {
5192                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl ADD: %s", __func__, ldb_errstring(ldb));
5193                 return replmd_replicated_request_error(ar, ret);
5194         }
5195
5196         for (i=0; i < md->ctr.ctr1.count; i++) {
5197                 md->ctr.ctr1.array[i].local_usn = ar->seq_num;
5198         }
5199         ndr_err = ndr_push_struct_blob(&md_value, msg, md,
5200                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5201         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5202                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
5203                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5204         }
5205         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &md_value, NULL);
5206         if (ret != LDB_SUCCESS) {
5207                 return replmd_replicated_request_error(ar, ret);
5208         }
5209
5210         replmd_ldb_message_sort(msg, ar->schema);
5211
5212         if (!remote_isDeleted) {
5213                 ret = dsdb_module_schedule_sd_propagation(ar->module,
5214                                                           ar->objs->partition_dn,
5215                                                           msg->dn, true);
5216                 if (ret != LDB_SUCCESS) {
5217                         return replmd_replicated_request_error(ar, ret);
5218                 }
5219         }
5220
5221         ar->isDeleted = remote_isDeleted;
5222
5223         ret = ldb_build_add_req(&change_req,
5224                                 ldb,
5225                                 ar,
5226                                 msg,
5227                                 ar->controls,
5228                                 ar,
5229                                 replmd_op_add_callback,
5230                                 ar->req);
5231         LDB_REQ_SET_LOCATION(change_req);
5232         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5233
5234         /* current partition control needed by "repmd_op_callback" */
5235         ret = ldb_request_add_control(change_req,
5236                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
5237                                       false, NULL);
5238         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5239
5240         if (ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
5241                 /* this tells the partition module to make it a
5242                    partial replica if creating an NC */
5243                 ret = ldb_request_add_control(change_req,
5244                                               DSDB_CONTROL_PARTIAL_REPLICA,
5245                                               false, NULL);
5246                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
5247         }
5248
5249         return ldb_next_request(ar->module, change_req);
5250 }
5251
5252 static int replmd_replicated_apply_search_for_parent_callback(struct ldb_request *req,
5253                                                               struct ldb_reply *ares)
5254 {
5255         struct replmd_replicated_request *ar = talloc_get_type(req->context,
5256                                                struct replmd_replicated_request);
5257         int ret;
5258
5259         if (!ares) {
5260                 return ldb_module_done(ar->req, NULL, NULL,
5261                                         LDB_ERR_OPERATIONS_ERROR);
5262         }
5263
5264         /*
5265          * The error NO_SUCH_OBJECT is not expected, unless the search
5266          * base is the partition DN, and that case doesn't happen here
5267          * because then we wouldn't get a parent_guid_value in any
5268          * case.
5269          */
5270         if (ares->error != LDB_SUCCESS) {
5271                 return ldb_module_done(ar->req, ares->controls,
5272                                         ares->response, ares->error);
5273         }
5274
5275         switch (ares->type) {
5276         case LDB_REPLY_ENTRY:
5277         {
5278                 struct ldb_message *parent_msg = ares->message;
5279                 struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
5280                 struct ldb_dn *parent_dn;
5281                 int comp_num;
5282
5283                 if (!ldb_msg_check_string_attribute(msg, "isDeleted", "TRUE")
5284                     && ldb_msg_check_string_attribute(parent_msg, "isDeleted", "TRUE")) {
5285                         /* Per MS-DRSR 4.1.10.6.10
5286                          * FindBestParentObject we need to move this
5287                          * new object under a deleted object to
5288                          * lost-and-found */
5289                         struct ldb_dn *nc_root;
5290
5291                         ret = dsdb_find_nc_root(ldb_module_get_ctx(ar->module), msg, msg->dn, &nc_root);
5292                         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
5293                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5294                                                        "No suitable NC root found for %s.  "
5295                                                        "We need to move this object because parent object %s "
5296                                                        "is deleted, but this object is not.",
5297                                                        ldb_dn_get_linearized(msg->dn),
5298                                                        ldb_dn_get_linearized(parent_msg->dn));
5299                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5300                         } else if (ret != LDB_SUCCESS) {
5301                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5302                                                        "Unable to find NC root for %s: %s. "
5303                                                        "We need to move this object because parent object %s "
5304                                                        "is deleted, but this object is not.",
5305                                                        ldb_dn_get_linearized(msg->dn),
5306                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
5307                                                        ldb_dn_get_linearized(parent_msg->dn));
5308                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5309                         }
5310
5311                         ret = dsdb_wellknown_dn(ldb_module_get_ctx(ar->module), msg,
5312                                                 nc_root,
5313                                                 DS_GUID_LOSTANDFOUND_CONTAINER,
5314                                                 &parent_dn);
5315                         if (ret != LDB_SUCCESS) {
5316                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5317                                                        "Unable to find LostAndFound Container for %s "
5318                                                        "in partition %s: %s. "
5319                                                        "We need to move this object because parent object %s "
5320                                                        "is deleted, but this object is not.",
5321                                                        ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(nc_root),
5322                                                        ldb_errstring(ldb_module_get_ctx(ar->module)),
5323                                                        ldb_dn_get_linearized(parent_msg->dn));
5324                                 return ldb_module_done(ar->req, NULL, NULL, LDB_ERR_OPERATIONS_ERROR);
5325                         }
5326                         ar->objs->objects[ar->index_current].last_known_parent
5327                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5328
5329                 } else {
5330                         parent_dn
5331                                 = talloc_steal(ar->objs->objects[ar->index_current].msg, parent_msg->dn);
5332
5333                 }
5334                 ar->objs->objects[ar->index_current].local_parent_dn = parent_dn;
5335
5336                 comp_num = ldb_dn_get_comp_num(msg->dn);
5337                 if (comp_num > 1) {
5338                         if (!ldb_dn_remove_base_components(msg->dn, comp_num - 1)) {
5339                                 talloc_free(ares);
5340                                 return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5341                         }
5342                 }
5343                 if (!ldb_dn_add_base(msg->dn, parent_dn)) {
5344                         talloc_free(ares);
5345                         return ldb_module_done(ar->req, NULL, NULL, ldb_module_operr(ar->module));
5346                 }
5347                 break;
5348         }
5349         case LDB_REPLY_REFERRAL:
5350                 /* we ignore referrals */
5351                 break;
5352
5353         case LDB_REPLY_DONE:
5354
5355                 if (ar->objs->objects[ar->index_current].local_parent_dn == NULL) {
5356                         struct GUID_txt_buf str_buf;
5357                         if (ar->search_msg != NULL) {
5358                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5359                                                        "No parent with GUID %s found for object locally known as %s",
5360                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5361                                                        ldb_dn_get_linearized(ar->search_msg->dn));
5362                         } else {
5363                                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5364                                                        "No parent with GUID %s found for object remotely known as %s",
5365                                                        GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid, &str_buf),
5366                                                        ldb_dn_get_linearized(ar->objs->objects[ar->index_current].msg->dn));
5367                         }
5368
5369                         /*
5370                          * This error code is really important, as it
5371                          * is the flag back to the callers to retry
5372                          * this with DRSUAPI_DRS_GET_ANC, and so get
5373                          * the parent objects before the child
5374                          * objects
5375                          */
5376                         return ldb_module_done(ar->req, NULL, NULL,
5377                                                replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT));
5378                 }
5379
5380                 if (ar->search_msg != NULL) {
5381                         ret = replmd_replicated_apply_merge(ar);
5382                 } else {
5383                         ret = replmd_replicated_apply_add(ar);
5384                 }
5385                 if (ret != LDB_SUCCESS) {
5386                         return ldb_module_done(ar->req, NULL, NULL, ret);
5387                 }
5388         }
5389
5390         talloc_free(ares);
5391         return LDB_SUCCESS;
5392 }
5393
5394 /*
5395  * Look for the parent object, so we put the new object in the right
5396  * place This is akin to NameObject in MS-DRSR - this routine and the
5397  * callbacks find the right parent name, and correct name for this
5398  * object
5399  */
5400
5401 static int replmd_replicated_apply_search_for_parent(struct replmd_replicated_request *ar)
5402 {
5403         struct ldb_context *ldb;
5404         int ret;
5405         char *tmp_str;
5406         char *filter;
5407         struct ldb_request *search_req;
5408         static const char *attrs[] = {"isDeleted", NULL};
5409         struct GUID_txt_buf guid_str_buf;
5410
5411         ldb = ldb_module_get_ctx(ar->module);
5412
5413         if (ar->objs->objects[ar->index_current].parent_guid == NULL) {
5414                 if (ar->search_msg != NULL) {
5415                         return replmd_replicated_apply_merge(ar);
5416                 } else {
5417                         return replmd_replicated_apply_add(ar);
5418                 }
5419         }
5420
5421         tmp_str = GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
5422                                   &guid_str_buf);
5423
5424         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
5425         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5426
5427         ret = ldb_build_search_req(&search_req,
5428                                    ldb,
5429                                    ar,
5430                                    ar->objs->partition_dn,
5431                                    LDB_SCOPE_SUBTREE,
5432                                    filter,
5433                                    attrs,
5434                                    NULL,
5435                                    ar,
5436                                    replmd_replicated_apply_search_for_parent_callback,
5437                                    ar->req);
5438         LDB_REQ_SET_LOCATION(search_req);
5439
5440         ret = dsdb_request_add_controls(search_req,
5441                                         DSDB_SEARCH_SHOW_RECYCLED|
5442                                         DSDB_SEARCH_SHOW_DELETED|
5443                                         DSDB_SEARCH_SHOW_EXTENDED_DN);
5444         if (ret != LDB_SUCCESS) {
5445                 return ret;
5446         }
5447
5448         return ldb_next_request(ar->module, search_req);
5449 }
5450
5451 /*
5452   handle renames that come in over DRS replication
5453  */
5454 static int replmd_replicated_handle_rename(struct replmd_replicated_request *ar,
5455                                            struct ldb_message *msg,
5456                                            struct ldb_request *parent,
5457                                            bool *renamed)
5458 {
5459         int ret;
5460         TALLOC_CTX *tmp_ctx = talloc_new(msg);
5461         struct ldb_result *res;
5462         struct ldb_dn *conflict_dn;
5463         const char *attrs[] = { "replPropertyMetaData", "objectGUID", NULL };
5464         const struct ldb_val *omd_value;
5465         struct replPropertyMetaDataBlob omd, *rmd;
5466         enum ndr_err_code ndr_err;
5467         bool rename_incoming_record, rodc;
5468         struct replPropertyMetaData1 *rmd_name, *omd_name;
5469         struct ldb_dn *new_dn;
5470         struct GUID guid;
5471
5472         DEBUG(4,("replmd_replicated_request rename %s => %s\n",
5473                  ldb_dn_get_linearized(ar->search_msg->dn),
5474                  ldb_dn_get_linearized(msg->dn)));
5475
5476
5477         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5478                                  DSDB_FLAG_NEXT_MODULE, ar->req);
5479         if (ret == LDB_SUCCESS) {
5480                 talloc_free(tmp_ctx);
5481                 *renamed = true;
5482                 return ret;
5483         }
5484
5485         if (ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
5486                 talloc_free(tmp_ctx);
5487                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module), "Failed to locally apply remote rename from %s to %s: %s",
5488                                        ldb_dn_get_linearized(ar->search_msg->dn),
5489                                        ldb_dn_get_linearized(msg->dn),
5490                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
5491                 return ret;
5492         }
5493
5494         ret = samdb_rodc(ldb_module_get_ctx(ar->module), &rodc);
5495         if (ret != LDB_SUCCESS) {
5496                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5497                                        "Failed to determine if we are an RODC when attempting to form conflict DN: %s",
5498                                        ldb_errstring(ldb_module_get_ctx(ar->module)));
5499                 return LDB_ERR_OPERATIONS_ERROR;
5500         }
5501         /*
5502          * we have a conflict, and need to decide if we will keep the
5503          * new record or the old record
5504          */
5505
5506         conflict_dn = msg->dn;
5507
5508         if (rodc) {
5509                 /*
5510                  * We are on an RODC, or were a GC for this
5511                  * partition, so we have to fail this until
5512                  * someone who owns the partition sorts it
5513                  * out
5514                  */
5515                 ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5516                                        "Conflict adding object '%s' from incoming replication but we are read only for the partition.  \n"
5517                                        " - We must fail the operation until a master for this partition resolves the conflict",
5518                                        ldb_dn_get_linearized(conflict_dn));
5519                 goto failed;
5520         }
5521
5522         /*
5523          * first we need the replPropertyMetaData attribute from the
5524          * old record
5525          */
5526         ret = dsdb_module_search_dn(ar->module, tmp_ctx, &res, conflict_dn,
5527                                     attrs,
5528                                     DSDB_FLAG_NEXT_MODULE |
5529                                     DSDB_SEARCH_SHOW_DELETED |
5530                                     DSDB_SEARCH_SHOW_RECYCLED, ar->req);
5531         if (ret != LDB_SUCCESS) {
5532                 DEBUG(0,(__location__ ": Unable to find object for conflicting record '%s'\n",
5533                          ldb_dn_get_linearized(conflict_dn)));
5534                 goto failed;
5535         }
5536
5537         omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData");
5538         if (omd_value == NULL) {
5539                 DEBUG(0,(__location__ ": Unable to find replPropertyMetaData for conflicting record '%s'\n",
5540                          ldb_dn_get_linearized(conflict_dn)));
5541                 goto failed;
5542         }
5543
5544         ndr_err = ndr_pull_struct_blob(omd_value, res->msgs[0], &omd,
5545                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5546         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5547                 DEBUG(0,(__location__ ": Failed to parse old replPropertyMetaData for %s\n",
5548                          ldb_dn_get_linearized(conflict_dn)));
5549                 goto failed;
5550         }
5551
5552         rmd = ar->objs->objects[ar->index_current].meta_data;
5553
5554         /*
5555          * we decide which is newer based on the RPMD on the name
5556          * attribute.  See [MS-DRSR] ResolveNameConflict.
5557          *
5558          * We expect omd_name to be present, as this is from a local
5559          * search, but while rmd_name should have been given to us by
5560          * the remote server, if it is missing we just prefer the
5561          * local name in
5562          * replmd_replPropertyMetaData1_new_should_be_taken()
5563          */
5564         rmd_name = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
5565         omd_name = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
5566         if (!omd_name) {
5567                 DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
5568                          ldb_dn_get_linearized(conflict_dn)));
5569                 goto failed;
5570         }
5571
5572         /*
5573          * Should we preserve the current record, and so rename the
5574          * incoming record to be a conflict?
5575          */
5576         rename_incoming_record =
5577                 !replmd_replPropertyMetaData1_new_should_be_taken(
5578                         ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
5579                         omd_name, rmd_name);
5580
5581         if (rename_incoming_record) {
5582
5583                 new_dn = replmd_conflict_dn(msg, msg->dn,
5584                                             &ar->objs->objects[ar->index_current].object_guid);
5585                 if (new_dn == NULL) {
5586                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5587                                                                   "Failed to form conflict DN for %s\n",
5588                                                                   ldb_dn_get_linearized(msg->dn));
5589
5590                         return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5591                 }
5592
5593                 ret = dsdb_module_rename(ar->module, ar->search_msg->dn, new_dn,
5594                                          DSDB_FLAG_NEXT_MODULE, ar->req);
5595                 if (ret != LDB_SUCCESS) {
5596                         ldb_asprintf_errstring(ldb_module_get_ctx(ar->module),
5597                                                "Failed to rename incoming conflicting dn '%s' (was '%s') to '%s' - %s\n",
5598                                                ldb_dn_get_linearized(conflict_dn),
5599                                                ldb_dn_get_linearized(ar->search_msg->dn),
5600                                                ldb_dn_get_linearized(new_dn),
5601                                                ldb_errstring(ldb_module_get_ctx(ar->module)));
5602                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5603                 }
5604
5605                 msg->dn = new_dn;
5606                 *renamed = true;
5607                 return LDB_SUCCESS;
5608         }
5609
5610         /* we are renaming the existing record */
5611
5612         guid = samdb_result_guid(res->msgs[0], "objectGUID");
5613         if (GUID_all_zero(&guid)) {
5614                 DEBUG(0,(__location__ ": Failed to find objectGUID for existing conflict record %s\n",
5615                          ldb_dn_get_linearized(conflict_dn)));
5616                 goto failed;
5617         }
5618
5619         new_dn = replmd_conflict_dn(tmp_ctx, conflict_dn, &guid);
5620         if (new_dn == NULL) {
5621                 DEBUG(0,(__location__ ": Failed to form conflict DN for %s\n",
5622                          ldb_dn_get_linearized(conflict_dn)));
5623                 goto failed;
5624         }
5625
5626         DEBUG(2,(__location__ ": Resolving conflict record via existing-record rename '%s' -> '%s'\n",
5627                  ldb_dn_get_linearized(conflict_dn), ldb_dn_get_linearized(new_dn)));
5628
5629         ret = dsdb_module_rename(ar->module, conflict_dn, new_dn,
5630                                  DSDB_FLAG_OWN_MODULE, ar->req);
5631         if (ret != LDB_SUCCESS) {
5632                 DEBUG(0,(__location__ ": Failed to rename conflict dn '%s' to '%s' - %s\n",
5633                          ldb_dn_get_linearized(conflict_dn),
5634                          ldb_dn_get_linearized(new_dn),
5635                          ldb_errstring(ldb_module_get_ctx(ar->module))));
5636                 goto failed;
5637         }
5638
5639         /*
5640          * now we need to ensure that the rename is seen as an
5641          * originating update. We do that with a modify.
5642          */
5643         ret = replmd_name_modify(ar, ar->req, new_dn);
5644         if (ret != LDB_SUCCESS) {
5645                 goto failed;
5646         }
5647
5648         DEBUG(2,(__location__ ": With conflicting record renamed, re-apply replicated rename '%s' -> '%s'\n",
5649                  ldb_dn_get_linearized(ar->search_msg->dn),
5650                  ldb_dn_get_linearized(msg->dn)));
5651
5652
5653         ret = dsdb_module_rename(ar->module, ar->search_msg->dn, msg->dn,
5654                                  DSDB_FLAG_NEXT_MODULE, ar->req);
5655         if (ret != LDB_SUCCESS) {
5656                 DEBUG(0,(__location__ ": After conflict resolution, failed to rename dn '%s' to '%s' - %s\n",
5657                          ldb_dn_get_linearized(ar->search_msg->dn),
5658                          ldb_dn_get_linearized(msg->dn),
5659                          ldb_errstring(ldb_module_get_ctx(ar->module))));
5660                         goto failed;
5661         }
5662 failed:
5663
5664         /*
5665          * On failure make the caller get the error
5666          * This means replication will stop with an error,
5667          * but there is not much else we can do.  In the
5668          * LDB_ERR_ENTRY_ALREADY_EXISTS case this is exactly what is
5669          * needed.
5670          */
5671
5672         talloc_free(tmp_ctx);
5673         return ret;
5674 }
5675
5676
5677 static int replmd_replicated_apply_merge(struct replmd_replicated_request *ar)
5678 {
5679         struct ldb_context *ldb;
5680         struct ldb_request *change_req;
5681         enum ndr_err_code ndr_err;
5682         struct ldb_message *msg;
5683         struct replPropertyMetaDataBlob *rmd;
5684         struct replPropertyMetaDataBlob omd;
5685         const struct ldb_val *omd_value;
5686         struct replPropertyMetaDataBlob nmd;
5687         struct ldb_val nmd_value;
5688         struct GUID remote_parent_guid;
5689         unsigned int i;
5690         uint32_t j,ni=0;
5691         unsigned int removed_attrs = 0;
5692         int ret;
5693         int (*callback)(struct ldb_request *req, struct ldb_reply *ares) = replmd_op_callback;
5694         bool isDeleted = false;
5695         bool local_isDeleted = false;
5696         bool remote_isDeleted = false;
5697         bool take_remote_isDeleted = false;
5698         bool sd_updated = false;
5699         bool renamed = false;
5700         bool is_schema_nc = false;
5701         NTSTATUS nt_status;
5702         const struct ldb_val *old_rdn, *new_rdn;
5703         struct replmd_private *replmd_private =
5704                 talloc_get_type(ldb_module_get_private(ar->module),
5705                                 struct replmd_private);
5706         NTTIME now;
5707         time_t t = time(NULL);
5708         unix_to_nt_time(&now, t);
5709
5710         ldb = ldb_module_get_ctx(ar->module);
5711         msg = ar->objs->objects[ar->index_current].msg;
5712
5713         is_schema_nc = ldb_dn_compare_base(replmd_private->schema_dn, msg->dn) == 0;
5714
5715         rmd = ar->objs->objects[ar->index_current].meta_data;
5716         ZERO_STRUCT(omd);
5717         omd.version = 1;
5718
5719         /* find existing meta data */
5720         omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
5721         if (omd_value) {
5722                 ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
5723                                                (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
5724                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5725                         nt_status = ndr_map_error2ntstatus(ndr_err);
5726                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5727                 }
5728
5729                 if (omd.version != 1) {
5730                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
5731                 }
5732         }
5733
5734         if (DEBUGLVL(8)) {
5735                 struct GUID_txt_buf guid_txt;
5736
5737                 char *s = ldb_ldif_message_redacted_string(ldb, ar,
5738                                                            LDB_CHANGETYPE_MODIFY, msg);
5739                 DEBUG(8, ("Initial DRS replication modify message of %s is:\n%s\n"
5740                           "%s\n"
5741                           "%s\n",
5742                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid, &guid_txt),
5743                           s,
5744                           ndr_print_struct_string(s,
5745                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5746                                                   "existing replPropertyMetaData",
5747                                                   &omd),
5748                           ndr_print_struct_string(s,
5749                                                   (ndr_print_fn_t)ndr_print_replPropertyMetaDataBlob,
5750                                                   "incoming replPropertyMetaData",
5751                                                   rmd)));
5752                 talloc_free(s);
5753         } else if (DEBUGLVL(4)) {
5754                 struct GUID_txt_buf guid_txt;
5755
5756                 DEBUG(4, ("Initial DRS replication modify DN of %s is: %s\n",
5757                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
5758                                           &guid_txt),
5759                           ldb_dn_get_linearized(msg->dn)));
5760         }
5761                 
5762         local_isDeleted = ldb_msg_find_attr_as_bool(ar->search_msg,
5763                                                     "isDeleted", false);
5764         remote_isDeleted = ldb_msg_find_attr_as_bool(msg,
5765                                                      "isDeleted", false);
5766
5767         /*
5768          * Fill in the remote_parent_guid with the GUID or an all-zero
5769          * GUID.
5770          */
5771         if (ar->objs->objects[ar->index_current].parent_guid != NULL) {
5772                 remote_parent_guid = *ar->objs->objects[ar->index_current].parent_guid;
5773         } else {
5774                 remote_parent_guid = GUID_zero();
5775         }
5776
5777         /*
5778          * To ensure we follow a complex rename chain around, we have
5779          * to confirm that the DN is the same (mostly to confirm the
5780          * RDN) and the parentGUID is the same.
5781          *
5782          * This ensures we keep things under the correct parent, which
5783          * replmd_replicated_handle_rename() will do.
5784          */
5785
5786         if (strcmp(ldb_dn_get_linearized(msg->dn), ldb_dn_get_linearized(ar->search_msg->dn)) == 0
5787             && GUID_equal(&remote_parent_guid, &ar->local_parent_guid)) {
5788                 ret = LDB_SUCCESS;
5789         } else {
5790                 /*
5791                  * handle renames, even just by case that come in over
5792                  * DRS.  Changes in the parent DN don't hit us here,
5793                  * because the search for a parent will clean up those
5794                  * components.
5795                  *
5796                  * We also have already filtered out the case where
5797                  * the peer has an older name to what we have (see
5798                  * replmd_replicated_apply_search_callback())
5799                  */
5800                 ret = replmd_replicated_handle_rename(ar, msg, ar->req, &renamed);
5801         }
5802
5803         if (ret != LDB_SUCCESS) {
5804                 ldb_debug(ldb, LDB_DEBUG_FATAL,
5805                           "replmd_replicated_request rename %s => %s failed - %s\n",
5806                           ldb_dn_get_linearized(ar->search_msg->dn),
5807                           ldb_dn_get_linearized(msg->dn),
5808                           ldb_errstring(ldb));
5809                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
5810         }
5811
5812         if (renamed == true) {
5813                 /*
5814                  * Set the callback to one that will fix up the name
5815                  * metadata on the new conflict DN
5816                  */
5817                 callback = replmd_op_name_modify_callback;
5818         }
5819
5820         ZERO_STRUCT(nmd);
5821         nmd.version = 1;
5822         nmd.ctr.ctr1.count = omd.ctr.ctr1.count + rmd->ctr.ctr1.count;
5823         nmd.ctr.ctr1.array = talloc_array(ar,
5824                                           struct replPropertyMetaData1,
5825                                           nmd.ctr.ctr1.count);
5826         if (!nmd.ctr.ctr1.array) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
5827
5828         /* first copy the old meta data */
5829         for (i=0; i < omd.ctr.ctr1.count; i++) {
5830                 nmd.ctr.ctr1.array[ni]  = omd.ctr.ctr1.array[i];
5831                 ni++;
5832         }
5833
5834         ar->seq_num = 0;
5835         /* now merge in the new meta data */
5836         for (i=0; i < rmd->ctr.ctr1.count; i++) {
5837                 bool found = false;
5838
5839                 for (j=0; j < ni; j++) {
5840                         bool cmp;
5841
5842                         if (rmd->ctr.ctr1.array[i].attid != nmd.ctr.ctr1.array[j].attid) {
5843                                 continue;
5844                         }
5845
5846                         cmp = replmd_replPropertyMetaData1_new_should_be_taken(
5847                                 ar->objs->dsdb_repl_flags,
5848                                 &nmd.ctr.ctr1.array[j],
5849                                 &rmd->ctr.ctr1.array[i]);
5850                         if (cmp) {
5851                                 /* replace the entry */
5852                                 nmd.ctr.ctr1.array[j] = rmd->ctr.ctr1.array[i];
5853                                 if (ar->seq_num == 0) {
5854                                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5855                                         if (ret != LDB_SUCCESS) {
5856                                                 return replmd_replicated_request_error(ar, ret);
5857                                         }
5858                                 }
5859                                 nmd.ctr.ctr1.array[j].local_usn = ar->seq_num;
5860                                 switch (nmd.ctr.ctr1.array[j].attid) {
5861                                 case DRSUAPI_ATTID_ntSecurityDescriptor:
5862                                         sd_updated = true;
5863                                         break;
5864                                 case DRSUAPI_ATTID_isDeleted:
5865                                         take_remote_isDeleted = true;
5866                                         break;
5867                                 default:
5868                                         break;
5869                                 }
5870                                 found = true;
5871                                 break;
5872                         }
5873
5874                         if (rmd->ctr.ctr1.array[i].attid != DRSUAPI_ATTID_instanceType) {
5875                                 DEBUG(3,("Discarding older DRS attribute update to %s on %s from %s\n",
5876                                          msg->elements[i-removed_attrs].name,
5877                                          ldb_dn_get_linearized(msg->dn),
5878                                          GUID_string(ar, &rmd->ctr.ctr1.array[i].originating_invocation_id)));
5879                         }
5880
5881                         /* we don't want to apply this change so remove the attribute */
5882                         ldb_msg_remove_element(msg, &msg->elements[i-removed_attrs]);
5883                         removed_attrs++;
5884
5885                         found = true;
5886                         break;
5887                 }
5888
5889                 if (found) continue;
5890
5891                 nmd.ctr.ctr1.array[ni] = rmd->ctr.ctr1.array[i];
5892                 if (ar->seq_num == 0) {
5893                         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &ar->seq_num);
5894                         if (ret != LDB_SUCCESS) {
5895                                 return replmd_replicated_request_error(ar, ret);
5896                         }
5897                 }
5898                 nmd.ctr.ctr1.array[ni].local_usn = ar->seq_num;
5899                 switch (nmd.ctr.ctr1.array[ni].attid) {
5900                 case DRSUAPI_ATTID_ntSecurityDescriptor:
5901                         sd_updated = true;
5902                         break;
5903                 case DRSUAPI_ATTID_isDeleted:
5904                         take_remote_isDeleted = true;
5905                         break;
5906                 default:
5907                         break;
5908                 }
5909                 ni++;
5910         }
5911
5912         /*
5913          * finally correct the size of the meta_data array
5914          */
5915         nmd.ctr.ctr1.count = ni;
5916
5917         new_rdn = ldb_dn_get_rdn_val(msg->dn);
5918         old_rdn = ldb_dn_get_rdn_val(ar->search_msg->dn);
5919
5920         if (renamed) {
5921                 ret = replmd_update_rpmd_rdn_attr(ldb, msg, new_rdn, old_rdn,
5922                                                   &nmd, ar, now, is_schema_nc,
5923                                                   false);
5924                 if (ret != LDB_SUCCESS) {
5925                         ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5926                         return replmd_replicated_request_error(ar, ret);
5927                 }
5928         }
5929         /*
5930          * sort the new meta data array
5931          */
5932         ret = replmd_replPropertyMetaDataCtr1_sort_and_verify(ldb, &nmd.ctr.ctr1, msg->dn);
5933         if (ret != LDB_SUCCESS) {
5934                 ldb_asprintf_errstring(ldb, "%s: error during DRS repl merge: %s", __func__, ldb_errstring(ldb));
5935                 return ret;
5936         }
5937
5938         /*
5939          * Work out if this object is deleted, so we can prune any extra attributes.  See MS-DRSR 4.1.10.6.9
5940          * UpdateObject.
5941          *
5942          * This also controls SD propagation below
5943          */
5944         if (take_remote_isDeleted) {
5945                 isDeleted = remote_isDeleted;
5946         } else {
5947                 isDeleted = local_isDeleted;
5948         }
5949
5950         ar->isDeleted = isDeleted;
5951
5952         /*
5953          * check if some replicated attributes left, otherwise skip the ldb_modify() call
5954          */
5955         if (msg->num_elements == 0) {
5956                 ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: skip replace\n",
5957                           ar->index_current);
5958
5959                 return replmd_replicated_apply_isDeleted(ar);
5960         }
5961
5962         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_replicated_apply_merge[%u]: replace %u attributes\n",
5963                   ar->index_current, msg->num_elements);
5964
5965         if (renamed) {
5966                 sd_updated = true;
5967         }
5968
5969         if (sd_updated && !isDeleted) {
5970                 ret = dsdb_module_schedule_sd_propagation(ar->module,
5971                                                           ar->objs->partition_dn,
5972                                                           msg->dn, true);
5973                 if (ret != LDB_SUCCESS) {
5974                         return ldb_operr(ldb);
5975                 }
5976         }
5977
5978         /* create the meta data value */
5979         ndr_err = ndr_push_struct_blob(&nmd_value, msg, &nmd,
5980                                        (ndr_push_flags_fn_t)ndr_push_replPropertyMetaDataBlob);
5981         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
5982                 nt_status = ndr_map_error2ntstatus(ndr_err);
5983                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
5984         }
5985
5986         /*
5987          * when we know that we'll modify the record, add the whenChanged, uSNChanged
5988          * and replPopertyMetaData attributes
5989          */
5990         ret = ldb_msg_add_string(msg, "whenChanged", ar->objs->objects[ar->index_current].when_changed);
5991         if (ret != LDB_SUCCESS) {
5992                 return replmd_replicated_request_error(ar, ret);
5993         }
5994         ret = samdb_msg_add_uint64(ldb, msg, msg, "uSNChanged", ar->seq_num);
5995         if (ret != LDB_SUCCESS) {
5996                 return replmd_replicated_request_error(ar, ret);
5997         }
5998         ret = ldb_msg_add_value(msg, "replPropertyMetaData", &nmd_value, NULL);
5999         if (ret != LDB_SUCCESS) {
6000                 return replmd_replicated_request_error(ar, ret);
6001         }
6002
6003         replmd_ldb_message_sort(msg, ar->schema);
6004
6005         /* we want to replace the old values */
6006         for (i=0; i < msg->num_elements; i++) {
6007                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
6008                 if (ldb_attr_cmp(msg->elements[i].name, "objectClass") == 0) {
6009                         if (msg->elements[i].num_values == 0) {
6010                                 ldb_asprintf_errstring(ldb, __location__
6011                                                        ": objectClass removed on %s, aborting replication\n",
6012                                                        ldb_dn_get_linearized(msg->dn));
6013                                 return replmd_replicated_request_error(ar, LDB_ERR_OBJECT_CLASS_VIOLATION);
6014                         }
6015                 }
6016         }
6017
6018         if (DEBUGLVL(8)) {
6019                 struct GUID_txt_buf guid_txt;
6020
6021                 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6022                                                            LDB_CHANGETYPE_MODIFY,
6023                                                            msg);
6024                 DEBUG(8, ("Final DRS replication modify message of %s:\n%s\n",
6025                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6026                                           &guid_txt),
6027                           s));
6028                 talloc_free(s);
6029         } else if (DEBUGLVL(4)) {
6030                 struct GUID_txt_buf guid_txt;
6031
6032                 DEBUG(4, ("Final DRS replication modify DN of %s is %s\n",
6033                           GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6034                                           &guid_txt),
6035                           ldb_dn_get_linearized(msg->dn)));
6036         }
6037
6038         ret = ldb_build_mod_req(&change_req,
6039                                 ldb,
6040                                 ar,
6041                                 msg,
6042                                 ar->controls,
6043                                 ar,
6044                                 callback,
6045                                 ar->req);
6046         LDB_REQ_SET_LOCATION(change_req);
6047         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6048
6049         /* current partition control needed by "repmd_op_callback" */
6050         ret = ldb_request_add_control(change_req,
6051                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
6052                                       false, NULL);
6053         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6054
6055         return ldb_next_request(ar->module, change_req);
6056 }
6057
6058 static int replmd_replicated_apply_search_callback(struct ldb_request *req,
6059                                                    struct ldb_reply *ares)
6060 {
6061         struct replmd_replicated_request *ar = talloc_get_type(req->context,
6062                                                struct replmd_replicated_request);
6063         int ret;
6064
6065         if (!ares) {
6066                 return ldb_module_done(ar->req, NULL, NULL,
6067                                         LDB_ERR_OPERATIONS_ERROR);
6068         }
6069         if (ares->error != LDB_SUCCESS &&
6070             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6071                 return ldb_module_done(ar->req, ares->controls,
6072                                         ares->response, ares->error);
6073         }
6074
6075         switch (ares->type) {
6076         case LDB_REPLY_ENTRY:
6077                 ar->search_msg = talloc_steal(ar, ares->message);
6078                 break;
6079
6080         case LDB_REPLY_REFERRAL:
6081                 /* we ignore referrals */
6082                 break;
6083
6084         case LDB_REPLY_DONE:
6085         {
6086                 struct replPropertyMetaData1 *md_remote;
6087                 struct replPropertyMetaData1 *md_local;
6088
6089                 struct replPropertyMetaDataBlob omd;
6090                 const struct ldb_val *omd_value;
6091                 struct replPropertyMetaDataBlob *rmd;
6092                 struct ldb_message *msg;
6093                 int instanceType;
6094                 ar->objs->objects[ar->index_current].local_parent_dn = NULL;
6095                 ar->objs->objects[ar->index_current].last_known_parent = NULL;
6096
6097                 /*
6098                  * This is the ADD case, find the appropriate parent,
6099                  * as this object doesn't exist locally:
6100                  */
6101                 if (ar->search_msg == NULL) {
6102                         ret = replmd_replicated_apply_search_for_parent(ar);
6103                         if (ret != LDB_SUCCESS) {
6104                                 return ldb_module_done(ar->req, NULL, NULL, ret);
6105                         }
6106                         talloc_free(ares);
6107                         return LDB_SUCCESS;
6108                 }
6109
6110                 /*
6111                  * Otherwise, in the MERGE case, work out if we are
6112                  * attempting a rename, and if so find the parent the
6113                  * newly renamed object wants to belong under (which
6114                  * may not be the parent in it's attached string DN
6115                  */
6116                 rmd = ar->objs->objects[ar->index_current].meta_data;
6117                 ZERO_STRUCT(omd);
6118                 omd.version = 1;
6119
6120                 /* find existing meta data */
6121                 omd_value = ldb_msg_find_ldb_val(ar->search_msg, "replPropertyMetaData");
6122                 if (omd_value) {
6123                         enum ndr_err_code ndr_err;
6124                         ndr_err = ndr_pull_struct_blob(omd_value, ar, &omd,
6125                                                        (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob);
6126                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6127                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6128                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6129                         }
6130
6131                         if (omd.version != 1) {
6132                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6133                         }
6134                 }
6135
6136                 ar->local_parent_guid = samdb_result_guid(ar->search_msg, "parentGUID");
6137
6138                 instanceType = ldb_msg_find_attr_as_int(ar->search_msg, "instanceType", 0);
6139                 if (((instanceType & INSTANCE_TYPE_IS_NC_HEAD) == 0)
6140                     && GUID_all_zero(&ar->local_parent_guid)) {
6141                         DEBUG(0, ("Refusing to replicate new version of %s "
6142                                   "as local object has an all-zero parentGUID attribute, "
6143                                   "despite not being an NC root\n",
6144                                   ldb_dn_get_linearized(ar->search_msg->dn)));
6145                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6146                 }
6147
6148                 /*
6149                  * now we need to check for double renames. We could have a
6150                  * local rename pending which our replication partner hasn't
6151                  * received yet. We choose which one wins by looking at the
6152                  * attribute stamps on the two objects, the newer one wins.
6153                  *
6154                  * This also simply applies the correct algorithms for
6155                  * determining if a change was made to name at all, or
6156                  * if the object has just been renamed under the same
6157                  * parent.
6158                  */
6159                 md_remote = replmd_replPropertyMetaData1_find_attid(rmd, DRSUAPI_ATTID_name);
6160                 md_local = replmd_replPropertyMetaData1_find_attid(&omd, DRSUAPI_ATTID_name);
6161                 if (!md_local) {
6162                         DEBUG(0,(__location__ ": Failed to find name attribute in local LDB replPropertyMetaData for %s\n",
6163                                  ldb_dn_get_linearized(ar->search_msg->dn)));
6164                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_DB_ERROR);
6165                 }
6166
6167                 /*
6168                  * if there is no name attribute given then we have to assume the
6169                  *  object we've received has the older name
6170                  */
6171                 if (replmd_replPropertyMetaData1_new_should_be_taken(
6172                             ar->objs->dsdb_repl_flags & DSDB_REPL_FLAG_PRIORITISE_INCOMING,
6173                             md_local, md_remote)) {
6174                         struct GUID_txt_buf p_guid_local;
6175                         struct GUID_txt_buf p_guid_remote;
6176                         msg = ar->objs->objects[ar->index_current].msg;
6177
6178                         /* Merge on the existing object, with rename */
6179
6180                         DEBUG(4,(__location__ ": Looking for new parent for object %s currently under %s "
6181                                  "as incoming object changing to %s under %s\n",
6182                                  ldb_dn_get_linearized(ar->search_msg->dn),
6183                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6184                                  ldb_dn_get_linearized(msg->dn),
6185                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6186                                                  &p_guid_remote)));
6187                         ret = replmd_replicated_apply_search_for_parent(ar);
6188                 } else {
6189                         struct GUID_txt_buf p_guid_local;
6190                         struct GUID_txt_buf p_guid_remote;
6191                         msg = ar->objs->objects[ar->index_current].msg;
6192
6193                         /*
6194                          * Merge on the existing object, force no
6195                          * rename (code below just to explain why in
6196                          * the DEBUG() logs)
6197                          */
6198
6199                         if (strcmp(ldb_dn_get_linearized(ar->search_msg->dn),
6200                                    ldb_dn_get_linearized(msg->dn)) == 0) {
6201                                 if (ar->objs->objects[ar->index_current].parent_guid != NULL &&
6202                                     GUID_equal(&ar->local_parent_guid,
6203                                                ar->objs->objects[ar->index_current].parent_guid)
6204                                     == false) {
6205                                         DEBUG(4,(__location__ ": Keeping object %s at under %s "
6206                                                  "despite incoming object changing parent to %s\n",
6207                                                  ldb_dn_get_linearized(ar->search_msg->dn),
6208                                                  GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6209                                                  GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6210                                                                  &p_guid_remote)));
6211                                 }
6212                         } else {
6213                                 DEBUG(4,(__location__ ": Keeping object %s at under %s "
6214                                          " and rejecting older rename to %s under %s\n",
6215                                          ldb_dn_get_linearized(ar->search_msg->dn),
6216                                          GUID_buf_string(&ar->local_parent_guid, &p_guid_local),
6217                                          ldb_dn_get_linearized(msg->dn),
6218                                          GUID_buf_string(ar->objs->objects[ar->index_current].parent_guid,
6219                                                          &p_guid_remote)));
6220                         }
6221                         /*
6222                          * This assignment ensures that the strcmp()
6223                          * and GUID_equal() calls in
6224                          * replmd_replicated_apply_merge() avoids the
6225                          * rename call
6226                          */
6227                         ar->objs->objects[ar->index_current].parent_guid =
6228                                 &ar->local_parent_guid;
6229
6230                         msg->dn = ar->search_msg->dn;
6231                         ret = replmd_replicated_apply_merge(ar);
6232                 }
6233                 if (ret != LDB_SUCCESS) {
6234                         return ldb_module_done(ar->req, NULL, NULL, ret);
6235                 }
6236         }
6237         }
6238
6239         talloc_free(ares);
6240         return LDB_SUCCESS;
6241 }
6242
6243 /**
6244  * Stores the linked attributes received in the replication chunk - these get
6245  * applied at the end of the transaction. We also check that each linked
6246  * attribute is valid, i.e. source and target objects are known.
6247  */
6248 static int replmd_store_linked_attributes(struct replmd_replicated_request *ar)
6249 {
6250         int ret = LDB_SUCCESS;
6251         uint32_t i;
6252         struct ldb_module *module = ar->module;
6253         struct replmd_private *replmd_private =
6254                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
6255         struct ldb_context *ldb;
6256
6257         ldb = ldb_module_get_ctx(module);
6258
6259         DEBUG(4,("linked_attributes_count=%u\n", ar->objs->linked_attributes_count));
6260
6261         /* save away the linked attributes for the end of the transaction */
6262         for (i = 0; i < ar->objs->linked_attributes_count; i++) {
6263                 struct la_entry *la_entry;
6264
6265                 if (replmd_private->la_ctx == NULL) {
6266                         replmd_private->la_ctx = talloc_new(replmd_private);
6267                 }
6268                 la_entry = talloc(replmd_private->la_ctx, struct la_entry);
6269                 if (la_entry == NULL) {
6270                         ldb_oom(ldb);
6271                         return LDB_ERR_OPERATIONS_ERROR;
6272                 }
6273                 la_entry->la = talloc(la_entry, struct drsuapi_DsReplicaLinkedAttribute);
6274                 if (la_entry->la == NULL) {
6275                         talloc_free(la_entry);
6276                         ldb_oom(ldb);
6277                         return LDB_ERR_OPERATIONS_ERROR;
6278                 }
6279                 *la_entry->la = ar->objs->linked_attributes[i];
6280                 la_entry->dsdb_repl_flags = ar->objs->dsdb_repl_flags;
6281
6282                 /* we need to steal the non-scalars so they stay
6283                    around until the end of the transaction */
6284                 talloc_steal(la_entry->la, la_entry->la->identifier);
6285                 talloc_steal(la_entry->la, la_entry->la->value.blob);
6286
6287                 ret = replmd_verify_linked_attribute(ar, la_entry);
6288
6289                 if (ret != LDB_SUCCESS) {
6290                         break;
6291                 }
6292
6293                 DLIST_ADD(replmd_private->la_list, la_entry);
6294         }
6295
6296         return ret;
6297 }
6298
6299 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar);
6300
6301 static int replmd_replicated_apply_next(struct replmd_replicated_request *ar)
6302 {
6303         struct ldb_context *ldb;
6304         int ret;
6305         char *tmp_str;
6306         char *filter;
6307         struct ldb_request *search_req;
6308         static const char *attrs[] = { "repsFrom", "replUpToDateVector",
6309                                        "parentGUID", "instanceType",
6310                                        "replPropertyMetaData", "nTSecurityDescriptor",
6311                                        "isDeleted", NULL };
6312         struct GUID_txt_buf guid_str_buf;
6313
6314         if (ar->index_current >= ar->objs->num_objects) {
6315
6316                 /*
6317                  * Now that we've applied all the objects, check the new linked
6318                  * attributes and store them (we apply them in .prepare_commit)
6319                  */
6320                 ret = replmd_store_linked_attributes(ar);
6321
6322                 if (ret != LDB_SUCCESS) {
6323                         return ret;
6324                 }
6325
6326                 /* done applying objects, move on to the next stage */
6327                 return replmd_replicated_uptodate_vector(ar);
6328         }
6329
6330         ldb = ldb_module_get_ctx(ar->module);
6331         ar->search_msg = NULL;
6332         ar->isDeleted = false;
6333
6334         tmp_str = GUID_buf_string(&ar->objs->objects[ar->index_current].object_guid,
6335                                   &guid_str_buf);
6336
6337         filter = talloc_asprintf(ar, "(objectGUID=%s)", tmp_str);
6338         if (!filter) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6339
6340         ret = ldb_build_search_req(&search_req,
6341                                    ldb,
6342                                    ar,
6343                                    ar->objs->partition_dn,
6344                                    LDB_SCOPE_SUBTREE,
6345                                    filter,
6346                                    attrs,
6347                                    NULL,
6348                                    ar,
6349                                    replmd_replicated_apply_search_callback,
6350                                    ar->req);
6351         LDB_REQ_SET_LOCATION(search_req);
6352
6353         ret = dsdb_request_add_controls(search_req, DSDB_SEARCH_SHOW_RECYCLED);
6354
6355         if (ret != LDB_SUCCESS) {
6356                 return ret;
6357         }
6358
6359         return ldb_next_request(ar->module, search_req);
6360 }
6361
6362 /*
6363  * This is essentially a wrapper for replmd_replicated_apply_next()
6364  *
6365  * This is needed to ensure that both codepaths call this handler.
6366  */
6367 static int replmd_replicated_apply_isDeleted(struct replmd_replicated_request *ar)
6368 {
6369         struct ldb_dn *deleted_objects_dn;
6370         struct ldb_message *msg = ar->objs->objects[ar->index_current].msg;
6371         int ret = dsdb_get_deleted_objects_dn(ldb_module_get_ctx(ar->module), msg, msg->dn,
6372                                               &deleted_objects_dn);
6373         if (ar->isDeleted && (ret != LDB_SUCCESS || ldb_dn_compare(msg->dn, deleted_objects_dn) != 0)) {
6374                 /*
6375                  * Do a delete here again, so that if there is
6376                  * anything local that conflicts with this
6377                  * object being deleted, it is removed.  This
6378                  * includes links.  See MS-DRSR 4.1.10.6.9
6379                  * UpdateObject.
6380                  *
6381                  * If the object is already deleted, and there
6382                  * is no more work required, it doesn't do
6383                  * anything.
6384                  */
6385
6386                 /* This has been updated to point to the DN we eventually did the modify on */
6387
6388                 struct ldb_request *del_req;
6389                 struct ldb_result *res;
6390
6391                 TALLOC_CTX *tmp_ctx = talloc_new(ar);
6392                 if (!tmp_ctx) {
6393                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
6394                         return ret;
6395                 }
6396
6397                 res = talloc_zero(tmp_ctx, struct ldb_result);
6398                 if (!res) {
6399                         ret = ldb_oom(ldb_module_get_ctx(ar->module));
6400                         talloc_free(tmp_ctx);
6401                         return ret;
6402                 }
6403
6404                 /* Build a delete request, which hopefully will artually turn into nothing */
6405                 ret = ldb_build_del_req(&del_req, ldb_module_get_ctx(ar->module), tmp_ctx,
6406                                         msg->dn,
6407                                         NULL,
6408                                         res,
6409                                         ldb_modify_default_callback,
6410                                         ar->req);
6411                 LDB_REQ_SET_LOCATION(del_req);
6412                 if (ret != LDB_SUCCESS) {
6413                         talloc_free(tmp_ctx);
6414                         return ret;
6415                 }
6416
6417                 /*
6418                  * This is the guts of the call, call back
6419                  * into our delete code, but setting the
6420                  * re_delete flag so we delete anything that
6421                  * shouldn't be there on a deleted or recycled
6422                  * object
6423                  */
6424                 ret = replmd_delete_internals(ar->module, del_req, true);
6425                 if (ret == LDB_SUCCESS) {
6426                         ret = ldb_wait(del_req->handle, LDB_WAIT_ALL);
6427                 }
6428
6429                 talloc_free(tmp_ctx);
6430                 if (ret != LDB_SUCCESS) {
6431                         return ret;
6432                 }
6433         }
6434
6435         ar->index_current++;
6436         return replmd_replicated_apply_next(ar);
6437 }
6438
6439 static int replmd_replicated_uptodate_modify_callback(struct ldb_request *req,
6440                                                       struct ldb_reply *ares)
6441 {
6442         struct ldb_context *ldb;
6443         struct replmd_replicated_request *ar = talloc_get_type(req->context,
6444                                                struct replmd_replicated_request);
6445         ldb = ldb_module_get_ctx(ar->module);
6446
6447         if (!ares) {
6448                 return ldb_module_done(ar->req, NULL, NULL,
6449                                         LDB_ERR_OPERATIONS_ERROR);
6450         }
6451         if (ares->error != LDB_SUCCESS) {
6452                 return ldb_module_done(ar->req, ares->controls,
6453                                         ares->response, ares->error);
6454         }
6455
6456         if (ares->type != LDB_REPLY_DONE) {
6457                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
6458                 return ldb_module_done(ar->req, NULL, NULL,
6459                                         LDB_ERR_OPERATIONS_ERROR);
6460         }
6461
6462         talloc_free(ares);
6463
6464         return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6465 }
6466
6467 static int replmd_replicated_uptodate_modify(struct replmd_replicated_request *ar)
6468 {
6469         struct ldb_context *ldb;
6470         struct ldb_request *change_req;
6471         enum ndr_err_code ndr_err;
6472         struct ldb_message *msg;
6473         struct replUpToDateVectorBlob ouv;
6474         const struct ldb_val *ouv_value;
6475         const struct drsuapi_DsReplicaCursor2CtrEx *ruv;
6476         struct replUpToDateVectorBlob nuv;
6477         struct ldb_val nuv_value;
6478         struct ldb_message_element *nuv_el = NULL;
6479         struct ldb_message_element *orf_el = NULL;
6480         struct repsFromToBlob nrf;
6481         struct ldb_val *nrf_value = NULL;
6482         struct ldb_message_element *nrf_el = NULL;
6483         unsigned int i;
6484         uint32_t j,ni=0;
6485         bool found = false;
6486         time_t t = time(NULL);
6487         NTTIME now;
6488         int ret;
6489         uint32_t instanceType;
6490
6491         ldb = ldb_module_get_ctx(ar->module);
6492         ruv = ar->objs->uptodateness_vector;
6493         ZERO_STRUCT(ouv);
6494         ouv.version = 2;
6495         ZERO_STRUCT(nuv);
6496         nuv.version = 2;
6497
6498         unix_to_nt_time(&now, t);
6499
6500         if (ar->search_msg == NULL) {
6501                 /* this happens for a REPL_OBJ call where we are
6502                    creating the target object by replicating it. The
6503                    subdomain join code does this for the partition DN
6504                 */
6505                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as no target DN\n"));
6506                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6507         }
6508
6509         instanceType = ldb_msg_find_attr_as_uint(ar->search_msg, "instanceType", 0);
6510         if (! (instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
6511                 DEBUG(4,(__location__ ": Skipping UDV and repsFrom update as not NC root: %s\n",
6512                          ldb_dn_get_linearized(ar->search_msg->dn)));
6513                 return ldb_module_done(ar->req, NULL, NULL, LDB_SUCCESS);
6514         }
6515
6516         /*
6517          * first create the new replUpToDateVector
6518          */
6519         ouv_value = ldb_msg_find_ldb_val(ar->search_msg, "replUpToDateVector");
6520         if (ouv_value) {
6521                 ndr_err = ndr_pull_struct_blob(ouv_value, ar, &ouv,
6522                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
6523                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6524                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6525                         return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6526                 }
6527
6528                 if (ouv.version != 2) {
6529                         return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6530                 }
6531         }
6532
6533         /*
6534          * the new uptodateness vector will at least
6535          * contain 1 entry, one for the source_dsa
6536          *
6537          * plus optional values from our old vector and the one from the source_dsa
6538          */
6539         nuv.ctr.ctr2.count = ouv.ctr.ctr2.count;
6540         if (ruv) nuv.ctr.ctr2.count += ruv->count;
6541         nuv.ctr.ctr2.cursors = talloc_array(ar,
6542                                             struct drsuapi_DsReplicaCursor2,
6543                                             nuv.ctr.ctr2.count);
6544         if (!nuv.ctr.ctr2.cursors) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6545
6546         /* first copy the old vector */
6547         for (i=0; i < ouv.ctr.ctr2.count; i++) {
6548                 nuv.ctr.ctr2.cursors[ni] = ouv.ctr.ctr2.cursors[i];
6549                 ni++;
6550         }
6551
6552         /* merge in the source_dsa vector is available */
6553         for (i=0; (ruv && i < ruv->count); i++) {
6554                 found = false;
6555
6556                 if (GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6557                                &ar->our_invocation_id)) {
6558                         continue;
6559                 }
6560
6561                 for (j=0; j < ni; j++) {
6562                         if (!GUID_equal(&ruv->cursors[i].source_dsa_invocation_id,
6563                                         &nuv.ctr.ctr2.cursors[j].source_dsa_invocation_id)) {
6564                                 continue;
6565                         }
6566
6567                         found = true;
6568
6569                         if (ruv->cursors[i].highest_usn > nuv.ctr.ctr2.cursors[j].highest_usn) {
6570                                 nuv.ctr.ctr2.cursors[j] = ruv->cursors[i];
6571                         }
6572                         break;
6573                 }
6574
6575                 if (found) continue;
6576
6577                 /* if it's not there yet, add it */
6578                 nuv.ctr.ctr2.cursors[ni] = ruv->cursors[i];
6579                 ni++;
6580         }
6581
6582         /*
6583          * finally correct the size of the cursors array
6584          */
6585         nuv.ctr.ctr2.count = ni;
6586
6587         /*
6588          * sort the cursors
6589          */
6590         TYPESAFE_QSORT(nuv.ctr.ctr2.cursors, nuv.ctr.ctr2.count, drsuapi_DsReplicaCursor2_compare);
6591
6592         /*
6593          * create the change ldb_message
6594          */
6595         msg = ldb_msg_new(ar);
6596         if (!msg) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6597         msg->dn = ar->search_msg->dn;
6598
6599         ndr_err = ndr_push_struct_blob(&nuv_value, msg, &nuv,
6600                                        (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
6601         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6602                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6603                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6604         }
6605         ret = ldb_msg_add_value(msg, "replUpToDateVector", &nuv_value, &nuv_el);
6606         if (ret != LDB_SUCCESS) {
6607                 return replmd_replicated_request_error(ar, ret);
6608         }
6609         nuv_el->flags = LDB_FLAG_MOD_REPLACE;
6610
6611         /*
6612          * now create the new repsFrom value from the given repsFromTo1 structure
6613          */
6614         ZERO_STRUCT(nrf);
6615         nrf.version                                     = 1;
6616         nrf.ctr.ctr1                                    = *ar->objs->source_dsa;
6617         nrf.ctr.ctr1.last_attempt                       = now;
6618         nrf.ctr.ctr1.last_success                       = now;
6619         nrf.ctr.ctr1.result_last_attempt                = WERR_OK;
6620
6621         /*
6622          * first see if we already have a repsFrom value for the current source dsa
6623          * if so we'll later replace this value
6624          */
6625         orf_el = ldb_msg_find_element(ar->search_msg, "repsFrom");
6626         if (orf_el) {
6627                 for (i=0; i < orf_el->num_values; i++) {
6628                         struct repsFromToBlob *trf;
6629
6630                         trf = talloc(ar, struct repsFromToBlob);
6631                         if (!trf) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6632
6633                         ndr_err = ndr_pull_struct_blob(&orf_el->values[i], trf, trf,
6634                                                        (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
6635                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6636                                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6637                                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6638                         }
6639
6640                         if (trf->version != 1) {
6641                                 return replmd_replicated_request_werror(ar, WERR_DS_DRA_INTERNAL_ERROR);
6642                         }
6643
6644                         /*
6645                          * we compare the source dsa objectGUID not the invocation_id
6646                          * because we want only one repsFrom value per source dsa
6647                          * and when the invocation_id of the source dsa has changed we don't need
6648                          * the old repsFrom with the old invocation_id
6649                          */
6650                         if (!GUID_equal(&trf->ctr.ctr1.source_dsa_obj_guid,
6651                                         &ar->objs->source_dsa->source_dsa_obj_guid)) {
6652                                 talloc_free(trf);
6653                                 continue;
6654                         }
6655
6656                         talloc_free(trf);
6657                         nrf_value = &orf_el->values[i];
6658                         break;
6659                 }
6660
6661                 /*
6662                  * copy over all old values to the new ldb_message
6663                  */
6664                 ret = ldb_msg_add_empty(msg, "repsFrom", 0, &nrf_el);
6665                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6666                 *nrf_el = *orf_el;
6667         }
6668
6669         /*
6670          * if we haven't found an old repsFrom value for the current source dsa
6671          * we'll add a new value
6672          */
6673         if (!nrf_value) {
6674                 struct ldb_val zero_value;
6675                 ZERO_STRUCT(zero_value);
6676                 ret = ldb_msg_add_value(msg, "repsFrom", &zero_value, &nrf_el);
6677                 if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6678
6679                 nrf_value = &nrf_el->values[nrf_el->num_values - 1];
6680         }
6681
6682         /* we now fill the value which is already attached to ldb_message */
6683         ndr_err = ndr_push_struct_blob(nrf_value, msg,
6684                                        &nrf,
6685                                        (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
6686         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
6687                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
6688                 return replmd_replicated_request_werror(ar, ntstatus_to_werror(nt_status));
6689         }
6690
6691         /*
6692          * the ldb_message_element for the attribute, has all the old values and the new one
6693          * so we'll replace the whole attribute with all values
6694          */
6695         nrf_el->flags = LDB_FLAG_MOD_REPLACE;
6696
6697         if (CHECK_DEBUGLVL(4)) {
6698                 char *s = ldb_ldif_message_redacted_string(ldb, ar,
6699                                                            LDB_CHANGETYPE_MODIFY,
6700                                                            msg);
6701                 DEBUG(4, ("DRS replication uptodate modify message:\n%s\n", s));
6702                 talloc_free(s);
6703         }
6704
6705         /* prepare the ldb_modify() request */
6706         ret = ldb_build_mod_req(&change_req,
6707                                 ldb,
6708                                 ar,
6709                                 msg,
6710                                 ar->controls,
6711                                 ar,
6712                                 replmd_replicated_uptodate_modify_callback,
6713                                 ar->req);
6714         LDB_REQ_SET_LOCATION(change_req);
6715         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6716
6717         return ldb_next_request(ar->module, change_req);
6718 }
6719
6720 static int replmd_replicated_uptodate_search_callback(struct ldb_request *req,
6721                                                       struct ldb_reply *ares)
6722 {
6723         struct replmd_replicated_request *ar = talloc_get_type(req->context,
6724                                                struct replmd_replicated_request);
6725         int ret;
6726
6727         if (!ares) {
6728                 return ldb_module_done(ar->req, NULL, NULL,
6729                                         LDB_ERR_OPERATIONS_ERROR);
6730         }
6731         if (ares->error != LDB_SUCCESS &&
6732             ares->error != LDB_ERR_NO_SUCH_OBJECT) {
6733                 return ldb_module_done(ar->req, ares->controls,
6734                                         ares->response, ares->error);
6735         }
6736
6737         switch (ares->type) {
6738         case LDB_REPLY_ENTRY:
6739                 ar->search_msg = talloc_steal(ar, ares->message);
6740                 break;
6741
6742         case LDB_REPLY_REFERRAL:
6743                 /* we ignore referrals */
6744                 break;
6745
6746         case LDB_REPLY_DONE:
6747                 ret = replmd_replicated_uptodate_modify(ar);
6748                 if (ret != LDB_SUCCESS) {
6749                         return ldb_module_done(ar->req, NULL, NULL, ret);
6750                 }
6751         }
6752
6753         talloc_free(ares);
6754         return LDB_SUCCESS;
6755 }
6756
6757
6758 static int replmd_replicated_uptodate_vector(struct replmd_replicated_request *ar)
6759 {
6760         struct ldb_context *ldb = ldb_module_get_ctx(ar->module);
6761         struct replmd_private *replmd_private =
6762                 talloc_get_type_abort(ldb_module_get_private(ar->module),
6763                 struct replmd_private);
6764         int ret;
6765         static const char *attrs[] = {
6766                 "replUpToDateVector",
6767                 "repsFrom",
6768                 "instanceType",
6769                 NULL
6770         };
6771         struct ldb_request *search_req;
6772
6773         ar->search_msg = NULL;
6774
6775         /*
6776          * Let the caller know that we did an originating updates
6777          */
6778         ar->objs->originating_updates = replmd_private->originating_updates;
6779
6780         ret = ldb_build_search_req(&search_req,
6781                                    ldb,
6782                                    ar,
6783                                    ar->objs->partition_dn,
6784                                    LDB_SCOPE_BASE,
6785                                    "(objectClass=*)",
6786                                    attrs,
6787                                    NULL,
6788                                    ar,
6789                                    replmd_replicated_uptodate_search_callback,
6790                                    ar->req);
6791         LDB_REQ_SET_LOCATION(search_req);
6792         if (ret != LDB_SUCCESS) return replmd_replicated_request_error(ar, ret);
6793
6794         return ldb_next_request(ar->module, search_req);
6795 }
6796
6797
6798
6799 static int replmd_extended_replicated_objects(struct ldb_module *module, struct ldb_request *req)
6800 {
6801         struct ldb_context *ldb;
6802         struct dsdb_extended_replicated_objects *objs;
6803         struct replmd_replicated_request *ar;
6804         struct ldb_control **ctrls;
6805         int ret;
6806
6807         ldb = ldb_module_get_ctx(module);
6808
6809         ldb_debug(ldb, LDB_DEBUG_TRACE, "replmd_extended_replicated_objects\n");
6810
6811         objs = talloc_get_type(req->op.extended.data, struct dsdb_extended_replicated_objects);
6812         if (!objs) {
6813                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: invalid extended data\n");
6814                 return LDB_ERR_PROTOCOL_ERROR;
6815         }
6816
6817         if (objs->version != DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION) {
6818                 ldb_debug(ldb, LDB_DEBUG_FATAL, "replmd_extended_replicated_objects: extended data invalid version [%u != %u]\n",
6819                           objs->version, DSDB_EXTENDED_REPLICATED_OBJECTS_VERSION);
6820                 return LDB_ERR_PROTOCOL_ERROR;
6821         }
6822
6823         ar = replmd_ctx_init(module, req);
6824         if (!ar)
6825                 return LDB_ERR_OPERATIONS_ERROR;
6826
6827         /* Set the flags to have the replmd_op_callback run over the full set of objects */
6828         ar->apply_mode = true;
6829         ar->objs = objs;
6830         ar->schema = dsdb_get_schema(ldb, ar);
6831         if (!ar->schema) {
6832                 ldb_debug_set(ldb, LDB_DEBUG_FATAL, "replmd_ctx_init: no loaded schema found\n");
6833                 talloc_free(ar);
6834                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
6835                 return LDB_ERR_CONSTRAINT_VIOLATION;
6836         }
6837
6838         ctrls = req->controls;
6839
6840         if (req->controls) {
6841                 req->controls = talloc_memdup(ar, req->controls,
6842                                               talloc_get_size(req->controls));
6843                 if (!req->controls) return replmd_replicated_request_werror(ar, WERR_NOT_ENOUGH_MEMORY);
6844         }
6845
6846         ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
6847         if (ret != LDB_SUCCESS) {
6848                 return ret;
6849         }
6850
6851         /* If this change contained linked attributes in the body
6852          * (rather than in the links section) we need to update
6853          * backlinks in linked_attributes */
6854         ret = ldb_request_add_control(req, DSDB_CONTROL_APPLY_LINKS, false, NULL);
6855         if (ret != LDB_SUCCESS) {
6856                 return ret;
6857         }
6858
6859         ar->controls = req->controls;
6860         req->controls = ctrls;
6861
6862         return replmd_replicated_apply_next(ar);
6863 }
6864
6865 /**
6866  * Checks how to handle an missing target - either we need to fail the
6867  * replication and retry with GET_TGT, ignore the link and continue, or try to
6868  * add a partial link to an unknown target.
6869  */
6870 static int replmd_allow_missing_target(struct ldb_module *module,
6871                                        TALLOC_CTX *mem_ctx,
6872                                        struct ldb_dn *target_dn,
6873                                        struct ldb_dn *source_dn,
6874                                        bool is_obj_commit,
6875                                        struct GUID *guid,
6876                                        uint32_t dsdb_repl_flags,
6877                                        bool *ignore_link,
6878                                        const char * missing_str)
6879 {
6880         struct ldb_context *ldb = ldb_module_get_ctx(module);
6881         bool is_in_same_nc;
6882
6883         /*
6884          * we may not be able to resolve link targets properly when
6885          * dealing with subsets of objects, e.g. the source is a
6886          * critical object and the target isn't
6887          *
6888          * TODO:
6889          * When we implement Trusted Domains we need to consider
6890          * whether they get treated as an incomplete replica here or not
6891          */
6892         if (dsdb_repl_flags & DSDB_REPL_FLAG_OBJECT_SUBSET) {
6893
6894                 /*
6895                  * Ignore the link. We don't increase the highwater-mark in
6896                  * the object subset cases, so subsequent replications should
6897                  * resolve any missing links
6898                  */
6899                 DEBUG(2, ("%s target %s linked from %s\n", missing_str,
6900                           ldb_dn_get_linearized(target_dn),
6901                           ldb_dn_get_linearized(source_dn)));
6902                 *ignore_link = true;
6903                 return LDB_SUCCESS;
6904         }
6905
6906         if (dsdb_repl_flags & DSDB_REPL_FLAG_TARGETS_UPTODATE) {
6907
6908                 /*
6909                  * target should already be up-to-date so there's no point in
6910                  * retrying. This could be due to bad timing, or if a target
6911                  * on a one-way link was deleted. We ignore the link rather
6912                  * than failing the replication cycle completely
6913                  */
6914                 *ignore_link = true;
6915                 DBG_WARNING("%s is %s but up to date. Ignoring link from %s\n",
6916                             ldb_dn_get_linearized(target_dn), missing_str,
6917                             ldb_dn_get_linearized(source_dn));
6918                 return LDB_SUCCESS;
6919         }
6920         
6921         is_in_same_nc = dsdb_objects_have_same_nc(ldb,
6922                                                   mem_ctx,
6923                                                   source_dn,
6924                                                   target_dn);
6925         if (is_in_same_nc) {
6926                 /* fail the replication and retry with GET_TGT */
6927                 ldb_asprintf_errstring(ldb, "%s target %s GUID %s linked from %s\n",
6928                                        missing_str,
6929                                        ldb_dn_get_linearized(target_dn),
6930                                        GUID_string(mem_ctx, guid),
6931                                        ldb_dn_get_linearized(source_dn));
6932                 return LDB_ERR_NO_SUCH_OBJECT;
6933         }
6934
6935         /*
6936          * The target of the cross-partition link is missing. Continue
6937          * and try to at least add the forward-link. This isn't great,
6938          * but a partial link can be fixed by dbcheck, so it's better
6939          * than dropping the link completely.
6940          */
6941         *ignore_link = false;
6942
6943         if (is_obj_commit) {
6944
6945                 /*
6946                  * Only log this when we're actually committing the objects.
6947                  * This avoids spurious logs, i.e. if we're just verifying the
6948                  * received link during a join.
6949                  */
6950                 DBG_WARNING("%s cross-partition target %s linked from %s\n",
6951                             missing_str, ldb_dn_get_linearized(target_dn),
6952                             ldb_dn_get_linearized(source_dn));
6953         }
6954         
6955         return LDB_SUCCESS;
6956 }
6957
6958 /**
6959  * Checks that the target object for a linked attribute exists.
6960  * @param guid returns the target object's GUID (is returned)if it exists)
6961  * @param ignore_link set to true if the linked attribute should be ignored
6962  * (i.e. the target doesn't exist, but that it's OK to skip the link)
6963  */
6964 static int replmd_check_target_exists(struct ldb_module *module,
6965                                       struct dsdb_dn *dsdb_dn,
6966                                       struct la_entry *la_entry,
6967                                       struct ldb_dn *source_dn,
6968                                       bool is_obj_commit,
6969                                       struct GUID *guid,
6970                                       bool *ignore_link)
6971 {
6972         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
6973         struct ldb_context *ldb = ldb_module_get_ctx(module);
6974         struct ldb_result *target_res;
6975         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
6976         const char *attrs[] = { "isDeleted", "isRecycled", NULL };
6977         NTSTATUS ntstatus;
6978         int ret;
6979         enum deletion_state target_deletion_state = OBJECT_REMOVED;
6980         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE) ? true : false;
6981
6982         *ignore_link = false;
6983         ntstatus = dsdb_get_extended_dn_guid(dsdb_dn->dn, guid, "GUID");
6984
6985         if (!NT_STATUS_IS_OK(ntstatus) && !active) {
6986
6987                 /*
6988                  * This strange behaviour (allowing a NULL/missing
6989                  * GUID) originally comes from:
6990                  *
6991                  * commit e3054ce0fe0f8f62d2f5b2a77893e7a1479128bd
6992                  * Author: Andrew Tridgell <tridge@samba.org>
6993                  * Date:   Mon Dec 21 21:21:55 2009 +1100
6994                  *
6995                  *  s4-drs: cope better with NULL GUIDS from DRS
6996                  *
6997                  *  It is valid to get a NULL GUID over DRS for a deleted forward link. We
6998                  *  need to match by DN if possible when seeing if we should update an
6999                  *  existing link.
7000                  *
7001                  *  Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>
7002                  */
7003                 ret = dsdb_module_search_dn(module, tmp_ctx, &target_res,
7004                                             dsdb_dn->dn, attrs,
7005                                             DSDB_FLAG_NEXT_MODULE |
7006                                             DSDB_SEARCH_SHOW_RECYCLED |
7007                                             DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7008                                             DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7009                                             NULL);
7010         } else if (!NT_STATUS_IS_OK(ntstatus)) {
7011                 ldb_asprintf_errstring(ldb, "Failed to find GUID in linked attribute 0x%x blob for %s from %s",
7012                                        la->attid,
7013                                        ldb_dn_get_linearized(dsdb_dn->dn),
7014                                        ldb_dn_get_linearized(source_dn));
7015                 talloc_free(tmp_ctx);
7016                 return LDB_ERR_OPERATIONS_ERROR;
7017         } else {
7018                 ret = dsdb_module_search(module, tmp_ctx, &target_res,
7019                                          NULL, LDB_SCOPE_SUBTREE,
7020                                          attrs,
7021                                          DSDB_FLAG_NEXT_MODULE |
7022                                          DSDB_SEARCH_SHOW_RECYCLED |
7023                                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7024                                          DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT,
7025                                          NULL,
7026                                          "objectGUID=%s",
7027                                          GUID_string(tmp_ctx, guid));
7028         }
7029
7030         if (ret != LDB_SUCCESS) {
7031                 ldb_asprintf_errstring(ldb, "Failed to re-resolve GUID %s: %s\n",
7032                                        GUID_string(tmp_ctx, guid),
7033                                        ldb_errstring(ldb));
7034                 talloc_free(tmp_ctx);
7035                 return ret;
7036         }
7037
7038         if (target_res->count == 0) {
7039
7040                 /*
7041                  * target object is unknown. Check whether to ignore the link,
7042                  * fail the replication, or add a partial link
7043                  */
7044                 ret = replmd_allow_missing_target(module, tmp_ctx, dsdb_dn->dn,
7045                                                   source_dn, is_obj_commit, guid,
7046                                                   la_entry->dsdb_repl_flags,
7047                                                   ignore_link, "Unknown");
7048
7049         } else if (target_res->count != 1) {
7050                 ldb_asprintf_errstring(ldb, "More than one object found matching objectGUID %s\n",
7051                                        GUID_string(tmp_ctx, guid));
7052                 ret = LDB_ERR_OPERATIONS_ERROR;
7053         } else {
7054                 struct ldb_message *target_msg = target_res->msgs[0];
7055
7056                 dsdb_dn->dn = talloc_steal(dsdb_dn, target_msg->dn);
7057
7058                 /* Get the object's state (i.e. Not Deleted, Tombstone, etc) */
7059                 replmd_deletion_state(module, target_msg,
7060                                       &target_deletion_state, NULL);
7061
7062                 /*
7063                  * Check for deleted objects as per MS-DRSR 4.1.10.6.14
7064                  * ProcessLinkValue(). Link updates should not be sent for
7065                  * recycled and tombstone objects (deleting the links should
7066                  * happen when we delete the object). This probably means our
7067                  * copy of the target object isn't up to date.
7068                  */
7069                 if (target_deletion_state >= OBJECT_RECYCLED) {
7070
7071                         /*
7072                          * target object is deleted. Check whether to ignore the
7073                          * link, fail the replication, or add a partial link
7074                          */
7075                         ret = replmd_allow_missing_target(module, tmp_ctx,
7076                                                           dsdb_dn->dn, source_dn,
7077                                                           is_obj_commit, guid,
7078                                                           la_entry->dsdb_repl_flags,
7079                                                           ignore_link, "Deleted");
7080                 }
7081         }
7082
7083         talloc_free(tmp_ctx);
7084         return ret;
7085 }
7086
7087 /**
7088  * Extracts the key details about the source/target object for a
7089  * linked-attribute entry.
7090  * This returns the following details:
7091  * @param ret_attr the schema details for the linked attribute
7092  * @param source_msg the search result for the source object
7093  * @param target_dsdb_dn the unpacked DN info for the target object
7094  */
7095 static int replmd_extract_la_entry_details(struct ldb_module *module,
7096                                            struct la_entry *la_entry,
7097                                            TALLOC_CTX *mem_ctx,
7098                                            const struct dsdb_attribute **ret_attr,
7099                                            struct ldb_message **source_msg,
7100                                            struct dsdb_dn **target_dsdb_dn)
7101 {
7102         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7103         struct ldb_context *ldb = ldb_module_get_ctx(module);
7104         const struct dsdb_schema *schema = dsdb_get_schema(ldb, mem_ctx);
7105         int ret;
7106         const struct dsdb_attribute *attr;
7107         WERROR status;
7108         struct ldb_result *res;
7109         const char *attrs[4];
7110
7111 /*
7112 linked_attributes[0]:
7113      &objs->linked_attributes[i]: struct drsuapi_DsReplicaLinkedAttribute
7114         identifier               : *
7115             identifier: struct drsuapi_DsReplicaObjectIdentifier
7116                 __ndr_size               : 0x0000003a (58)
7117                 __ndr_size_sid           : 0x00000000 (0)
7118                 guid                     : 8e95b6a9-13dd-4158-89db-3220a5be5cc7
7119                 sid                      : S-0-0
7120                 __ndr_size_dn            : 0x00000000 (0)
7121                 dn                       : ''
7122         attid                    : DRSUAPI_ATTID_member (0x1F)
7123         value: struct drsuapi_DsAttributeValue
7124             __ndr_size               : 0x0000007e (126)
7125             blob                     : *
7126                 blob                     : DATA_BLOB length=126
7127         flags                    : 0x00000001 (1)
7128                1: DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE
7129         originating_add_time     : Wed Sep  2 22:20:01 2009 EST
7130         meta_data: struct drsuapi_DsReplicaMetaData
7131             version                  : 0x00000015 (21)
7132             originating_change_time  : Wed Sep  2 23:39:07 2009 EST
7133             originating_invocation_id: 794640f3-18cf-40ee-a211-a93992b67a64
7134             originating_usn          : 0x000000000001e19c (123292)
7135
7136 (for cases where the link is to a normal DN)
7137      &target: struct drsuapi_DsReplicaObjectIdentifier3
7138         __ndr_size               : 0x0000007e (126)
7139         __ndr_size_sid           : 0x0000001c (28)
7140         guid                     : 7639e594-db75-4086-b0d4-67890ae46031
7141         sid                      : S-1-5-21-2848215498-2472035911-1947525656-19924
7142         __ndr_size_dn            : 0x00000022 (34)
7143         dn                       : 'CN=UOne,OU=TestOU,DC=vsofs8,DC=com'
7144  */
7145
7146         /* find the attribute being modified */
7147         attr = dsdb_attribute_by_attributeID_id(schema, la->attid);
7148         if (attr == NULL) {
7149                 struct GUID_txt_buf guid_str;
7150                 ldb_asprintf_errstring(ldb, "Unable to find attributeID 0x%x for link on <GUID=%s>",
7151                                        la->attid,
7152                                        GUID_buf_string(&la->identifier->guid,
7153                                                        &guid_str));
7154                 return LDB_ERR_OPERATIONS_ERROR;
7155         }
7156
7157         attrs[0] = attr->lDAPDisplayName;
7158         attrs[1] = "isDeleted";
7159         attrs[2] = "isRecycled";
7160         attrs[3] = NULL;
7161
7162         /*
7163          * get the existing message from the db for the object with
7164          * this GUID, returning attribute being modified. We will then
7165          * use this msg as the basis for a modify call
7166          */
7167         ret = dsdb_module_search(module, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
7168                                  DSDB_FLAG_NEXT_MODULE |
7169                                  DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
7170                                  DSDB_SEARCH_SHOW_RECYCLED |
7171                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT |
7172                                  DSDB_SEARCH_REVEAL_INTERNALS,
7173                                  NULL,
7174                                  "objectGUID=%s", GUID_string(mem_ctx, &la->identifier->guid));
7175         if (ret != LDB_SUCCESS) {
7176                 return ret;
7177         }
7178         if (res->count != 1) {
7179                 ldb_asprintf_errstring(ldb, "DRS linked attribute for GUID %s - DN not found",
7180                                        GUID_string(mem_ctx, &la->identifier->guid));
7181                 return LDB_ERR_NO_SUCH_OBJECT;
7182         }
7183
7184         *source_msg = res->msgs[0];
7185
7186         /* the value blob for the attribute holds the target object DN */
7187         status = dsdb_dn_la_from_blob(ldb, attr, schema, mem_ctx, la->value.blob, target_dsdb_dn);
7188         if (!W_ERROR_IS_OK(status)) {
7189                 ldb_asprintf_errstring(ldb, "Failed to parsed linked attribute blob for %s on %s - %s\n",
7190                                        attr->lDAPDisplayName,
7191                                        ldb_dn_get_linearized(res->msgs[0]->dn),
7192                                        win_errstr(status));
7193                 return LDB_ERR_OPERATIONS_ERROR;
7194         }
7195
7196         *ret_attr = attr;
7197
7198         return LDB_SUCCESS;
7199 }
7200
7201 /**
7202  * Verifies the source and target objects are known for a linked attribute
7203  */
7204 static int replmd_verify_linked_attribute(struct replmd_replicated_request *ar,
7205                                           struct la_entry *la)
7206 {
7207         int ret = LDB_SUCCESS;
7208         TALLOC_CTX *tmp_ctx = talloc_new(la);
7209         struct ldb_module *module = ar->module;
7210         struct ldb_message *src_msg;
7211         const struct dsdb_attribute *attr;
7212         struct dsdb_dn *tgt_dsdb_dn;
7213         struct GUID guid = GUID_zero();
7214         bool dummy;
7215
7216         ret = replmd_extract_la_entry_details(module, la, tmp_ctx, &attr,
7217                                               &src_msg, &tgt_dsdb_dn);
7218
7219         /*
7220          * When we fail to find the source object, the error code we pass
7221          * back here is really important. It flags back to the callers to
7222          * retry this request with DRSUAPI_DRS_GET_ANC. This case should
7223          * never happen if we're replicating from a Samba DC, but it is
7224          * needed to talk to a Windows DC
7225          */
7226         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7227                 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_MISSING_PARENT);
7228         }
7229
7230         if (ret != LDB_SUCCESS) {
7231                 talloc_free(tmp_ctx);
7232                 return ret;
7233         }
7234
7235         /*
7236          * We can skip the target object checks if we're only syncing critical
7237          * objects, or we know the target is up-to-date. If either case, we
7238          * still continue even if the target doesn't exist
7239          */
7240         if ((la->dsdb_repl_flags & (DSDB_REPL_FLAG_OBJECT_SUBSET |
7241                                     DSDB_REPL_FLAG_TARGETS_UPTODATE)) == 0) {
7242
7243                 ret = replmd_check_target_exists(module, tgt_dsdb_dn, la,
7244                                                  src_msg->dn, false, &guid,
7245                                                  &dummy);
7246         }
7247
7248         /*
7249          * When we fail to find the target object, the error code we pass
7250          * back here is really important. It flags back to the callers to
7251          * retry this request with DRSUAPI_DRS_GET_TGT
7252          */
7253         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
7254                 ret = replmd_replicated_request_werror(ar, WERR_DS_DRA_RECYCLED_TARGET);
7255         }
7256
7257         talloc_free(tmp_ctx);
7258         return ret;
7259 }
7260
7261 /**
7262  * Finds the current active Parsed-DN value for a single-valued linked
7263  * attribute, if one exists.
7264  * @param ret_pdn assigned the active Parsed-DN, or NULL if none was found
7265  * @returns LDB_SUCCESS (regardless of whether a match was found), unless
7266  * an error occurred
7267  */
7268 static int replmd_get_active_singleval_link(struct ldb_module *module,
7269                                             TALLOC_CTX *mem_ctx,
7270                                             struct parsed_dn pdn_list[],
7271                                             unsigned int count,
7272                                             const struct dsdb_attribute *attr,
7273                                             struct parsed_dn **ret_pdn)
7274 {
7275         unsigned int i;
7276
7277         *ret_pdn = NULL;
7278
7279         if (!(attr->ldb_schema_attribute->flags & LDB_ATTR_FLAG_SINGLE_VALUE)) {
7280
7281                 /* nothing to do for multi-valued linked attributes */
7282                 return LDB_SUCCESS;
7283         }
7284
7285         for (i = 0; i < count; i++) {
7286                 int ret = LDB_SUCCESS;
7287                 struct parsed_dn *pdn = &pdn_list[i];
7288
7289                 /* skip any inactive links */
7290                 if (dsdb_dn_is_deleted_val(pdn->v)) {
7291                         continue;
7292                 }
7293
7294                 /* we've found an active value for this attribute */
7295                 *ret_pdn = pdn;
7296
7297                 if (pdn->dsdb_dn == NULL) {
7298                         struct ldb_context *ldb = ldb_module_get_ctx(module);
7299
7300                         ret = really_parse_trusted_dn(mem_ctx, ldb, pdn,
7301                                                       attr->syntax->ldap_oid);
7302                 }
7303
7304                 return ret;
7305         }
7306
7307         /* no active link found */
7308         return LDB_SUCCESS;
7309 }
7310
7311 /**
7312  * @returns true if the replication linked attribute info is newer than we
7313  * already have in our DB
7314  * @param pdn the existing linked attribute info in our DB
7315  * @param la the new linked attribute info received during replication
7316  */
7317 static bool replmd_link_update_is_newer(struct parsed_dn *pdn,
7318                                         struct drsuapi_DsReplicaLinkedAttribute *la)
7319 {
7320         /* see if this update is newer than what we have already */
7321         struct GUID invocation_id = GUID_zero();
7322         uint32_t version = 0;
7323         NTTIME change_time = 0;
7324
7325         if (pdn == NULL) {
7326
7327                 /* no existing info so update is newer */
7328                 return true;
7329         }
7330
7331         dsdb_get_extended_dn_guid(pdn->dsdb_dn->dn, &invocation_id, "RMD_INVOCID");
7332         dsdb_get_extended_dn_uint32(pdn->dsdb_dn->dn, &version, "RMD_VERSION");
7333         dsdb_get_extended_dn_nttime(pdn->dsdb_dn->dn, &change_time, "RMD_CHANGETIME");
7334
7335         return replmd_update_is_newer(&invocation_id,
7336                                       &la->meta_data.originating_invocation_id,
7337                                       version,
7338                                       la->meta_data.version,
7339                                       change_time,
7340                                       la->meta_data.originating_change_time);
7341 }
7342
7343 /**
7344  * Marks an existing linked attribute value as deleted in the DB
7345  * @param pdn the parsed-DN of the target-value to delete
7346  */
7347 static int replmd_delete_link_value(struct ldb_module *module,
7348                                     struct replmd_private *replmd_private,
7349                                     TALLOC_CTX *mem_ctx,
7350                                     struct ldb_dn *src_obj_dn,
7351                                     const struct dsdb_schema *schema,
7352                                     const struct dsdb_attribute *attr,
7353                                     uint64_t seq_num,
7354                                     bool is_active,
7355                                     struct GUID *target_guid,
7356                                     struct dsdb_dn *target_dsdb_dn,
7357                                     struct ldb_val *output_val)
7358 {
7359         struct ldb_context *ldb = ldb_module_get_ctx(module);
7360         time_t t;
7361         NTTIME now;
7362         const struct GUID *invocation_id = NULL;
7363         int ret;
7364
7365         t = time(NULL);
7366         unix_to_nt_time(&now, t);
7367
7368         invocation_id = samdb_ntds_invocation_id(ldb);
7369         if (invocation_id == NULL) {
7370                 return LDB_ERR_OPERATIONS_ERROR;
7371         }
7372
7373         /* if the existing link is active, remove its backlink */
7374         if (is_active) {
7375
7376                 ret = replmd_add_backlink(module, replmd_private, schema,
7377                                           src_obj_dn, target_guid, false,
7378                                           attr, NULL);
7379                 if (ret != LDB_SUCCESS) {
7380                         return ret;
7381                 }
7382         }
7383
7384         /* mark the existing value as deleted */
7385         ret = replmd_update_la_val(mem_ctx, output_val, target_dsdb_dn,
7386                                    target_dsdb_dn, invocation_id, seq_num,
7387                                    seq_num, now, true);
7388         return ret;
7389 }
7390
7391 /**
7392  * Checks for a conflict in single-valued link attributes, and tries to
7393  * resolve the problem if possible.
7394  *
7395  * Single-valued links should only ever have one active value. If we already
7396  * have an active link value, and during replication we receive an active link
7397  * value for a different target DN, then we need to resolve this inconsistency
7398  * and determine which value should be active. If the received info is better/
7399  * newer than the existing link attribute, then we need to set our existing
7400  * link as deleted. If the received info is worse/older, then we should continue
7401  * to add it, but set it as an inactive link.
7402  *
7403  * Note that this is a corner-case that is unlikely to happen (but if it does
7404  * happen, we don't want it to break replication completely).
7405  *
7406  * @param pdn_being_modified the parsed DN corresponding to the received link
7407  * target (note this is NULL if the link does not already exist in our DB)
7408  * @param pdn_list all the source object's Parsed-DNs for this attribute, i.e.
7409  * any existing active or inactive values for the attribute in our DB.
7410  * @param dsdb_dn the target DN for the received link attribute
7411  * @param add_as_inactive gets set to true if the received link is worse than
7412  * the existing link - it should still be added, but as an inactive link.
7413  */
7414 static int replmd_check_singleval_la_conflict(struct ldb_module *module,
7415                                               struct replmd_private *replmd_private,
7416                                               TALLOC_CTX *mem_ctx,
7417                                               struct ldb_dn *src_obj_dn,
7418                                               struct drsuapi_DsReplicaLinkedAttribute *la,
7419                                               struct dsdb_dn *dsdb_dn,
7420                                               struct parsed_dn *pdn_being_modified,
7421                                               struct parsed_dn *pdn_list,
7422                                               struct ldb_message_element *old_el,
7423                                               const struct dsdb_schema *schema,
7424                                               const struct dsdb_attribute *attr,
7425                                               uint64_t seq_num,
7426                                               bool *add_as_inactive)
7427 {
7428         struct parsed_dn *active_pdn = NULL;
7429         bool update_is_newer = false;
7430         int ret;
7431
7432         /*
7433          * check if there's a conflict for single-valued links, i.e. an active
7434          * linked attribute already exists, but it has a different target value
7435          */
7436         ret = replmd_get_active_singleval_link(module, mem_ctx, pdn_list,
7437                                                old_el->num_values, attr,
7438                                                &active_pdn);
7439
7440         if (ret != LDB_SUCCESS) {
7441                 return ret;
7442         }
7443
7444         /*
7445          * If no active value exists (or the received info is for the currently
7446          * active value), then no conflict exists
7447          */
7448         if (active_pdn == NULL || active_pdn == pdn_being_modified) {
7449                 return LDB_SUCCESS;
7450         }
7451
7452         DBG_WARNING("Link conflict for %s attribute on %s\n",
7453                     attr->lDAPDisplayName, ldb_dn_get_linearized(src_obj_dn));
7454
7455         /* Work out how to resolve the conflict based on which info is better */
7456         update_is_newer = replmd_link_update_is_newer(active_pdn, la);
7457
7458         if (update_is_newer) {
7459                 DBG_WARNING("Using received value %s, over existing target %s\n",
7460                             ldb_dn_get_linearized(dsdb_dn->dn),
7461                             ldb_dn_get_linearized(active_pdn->dsdb_dn->dn));
7462
7463                 /*
7464                  * Delete our existing active link. The received info will then
7465                  * be added (through normal link processing) as the active value
7466                  */
7467                 ret = replmd_delete_link_value(module, replmd_private, old_el,
7468                                                src_obj_dn, schema, attr,
7469                                                seq_num, true, &active_pdn->guid,
7470                                                active_pdn->dsdb_dn,
7471                                                active_pdn->v);
7472
7473                 if (ret != LDB_SUCCESS) {
7474                         return ret;
7475                 }
7476         } else {
7477                 DBG_WARNING("Using existing target %s, over received value %s\n",
7478                             ldb_dn_get_linearized(active_pdn->dsdb_dn->dn),
7479                             ldb_dn_get_linearized(dsdb_dn->dn));
7480
7481                 /*
7482                  * we want to keep our existing active link and add the
7483                  * received link as inactive
7484                  */
7485                 *add_as_inactive = true;
7486         }
7487
7488         return LDB_SUCCESS;
7489 }
7490
7491 /*
7492   process one linked attribute structure
7493  */
7494 static int replmd_process_linked_attribute(struct ldb_module *module,
7495                                            struct replmd_private *replmd_private,
7496                                            struct la_entry *la_entry,
7497                                            struct ldb_request *parent)
7498 {
7499         struct drsuapi_DsReplicaLinkedAttribute *la = la_entry->la;
7500         struct ldb_context *ldb = ldb_module_get_ctx(module);
7501         struct ldb_message *msg;
7502         TALLOC_CTX *tmp_ctx = talloc_new(la_entry);
7503         const struct dsdb_schema *schema = dsdb_get_schema(ldb, tmp_ctx);
7504         int ret;
7505         const struct dsdb_attribute *attr;
7506         struct dsdb_dn *dsdb_dn;
7507         uint64_t seq_num = 0;
7508         struct ldb_message_element *old_el;
7509         time_t t = time(NULL);
7510         struct parsed_dn *pdn_list, *pdn, *next;
7511         struct GUID guid = GUID_zero();
7512         bool active = (la->flags & DRSUAPI_DS_LINKED_ATTRIBUTE_FLAG_ACTIVE)?true:false;
7513         bool ignore_link;
7514         enum deletion_state deletion_state = OBJECT_NOT_DELETED;
7515         struct dsdb_dn *old_dsdb_dn = NULL;
7516         struct ldb_val *val_to_update = NULL;
7517         bool add_as_inactive = false;
7518
7519         /*
7520          * get the attribute being modified, the search result for the source object,
7521          * and the target object's DN details
7522          */
7523         ret = replmd_extract_la_entry_details(module, la_entry, tmp_ctx, &attr,
7524                                               &msg, &dsdb_dn);
7525
7526         if (ret != LDB_SUCCESS) {
7527                 talloc_free(tmp_ctx);
7528                 return ret;
7529         }
7530
7531         /*
7532          * Check for deleted objects per MS-DRSR 4.1.10.6.14
7533          * ProcessLinkValue, because link updates are not applied to
7534          * recycled and tombstone objects.  We don't have to delete
7535          * any existing link, that should have happened when the
7536          * object deletion was replicated or initiated.
7537          */
7538         replmd_deletion_state(module, msg, &deletion_state, NULL);
7539
7540         if (deletion_state >= OBJECT_RECYCLED) {
7541                 talloc_free(tmp_ctx);
7542                 return LDB_SUCCESS;
7543         }
7544
7545         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7546         if (old_el == NULL) {
7547                 ret = ldb_msg_add_empty(msg, attr->lDAPDisplayName, LDB_FLAG_MOD_REPLACE, &old_el);
7548                 if (ret != LDB_SUCCESS) {
7549                         ldb_module_oom(module);
7550                         talloc_free(tmp_ctx);
7551                         return LDB_ERR_OPERATIONS_ERROR;
7552                 }
7553         } else {
7554                 old_el->flags = LDB_FLAG_MOD_REPLACE;
7555         }
7556
7557         /* parse the existing links */
7558         ret = get_parsed_dns_trusted(module, replmd_private, tmp_ctx, old_el, &pdn_list,
7559                                      attr->syntax->ldap_oid, parent);
7560
7561         if (ret != LDB_SUCCESS) {
7562                 talloc_free(tmp_ctx);
7563                 return ret;
7564         }
7565
7566         ret = replmd_check_target_exists(module, dsdb_dn, la_entry, msg->dn,
7567                                          true, &guid, &ignore_link);
7568
7569         if (ret != LDB_SUCCESS) {
7570                 talloc_free(tmp_ctx);
7571                 return ret;
7572         }
7573
7574         /*
7575          * there are some cases where the target object doesn't exist, but it's
7576          * OK to ignore the linked attribute
7577          */
7578         if (ignore_link) {
7579                 talloc_free(tmp_ctx);
7580                 return ret;
7581         }
7582
7583         /* see if this link already exists */
7584         ret = parsed_dn_find(ldb, pdn_list, old_el->num_values,
7585                              &guid,
7586                              dsdb_dn->dn,
7587                              dsdb_dn->extra_part, 0,
7588                              &pdn, &next,
7589                              attr->syntax->ldap_oid,
7590                              true);
7591         if (ret != LDB_SUCCESS) {
7592                 talloc_free(tmp_ctx);
7593                 return ret;
7594         }
7595
7596         if (!replmd_link_update_is_newer(pdn, la)) {
7597                 DEBUG(3,("Discarding older DRS linked attribute update to %s on %s from %s\n",
7598                          old_el->name, ldb_dn_get_linearized(msg->dn),
7599                          GUID_string(tmp_ctx, &la->meta_data.originating_invocation_id)));
7600                 talloc_free(tmp_ctx);
7601                 return LDB_SUCCESS;
7602         }
7603
7604         /* get a seq_num for this change */
7605         ret = ldb_sequence_number(ldb, LDB_SEQ_NEXT, &seq_num);
7606         if (ret != LDB_SUCCESS) {
7607                 talloc_free(tmp_ctx);
7608                 return ret;
7609         }
7610
7611         /*
7612          * check for single-valued link conflicts, i.e. an active linked
7613          * attribute already exists, but it has a different target value
7614          */
7615         if (active) {
7616                 ret = replmd_check_singleval_la_conflict(module, replmd_private,
7617                                                          tmp_ctx, msg->dn, la,
7618                                                          dsdb_dn, pdn, pdn_list,
7619                                                          old_el, schema, attr,
7620                                                          seq_num,
7621                                                          &add_as_inactive);
7622                 if (ret != LDB_SUCCESS) {
7623                         talloc_free(tmp_ctx);
7624                         return ret;
7625                 }
7626         }
7627
7628         if (pdn != NULL) {
7629                 uint32_t rmd_flags = dsdb_dn_rmd_flags(pdn->dsdb_dn->dn);
7630
7631                 if (!(rmd_flags & DSDB_RMD_FLAG_DELETED)) {
7632                         /* remove the existing backlink */
7633                         ret = replmd_add_backlink(module, replmd_private,
7634                                                   schema, 
7635                                                   msg->dn,
7636                                                   &pdn->guid, false, attr,
7637                                                   parent);
7638                         if (ret != LDB_SUCCESS) {
7639                                 talloc_free(tmp_ctx);
7640                                 return ret;
7641                         }
7642                 }
7643
7644                 val_to_update = pdn->v;
7645                 old_dsdb_dn = pdn->dsdb_dn;
7646
7647         } else {
7648                 unsigned offset;
7649
7650                 /*
7651                  * We know where the new one needs to be, from the *next
7652                  * pointer into pdn_list.
7653                  */
7654                 if (next == NULL) {
7655                         offset = old_el->num_values;
7656                 } else {
7657                         if (next->dsdb_dn == NULL) {
7658                                 ret = really_parse_trusted_dn(tmp_ctx, ldb, next,
7659                                                               attr->syntax->ldap_oid);
7660                                 if (ret != LDB_SUCCESS) {
7661                                         return ret;
7662                                 }
7663                         }
7664                         offset = next - pdn_list;
7665                         if (offset > old_el->num_values) {
7666                                 talloc_free(tmp_ctx);
7667                                 return LDB_ERR_OPERATIONS_ERROR;
7668                         }
7669                 }
7670
7671                 old_el->values = talloc_realloc(msg->elements, old_el->values,
7672                                                 struct ldb_val, old_el->num_values+1);
7673                 if (!old_el->values) {
7674                         ldb_module_oom(module);
7675                         return LDB_ERR_OPERATIONS_ERROR;
7676                 }
7677
7678                 if (offset != old_el->num_values) {
7679                         memmove(&old_el->values[offset + 1], &old_el->values[offset],
7680                                 (old_el->num_values - offset) * sizeof(old_el->values[0]));
7681                 }
7682
7683                 old_el->num_values++;
7684
7685                 val_to_update = &old_el->values[offset];
7686                 old_dsdb_dn = NULL;
7687         }
7688
7689         /* set the link attribute's value to the info that was received */
7690         ret = replmd_set_la_val(tmp_ctx, val_to_update, dsdb_dn, old_dsdb_dn,
7691                                 &la->meta_data.originating_invocation_id,
7692                                 la->meta_data.originating_usn, seq_num,
7693                                 la->meta_data.originating_change_time,
7694                                 la->meta_data.version,
7695                                 !active);
7696         if (ret != LDB_SUCCESS) {
7697                 talloc_free(tmp_ctx);
7698                 return ret;
7699         }
7700
7701         if (add_as_inactive) {
7702
7703                 /* Set the new link as inactive/deleted to avoid conflicts */
7704                 ret = replmd_delete_link_value(module, replmd_private, old_el,
7705                                                msg->dn, schema, attr, seq_num,
7706                                                false, &guid, dsdb_dn,
7707                                                val_to_update);
7708
7709                 if (ret != LDB_SUCCESS) {
7710                         talloc_free(tmp_ctx);
7711                         return ret;
7712                 }
7713
7714         } else if (active) {
7715
7716                 /* if the new link is active, then add the new backlink */
7717                 ret = replmd_add_backlink(module, replmd_private,
7718                                           schema,
7719                                           msg->dn,
7720                                           &guid, true, attr,
7721                                           parent);
7722                 if (ret != LDB_SUCCESS) {
7723                         talloc_free(tmp_ctx);
7724                         return ret;
7725                 }
7726         }
7727
7728         /* we only change whenChanged and uSNChanged if the seq_num
7729            has changed */
7730         ret = add_time_element(msg, "whenChanged", t);
7731         if (ret != LDB_SUCCESS) {
7732                 talloc_free(tmp_ctx);
7733                 ldb_operr(ldb);
7734                 return ret;
7735         }
7736
7737         ret = add_uint64_element(ldb, msg, "uSNChanged", seq_num);
7738         if (ret != LDB_SUCCESS) {
7739                 talloc_free(tmp_ctx);
7740                 ldb_operr(ldb);
7741                 return ret;
7742         }
7743
7744         old_el = ldb_msg_find_element(msg, attr->lDAPDisplayName);
7745         if (old_el == NULL) {
7746                 talloc_free(tmp_ctx);
7747                 return ldb_operr(ldb);
7748         }
7749
7750         ret = dsdb_check_single_valued_link(attr, old_el);
7751         if (ret != LDB_SUCCESS) {
7752                 talloc_free(tmp_ctx);
7753                 return ret;
7754         }
7755
7756         old_el->flags |= LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK;
7757
7758         ret = linked_attr_modify(module, msg, parent);
7759         if (ret != LDB_SUCCESS) {
7760                 ldb_debug(ldb, LDB_DEBUG_WARNING, "Failed to apply linked attribute change '%s'\n%s\n",
7761                           ldb_errstring(ldb),
7762                           ldb_ldif_message_redacted_string(ldb,
7763                                                            tmp_ctx,
7764                                                            LDB_CHANGETYPE_MODIFY,
7765                                                            msg));
7766                 talloc_free(tmp_ctx);
7767                 return ret;
7768         }
7769
7770         talloc_free(tmp_ctx);
7771
7772         return ret;
7773 }
7774
7775 static int replmd_extended(struct ldb_module *module, struct ldb_request *req)
7776 {
7777         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_REPLICATED_OBJECTS_OID) == 0) {
7778                 return replmd_extended_replicated_objects(module, req);
7779         }
7780
7781         return ldb_next_request(module, req);
7782 }
7783
7784
7785 /*
7786   we hook into the transaction operations to allow us to
7787   perform the linked attribute updates at the end of the whole
7788   transaction. This allows a forward linked attribute to be created
7789   before the object is created. During a vampire, w2k8 sends us linked
7790   attributes before the objects they are part of.
7791  */
7792 static int replmd_start_transaction(struct ldb_module *module)
7793 {
7794         /* create our private structure for this transaction */
7795         struct replmd_private *replmd_private = talloc_get_type(ldb_module_get_private(module),
7796                                                                 struct replmd_private);
7797         replmd_txn_cleanup(replmd_private);
7798
7799         /* free any leftover mod_usn records from cancelled
7800            transactions */
7801         while (replmd_private->ncs) {
7802                 struct nc_entry *e = replmd_private->ncs;
7803                 DLIST_REMOVE(replmd_private->ncs, e);
7804                 talloc_free(e);
7805         }
7806
7807         replmd_private->originating_updates = false;
7808
7809         return ldb_next_start_trans(module);
7810 }
7811
7812 /*
7813   on prepare commit we loop over our queued la_context structures and
7814   apply each of them
7815  */
7816 static int replmd_prepare_commit(struct ldb_module *module)
7817 {
7818         struct replmd_private *replmd_private =
7819                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7820         struct la_entry *la, *prev;
7821         int ret;
7822
7823         /*
7824          * Walk the list of linked attributes from DRS replication.
7825          *
7826          * We walk backwards, to do the first entry first, as we
7827          * added the entries with DLIST_ADD() which puts them at the
7828          * start of the list
7829          */
7830         for (la = DLIST_TAIL(replmd_private->la_list); la; la=prev) {
7831                 prev = DLIST_PREV(la);
7832                 DLIST_REMOVE(replmd_private->la_list, la);
7833                 ret = replmd_process_linked_attribute(module, replmd_private,
7834                                                       la, NULL);
7835                 if (ret != LDB_SUCCESS) {
7836                         replmd_txn_cleanup(replmd_private);
7837                         return ret;
7838                 }
7839         }
7840
7841         replmd_txn_cleanup(replmd_private);
7842
7843         /* possibly change @REPLCHANGED */
7844         ret = replmd_notify_store(module, NULL);
7845         if (ret != LDB_SUCCESS) {
7846                 return ret;
7847         }
7848
7849         return ldb_next_prepare_commit(module);
7850 }
7851
7852 static int replmd_del_transaction(struct ldb_module *module)
7853 {
7854         struct replmd_private *replmd_private =
7855                 talloc_get_type(ldb_module_get_private(module), struct replmd_private);
7856         replmd_txn_cleanup(replmd_private);
7857
7858         return ldb_next_del_trans(module);
7859 }
7860
7861
7862 static const struct ldb_module_ops ldb_repl_meta_data_module_ops = {
7863         .name          = "repl_meta_data",
7864         .init_context      = replmd_init,
7865         .add               = replmd_add,
7866         .modify            = replmd_modify,
7867         .rename            = replmd_rename,
7868         .del               = replmd_delete,
7869         .extended          = replmd_extended,
7870         .start_transaction = replmd_start_transaction,
7871         .prepare_commit    = replmd_prepare_commit,
7872         .del_transaction   = replmd_del_transaction,
7873 };
7874
7875 int ldb_repl_meta_data_module_init(const char *version)
7876 {
7877         LDB_MODULE_CHECK_VERSION(version);
7878         return ldb_register_module(&ldb_repl_meta_data_module_ops);
7879 }