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